WARDEN-WP-0026 finish Strand A (T04/T05/T07)
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.
This commit is contained in:
parent
7d0c7c7684
commit
b971403dad
16 changed files with 689 additions and 31 deletions
|
|
@ -383,3 +383,39 @@ def test_access_fingerprint_masks_and_bypasses_stdout_guard(monkeypatch, tmp_pat
|
|||
assert r.exit_code == 0
|
||||
assert "top-secret-token-value" not in r.output # value never shown
|
||||
assert "hidden" in r.output and "sha256:" in r.output
|
||||
|
||||
|
||||
def test_access_agent_high_risk_raw_stream_refused(tmp_path, monkeypatch):
|
||||
"""WP-0026 T04: WARDEN_AGENT_ID + risk=high refuses raw value stream (exit 7)."""
|
||||
_proxy_env(monkeypatch, tmp_path)
|
||||
monkeypatch.setenv("VAULT_TOKEN", "caller-token")
|
||||
monkeypatch.setenv("WARDEN_AGENT_ID", "grok")
|
||||
# Prefer high-risk lane; use --unsafe-stdout so T02 would allow if T04 failed.
|
||||
r = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"access", "railiance-backup-offsite-lane",
|
||||
"--fetch", "--no-policy", "--unsafe-stdout",
|
||||
],
|
||||
)
|
||||
assert r.exit_code == 7, r.output
|
||||
assert "agent read-boundary" in r.output.lower() or "risk=high" in r.output.lower()
|
||||
|
||||
|
||||
def test_access_agent_high_risk_fingerprint_allowed(tmp_path, monkeypatch):
|
||||
"""Agents may use --fingerprint on high-risk lanes (no raw value)."""
|
||||
_proxy_env(monkeypatch, tmp_path)
|
||||
monkeypatch.setenv("VAULT_TOKEN", "caller-token")
|
||||
monkeypatch.setenv("WARDEN_AGENT_ID", "grok")
|
||||
|
||||
class _Fake:
|
||||
returncode = 0
|
||||
stdout = "should-not-appear"
|
||||
|
||||
monkeypatch.setattr("warden.proxy.subprocess.run", lambda *a, **k: _Fake())
|
||||
r = runner.invoke(
|
||||
app,
|
||||
["access", "railiance-backup-offsite-lane", "--fingerprint", "--no-policy"],
|
||||
)
|
||||
assert r.exit_code == 0, r.output
|
||||
assert "should-not-appear" not in r.output
|
||||
|
|
|
|||
|
|
@ -531,3 +531,47 @@ def test_rotate_guide_cli_ssh_lane_is_graceful():
|
|||
# SSH renewal is re-issuance, not a static rotation — exit 0, not an error.
|
||||
result = runner.invoke(app, ["rotate-guide", "ssh-cert-host-access"])
|
||||
assert result.exit_code == 0
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Agent read-boundary + risk class (WARDEN-WP-0026 T04)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_high_risk_lanes_classified():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
high = {e.id for e in catalog.entries if e.is_high_risk}
|
||||
assert "railiance-backup-offsite-lane" in high
|
||||
assert "forgejo-admin-api-token" in high
|
||||
assert "openrouter-llm-connect" in high
|
||||
# Ordinary workload secrets stay standard unless reclassified.
|
||||
assert catalog.get("issue-core-ingestion-api-key").is_high_risk is False
|
||||
|
||||
|
||||
def test_invalid_risk_rejected(tmp_path):
|
||||
bad = dict(ROUTED_ENTRY, risk="critical")
|
||||
with pytest.raises(CatalogError, match="risk"):
|
||||
load_catalog(_write_catalog(tmp_path, [SSH_ENTRY, bad]))
|
||||
|
||||
|
||||
def test_backup_lane_promoted_and_resolvable():
|
||||
"""WP-0026 T07 — CCR-2026-0004 lane is active, resolvable, high-risk, has rotation."""
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
e = catalog.get("railiance-backup-offsite-lane")
|
||||
assert e is not None
|
||||
assert e.status == "active"
|
||||
assert e.resolvable is True
|
||||
assert e.is_high_risk is True
|
||||
assert e.has_rotation is True
|
||||
assert e.rotation.method == "re-establish"
|
||||
assert "NC_WEBDAV_TOKEN" in (e.fetch_command or "")
|
||||
assert "<" not in (e.fetch_command or "")
|
||||
|
||||
|
||||
def test_route_show_json_includes_risk():
|
||||
result = runner.invoke(app, ["route", "show", "railiance-backup-offsite-lane", "--json"])
|
||||
assert result.exit_code == 0
|
||||
payload = json.loads(result.stdout)
|
||||
assert payload["risk"] == "high"
|
||||
assert payload["high_risk"] is True
|
||||
assert payload["resolvable"] is True
|
||||
assert payload["status"] == "active"
|
||||
|
|
|
|||
70
tests/test_taint.py
Normal file
70
tests/test_taint.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
"""Tests for EXPOSED taint convention (WARDEN-WP-0026 T05)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from warden.cli import app
|
||||
from warden.taint import (
|
||||
EXPOSED_AT,
|
||||
TaintStatus,
|
||||
parse_custom_metadata,
|
||||
kv_metadata_path,
|
||||
)
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
|
||||
def test_parse_custom_metadata_tainted():
|
||||
status = parse_custom_metadata({
|
||||
"custom_metadata": {
|
||||
EXPOSED_AT: "2026-07-16T00:00:00Z",
|
||||
"exposed_version": "2",
|
||||
"exposed_reason": "test",
|
||||
"exposed_ref": "history/x.md",
|
||||
},
|
||||
"current_version": 2,
|
||||
})
|
||||
assert status.tainted is True
|
||||
assert status.exposed_at == "2026-07-16T00:00:00Z"
|
||||
assert status.exposed_version == "2"
|
||||
assert status.current_version == 2
|
||||
|
||||
|
||||
def test_parse_custom_metadata_clean():
|
||||
status = parse_custom_metadata({"custom_metadata": None, "current_version": 1})
|
||||
assert status.tainted is False
|
||||
assert status.exposed_at is None
|
||||
|
||||
|
||||
def test_parse_empty_exposed_at_not_tainted():
|
||||
status = parse_custom_metadata({"custom_metadata": {EXPOSED_AT: " "}, "current_version": 1})
|
||||
assert status.tainted is False
|
||||
|
||||
|
||||
def test_kv_metadata_path_strips():
|
||||
assert kv_metadata_path(" platform/workloads/x ") == "platform/workloads/x"
|
||||
|
||||
|
||||
def test_taint_status_to_dict():
|
||||
s = TaintStatus(
|
||||
lane_id="x", path="p", tainted=True,
|
||||
exposed_at="t", exposed_version="1", current_version=1,
|
||||
)
|
||||
d = s.to_dict()
|
||||
assert d["tainted"] is True
|
||||
assert d["id"] == "x"
|
||||
|
||||
|
||||
def test_taint_cli_unknown_id():
|
||||
result = runner.invoke(app, ["taint", "no-such-lane-xyz"])
|
||||
assert result.exit_code == 1
|
||||
|
||||
|
||||
def test_taint_cli_template_lane_errors():
|
||||
"""openbao-api-key has <placeholders> — cannot query taint."""
|
||||
result = runner.invoke(app, ["taint", "openbao-api-key", "--json"])
|
||||
assert result.exit_code == 2
|
||||
Loading…
Add table
Add a link
Reference in a new issue