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.accessaudit event, and grant creation and revocation write one too.
Platform scope or tenant scope
Choose the narrower one that lets the assessment proceed.
| Scope | What the assessor can see |
|---|---|
platform | The whole-platform compliance surfaces (every tenant). |
tenant | The 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:
| Method | Path | What it does |
|---|---|---|
POST | /v1/compliance/auditor-grants | Create a grant (201). |
GET | /v1/compliance/auditor-grants | List all grants, newest first. |
POST | /v1/compliance/auditor-grants/{grant_id}/revoke | Revoke 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 with422, not shortened; - an unknown
user_idis404(AUDITOR_USER_NOT_FOUND); scopeis validated toplatformortenant, andtenant_idis required for a tenant grant;data_content_granteddefaults tofalse— 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:
- Create the assessor's account the normal way, and have them confirm their tenant (the tenant the account lives in).
- From the Auditor access page (platform admins only), pick that account, choose scope, set an expiry within 90 days, and decide on data content.
- 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/profilesandGET /v1/platform/compliance/statusGET /v1/platform/compliance/time-syncGET /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.
Related pages
- Secure configuration profiles — what the assessor's profile view is comparing against.
- SIEM hookup — where the
auditor.accessevents go. - FIPS mode at install — the crypto posture the assessor will ask about.
- Access reviews — the recurring review the grant itself should appear in.