Skip to content

Run evidence collectors

Collectors retrieve source evidence through the evidentia collect CLI group and the Collect screen in the web console. Credentialed providers read cloud, identity, database and vendor-risk systems. Some collectors also accept local exports or reviewed packaged sources. Findings, coverage and control mappings depend on the collector: Entra/M365, retention, incident clocks and public registries return full collection results with explicit scope and limitations. Registry observations keep compliance status unknown.

This is the operator reference for the whole collector matrix. If you have never run a collector before, start with the gentler end-to-end walkthrough in Getting started → Your first evidence collection, which wires the GitHub collector start-to-finish; this guide assumes you already understand that shape and focuses on the breadth of providers, the credential model, and the network/SSRF guards.

Import local SCAP results

The Collect > SCAP tab and collect scap accept XCCDF 1.2 Benchmark results, standalone TestResult documents with their required inert benchmark reference, and OVAL 5.8, 5.11.2 or 5.12.3 core results. Select the exact profile, assessment occurrence and local XML file. These imports preserve native outcomes and completion provenance; they do not run scanners or establish compliance.

A full result can succeed with no evidence artifact. OVAL completion requires a separate, source-bound assertion rather than an inference from its generator timestamp. Saving is a separate action, and source references remain inert. The SCAP operator guide explains assertions, CLI flags, API authentication, downloads and finite limits.

Observe public release publications

The Collect > Release cadence tab and collect release-cadence observe public GitHub release metadata with no GitHub credential. Choose an owner, repository and full_releases or all_published channel. The default poll returns the full bounded result without opening the evidence store; saving requires an explicit request and write permission.

Use CONMON > Release series or conmon release-series to evaluate local recorded publication spacing. This is upstream-release evidence, not proof of installed patches or remediation. The release-cadence guide explains exact commands, authentication, persistence outcomes, source limits and offline series states. Unlike provider-specific collectors with transport overrides, this profile fixes the public GitHub destination and refuses redirects.

What this surface is for

  • Pull live posture from a source system and turn it into control-mapped findings you can fold into a gap analysis (--format oscal-ar) or convert to OCSF for a SIEM.
  • Cover many providers — cloud (AWS), code (GitHub), identity (Okta, Google Workspace), data stores (PostgreSQL, MySQL, SQLite, MS SQL, Oracle, Databricks, Snowflake), and vendor-risk platforms (Vanta, Drata, BitSight, SecurityScorecard).
  • Ingest or convert OCSF — pull third-party OCSF findings in (collect ocsf) or push Evidentia findings out to an OCSF bundle (collect convert).

Every credentialed collector is read-only by design. The SQL adapters even run a write-privilege probe on first connect and emit an EVIDENTIA-WRITE-PRIV-DETECTED finding (mapped to NIST AC-6) if they find more access than they should have.

The credential model (read this first)

