Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ application relying-party registration.
- SAML/OIDC identity-provider desired-state validation and reconciliation;
- LDAP/Active Directory component preflight and desired-state reconciliation;
- OIDC relying-party preflight and secret-free desired-state reconciliation;
- audit and user-operation lock boundaries.
- audit and user-operation lock boundaries;
- hierarchical software-unit, menu, inheritance, and SSO-combination
authorization decisions consumed from Orgmetra assignment snapshots;
- app start-login / IdP discovery helper for relying parties;
- hashed programmable application tokens scoped to one software unit and API.

The core merge and SCIM layer depends on the narrow `AdminApi` protocol.
Product extensions are isolated behind `ProductAdminApi`; relying-party client
Expand Down Expand Up @@ -93,7 +97,11 @@ modules require neither protocol nor any network client.
`relying_party_sources`, `relying_party_apply_receipts`;
- merge audit: `account_merge_audit`;
- cross-process user mutation lock sidecar:
`user_operation_lock_state`.
`user_operation_lock_state`;
- hierarchical authorization grants:
`authorization_software_unit_grants`, `authorization_menu_grants`;
- SSO combination scopes: `authorization_sso_combination_scopes`;
- hashed programmable tokens: `application_access_tokens`.

Database objects and namespaces use descriptive two-word-or-longer snake_case
names.
Expand Down Expand Up @@ -178,9 +186,18 @@ profiles.
Each downstream RP is a separate trust boundary. The RP must validate the
Keyverse issuer, signature/algorithm, expiry, subject, and audience, map the
verified tenant (`org`/deployment mapping), apply resource and purpose ABAC,
and then apply bounded role/scope/group RBAC. A registered client or accepted
mapper receipt never grants authorization by itself; see ADR-0008 for the
non-fork application matrix and remediation gates.
and then apply bounded role/scope/group RBAC. A registered client, accepted
mapper receipt, or Keyverse PDP decision never grants authorization by itself;
see ADR-0008 for the non-fork application matrix and remediation gates.
ADR-0010 adds issuer-side hierarchical attributes (`group_company`,
`legal_entity`, `business_unit`, `team`, `person`, `org_path`) and decisions.
Those names are distinct from the unmerged LineageWeave `role`/`org`/`workspace`
profile reserved as ADR-0009 on PR #100. Orgmetra remains employment truth;
Keyverse binds an opaque subject and does not copy the Orgmetra tree.

Relying applications start brokered login through the Keyverse start-login
helper (ADR-0011) and may present software-unit-scoped programmable tokens
(ADR-0012) that are hashed at rest and never inherit org-tree grants.

## Account and provisioning invariants

Expand Down Expand Up @@ -246,6 +263,8 @@ explicitly documented deployment-controller responsibility.

Detailed decisions and evidence are maintained under:

- `docs/adr/` — accepted architecture decisions (0001–0008 plus 0010–0012;
0009 reserved for the unmerged LineageWeave profile);
- `docs/superpowers/specs/` — approved feature architecture;
- `docs/superpowers/plans/` — executable implementation plans;
- `docs/doctoring/` — standards interpretation and APA 7th traceability;
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ Keep a Changelog, and releases use semantic versioning.

### Added

