Commit graph

68 commits

Author SHA1 Message Date
207d29e8d1 feat(case): attended-change lane kind with session_lane; grade apps-consumer-handover high
LANE-KIND accepts an attended step on a login lane, or on an attended-change
lane whose session_lane resolves to an active, reviewed login lane.
keycape-attended-case-change -> session_lane key-cape-oidc-login (OW-1.3-C1).
consumer-owner-deployment and apps-consumer-handover -> pending-owner-confirmation:
no catalog login lane authenticates a railiance-apps operator session.
apps-consumer-handover risk: high (KERNEL-2, change effect).

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 903097@bnt-lap001
Assistant-Session: aa320c8f-c3fa-46e7-8541-0b58e1e45d23
2026-10-17 12:13:49 +02:00
a14376cf62 feat(case): KERNEL-2/3 lane resolution and mode-aware admission; CATALOG-1 draft lanes
nk48 1.3 owner review (owner-review-ops-warden.json):
- KERNEL-2: Executor.admit parses catalog_source and resolves descriptor.lane;
  refuses a missing, non-active, undelegated or ungraded lane, an owner outside
  owner_repo, and a mint/change effect on a lane not graded risk high.
  catalog-routing-acceptance still covers the whole catalog digest.
- KERNEL-3: dispatch mode is read from the type's follow_through step
  (warden_executes/attended). The step must declare both booleans and a lane
  and agree with the descriptor's lane and owner. Attended: human actor,
  WARDEN_AGENT_ID unset, parent-session revocation scope, caller lane equal to
  the step lane. Owner: native delegation, owner_repo == descriptor.owner, no
  Warden-executed lane and no Warden-brokered mint.
- CATALOG-1: draft entries keycape-attended-case-change (OW-1.3-C1),
  platform-secret-delivery, consumer-owner-deployment, apps-consumer-handover.
  Not promoted; promotion waits for owner confirmation.
- Fixture catalogs and type steps in tests; published routing_lanes coverage
  and the workload-join count follow the four new not-applicable lanes.

PARAMETER_PINS untouched (PIN-1 waits for founder acknowledgment).

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 903097@bnt-lap001
Assistant-Session: aa320c8f-c3fa-46e7-8541-0b58e1e45d23
2026-10-17 12:08:49 +02:00
117fec9241 fix(case): validate original intent and bind its running receipt
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a1468b-63fa-7710-85dc-8f2e16b3ebfa
2026-10-17 10:33:43 +02:00
a45cf475bc WARDEN-WP-0044-T03: original-intent lookup/context for owner reconciliation
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Durably record the original run Invocation, pins, adapter source and
tenant/realm provenance before dispatch; expose Journal.original_intent and
Adapter.reconcile_original(ReconcileContext) for NK-WP-0048-T15. Missing or
mismatched intent refuses and leaves the step uncertain.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 903097@bnt-lap001
Assistant-Session: aa320c8f-c3fa-46e7-8541-0b58e1e45d23
2026-10-17 04:32:50 +02:00
d97652a3bb fix(cases): admit reviewed descriptor pin validator revision
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
2026-10-16 21:35:04 +02:00
d79f065955 Route explicit attended OpenBao administration to governed login
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
2026-10-16 18:44:02 +02:00
958352089b fix(cases): validate browser metadata against pinned owner source
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
2026-10-16 01:58:20 +02:00
d2cd3fa940 fix: contain attended login diagnostics and OpenBao recovery
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a137ca-5c77-7a71-b9ae-23ad9b0b5684
2026-10-15 04:25:05 +02:00
8dbf62515a Show the OpenBao identity warden access evaluates
reuse-surface-hub-write-token does not select a caller. The data plane
uses the ambient token, which can be the coding-agent role denied by
agent-high-risk-boundary while an attended platform-admin lookup still
shows read. Advisory and proxy output now report that entity, role, and
policies without the token. CCR-2026-0005 still has no OIDC binding for
workload-kv-read-reuse-surface-runtime.

