Skip to main content

Giving Your Assessor Read-Only Access

When an outside party needs to assess your compliance work, you do not hand them a normal admin account. MOD supports a dedicated access path for that: a grant that gives one account a read-only, time-limited view of the compliance surfaces. MOD enables your assessor's work; it does not certify anything on their behalf, and the grant is an access mechanism, not a compliance claim.

Everything about a grant is designed so that access cannot quietly grow or linger:

  • Time-boxed. An expiry is required, and grants are capped at 90 days. A request for longer is rejected rather than silently shortened.
  • Read-only by construction. A write from an auditor account is refused with a 403.
  • Scoped. Either the whole platform, or one named tenant.
  • Never deleted. Expiry and revocation are status changes on the grant record (active → expired / revoked), so the record of who looked at what stays in place.
  • Every visit recorded. Each auditor request writes an auditor.access audit event, and grant creation and revocation write one too.

Platform scope or tenant scope​

Choose the narrower one that lets the assessment proceed.

ScopeWhat the assessor can see
platformThe whole-platform compliance surfaces (every tenant).
tenantThe same surfaces, limited to the one tenant named on the grant.

A tenant-scoped grant needs a tenant_id; a grant whose scope does not cover the resource being requested is refused with a 403 and audited as grant_out_of_scope. A platform-scoped grant also covers a tenant-scoped surface.

The data-content flag, and its risk​

By default a grant carries no tenant data content. The assessor sees the compliance surfaces — conformance results, compliance reports, AI-transparency records, audit-log exports, platform settings, the evidence bundle — but not the substance of your workflows.

Checking the "Include tenant data content" box changes that: the assessor can then read files, cogs, run outputs and chat surfaces. That is real content leakage risk, so:

  • leave the flag unchecked unless the assessment genuinely requires it. The default grant is evidence and metadata only;
  • if you do check it, keep the window short (the cap is 90 days, but a data-content grant that long is longer than most assessments need), and revoke it as soon as the assessor is done;
  • requests for data content without the flag are refused with a 403 and audited as data_content_not_granted, so a refusal is visible in the audit trail rather than silent.

Granting one from the API​

The same grant the page writes is available to platform admins as three endpoints under /v1/compliance/auditor-grants:

MethodPathWhat it does
POST/v1/compliance/auditor-grantsCreate a grant (201).
GET/v1/compliance/auditor-grantsList all grants, newest first.
POST/v1/compliance/auditor-grants/{grant_id}/revokeRevoke one grant.

The create body:

{
"user_id": 42, // the assessor's existing account
"scope": "platform", // "platform" or "tenant"
"tenant_id": 7, // required when scope = "tenant"
"expires_at": "2026-12-01T00:00:00Z", // explicit expiry, or
"days": 30, // days from now (1..90) when expires_at is null
"data_content_granted": false // explicit data-content flag
}

Behaviour worth knowing before you call it:

  • an expiry beyond 90 days (auditor_access.MAX_GRANT_DAYS) is rejected with 422, not shortened;
  • an unknown user_id is 404 (AUDITOR_USER_NOT_FOUND);
  • scope is validated to platform or tenant, and tenant_id is required for a tenant grant;
  • data_content_granted defaults to false — the flag is only ever set explicitly, and the create is audited with the grant id, scope, expiry and the flag;
  • revoking is idempotent (an already-revoked grant returns the same status) and records revoked_at / revoked_by; the grant row is never deleted.

The response carries id, user_id, scope, tenant_id, granted_by, expires_at, data_content_granted, status (active / expired / revoked), revoked_at, revoked_by and created_at.

How the assessor logs in​

There is no special "auditor account type". The assessor signs in with an ordinary account, created through your usual identity setup like any other user. The grant is what unlocks access for that account; without one, the compliance surfaces answer 403 (Auditor access required (or platform admin).).

Practically:

  1. Create the assessor's account the normal way, and have them confirm their tenant (the tenant the account lives in).
  2. From the Auditor access page (platform admins only), pick that account, choose scope, set an expiry within 90 days, and decide on data content.
  3. Send the assessor the normal sign-in address. Nothing about the login itself is different.

The Auditor access page​

The Dashboard page is at #auditor-access (CORE/Dashboard/pages/auditor-access.html, served by js/compliance-auditor-access.js) and is shown to platform admins. It lists grants (filterable by status: active / expired / revoked) with assessor, scope, tenant, expiry, data-content flag, status and who granted it, and offers a Grant access form and a Revoke action per grant.

Revoking is a confirmation against one grant; it flips the status and records revoked_at and revoked_by. Revoking an already-revoked grant is idempotent. Grants are never removed from the list, which is why the status filter exists.

What the assessor can export​

Two exports matter for an assessment.

Evidence bundle​

POST /v1/compliance/evidence-bundle returns a signed zip (mod-evidence-bundle-<timestamp>.zip). The body is:

{
"tenant_id": "…", // optional
"window_start": "2026-01-01T00:00:00Z",
"window_end": "2026-06-30T00:00:00Z"
}

The window is required, window_end must be after window_start, and a window longer than 366 days is rejected. The bundle holds one JSON file per section under sections/ — profiles, conformance, audit extract, access review, crypto status, images, patch log, restore tests, ports, AI model inventory, compliance reports — plus a manifest.json listing each section and its SHA-256. The manifest is signed with a server-side Ed25519 key, and manifest.sig and pubkey.pem ride along so the bundle can be verified offline. A section whose source is unavailable degrades to a {"status": "unavailable", "reason": …} entry; the bundle as a whole does not fail.

The POST here is a read that generates an export, and it is the one write-shaped path an auditor account is allowed. The export itself is audited as a compliance.evidence_bundle.export event with the window, tenant and byte count.

Feature reference​

GET /v1/compliance/feature-reference?format=csv|oscal returns the feature-to- control mapping as CSV or as an OSCAL component definition. It is generated from the conformance check registry, so the mapping cannot drift from the checks it describes. Note that this endpoint is a platform admin surface: an auditor grant does not unlock it. If your assessor needs the mapping, export it yourself and include it with the bundle.

Both formats state that a feature supports a control. Nothing in MOD states that a control is satisfied, and the exports should not be read that way.

After the assessment​

Revoke the grant when the assessor is done, even if it still has time left. Expiry is checked at every request (an unrevoked grant past its deadline is marked expired at that moment), so an unrevoked grant does eventually stop working — but revoking makes the end of access explicit in the audit trail.

To review what an assessor actually touched, look for auditor.access events in the audit log: each carries the request route, method, scope, the resulting status, the grant id, and a reason when a request was refused.

Surfaces a grant unlocks​

The grant is checked by the shared dependency (CORE/API/dependencies.py:require_auditor_or_admin), so the read-only surfaces it admits are the ones that use it:

  • GET /v1/platform/compliance/profiles and GET /v1/platform/compliance/status
  • GET /v1/platform/compliance/time-sync
  • GET /v1/audit-logs/export
  • the conformance reads in routers/compliance_conformance.py
  • the AI-transparency reads in routers/ai_transparency.py

Anything not on that path answers 403 for an auditor account, and platform-admin surfaces such as POST /v1/compliance/auditor-grants, GET /v1/platform/compliance/crypto-status and GET /v1/platform/compliance/key-rotation stay admin-only. The grant is read-only except for the evidence-bundle export, which is the one write-shaped path an auditor account is allowed.