- Hierarchical authorization plane (ADR-0010): software-unit ACL, menu
ABAC/RBAC decisions, SSO combination scopes, and most-specific org-path
inheritance consumed from Orgmetra assignment snapshots. ADR-0008 stays
the PEP boundary. Hierarchical attributes use `group_company`,
`legal_entity`, `business_unit`, `team`, `person`, and `org_path` so they
do not collide with the unmerged LineageWeave `role`/`org`/`workspace`
profile reserved as ADR-0009 on PR #100.
- App start-login helper (ADR-0011) that discovers enabled brokered IdPs from
the local registry and returns a Keycloak `kc_idp_hint` authorization URL
without metadata or discovery fetch.
- Programmable application tokens (ADR-0012) hashed at rest, purpose-bound,
software-unit and API scoped, rotatable, auditable, and never a password
substitute or inherited secret.
- ADR-0008 and the non-fork RP authorization matrix, requiring explicit
Keyverse token validation, tenant/resource ABAC, bounded RBAC, and
cross-tenant acceptance evidence per application.
Expand Down
1 change: 1 addition & 0 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Keyverse already has strong feature-specific specifications, doctoring, federati
| Requirements/evidence traceability | [`docs/TRACEABILITY.md`](docs/TRACEABILITY.md) |
| Architecture decisions | [`docs/adr/README.md`](docs/adr/README.md) |
| Federation onboarding | [`docs/federation-onboarding.md`](docs/federation-onboarding.md) |
| Authorization onboarding | [`docs/authorization-onboarding.md`](docs/authorization-onboarding.md) |
| RP onboarding | [`docs/rp-onboarding.md`](docs/rp-onboarding.md) |
| Account merge/unification | [`docs/merge-unification-flow.md`](docs/merge-unification-flow.md) |
| Standards/APA 7 evidence | [`docs/doctoring/`](docs/doctoring/) and [`docs/papers/`](docs/papers/) |
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,15 @@ See [`docs/federation-onboarding.md`](docs/federation-onboarding.md),
[`deploy/keycloak/README.md`](deploy/keycloak/README.md), and
[`deploy/templates/README.md`](deploy/templates/README.md).

An application starts brokered login through
`POST /federation/identity-providers:start-login` and then adds PKCE locally.
See [`docs/authorization-onboarding.md`](docs/authorization-onboarding.md).

### Onboard a relying party

See [`docs/rp-onboarding.md`](docs/rp-onboarding.md).
See [`docs/rp-onboarding.md`](docs/rp-onboarding.md). Software-unit ACL, menu
decisions, SSO combinations, and programmable application tokens are documented
in [`docs/authorization-onboarding.md`](docs/authorization-onboarding.md).

## Account unification & merge

Expand Down
57 changes: 55 additions & 2 deletions docs/ERD.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
# Keyverse Logical and Persistence ERD

**Status:** Accepted cross-cutting data model. Exact Keycloak internal schema remains Keycloak-owned.
**Last reviewed:** 2026-08-09
**Last reviewed:** 2026-08-18

Keyverse persists its own configuration, desired-state, receipts, merge audit, and user-operation locks while Keycloak/PostgreSQL owns canonical IdP users/sessions/clients/federation runtime state. This ERD models Keyverse-owned durable records and their relation to external Keycloak identities without pretending to own Keycloak's internal tables.
Keyverse persists its own configuration, desired-state, receipts, merge audit, user-operation locks, authorization grants, SSO combination scopes, and hashed application tokens while Keycloak/PostgreSQL owns canonical IdP users/sessions/clients/federation runtime state. Orgmetra remains the employment-tree system of record; Keyverse stores grants against org-path nodes and does not persist Orgmetra `organization_unit` rows as source of record. This ERD models Keyverse-owned durable records and their relation to external Keycloak identities without pretending to own Keycloak's internal tables.

```mermaid
erDiagram
IDP_CONFIG_ENTRY }o--|| TENANT_DEPLOYMENT : scoped_to
FEDERATION_SOURCE }o--|| TENANT_DEPLOYMENT : scoped_to
DIRECTORY_FEDERATION_SOURCE }o--|| TENANT_DEPLOYMENT : scoped_to
RELYING_PARTY_SOURCE }o--|| TENANT_DEPLOYMENT : scoped_to
AUTHORIZATION_SOFTWARE_UNIT_GRANT }o--|| TENANT_DEPLOYMENT : scoped_to
AUTHORIZATION_MENU_GRANT }o--|| TENANT_DEPLOYMENT : scoped_to
SSO_COMBINATION_SCOPE }o--|| TENANT_DEPLOYMENT : scoped_to
APPLICATION_ACCESS_TOKEN }o--|| TENANT_DEPLOYMENT : scoped_to

FEDERATION_SOURCE ||--o{ FEDERATION_APPLY_RECEIPT : produces
DIRECTORY_FEDERATION_SOURCE ||--o{ DIRECTORY_FEDERATION_APPLY_RECEIPT : produces
Expand Down Expand Up @@ -136,6 +140,49 @@ erDiagram
timestamptz acquired_at
timestamptz lease_expires_at
}

AUTHORIZATION_SOFTWARE_UNIT_GRANT {
text grant_key PK
uuid tenant_deployment_id FK
text org_path
text software_unit_id
text effect_code
text actor_identity_id
}

AUTHORIZATION_MENU_GRANT {
text grant_key PK
uuid tenant_deployment_id FK
text org_path
text software_unit_id
text menu_path
text effect_code
jsonb capability_codes
jsonb attribute_constraints
text actor_identity_id
}

SSO_COMBINATION_SCOPE {
text combination_name PK
uuid tenant_deployment_id FK
jsonb software_unit_ids
text actor_identity_id
}

APPLICATION_ACCESS_TOKEN {
text application_token_id PK
uuid tenant_deployment_id FK
text software_unit_id
text token_prefix
text token_hash
text purpose_code
jsonb capability_codes
text lifecycle_status_code
timestamptz expires_at
timestamptz created_at
timestamptz revoked_at
text actor_identity_id
}
```