Assistant: grok
Assistant-Session: 01a13b2d-0bc1-7a91-ab1d-325bcfb09bf0
2026-10-14 18:21:02 +02:00
6e1430073c WARDEN-WP-0036: tighten attended-login stdout/stderr allowlist
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Reject non-null wrap_info (a wrapping token survives token revoke -self),
non-empty data, empty client_token, and leading whitespace before the OIDC
stderr prompt. Fail-closed and hand-off tests now run through the CLI and
assert sentinel absence from both audit files.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 680842@bnt-lap001
Assistant-Session: 54eb9e8e-7d6b-4f0c-b7a6-a6db62075883
2026-10-14 12:41:43 +02:00
244f1ae2ca WARDEN-WP-0036: restore fail-closed on non-allowlisted attended-login output
b4c1d39 dropped login output from the attended-login fail-closed condition,
so any stdout/stderr was ignored once the helper was populated (RPF-WP-0017
criterion 4 regression). Login output stays captured and never forwarded and
is now accepted only when empty or allowlisted by structure: one bao login
-format=json object on stdout, the OpenBao OIDC prompt on stderr. Anything
else self-revokes, cleans up, and exits 10/login_failed without retry.
Adds populated-helper tests for unexpected stdout, stderr, malformed and
multi-object JSON, and unexpected keys.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 680842@bnt-lap001
Assistant-Session: 54eb9e8e-7d6b-4f0c-b7a6-a6db62075883
2026-10-14 12:34:40 +02:00
1b8261917e Prepare reviewed durable case execution kernel and accepted layer pins
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
2026-10-11 02:21:03 +02:00
23ba584ccd Catalog fluid-telegram-operator (draft) and tenant-engine sender projection; case plan env spec and case-ref
- fluid-telegram-operator: pointer-only draft entry and playbook from ops-mason's
  MASON-WP-0005-T06 proposal; activation waits for the owner-run member and
  non-member checks and the salt create-once probe.
- audit-core-senders: tenant-engine recorded as a verified exact-path consumer
  projection (MASON-WP-0007-T06). The registry lane itself stays draft.
- warden case plan: {param:env} format spec (net-kingdom 850907a), other specs
  and conversions refused; prints case-ref <case_id>@sha256:<file digest>.
- Workload-join unknown count 21 -> 22 (test and pep-stance.yaml).

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 427672@bnt-lap001
Assistant-Session: a0a2367e-4697-440c-a4e5-9713c009f6d8
2026-10-09 19:59:49 +02:00
9a85405e7a WARDEN-WP-0044-T02: warden case plan; close WP-0044-T01 and WP-0043-T02
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s
warden case plan resolves an accepted, materialized SecurityCase against its
acknowledged type: warden, attended and owner steps, type defaults, conditions,
rendered entry points and verification. Executes nothing; refuses unmaterialized
cases, missing or unreviewed lanes and secret or type-fixed parameters.

