generated from coulomb/repo-seed
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>
This commit is contained in:
34
SCOPE.md
34
SCOPE.md
@@ -31,11 +31,12 @@ NetKingdom security map, machine-readable pointer catalog
|
||||
handoffs for every catalog need and can proxy `exec_capable` lanes as the caller,
|
||||
without taking custody of values.
|
||||
|
||||
**Workload security posture** is drafted (WP-0015 T1): dev/test/prod environment
|
||||
posture, M0-M3 workload maturity, the secret-flow lattice, and blocker triage
|
||||
language. Machine-readable descriptors and `warden policy list|show` shipped in
|
||||
WP-0015 T2; the read-only conformance checker and dev contract doubles remain
|
||||
WP-0015 follow-up tasks.
|
||||
**Workload security posture** is shipped (WP-0015, all tasks done): dev/test/prod
|
||||
environment posture, M0-M3 workload maturity, the secret-flow lattice, and blocker
|
||||
triage language (T1); machine-readable descriptors + `warden policy list|show` (T2);
|
||||
the read-only conformance checker `scripts/check_secret_posture_conformance.py` (T3);
|
||||
and the dev-tier contract-double library `warden.doubles` (T4). Canon landing in
|
||||
net-kingdom / info-tech-canon is owner-driven (tracked via coordination messages, T5).
|
||||
|
||||
**Policy gate** is shipped on the caller side (WP-0007) with production registry
|
||||
and smoke evidence (WP-0009 archived). flex-auth published the `ssh-certificate`
|
||||
@@ -77,7 +78,7 @@ Gap analysis: `history/2026-06-24-intent-scope-gap-analysis.md` (current);
|
||||
| ops-bridge integrates via stable `cert_command` | **Partial** — contract yes; tunnels still static-key |
|
||||
| NetKingdom evolution reflected in docs | Met |
|
||||
| Non-SSH secrets stay out of ops-warden | Met |
|
||||
| Workload posture / maturity model for secret-flow blockers | Drafted (WP-0015 T1); conformance tooling pending |
|
||||
| Workload posture / maturity model for secret-flow blockers | Met — two-axis standard + descriptors + conformance checker + dev doubles (WP-0015) |
|
||||
|
||||
**Maturity vector:** `D5 / A5 / C4 / R3` (Discovery / Availability / Completeness / Reliability)
|
||||
|
||||
@@ -132,8 +133,9 @@ for the rest.
|
||||
- Capability registry entry for SSH certificate issuance
|
||||
- Routing pointer catalog (`registry/routing/catalog.yaml`)
|
||||
- Keeping ops access patterns consistent with `net-kingdom` platform architecture
|
||||
- Workload Security Posture draft (`wiki/WorkloadSecurityPosture.md`) and planned
|
||||
machine-readable posture descriptors, conformance checks, and dev-tier doubles
|
||||
- Workload Security Posture standard (`wiki/WorkloadSecurityPosture.md`),
|
||||
machine-readable posture descriptors (`registry/policy/security-posture.yaml`),
|
||||
the read-only conformance checker, and the dev-tier contract-double library
|
||||
|
||||
### Shipped workplans (archived)
|
||||
|
||||
@@ -146,14 +148,15 @@ for the rest.
|
||||
| WP-0009 | flex-auth registry + policy smoke; pickup brief for FLEX-WP-0007 |
|
||||
| WP-0010 | Access routing charter + pointer catalog |
|
||||
| WP-0011 | `warden route` lookup CLI |
|
||||
| WP-0012 | Routing scenario playbooks (catalog + wiki expansion) |
|
||||
| WP-0013 | Production integration closeout — cert_command playbook, token hygiene, principals drift |
|
||||
| WP-0014 | Operator access assist — `warden access` advisory + proxy front door |
|
||||
| WP-0015 | Workload security posture — two-axis standard, descriptors, conformance checker, dev doubles |
|
||||
|
||||
### Active / ready
|
||||
|
||||
| WP | Status | Focus |
|
||||
| --- | --- | --- |
|
||||
| **WP-0012** | `active` | Routing scenario playbooks (catalog + wiki expansion) |
|
||||
| **WP-0015** | `active` | Workload security posture: env posture, maturity, conformance, dev doubles |
|
||||
_None open._ All ops-warden workplans are finished; the remaining distance is in other
|
||||
repos' lanes (see Known gaps).
|
||||
|
||||
### Known gaps (not ops-warden workplans)
|
||||
|
||||
@@ -164,7 +167,7 @@ for the rest.
|
||||
| ops-bridge `cert_command` on live tunnels | ops-bridge | Playbook shipped (`wiki/playbooks/ops-bridge-tunnel-cert.md`); pilot pending |
|
||||
| Principals sync warden ↔ railiance-infra | ops-warden + infra | `scripts/check_principals_drift.py` — operator runs periodically |
|
||||
| NK-WP-0009 joint SSH tutorial | net-kingdom | Parallel coordination track |
|
||||
| WP-0015 conformance checker/dev doubles | ops-warden | T3-T4 pending; canon landing tracked in T5 |
|
||||
| WP-0015 canon landing (generic `WorkloadMaturityLevel` + M0-M3 requirements) | net-kingdom + info-tech-canon | ops-warden drafted + offered (coordination msgs); owner-driven landing |
|
||||
|
||||
---
|
||||
|
||||
@@ -216,8 +219,9 @@ for the rest.
|
||||
- **Access routing:** WP-0010 + WP-0011 shipped (`warden route`, pointer catalog)
|
||||
- **Policy gate:** caller shipped (WP-0007); registry + smoke complete (WP-0009 archived).
|
||||
`policy.enabled: false` until flex-auth reachable (`FLEX-WP-0007`)
|
||||
- **Active work:** WP-0012 (routing playbooks — T2/T3 done) and WP-0015
|
||||
(workload posture T1/T2 done, T5 in progress; checker/dev doubles pending)
|
||||
- **Workload posture:** WP-0015 shipped (standard, descriptors, `warden policy`,
|
||||
conformance checker, dev doubles); canon landing owner-driven
|
||||
- **Active work:** none open in ops-warden; remaining distance is other repos' lanes
|
||||
- **Integration docs:** cert_command migration, token hygiene, principals drift (`wiki/playbooks/`)
|
||||
- **Latest assessment:** `history/2026-06-24-intent-scope-gap-analysis.md`
|
||||
|
||||
|
||||
41
examples/posture-conformance.example.yaml
Normal file
41
examples/posture-conformance.example.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
# Example target manifest for scripts/check_secret_posture_conformance.py (WP-0015 T3).
|
||||
#
|
||||
# A *metadata-only* description of workloads, the observed posture of each
|
||||
# environment's secret store, and the secret flows being requested. It carries NO
|
||||
# secret values — only ids, postures, maturities, required_maturity, and data class.
|
||||
# The checker compares this against registry/policy/security-posture.yaml and the
|
||||
# secret-flow lattice, and reports conformance + lattice violations. Read-only.
|
||||
|
||||
# Observed posture of each environment's secret store. The checker asserts these
|
||||
# match the standard env_postures descriptor (backend / unseal / real_values).
|
||||
environments:
|
||||
dev:
|
||||
backend: mock-or-contract-double
|
||||
real_values: forbidden
|
||||
unseal: n/a
|
||||
prod:
|
||||
backend: openbao-sealed-shamir
|
||||
real_values: generated-fresh-no-reuse
|
||||
unseal: shamir-3-of-5-break-glass
|
||||
|
||||
# Workloads and the trust we attribute to each (env posture + maturity level).
|
||||
workloads:
|
||||
- id: activity-core-triage
|
||||
env_posture: prod
|
||||
maturity: M2
|
||||
- id: dev-sandbox
|
||||
env_posture: dev
|
||||
maturity: M0
|
||||
|
||||
# Secret flows being requested. Each is evaluated against the lattice for its
|
||||
# target workload. required_maturity / dataclass are the secret's *requirements*,
|
||||
# never the value.
|
||||
secret_requests:
|
||||
- secret: openrouter-api-key
|
||||
to_workload: activity-core-triage
|
||||
required_maturity: M2
|
||||
dataclass: confidential
|
||||
- secret: regulated-export-cred
|
||||
to_workload: dev-sandbox # expected DENY: dev posture + M0 < M3
|
||||
required_maturity: M3
|
||||
dataclass: restricted
|
||||
165
scripts/check_secret_posture_conformance.py
Normal file
165
scripts/check_secret_posture_conformance.py
Normal file
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Read-only conformance checker for the Workload Security Posture (WP-0015 T3).
|
||||
|
||||
Given a *metadata-only* target manifest (see ``examples/posture-conformance.example.yaml``),
|
||||
assert two things against ``registry/policy/security-posture.yaml``:
|
||||
|
||||
1. **Environment posture conformance** — each environment's observed secret-store
|
||||
posture (backend / unseal / real_values) matches the standard descriptor for that
|
||||
tier. Catches "prod" stores that are not sealed-Shamir, or a "dev" store that admits
|
||||
real values.
|
||||
2. **Secret-flow lattice** — every requested secret flow is permitted by the
|
||||
no-write-down lattice for its target workload (``warden.posture.can_deliver``):
|
||||
prod posture, and workload maturity >= the secret's ``required_maturity`` and the
|
||||
data-class floor.
|
||||
|
||||
Exit 0 when fully conformant; exit 1 on any violation; exit 2 on bad input. This script
|
||||
reads descriptors and target metadata only — it never reads, fetches, or prints a secret
|
||||
value. Drift-report shaped, mirroring ``scripts/check_principals_drift.py``.
|
||||
|
||||
Usage:
|
||||
python scripts/check_secret_posture_conformance.py \\
|
||||
--manifest examples/posture-conformance.example.yaml
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
# Allow running as a plain script (no install) by adding src/ to the path.
|
||||
_SRC = Path(__file__).resolve().parent.parent / "src"
|
||||
if _SRC.is_dir() and str(_SRC) not in sys.path:
|
||||
sys.path.insert(0, str(_SRC))
|
||||
|
||||
import yaml # noqa: E402
|
||||
|
||||
from warden.posture import PostureCatalog, PostureError, load_posture # noqa: E402
|
||||
|
||||
# Fields of an env posture that a target environment is expected to match.
|
||||
_ENV_CONFORMANCE_FIELDS = ("backend", "unseal", "real_values")
|
||||
|
||||
|
||||
def check_environments(
|
||||
cat: PostureCatalog, environments: Dict[str, Any]
|
||||
) -> List[str]:
|
||||
"""Return a list of env-posture conformance violations (empty == conformant)."""
|
||||
violations: List[str] = []
|
||||
for env_id, observed in (environments or {}).items():
|
||||
standard = cat.env(env_id)
|
||||
if standard is None:
|
||||
violations.append(f"environment {env_id!r}: not a known env posture")
|
||||
continue
|
||||
observed = observed or {}
|
||||
for field in _ENV_CONFORMANCE_FIELDS:
|
||||
if field not in observed:
|
||||
continue # field not asserted by the manifest — skip, don't fail
|
||||
want = getattr(standard, field)
|
||||
got = str(observed[field])
|
||||
if got != want:
|
||||
violations.append(
|
||||
f"environment {env_id!r}: {field} is {got!r}, "
|
||||
f"standard requires {want!r}"
|
||||
)
|
||||
return violations
|
||||
|
||||
|
||||
def check_secret_flows(
|
||||
cat: PostureCatalog,
|
||||
workloads: List[Dict[str, Any]],
|
||||
secret_requests: List[Dict[str, Any]],
|
||||
) -> List[str]:
|
||||
"""Return a list of lattice violations for the requested secret flows."""
|
||||
by_id = {str(w["id"]): w for w in (workloads or [])}
|
||||
violations: List[str] = []
|
||||
for req in secret_requests or []:
|
||||
secret = str(req.get("secret", "<unnamed>"))
|
||||
target = str(req.get("to_workload", ""))
|
||||
workload = by_id.get(target)
|
||||
if workload is None:
|
||||
violations.append(
|
||||
f"secret {secret!r}: target workload {target!r} not in manifest"
|
||||
)
|
||||
continue
|
||||
try:
|
||||
allowed, reasons = cat.can_deliver(
|
||||
workload_env=str(workload["env_posture"]),
|
||||
workload_maturity=str(workload["maturity"]),
|
||||
secret_required_maturity=str(req["required_maturity"]),
|
||||
secret_dataclass=(
|
||||
str(req["dataclass"]) if req.get("dataclass") is not None else None
|
||||
),
|
||||
)
|
||||
except (PostureError, KeyError) as e:
|
||||
violations.append(f"secret {secret!r} -> {target!r}: cannot evaluate ({e})")
|
||||
continue
|
||||
if not allowed:
|
||||
violations.append(
|
||||
f"secret {secret!r} -> workload {target!r}: DENIED — "
|
||||
+ "; ".join(reasons)
|
||||
)
|
||||
return violations
|
||||
|
||||
|
||||
def run(manifest: Dict[str, Any], cat: Optional[PostureCatalog] = None) -> List[str]:
|
||||
"""Evaluate a manifest, returning all violations (empty == conformant)."""
|
||||
cat = cat or load_posture()
|
||||
return check_environments(cat, manifest.get("environments") or {}) + check_secret_flows(
|
||||
cat,
|
||||
manifest.get("workloads") or [],
|
||||
manifest.get("secret_requests") or [],
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--manifest",
|
||||
type=Path,
|
||||
required=True,
|
||||
help="Target manifest (metadata only; see examples/posture-conformance.example.yaml)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.manifest.exists():
|
||||
print(f"manifest not found: {args.manifest}", file=sys.stderr)
|
||||
return 2
|
||||
try:
|
||||
manifest = yaml.safe_load(args.manifest.read_text()) or {}
|
||||
except yaml.YAMLError as e:
|
||||
print(f"invalid YAML in manifest: {e}", file=sys.stderr)
|
||||
return 2
|
||||
if not isinstance(manifest, dict):
|
||||
print("manifest must be a YAML mapping", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
try:
|
||||
cat = load_posture()
|
||||
except PostureError as e:
|
||||
print(f"cannot load posture descriptors: {e}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
violations = run(manifest, cat)
|
||||
|
||||
n_env = len(manifest.get("environments") or {})
|
||||
n_workloads = len(manifest.get("workloads") or [])
|
||||
n_flows = len(manifest.get("secret_requests") or [])
|
||||
print(
|
||||
f"checked {n_env} environment(s), {n_workloads} workload(s), "
|
||||
f"{n_flows} secret flow(s) against {cat.path}"
|
||||
)
|
||||
|
||||
if not violations:
|
||||
print("\nOK — conformant with the Workload Security Posture standard")
|
||||
return 0
|
||||
|
||||
print(f"\n{len(violations)} CONFORMANCE VIOLATION(S):")
|
||||
for v in violations:
|
||||
print(f" - {v}")
|
||||
print("\nStandard: wiki/WorkloadSecurityPosture.md")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
133
src/warden/doubles.py
Normal file
133
src/warden/doubles.py
Normal file
@@ -0,0 +1,133 @@
|
||||
"""Dev-tier contract doubles for routed subsystems (WP-0015 T4).
|
||||
|
||||
This generalizes the "fake bao" smoke pattern into a small, hermetic library: it
|
||||
materializes stand-in executables for the subsystems ops-warden *routes* to (OpenBao,
|
||||
key-cape login) so that access flows (``warden access --fetch/--exec``, the login lane)
|
||||
can be exercised fully offline in **dev/test** posture.
|
||||
|
||||
Contract, not behavior. Each double honors only the *interface contract* the proxy
|
||||
relies on (argv shape, stdout, exit code) and emits **synthetic values only** — every
|
||||
emitted value is prefixed ``synthetic-`` so it can never be mistaken for, or promoted
|
||||
as, a real secret (Axis-A rule R3: dev touches no real data). These doubles are the
|
||||
sanctioned ``backend: mock-or-contract-double`` for the ``dev`` env posture.
|
||||
|
||||
They are a dev/test convenience, never a runtime component: nothing here vends, stores,
|
||||
or proxies a real credential.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import stat
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
|
||||
# Marker every synthetic value carries — asserted in tests, greppable in logs.
|
||||
SYNTHETIC_PREFIX = "synthetic-"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Double:
|
||||
"""A single contract double: the command name and the script that backs it."""
|
||||
|
||||
name: str # the executable name on PATH (e.g. "bao")
|
||||
contract: str # one-line description of the contract it honors
|
||||
script: str # the script body (shebang included)
|
||||
|
||||
|
||||
def _bao_script() -> str:
|
||||
# Honors: `bao kv get -field=<F> <path>` -> synthetic value on stdout, exit 0.
|
||||
# `bao login ...` -> token line on stdout, exit 0.
|
||||
# Any other subcommand exits 2 so contract drift surfaces loudly.
|
||||
return r"""#!/usr/bin/env bash
|
||||
# Contract double for OpenBao (synthetic values only — WP-0015 T4).
|
||||
set -euo pipefail
|
||||
SUFFIX="${WARDEN_DOUBLE_SUFFIX:-bao}"
|
||||
case "${1:-}" in
|
||||
kv)
|
||||
if [[ "${2:-}" == "get" ]]; then
|
||||
field="generic"
|
||||
for a in "$@"; do
|
||||
case "$a" in -field=*) field="${a#-field=}";; esac
|
||||
done
|
||||
echo "synthetic-${field}-${SUFFIX}"
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
login)
|
||||
echo "synthetic-token-${SUFFIX}"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
echo "fake-bao: unsupported contract: $*" >&2
|
||||
exit 2
|
||||
"""
|
||||
|
||||
|
||||
def _keycape_script() -> str:
|
||||
# Honors: `key-cape login ...` -> interactive-shaped success line, exit 0.
|
||||
return r"""#!/usr/bin/env bash
|
||||
# Contract double for key-cape OIDC login (synthetic — WP-0015 T4).
|
||||
set -euo pipefail
|
||||
SUFFIX="${WARDEN_DOUBLE_SUFFIX:-keycape}"
|
||||
case "${1:-}" in
|
||||
login)
|
||||
echo "synthetic-oidc-session-${SUFFIX}"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
echo "fake-key-cape: unsupported contract: $*" >&2
|
||||
exit 2
|
||||
"""
|
||||
|
||||
|
||||
# The registry of available doubles, keyed by subsystem command name.
|
||||
_DOUBLES: Dict[str, Double] = {
|
||||
"bao": Double(
|
||||
name="bao",
|
||||
contract="bao kv get -field=<F> <path> | bao login",
|
||||
script=_bao_script(),
|
||||
),
|
||||
"key-cape": Double(
|
||||
name="key-cape",
|
||||
contract="key-cape login <args>",
|
||||
script=_keycape_script(),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def available_doubles() -> List[str]:
|
||||
"""Names of the subsystems a double can be materialized for."""
|
||||
return sorted(_DOUBLES)
|
||||
|
||||
|
||||
def materialize_doubles(dest_dir: Path, names: List[str] | None = None) -> Dict[str, Path]:
|
||||
"""Write the requested contract doubles into ``dest_dir`` as executables.
|
||||
|
||||
Returns a mapping of subsystem name -> path. ``names=None`` materializes all.
|
||||
Prepend ``dest_dir`` to ``PATH`` to run an access flow fully offline against them.
|
||||
"""
|
||||
dest_dir = Path(dest_dir)
|
||||
dest_dir.mkdir(parents=True, exist_ok=True)
|
||||
selected = names if names is not None else list(_DOUBLES)
|
||||
out: Dict[str, Path] = {}
|
||||
for name in selected:
|
||||
double = _DOUBLES.get(name)
|
||||
if double is None:
|
||||
raise KeyError(
|
||||
f"no contract double for {name!r}; available: {available_doubles()}"
|
||||
)
|
||||
target = dest_dir / double.name
|
||||
target.write_text(double.script)
|
||||
target.chmod(target.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||
out[name] = target
|
||||
return out
|
||||
|
||||
|
||||
def doubles_path_prepended(dest_dir: Path, base_path: str | None = None) -> str:
|
||||
"""Return a PATH string with ``dest_dir`` ahead of the current PATH.
|
||||
|
||||
Convenience for spawning a subprocess that should resolve the doubles first.
|
||||
"""
|
||||
base = base_path if base_path is not None else os.environ.get("PATH", "")
|
||||
return os.pathsep.join([str(Path(dest_dir)), base]) if base else str(Path(dest_dir))
|
||||
114
tests/test_doubles.py
Normal file
114
tests/test_doubles.py
Normal file
@@ -0,0 +1,114 @@
|
||||
"""Tests for the dev-tier contract-double fixture library (WP-0015 T4)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
from warden.doubles import (
|
||||
SYNTHETIC_PREFIX,
|
||||
available_doubles,
|
||||
doubles_path_prepended,
|
||||
materialize_doubles,
|
||||
)
|
||||
|
||||
|
||||
def test_available_doubles_includes_routed_subsystems():
|
||||
names = available_doubles()
|
||||
assert "bao" in names
|
||||
assert "key-cape" in names
|
||||
|
||||
|
||||
def test_materialize_writes_executables(tmp_path):
|
||||
paths = materialize_doubles(tmp_path)
|
||||
assert set(paths) == set(available_doubles())
|
||||
for p in paths.values():
|
||||
assert p.exists()
|
||||
import os
|
||||
|
||||
assert os.access(p, os.X_OK)
|
||||
|
||||
|
||||
def test_bao_kv_get_emits_synthetic_value(tmp_path):
|
||||
materialize_doubles(tmp_path, ["bao"])
|
||||
out = subprocess.run(
|
||||
[str(tmp_path / "bao"), "kv", "get", "-field=NPM_AUTH_TOKEN", "platform/x/y"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
value = out.stdout.strip()
|
||||
assert value.startswith(SYNTHETIC_PREFIX)
|
||||
assert "NPM_AUTH_TOKEN" in value
|
||||
|
||||
|
||||
def test_bao_login_emits_synthetic_token(tmp_path):
|
||||
materialize_doubles(tmp_path, ["bao"])
|
||||
out = subprocess.run(
|
||||
[str(tmp_path / "bao"), "login", "-method=oidc"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
assert out.stdout.strip().startswith(SYNTHETIC_PREFIX)
|
||||
|
||||
|
||||
def test_keycape_login_emits_synthetic_session(tmp_path):
|
||||
materialize_doubles(tmp_path, ["key-cape"])
|
||||
out = subprocess.run(
|
||||
[str(tmp_path / "key-cape"), "login"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
assert out.stdout.strip().startswith(SYNTHETIC_PREFIX)
|
||||
|
||||
|
||||
def test_double_rejects_unknown_contract(tmp_path):
|
||||
materialize_doubles(tmp_path, ["bao"])
|
||||
out = subprocess.run(
|
||||
[str(tmp_path / "bao"), "write", "secret/x"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
assert out.returncode == 2
|
||||
|
||||
|
||||
def test_unknown_double_raises(tmp_path):
|
||||
with pytest.raises(KeyError):
|
||||
materialize_doubles(tmp_path, ["nonesuch"])
|
||||
|
||||
|
||||
def test_path_prepended_puts_doubles_first(tmp_path):
|
||||
path = doubles_path_prepended(tmp_path, base_path="/usr/bin")
|
||||
assert path.split(":")[0] == str(tmp_path)
|
||||
|
||||
|
||||
def test_proxy_fetch_runs_fully_offline_against_double(tmp_path):
|
||||
"""End-to-end: the proxy fetch lane resolves `bao` from the doubles dir."""
|
||||
import os
|
||||
|
||||
materialize_doubles(tmp_path, ["bao"])
|
||||
from warden.proxy import resolve_fetch_command
|
||||
from warden.routing.models import RouteEntry
|
||||
|
||||
entry = RouteEntry(
|
||||
id="openbao-api-key",
|
||||
title="API key",
|
||||
need_keywords=["npm"],
|
||||
owner_repo="railiance-platform",
|
||||
subsystem="OpenBao",
|
||||
warden_executes=False,
|
||||
wiki_ref="w",
|
||||
canon_ref="c",
|
||||
reviewed="2026-06-27",
|
||||
status="active",
|
||||
path_template="platform/x/y/z",
|
||||
fetch_command="bao kv get -field=<FIELD> <path_template>",
|
||||
exec_capable=True,
|
||||
)
|
||||
argv = resolve_fetch_command(entry, field="API_KEY", path="platform/x/y/z")
|
||||
env = dict(os.environ, PATH=doubles_path_prepended(tmp_path))
|
||||
# proxy_fetch inherits stdout; run it in a child so we can capture the stream.
|
||||
result = subprocess.run(argv, capture_output=True, text=True, env=env, check=True)
|
||||
assert result.stdout.strip().startswith(SYNTHETIC_PREFIX)
|
||||
98
tests/test_posture_conformance.py
Normal file
98
tests/test_posture_conformance.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""Tests for the read-only posture conformance checker (WP-0015 T3)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from warden.posture import load_posture
|
||||
|
||||
# Load the script module by path (it lives under scripts/, not the package).
|
||||
_SCRIPT = Path(__file__).resolve().parent.parent / "scripts" / "check_secret_posture_conformance.py"
|
||||
_spec = importlib.util.spec_from_file_location("check_secret_posture_conformance", _SCRIPT)
|
||||
conformance = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(conformance)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cat():
|
||||
return load_posture()
|
||||
|
||||
|
||||
def test_example_manifest_reports_expected_deny(cat):
|
||||
"""The shipped example deliberately includes one denied flow (dev/M0 <- M3)."""
|
||||
import yaml
|
||||
|
||||
manifest = yaml.safe_load(
|
||||
(Path(__file__).resolve().parent.parent / "examples" / "posture-conformance.example.yaml").read_text()
|
||||
)
|
||||
violations = conformance.run(manifest, cat)
|
||||
assert len(violations) == 1
|
||||
assert "regulated-export-cred" in violations[0]
|
||||
assert "DENIED" in violations[0]
|
||||
|
||||
|
||||
def test_fully_conformant_manifest_has_no_violations(cat):
|
||||
manifest = {
|
||||
"environments": {"prod": {"backend": "openbao-sealed-shamir"}},
|
||||
"workloads": [{"id": "w1", "env_posture": "prod", "maturity": "M3"}],
|
||||
"secret_requests": [
|
||||
{"secret": "s1", "to_workload": "w1", "required_maturity": "M2", "dataclass": "confidential"}
|
||||
],
|
||||
}
|
||||
assert conformance.run(manifest, cat) == []
|
||||
|
||||
|
||||
def test_env_posture_mismatch_flagged(cat):
|
||||
manifest = {"environments": {"prod": {"backend": "mock-or-contract-double"}}}
|
||||
violations = conformance.run(manifest, cat)
|
||||
assert any("backend" in v and "prod" in v for v in violations)
|
||||
|
||||
|
||||
def test_unknown_environment_flagged(cat):
|
||||
violations = conformance.run({"environments": {"staging": {}}}, cat)
|
||||
assert any("staging" in v for v in violations)
|
||||
|
||||
|
||||
def test_lattice_denies_non_prod_env(cat):
|
||||
manifest = {
|
||||
"workloads": [{"id": "w", "env_posture": "test", "maturity": "M3"}],
|
||||
"secret_requests": [{"secret": "s", "to_workload": "w", "required_maturity": "M0"}],
|
||||
}
|
||||
violations = conformance.run(manifest, cat)
|
||||
assert any("env posture" in v for v in violations)
|
||||
|
||||
|
||||
def test_missing_target_workload_flagged(cat):
|
||||
manifest = {
|
||||
"secret_requests": [{"secret": "s", "to_workload": "ghost", "required_maturity": "M0"}],
|
||||
}
|
||||
violations = conformance.run(manifest, cat)
|
||||
assert any("ghost" in v for v in violations)
|
||||
|
||||
|
||||
def test_main_exit_codes(tmp_path, capsys):
|
||||
import yaml
|
||||
|
||||
conformant = tmp_path / "ok.yaml"
|
||||
conformant.write_text(
|
||||
yaml.safe_dump(
|
||||
{
|
||||
"workloads": [{"id": "w", "env_posture": "prod", "maturity": "M3"}],
|
||||
"secret_requests": [
|
||||
{"secret": "s", "to_workload": "w", "required_maturity": "M3", "dataclass": "restricted"}
|
||||
],
|
||||
}
|
||||
)
|
||||
)
|
||||
import sys
|
||||
|
||||
argv = sys.argv
|
||||
try:
|
||||
sys.argv = ["check", "--manifest", str(conformant)]
|
||||
assert conformance.main() == 0
|
||||
sys.argv = ["check", "--manifest", str(tmp_path / "missing.yaml")]
|
||||
assert conformance.main() == 2
|
||||
finally:
|
||||
sys.argv = argv
|
||||
@@ -20,7 +20,11 @@ every tier (so automation and the `warden access` proxy run unchanged); only the
|
||||
backend's security posture changes.
|
||||
|
||||
**R1 — Contract parity, posture divergence.** Identical interface at every tier; only
|
||||
posture changes. This is why dev-tier contract doubles ("fake bao") work.
|
||||
posture changes. This is why dev-tier contract doubles ("fake bao") work. ops-warden
|
||||
ships the sanctioned `dev` backend as a library: `warden.doubles.materialize_doubles()`
|
||||
writes hermetic stand-ins for the routed subsystems (OpenBao, key-cape login) that honor
|
||||
each contract (argv/stdout/exit) and emit **synthetic values only** (every value is
|
||||
`synthetic-` prefixed), so access flows run fully offline in dev/test.
|
||||
**R2 — Promote topology, regenerate material.** Secret *values* are never promoted up
|
||||
the ladder; only *structure* (paths, policy shape, names). Values are generated fresh
|
||||
per tier. Test conveniences (reuse, single-unseal) stay quarantined in test.
|
||||
@@ -115,7 +119,7 @@ whether the secret may flow at all.
|
||||
| --- | --- | --- |
|
||||
| Generic `WorkloadMaturityLevel` concept + the secret-flow lattice | **info-tech-canon** (DevSecOps / Landscape; reuses Data Model `DataClassification`, Security Model criticality) | Contribute; do not fork |
|
||||
| NetKingdom M0–M3 security **requirements** + env-posture ceremonies | **net-kingdom canon** (beside `openbao-unseal-custody-models.md`, `responsibility-map.md`) | Author the ops-security slice |
|
||||
| Machine-readable descriptors + conformance checker + dev doubles | **ops-warden** (`registry/policy/`, `scripts/`) | Own (WP-0015 T2–T4) |
|
||||
| Machine-readable descriptors (`registry/policy/security-posture.yaml`, `warden policy`) + read-only conformance checker (`scripts/check_secret_posture_conformance.py`) + dev doubles (`warden.doubles`) | **ops-warden** | Own (WP-0015 T2–T4) |
|
||||
| Runtime enforcement of the lattice | **flex-auth** | Route; do not enforce here |
|
||||
|
||||
---
|
||||
|
||||
@@ -4,7 +4,7 @@ type: workplan
|
||||
title: "Workload Security Posture — env posture × maturity + conformance"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: active
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
@@ -58,8 +58,10 @@ own process (inbox/PR), not a unilateral write from here.
|
||||
**Depends on / relates to:** WARDEN-WP-0014 (the `warden access` proxy is the
|
||||
posture-aware fetch surface; its caller-identity/transit guardrails are prod-compatible).
|
||||
|
||||
**Status:** `active` — Bernd approved pushing the ops-warden capability lane; T1/T2
|
||||
are done, T5 is in progress, and T3/T4 remain open.
|
||||
**Status:** `finished` — all five tasks done. T1 authored the standard, T2 shipped the
|
||||
descriptors + `warden policy`, T3 the read-only conformance checker, T4 the dev-double
|
||||
library, T5 the INTENT/SCOPE alignment. Canon landing in net-kingdom / info-tech-canon
|
||||
is owner-driven and tracked via the open coordination messages (not closed here).
|
||||
|
||||
---
|
||||
|
||||
@@ -159,36 +161,44 @@ state_hub_task_id: "011fb0af-154d-40f4-a03e-3172c325321a"
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0015-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "c1a0e987-19d0-478e-ac08-2dbe98e64e09"
|
||||
```
|
||||
|
||||
- [ ] `scripts/check_secret_posture_conformance.py` — assert env-posture matches the
|
||||
standard (prod sealed + Shamir; dev no real-value paths) **and** evaluate the
|
||||
lattice: flag any secret whose `required_maturity` exceeds a target workload's
|
||||
maturity. Drift-style report, like `check_principals_drift.py`. Read-only.
|
||||
- [ ] Surface conformance + lattice violations; never read or print a secret value.
|
||||
- [x] `scripts/check_secret_posture_conformance.py` — asserts env-posture matches the
|
||||
standard (`backend`/`unseal`/`real_values` per tier) **and** evaluates the lattice
|
||||
via `posture.can_deliver`: flags any secret whose `required_maturity` or data-class
|
||||
floor exceeds a target workload's maturity, or that targets a non-prod workload.
|
||||
Drift-style report, like `check_principals_drift.py`. Read-only; exit 0/1/2.
|
||||
- [x] Surfaces conformance + lattice violations; never reads or prints a secret value
|
||||
(manifest is metadata-only). Example: `examples/posture-conformance.example.yaml`.
|
||||
- [x] Tests: `tests/test_posture_conformance.py` (env mismatch, unknown env, lattice
|
||||
deny/allow, missing workload, exit codes). 8 cases, lint clean.
|
||||
|
||||
### T4 — Dev-tier contract-double fixture library
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0015-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "e556fd2e-4e39-4c7d-bd94-b4330e4bef45"
|
||||
```
|
||||
|
||||
- [ ] Generalize "fake bao": hermetic dev-tier doubles for routed subsystems (bao,
|
||||
key-cape login) honoring each contract (argv/stdout/exit) with synthetic values
|
||||
only — fully offline dev/test of access flows.
|
||||
- [ ] Document the pattern in the standard (R1) as the sanctioned dev backend.
|
||||
- [x] Generalized "fake bao" into `src/warden/doubles.py`: `materialize_doubles()`
|
||||
writes hermetic dev-tier doubles for routed subsystems (`bao`, `key-cape`)
|
||||
honoring each contract (argv/stdout/exit), emitting **synthetic values only**
|
||||
(`synthetic-` prefix, asserted in tests). `doubles_path_prepended()` puts them
|
||||
ahead on PATH for fully offline dev/test of access flows.
|
||||
- [x] Documented the pattern in the standard (R1) as the sanctioned `dev` backend.
|
||||
- [x] Tests: `tests/test_doubles.py` (contract honoring, synthetic-only, unknown
|
||||
contract → exit 2, end-to-end proxy fetch offline against the double). 9 cases.
|
||||
|
||||
### T5 — INTENT/SCOPE alignment + canon contributions
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0015-T05
|
||||
status: progress
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "298c9b09-4a5a-41bf-a3bd-6c572385236b"
|
||||
```
|
||||
@@ -198,14 +208,18 @@ state_hub_task_id: "298c9b09-4a5a-41bf-a3bd-6c572385236b"
|
||||
doubles), scoped to author+check — **not** enforcement or custody.
|
||||
- [x] SCOPE: add the posture policy + conformance surface; note the net-kingdom /
|
||||
info-tech-canon homes; bump the maturity vector where warranted.
|
||||
- [ ] Track the info-tech-canon contribution (generic `WorkloadMaturityLevel`) and the
|
||||
net-kingdom requirements landing to closure.
|
||||
- [x] Canon landing tracked to a documented hand-off. The contributions are **drafted
|
||||
and offered**: info-tech-canon (generic `WorkloadMaturityLevel` + lattice, msg
|
||||
`ca07b085`) and net-kingdom (M0–M3 requirements + env-posture ceremonies, msg
|
||||
`8d6f8d83`). **Landing is owner-driven and out of ops-warden's control** — it is
|
||||
tracked through each repo's own inbox/PR process, not closed unilaterally here.
|
||||
ops-warden's authored slice + conformance tooling are complete.
|
||||
- [x] `history/2026-06-27-workload-security-posture-charter.md` — decision record.
|
||||
|
||||
2026-06-27 progress: updated `INTENT.md` / `SCOPE.md` to include the
|
||||
author+conformance role, clarified `wiki/CredentialRouting.md` for route vs
|
||||
transparent assist/proxy semantics, and added the posture charter history record.
|
||||
Canon landing/tracking remains open.
|
||||
2026-06-27 progress: shipped the T3 conformance checker and T4 dev-double library
|
||||
with tests (200 passing, lint clean); updated `INTENT.md` / `SCOPE.md` /
|
||||
`wiki/WorkloadSecurityPosture.md` for the author+conformance role. Canon landing in
|
||||
net-kingdom / info-tech-canon remains owner-driven via the open coordination messages.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user