ledger.py python
166 lines 5.3 KB
Raw
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 1 day ago
1 """``overseer ledger`` commands (§K9.9)."""
2
3 from __future__ import annotations
4
5 import sys
6 from argparse import Namespace
7
8 from adapters.config import load_config
9 from adapters.errors import ConfigError
10 from cli.context import CliContext
11 from cli.paths import resolve_config_path, resolve_repo_root
12 from cli.sanitize import config_exit_code, format_config_error
13 from tools.honesty.ledger import append_entry, parse_append_body, show_entries, verify_ledger_file
14 from tools.honesty.types import ENTRY_KINDS, LedgerAppendOptions
15
16
17 def run_ledger_command(args: Namespace, ctx: CliContext) -> int:
18 """Dispatch ``overseer ledger {append,verify,show}``."""
19 action = args.ledger_action
20 if action == "append":
21 return _run_append(args, ctx)
22 if action == "verify":
23 return _run_verify(args, ctx)
24 if action == "show":
25 return _run_show(args, ctx)
26 ctx.output.error("usage: ledger requires append|verify|show")
27 return 1
28
29
30 def _load_config_or_exit(args: Namespace, ctx: CliContext):
31 repo_root = resolve_repo_root(cwd=ctx.cwd, repo_arg=args.repo, command="ledger")
32 overseer_dir = repo_root / ".overseer"
33 if not overseer_dir.is_dir():
34 ctx.output.error("not initialized — run ok init first")
35 return None, None, 2
36
37 config_path = resolve_config_path(repo_root, args.config)
38 try:
39 config = load_config(config_path)
40 except ConfigError as exc:
41 ctx.output.error(format_config_error(exc, repo_root))
42 return None, None, config_exit_code(exc)
43
44 for warning in config.extension_warnings:
45 ctx.output.warn(warning)
46 return config, repo_root, None
47
48
49 def _run_append(args: Namespace, ctx: CliContext) -> int:
50 if not args.kind:
51 ctx.output.error("usage: --kind is required")
52 return 1
53 if args.file and args.stdin:
54 ctx.output.error("usage: at most one of --file or --stdin")
55 return 1
56
57 config, repo_root, early = _load_config_or_exit(args, ctx)
58 if early is not None:
59 return early
60
61 stdin_text = None
62 if args.stdin:
63 stdin_text = sys.stdin.read()
64
65 body, body_exit, _ = parse_append_body(
66 repo_root=repo_root,
67 file_path=args.file,
68 stdin_text=stdin_text,
69 )
70 if body_exit != 0:
71 if body_exit == 2:
72 ctx.output.error("invalid append body")
73 else:
74 ctx.output.error("refused")
75 return body_exit
76
77 if args.kind not in ENTRY_KINDS:
78 ctx.output.error("unknown entry kind")
79 return 2
80
81 result = append_entry(
82 config=config,
83 repo_root=repo_root,
84 options=LedgerAppendOptions(kind=args.kind, body=body or {}),
85 )
86
87 if result.stderr_extra:
88 for line in result.stderr_extra.splitlines():
89 if line.startswith("honesty.roles_file"):
90 ctx.output.warn(line)
91 else:
92 print(line, file=sys.stderr)
93
94 if result.exit_code == 4:
95 ctx.output.error("refused")
96 elif result.exit_code == 23:
97 ctx.output.error("role violation")
98 elif result.exit_code == 24:
99 ctx.output.error("evidence-free verdict")
100 elif result.exit_code == 21:
101 ctx.output.error("approval integrity failure")
102 elif result.exit_code == 5:
103 ctx.output.error("ledger write failed")
104 elif result.exit_code == 2:
105 ctx.output.error("invalid ledger entry")
106 elif result.exit_code == 25:
107 ctx.output.error("provenance signature verification failed")
108 elif result.exit_code == 26:
109 ctx.output.error("signature required but absent")
110
111 return result.exit_code
112
113
114 def _run_verify(args: Namespace, ctx: CliContext) -> int:
115 config, repo_root, early = _load_config_or_exit(args, ctx)
116 if early is not None:
117 return early
118
119 result = verify_ledger_file(config=config, repo_root=repo_root)
120 if result.stderr_extra:
121 for line in result.stderr_extra.splitlines():
122 if line.startswith("honesty.roles_file"):
123 ctx.output.warn(line)
124 else:
125 print(line, file=sys.stderr)
126
127 if result.exit_code == 22:
128 ctx.output.error("ledger chain broken")
129 elif result.exit_code == 25:
130 ctx.output.error("provenance signature verification failed")
131 elif result.exit_code == 26:
132 ctx.output.error("signature required but absent")
133 elif result.exit_code == 2:
134 ctx.output.error("malformed provenance envelope")
135 elif result.exit_code == 4:
136 ctx.output.error("refused")
137 return result.exit_code
138
139
140 def _run_show(args: Namespace, ctx: CliContext) -> int:
141 last_n = args.last if args.last is not None else 20
142 config, repo_root, early = _load_config_or_exit(args, ctx)
143 if early is not None:
144 return early
145
146 result = show_entries(config=config, repo_root=repo_root, last_n=last_n)
147 if result.stderr_extra:
148 for line in result.stderr_extra.splitlines():
149 if line.startswith("honesty.roles_file"):
150 ctx.output.warn(line)
151 else:
152 print(line, file=sys.stderr)
153
154 if result.exit_code == 1:
155 ctx.output.error("usage")
156 return 1
157 if result.exit_code == 4:
158 ctx.output.error("refused")
159 return 4
160 if result.exit_code == 22:
161 ctx.output.error("ledger chain broken")
162 return 22
163
164 for line in result.stdout_lines:
165 print(line)
166 return 0
File History 2 commits
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 1 day ago
sha256:4671b7f787ddbe63ced31c895b688c77ab495653b65a730b423329f26b3c1439 feat: K1-P1 complete — agent provenance, build-verification… Sonnet 4.6 patch 53 days ago