T01 closes on net-kingdom's R8 option 1 and the founder's acknowledgement of
the type (memo r4). WP-0043-T02 closes on railiance-platform b77cb41.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 427672@bnt-lap001
Assistant-Session: a0a2367e-4697-440c-a4e5-9713c009f6d8
2026-10-09 14:46:17 +02:00
0e7ceb8c06 WARDEN-WP-0044-T01: warden case check-type; revised oidc-rp 1.0 type conforms
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Mechanical follow-through check (lane, warden_executes, value_handling,
attended justification, read-free verification, rollback coverage). The
revised type passes schema; lanes identity-provisioner-groups and
keycape-client-secret-generate are not yet in the catalog (gate T02).

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 327203@bnt-lap001
Assistant-Session: 55028ae3-4914-4bd1-8f5c-815f3527aef0
2026-10-09 00:25:11 +02:00
139f77dd55 Route OpenBao configuration and provisioning away from the structure survey
Configuration intent (policies, auth roles) routes to the attended
openbao-platform-admin-login lane and value provisioning to openbao-api-key
custody; both fail closed when their front door is missing. The survey lane
now points at ops-mason's read-only ops-mason-survey grant (MASON-IN-0004).

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 327285@bnt-lap001
Assistant-Session: d6532cd1-7cd5-417b-baac-b841c9103a6b
2026-10-08 23:21:46 +02:00
a3555498dd Verify offline scaffolds and preserve Forge qualifier receiving
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a10391-6355-7b41-b0fa-3e14e874f091
2026-10-04 02:32:36 +02:00
dfe436e4e0 Implement offline catalog lane scaffold generation
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a10391-6355-7b41-b0fa-3e14e874f091
2026-10-04 02:24:40 +02:00
7d4381e887 WARDEN: separate fetch evaluator URL for secret-read checks (CUST-WP-0075)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
check_fetch_policy now posts only to policy.fetch_flex_auth_url (access-engine
pin flex-auth-ops-warden-fetch, workstation 127.0.0.1:19091). Signing keeps
policy.flex_auth_url. Unset or unreachable fetch evaluator fails closed with a
message naming it; no fallback to the signing pin or to allow. warden access
advisory output names the fetch evaluator. Recorded under WARDEN-WP-0039-T03.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 3775@bnt-lap001
Assistant-Session: cfacb6a5-ad5b-4f79-ac67-053e3b0d34a3
2026-10-03 09:18:54 +02:00
4c3a0f4d3a Fix attended login result auditing and reconcile blocked workplans
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 3s
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e6ef-4273-7fc2-8741-dc96b3e5fe0d
2026-09-28 09:44:49 +02:00
5a232b7f97 Attach optional Railiance recording-time evidence
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a09cbb-87c6-7900-a145-4ce53ba9f1a6
2026-09-15 22:18:06 +02:00
66db87e6ae feat: refuse to answer a write with a read (WARDEN-WP-0038)
`warden plan` scored needs by keyword overlap with no notion of what the
caller wanted to DO, so "generate a successor secret and CAS-write it to two
custodians" matched the lane that READS that path and inherited its
`autonomous` verdict -- answered with --out/--exec/--wrap.

Two counterparties reported it in two days. key-cape distrusted the output on
principle and was right to; railiance-platform, answering as the write
authority being wrongly bypassed, said plainly that `founder_required` is the
verdict it should have returned and that until it is fixed a plan result must
not stand in for the owner's answer.

A mutating need on a lane ops-warden does not permanently own can no longer
reach any branch returning `autonomous`: it becomes `founder_required` with
an approve act naming the write owner, or `unroutable` with a CCR stub when
the lane admits no rotation route. Commands carry no read transport either
way, which is the half that made the wrong verdict actionable.

