Skip to content

feat: add single-use delegated Core authorization (ENG-CORE-DELEGATION-001A) - #124

Merged
ezutfen merged 7 commits into
mainfrom
feat/eng-core-delegation-001a-read-broker
Jul 28, 2026
Merged

feat: add single-use delegated Core authorization (ENG-CORE-DELEGATION-001A)#124
ezutfen merged 7 commits into
mainfrom
feat/eng-core-delegation-001a-read-broker

Conversation

@ezutfen

@ezutfen ezutfen commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary and threat model

Adds a separate, opaque delegated credential authority for one short-lived, single-use Core read request. The design prevents an external broker from inheriting provisioning authority, stores no plaintext bearer secret, consumes authority before route execution, terminally revokes unused tokens on any observed authority loss, and returns generic authentication failures.

Work-start and repository state

  • Expected Core base: 3e4f8933df10dedb4729a4aaccc0676d833a17c2
  • Actual Core work-start: 3e4f8933df10dedb4729a4aaccc0676d833a17c2
  • Final branch head: f06a15b (includes current origin/main at 96fd2f3dda3e4629e28c2efdba69a4566ee5f11d)
  • Portal reference: a744e761e35cf243b02b0f7aa128948a5fc78585
  • Portal tree was clean and remained untouched.
  • PR remains draft.

Files and migration 029

28 files changed across delegated auth/API/CLI/config/model code, migration and deterministic downgrade, CI leak scanning, focused tests, operator/security/integration documentation, and an MCP v1 compatibility constraint exposed by the fresh CI resolver.

Migration 029 adds service_delegation_grants, service_delegation_tokens, service_delegation_idempotency, and append-only service_delegation_events; issue/revoke SECURITY DEFINER functions; subject-integrity, append-only, revoked-grant-history, and terminal authority-invalidation triggers; binding integrity keys and required indexes. Objects remain owner-owned. The provisioner has no delegation-table SELECT or DML and receives EXECUTE only on the two public delegation functions; trigger helpers are not executable by application/provisioner roles.

Clean 001→029 and persisted 028→029 upgrade/downgrade proofs pass. Existing clients, credentials, bindings, permissions, events, and the provisioner password remain unchanged. No broker, grant, token, event, or delegation.issue permission is created silently.

Permission and broker model

The canonical service vocabulary adds delegation.issue. The test broker has only that permission. The separate binding owner retains the five provisioning permissions and has no delegation permission. An owner-created active broker→binding-owner grant is required, has a bounded maximum TTL, and cannot be reactivated after revocation.

Credential lifecycle

The delegated grammar is the Bearer-compatible engd_<22-character-base62-key-id>_<43-character-URL-safe-secret>. PostgreSQL stores only the redacted representation: key ID plus SHA-256 secret digest. Scope is exactly read, audience is engram-core, TTL is 30–300 seconds, and successful authentication atomically transitions active→used before returning the existing human principal.

Malformed delegated material never reaches legacy API-key fallback. Delegated principals are not cached. Service routes retain strict service-credential parsing. Generation, parsing, documentation, leak scanning, fixtures, and tests use only the underscore form; no compatibility path exists for the unmerged asterisk form. A generation test proves every emitted credential is valid RFC 6750 Bearer token material.

Idempotency and ambiguous-response recovery

Canonical compact sorted request state is recomputed inside PostgreSQL. Same-key replay and exact external-reference reconciliation return original metadata without plaintext or expiry extension. Changed key/request or external-reference/request pairs produce bounded conflicts without partial state. Response-loss recovery is: replay, revoke the prior external reference, then issue under a new external reference; the old token remains unusable and the replacement authenticates once.

Revocation and terminal invalidation matrix

Unused authority is denied after explicit revoke, expiry, use, grant revoke, issuer disable, binding-owner disable, issuer credential revoke/expiry, permission removal, or subject/binding-integrity change. Authority mutations atomically revoke every active affected token and append bounded denial evidence. A use attempt that first observes time-based or otherwise invalid authority atomically marks the token authority_invalidated before returning 401.

