Collects Modal workspace members, tokens, secrets, and web endpoints
v0.1.0 passed its nightly check on Nov 7, 2026: 81 of 81 values matched. See the checked values
epack install collector modal
Adds to epack.yaml, resolves dependencies, downloads binary.
Run all configured collectors and build a pack:
epack collect
Runs all collectors in epack.yaml and outputs an evidence pack.
Or add manually to epack.yaml:
collectors:
modal:
source: https://github.com/locktivity/epack-collector-modal
Then run epack install to lock and sync.
epack-collector-modal collects evidence of who can reach a Modal workspace and what the workspace exposes to the internet.
From Modal's API, with a token that belongs to the workspace's Owner or a Manager:
artifacts/modal.access-posture.json describes access to the workspace in the shared evidencepack/access-posture@v1 format. It is built from the members, service users, and proxy auth tokens, with no other calls.
sso_configured is true when any member signs in through SAML SSO.audit level.An environment with no setting of its own for blocking unauthenticated web endpoints follows the workspace default. Modal's API does not report that default, so blocks_unauthenticated is null for that environment.
Modal's API does not report these access-posture values either. Each one is left out of every run with an unsupported gap:
Modal does not report when a proxy auth token was last used. In a workspace with proxy auth tokens, the unused credentials are left out with an unsupported gap.
A service user's access comes from its role in each environment. Modal reports these roles, but the collector reads them only in restricted environments, from the audit level. In a workspace with service users, the unrestricted credentials and those with write access are left out with a not_read gap.
artifacts/modal.details.json, described by docs/schema/v1.0.0.json.artifacts/modal.access-posture.json, in the evidencepack/access-posture@v1 format. docs/schema/methods.json says how each of its values is measured.artifacts/modal.collector-result.json, which records each value left out and why, the run's steps, and its calls.See levels.md for what each collection level adds and examples.md for sample output.
The collector reads a Modal workspace through Modal's API with an API token.
Create the token as the workspace's Owner or a Manager, since only they can list the workspace's members and service users. With a Member's token, the members and the service users are left out with a permission_denied gap. The sign-in, members, and admins in artifacts/modal.access-posture.json come from the members list, so they are left out too. The credential counts and percentages there need the service users, so they are also left out.
A Modal API token can do anything its user can, so a Manager's token can also change the workspace and its members.
collectors:
modal:
source: locktivity/epack-collector-modal@^0.1
config:
level: audit
secrets:
- MODAL_TOKEN_ID
- MODAL_TOKEN_SECRET
export MODAL_TOKEN_ID=YOUR-TOKEN-ID MODAL_TOKEN_SECRET=YOUR-TOKEN-SECRET
The collector reads the workspace the token belongs to.
| Option | Required | Description |
|---|---|---|
level |
No | trust (the default), audit, or internal. See levels.md. |
collect |
No | The kinds of evidence to collect, from access-posture and details. Defaults to both. |
| Variable | Description |
|---|---|
MODAL_TOKEN_ID |
The API token's ID, which starts with ak-. |
MODAL_TOKEN_SECRET |
The API token's secret, which starts with as-. |
The run fails only when the configuration is invalid (exit 2), when Modal rejects the token (exit 3), or when Modal's API cannot be reached (exit 4). Every other read that fails leaves its values out of artifacts/modal.details.json and artifacts/modal.access-posture.json. artifacts/modal.collector-result.json records a gap for each, with the call that failed and what to check.
This value is left out every time its condition holds:
| Value | Code | When |
|---|---|---|
members and service_users in artifacts/modal.details.json |
permission_denied |
The token belongs to a Member. |
sign_in, members, and admins in artifacts/modal.access-posture.json |
permission_denied |
The token belongs to a Member. |
The counts and percentages under credentials in artifacts/modal.access-posture.json |
permission_denied |
The token belongs to a Member. |
unused_pct and unused_credential_count in artifacts/modal.access-posture.json |
unsupported |
The workspace has a proxy auth token. |
unrestricted_pct, write_access_pct, and their counts in artifacts/modal.access-posture.json |
not_read |
The workspace has a service user. |
Counts for the workspace, at the default trust level:
collectors:
modal:
source: locktivity/epack-collector-modal@^0.1
secrets:
- MODAL_TOKEN_ID
- MODAL_TOKEN_SECRET
At audit, each count has its rows beside it:
collectors:
modal:
source: locktivity/epack-collector-modal@^0.1
config:
level: audit
secrets:
- MODAL_TOKEN_ID
- MODAL_TOKEN_SECRET
For a Team workspace read with a Manager's token, at the trust level, artifacts/modal.details.json holds:
{
"schema_version": "1.0.0",
"collected_at": "2026-10-22T12:00:00Z",
"collected_at_level": "trust",
"workspace": {"id": "ac-0123456789abcdefghijkl", "name": "example-workspace"},
"members": {
"total_count": 3,
"owner_count": 1,
"manager_count": 1,
"member_count": 1,
"sign_in": {"github_count": 1, "google_count": 2, "saml_count": 0, "other_count": 0},
"inactive_count": 2
},
"environments": {"total_count": 3, "restricted_count": 1},
"service_users": {"total_count": 2, "never_used_count": 1},
"proxy_auth_tokens": {"total_count": 2, "unscoped_count": 1},
"secrets": {"total_count": 3, "never_used_count": 2},
"apps": {
"deployed_count": 3,
"web_endpoint_count": 2,
"unauthenticated_endpoint_count": 1,
"scheduled_function_count": 1
}
}
For the same workspace, artifacts/modal.access-posture.json holds:
{
"schema_version": "1.0.0",
"collected_at": "2026-10-22T12:00:00Z",
"provider": "modal",
"system_type": "platform",
"sign_in": {"sso_configured": false},
"members": {
"members_present": true,
"sso_coverage_pct": 0,
"local_members_present": true,
"inactive_pct": 67
},
"admins": {
"admins_present": true,
"admin_share_pct": 67,
"local_admins_present": true
},
"credentials": {
"credentials_present": true,
"rotation_overdue_pct": 25
}
}
The workspace has service users, so unrestricted_pct and write_access_pct are left out with a not_read gap.
With a Member's token, members and service_users are absent and artifacts/modal.collector-result.json has a gap for each. The access-posture artifact leaves out sign_in, members, and admins, and the credential counts and percentages. Each has a permission_denied gap. At audit, the detailed artifact's gap on the members is:
"gaps": [
{
"path": "artifacts/modal.details.json",
"pointer": "/members",
"status": "not_collected",
"code": "permission_denied",
"owner": "customer",
"vendor_code": "PERMISSION_DENIED",
"operation": "modal.members.list",
"call": 2,
"source": "internal/collector/members.go:25",
"missing_permission": "Manager",
"warning": "Reading members needs a token that belongs to the workspace's Owner or a Manager.",
"detail": "modal.members.list: PERMISSION_DENIED: User example-member does not have manage access to workspace example-workspace. Contact your workspace administrator to update permissions."
}
]
At audit, a restricted environment's row lists who holds a role in it:
{
"name": "prod",
"default": false,
"restricted": true,
"created_at": "2026-10-02T12:00:00Z",
"default_member_role": "no_access",
"blocks_unauthenticated": true,
"roles": [
{"principal": "member@example.com", "kind": "member", "role": "viewer"},
{"principal": "ci-deployer", "kind": "service_user", "role": "contributor"}
]
}
A deployed app's row:
{
"name": "public-api",
"environment": "dev",
"state": "deployed",
"created_at": "2026-10-19T12:00:00Z",
"web_endpoints": 1,
"unauthenticated_endpoints": 1,
"scheduled_functions": 0
}
A Modal workspace on the Starter plan, used only for these checks. It has an owner, a manager, and a member, three environments, three secrets, one proxy auth token, and three deployed apps: a web endpoint anyone can call, one that needs a proxy auth token, and a job that runs every day. The collector reads the workspace at the audit level with the manager's token.
Runs at Audit, which includes Trust. Internal isn't checked.
v0.1.0 · Nov 7, 2026 · 81 of 81 values matched
16 of 16 nights passed, Oct 23 to Nov 7.
The test account is set up only for these checks. Its settings are kept in code, so the value the collector should report for each field is known ahead of time.
Every night at 05:00 UTC, the newest published version runs against the test account. Each value it reports is compared with the known value. New versions go through the same check before they're published.
Values that could identify a test account, such as its domain, IDs, or user logins, aren't shown here. They're still checked.
The same results, with the same values withheld, are published as sandbox-results.json.
Full Changelog: https://github.com/locktivity/epack-collector-modal/compare/v0.1.0...v0.2.0
Nightly checks: 16 passed.
268 fields. The test account checks 51 of them.
Every field this collector can write, each tagged with the lowest level that collects it. Each level includes everything in the level before it.
No fields match these filters.
The values Foundational Controls and other profiles read.
The test account doesn't have a known value for this field.
The system's vendor, such as github, aws, or clickhouse
The test account doesn't have a known value for this field.
The test account doesn't have a known value for this field.
The kind of system
The test account doesn't have a known value for this field.
Admins
The test account doesn't have a known value for this field.
Whether the system has any admins
The test account doesn't have a known value for this field.
Admins who can sign in without SSO. An admin linked to SSO counts when the system still lets them sign in another way
The test account doesn't have a known value for this field.
Percentage of admins who can sign in without SSO and have MFA. Null when no admin can sign in without SSO
The test account doesn't have a known value for this field.
Whether any admins can sign in without SSO. An admin linked to SSO counts too when the system still lets them sign in another way. When false, local_admin_mfa_coverage_pct has no admins to count
The test account doesn't have a known value for this field.
Admins counted in local_admin_count who have MFA
The test account doesn't have a known value for this field.
Admins
The test account doesn't have a known value for this field.
Whether the system has any admins
The test account doesn't have a known value for this field.
Admins who can sign in without SSO. An admin linked to SSO counts when the system still lets them sign in another way
The test account doesn't have a known value for this field.
Percentage of admins who can sign in without SSO and have MFA. Null when no admin can sign in without SSO
The test account doesn't have a known value for this field.
Whether any admins can sign in without SSO. An admin linked to SSO counts too when the system still lets them sign in another way. When false, local_admin_mfa_coverage_pct has no admins to count
The test account doesn't have a known value for this field.
Admins counted in local_admin_count who have MFA
The test account doesn't have a known value for this field.
Third-party apps with access
The test account doesn't have a known value for this field.
Whether any third-party app has access
The test account doesn't have a known value for this field.
Machine credentials
The test account doesn't have a known value for this field.
Whether the system has any machine credentials. When false, the credential percentages have none to count
The test account doesn't have a known value for this field.
Credentials that never expire
The test account doesn't have a known value for this field.
Percentage of credentials that never expire. Null when there are none
The test account doesn't have a known value for this field.
Credentials older than 90 days. When the system does not record when a credential was created, this is left out with a gap
The test account doesn't have a known value for this field.
Percentage of credentials older than 90 days. Left out with a gap when the system does not record when a credential was created. Null when there are none
The test account doesn't have a known value for this field.
Credentials with neither an IP limit nor a scope narrower than full access. A credential limited to chosen permissions or resources has a narrower scope. A credential with either limit is restricted
The test account doesn't have a known value for this field.
Percentage of credentials with neither an IP limit nor a scope narrower than full access. Null when there are none
The test account doesn't have a known value for this field.
Credentials never used, or unused in the last 90 days
The test account doesn't have a known value for this field.
Percentage of credentials never used, or unused in the last 90 days. Null when there are none
The test account doesn't have a known value for this field.
Credentials that can write or administer
The test account doesn't have a known value for this field.
Percentage of credentials that can write or administer. Null when there are none
The test account doesn't have a known value for this field.
Machine credentials
The test account doesn't have a known value for this field.
Whether the system has any machine credentials. When false, the credential percentages have none to count
The test account doesn't have a known value for this field.
Credentials that never expire
The test account doesn't have a known value for this field.
Percentage of credentials that never expire. Null when there are none
The test account doesn't have a known value for this field.
Credentials older than 90 days. When the system does not record when a credential was created, this is left out with a gap
The test account doesn't have a known value for this field.
Percentage of credentials older than 90 days. Left out with a gap when the system does not record when a credential was created. Null when there are none
The test account doesn't have a known value for this field.
Credentials with neither an IP limit nor a scope narrower than full access. A credential limited to chosen permissions or resources has a narrower scope. A credential with either limit is restricted
The test account doesn't have a known value for this field.
Percentage of credentials with neither an IP limit nor a scope narrower than full access. Null when there are none
The test account doesn't have a known value for this field.
Credentials never used, or unused in the last 90 days
The test account doesn't have a known value for this field.
Percentage of credentials never used, or unused in the last 90 days. Null when there are none
The test account doesn't have a known value for this field.
Credentials that can write or administer
The test account doesn't have a known value for this field.
Percentage of credentials that can write or administer. Null when there are none
The test account doesn't have a known value for this field.
Members from outside the organization
The test account doesn't have a known value for this field.
Whether any members come from outside the organization, such as outside collaborators or guests
The test account doesn't have a known value for this field.
Members with no sign-in or other recorded activity in the last 90 days
The test account doesn't have a known value for this field.
Percentage of members with no sign-in or other recorded activity in the last 90 days. Null when there are no members
The test account doesn't have a known value for this field.
Members who can sign in without SSO. A member linked to SSO counts when the system still lets them sign in another way
The test account doesn't have a known value for this field.
Whether any members can sign in without SSO, with a password or a social login. A member linked to SSO counts too when the system still lets them sign in another way, so local and SSO members can overlap. When false, local_mfa_coverage_pct has no members to count
The test account doesn't have a known value for this field.
Percentage of members who can sign in without SSO and have MFA. Null when no member can sign in without SSO
The test account doesn't have a known value for this field.
Members counted in local_member_count who have MFA
The test account doesn't have a known value for this field.
Members
The test account doesn't have a known value for this field.
Whether the system has any members. When false, the member percentages have no members to count
The test account doesn't have a known value for this field.
Percentage of members whose account is linked to SSO. Null when there are no members
The test account doesn't have a known value for this field.
Members whose account is linked to SSO
The test account doesn't have a known value for this field.
Members from outside the organization
The test account doesn't have a known value for this field.
Whether any members come from outside the organization, such as outside collaborators or guests
The test account doesn't have a known value for this field.
Members with no sign-in or other recorded activity in the last 90 days
The test account doesn't have a known value for this field.
Percentage of members with no sign-in or other recorded activity in the last 90 days. Null when there are no members
The test account doesn't have a known value for this field.
Members who can sign in without SSO. A member linked to SSO counts when the system still lets them sign in another way
The test account doesn't have a known value for this field.
Whether any members can sign in without SSO, with a password or a social login. A member linked to SSO counts too when the system still lets them sign in another way, so local and SSO members can overlap. When false, local_mfa_coverage_pct has no members to count
The test account doesn't have a known value for this field.
Percentage of members who can sign in without SSO and have MFA. Null when no member can sign in without SSO
The test account doesn't have a known value for this field.
Members counted in local_member_count who have MFA
The test account doesn't have a known value for this field.
Members
The test account doesn't have a known value for this field.
Whether the system has any members. When false, the member percentages have no members to count
The test account doesn't have a known value for this field.
Percentage of members whose account is linked to SSO. Null when there are no members
The test account doesn't have a known value for this field.
Members whose account is linked to SSO
The test account doesn't have a known value for this field.
Whether any root account has access keys
The test account doesn't have a known value for this field.
Root accounts. A system with scopes has one per scope
The test account doesn't have a known value for this field.
Whether the system has a built-in root account. When false, root_mfa_coverage_pct has no accounts to count
The test account doesn't have a known value for this field.
Root accounts with MFA
The test account doesn't have a known value for this field.
Percentage of root accounts with MFA. Null when there are none
The test account doesn't have a known value for this field.
Whether any root account has access keys
The test account doesn't have a known value for this field.
Root accounts. A system with scopes has one per scope
The test account doesn't have a known value for this field.
Whether the system has a built-in root account. When false, root_mfa_coverage_pct has no accounts to count
The test account doesn't have a known value for this field.
Root accounts with MFA
The test account doesn't have a known value for this field.
Percentage of root accounts with MFA. Null when there are none
The test account doesn't have a known value for this field.
The account or subscription ID
The test account doesn't have a known value for this field.
The test account doesn't have a known value for this field.
The account or subscription name
The test account doesn't have a known value for this field.
Whether the system requires MFA from anyone who signs in without SSO
The test account doesn't have a known value for this field.
Whether accounts are created and removed through SCIM
The test account doesn't have a known value for this field.
Whether SSO is set up for the system
The test account doesn't have a known value for this field.
Whether everyone must sign in through SSO
The test account doesn't have a known value for this field.
Whether the system requires MFA from anyone who signs in without SSO
The test account doesn't have a known value for this field.
Whether accounts are created and removed through SCIM
The test account doesn't have a known value for this field.
Whether SSO is set up for the system
The test account doesn't have a known value for this field.
Whether everyone must sign in through SSO
The test account doesn't have a known value for this field.
Everything this collector reads, grouped by area. Each field lists the lowest level that collects it. Its schema isn't published yet, so only the checked fields are listed.
Not in the published schema yet. The checks below name the paths as the collector writes them.
| Path | Expected | Reported | Result |
|---|---|---|---|
| collector.name | "modal" | "modal" | Matches |
Not in the published schema yet. The checks below name the paths as the collector writes them.
| Path | Expected | Reported | Result |
|---|---|---|---|
| collector.version | the same as artifacts/modal.collector-result.json /collector/version, which is "0.1.0" | withheld | Matches |
Not in the published schema yet. The checks below name the paths as the collector writes them.
| Path | Expected | Reported | Result |
|---|---|---|---|
| schemas.artifacts/modal.json | any value | any value | Matches |
Not in the published schema yet. The checks below name the paths as the collector writes them.
| Path | Expected | Reported | Result |
|---|---|---|---|
| trace_map.artifacts.artifacts/modal.json./members/total_count.operations | ["modal.members.list"] | ["modal.members.list"] | Matches |
Everything this collector reads, grouped by area. Each field lists the lowest level that collects it.
When the collector ran.
The test account doesn't have a known value for this field.
The collection level the artifact was made at. audit adds the inventories to trust's counts, and internal adds nothing more.
| Path | Expected | Reported | Result |
|---|---|---|---|
| collected_at_level | "audit" | "audit" | Matches |
The version of this schema.
| Path | Expected | Reported | Result |
|---|---|---|---|
| schema_version | "1.0.0" | "1.0.0" | Matches |
Deployed apps.
| Path | Expected | Reported | Result |
|---|---|---|---|
| apps.deployed_count | 3 | 3 | Matches |
Every app, sorted by environment, then name.
| Path | Expected | Reported | Result |
|---|---|---|---|
| apps.inventory[3] | left out | left out | Matches |
When the app was created. Null when the API does not say.
The test account doesn't have a known value for this field.
The environment the app belongs to.
| Path | Expected | Reported | Result |
|---|---|---|---|
| apps.inventory[0].environment | "dev" | "dev" | Matches |
| apps.inventory[1].environment | "prod" | "prod" | Matches |
| apps.inventory[2].environment | "prod" | "prod" | Matches |
The app's name.
| Path | Expected | Reported | Result |
|---|---|---|---|
| apps.inventory[0].name | "sandbox-public-api" | "sandbox-public-api" | Matches |
| apps.inventory[1].name | "sandbox-nightly-job" | "sandbox-nightly-job" | Matches |
| apps.inventory[2].name | "sandbox-private-api" | "sandbox-private-api" | Matches |
The app's functions that run on a schedule.
| Path | Expected | Reported | Result |
|---|---|---|---|
| apps.inventory[0].scheduled_functions | 0 | 0 | Matches |
| apps.inventory[1].scheduled_functions | 1 | 1 | Matches |
| apps.inventory[2].scheduled_functions | 0 | 0 | Matches |
The app's state. other is a state this version of the collector does not know.
| Path | Expected | Reported | Result |
|---|---|---|---|
| apps.inventory[0].state | "deployed" | "deployed" | Matches |
| apps.inventory[1].state | "deployed" | "deployed" | Matches |
| apps.inventory[2].state | "deployed" | "deployed" | Matches |
Of those, the ones anyone with the URL can call, with no proxy auth token.
| Path | Expected | Reported | Result |
|---|---|---|---|
| apps.inventory[0].unauthenticated_endpoints | 1 | 1 | Matches |
| apps.inventory[2].unauthenticated_endpoints | 0 | 0 | Matches |
The app's functions that serve web requests.
| Path | Expected | Reported | Result |
|---|---|---|---|
| apps.inventory[0].web_endpoints | 1 | 1 | Matches |
| apps.inventory[1].web_endpoints | 0 | 0 | Matches |
| apps.inventory[2].web_endpoints | 1 | 1 | Matches |
Functions of deployed apps that run on a schedule.
| Path | Expected | Reported | Result |
|---|---|---|---|
| apps.scheduled_function_count | 1 | 1 | Matches |
In the test account: The daily job runs on a schedule.
Of those, the ones anyone with the URL can call, with no proxy auth token.
| Path | Expected | Reported | Result |
|---|---|---|---|
| apps.unauthenticated_endpoint_count | 1 | 1 | Matches |
In the test account: Of the two web endpoints, the one in the dev environment needs no proxy auth token.
Functions of deployed apps that serve web requests.
| Path | Expected | Reported | Result |
|---|---|---|---|
| apps.web_endpoint_count | 2 | 2 | Matches |
Every environment the token can see, sorted by name.
Its rows aren't described in the schema yet. The checks below name the paths as the collector writes them.
| Path | Expected | Reported | Result |
|---|---|---|---|
| environments.inventory[3] | left out | left out | Matches |
| environments.inventory.*.restricted | false | false | Matches |
| environments.inventory.*.blocks_unauthenticated | null | null | Matches |
| environments.inventory.*.roles | null | null | Matches |
Whether the environment rejects new web endpoints, servers, and tunnels that anyone can call without authentication.
The test account doesn't have a known value for this field.
When the environment was created. Null when the API does not say.
The test account doesn't have a known value for this field.
Whether this is the workspace's default environment.
| Path | Expected | Reported | Result |
|---|---|---|---|
| environments.inventory[0].default | false | false | Matches |
| environments.inventory[1].default | true | true | Matches |
| environments.inventory[2].default | false | false | Matches |
The role a member gets in a restricted environment when they hold no role of their own. other is a role this version of the collector does not know. Null when Modal reports none.
The test account doesn't have a known value for this field.
The environment's name.
| Path | Expected | Reported | Result |
|---|---|---|---|
| environments.inventory[0].name | "dev" | "dev" | Matches |
| environments.inventory[1].name | "main" | "main" | Matches |
| environments.inventory[2].name | "prod" | "prod" | Matches |
Whether only members and service users with a role in the environment can use it.
The test account doesn't have a known value for this field.
Whether the role belongs to a member or a service user.
The test account doesn't have a known value for this field.
The member's email address, or the service user's name.
The test account doesn't have a known value for this field.
The role, such as contributor or viewer, or the name of a custom role.
The test account doesn't have a known value for this field.
Environments with restricted access, where a member needs a role in the environment to use it.
| Path | Expected | Reported | Result |
|---|---|---|---|
| environments.restricted_count | 0 | 0 | Matches |
In the test account: Starter has no restricted environments.
Environments the token can see.
| Path | Expected | Reported | Result |
|---|---|---|---|
| environments.total_count | 3 | 3 | Matches |
Members with no activity in the 90 days before the collector ran, including members who have never been active. The collector's calls count as activity for the member the token belongs to, so that member is never inactive.
The test account doesn't have a known value for this field.
Every member, sorted by email.
| Path | Expected | Reported | Result |
|---|---|---|---|
| members.inventory[3] | left out | left out | Matches |
The member's email address, in lowercase.
The test account doesn't have a known value for this field.
Whether the member had no activity in the 90 days before the collector ran, or has never been active.
The test account doesn't have a known value for this field.
When the member joined the workspace. Null when the API does not say.
The test account doesn't have a known value for this field.
When the member was last active. Null for a member who has never been active.
The test account doesn't have a known value for this field.
The member's display name.
The test account doesn't have a known value for this field.
The member's workspace role. other is a role this version of the collector does not know.
The test account doesn't have a known value for this field.
How the member signs in.
The test account doesn't have a known value for this field.
Members with the Manager role.
| Path | Expected | Reported | Result |
|---|---|---|---|
| members.manager_count | 1 | 1 | Matches |
Members with the Member role.
| Path | Expected | Reported | Result |
|---|---|---|---|
| members.member_count | 1 | 1 | Matches |
Members with the Owner role.
| Path | Expected | Reported | Result |
|---|---|---|---|
| members.owner_count | 1 | 1 | Matches |
Members counted by how they sign in.
| Path | Expected | Reported | Result |
|---|---|---|---|
| members.sign_in | {"github_count":1,"google_count":2,"other_count":0,"saml_count":0} | {"github_count":1,"google_count":2,"other_count":0,"saml_count":0} | Matches |
In the test account: The owner signs in with GitHub, and the manager and the member with Google.
Members who sign in with GitHub.
The test account doesn't have a known value for this field.
Members who sign in with Google.
The test account doesn't have a known value for this field.
Members who sign in some other way, or whose sign-in Modal does not report.
The test account doesn't have a known value for this field.
Members who sign in through SAML SSO.
The test account doesn't have a known value for this field.
Members of the workspace.
| Path | Expected | Reported | Result |
|---|---|---|---|
| members.total_count | 3 | 3 | Matches |
In the test account: The owner, the manager, and the member.
When the token was created. Null when the API does not say.
The test account doesn't have a known value for this field.
Who created the token. Null when the API does not say.
The test account doesn't have a known value for this field.
The environments a scoped token works in, sorted. Null for a token that is not scoped.
| Path | Expected | Reported | Result |
|---|---|---|---|
| proxy_auth_tokens.inventory[0].environments | null | null | Matches |
The token's name.
| Path | Expected | Reported | Result |
|---|---|---|---|
| proxy_auth_tokens.inventory[0].name | "sandbox-caller" | "sandbox-caller" | Matches |
Whether the token works only in the environments it lists.
| Path | Expected | Reported | Result |
|---|---|---|---|
| proxy_auth_tokens.inventory[0].scoped | false | false | Matches |
Proxy auth tokens in the workspace.
| Path | Expected | Reported | Result |
|---|---|---|---|
| proxy_auth_tokens.total_count | 1 | 1 | Matches |
Tokens that work in every environment.
| Path | Expected | Reported | Result |
|---|---|---|---|
| proxy_auth_tokens.unscoped_count | 1 | 1 | Matches |
In the test account: The one proxy auth token works in every environment.
Every secret, sorted by environment, then name.
| Path | Expected | Reported | Result |
|---|---|---|---|
| secrets.inventory[3] | left out | left out | Matches |
When the secret was created. Null when the API does not say.
The test account doesn't have a known value for this field.
Who created the secret. Null when the API does not say.
The test account doesn't have a known value for this field.
The environment the secret belongs to.
| Path | Expected | Reported | Result |
|---|---|---|---|
| secrets.inventory[0].environment | "dev" | "dev" | Matches |
| secrets.inventory[1].environment | "prod" | "prod" | Matches |
| secrets.inventory[2].environment | "prod" | "prod" | Matches |
The names of the secret's keys, sorted. The collector never reads their values.
| Path | Expected | Reported | Result |
|---|---|---|---|
| secrets.inventory[0].keys | ["API_KEY"] | ["API_KEY"] | Matches |
| secrets.inventory[1].keys | ["DB_PASSWORD"] | ["DB_PASSWORD"] | Matches |
| secrets.inventory[2].keys | ["TOKEN"] | ["TOKEN"] | Matches |
When the secret was last used. Null for one that has never been used.
The test account doesn't have a known value for this field.
The secret's name.
| Path | Expected | Reported | Result |
|---|---|---|---|
| secrets.inventory[0].name | "api-key" | "api-key" | Matches |
| secrets.inventory[1].name | "db-credentials" | "db-credentials" | Matches |
| secrets.inventory[2].name | "stale-token" | "stale-token" | Matches |
Whether the secret has never been used.
| Path | Expected | Reported | Result |
|---|---|---|---|
| secrets.inventory[0].never_used | true | true | Matches |
| secrets.inventory[1].never_used | false | false | Matches |
| secrets.inventory[2].never_used | true | true | Matches |
Secrets that have never been used.
| Path | Expected | Reported | Result |
|---|---|---|---|
| secrets.never_used_count | 2 | 2 | Matches |
In the test account: The daily job reads one of the three secrets. No app reads the other two.
Secrets across those environments.
| Path | Expected | Reported | Result |
|---|---|---|---|
| secrets.total_count | 3 | 3 | Matches |
Every service user, sorted by name.
| Path | Expected | Reported | Result |
|---|---|---|---|
| service_users.inventory[0] | left out | left out | Matches |
When the service user was created. Null when the API does not say.
The test account doesn't have a known value for this field.
Who created the service user. Null when the API does not say.
The test account doesn't have a known value for this field.
When the service user was last used. Null for one that has never been used.
The test account doesn't have a known value for this field.
The service user's name.
The test account doesn't have a known value for this field.
Whether the service user has never been used.
The test account doesn't have a known value for this field.
Service users that have never been used.
The test account doesn't have a known value for this field.
Service users in the workspace.
| Path | Expected | Reported | Result |
|---|---|---|---|
| service_users.total_count | 0 | 0 | Matches |
In the test account: Starter has no service users.
The workspace's ID.
The test account doesn't have a known value for this field.
The workspace's name.
| Path | Expected | Reported | Result |
|---|---|---|---|
| workspace.name | withheld | withheld | Matches |
The status of each run, and any value it couldn't read and why.
Number of findings left out after the first 100.
The test account doesn't have a known value for this field.
Number of requests sent, including retries. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
Number of times the collector made the call, not counting retries. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The Deprecation header from the vendor's most recent response that carried one.
The test account doesn't have a known value for this field.
The codes of the operation's failed attempts, without their counts.
The test account doesn't have a known value for this field.
Number of failed attempts per code. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The operation's name, such as okta.users.list.
The test account doesn't have a known value for this field.
The permission the call needs, in the vendor's terms. The collector declares it with Operation.Permission. A permission_denied gap from the call records it as its missing_permission.
The test account doesn't have a known value for this field.
True when a request for the operation was a retry.
The test account doesn't have a known value for this field.
Number of requests that were retries. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The HTTP status codes, or DNS response codes for a lookup, that the operation's responses had, without their counts.
The test account doesn't have a known value for this field.
Number of responses per HTTP status code, or per DNS response code for a lookup. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The Sunset header from the vendor's most recent response that carried one.
The test account doesn't have a known value for this field.
Number of the rows left out whose attempt failed or was a retry. Present wherever the rows are; 0 means every failed or retried request has a row.
The test account doesn't have a known value for this field.
Which attempt the request was: 1 for the first, higher for a retry.
The test account doesn't have a known value for this field.
The call's number in the run, counting from 1 in the order calls start. Every attempt of one call has the same number.
The test account doesn't have a known value for this field.
How long the request took, in milliseconds.
The test account doesn't have a known value for this field.
The code for a request that failed. Absent when it succeeded.
The test account doesn't have a known value for this field.
The request's host, the name a DNS lookup queried, or the host dialed.
The test account doesn't have a known value for this field.
The HTTP method, DNS and the record type looked up, such as DNS TXT, or DIAL.
The test account doesn't have a known value for this field.
The operation the request belongs to.
The test account doesn't have a known value for this field.
Names of the request's query parameters. Their values are not recorded.
The test account doesn't have a known value for this field.
DNS lookups only: the response code. A lookup that got no response has none.
The test account doesn't have a known value for this field.
The vendor's request ID from the response headers, when it sent one.
The test account doesn't have a known value for this field.
HTTP requests only.
The test account doesn't have a known value for this field.
When the attempt was sent, in milliseconds after the run's started_at.
The test account doesn't have a known value for this field.
The response's HTTP status code. Absent when no response arrived.
The test account doesn't have a known value for this field.
The step the call was made in. Absent for a call made outside every step.
The test account doesn't have a known value for this field.
The vendor's own error code from a failed response, such as E0000047. Never the vendor's message. Absent for collectors that do not read one.
The test account doesn't have a known value for this field.
On a retry, how long the SDK waited before sending it: the Retry-After value, the rate limit reset, or its own backoff. Absent on a first attempt and on a retry sent at once.
The test account doesn't have a known value for this field.
Number of request rows left out.
The test account doesn't have a known value for this field.
The first 100 findings of the output checks the SDK runs on each artifact it writes. Absent when there are none.
| Path | Expected | Reported | Result |
|---|---|---|---|
| checks | left out | left out | Matches |
schema, schema_unusable, population, nulls, rollups, ratios, guidance, or levels.
The test account doesn't have a known value for this field.
What the check found.
The test account doesn't have a known value for this field.
The artifact the finding is about. A schema_unusable finding has none.
The test account doesn't have a known value for this field.
JSON pointer to the value the finding is about.
The test account doesn't have a known value for this field.
What happens if the customer picks the option, including its cost and what stays Not collected.
The test account doesn't have a known value for this field.
The test account doesn't have a known value for this field.
The test account doesn't have a known value for this field.
What happens if the customer picks the option, including its cost and what stays Not collected.
The test account doesn't have a known value for this field.
The test account doesn't have a known value for this field.
The test account doesn't have a known value for this field.
Each kind the collector could write that the key left out. Each has a not_shared gap.
The test account doesn't have a known value for this field.
The kinds of evidence the collect config key listed, such as cloud-posture.
The test account doesn't have a known value for this field.
Each kind the key listed that the run never wrote, such as a misspelled one.
The test account doesn't have a known value for this field.
The source commit the collector was built from. Absent when the build set none.
The test account doesn't have a known value for this field.
The collector's name, as its spec declares it.
| Path | Expected | Reported | Result |
|---|---|---|---|
| collector.name | "modal" | "modal" | Matches |
The collector's version, such as v0.3.0. Absent when the build set none.
The test account doesn't have a known value for this field.
One entry per value the collector left out of an artifact, and why.
| Path | Expected | Reported | Result |
|---|---|---|---|
| gaps[0] | left out | left out | Matches |
The number of that call, matching the call on its request rows. A partial gap names the first failed call among those it counts. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
Why the value was left out: auth_failed, permission_denied, config_invalid, not_licensed, unsupported, not_read, rate_limited, vendor_error, timeout, invalid_response, too_large, internal, or not_shared. unsupported means the vendor does not report the value. too_large means the vendor holds more than the collector reads. not_shared means the customer left it out of this pack with the collect config key.
The test account doesn't have a known value for this field.
Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The one instruction that fixes collection. It uses fixed wording plus permission, plan, and region names. A gap has at most one of fix, no_action, and choice.
The test account doesn't have a known value for this field.
For a permission_denied gap, the permission to grant, in the vendor's own terms, such as okta.logs.read.
The test account doesn't have a known value for this field.
True when nothing needs changing now. It does not clear the gap.
The test account doesn't have a known value for this field.
The operation whose failed call left the value out. Absent when no call's error caused the gap, such as for a feature the plan lacks.
The test account doesn't have a known value for this field.
Who can act on the code: customer, nobody for an expected gap such as a feature the plan lacks, vendor, vendor_or_runner, or publisher.
The test account doesn't have a known value for this field.
The artifact the value belongs in. Absent when the run wrote no such artifact, in which case schema names it.
The test account doesn't have a known value for this field.
JSON pointer to the value within the artifact. Items are addressed by array index.
The test account doesn't have a known value for this field.
The schema of the artifact the value belongs in, when the run wrote no such artifact.
The test account doesn't have a known value for this field.
The account, tenant, or region affected. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The file and line in the collector's own source that recorded the gap, relative to its module root, such as internal/collector/system_log.go:155.
The test account doesn't have a known value for this field.
not_collected when the collector could not read the value. partial when a rollup was left out because some of the items it covers could not be read, or when a list or object holds only the items that could be.
The test account doesn't have a known value for this field.
For a partial gap, the number of items that could not be read. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The vendor's own error code, when its response included one.
The test account doesn't have a known value for this field.
The collector's message to the operator about the gap, redacted. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
Its calls in the step. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The operation.
The test account doesn't have a known value for this field.
For a partial run, the code of the first gap other than a not_shared, unsupported, or not_read one, saying why its value was left out.
The test account doesn't have a known value for this field.
For a partial run, who can act on that code.
The test account doesn't have a known value for this field.
collected when the run read every value its level collects, or partial when it left values out. gaps lists each one. A not_shared or unsupported gap does not make a run partial.
The test account doesn't have a known value for this field.
True when SSL_CERT_FILE or SSL_CERT_DIR was set for the run.
The test account doesn't have a known value for this field.
When the run finished, in RFC 3339 UTC.
The test account doesn't have a known value for this field.
The level the run collected at, at every level. A reader uses it to tell a value the level left out from one the collector could not read. Absent from results of older SDKs.
The test account doesn't have a known value for this field.
True when a proxy variable such as HTTPS_PROXY was set for the run.
The test account doesn't have a known value for this field.
The run ID the runner passed in EPACK_RUN_ID. Absent when it passed none.
The test account doesn't have a known value for this field.
When the run started, in RFC 3339 UTC.
The test account doesn't have a known value for this field.
How the collector proved its identity, such as private_key_jwt for OAuth 2.0 client credentials with a signed key assertion or api_token for an API token.
| Path | Expected | Reported | Result |
|---|---|---|---|
| signed_in_as.auth_method | "api_token" | "api_token" | Matches |
Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The kind of principal, such as service_app, service_principal, or user.
| Path | Expected | Reported | Result |
|---|---|---|---|
| signed_in_as.kind | "user" | "user" | Matches |
The identity system, such as okta or microsoft-entra.
| Path | Expected | Reported | Result |
|---|---|---|---|
| signed_in_as.provider | "modal" | "modal" | Matches |
Present when the collector can show that its credential could only read.
The test account doesn't have a known value for this field.
The scopes the collector asked for. A scope here and missing from scopes was not granted.
The test account doesn't have a known value for this field.
The permissions the sign-in carried.
The test account doesn't have a known value for this field.
The tenant, account, or organization signed in to. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The named parts of the run, in the order they started, at every level. Absent when the collector opens none.
| Path | Expected | Reported | Result |
|---|---|---|---|
| steps[5] | left out | left out | Matches |
True when an attempt in the step failed: one with an error code or a status of 400 or more.
The test account doesn't have a known value for this field.
The calls those requests belong to. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
When the step ended, in milliseconds after the run's started_at. A step still open when the collector emitted ended then. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The attempts that failed: those with an error code or a status of 400 or more. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The step's name, such as people. Step names are part of the collector's contract, like operation names.
| Path | Expected | Reported | Result |
|---|---|---|---|
| steps[0].name | "sign_in" | "sign_in" | Matches |
| steps[1].name | "members" | "members" | Matches |
| steps[2].name | "environments" | "environments" | Matches |
| steps[3].name | "tokens" | "tokens" | Matches |
| steps[4].name | "workloads" | "workloads" | Matches |
The requests sent in the step, including rows left out of calls.requests. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The requests that were retries. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
When the step started, in milliseconds after the run's started_at. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The step's title, such as People and sign-in methods.
The test account doesn't have a known value for this field.
How many distinct values the run read that the vocabulary lacks.
The test account doesn't have a known value for this field.
The first 50 of those values, sorted. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The vocabulary's name, such as okta.event_types.
The test account doesn't have a known value for this field.
The one instruction that fixes collection. A warning has at most one of fix, no_action, and choice.
The test account doesn't have a known value for this field.
The collector's message about what happened. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The permission to grant, in the vendor's own terms.
The test account doesn't have a known value for this field.
True when nothing needs changing now.
The test account doesn't have a known value for this field.
The account, tenant, or region affected. Present at the audit and internal levels only.
The test account doesn't have a known value for this field.
The controls that read this collector's evidence.