The ownership test does the work a verb list cannot. SSH certificate
issuance is itself a mutating act, so `delegation.mode: permanent` -- not the
absence of a verb -- separates ops-warden's own front door from someone
else's custody. A regression asserts `warden sign` still proceeds; a guard
that refused our own lane would be worse than the defect it fixes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EPuTc18FjU5WFqoSEKH3C

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1276224@bnt-lap001
Assistant-Session: 426ec497-e1c4-4dd3-b417-dfce1ca1dbc3
2026-09-10 08:02:10 +02:00
31d9b6671c Refuse explicit policy authentication and binding denials before side effects
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-5.6-luna
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
2026-09-08 16:46:00 +02:00
00145d705e feat: complete local layer model v0.7 conformance work
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a06eaf-3425-7f92-a0c2-bb4aa4faebe4
2026-09-05 01:19:48 +02:00
8f01eefb1e Preserve Warden config in attended child
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
2026-09-01 00:24:18 +02:00
b4c1d3900a Fix contained OpenBao login handoff
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
2026-09-01 00:13:26 +02:00
0fae0904ce fix: contain attended OpenBao login output
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0290b-3241-74c3-b868-6049545af836
2026-08-23 01:31:05 +02:00
e3b9b1620c fix: route OpenBao recovery ceremonies safely
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0290b-3241-74c3-b868-6049545af836
2026-08-22 20:54:45 +02:00
8280c0b7b7 fix: route OpenBao platform administration login
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0290b-3241-74c3-b868-6049545af836
2026-08-22 19:08:21 +02:00
7ce58ae638 feat: adopt security zones and explicit workload refs
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0291a-1e87-7151-9934-fcbfe3f65eb1
2026-08-22 15:36:37 +02:00
e18894ee5b Scale the blocker window by lane risk, converging with risk-nexus
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
risk-nexus accepted the offer to match their convention rather than grow a second
one, and published it: 14d critical/high, 30d medium, 60d low, nothing auto-closing
on staleness alone. Their preference — point warden route gaps at those windows and
the two registers agree without a shared mechanism — is better than a joint tool.

blocker_stale_days() now maps lane risk onto those windows. A flat 14 would have
been wrong in both directions: too aggressive for a low-risk pointer, and it treated
an admin PAT lane the same as one.

ungraded takes the shortest window, not the longest. ADR-0007 makes an absent grade
a defect and ADR-0008 makes a grade cover the whole path, so a lane nobody graded is
the one whose blocker deserves least trust. Encoding that as 60 days would have been
the fail-open default this repo already fixed once.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 13:29:29 +02:00
55f0f47a02 WARDEN-WP-0033-T05: split the stale cadences, and record how a blocker was verified
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
The 90-day --stale-days default on `warden route gaps` was not a loose threshold,
it was an inert one: the delegation register was created 2026-08-15, so it could
not have fired before November. It was inherited from the catalog pointer cadence
and applied to a claim with a completely different half-life.

Two changes. DEFAULT_BLOCKER_STALE_DAYS = 14 now governs interim blockers, while
DEFAULT_STALE_DAYS = 90 keeps governing pointer freshness -- "is this the right
owner and page" is quarterly, "has the owner answered" is not. 14 is calibrated
on blockers that actually cost something: ten days for the secrets-engine lanes,
one for RISK-F-0001, roughly fifty for FLEX-WP-0007.

The second change matters more. `reviewed` records when someone touched an entry,
which is indistinguishable from re-checking it -- six lanes read as freshly
reviewed today because I typed in them. `verified:` now says how the claim was
established, and asked-and-waiting explicitly does NOT count: that is the state
the secrets-engine blocker sat in for ten days while looking current. A lane in
that state is stale at zero days old, and key-cape-oidc-login proves it works.

8 of 14 interim lanes are honestly marked unverified rather than given a fresh
date they did not earn.

--fail-on-stale exits 3 for a cron or gate. No CI test on age: a date-triggered
failure breaks the build for whoever commits next instead of whoever owns the
blocker. The CI test is structural -- every interim lane must record how it was
verified -- so it fails on the commit that introduces the omission.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 13:26:10 +02:00
d0d4f9d8fc Make the risk grade fail safe, and gate CI on absence
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
The mechanism behind RISK-F-0003 was sharper than the finding described.
is_high_risk was risk == "high", but risk was never absent at the model layer:
RouteEntry.risk carried a dataclass default of "standard". An omitted grade was
not unhandled, it was actively resolved to the permissive value — fail-open by
construction, which is why nothing ever warned.

The default is now "ungraded" and is_high_risk returns true for anything outside
an explicit low-risk vocabulary (standard / low / accepted). An omitted grade and
an unrecognised grade from a newer catalog both resolve to high, so the boundary
fails safe in both directions rather than reading an unknown value as permission.

test_every_repo_catalog_lane_is_explicitly_graded is the CI gate that stops an
ungraded lane being committed, per ADR-0007: absence is not a grade.

"accepted" is in the low-risk vocabulary deliberately, ready for the
maturity-derived default — an experimental-context lane may be explicitly
accepted, which is a graded decision rather than an omission.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 01:13:35 +02:00
0a331413a2 Send a caller identity to flex-auth so policy.enabled can flip
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
flex-auth's flex-auth-ops-warden pin (FLEX-WP-0016) TokenReviews the caller and
binds resource.system: ops-warden to system:serviceaccount:ops-warden:ops-warden.
policy.py posted /v1/check with no Authorization header, so the pin logs
"caller authentication warning" and can only run callerAuth.mode: warn — which,
under ADHOC-2026-08-17-T01, is exactly what blocks policy.enabled: true.

- policy.caller_auth (none | file | env | command) + src/warden/caller_identity.py:
  token resolved per call, never cached, written, or logged (ADR-0002)
- both check_sign_policy and check_fetch_policy attach the bearer header; an
  unobtainable token fails closed rather than retrying anonymously
- scripts/check_policy_caller_identity.py: read-only gate, prints length and a
  truncated fingerprint only, distinguishes 401 (audience/binding) from 403
- example config: caller_auth block, and flex_auth_url corrected — it pointed at
  flex-auth.flex-auth.svc, a Service that does not exist
- WARDEN-WP-0031, PolicyGatedSigning caller-identity section and flip sequence

Default stays mode: none, so behaviour is unchanged until an operator opts in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 15:08:34 +02:00
c93e3c9b43 Ship WARDEN-WP-0030: delegation register for every catalog lane
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Every execution position is now explicit. Catalog entries carry
delegation.mode (permanent / native / interim) with intended owner and
blocker. warden route gaps lists the interim set. Promotion requires
the ownership question. Doctrine lives in AccessRouting.md; the
register was published to the named owner repos.
2026-08-15 20:54:58 +02:00
5149946a4c WARDEN-WP-0029: implement plan front door, org posture, desk, freshness
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s
Ship posture-aware access planning: organization_posture=build (axis C),
catalog freshness warnings, warden plan verdicts, localhost founder desk,
and playbook/agent guidance that retire /tmp file-drop patterns.

Compose route catalog + handoff rather than a second routing layer.
2026-07-18 16:59:37 +02:00
b971403dad WARDEN-WP-0026 finish Strand A (T04/T05/T07)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Promote railiance-backup-offsite-lane to active/resolvable after
capabilities-safe re-verify. Add catalog risk=high, agent read-boundary
(exit 7 + OpenBao policy companion), EXPOSED taint via warden taint, and
close WP-0026.
2026-07-16 23:26:26 +02:00
fc0f18aa5c WARDEN-WP-0026 T03: masking display filter (defense-in-depth)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
- warden/mask.py: fingerprint()/mask_value() — presence, length, 8-char sha256
  prefix; never the value.
- proxy.proxy_fetch_fingerprint + `warden access --fingerprint`: masked status view
  (presence/length/hash) that emits no value, so it bypasses the T02 stdout guard.
  Lets two parties compare sha256 prefixes to confirm a shared value without seeing
  it (e.g. rotation landed).
- documented as defense-in-depth (raw bao bypasses it) in OperatorAccessAssist.md
  and the module docstring.
- tests: tests/test_mask.py + CLI fingerprint test. 299 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 14:54:55 +02:00
359ca1bd0e WARDEN-WP-0026 T02: safe access transports (no secret values on stdout)
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s
- proxy.py: proxy_fetch_to_file (mode-0600 file), build_wrapped_fetch +
  proxy_fetch_wrapped (single-use OpenBao response-wrapping token), _capture_value
  helper, is_bao_kv_fetch.
- warden access: --out FILE, --wrap [--wrap-ttl], --unsafe-stdout. Raw --fetch to a
  non-TTY stdout is refused (exit 6) — captured/piped output is the disclosure risk;
  sanctioned transports are --out / --exec / --wrap.
- canon: anti-pattern (secret value onto captured stdout) + transport table in
  .claude/rules/credential-routing.md; OperatorAccessAssist.md examples + G2 updated.
- tests: file/wrap/build + stdout-guard in tests/test_proxy.py. 293 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 14:51:56 +02:00
c3eb59ea04 WARDEN-WP-0026 T06: rotation guidance registry + warden rotate-guide
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
- routing model: RotationGuide (method rotate|re-establish, steps, owner,
  automatable), RouteEntry.rotation + has_rotation + vends_secret.
- catalog parser: validate rotation block; secret-material screen gains a
  prose-safe mode (high-entropy detector only) so authored steps aren't tripped
  by substrings like "s."/"exists.".
- CLI: `warden rotate-guide <id>` (human + --json); route show --json now
  carries has_rotation + rotation.
- scorecard: catalog_rotation_coverage — every active secret-vending lane must
  carry a rotation block (SSH/login/pointer lanes exempt). Promotion checklist
  criterion 9.
- data: rotation blocks for all 7 active vending lanes + the draft
  railiance-backup lane (re-establish: age keypair regen + re-encrypt).
- fix pre-existing collision: bare `npm` keyword on forgejo-admin -> forgejo-npm
  so "npm token" routes to the generic lane (restores test_access expectations).
- tests: rotation parse/coverage/prose-screen/CLI in tests/test_routing.py;
  scorecard count 6 -> 7.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 14:40:30 +02:00
be3b4a2a86 Fix warden access proxy for catalog fetch commands with shell pipes.
resolve_fetch_command used shlex.split, which treated `|` as a literal
argument — breaking reuse-surface-hub-write-token (kubectl | base64 -d).
Piped commands now run via shell=True with inherited stdio for --fetch.
2026-07-07 16:42:26 +02:00
210f7eab68 Add Makefile targets to install and verify phase-memory with warden.
install-all uses uv tool install --with-editable for sibling phase-memory.
check-memory and verify-memory confirm warden can load experiential memory.
2026-07-03 00:54:21 +02:00
120de64bcb Enable implicit phase-memory activation on every warden command.
Load coordination memory by default via ensure_memory_context on app bootstrap
and route/access flows; invalidate cache after episode writes. WARDEN_MEMORY=0
remains the opt-out. Document that warden memory activate is optional only.
2026-07-03 00:49:36 +02:00
04929e7981 Implement WARDEN-WP-0024 experiential memory and agent sessions.
Add phase-memory bridge, warden memory CLI, route/access/sign recording,
memory-aware worker planning with OpenRouter skip, tests, wiki, and AGENTS.md
orientation for Claude, Codex, Grok, and future agent sessions.
2026-07-02 23:40:45 +02:00
d6088e4e16 Implement WP-0022 audit trail and WP-0023 INTENT–SCOPE closeout
Add unified metadata-only audit.jsonl with secret-material guard, instrument
sign/access/worker paths, and expose warden activity CLI. Surface broker hint
when VAULT_TOKEN is unset, refresh INTENT/SCOPE docs, and add production
integration checklists plus catalog lane promotion playbook.
2026-07-01 23:32:38 +02:00
a10bbd2162 feat(WARDEN-WP-0021): T3-T5 — visibility, approve loop, runbook (scheduled worker complete)
T4 (review→send loop): conservative tick persists structured drafts to
state_dir/worker-drafts.json; `warden worker drafts` lists them, `warden worker approve
<id> [--body …]` sends the reviewed draft as the reply + marks read + drops it. Escalated
plans persist no draft. Live-verified end-to-end.

T3 (visibility): `warden worker status` (pending drafts, triage count, last digest, timer
state); best-effort notify-send nudge in the tick when drafts are pending.