Disable/re-enable, permission remove/restore, credential revoke/restore, and subject invalid/restore cycles never reactivate an affected token. A credential that expires and is restored before its token's first use still terminally invalidates that token. Status-only used/revoked transitions bypass current-subject validation, while insertion and identity-column changes retain relationship validation. Explicit revocation while the principal is invalid succeeds idempotently as already_revoked.

Revoke returns truthful revoked, already_revoked, already_used, and not_found dispositions. A read authenticated before a later revocation commit may finish; authentication beginning afterward cannot succeed.

Scope denial matrix

  • Read and /whoami: allowed.
  • Write/remember, review, export, and admin: 403 after authentication, consuming the token.
  • Provisioning and delegation service routes: 401 for delegated material.
  • Broker calls to provisioning routes: 403.

PostgreSQL race, events, and rollback results

Concurrent use/use yields exactly one success. Concurrent equivalent issue yields one token; same-external reconciliation and changed-request conflict serialize correctly. Use/revoke yields only use-first/already-used or revoke-first/denied. A use blocked on the token row observes a committed revoke.

Isolated count proofs record exactly one event for grant create/revoke and each issued, replayed, reconciled, used, revoked, authority-invalidated, and denied operation; the conflict sequence records one bounded event per intentional conflict. Event fields contain digests rather than raw external identities.

Owner-installed test failpoints after token insert, idempotency insert, event insert, credential timestamp update, and during revoke prove no partial token, idempotency, event, credential timestamp, or status mutation survives rollback. Locked issuance rejects credential and grant revocation occurring after preliminary service authentication.

Privilege and secret proofs

The provisioner is LOGIN, NOSUPERUSER, NOBYPASSRLS, NOCREATEDB, NOCREATEROLE, NOREPLICATION, NOINHERIT; it has no memberships, schema CREATE, or public object ownership. Delegation-table privilege checks and delegation-function EXECUTE checks pass.

Tracked/untracked repository files, all PostgreSQL text/JSON fields, generated diffs, and container logs are scanned for credential-shaped material. The scanner recognizes the Bearer-compatible delegated grammar and works from Git metadata locally and from the exact copied source snapshot in git-less CI runtime images.

Verification

  • Delegated credential/auth unit suite: 15 passed.
  • Focused real-PostgreSQL delegation suite: 32 passed, including terminal restoration cycles, elapsed-expiry observation, explicit invalid-subject revocation, races, ACLs, and rollback proofs.
  • Local full root gate against fresh PostgreSQL 16 + pgvector: 3,035 passed, 2 repository-standard skips; lint and strict typing passed.
  • Clean migration 001→029 completed successfully on the fresh database; upgrade/downgrade proofs passed in the full suite.
  • SDK, MCP adapter, hooks adapter, conformance vectors, lock drift, RLS, git diff --check, and leak scans remain covered by CI.
  • Prior exact-head CI baseline: run 30373045018, passed at 4748e6a2a99dcb81b84693f1a4b993d3239f3e13.
  • Prior merge-ref CI baseline: run 30373044943, passed.
  • Corrected pre-reconciliation exact-head CI: run 30377987068, passed at 609c68d6be7094f5b3d0f33a098c57a700adfc4a.
  • Corrected pre-reconciliation merge-ref CI: run 30377987062, passed.
  • Reconciled-head CI exposed and rejected a credential-shaped pytest parameter in JUnit XML; the fixture now has a safe explicit test ID.
  • Final exact-head CI: run 30379821774, passed at f06a15bafb30609d40668b6494ddf1e0841fcb56 (3,006 root passed; SDK 55, MCP 36, hooks 186; leak scan tracked_files=0 database_fields=0).
  • Final merge-ref CI: run 30379821581, passed, including runtime-image smoke, conformance, lock-drift, and post-JUnit leak scanning.

Deferred work

Portal broker/BFF delivery, memory UI, browser proxying, review step-up authority, and additional-agent delegation remain explicitly out of scope. Portal was not modified.

@ezutfen
ezutfen marked this pull request as ready for review July 28, 2026 17:14
@ezutfen
ezutfen merged commit 6109f7d into main Jul 28, 2026
6 checks passed
@ezutfen
ezutfen deleted the feat/eng-core-delegation-001a-read-broker branch July 28, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant