NK-WP-0056-T10: journey-only executor mode; fail-closed proof on the T08 stack

cli.py --journey-only: read-only, no admission; journey-read role only
(CCR-2026-0059), no Kubernetes/directory client, no approval or audit call;
exit 0 pass / 1 fail closed / 4 refused. Shared operations.journey_from_kv
with the admission check. Synthetic proof: healthy pass, broken svc-authelia
bind fails closed at authelia_first_factor, restored pass, journey token
cannot read the bind; all_met, no values. 45 executor tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5502@bnt-lap001
Assistant-Session: 68b3b02f-5d0f-4e71-8421-796f62e50196
This commit is contained in:
tegwick 2026-10-31 19:56:52 +01:00
parent ef6284c371
commit abed4360d4
8 changed files with 327 additions and 18 deletions

View file

@ -0,0 +1,24 @@
# NK-WP-0056-T10: journey-only run, synthetic proof (2026-10-31)
`bounded-executor/cli.py --journey-only` is a read-only run that needs no admission:
- it logs in with the journey-read role only (CCR-2026-0059);
- it reads the syn-journey identity and runs the synthetic MFA journey once;
- it prints the journey's value-free receipt.
It has no write role, no Kubernetes or directory client, and no approval or audit call. Exit codes: `0` pass, `1`
fail closed, `4` refused before the journey.
`synthetic-report.json` comes from `uv run bounded-executor/synthetic_journey_only.py`. It runs the same code path
(`operations.journey_from_kv`) on the T08 stack (pinned LLDAP, privacyIDEA, Authelia and KeyCape) plus a dev OpenBao
token that holds only the journey-read policy:
| Scenario | Expected | Result |
| --- | --- | --- |
| healthy | pass | pass |
| broken bind: svc-authelia changed in LLDAP, Authelia keeps the old value | fail closed at `authelia_first_factor` | fail at `authelia_first_factor` (`first_factor_rejected`) |
| restored | pass | pass |
| lane boundary | journey token cannot read the svc-authelia bind | denied |
`all_met: true`, `no_values_in_report: true`. This is T10's fail-closed proof. The unattended live run is the
rapp's `make journey`.

View file

@ -0,0 +1,48 @@
{
"all_met": true,
"code_path": "operations.journey_from_kv (cli.py --journey-only)",
"finished_at": "2026-10-31T18:56:06+00:00",
"images": {
"openbao": "quay.io/openbao/openbao@sha256:436eaf9778cad75507ff70ea26ace30dcbe15606e619ac3823495663d7f7c115"
},
"no_values_in_report": true,
"results": [
{
"expected": "pass",
"journey": {
"failed_step": null,
"reason": null,
"result": "pass"
},
"met": true,
"scenario": "healthy"
},
{
"expected": "fail at authelia_first_factor",
"journey": {
"failed_step": "authelia_first_factor",
"reason": "first_factor_rejected",
"result": "fail"
},
"met": true,
"scenario": "broken bind (svc-authelia)"
},
{
"expected": "pass",
"journey": {
"failed_step": null,
"reason": null,
"result": "pass"
},
"met": true,
"scenario": "restored"
},
{
"expected": "journey token cannot read the bind",
"met": true,
"scenario": "lane boundary"
}
],
"schema": "netkingdom.bounded-executor.synthetic-journey-only/v1",
"started_at": "2026-10-31T18:55:19+00:00"
}