Plan credential-grant authorization for railiance-platform (FLEX-WP-0012)
Opens the State Hub capability request 893ff109, unanswered since 2026-07-02. Drafted as proposed/P3 rather than as the blocker it was filed as, because two of its premises no longer hold: - It is not blocking anyone. railiance-platform re-scoped and closed RAILIANCE-WP-0005-T07 the same day it filed the request; WP-0005 is finished and their grant catalog already enforces TTL, actor-type, purpose and delivery-mode bounds locally. This buys defence in depth and central decision records, not unblocking. - The stated technical blocker is wrong. The request says the CARING /v1/check schema cannot express TTL, purpose or delivery mode; the ops-warden package in this repo already denies ttl_out_of_bounds by reading input.context.ttl_hours against resource.attributes. CARING constrains descriptor vocabulary, not the request payload. The real gap is narrower: no credential-grant policy package exists, and the helper's flat payload/response shape differs from CheckRequest. Its endpoint path is configurable, so no bespoke endpoint is strictly required. T01 makes the adapter-vs-consumer-mapping call an explicit, jointly-agreed decision rather than a default. Flags two things worth knowing before anyone implements: the helper sends requested_ttl as a duration string while the ops-warden precedent compares numeric hours (mis-parsing it would fail open on the check that matters most), and without --require-flex-auth the helper continues by local preauthorization when flex-auth is unreachable -- a different posture from the tenant-engine and ops-warden gates. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
3dc6223cc2
commit
693136edbc
1 changed files with 213 additions and 0 deletions
213
workplans/FLEX-WP-0012-credential-grant-authorization-surface.md
Normal file
213
workplans/FLEX-WP-0012-credential-grant-authorization-surface.md
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
---
|
||||
id: FLEX-WP-0012
|
||||
type: workplan
|
||||
title: "Authorize railiance-platform credential-grant requests"
|
||||
domain: infotech
|
||||
repo: flex-auth
|
||||
status: proposed
|
||||
owner: codex
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P3
|
||||
planning_order: 120
|
||||
related_workplans:
|
||||
- RAILIANCE-WP-0005
|
||||
created: "2026-08-11"
|
||||
updated: "2026-08-11"
|
||||
---
|
||||
|
||||
# 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:
|
||||
|
||||
1. No credential-grant policy package or protected-system manifest exists for
|
||||
`railiance-platform`.
|
||||
2. 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/check` without a code change on their side.
|
||||
3. 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 reads `allowed` / `decision`
|
||||
/ `status` plus optional `decision_id` and `reason`. `/v1/check` expects a
|
||||
`CheckRequest` (`subject` / `action` / `resource` / `context`) and returns
|
||||
`effect`, `reason`, `id`. Something has to translate.
|
||||
|
||||
## T01 - Decide where the translation lives
|
||||
|
||||
```task
|
||||
id: FLEX-WP-0012-T01
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
## T02 - Credential-grant policy package and fixtures
|
||||
|
||||
```task
|
||||
id: FLEX-WP-0012-T02
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
## T03 - Implement the decided integration and prove it end to end
|
||||
|
||||
```task
|
||||
id: FLEX-WP-0012-T03
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
```task
|
||||
id: FLEX-WP-0012-T04
|
||||
status: todo
|
||||
priority: low
|
||||
```
|
||||
|
||||
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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue