Skip to content

Latest commit

 

History

History
226 lines (200 loc) · 21 KB

audit.md

File metadata and controls

226 lines (200 loc) · 21 KB

Identity — Audit Coverage Matrix

Status: Global/contextual seed writers, internal directory and finite Role grant acts implemented. Current qualification and review state lives in the phase Status block. The User off-path catalogue, contextual requests and persistence exist. Derived from jointly Accepted ADR-0072, ADR-0073 and jointly Accepted ADR-0076 / ADR-0077, with Standard 18. Part of the module spec. The internal fixed-seed prerequisite boundary derives from ADR-0080; new qualification remains in the phase Status block. The distinct internal fixed-origin completion purpose derives from Accepted ADR-0081.

The baseline MUST floor applies. IdentityAuditCatalogSource declares actual operations: catalogue-to-matrix coverage is total. Audit slugs are not additional permission keys. The internal ListMembershipsQuery has a real MUST catalogue entry, ordinary ReadWrite adapter and declared HTTP admission. The two grant commands have real MUST catalogue entries and contained Role diffs. Membership detail, both profile writers, status and assignment replacement have actual typed MUST bindings; exact own-profile reading is separately registered Off. (off-path) marks a central event without a MediatR request. Catalogue → matrix remains total; the reverse request join applies only when the request exists, and off-path events register by slug when their writer lands.

Resource Operation Class Why
User/global immutable subject identity.user.create (off-path) MUST (security-event) ADR-0072's confined creation/adoption owner and central non-success reconciliation; success shares the User transaction. Exact global witness, source and retention contract stays there.
Role including grants identity.role.initialize MUST (security-event) InitializeSeedRole; one Role transaction, with contained grants.
Membership including Profile/Assignments identity.membership.create_first_seed_admin MUST (security-event) CreateFirstSeedAdminMembership; one Membership transaction.
Membership including Profile/Assignments identity.membership.create_seed MUST (security-event) CreateSeedMembership; one Membership transaction.
MembershipProfile, captured under Membership identity.membership_profile.set_seed_profile MUST (update) SetSeedMembershipProfile; same Membership transaction. The slug matches the gated sub-resource while the row's subject remains its owning aggregate.
Authorization decision identity.authorization.deny (off-path) MUST (security-event) Central HTTP/application/resource denial owner; one decided invocation event, separate from ordinary plural resource intents. No tenant override or host suppression budget.
Membership directory identity.membership.list MUST (read-sensitive) Internal ListMembershipsQuery under existing Tenant identity.membership.admin; ordinary ReadWrite owner commits its row before disclosure. No HTTP activation follows from its catalogue entry.
Role including grants identity.role.change_grants MUST (security-event) ChangeRoleGrantsCommand; one Role root and contained grant diff, expected row version and fresh post-lock authority recheck; success/audit share the transaction.
Role including grants identity.role.adopt_manifest MUST (security-event) AdoptRoleGrantManifestCommand; exact first v2 delta, one Role root and contained marker/grant capture; historical v1/repeated adoption refuses, with no automatic registry/seed upgrade.
Current-branch Membership directory identity.membership.list_organization MUST (read-sensitive) Exact branch-scoped member list under an admitted Tenant-or-Organization alternative; no Tenant read hatch on this endpoint.
Membership detail identity.membership.read MUST (read-sensitive) GetMembershipDetailQuery; ordinary ReadWrite owner commits before contextual profile/assignment disclosure. Only the matched Tenant clause may widen reads; Organization admission stays scoped.
MembershipProfile, captured under Membership identity.membership_profile.write MUST (update) Separate SetMembershipProfileCommand and SetOwnMembershipProfileCommand bindings share this slug. Exact Active target, contextual fields and expected version; one Membership root, with contained profile capture on the business transaction.
Membership including assignments identity.membership.replace_role_assignments MUST (security-event) ReplaceMembershipRoleAssignmentsCommand; current Role graph/whole-grant delegation, expected version and ordered fences; retained children and actual contained diffs share the transaction.
Membership lifecycle identity.membership.change_status MUST (security-event) ChangeMembershipStatusCommand; suspend/reactivate/revoke with fresh authority, actual User admission, exact scope and last-admin guards; Revoked is terminal.
Membership context admission identity.membership.admit_session_scope MUST (security-event) AdmitNativeSessionScopeCommand; initial context selection/explicit switch under the native source. The ordinary ReadWrite owner commits before its association witness. Prefer the exact branch Membership when present, otherwise the covering tenant-wide Membership; designate that actual resource. This event proves API admission, not browser cookie delivery.
Role summaries identity.role.list MUST (read-sensitive) Current Role-read admission before finite template disclosure.
Role detail identity.role.read MUST (read-sensitive) Current Role-read admission before grants/release-marker disclosure.
Permission registry and release choices identity.role.list_permissions MUST (read-sensitive) Tenant role-admin admits the exact finite registry/release configuration, separately from own-capability hints.
Original Membership outcome identity.membership.read_receipt MUST (read-sensitive) Current original-target disclosure authority before stored successful bytes; terminal target facts only for this receipt.
Original MembershipProfile outcome identity.membership_profile.read_receipt MUST (read-sensitive) Exact stored original Membership and self/admin predicate; no later successor substitution.
Original Role outcome identity.role.read_receipt MUST (read-sensitive) Fresh Role receipt disclosure admission; does not reexecute grant/adoption mutation.