## Logical uniqueness constraints
Expand All @@ -148,6 +195,10 @@ UUID primary identifiers are globally unique. Human/provider identifiers are sco
| `FEDERATION_SOURCE` | `(tenant_deployment_id, federation_alias)` |
| `DIRECTORY_FEDERATION_SOURCE` | `(tenant_deployment_id, directory_alias)` |
| `RELYING_PARTY_SOURCE` | `(tenant_deployment_id, client_id)` |
| `AUTHORIZATION_SOFTWARE_UNIT_GRANT` | `(tenant_deployment_id, org_path, software_unit_id)` |
| `AUTHORIZATION_MENU_GRANT` | `(tenant_deployment_id, org_path, software_unit_id, menu_path)` |
| `SSO_COMBINATION_SCOPE` | `(tenant_deployment_id, combination_name)` |
| `APPLICATION_ACCESS_TOKEN` | `(tenant_deployment_id, application_token_id)` and unique `token_hash` |
| `KEYCLOAK_USER_REFERENCE` | `(tenant_deployment_id, keycloak_user_uuid)` |
| `EXTERNAL_IDENTITY_LINK` | `(federation_source_id, external_subject_hash)` |

Expand Down Expand Up @@ -178,6 +229,8 @@ or documentation labels are bypassed.
- Exact external identity key is `(identity_provider, subject)`; verified email may support matching under policy but unverified email never authorizes linking.
- `tenant_deployment_id` is explicit in Keyverse-owned records; deployment/customer separation must not be inferred from realm/resource names.
- Secrets are referenced through protected values/handles where possible; secret-free desired-state tables must never gain client/bind credentials accidentally.
- Application access tokens store only `token_hash` and `token_prefix`. Plaintext tokens and org-tree secrets never appear on grant or combination rows.
- Hierarchical grant paths use `group_company` / `legal_entity` / `business_unit` / `team` / `person`. They do not persist Orgmetra trees and do not reuse LineageWeave `role` / `org` / `workspace` claim names.

## Desired-state and receipt invariant

Expand Down
18 changes: 17 additions & 1 deletion docs/OPERABILITY.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Keyverse Operability, Recovery, and Release Guide

**Status:** Accepted cross-cutting operating baseline
**Last reviewed:** 2026-08-11
**Last reviewed:** 2026-08-18

Feature-specific procedures under `docs/operations/`, federation/RP onboarding, and deployment READMEs remain authoritative for their slices. This guide defines the shared operating model and evidence needed before declaring the identity platform healthy or release-ready.

Expand Down Expand Up @@ -66,6 +66,22 @@ must test the **Naruon** product login/token/authorization journey using the
`naruon-web` RP client ID and verify the expected audience and bounded claims.
Mapper unit tests alone do not prove Naruon product authorization readiness.

## Authorization-plane and token runbook