T5: wiki/playbooks/scheduled-worker.md (enable/disable, the approve loop, failure modes,
conservative-only posture) + SCOPE note.

WARDEN-WP-0021 finished: the conservative worker now runs on a systemd --user timer
(enabled, every 15 min), triages new inbox messages into drafts you approve with one
command, degrades gracefully, and stops with one command. 249 tests, lint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 15:24:10 +02:00
d0261ebb52 feat(WARDEN-WP-0020): conservative triage tier as the --execute default (Option A)
Per Bernd's call: the guardrails prevent security harm but not LLM content errors, so the
worker should triage + draft, not auto-send, until reply quality is proven (matches the
build-stage/recoverability posture).

run_conservative triages NEW messages into a reviewed digest (state_dir/worker-digest.md)
with drafted replies, posts ONE progress note, tracks seen message ids (schedule-safe
dedup), and sends NOTHING to other agents / marks nothing read. `warden worker run
--execute` now runs this conservative tier; `--full-auto` opts into the auto-send path.

Live-verified with the LLM brain on the real inbox: produced a high-quality draft reply to
a secrets-engine coordination message and correctly flagged the llm-connect custody request
as NEEDS YOU. Conservative mode is safe to schedule (T4). 244 tests, lint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 00:38:36 +02:00
f8ac55367c feat(WARDEN-WP-0020): T3 — guarded executor (worker now acts, not just plans)
HubClient gains writes (mark_read, send_reply, add_progress). execute_plan/execute_plans
run the safe, allowlisted actions autonomously: route_answer (reply with the computed
answer + auto mark-read), reply (LLM-drafted body), progress_note, mark_read. Escalated
plans and non-auto-executable kinds are left for a human; every action is metadata-only
(no secret value read/sent/logged).

Deliberate guardrail: propose_catalog_diff and any code/routing change is NOT auto-executed
even under full-auto — a bad catalog commit could misroute credentials, so it goes to human
review (recoverability over convenience). AUTO_EXECUTABLE is the messaging/hub tier only.

`warden worker run --execute` runs the executor (dry-run still default). 7 executor tests
(reply+mark, with/without body, escalated skip, catalog-diff-left-for-human, progress,
failure-without-crash); 243 pass, lint clean. First live --execute shakedown is the
operator's (staged rollout); T4 schedules it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 23:19:13 +02:00
859beed07f feat(WARDEN-WP-0020): T2 — llm-connect brain (autonomous worker now thinks)
llm-connect is operational (operator set OPENROUTER_API_KEY). Contract discovered from
the running service: POST /execute {"prompt":...} -> {"content":...}.

LlmConnectBrain embeds the fixed charter + the inbox message as untrusted data, calls
/execute, and parses a JSON action plan (_extract_json tolerates fences/prose), escalating
defensively on malformed/empty/transport errors. The build_plans guardrail still enforces
the allowlist + no-secret invariant on whatever the model returns — the LLM cannot widen
ops-warden's authority. `warden worker run --brain rule|llm` selects the planner.

Live-verified on the real inbox: the LLM brain planned a sensible reply+mark_read for a
secrets-engine coordination message and correctly escalated a secret-custody request as
out-of-lane — better classification than the deterministic RuleBrain.

6 new tests, 236 pass, lint clean. T3 (guarded executor) and T4 (scheduling) remain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 23:10:28 +02:00
4287eccc80 feat(WARDEN-WP-0020): worker drafts real route answers in dry-run (T3 groundwork)
build_plans now computes the concrete routing answer for each route_answer action
in-process (reuses the catalog; read-only, no subprocess/network) and render_plans
shows it as a `draft:` line. The dry-run demonstrates the actual answer the executor
(T3) will send, not just an intent. RuleBrain stays the default; the llm-connect brain
(T2) is gated on llm-connect being operational + its /execute contract.

230 tests, lint clean. Live dry-run verified against the real inbox.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 22:42:54 +02:00