Invitation bindings

The P03-4 contract derives from ADR-0093. Invitation consumers and the four email job roots have actual policy and catalogue registrations; inspection and own-result navigation are explicit Off. The phase Status owns delivery.

Resource Operation Class Why
Invitation identity.invitation.create MUST (security-event) CreateInvitationCommand; offer, generation-1 verifier, encrypted envelope and identifier-only job share the ordinary business transaction and required audit.
Invitation identity.invitation.reissue MUST (security-event) ReissueInvitationCommand; new generation/token/envelope/job with current TTL; former verifier invalidates atomically, without raw secret replay.
Invitation identity.invitation.revoke MUST (security-event) RevokeInvitationCommand; terminal withdrawal; later Prepare refuses obsolete work, while already-prepared email may still arrive with an invalid link.
Invitation identity.invitation.accept MUST (security-event) AcceptInvitationCommand; central capture includes accepted actor, original Membership and acceptanceDisposition. The row shares the grant transaction.
Original Membership outcome identity.membership.admit_invitation MUST (security-event) Second central intent on acceptance. New Membership includes tracked children; already_member identifies the unchanged original Membership with a subject-only row, no fabricated change or arbitrary handler metadata.
Invitation preparation identity.invitation.prepare_email MUST (security-event) PrepareTenantInvitationEmailCommand / PrepareOrganizationInvitationEmailCommand; ordinary module-owned preparation records the exact current-generation submission intent before the external stage. No SMTP socket is opened inside its business transaction.
Invitation submission outcome identity.invitation.email_submission MUST (security-event) FinalizeTenantInvitationEmailCommand / FinalizeOrganizationInvitationEmailCommand; ordinary owner applies validated durable provider evidence to the exact Invitation. SMTP acceptance is submission only; ambiguous outcomes remain uncertain and retain occupancy. No private audit INSERT or provider receipt substitutes for this row.
Invitation directory identity.invitation.list MUST (read-sensitive) Administrative bounded offer list under current exact-scope authority before other-person disclosure.
Invitation detail/status identity.invitation.read MUST (read-sensitive) Administrative detail and bounded normalized current-generation submission evidence, through the owning port; no encrypted body, raw link or another envelope is disclosed.
Delegable Role summaries identity.invitation.list_invitable_roles MUST (read-sensitive) Exact delegation-limited ID/key/scope/version choices; no general Role/registry authority is inferred.
Original Invitation outcome identity.invitation.read_receipt MUST (read-sensitive) Fresh current original-target disclosure admission before protected replay; retained bytes contain no recipient credential/link.

InspectInvitationQuery and GetOwnInvitationResultQuery are explicit Off registrations, not OperationClass values or mutation rows. Pending inspection performs fresh verified UserInfo; accepted-result recovery checks the same Active actor, consumed verifier and original Active Membership, without Pending-only email/expiry/Role/inviter checks. Already Accepted is routed to Off before declaring mutation intents. A Pending mutation that sees Accepted after a race returns conflict with truthful failed-attempt evidence, never another successful acceptance row. No provider attempt receipt or UI poll declares a successful Membership mutation.

AcceptInvitationCommandHandler is the only added two-root exception: central plural MUST intents for Invitation and the actual Membership share one ordinary unit of work. No User/provider transaction joins it. A missing required row or failed audit rolls back the whole grant/consumption outcome. Raw email, token, verifier, ciphertext and SMTP response/exception text never enter audit values; redacted properties remain present to preserve that a change occurred. Typed closed provider outcomes and subject references are evidence, not free metadata. Provider claim/complete functions retain immutable operational receipts; the common audit composer remains the only audit owner.

Explicit Off reads. Contextual seed verification request types are registered Off before use; they inspect only the exact bounded declared seed facts, with no directory/provider profile. Ordinary existing-binding lookups create no mutation intent under ADR-0072. Off request registration is separate from MUST operation rows; no Off value is presented as an OperationClass or a MUST audit slug. GetOwnMembershipProfileQuery is registered Off and declared physically ReadOnly by Identity. It reads only the actor's exact current Active Membership profile, with no supplied target or NULL-org fallback. Its separate writer remains MUST and ReadWrite. GetOwnMembershipContextsQuery and GetOwnCapabilitiesQuery are also explicitly Off and physically ReadOnly; their bounded own-navigation responses have no ETag. Administration reads and receipts are no-store.

The separate closed prerequisite operation is internal to an already classified seed act, rather than a new Off request or externally disclosed sensitive read. It returns no raw editor IDs, relationship metadata or profile values. Existing seed mutation classifications, MUST floors, failed/denied outcomes and genuine unknown-COMMIT reconciliation remain unchanged; no separate successful read event or private receipt is added. Standard 18 owns the audit boundary; Standard 05 owns the metadata-only projection and restoration before results.

The distinct fixed-origin completion operation has one consumer, AdoptSeedAdministrationOriginCommand, without joining the eight pristine consumers. Identity's retained metadata/relationship checks remain internal on that adoption owner, with no profile/global/provider value projection or raw editor result. They add no Identity mutation, separate Off request, successful sensitive-read event or durable receipt. The adoption act retains its plural MUST evidence, refusal and genuine unknown-COMMIT contract; marker-2/exact-mapping repeats stop before mutation dispatch or new intents. Standard 05 owns source, lifetime and retained-local completion semantics; acceptance supplies no runtime qualification.

No seed command mutates a second root. Role grants travel in Role diffs; assignments/Profile travel in Membership diffs. Instance-qualified paths include /Membership/{id}/Profile, /Membership/{id}/RoleAssignments/{roleId} and /Role/{id}/Grants/{scope}~1{key}. The grant's composite local key uses the canonical RFC 6901 escape for its slash separator. Collection snapshots appear only when actually complete; partial loads cannot claim a complete collection. Stable resource/subject keys are references, not safe diagnostic labels. Global paths and non-success reconciliation follow ADR-0072's canonical owner.

Personal-data declarations

Step 2's actual mapped-property census declares a typed category or explicit None/purpose for every mapped property, including inherited actor references and owned children. This table assigns semantic review; it is not a completed census or a reflection/name heuristic.

Subject Personal/reference paths to classify Snapshot/diagnostic rule
User AuthorityId, raw provider_subject, subject key, actor and immutable audit linkage; no email/verification mirror Raw subject explicitly [PiiSensitive]; keys/actor are classified retained linkage, not diagnostic labels; canonical grants/encoding in Standard 05
Membership UserId, lifecycle/audit actor references and person-to-tenant/org relationship Explicit reference classifications; no diagnostic value capture
MembershipProfile Display name and locale preference Both personal scalars marked for snapshot redaction; fixed diagnostics
Assignment Membership/person linkage and assignment history Exact paths under Membership row; never log raw DTOs
Role/Grant Built-in key, capability scope, scoped keys, tenant and inherited actor references None only for reviewed nonpersonal metadata; actor/linkage paths stay classified
Invitation Recipient email; current/consumed verifier; inviter, acceptor, result Membership, Role/version and generation/job references Email/verifiers are redacted in snapshots; actor/relationship links remain classified; closed disposition is centrally captured, with no value-bearing diagnostics