1. Obtain an Orgmetra assignment snapshot for the subject; do not copy the
Orgmetra tree into Keyverse.
2. PUT software-unit and menu grants at the intended org-path node.
3. PUT an SSO combination when several RPs should share one session.
4. Call the matching `:decide` endpoint and keep the RP as PEP.
5. For app login, call `POST /federation/identity-providers:start-login`, add
PKCE locally, and redirect. Do not fetch IdP metadata from the app.
6. Mint a PAT with `POST /application-tokens`, store the plaintext in the
application secret manager, and verify through Keyverse. Rotate or revoke
instead of sharing a password.

See `docs/authorization-onboarding.md` and
`docs/operations/authorization-plane.md`.

## Account merge recovery

Merge and SCIM full replacement (`PUT`) must hold the shared operation lock. Protected-main `PATCH active=false` is not currently inside that shared-lock guarantee and must not be treated as transactionally serialized with merge. On failure, classify whether state changed in Keycloak, Keyverse audit, linked identities, or tombstone status. Re-observe before retry. Never infer a retry is safe solely from the previous HTTP response. Preserve survivor and duplicate lineage in audit.
Expand Down
29 changes: 28 additions & 1 deletion docs/PRD.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Keyverse Product Requirements Document

**Status:** Accepted cross-cutting product baseline for protected `main` at `196814abe45ecf972a7776836af3933506d13fd5`
**Last reviewed:** 2026-08-11
**Last reviewed:** 2026-08-18

## 1. Product purpose

Expand All @@ -24,6 +24,9 @@ Its job is to let CWL products consume stable standards-based identity without e
- configuration/secret bootstrap via KV/DB boundary rather than application environment as runtime source of truth;
- 100% production statement/branch/docstring quality gates and protected review/security workflows.
- an explicit per-RP Keyverse token-validation and downstream ABAC/RBAC acceptance boundary; application login alone is not authorization readiness.
- an issuer-side hierarchical authorization plane for software-unit ACL, menu ABAC/RBAC decisions, SSO combination scopes, and org-path inheritance consumed from Orgmetra assignment snapshots;
- an app start-login helper that discovers enabled brokered IdPs and returns a `kc_idp_hint` authorization URL without metadata fetch;
- hashed, purpose-bound programmable application tokens scoped to one software unit and API capabilities.

The current SCIM `PATCH active=false` deprovisioning path is not protected by the shared cross-process user-operation lock used by merge and full replacement. It must not be represented as transactionally serialized with merge until a source change and concurrency regression prove that boundary.

Expand Down Expand Up @@ -104,6 +107,30 @@ Compose/Helm deployments SHALL expose component readiness that distinguishes Key

Privileged identity and desired-state operations SHALL produce auditable intent/outcome evidence sufficient for reconciliation/rollback without exposing protected secret values.

### PRD-FR-011 Software-unit access control

Keyverse SHALL decide whether an opaque Keyverse subject may use a named software unit / relying party from grants attached to a hierarchical org path. Employment truth SHALL remain in Orgmetra; Keyverse SHALL consume an assignment snapshot and SHALL NOT copy the Orgmetra tree as source of record.

### PRD-FR-012 Menu ABAC and RBAC

Keyverse SHALL decide menu access only after software-unit allow, applying closed ABAC constraints before remaining capability codes. Hierarchical attribute names SHALL be `group_company`, `legal_entity`, `business_unit`, `team`, `person`, and `org_path`, and SHALL NOT redefine LineageWeave `role`, `org`, or `workspace`.

### PRD-FR-013 SSO combination scopes

Keyverse SHALL authorize a named combination of software units to share one Keyverse session only when every member software unit is allowed for that snapshot. The Keycloak session remains Keycloak-owned.

### PRD-FR-014 Higher-permission inheritance

A grant at a higher org node SHALL apply to descendants unless a more-specific assignment restricts it. Default SHALL be deny. Secrets and programmable application tokens SHALL NOT inherit.

### PRD-FR-015 App start-login helper

Keyverse SHALL provide a start-login helper that discovers enabled identity providers from the local registry and returns a Keycloak authorization URL with `kc_idp_hint`. The helper SHALL NOT fetch metadata or discovery documents and SHALL NOT move federation ownership into the application.

### PRD-FR-016 Programmable application tokens

