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.
This commit is contained in:
tegwick 2026-07-01 23:32:38 +02:00
parent f47d632d8e
commit d6088e4e16
18 changed files with 875 additions and 59 deletions

View file

@ -39,6 +39,11 @@ worker_app = typer.Typer(
no_args_is_help=True,
)
app.add_typer(worker_app, name="worker")
activity_app = typer.Typer(
help="Unified metadata-only audit view (WARDEN-WP-0022)",
no_args_is_help=True,
)
app.add_typer(activity_app, name="activity")
console = Console()
err = Console(stderr=True)
@ -1237,6 +1242,55 @@ def worker_approve(
raise typer.Exit(1)
@activity_app.callback(invoke_without_command=True)
def activity_show(
days: Annotated[int, typer.Option("--days", help="Look back N days")] = 7,
kind: Annotated[
Optional[str],
typer.Option("--kind", help="Filter: sign, access, worker, hub"),
] = None,
output_json: Annotated[bool, typer.Option("--json", help="Output JSON")] = False,
include_hub: Annotated[
bool, typer.Option("--hub", help="Include State Hub progress notes")
] = False,
) -> None:
"""Show what ops-warden did recently (metadata only — no secret values)."""
from warden.audit import collect_activity, fetch_hub_notes
cfg = _load_cfg()
kinds = {kind} if kind else None
events = collect_activity(cfg.state_dir, days=days, kinds=kinds)
if include_hub and (kinds is None or "hub" in kinds):
events.extend(fetch_hub_notes(days=days))
events.sort(key=lambda e: str(e.get("ts", "")))
if output_json:
print(json.dumps(events, indent=2))
return
if not events:
console.print(f"No activity in the last {days} day(s).")
return
table = Table(title=f"ops-warden activity (last {days} days)")
table.add_column("When", style="dim")
table.add_column("Kind")
table.add_column("Action")
table.add_column("Subject")
table.add_column("Target")
table.add_column("Outcome")
for event in events:
table.add_row(
str(event.get("ts", ""))[:19],
str(event.get("kind", "")),
str(event.get("action", "")),
str(event.get("subject", ""))[:24],
str(event.get("target", ""))[:28],
str(event.get("outcome", "")),
)
console.print(table)
@worker_app.command("status")
def worker_status_cmd() -> None:
"""Show worker state: pending drafts, triage count, last digest, timer status."""