This is the highest-risk surface in Evidentia, so the credential handling is deliberate and worth understanding before you run anything:

  • Secrets never pass through a CLI value flag or a request body. Tokens and passwords are sourced from server-side environment variables (or the provider SDK's own credential chain). For example the GitHub collector reads $GITHUB_TOKEN; Okta reads $OKTA_API_TOKEN; the SQL adapters read a password from an env var you name with --password-env. The collectors refuse a secret passed as a flag.
  • In the web console, the forms only carry non-secret parameters — region, repo, host, options. The browser never sees a key value, and the Status tab reports only configured: true/false plus the env-var name a token came from, never the value.
  • Networked collectors block private IPs by default (--block-private-ips). This SSRF guard refuses any host that resolves to a private / loopback / link-local / multicast / reserved range — including the cloud instance-metadata endpoint 169.254.169.254 — before a socket opens. You opt out per-call with --allow-private-ips only for a trusted internal endpoint.

Prerequisites

  • Evidentia installed (pip install evidentia; verify with evidentia version).
  • The provider extra for whatever you are collecting — for example pip install "evidentia-collectors[aws]" or pip install "evidentia-core[ocsf]" for the OCSF verbs. A missing extra surfaces as a clear install hint rather than a stack trace.
  • The relevant credential exported in your shell (CLI) or set in the server's environment (console). See each provider's --help for the exact env-var name.

Step 1 — See what you can collect

List the whole collector matrix:

evidentia collect --help

You will see the credentialed providers (aws, github, okta, google-workspace, entra-m365, retention, sql, databricks, snowflake, vanta, drata, bitsight, securityscorecard) plus the two OCSF verbs (ocsf to ingest, convert to emit). Each subcommand has its own --help with the exact flags and the env var its secret is read from:

evidentia collect github --help

Step 2 — Configure the credential

Each collector documents its credential source in --help. The token/password is always read from the environment, never a flag. For GitHub:

Bash / Linux / macOS

export GITHUB_TOKEN=ghp_your_token_here

PowerShell (Windows)

$env:GITHUB_TOKEN = "ghp_your_token_here"

For the SQL adapters, the password lives in the env var named by --password-env (default differs per adapter, e.g. EVIDENTIA_POSTGRES_PASSWORD). For the SaaS/vendor-risk collectors, set the provider's token env var (OKTA_API_TOKEN, GOOGLE_WORKSPACE_ACCESS_TOKEN, VANTA_API_TOKEN, DRATA_API_TOKEN, BITSIGHT_API_TOKEN, SECURITYSCORECARD_API_TOKEN, SNOWFLAKE_PASSWORD, etc.).

Step 3 — Run a collector

Run one provider and write the findings JSON to a file with --output (or omit it to print to stdout). A plain evidentia collect ... line works the same in any shell:

evidentia collect github --repo octocat/Hello-World --output findings.json

A few representative providers:

evidentia collect aws --region us-east-1 --output aws-findings.json
evidentia collect okta --org-url https://your-org.okta.com --output okta-findings.json
evidentia collect google-workspace --customer my_customer --output google-workspace-findings.json

Public registry lookups

evidentia collect registry selects one identity and returns the complete RegistryLookupResult, including findings, source reads, diagnostics and a manifest. Lookup outcome, traversal status and freshness are separate fields. Registry listings and source disclosures do not establish compliance, eligibility, ownership, deployment or legal applicability.

Use the tls, rdap, sam-entity, sam-exclusions, gleif, fedramp, cmvp, fcc-covered-list, incommon, ssl-labs or security-txt selector. The request table names each target. Credentials and arbitrary origins cannot appear in requests. SAM uses the server-side EVIDENTIA_REGISTRY_SAM_API_KEY reference. InCommon needs pip install 'evidentia-collectors[registries]'; installing the GUI alone does not include that extra. TLS trust and the InCommon signing certificate are fixed by the implementation. There is no private-address or trust-bypass switch.

For a packaged lookup with no upstream request, save this as cmvp-request.json:

{"registry":"cmvp","target":{"certificate_number":"5517"},"scope_label":"Selected published certificate"}

The same command works in Bash and PowerShell:

evidentia collect registry --registry cmvp --request-file cmvp-request.json --output cmvp-result.json

The reviewed CMVP package includes that certificate detail but has no supported publisher cutoff. Its freshness remains unknown, so the command exits 1 while still writing the complete result. FedRAMP and FCC use their recorded publisher cutoffs; stale packages cannot establish current absence. The runtime never refreshes a package automatically.

Exit 0 means complete found/not_found evidence with current_observation or a non-stale dated_snapshot. Exit 1 also covers ambiguous, partial, unavailable, stale or unknown-freshness results and operational failures. The packaged FedRAMP and FCC snapshots carry their capture dates (2026-09-10 and 2026-09-09); a found and complete snapshot lookup older than seven days exits 1 with freshness stale until the snapshots are refreshed through the reviewed source procedure. Exit 2 means invalid input; exit 77 means read authorization was denied. Without --output, stdout contains full JSON only and fixed diagnostics go to stderr. Input must be a named regular JSON file of at most 65536 bytes.

The Collect > Public registries screen uses the same selectors and finite forms. It requires fresh API read authentication before an actual request, including a local packaged lookup. The backing operation is POST /api/collectors/registry. SSL Labs live access is visibly disabled and performs no assessment, polling, registration or cache request.

The screen separates source scope, match basis, literal dates, trust limitations and diagnostic counts. Candidate pages contain at most twenty observations; visible fields are capped at 16 KiB. Download full registry JSON retains the complete original validated bytes, including large integers and exact timestamp text. Demo mode contains 43 synthetic examples generated by the real collector and session. It uses no provider calls or production signature claims.

Maintainer source checks run locally without writes or downloads:

python -m scripts.registries.check_source_index

A source refresh needs reviewed replacement inputs and the existing gates. The documented FedRAMP exception retains 22 publisher-data matches only in its two exact approved files and hashes. Changed source bytes do not inherit that exception.

Entra ID and Microsoft 365

evidentia collect entra-m365 returns a result envelope with findings, a manifest and all nine capability records. It is not a bare findings array. The capability names are conditional-access, authentication-registration, sign-ins, directory-roles, managed-devices, retention-labels, dlp-export, defender-alerts and defender-incidents. Omit --capability to request all nine, or repeat it to choose a subset.

The alias supplied through --tenant-label must start with an ASCII letter or digit and contain at most 64 letters, digits, underscores, periods or hyphens. It is an operator label, not a verified tenant ID. Tokens are never decoded to infer identity. Provision pre-minted tokens through the operator's secret management process, using these fixed environment references:

Reference Use
ENTRA_M365_ACCESS_TOKEN Seven Graph capabilities other than retention labels.
ENTRA_M365_AUTH_MODE Declared primary mode: application (default) or delegated.
ENTRA_M365_RETENTION_ACCESS_TOKEN Separate delegated token for retention labels, with no fallback to the primary token.

The collector only makes GET requests to eight fixed commercial Graph v1.0 collections. It does not acquire or refresh tokens, execute PowerShell, accept an arbitrary host, or allow private-address access. Source permissions, delegated roles and licensing are separate requirements; see the permission and evidence boundary tables. A 403 does not identify which of those requirements is missing. A primary-token 401 stops later reuse of that token while retaining independent retention and DLP evidence.

After configuring an authorized token, this command requests two capabilities. It is identical in Bash and PowerShell:

evidentia collect entra-m365 --tenant-label audit-sample --capability conditional-access --capability sign-ins --lookback-days 7 --max-items 1000 --max-pages 10 --output entra-result.json

--lookback-days accepts 1 through 30 (default 30), --max-items accepts 1 through 10,000 (default 10,000), and --max-pages accepts 1 through 100 (default 100). Event timestamps retain source precision and the result distinguishes the requested window from the first and last observed events. A limit that stops collection leaves partial evidence after an accepted page, or unavailable evidence before one. A terminal page exactly at a cap can still complete.

DLP configuration comes from a local UTF-8 JSON file of at most 4 MiB. It needs no token when dlp-export is the only selected capability. The default format is evidentia-dlp-v1, which the recorded fixture below uses. Select scubagear-provider-v1 explicitly for original provider JSON containing dlp_compliance_policies and dlp_compliance_rules arrays. Neither format executes scripts or follows URLs. The design defines the exact policy, rule and source fields and GUID join rules.

From a repository checkout, this recorded-fixture example runs offline and works unchanged in Bash or PowerShell:

evidentia collect entra-m365 --tenant-label recorded-sample --capability dlp-export --dlp-export tests/fixtures/entra_m365/purview/cisa-dlp-recorded.json --dlp-format evidentia-dlp-v1 --output dlp-result.json

The fixture preserves 11 policies, 15 rules and publisher-attested provenance. All policy distribution states are Pending; complete enumeration does not establish enforcement. This is a selected recorded DLP export, not a Graph recording or a live tenant assessment. Other Graph test fixtures and both console demo scenarios are explicitly synthetic.

Check status, full_surface_complete and each capability's state before using the findings. A selected subset can be complete while full-surface coverage is false. Unrequested capabilities remain not_requested; missing, denied or incomplete evidence is not a compliance pass. Directory roles are activated-role inventory without memberships or PIM assignments; retention labels show configuration without item application or immutability proof.

The CLI writes the full valid result before exiting: 0 for complete, 1 for partial or unavailable, 2 for invalid input, and 77 for an existing read-role denial. Operational or output failure also exits 1. --output uses atomic replacement after input/output identity and feasibility checks; symlink output leaves are refused. Without it, stdout contains only JSON and notices use stderr. Keep the envelope as collection evidence. Consumers requiring a findings array must explicitly extract findings after reviewing completeness.

The API accepts the same request fields at POST /api/collectors/entra-m365/collect, with inline dlp_content rather than a file path. Its entire JSON body is bounded to 8 MiB. Well-formed completed attempts return HTTP 200 even when evidence is partial or unavailable. Invalid JSON or fields return sanitized 400 errors, oversized bodies 413 and unsupported media types 415. Graph requests require configured API authentication and read RBAC; DLP-only requests retain read RBAC without requiring a Graph credential. A missing optional collector returns 503 without parsing the export.

In the console, choose the Entra/M365 tab, select capabilities and enter a nonsecret alias. Graph collection rechecks authentication immediately before submission. DLP-only ingestion stays available under the local parsing posture. All nine states, counts, windows and source limitations remain visible even with zero findings. The page previews at most 100 findings, with source observations for the first 10 findings; Download full result JSON retains the complete result. The Status tab reports configuration presence separately from live validation, which remains false.

Storage retention

Use this collector to observe retention configuration on explicitly selected S3 general-purpose buckets, Azure Blob containers and their account/service context, or GCS buckets. It does not list resources, inspect objects, test deletion, change locks or establish compliance.

Install evidentia-collectors[retention] for S3 signing and XML support. Azure and GCS use the base collector dependencies. Configure only the selected provider's fixed credential references through your normal secret-management process:

Provider Fixed environment references
S3 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, optional AWS_SESSION_TOKEN
Azure STORAGE_RETENTION_AZURE_ACCESS_TOKEN
GCS STORAGE_RETENTION_GCS_ACCESS_TOKEN

Tokens must already exist; collection does not acquire or refresh them. Credentials, endpoint URLs, object keys and adjustable limits are never accepted in the request file. For a synthetic GCS target, the file shape is:

{
  "provider": "gcs",
  "scope_label": "example-scope",
  "targets": [{"bucket": "example-retention-bucket"}]
}

Replace the target with a resource you are authorized to read. Select one provider and 1 through 20 distinct targets. S3 targets use bucket, region and optional expected_owner; Azure targets use subscription_id, resource_group, account and container. The scope label is operator-declared and does not verify ownership or credential identity.

evidentia collect retention --help
evidentia collect retention --request-file request.json --output result.json

The request must be a named regular JSON file of at most 65536 bytes. Stdin, links and request/output aliases are refused. Output is reserved before any collection and replaced atomically after the full result validates. Omit --output for stdout. Complete results exit 0; partial/unavailable evidence and operational failures exit 1; invalid input exits 2; read-role denial exits 77. An exit of 1 may still produce valid, useful partial evidence, so inspect resource and component diagnostics.

The API equivalent is POST /api/collectors/retention/collect with the same JSON object. Configured authentication and read RBAC precede body parsing and provider access. Valid results return HTTP 200 for every collection status. Invalid JSON/fields return 400, excess streamed bytes 413, unsupported media 415, absent optional support 503 and unexpected failures a sanitized 500.

In the console, select Storage retention, fill the nonsecret scope and target fields, then run. The tab retains every resource/component state, including unavailable evidence, and provides a full JSON download. Native source values retain their response spelling, including integers beyond browser number precision. Findings remain informational with unknown compliance status and no control mappings. The Status tab reports configured reference presence; live-provider and identity validation remain false. Demo responses and the public HTTP fixtures are explicitly synthetic. See the collector design for exact methods and limits.

Enterprise retention

Use Enterprise retention for configuration on selected Google Vault matters and holds, Splunk Enterprise indexes, or Elasticsearch ILM indexes and referenced policies. It reads configuration only. It does not enumerate a tenant, inspect records, change a policy or prove effective retention, record coverage or compliance. M365 retention labels remain part of the separate Entra/M365 collector.

An administrator configures a trusted profile registry on the API server or local CLI host. Set EVIDENTIA_ENTERPRISE_RETENTION_PROFILES_FILE to a named regular JSON file. This synthetic example describes the shape and grants no collection access:

{
  "schema_version": "enterprise-retention-profiles/v1",
  "profiles": [{
    "alias": "selected",
    "provider": "splunk-enterprise",
    "origin": "https://splunk.example.invalid:8089",
    "credential_ref": "ENTERPRISE_RETENTION_SPLUNK_TOKEN",
    "address_policy": {"mode": "public", "cidrs": []},
    "api_principals": [],
    "allow_local_cli": false
  }]
}

Replace the synthetic origin with the authorized server's exact HTTPS origin and explicit port. Vault uses the fixed origin https://vault.googleapis.com:443. Private deployments require a private address policy with explicit RFC1918 or ULA CIDRs; public mode rejects private addresses. Optional trusted CA configuration is read and detached from its file before collection. Requests cannot override destination, trust, address policy or limits.

Grant API access by adding each complete authenticated principal to api_principals, with exact case and suffixes. The API also requires configured authentication and read RBAC. Unknown, wrong-provider and unauthorized aliases receive the same denial. An API grant does not grant CLI access: set allow_local_cli to true only for a profile intended for local use. CLI identity and tenant labels are operator assertions, not authenticated people. The shared local-operator token identity cannot distinguish individual token holders.

Provision the selected preminted token through your normal secret-management process at the profile's environment reference. No token belongs in this JSON, command arguments or browser form. Vault and Splunk use Bearer tokens; Elastic uses an API key. The collector does not acquire, refresh or discover credentials. See the design for provider permission and licensing limits.

The separate request file contains only a provider, profile alias, scope label and 1 through 20 distinct literal targets:

{
  "provider": "splunk-enterprise",
  "profile_alias": "selected",
  "scope_label": "example-scope",
  "targets": [{"index": "selected-index"}]
}

Vault targets use matter_id; Splunk and Elastic targets use index. Wildcards and all-resource selectors are unsupported. The scope label describes the selection and does not verify ownership.

evidentia collect enterprise-retention --help
evidentia collect enterprise-retention --request-file request.json --output result.json

Input is a named regular JSON file of at most 65536 bytes. The CLI checks read permission before opening it, checks the profile's local grant, and reserves output before collection. It validates the complete result and original selection before atomic replacement. Omit --output for full JSON on stdout. Complete exits 0; partial/unavailable results and operational failures exit 1; invalid input exits 2; read-role or profile denial exits 77. A partial result can retain useful evidence, so inspect the resource and source-read diagnostics.

The API uses POST /api/collectors/enterprise-retention/collect with the same request object. Authentication and read RBAC precede body reads; exact profile authorization precedes provider access. The request cap applies to actual cumulative bytes. Valid full results use HTTP 200 for all three collection states; invalid input uses 400, denial 401/403, excess bytes 413, unsupported media 415, unavailable optional support 503, and unexpected failures a fixed 500. Profiles load once at application startup. Invalid configuration fails startup; an absent enterprise installation does not read the configured profile file. Status reports installation only, without enumerating profiles or inspecting credential references.

In Collect, select Enterprise retention, choose the provider and enter the nonsecret profile alias, scope and targets, or import the bounded request JSON. The console retains every resource and unique read, including unattempted or unavailable reads. It previews the first ten observations per read; Download full enterprise result JSON includes every retained observation. Native field text and the download preserve large integers, float spelling and source timestamps. Browser validation checks bounded structure and selection consistency; the Python result validator is authoritative for field interpretation, projection digests and finding identity.

Vault default/custom retention rules and held-record coverage remain unassessed. Splunk archive settings expose only absent/null/empty/nonempty states; a configured path does not prove archival execution. Elastic keeps running phase data separate from current policy configuration and does not claim an atomic server snapshot. Synthetic demo scenarios cover all three result states for each provider. Public fixtures are authored synthetic responses; live-provider acceptance remains unverified.

Incident workflow clocks

Use Collect > Incident clock or evidentia collect incident-clock to observe one authorized record in ServiceNow, Jira Cloud or PagerDuty. Source completeness and workflow clock state are separate. An operational event does not establish a human determination or a legal notification deadline.

Provider Request identity Selected events
ServiceNow Exact lower-case 32-character sys_id Two distinct configured raw UTC date columns on sn_si_incident; no field-history reconstruction.
Jira Cloud Exact numeric issue ID Configured field IDs and native from/to transitions in the visible changelog.
PagerDuty Exact incident ID plus since and until Configured log-entry types in a timezone-aware interval of at most 366 days.

An administrator supplies a trusted profile file containing allowed records, clock definitions, credential references and exact API principal grants. Local CLI use requires a separate allow_local_cli grant. A profile name alone does not authorize a record. The API reads EVIDENTIA_INCIDENT_CLOCK_PROFILES_FILE lazily after authentication and request validation. The CLI uses --profiles-file or that same environment reference. Keep this configuration out of public source control and restrict local access.

This synthetic Jira profile illustrates the shape. Supply your own site, permitted records, principal and declared workflow meaning:

{
  "schema_version": "1",
  "profiles": [{
    "alias": "jira-ops",
    "provider": "jira",
    "cloud_id": "11111111-1111-1111-1111-111111111111",
    "credential_ref": "INCIDENT_CLOCK_JIRA_TOKEN",
    "allow_local_cli": true,
    "api_principals": ["operator"],
    "record_ids": ["10001"],
    "clocks": [{
      "clock_alias": "triage",
      "label": "Triage interval",
      "mapping_reference": "Organization incident runbook",
      "declared_workflow_meaning": "Entry into and completion of triage",
      "start": {
        "field_id": "status",
        "from": {"state": "null", "value": null},
        "to": {"state": "value", "value": "100"},
        "label": "Entered triage",
        "meaning": "Recorded workflow transition into triage"
      },
      "end": {
        "field_id": "status",
        "from": {"state": "value", "value": "100"},
        "to": {"state": "value", "value": "200"},
        "label": "Completed triage",
        "meaning": "Recorded workflow transition out of triage"
      }
    }]
  }]
}

The credential reference names an existing server or shell environment value; it never contains the token itself. A reference ending in _TOKEN uses the companion _EXPIRES_AT name, for example INCIDENT_CLOCK_JIRA_EXPIRES_AT. Jira and ServiceNow require a declared, unexpired timezone-aware expiry. PagerDuty permits an omitted expiry and reports expiry_unknown explicitly. Tokens are checked again before each selected read. Collection does not register applications, exchange or refresh tokens, or verify credential identity.

Save the corresponding request as incident-request.json:

{
  "provider": "jira",
  "profile_alias": "jira-ops",
  "record_id": "10001",
  "clock_alias": "triage",
  "start_occurrence": null,
  "end_occurrence": null
}
evidentia collect incident-clock --provider jira --request-file incident-request.json --profiles-file incident-profiles.json --output incident-clock.json

Jira occurrences use {"history_id":"H1","item_index":0}; item indexes range from 0 through 255. PagerDuty occurrences use {"event_id":"E1"}. An explicit occurrence must still match the configured endpoint. Multiple unqualified matches remain ambiguous. Null, empty, missing or unsupported timestamps remain visible; reversed endpoints have no elapsed value. The console accepts timestamp text directly to preserve native fractional precision.

Source state Clock meaning CLI exit / API status
complete computed, unresolved_events or reversed_order 0 / 200
incomplete or unavailable incomplete_source; admitted candidates retained 1 / 200

The CLI writes the full validated JSON before returning a source-state exit code. Input or output failure does not replace an existing destination with a partial result. Invalid input returns 2; authorization/profile refusal returns 77; operational or broken-feature failure returns 1. Request/profile files must be bounded regular files, at most 16 KiB/64 KiB. Output cannot alias either input. Symlinks, reparse points, multiple hard links and changed identities are refused.

The API is POST /api/collectors/incident-clock. Authentication and read RBAC precede body and profile reads. Invalid request JSON returns 400, oversize bodies 413, unsupported media types 415, and profile refusal 403. Genuine package or incident-feature absence returns 503 before body I/O. Broken installed dependencies or a provider without its callable collector refuse startup. Unavailable credentials or sources produce a full unavailable result when the collection can finish safely.

Results retain the selected record, admitted events, exact decimal elapsed seconds, read counts and hashes, diagnostics, workflow definition and manifest. Complete visible traversal does not establish historical retention or complete organization-wide incident coverage. The browser shows twenty events per page and bounds field previews to 4 KiB. Download full incident clock JSON retains every original validated response byte, up to 16 MiB.

All providers use fixed reads and verified public destinations. There is no private-IP, redirect, proxy or TLS-verification override. Useful work is bounded to 60 seconds, 100 history pages and 10000 events. A rejected page preserves earlier admitted pages. The incident clock design defines the exact source, transport and publication bounds.

Shipped tests and examples use authored synthetic source responses. They do not establish live permissions, ServiceNow SIR entitlement, provider plan access or workflow correctness. Operators must establish those prerequisites separately.

Google Workspace

The Google Workspace collector is read-only against two Admin SDK surfaces: the Directory API (user inventory, admin roles, 2-Step Verification status) and the Reports API (login activity). Set GOOGLE_WORKSPACE_ACCESS_TOKEN to a pre-minted OAuth 2.0 access token carrying two read-only scopes: https://www.googleapis.com/auth/admin.directory.user.readonly always, and https://www.googleapis.com/auth/admin.reports.audit.readonly when --login-window-days is greater than 0. The collector never mints or refreshes a token itself, so a very long enumeration against a very large tenant can outlive the token's roughly one-hour lifetime.

It emits six findings: user inventory, inactive accounts, admin accounts, super admin 2-Step Verification enrollment, tenant-wide 2-Step Verification enrollment, and login activity. --login-window-days (default 30, range 0-180) controls how far back the Reports API pull looks; setting it to 0 skips the Reports API entirely, so no login-activity finding is produced and the manifest records the omission rather than treating it as an error.

Four blind spots are documented on the collector: the pre-minted token has no refresh path; 2-Step Verification is reported as enrolled/enforced booleans, not the method in use; login activity is bounded by Google's roughly 180-day retention window; and --max-users / --max-login-events truncate very large tenants (the affected finding records truncated).

The SQL adapter takes --adapter, a password-free --connection-uri, and reads the password from --password-env:

evidentia collect sql --adapter postgres --connection-uri postgres://reader@db.example.com/app --output db-findings.json

SQLite is the exception — no auth, no password env var; pass the database file path as the connection URI:

evidentia collect sql --adapter sqlite --connection-uri /var/lib/app/data.db --output sqlite-findings.json

Step 4 — Fold findings into a gap analysis

The payoff: pass a findings file to evidentia gap analyze with --format oscal-ar and each finding is embedded in the OSCAL Assessment Results back-matter with a SHA-256 digest for chain-of-custody:

evidentia gap analyze --inventory my-controls.yaml --frameworks nist-800-53-rev5-moderate --findings findings.json --format oscal-ar --output assessment-results.json

See Run a gap analysis for the full workflow.

Step 5 — Ingest or emit OCSF

Pull third-party OCSF findings (Prowler, AWS Security Hub) in with collect ocsf. The --input accepts a local file path or an https:// URL; URL mode keeps the --block-private-ips SSRF guard on by default:

evidentia collect ocsf --input prowler.ocsf.json --output findings.json

Push Evidentia findings out to an OCSF Compliance Finding bundle with collect convert:

evidentia collect convert --input findings.json --format ocsf --output findings.ocsf.json

OCSF has its own dedicated guide — see Ingest OCSF for the round-trip and SIEM-ingest path, and Emit OCSF detection findings for the export side.

Running collectors in the web console

Everything above also works from the browser. Start the server with evidentia serve and open the Collect screen from the sidebar (under Connect, route /collect). Its nine tabs are Collectors, Entra/M365, Storage retention, Enterprise retention, OCSF ingest, Nessus scan, Greenbone report, Convert and Status. The Entra/M365 and Storage retention tabs retain the full result alongside the finding cards.

The Collect screen

The auth gate (why your Run buttons may be disabled)

Collectors make credentialed, network-egressing calls, so the console refuses to run them on an unauthenticated deployment. The page reads the backend's auth_configured flag and, when it is false, shows a red "Collectors disabled" banner and disables every credentialed Run button. To enable them, configure API authentication by pointing EVIDENTIA_API_AUTH_TOKEN_FILE at a token file and restarting evidentia serve. This mirrors the always-visible security-posture banner — it is a §4(c) safeguard so that anyone who can reach the local API cannot silently drive credentialed external calls.

Local parsing stays available without a configured AuthProvider: Convert, OCSF ingest with inline content, the Nessus and Greenbone export tabs, and Entra/M365 with only DLP export selected. Configured read-role checks still apply. The OCSF ingest URL mode is networked, so it is auth-gated like the credentialed collectors.

Collectors tab

  1. Choose a collector. Click a provider pill (AWS, GitHub, Okta, Google Workspace, PostgreSQL, Databricks, Snowflake, Vanta, Drata, BitSight, SecurityScorecard). Each card says where its credentials come from (e.g. "Token via server $GITHUB_TOKEN").
  2. Fill the non-secret parameters. The form carries only fields like region, repo, org URL, connection URI (without a password), or account/user — never a secret. Required fields are marked; the Run button stays disabled until they are filled (and until auth is configured).
  3. Confirm, then run. Because a run hits a live external API, the button is a two-step: clicking Run collector reveals a red Confirm — run collector button (and a Cancel). Confirming issues the run; the page shows Running… and then a finding count with per-finding cards (severity, source system, title, description, resource id). Errors — including the provider's own message — are surfaced inline as escaped text.

OCSF ingest tab

Choose Inline content (paste OCSF JSON — a single finding object or an array; parsed locally, no network) or URL (fetch from an https:// endpoint). URL mode shows a Block private IPs (SSRF guard) checkbox that is checked by default; unchecking it pops a warning that the URL may resolve to a private / loopback / link-local / metadata address — only opt out for a trusted internal endpoint. Click Ingest OCSF to run.

Convert tab

Paste a findings document (a single SecurityFinding or an array), set the output format (currently ocsf), and click Convert. This round-trips through the OCSF mapping layer entirely locally — no network, no credentials — and prints the converted JSON.

Status tab

Reports which collectors are installed and which credentials are configured on the server — as booleans plus the env-var name a token was sourced from. It never returns a token value. Use it to confirm a provider is ready before you try to run it.

Under the hood the console calls POST /api/collectors/<provider>/collect (and /api/collectors/ocsf/collect, /api/collectors/convert, GET /api/collectors/status) — the same engine the CLI drives, so the two paths produce identical findings.

What's next

Got stuck?

  • Console Run buttons are greyed out / "Collectors disabled" banner: the deployment is unauthenticated. Set EVIDENTIA_API_AUTH_TOKEN_FILE and restart evidentia serve, and front the console with a reverse proxy that injects the bearer header (the console sends none itself; see the serve guide). Local-only Convert and OCSF inline ingest stay enabled regardless.
  • ... collector not installed. Run pip install ... — install the provider extra named in the message (e.g. evidentia-collectors[aws], evidentia-core[ocsf]).
  • "Env var '…' is not set or is empty" — the server has no credential for that provider. Export the named env var (CLI) or set it in the server environment (console) and re-run; confirm with the Status tab.
  • An OCSF URL is refused / SSRF error — the host resolved to a private / loopback / link-local / metadata address and the default guard blocked it. Use a public URL, or pass --allow-private-ips (CLI) / uncheck Block private IPs (console) only for a trusted internal endpoint.
  • A finding shows compliance_status: unknown: inspect its source limitations and diagnostics. Some collectors use this for an indeterminate sub-check. Storage retention observations always retain unknown compliance status because configuration alone does not assess object enforcement.