Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 735967@bnt-lap001 Assistant-Session: 5971967f-77f8-4ced-9e02-c6ef67040ffc
8 KiB
| id | type | title | domain | repo | status | owner | topic_slug | created | updated | related | state_hub_workstream_id | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| FLEX-WP-0035 | workplan | Per-identity application access readback and readable protected-system registry for user-engine | infotech | access-engine | active | claude | netkingdom | 2026-10-09 | 2026-10-09 |
|
cb9755fa-6824-5288-81c4-3aa2fbff1a9f |
user-engine (message f1637c32, 2026-10-09, routed by net-kingdom 19a0cbcd)
needs to show a signed-in person which applications they can use. Its
USER-WP-0026-T03 and USER-WP-0028-T02 are blocked_on access-engine. The
PEP stance is already fail-closed: no decision renders unavailable, and allow
is never inferred from membership, platform role, registration, or a missing
record.
What exists today (2026-10-09 review)
POST /v1/batch_checktakes several resources in one call and returns one decision per resource, each with alifetime(expires_at) per the decision envelope. Shape-wise this is close to request (1).- Caller auth authorizes the caller token against every
resource.systemin the batch (cmd/flex-auth/main.go,/v1/batch_check). Theflex-auth-user-enginecaller is bound to its own protected system, so a readback across other systems is a 403 today. That is correct behaviour for enforcement, and the reason this needs design rather than a config change. - There is no generic "may use this application" action. Each package has its own action vocabulary, so "access to system X" has no defined meaning yet.
- There is no registry read endpoint. The protected-system registry is loaded from files and never served.
Define the readback contract
id: FLEX-WP-0035-T01
status: done
priority: high
state_hub_task_id: "0585a684-d462-5caa-937f-b1730efddbd8"
Decide the action that a readback evaluates per system: a declared
application.access action each consumer package must opt into, versus a
per-system mapping held in the registry. A system that declares nothing is
returned as not_applicable, never allow. State per input class the
revocation-visibility deadline the readback carries (§9.7). Decide whether the
readback is a decision for audit purposes (decision record, emission) or an
explicitly non-enforcing advisory read. A displayed allow must not be usable as
a PEP decision by another system.
Gate: written contract in docs/ plus an ADR or decision record; reviewed with
user-engine before code.
2026-10-09: user-engine accepted the contract (message f54df082) with three
amendments, now folded in: the /v1/check subject shape with tenant, the
rendering table, and a separate USER_ENGINE_READBACK_TOKEN_FILE. Also added: a
realm-level-claims-only rule. FLEX-DEC-2026-019 is accepted.
2026-10-09: activated by the founder. Draft contract
docs/application-access-readback.md and FLEX-DEC-2026-019 (proposed). Key
finding: each pin loads one consumer's package, so no existing pin can answer
across applications. The draft proposes a dedicated readback pin with
multi-package mode, a purpose: "readback" binding that keeps decisions
non-transferable, and a new optional client_binding manifest field. Sent to
user-engine with four review questions. The gate closes on their reply.
Caller authorization for cross-system readback
id: FLEX-WP-0035-T02
status: done
priority: high
depends_on: [FLEX-WP-0035-T01]
state_hub_task_id: "eb0b6a91-7750-553b-b87f-c4262eb9df07"
Add a distinct caller capability (readback scope) instead of widening the
flex-auth-user-engine binding to other systems' check rights. The readback
caller must not be able to obtain a decision that another system's PEP would
accept, and its decisions must say so in the binding.
Gate: tests prove a readback-scoped token gets 403 on /v1/check for a foreign
system and is admitted only on the readback route.
2026-10-09 done. flex-auth serve-readback is a separate subcommand that mounts
no /v1/check or /v1/batch_check (404 there). --readback-caller is bound
under the non-system key application-readback. CheckRequest.purpose is
hashed into request_digest, submitted_request_digest and
approval_binding_digest, but only when set, so enforcement digests are
unchanged. /v1/check refuses a request that carries it. Tests:
cmd/flex-auth/readback_test.go
(TestReadbackPrincipalCannotCheckOnEnforcementPin,
TestReadbackHTTPCallerAndRequestShape, TestReadbackWithholdsUncommittedAllow)
and pkg/api/purpose_test.go.
Readable protected-system registry
id: FLEX-WP-0035-T03
status: done
priority: medium
depends_on: [FLEX-WP-0035-T01]
state_hub_task_id: "5dbb3280-8490-58a5-a0bb-f3883e568f58"
Serve a read-only projection: system id, display name, key-cape client binding.
Include the registry-snapshot digest so the catalogue is tied to the same
snapshot that decisions record (G1, FLEX-WP-0019). Grants and revocations stay
inside access-engine; user-domain admins get no grant surface from this work.
Gate: endpoint plus schema, admitted only for the readback caller, tests.
2026-10-09 done. GET /v1/readback/systems; optional client_binding on
protected_system_manifest. Schemas readback_request, readback_response
and readback_systems are checked against live service output
(TestReadbackShapesMatchSchemas). schemaguard gained maxItems for this.
informed-decision declares application.access
id: FLEX-WP-0035-T05
status: wait
priority: high
blocked_on: message-from:informed-decision
blocking_reason: "Source side done; informed-decision must agree to lifecycle v2 (its own lifecycle pin will run the same digest at the next rollout)."
state_hub_task_id: "701cbd99-1a84-5290-8f66-15fa7f407d3b"
informed-decision is the first participant. Its informed-decision.lifecycle
package reads authentication_audience, which the readback must not use
(contract §3). Add an application.access rule over realm-level claims only,
as a new package version with fixtures. Coordinate the version bump with
informed-decision, because its own pin must run the same digest. Add
client_binding to its registry entry.
Gate: package valid with allow/deny fixtures, informed-decision agrees, and the rule reads no audience, authorized-party or client-scoped claim.
2026-10-09 source done. informed-decision.lifecycle is now v2
(sha256:da01e045…, pin.json updated). It adds application.access, which
requires purpose == "readback" and the existing human bar: net-kingdom-admins,
KeyCape AAL2 pwd+otp within 12h, platform tenant. It has no workload path
and reads no audience or client-scoped claim. v1's twelve operations are
unchanged. Eight Go cases cover it, plus a fixture showing that it denies
without the readback purpose. The catalogue examples/application-readback/
binds informed-decision to https://kc.coulomb.social /
informed-decision-approver. TestReadbackInformedDecisionCatalogue proves the
readback over the shipped files. The live lifecycle pin still runs v1 (image
bdac62bc) until the T04 rollout. Waiting on informed-decision's agreement.
Deploy the readback pin
id: FLEX-WP-0035-T04
status: wait
needs_human: true
depends_on: [FLEX-WP-0035-T05]
blocking_reason: "Live pin change on railiance01 needs founder go."
priority: medium
state_hub_task_id: "82a8a7e6-54e9-5262-a271-24ce2f161362"
Add values/flex-auth-application-readback.yaml (or a deploy manifest) for a
dedicated flex-auth-application-readback pin, plus a test asserting that its
package paths match each participant's own pin values (digest-equality, §4).
Add the user-engine ingress rule, then get the founder's go for the rollout.
Promised to user-engine (reply to d7e02758, 2026-10-10), so the values file
must match: URL
http://flex-auth-application-readback.flex-auth.svc.cluster.local.:8080
(trailing dot, in-cluster only), caller token audience flex-auth
(serve-readback --caller-audience default), readback caller
system:serviceaccount:user-engine:user-engine.
The pin ships with the image that contains serve-readback. Hand user-engine
the evidence that unblocks USER-WP-0026-T03.