generated from coulomb/repo-seed
Implement identity canon alignment
This commit is contained in:
118
docs/canon-interface-card.yaml
Normal file
118
docs/canon-interface-card.yaml
Normal file
@@ -0,0 +1,118 @@
|
||||
subsystem: user-engine
|
||||
description: >
|
||||
NetKingdom identity-domain integration layer for user, account, identity-link,
|
||||
tenant, membership, profile, lifecycle, and evidence-facing context.
|
||||
status: candidate
|
||||
owner: codex
|
||||
updated: "2026-06-05"
|
||||
|
||||
implements:
|
||||
- identity-canon conceptual model as an implementation-facing domain facade
|
||||
- InfoTechCanon user-engine evaluation pack
|
||||
- small-saas user-management alignment surface
|
||||
|
||||
produces:
|
||||
- User
|
||||
- Account
|
||||
- Identity Record
|
||||
- Scoped Identifier
|
||||
- Profile
|
||||
- Tenant
|
||||
- Membership Relationship
|
||||
- Authenticated Subject reference
|
||||
- Authorization Principal reference
|
||||
- Evidence Source reference
|
||||
- Access Grant or grant-like membership fact
|
||||
|
||||
consumes:
|
||||
- NetKingdom IAM Profile claims
|
||||
- verified issuer and subject identifiers
|
||||
- assurance and principal type claims
|
||||
- authorization decisions and obligations
|
||||
- policy, control, review, exception, and evidence references
|
||||
- lifecycle task references from downstream task systems
|
||||
- platform audit and event sinks
|
||||
|
||||
owned_concepts:
|
||||
user_record: User-engine local user record mapped to identity-canon User as a convenience term.
|
||||
account_record: Operational account state for a user-engine scope.
|
||||
external_identity_link: Source-specific issuer and subject link to a user record.
|
||||
profile_value: Scoped profile or preference value.
|
||||
membership_fact: User-domain relationship to tenant, team, application, or scope.
|
||||
identity_context: Canon-facing read model over user, account, actor, subject, principal, scope, memberships, profile, and evidence references.
|
||||
|
||||
mapped_not_owned:
|
||||
Actor: Consumed from verified identity claims and represented as canon reference.
|
||||
Authenticated Subject: Projected from issuer and subject after authentication.
|
||||
Authorization Principal: Projected for the authorization system; final decisions remain outside user-engine.
|
||||
Policy: Referenced from authorization/governance systems.
|
||||
Control: Referenced from security/governance systems.
|
||||
Evidence Source: Referenced from audit, review, approval, or verification systems.
|
||||
AccessReview: Referenced from governance or review systems.
|
||||
Organization: Referenced when tenants, teams, or users map to organization systems.
|
||||
Credential: Explicitly not stored or lifecycle-managed by user-engine.
|
||||
|
||||
accepted_relationships:
|
||||
- identity_link
|
||||
- belongs_to_tenant
|
||||
- authenticates_as
|
||||
- evaluated_as
|
||||
- member_of
|
||||
- role_label
|
||||
- scoped_to
|
||||
- governed_by
|
||||
- implemented_by
|
||||
- evidenced_by
|
||||
- creates_task
|
||||
|
||||
emitted_events:
|
||||
- user.created
|
||||
- account.status_changed
|
||||
- tenant_account.status_changed
|
||||
- identity.linked
|
||||
- membership.added
|
||||
- profile.value_set
|
||||
- application.registered
|
||||
- catalog.published
|
||||
|
||||
required_identifiers:
|
||||
actor_key: "issuer + subject"
|
||||
user_id: "opaque user-engine user id"
|
||||
account_id: "opaque user-engine account id"
|
||||
identity_id: "opaque user-engine external identity id"
|
||||
tenant: "NetKingdom-aligned tenant or platform scope"
|
||||
application_id: "registered application id when projection is application-scoped"
|
||||
correlation_id: "operation-level audit and event correlation id"
|
||||
|
||||
mapping_rules:
|
||||
- Resolve source terms such as user, group, role, tenant, subject, and principal into identity-canon layers before exposing them as implementation concepts.
|
||||
- Keep account records, authenticated subjects, and authorization principals distinct even when they share issuer or subject identifiers.
|
||||
- Treat memberships as relationship facts that may produce grant-like access facts, not as final authorization decisions.
|
||||
- Preserve source system, scope, lifecycle state, and evidence reference whenever a relationship affects access, privacy, or lifecycle.
|
||||
- Link policy, control, review, exception, and task concepts by reference unless user-engine is the actual source of truth.
|
||||
|
||||
validation_rules:
|
||||
- User, Account, Actor, Authenticated Subject, Authorization Principal, Tenant, Team, Membership, and Profile must remain distinguishable in the identity context read model.
|
||||
- Tenant-scoped privileged membership must expose scope and evidence or an explicit evidence gap.
|
||||
- Cross-tenant context must be denied unless the actor is a platform operator.
|
||||
- Claims enrichment projections must not imply token issuance ownership.
|
||||
- Credential, MFA, policy decision, and durable platform audit ownership must remain outside user-engine.
|
||||
|
||||
source_of_truth:
|
||||
user_records: user-engine
|
||||
account_state: user-engine
|
||||
external_identity_links: user-engine
|
||||
profile_values: user-engine
|
||||
membership_facts_created_here: user-engine
|
||||
authentication: NetKingdom IAM infrastructure
|
||||
credential_assurance: NetKingdom IAM/security infrastructure
|
||||
authorization_decisions: NetKingdom authorization infrastructure
|
||||
policy_and_control_definitions: NetKingdom governance/security infrastructure
|
||||
durable_platform_audit: NetKingdom audit infrastructure
|
||||
organization_authority: NetKingdom organization or directory systems
|
||||
|
||||
known_deviations:
|
||||
- User remains a local implementation class even though identity-canon treats user as a non-root convenience term; mappings must state whether it represents actor-facing profile holder, account owner, or local user record.
|
||||
- Access Grant is currently a grant-like reference derived from memberships, not a durable authorization grant table.
|
||||
- Evidence Source references currently derive from local audit records unless an external evidence exporter is supplied.
|
||||
- AccessReview, Policy, Control, Exception, and lifecycle Task are references or gaps, not first-class owned records.
|
||||
103
docs/canon-mapping.md
Normal file
103
docs/canon-mapping.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Canon Mapping
|
||||
|
||||
Status: candidate
|
||||
Updated: 2026-06-05
|
||||
|
||||
This document maps current `user-engine` implementation concepts to
|
||||
identity-canon and InfoTechCanon concepts. It is intentionally explicit about
|
||||
owned facts, consumed facts, references, and gaps.
|
||||
|
||||
## Mapping Stance
|
||||
|
||||
`identity-canon` treats `User` as a convenience term, not the root concept.
|
||||
`user-engine` keeps the existing `User` implementation class for compatibility,
|
||||
but exposes canon-facing context through `identity_context` so consumers can see
|
||||
the distinct account, actor, subject, principal, tenant, membership, profile,
|
||||
and evidence references.
|
||||
|
||||
## Entity Mapping
|
||||
|
||||
| user-engine concept | Canon concept | Ownership | Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| `Actor` | Actor | consumed/reference | Normalized from verified IAM claims; not persisted as source of truth. |
|
||||
| `Actor.issuer + Actor.subject` | Authenticated Subject / Scoped Identifier | consumed/reference | Protocol-level identity after authentication. |
|
||||
| `User` | User convenience term / profile holder | owned local record | Not treated as Natural Person unless a future mapping proves that relationship. |
|
||||
| `Account` | Account | owned | Operational account state for the user-engine scope. |
|
||||
| `TenantAccount` | Account scoped to Tenant | owned | Tenant-local account lifecycle state. |
|
||||
| `ExternalIdentity` | Identity Record / Scoped Identifier / Synonymity Assertion seed | owned link | Links issuer-subject pairs to local user records without destructive merge. |
|
||||
| `Application` | Scope / Application Service reference | owned local registry | Application-specific profile consumer and catalog owner. |
|
||||
| `ApplicationBinding` | Trust Relationship / integration binding | owned local registry | Binds user-engine app IDs to external clients, protected systems, events, and catalogs. |
|
||||
| `Membership` | Membership Relationship | owned when created here | Relationship from user/account context to tenant, team, application, group, or other scope. |
|
||||
| `Membership.kind` | Role label / grant-like fact | owned local label | Role-like string is not a final authorization decision. |
|
||||
| `ProfileValue` | Profile | owned | Scoped presentation or preference value. |
|
||||
| `Catalog` / `AttributeDefinition` | Profile schema / governance metadata | owned | Attribute ownership, sensitivity, visibility, and mutability metadata. |
|
||||
| `AuthorizationRequest` | Authorization request | emitted/consumed | Sent to authorization port; policy decision remains external. |
|
||||
| `AuthorizationDecision` | Authorization decision | consumed/reference | Enforced locally; decision authority remains external. |
|
||||
| `AuditRecord` | Evidence Source | owned local evidence, exportable | Local operational evidence; durable platform audit is external. |
|
||||
| `OutboxEvent` | Lifecycle event / evidence source | owned local event | Integration event queue for downstream systems. |
|
||||
|
||||
## Relationship Mapping
|
||||
|
||||
| Relationship | Source | Target | Implementation source |
|
||||
| --- | --- | --- | --- |
|
||||
| `identity_link` | Identity Record | User | `ExternalIdentity.user_id` |
|
||||
| `belongs_to_tenant` | User or Account | Tenant | `TenantAccount` and tenant-scoped operations |
|
||||
| `authenticates_as` | Account | Authenticated Subject | normalized IAM claims |
|
||||
| `evaluated_as` | Authenticated Subject | Authorization Principal | `identity_context` principal projection |
|
||||
| `member_of` | User | Team / Group / Scope | `Membership(scope_type, scope_id)` |
|
||||
| `role_label` | Membership Relationship | Role | `Membership.kind` |
|
||||
| `scoped_to` | Access Grant or grant-like fact | Tenant / Scope | `Membership.tenant` and operation tenant |
|
||||
| `governed_by` | Grant-like fact / decision | Policy reference | external policy/control resolver gap |
|
||||
| `implemented_by` | Policy reference | Control reference | external policy/control resolver gap |
|
||||
| `evidenced_by` | Identity-domain claim or grant-like fact | Evidence Source | local audit or external evidence exporter |
|
||||
| `creates_task` | Evidence gap / integration gap | lifecycle task reference | lifecycle task sink gap |
|
||||
|
||||
## Read Model
|
||||
|
||||
`UserEngineService.identity_context(...)` returns the current implementation
|
||||
surface for canon-facing identity context. It includes:
|
||||
|
||||
- the normalized actor;
|
||||
- local user and account records;
|
||||
- external identity links;
|
||||
- tenant and optional application scope;
|
||||
- membership facts;
|
||||
- entity references for User, Account, Actor, Authenticated Subject,
|
||||
Authorization Principal, Tenant, Identity Record, Scoped Identifier, Team,
|
||||
Scope, Membership Relationship, and Role;
|
||||
- relationship references for identity link, tenant scope, authentication,
|
||||
principal evaluation, membership, role label, and grant-like scope;
|
||||
- access grant-like references derived from memberships;
|
||||
- evidence references derived from audit records;
|
||||
- an optional effective profile projection;
|
||||
- explicit gaps when evidence is missing.
|
||||
|
||||
## Current Gaps
|
||||
|
||||
- `Natural Person` is not modeled directly. A user record may represent a human
|
||||
profile holder, but that relationship is not currently asserted.
|
||||
- `Synonymity Assertion` is implicit in identity linking. Strong/weak link
|
||||
confidence, verification method, privacy scope, and revocation state are not
|
||||
first-class yet.
|
||||
- `Organization`, `Customer`, `Vendor`, and `Legal Entity` are referenced only
|
||||
through tenant, team, owner, or external system identifiers.
|
||||
- `AccessReview`, `Policy`, `Control`, `Exception`, and lifecycle `Task`
|
||||
references depend on external NetKingdom systems or future adapter
|
||||
implementations.
|
||||
- `Access Grant` is currently an exported grant-like reference derived from
|
||||
memberships. It is not a durable authorization grant table.
|
||||
- Evidence references currently derive from local audit records unless an
|
||||
`EvidenceReferenceExporter` is supplied.
|
||||
|
||||
## Validation Hooks
|
||||
|
||||
The first executable checks live in `tests/test_identity_canon_alignment.py`.
|
||||
They verify that:
|
||||
|
||||
- user, account, authenticated subject, authorization principal, tenant, team,
|
||||
membership, and grant-like references remain distinct;
|
||||
- service accounts project into service principals without becoming natural
|
||||
persons;
|
||||
- cross-tenant identity context is denied without platform scope;
|
||||
- claims-enrichment context can be read without implying token issuance
|
||||
ownership.
|
||||
@@ -10,9 +10,32 @@ HTTP or RPC adapters should preserve these operation names:
|
||||
- `resolve_tenant_context`, `set_tenant_account_status`, `add_membership`,
|
||||
`tenant_diagnostics`
|
||||
- `register_application`, `publish_catalog`
|
||||
- `set_profile_value`, `effective_profile`, `projection`
|
||||
- `set_profile_value`, `effective_profile`, `projection`, `identity_context`
|
||||
- `audit_records`, `outbox_events`
|
||||
|
||||
## Identity Context Contract
|
||||
|
||||
`identity_context` is the first canon-facing read model for NetKingdom
|
||||
identity-domain consumers. It resolves a verified actor into the local user,
|
||||
account, external identity links, tenant scope, memberships, optional
|
||||
application scope, optional effective profile, canon entity references,
|
||||
relationship references, grant-like membership facts, and evidence references.
|
||||
|
||||
The method keeps these concepts distinct:
|
||||
|
||||
- user-engine `User` record;
|
||||
- operational `Account`;
|
||||
- external `Identity Record` and scoped issuer/subject identifier;
|
||||
- `Actor` from verified claims;
|
||||
- `Authenticated Subject` projected from issuer and subject;
|
||||
- `Authorization Principal` projected for policy evaluation;
|
||||
- `Tenant`, `Team`, `Scope`, `Membership Relationship`, and `Role` references.
|
||||
|
||||
Evidence references are currently derived from local audit records. External
|
||||
policy, control, access-review, exception, and lifecycle task references belong
|
||||
to adapter contracts and remain non-owned unless a later workplan assigns
|
||||
source-of-truth responsibility to user-engine.
|
||||
|
||||
## Error Taxonomy
|
||||
|
||||
- `ValidationError`: caller supplied an invalid shape, state transition, or
|
||||
@@ -42,6 +65,9 @@ Every mutating service operation appends an audit record and outbox event with
|
||||
the same correlation id and resolved tenant. Authorization denials are audited
|
||||
without emitting outbox events.
|
||||
|
||||
Local audit records may be exported as identity-canon `Evidence Source`
|
||||
references. Durable platform audit custody remains outside user-engine.
|
||||
|
||||
## Migration Contract
|
||||
|
||||
The isolated store exposes `SCHEMA_VERSION = 0001_initial` and a `migrate`
|
||||
|
||||
62
docs/evidence-gap-examples.md
Normal file
62
docs/evidence-gap-examples.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Evidence Gap Examples
|
||||
|
||||
Status: candidate
|
||||
Updated: 2026-06-05
|
||||
|
||||
`user-engine` should not pretend missing review or governance material exists.
|
||||
When identity-domain context lacks evidence, policy, control, review, or task
|
||||
references, the gap must be explicit and handoff-ready.
|
||||
|
||||
## Gap Shape
|
||||
|
||||
```yaml
|
||||
gap_id: evidence:no-audit-records
|
||||
subject:
|
||||
concept: Account
|
||||
identifier: acct_example
|
||||
scope: tenant:acme
|
||||
reason: No local audit or external evidence reference supports this identity-domain claim.
|
||||
proposed_disposition: create_or_link_lifecycle_task
|
||||
owner: user-engine adapter boundary
|
||||
```
|
||||
|
||||
## Privileged Membership Without External Review
|
||||
|
||||
```yaml
|
||||
gap_id: review:tenant-admin-membership
|
||||
subject:
|
||||
concept: Access Grant
|
||||
identifier: mem_example
|
||||
scope: tenant:acme
|
||||
reason: Tenant admin membership has local audit evidence but no external access review reference.
|
||||
proposed_disposition: link AccessReview through EvidenceReferenceExporter or create review task through LifecycleTaskSink.
|
||||
```
|
||||
|
||||
## Policy Or Control Reference Missing
|
||||
|
||||
```yaml
|
||||
gap_id: control:tenant-isolation-reference
|
||||
subject:
|
||||
concept: Membership Relationship
|
||||
identifier: mem_example
|
||||
scope: tenant:acme
|
||||
reason: Membership is tenant-scoped, but no external policy/control reference was supplied.
|
||||
proposed_disposition: resolve policy and control through PolicyControlReferenceResolver.
|
||||
```
|
||||
|
||||
## Lifecycle Task Handoff
|
||||
|
||||
```yaml
|
||||
task_reference:
|
||||
concept: Task
|
||||
identifier: task_from_lifecycle_sink
|
||||
source_gap: review:tenant-admin-membership
|
||||
summary: Review tenant-admin membership for tenant:acme.
|
||||
evidence:
|
||||
- concept: Evidence Source
|
||||
identifier: aud_example
|
||||
```
|
||||
|
||||
These examples are intentionally adapter-neutral. The task, review, policy, and
|
||||
control source of truth belongs to the surrounding NetKingdom systems unless a
|
||||
future workplan assigns one of those responsibilities to `user-engine`.
|
||||
55
docs/identity-domain-naming-decision.md
Normal file
55
docs/identity-domain-naming-decision.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Identity Domain Naming Decision
|
||||
|
||||
Status: candidate
|
||||
Decision date: 2026-06-05
|
||||
|
||||
## Context
|
||||
|
||||
`user-engine` is moving from a narrow user/profile service toward a NetKingdom
|
||||
identity-domain integration layer. That raises the question of whether the
|
||||
repository should be renamed to `identity-engine`, `identity-domain-engine`, or
|
||||
`organization-engine`.
|
||||
|
||||
## Decision
|
||||
|
||||
Keep the repository named `user-engine` for USER-WP-0007 implementation.
|
||||
|
||||
Treat `identity-engine` or `identity-domain-engine` as future candidate names
|
||||
only after the canon interface card, mapping export, identity-context read
|
||||
model, NetKingdom adapter contracts, and conformance tests are established and
|
||||
reviewed.
|
||||
|
||||
Do not use `organization-engine` for this scope.
|
||||
|
||||
## Rationale
|
||||
|
||||
- `user-engine` is already the implemented package, module, docs, and workplan
|
||||
identity.
|
||||
- The current implementation still owns user-domain facts: users, accounts,
|
||||
identity links, profiles, memberships, catalogs, projections, audit, and
|
||||
events.
|
||||
- `identity-engine` could imply ownership of the full identity provider,
|
||||
credential lifecycle, federation, MFA, token issuance, and IAM substrate unless
|
||||
the boundary is already well proven.
|
||||
- `organization-engine` would imply ownership of organization, HR, authority,
|
||||
responsibility, reporting, legal entity, customer, vendor, and community
|
||||
modeling. Those are adjacent canon concepts, not this repo's current source of
|
||||
truth.
|
||||
|
||||
## Rename Criteria
|
||||
|
||||
Revisit the name when all of the following are true:
|
||||
|
||||
- consumers primarily use the identity-context API rather than only user/profile
|
||||
APIs;
|
||||
- NetKingdom IAM, authorization, audit, and evidence adapters are stable;
|
||||
- identity-canon mappings are validated by executable scenarios;
|
||||
- docs consistently describe the repo as an identity-domain facade and not as an
|
||||
identity provider;
|
||||
- downstream consumers would be misled by the old `user-engine` name.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Existing imports, package names, workplans, and docs remain stable.
|
||||
- The intent and interface card carry the strategic direction explicitly.
|
||||
- Naming pressure becomes a tracked decision rather than hidden scope drift.
|
||||
@@ -23,6 +23,9 @@ See also the cross-repo assessment in the net-kingdom repo:
|
||||
| `MembershipFactExporter` | outbound | Export user-engine-owned membership facts as read models for authorization systems. |
|
||||
| `EventOutbox` | outbound | Publish durable lifecycle/profile/catalog/membership events after commit. |
|
||||
| `AuditWriter` | local/outbound | Persist local audit and provide redacted summaries for platform audit sinks. |
|
||||
| `EvidenceReferenceExporter` | outbound | Export local audit/review material as identity-canon evidence references without owning the platform audit system. |
|
||||
| `PolicyControlReferenceResolver` | outbound | Resolve policy, control, review, exception, or waiver references for identity-domain traces. |
|
||||
| `LifecycleTaskSink` | outbound | Create or link lifecycle, review, remediation, or integration-gap work in a task system. |
|
||||
| `SecretProvider` | inbound | Load runtime secrets through environment/local config in standalone mode and scoped secret providers in platform mode. |
|
||||
|
||||
## Source-Of-Truth Rules
|
||||
@@ -33,6 +36,11 @@ See also the cross-repo assessment in the net-kingdom repo:
|
||||
- Identity providers are the source of truth for authentication-time subject,
|
||||
issuer, assurance, coarse role, and group claims.
|
||||
- Authorization systems decide whether an actor may perform an action.
|
||||
- Governance, security, and authorization systems own policy, control, review,
|
||||
exception, and waiver definitions. user-engine can reference them in identity
|
||||
context traces.
|
||||
- Task systems own lifecycle work queues. user-engine can create or link
|
||||
identity-domain work through an explicit task sink.
|
||||
- Event sinks and audit stores consume user-engine events; they do not become
|
||||
profile stores.
|
||||
|
||||
@@ -64,6 +72,41 @@ context:
|
||||
The domain layer should depend on this port, not on a concrete authorization
|
||||
client.
|
||||
|
||||
## Identity Context Shape
|
||||
|
||||
Every domain-facing identity context should be reducible to:
|
||||
|
||||
```yaml
|
||||
actor:
|
||||
issuer: string
|
||||
subject: string
|
||||
tenant: string
|
||||
principal_type: human | service | agent
|
||||
user:
|
||||
user_id: string
|
||||
account:
|
||||
account_id: string
|
||||
status: string
|
||||
identity_links:
|
||||
- issuer: string
|
||||
subject: string
|
||||
tenant: string
|
||||
application_id: string | null
|
||||
memberships:
|
||||
- scope_type: string
|
||||
scope_id: string
|
||||
kind: string
|
||||
canon_refs:
|
||||
entities: object
|
||||
relationships: object
|
||||
grant_like_refs: object
|
||||
evidence_refs: object
|
||||
gaps: [string]
|
||||
```
|
||||
|
||||
The context is a facade over NetKingdom IAM and security infrastructure. It
|
||||
does not issue tokens, decide authorization policy, or own credentials.
|
||||
|
||||
## Projection Types
|
||||
|
||||
- `self_service`: current-user view and allowed mutations.
|
||||
|
||||
@@ -14,6 +14,7 @@ projection, audit, and event behavior testable without a UI.
|
||||
| two_applications | Catalog ownership and projections prevent application data leakage. |
|
||||
| sensitive_redaction | Sensitive values are redacted in runtime and claims-enrichment projections. |
|
||||
| audit_event_replay | Mutations carry audit records, outbox events, and correlation ids. |
|
||||
| identity_canon_context | Actor, user, account, authenticated subject, authorization principal, tenant, membership, grant-like facts, and evidence references stay distinguishable. |
|
||||
|
||||
## Fixture Actors
|
||||
|
||||
|
||||
Reference in New Issue
Block a user