No provider credentials, raw invitation token, browser binding, global active scope or dormant custom-field blob belongs in these models. Invitation verifiers remain the explicitly sensitive one-way credential fields described above. Publication does not make arbitrary tenant text diagnostically safe. SQL-only/control/vendor inventory remains in canonical Data Protection, not another durable-store list.

Translate expected conflicts/upstream failures to fixed bounded descriptors before L1/error-tracking sinks; retain no value-bearing original inner exception. Unexpected paths retain a fixed operational signal. Snapshot markers, name-based logging guards and LS0002 remain distinct; no global exception scrubbing is claimed.

Qualification and later owners

P03-1 Steps 2/4 prove actual root/child capture, MUST rollback, inherited references and sensitive/neutral-key nested canaries at each real sink: validation/response, logs, local archive, Sentry envelope and audit snapshot. Every sink receives a positive event. Preserve existing TenantSetting whole-value redaction. Steps 3/4 also extend the existing audit-interface/matrix controls for the central global seams, exact classifications and planted wrong-column, missing-global-row and child-capture controls; canonical signatures/SQL stay in Standard 05. No runtime test is claimed here.

P03-2's Accepted trusted evidence contract owns immutable provenance, fixed denial occurrence/time and exact full-row verification, pre-success barriers and refusal preservation. It keeps normal resource classification unchanged and AccountSite success Off. The central denial event and the internal directory/grant commands have actual catalogue entries; the phase record owns their qualification. P03-5 extends revision-aware dynamic values; P03-10 delivers applicable user-reference locators and export/ erasure/closure under separate authority. A stub or retained hash is not completion or anonymisation. The module table records current versus planned proof status.

Authorization Membership/Role IDs in metadata.authorization are retained personal linkage, outside the six-column redaction grant. Each row follows its own retention target: SecurityEvent seven years, ReadSensitive two years. Purge remains Phase 11 work; P03-10's Audit participant locates/reports surviving actor/subject linkage without metadata UPDATE authority. No email mirror or Platform/operator flag population is added.

Bounded entry and administration classifications

Accepted under ADR-0078/0079. Membership administration, current-branch directory, Role/registry and receipt consumers have actual catalogue bindings. The closed HTTP surface commits each required read event before response bytes; replay emits a fresh receipt read rather than another mutation event. The phase Status block owns qualification and review state. Existing User creation, Role grant/adoption and denial slugs keep their implemented classifications; their new consumers do not invent private audit writers. V2 adoption extends the existing Role adoption operation with the exact approved delta and same-transaction contained marker/grant capture.

Global-self lookup/context choices, current-tenant own contexts, exact own-profile reads and own-capability previews are explicitly Off, no-store self navigation. Their request types require Off catalogue registration before dispatch. An ordinary refresh's positive new-token association/AccountSite check preserves the original scope and remains Off; it does not call the audited admission operation. Initial selection/explicit switch alone produces the new admission security event. Bootstrap retains the existing central identity.user.create owner: actual creation/audit commit together, matching existing bindings declare no new creation intent, and failed/indeterminate creation follows central reconciliation. No User or session is inferred from a failed audit/unknown COMMIT.

Protected completed response replay performs a separately classified current receipt read. It checks the stored original target and commits a new MUST read event before disclosure; it never repeats the original mutation event or exchange headers. Failed read/audit retains the stored completion. The storage contract owns typed target persistence, reclamation and owner/fence lifetime.

Own context choices, association witnesses, stored receipt targets and copied page/response bodies remain personal/reference data where linkable. Off means no operation event, not anonymous data or diagnostic permission. SecurityEvent and ReadSensitive retention remain policy targets; Phase 11 owns automatic purge, while P03-10 owns applicable export/closure/linkage location. Acceptance does not qualify the new provider, database, browser, race or failure proofs.