Commit graph

16 commits

Author SHA1 Message Date
f815bb35ca Implement §5.3 machine-readably — layer.yaml, checker, conformance tests
The security layer model moved v0.1 -> v0.4 (accepted) after ops-warden's
assent. Both §5 asks from ADR-0010 were adopted: §5.2 now sanctions the conduit
shape on the supplied-authority property, and §5.3 is the declared engine gap
amendment, carrying the four fields verbatim and crediting ops-warden's
delegation machinery as prior art.

Which creates an obligation. §5.3 requires those fields MACHINE-READABLY, and
§11 makes "every direct Tooling client maps to a declared §5.1/§5.2/§5.3 entry"
a mechanical check. ops-warden's declaration was prose in INTENT.md — the repo
that proposed the shape was not implementing it.

layer.yaml is the map: 5 contacts (2 declared gaps, 1 read-only observation,
2 conduits) plus the non-Tooling clients recorded explicitly so the check is
total rather than silently selective.

scripts/check_layer_conformance.py enforces it and found three undeclared
modules on its first run — all false positives (help text, a docstring, and the
doubles library that SIMULATES bao rather than calling it), which is why the
scan now matches invocation shapes instead of the word: an httpx call built
against the configured OpenBao address, or an argv whose first element is the
bao binary.

tests/test_layer_conformance.py adds the §5.2 test the standard says SHOULD
exist: _caller_env() returns the caller's environment unchanged, and proxy.py
is asserted not to reference X-Vault-Token, approle login, or token create — a
conduit that presents its own token is not a conduit.

No assertion on review dates, deliberately: a date-triggered failure breaks the
build on a calendar day with no code change, the same reasoning WP-0033-T05
recorded for blocker staleness.

398 tests pass, ruff clean.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-29 02:45:29 +02:00
e24d2d5bd0 docs: record live zone config migration
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:50:42 +02:00
6604ace982 chore: refresh generated security inputs
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:37:33 +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
6e1d5201aa WARDEN-WP-0033-T03: emit the high-risk data-path artifact
railiance-platform asked for a generated list to consume instead of hand-
maintaining agent-high-risk-boundary. Hand-maintaining it is what let the two
lists drift for four lanes in RISK-F-0009.

19 high-risk lanes, 14 concrete data paths, 5 without a single KV address listed
separately so absence does not read as omission. Carries catalog_revision and a
dirty flag. fields is null where unestablished, never a one-element guess.

The header states plainly that this is an input and not a policy: railiance-
platform owns the deny set and may deny more, less, or dispute a grade. ADR-0002
survives the handoff.

Two CI tests guard staleness, because a consumer applies this to a live control.
Note the immediate consequence of T02: 2 uncovered against a policy they closed
to 0 yesterday.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 08:38:13 +02:00
edb587851c Verify the OpenBao read-boundary live; ship the invariant
The operator token was not expired after all -- `bao policy read` succeeded, so
the deployed policy is now compared directly instead of the file. Three
corrections to RISK-F-0009, which was filed static:

1. Six high-risk lanes are uncovered, not eight. The finding counted
   openbao-api-key (a path pattern) and ops-warden-warden-sign-token (a broker
   grant, not KV) among the concrete uncovered paths, while its own prose said
   the first was a pattern. Five lanes have no address for a policy to deny.
2. Coverage holds at 6 of 17 against the live policy.
3. The deployed policy has drifted from the file: the file denies
   platform/workloads/core-hub/runtime, the server does not. No ops-warden lane
   maps there so our numbers are unchanged, but it proves the file was never a
   safe proxy for the server -- which is what the finding flagged as unconfirmed.

scripts/check_agent_read_boundary.py is the invariant RISK-F-0009 asked for
rather than a one-off audit: it fails when a high-risk lane has no corresponding
deny. Capabilities-only by construction -- it reads the policy document, never a
secret value, and never mints a token.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 00:50:00 +02:00
72f7dc2c5d Add scripts/report_workload_join.py — measure the lane-to-workload join
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Computes the join rather than asserting it, and offers both plausible workload
segments per path instead of a single positional guess, because the path
convention is inconsistent.

Measured result: 1 of 27 lanes matches a declared workload. The workload
declaration surface exists, but it covers almost none of the credential estate.

Read-only; touches no secret value and no live system.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 07:22:07 +02:00
654c05dece WARDEN-WP-0031 T04: prove ops-warden's caller identity against the live pin
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
flex-auth's binding names system:serviceaccount:ops-warden:ops-warden, and that
ServiceAccount did not exist. deploy/kubernetes/caller-identity.yaml creates it
plus its namespace — no RBAC, automount off; it is never used to call the
Kubernetes API, only to be TokenReviewed. Applied to the railiance01 cluster.

Operator warden.yaml now uses caller_auth mode: command (kubectl create token,
audience flex-auth, 10m). Gate exits 0 live against a port-forward of the pin:
HTTP 200, effect=allow, decision:f3f7c88f9585582a.

The evidence is not that allow — warn allows anonymous callers too. It is that
the pin's "caller authentication warning" count held at 4 across two
authenticated runs. That is the ADHOC-2026-08-17-T01 condition.

Also gives the readiness probe a structurally complete context, so a deny means
the policy said no rather than the probe being malformed.

policy.enabled stays false. T05 waits on flex-auth setting callerAuth.mode:
enforce (their FLEX-WP-0016 T03).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 19:06:04 +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
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
9dc1db0162 feat(WARDEN-WP-0021): T1+T2 — scheduled worker tick enabled (systemd --user timer)
T1: systemd --user units (ops-warden-worker.{service,timer}) + scripts/install-worker-timer.sh
(--enable opt-in, cron fallback documented) + examples/worker.env.example. Kill switch:
`systemctl --user disable --now ops-warden-worker.timer` or WORKER_ENABLED=0. Installed and
ENABLED — verified a real systemd run (Result=success, used the llm brain) and the timer is
active (next run +15min).

T2: hardened worker-tick.sh — State Hub /state/health precheck → graceful skip (exit 0) when
unreachable; worker-run failure logged but never fails the unit (retry next tick). Verified
hub-down skip and a live tick.

Conservative tier only; nothing auto-sent. Kill switch is one command.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 15:19:23 +02:00
22c5bd1bbb feat(WARDEN-WP-0020): T4 scheduling tick + T5 SCOPE — worker complete
T4 — scripts/worker-tick.sh: scheduled tick for the conservative worker. flock concurrency
guard; short-lived kubectl port-forward to llm-connect (or LLM_CONNECT_URL, or rule-brain
fallback). Ships disabled; header documents the cron entry. Schedules the conservative tier
only (never auto-send).

T5 — SCOPE records `warden worker` as an implemented capability: conservative triage
default, full-auto opt-in, llm-connect brain, the four guardrails, schedulable tick.

WARDEN-WP-0020 finished: the autonomous coordination worker — T1 scaffold, T2 llm-connect
brain, T3 guarded executor, conservative tier (Option A), T4 scheduling, T5 docs. 245 tests,
lint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 00:41:04 +02:00
50ab78392f feat(smoke): joint-smoke mode against deployed flex-auth (assist FLEX-WP-0007 T4)
flex-auth asked ops-warden to help close FLEX-WP-0007 T4 (joint OpenBao + policy-gate
production smoke) against their deployed runtime (reachable on CoulombCore via the
flex-auth-coulombcore tunnel at 127.0.0.1:18090). The smoke previously spawned its own
local flex-auth, so it never exercised the deployed runtime.

Add FLEX_AUTH_EXTERNAL=1 to scripts/policy_gate_production_smoke.sh: skip the local
serve/load-registry and run the allow/deny/vault paths against the already-running
flex-auth, with a /healthz precheck that fails fast with a tunnel-up hint. Verified the
committed production_registry_snapshot.json is current vs inventory (4 actors). Recorded
in ADHOC-2026-06-29.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 00:40:20 +02:00
8bbd22285e feat(WARDEN-WP-0016): ops-bridge cert_command readiness gate + handoff
Close ops-warden's side of the last Partial INTENT criterion (ops-bridge integrates
via a stable cert_command). The migration playbook and contract already existed; what
was missing was an automated readiness gate before touching tunnel config.

T1 — scripts/check_tunnel_cert_readiness.py: read-only preflight that asserts the
cert_command path is ready without signing — config/backend, actor inventory + TTL
within type max, pubkey exists/parses/not-private, principals present, and optional
host-principal deployment (mirrors check_principals_drift). Exit 0/1/2.

T2 — opt-in --sign-smoke: runs the cert_command against the local backend and validates
identity/principals/TTL of the emitted cert; refuses a vault backend. Window measured
from the cert's own valid_from->valid_before so it's timezone-robust (fixes a CEST
off-by-2h artifact). integration-marked test + a vault-refusal unit test.

T3 — playbook now leads with Step 0 readiness gate; ops-bridge handoff message sent.
T4 — SCOPE INTENT row: Partial -> Pilot-ready; known-gaps + SSH-lane list updated.

9 unit + 1 integration test, 209 default passing, lint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 19:50:28 +02:00
41a55c95b0 feat(WARDEN-WP-0015): T3 conformance checker + T4 dev-tier contract doubles
Finish the Workload Security Posture workplan (all five tasks done).

T3 — scripts/check_secret_posture_conformance.py: read-only checker that asserts
env-posture conformance (backend/unseal/real_values per tier) and evaluates the
secret-flow lattice via posture.can_deliver. Metadata-only manifest, no secret
values, exit 0/1/2. examples/posture-conformance.example.yaml as the reference.

T4 — src/warden/doubles.py: generalizes "fake bao" into materialize_doubles() —
hermetic, synthetic-only (synthetic- prefix) stand-ins for bao/key-cape honoring
each argv/stdout/exit contract, for fully offline dev/test access flows. Documented
as the sanctioned dev backend in WorkloadSecurityPosture.md R1.

T5 — INTENT/SCOPE/wiki aligned; canon landing in net-kingdom/info-tech-canon left
owner-driven (tracked via coordination messages).

16 new tests, 200 passing, ruff clean. Archived WP-0012/0014/0015 to
workplans/archived/ with 260627- prefix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 19:30:30 +02:00
90007c2cda feat: close WP-0009/WP-0013 production integration stewardship strand
Ship flex-auth policy gate registry and smoke evidence, archive WP-0009
through WP-0013, and add integration docs: ops-bridge cert_command
migration playbook, operator OpenBao token hygiene, principals drift
check script, and 2026-06-24 INTENT/SCOPE gap analysis.
2026-06-24 12:44:32 +02:00