openworkproof 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. openworkproof/__init__.py +1 -0
  2. openworkproof/acceptance.py +3006 -0
  3. openworkproof/cli.py +164 -0
  4. openworkproof/composition.py +832 -0
  5. openworkproof/evidence.py +8281 -0
  6. openworkproof/execution_adapter.py +256 -0
  7. openworkproof/external_acceptor.py +211 -0
  8. openworkproof/mcp_server.py +2939 -0
  9. openworkproof/mcp_transport.py +72 -0
  10. openworkproof/models.py +3380 -0
  11. openworkproof/policy.py +2494 -0
  12. openworkproof/predicates.py +333 -0
  13. openworkproof/repo_pipeline/__init__.py +74 -0
  14. openworkproof/repo_pipeline/analysis.py +152 -0
  15. openworkproof/repo_pipeline/errors.py +64 -0
  16. openworkproof/repo_pipeline/models.py +80 -0
  17. openworkproof/repo_pipeline/output.py +68 -0
  18. openworkproof/repo_pipeline/reader.py +47 -0
  19. openworkproof/repo_pipeline/sources.py +120 -0
  20. openworkproof/repo_pipeline/traversal.py +253 -0
  21. openworkproof/repo_tools.py +8382 -0
  22. openworkproof/runtime_context.py +189 -0
  23. openworkproof/schema_registry.py +623 -0
  24. openworkproof/schemas/v0.1/acceptance-receipt.schema.json +1 -0
  25. openworkproof/schemas/v0.1/acceptance-rejection-receipt.schema.json +1 -0
  26. openworkproof/schemas/v0.1/action-receipt.schema.json +1 -0
  27. openworkproof/schemas/v0.1/capability-grant.schema.json +1 -0
  28. openworkproof/schemas/v0.1/schema-registry.json +1 -0
  29. openworkproof/schemas/v0.1/work-order.schema.json +1 -0
  30. openworkproof/signing.py +421 -0
  31. openworkproof/state.py +765 -0
  32. openworkproof/team_network_client.py +419 -0
  33. openworkproof/trusted_helper.py +269 -0
  34. openworkproof-1.0.0.dist-info/METADATA +578 -0
  35. openworkproof-1.0.0.dist-info/RECORD +39 -0
  36. openworkproof-1.0.0.dist-info/WHEEL +5 -0
  37. openworkproof-1.0.0.dist-info/entry_points.txt +2 -0
  38. openworkproof-1.0.0.dist-info/licenses/LICENSE +202 -0
  39. openworkproof-1.0.0.dist-info/top_level.txt +1 -0