Keyverse SHALL issue hashed-at-rest, purpose-bound, software-unit and API scoped tokens that are rotatable, revocable, and auditable. Tokens SHALL NOT substitute for a password or WebAuthn authenticator and SHALL NOT inherit org-tree grants.

## 7. Security/privacy requirements

- passkey/federation/SCIM/OIDC/SAML/JWT behaviors follow current standards and Keycloak-supported contracts;
Expand Down
19 changes: 17 additions & 2 deletions docs/TEST_STRATEGY.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Keyverse Test Strategy

**Status:** Accepted quality baseline
**Last reviewed:** 2026-08-11
**Last reviewed:** 2026-08-18

## Mandatory gates

Expand Down Expand Up @@ -76,6 +76,21 @@ and rejection of scripts/arbitrary claims/classes.
ADR-0008's application matrix remains deployment-restricted until each RP
repository supplies its own exact token-validation and ABAC/RBAC evidence.

## Authorization-plane tests

- contiguous Macro-to-Micro `org_path` parsing and reserved-name rejection;
- ancestor allow inheritance and more-specific deny restriction;
- default deny when no grant matches;
- software-unit ACL isolation per relying party;
- menu decisions require software-unit allow, then ABAC, then RBAC capabilities;
- SSO combinations allow only when every member software unit is allowed;
- start-login uses the local registry, rejects discovery/metadata URLs, and
performs no Keycloak or network I/O;
- PAT issue returns plaintext once; verify/revoke/rotate never echo secrets;
- PAT purposes cannot be password or authenticator substitutes;
- PATs do not inherit org-tree grants;
- Orgmetra trees are not persisted as source of record.

## Deployment and persistence tests

- PostgreSQL/KV migrations and rollback for Keyverse-owned records;
Expand All @@ -93,7 +108,7 @@ Mirror `docs/THREAT_MODEL.md`: malicious IdP/LDAP URLs, path/resource IDs, dupli

## Documentation contract

CI should require PRD, TRD, Architecture, UML, ERD, Threat Model, Test Strategy, Operability, Traceability, ADR index, README, AGENTS, CLAUDE, CHANGELOG, and discoverable `docs/doctoring/`, `docs/papers/`, and `docs/operations/` research/standards/runbook records. It must assert PR #72/#74 are recorded as integrated protected-main changes and ADR-0008 remains indexed.
CI should require PRD, TRD, Architecture, UML, ERD, Threat Model, Test Strategy, Operability, Traceability, ADR index, README, AGENTS, CLAUDE, CHANGELOG, and discoverable `docs/doctoring/`, `docs/papers/`, and `docs/operations/` research/standards/runbook records. It must assert PR #72/#74 are recorded as integrated protected-main changes and ADR-0008 remains indexed. ADR-0009 is reserved for PR #100; ADR-0010–0012 index the authorization plane, start-login helper, and programmable tokens.

## Release acceptance

Expand Down
6 changes: 5 additions & 1 deletion docs/THREAT_MODEL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Keyverse Threat Model

**Status:** Accepted baseline for protected-main identity control plane
**Last reviewed:** 2026-08-11
**Last reviewed:** 2026-08-18

## Trust boundaries

Expand Down Expand Up @@ -49,6 +49,10 @@ flowchart LR
| automation credential exposure | repository/provider compromise | isolated OpenCode/broker/verification/publication and reviewer separation |
| stale/false-green CI | unverified identity policy lands | exact-head checks, success-only evidence, fail-closed API gate |
| RP accepts identity without authorization boundary | cross-tenant access or privilege elevation | explicit issuer/audience/JWKS profile, tenant/resource ABAC before bounded RBAC, cross-tenant denial tests, production fail-closed defaults |
| inherited grant applied too broadly | privilege elevation down the org tree | most-specific grant wins; default deny; more-specific deny restricts |
| PAT used as password | bypass of passwordless authenticator | closed purpose codes; reject password/WebAuthn/login purposes |
| PAT or grant secret leakage | credential theft | hash-at-rest; one-time plaintext; redacted list/verify; no org-tree inheritance of secrets |
| app fetches IdP metadata | SSRF / split federation ownership | start-login reads local registry only; discovery URLs rejected |

## STRIDE interpretation

Expand Down
Loading
Loading