Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a02e47-6aac-7ee1-914d-0584c75d3c81
11 KiB
| id | type | title | domain | repo | status | owner | topic_slug | planning_priority | planning_order | related_workplans | created | updated | state_hub_workstream_id | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| FLEX-WP-0012 | workplan | Authorize railiance-platform credential-grant requests | infotech | flex-auth | active | codex | netkingdom | P3 | 120 |
|
2026-08-11 | 2026-08-23 | 89ecdb1f-ceb0-4a50-b72d-c3dfd5fa7c73 |
FLEX-WP-0012 - Authorize railiance-platform credential-grant requests
railiance-platform's credential broker (scripts/credential.py) can call
flex-auth as a preflight before issuing a credential lease, posting non-secret
grant metadata and expecting an allow/deny back. It has been able to do this
since 2026-06-27. flex-auth has never answered, because nothing in this repo
serves the endpoint the helper posts to or understands the payload it sends.
Opened from State Hub capability request 893ff109, filed 2026-07-02 and
unanswered since. Read the two corrections below before planning any work:
the request as filed rests on a premise that is not true, and the urgency it
describes has since evaporated.
Correction 1: this is not blocking anyone
The capability request says RAILIANCE-WP-0005-T07 is blocked. It is not.
Later the same day, railiance-platform re-scoped and closed T07 on its own
scope, and RAILIANCE-WP-0005 is now finished. Their closure note records
that the flex-auth call is optional by T07's own exit criteria, and that
the grant catalog already enforces TTL, actor-type, purpose, and
delivery-mode bounds locally.
So this workplan buys defence in depth and central, auditable policy — a second, independently-owned opinion on credential issuance, with decision records — not the unblocking of stalled work. Priority is set accordingly. If it is never done, railiance-platform keeps enforcing the same bounds locally; what is lost is central policy and the decision log, not safety.
Their closure note also says: "Decision taken autonomously (operator away);
revert to wait if Bernd prefers to hold WP-0005 open on flex-auth." That
choice is still open and should be confirmed rather than assumed.
Correction 2: the stated technical blocker is wrong
The request says the CARING /v1/check schema "cannot express TTL bounds,
purpose, or delivery-mode checks." That is not correct, and the
counter-example already ships in this repo.
examples/ops-warden/policy_package.md denies ttl_out_of_bounds today by
reading input.context.ttl_hours and comparing it against
input.resource.attributes.max_ttl_hours. CheckRequest carries open
context and resource.attributes maps; Rego reads whatever is in them.
The CARING profile constrains descriptor vocabulary — canonical roles,
planes, capabilities — not the request payload a policy may inspect. A
credential-grant preflight is the same shape as the ops-warden SSH signing
gate that has been in production since FLEX-WP-0007: bounded TTL, an actor
class, and a purpose.
What is actually missing is narrower and worth stating precisely:
- No credential-grant policy package or protected-system manifest exists for
railiance-platform. - The helper posts to
/credential-grants/authorize, which flex-auth does not serve. This is not the obstacle it appears to be — the path is configurable via--flex-auth-path/FLEX_AUTH_PATH, so it can be pointed at/v1/checkwithout a code change on their side. - The payload and response shapes genuinely do differ, and this is the one
real gap. The helper posts a flat object —
grant_id,actor,actor_type,subject,purpose,requested_ttl,delivery_mode,audience,issuer,credential_type— and readsallowed/decision/statusplus optionaldecision_idandreason./v1/checkexpects aCheckRequest(subject/action/resource/context) and returnseffect,reason,id. Something has to translate.
T01 - Decide where the translation lives
id: FLEX-WP-0012-T01
status: wait
priority: medium
state_hub_task_id: "a1c9ba0c-3413-4823-9f9e-ccee09cf5d74"
Two honest options, and the choice is a charter question rather than a technical one:
A. railiance-platform emits a CheckRequest. No new flex-auth API
surface. FLEX_AUTH_PATH=/v1/check, the helper maps its own fields into
subject/action/resource/context and reads effect. Keeps flex-auth's
decision surface singular, which is what SCOPE.md describes. Costs a change
in a repo whose workplan is already finished, and pushes mapping knowledge
into the consumer — the thing FLEX-WP-0008-T01 established should be
coordinated, not independently invented.
B. flex-auth serves a thin /v1/credential-grants/authorize adapter. It
translates the flat payload into a CheckRequest, evaluates the
credential-grant package, and answers in the helper's vocabulary. No consumer
change beyond setting FLEX_AUTH_URL. Costs a second decision surface, and
risks the pattern SCOPE.md warns about — consumer-specific assumptions
leaking into the generic model — if the adapter grows policy logic instead of
staying a pure shape translation.
Recommendation to argue with, not to accept by default: B, on the strict condition that the adapter contains no authorization logic whatsoever — it maps fields, delegates to the same engine, and returns the same decision id. The ops-warden gate is the precedent for the policy; the adapter is only about a consumer's wire format, and confining it to that is what keeps the generic model clean.
Record the decision and its reasoning in the policy package, in the style of
FLEX-WP-0010-T02.
Done when the decision is recorded, and railiance-platform has agreed to it — this one cannot be decided unilaterally, because either option changes something they own.
Progress 2026-08-23: revalidated both repositories. The helper still emits the
flat payload and defaults to /credential-grants/authorize; flex-auth still
serves only /v1/check. The translation choice is therefore current, not stale.
Request railiance-platform agreement before implementing either wire shape.
State Hub decision 1f9f257d-c9f2-4a5e-a018-8058a3f2a51a records the two
options and was automatically escalated for human resolution; coordination
message 338e54d9-7313-433f-a8fe-8ad572d00365 asks the consumer to choose and
place duration normalization explicitly.
T02 - Credential-grant policy package and fixtures
id: FLEX-WP-0012-T02
status: done
priority: medium
state_hub_task_id: "7e9c4e59-e59c-4617-a87f-99142952fe78"
Add examples/railiance-platform/ with a protected-system manifest, subject
manifest, registry snapshot, policy package, and fixtures. Model it on
examples/ops-warden/, which already encodes the hard part — bounded TTL
against a per-resource maximum.
The four denials the capability request asks for, and their shapes:
| Denial | Reads |
|---|---|
| overbroad TTL | requested TTL vs the grant's max, as ops-warden does |
| wrong actor type | actor_type against the grant's allowed classes (human-operator, approved-agent, ci-runner) |
| wrong purpose | purpose required and matching the grant's permitted purposes |
| disallowed delivery mode | delivery_mode against the grant's allowed modes |
Note the TTL unit mismatch: the helper sends requested_ttl as a duration
string (15m), while the ops-warden package compares a numeric
ttl_hours. Decide where normalisation happens and make it explicit — a
policy that silently mis-parses 15m as 15 would be a fail-open bug in the
one check most worth getting right. Prove the parse with a fixture, not an
assumption.
Fixtures must cover allow plus one deny per row above, and an unknown grant
id. Verify against the real binary: test-policy, load-registry, and
check against standalone request files.
Done when all Rego tests and fixtures pass and default-deny is demonstrated for an unregistered grant.
Completed 2026-08-23. examples/railiance-platform/ registers all three
current catalog grants and representative requester subjects. The policy uses
numeric requested_ttl_seconds; duration parsing belongs to the selected wire
translator, and strings are explicitly denied. Three embedded Rego tests and
six external fixtures pass, covering allow, TTL, actor type, purpose, delivery
mode, and unknown-grant default deny. Real load-registry and check commands
returned credential_grant_allowed for the registered runtime grant and
unknown_grant for an unregistered id.
T03 - Implement the decided integration and prove it end to end
id: FLEX-WP-0012-T03
status: wait
priority: medium
state_hub_task_id: "3335b2b7-cf1a-411d-95b3-03c4b4c35659"
Implement whichever shape T01 chose. If B, the adapter must reuse the
existing engine and emit the same decision id and provenance as /v1/check —
no parallel evaluation path, no second decision log.
Then close the loop against the real helper, the way FLEX-WP-0010-T03 did
rather than in isolation: run flex-auth serve with this registry, point
scripts/credential.py at it via FLEX_AUTH_URL, and exercise an allow plus
each of the four denials with --require-flex-auth set, so a deny actually
stops issuance rather than falling through to local preauthorization.
Also verify the degraded path deliberately: with --require-flex-auth
unset and flex-auth unreachable, the helper is documented to continue by
local preauthorization. Confirm that is still what happens, and record it —
it means flex-auth is an additional gate here, not the deciding one, which
is a materially different security posture from the tenant-engine and
ops-warden gates and should not be quietly assumed to match them.
No secret material is involved anywhere in this flow. The helper posts request metadata only. Nothing in this workplan should read, log, or persist a credential value; if a task appears to require one, that is a signal the design has drifted, not a reason to handle secrets here.
Waiting on T01's wire-translation decision. The policy-side normalized request contract is implemented; either integration option must produce its numeric TTL field without changing policy semantics.
Done when allow and all four denials are demonstrated against the real helper
over real HTTP, go test ./... is green, and gofmt/go vet are clean.
T04 - Closure and handoff
id: FLEX-WP-0012-T04
status: wait
priority: low
state_hub_task_id: "40015a87-040c-4d48-b360-fd5566dbc552"
Reply to capability request 893ff109 — it has been open since 2026-07-02
and deserves an answer either way, including if the answer is "declined, use
/v1/check directly."
If the work lands, ship an image (.forgejo/workflows/image.yaml builds it)
and state plainly whether the credential-grant policy is deployed or only
in source — the distinction FLEX-WP-0010 learned the hard way. Note that
the helper's flex-auth URL points at a local instance (127.0.0.1:18090),
not the cluster Services, so deployment here may mean something different
from the tenant-engine and user-engine rollouts; establish which runtime is
actually meant before promising an endpoint.
Update docs/ with a credential-grant action vocabulary, matching the
existing per-consumer vocabulary docs.
The source-side action vocabulary is now present at
docs/railiance-platform-action-vocabulary.md; final consumer/deployment
handoff waits on T01 and T03.