openworkproof/cli.py ADDED
@@ -0,0 +1,164 @@
1
+ """Command-line transport for OpenWorkProof.
2
+
3
+ The CLI is a thin transport: it parses JSON protocol messages and forwards
4
+ them to the coordinator handlers. It does not author policy, sign requests,
5
+ or fabricate authority — those live in the protocol layer.
6
+
7
+ Commands:
8
+
9
+ - ``owp status <ledger>`` — replay the ledger and print its state
10
+ - ``owp run-tests <ledger> <payload.json>`` — forward a run-tests execution
11
+ - ``owp repo-read <ledger> <payload.json>`` — forward a repo-read execution
12
+
13
+ Payload files carry the signed AgentRequest plus the typed arguments, the
14
+ execution facts, and the replay checkpoint; see the transport tests for the
15
+ exact JSON shape.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import argparse
21
+ import json
22
+ from pathlib import Path
23
+ import sys
24
+ from typing import Sequence
25
+
26
+ from openworkproof import evidence
27
+
28
+
29
+ class CliError(Exception):
30
+ """A transport-level CLI failure with a stable message."""
31
+
32
+
33
+ def cli_status(ledger_path: str | Path) -> dict[str, object]:
34
+ """Replay one ledger and return its authoritative state as JSON data."""
35
+ path = Path(ledger_path)
36
+ if not path.is_file():
37
+ raise CliError(f"ledger does not exist: {path}")
38
+ connection = evidence.connect_ledger(path)
39
+ try:
40
+ work_order, receipts, _, _ = (
41
+ evidence._replay_receipt_publication_ledger(connection)
42
+ )
43
+ state_row = connection.execute(
44
+ "SELECT current_state, version FROM work_order_state "
45
+ "WHERE singleton = 1"
46
+ ).fetchone()
47
+ finally:
48
+ connection.close()
49
+ if state_row is None:
50
+ raise CliError("ledger has no authoritative state row")
51
+ return {
52
+ "schema_version": "openworkproof/cli-status/0.1",
53
+ "work_order_digest": work_order.digest,
54
+ "current_state": state_row[0],
55
+ "version": state_row[1],
56
+ "receipt_count": len(receipts),
57
+ }
58
+
59
+
60
+ def _load_payload(path: str | Path) -> dict[str, object]:
61
+ payload_path = Path(path)
62
+ if not payload_path.is_file():
63
+ raise CliError(f"payload does not exist: {payload_path}")
64
+ try:
65
+ raw = json.loads(payload_path.read_text(encoding="utf-8"))
66
+ except (OSError, ValueError) as error:
67
+ raise CliError(f"payload is not valid JSON: {path}") from error
68
+ if type(raw) is not dict:
69
+ raise CliError("payload must be a JSON object")
70
+ return raw
71
+
72
+
73
+ def cli_run_tests(ledger_path: str | Path, payload: dict[str, object]) -> dict:
74
+ """Forward one run-tests execution from a payload dict."""
75
+ from openworkproof import mcp_server
76
+
77
+ try:
78
+ receipt = mcp_server._run_tests_from_payload(
79
+ ledger_path, payload
80
+ )
81
+ except KeyError as error:
82
+ raise CliError(f"payload is missing a required field: {error}") from error
83
+ return {
84
+ "schema_version": "openworkproof/cli-result/0.1",
85
+ "receipt_id": receipt.receipt_id,
86
+ "tool_name": receipt.tool_name,
87
+ "execution_status": receipt.execution_status,
88
+ "state_after": receipt.state_after,
89
+ "output_digest": receipt.output_digest,
90
+ }
91
+
92
+
93
+ def cli_repo_read(ledger_path: str | Path, payload: dict[str, object]) -> dict:
94
+ """Forward one repo-read execution from a payload dict."""
95
+ from openworkproof import mcp_server
96
+
97
+ try:
98
+ receipt = mcp_server._repo_read_from_payload(
99
+ ledger_path, payload
100
+ )
101
+ except KeyError as error:
102
+ raise CliError(f"payload is missing a required field: {error}") from error
103
+ return {
104
+ "schema_version": "openworkproof/cli-result/0.1",
105
+ "receipt_id": receipt.receipt_id,
106
+ "tool_name": receipt.tool_name,
107
+ "execution_status": receipt.execution_status,
108
+ "state_after": receipt.state_after,
109
+ "output_digest": receipt.output_digest,
110
+ }
111
+
112
+
113
+ def build_parser() -> argparse.ArgumentParser:
114
+ parser = argparse.ArgumentParser(prog="owp")
115
+ parser.add_argument(
116
+ "--output", choices=("json", "text"), default="json",
117
+ help="output format (default: json)",
118
+ )
119
+ sub = parser.add_subparsers(dest="command", required=True)
120
+
121
+ status = sub.add_parser("status", help="replay a ledger and print its state")
122
+ status.add_argument("ledger", help="path to the SQLite ledger file")
123
+
124
+ run_tests = sub.add_parser(
125
+ "run-tests", help="forward one run-tests execution payload"
126
+ )
127
+ run_tests.add_argument("ledger", help="path to the SQLite ledger file")
128
+ run_tests.add_argument("payload", help="path to the run-tests payload JSON")
129
+
130
+ repo_read = sub.add_parser(
131
+ "repo-read", help="forward one repo-read execution payload"
132
+ )
133
+ repo_read.add_argument("ledger", help="path to the SQLite ledger file")
134
+ repo_read.add_argument("payload", help="path to the repo-read payload JSON")
135
+ return parser
136
+
137
+
138
+ def app(argv: Sequence[str] | None = None) -> int:
139
+ """Console entry point (``owp``)."""
140
+ parser = build_parser()
141
+ args = parser.parse_args(argv)
142
+ try:
143
+ if args.command == "status":
144
+ result: dict[str, object] = cli_status(args.ledger)
145
+ elif args.command == "run-tests":
146
+ result = cli_run_tests(args.ledger, _load_payload(args.payload))
147
+ elif args.command == "repo-read":
148
+ result = cli_repo_read(args.ledger, _load_payload(args.payload))
149
+ else:
150
+ parser.error(f"unknown command: {args.command}")
151
+ return 2
152
+ except CliError as error:
153
+ print(json.dumps({"error": str(error)}, ensure_ascii=False), file=sys.stderr)
154
+ return 1
155
+ if args.output == "text" and args.command == "status":
156
+ print(f"state={result['current_state']} version={result['version']} "
157
+ f"receipts={result['receipt_count']}")
158
+ else:
159
+ print(json.dumps(result, ensure_ascii=False, sort_keys=True, indent=2))
160
+ return 0
161
+
162
+
163
+ if __name__ == "__main__":
164
+ raise SystemExit(app())