gargoyle-receipts 0.6.0.dev0__tar.gz → 0.6.1.dev0__tar.gz

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 (68) hide show
  1. {gargoyle_receipts-0.6.0.dev0/gargoyle_receipts.egg-info → gargoyle_receipts-0.6.1.dev0}/PKG-INFO +2 -2
  2. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/README.md +1 -1
  3. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/cli.py +2 -0
  4. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/evidence.py +7 -4
  5. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0/gargoyle_receipts.egg-info}/PKG-INFO +2 -2
  6. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/pyproject.toml +1 -1
  7. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_cli.py +1 -0
  8. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/LICENSE +0 -0
  9. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/NOTICE +0 -0
  10. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/__init__.py +0 -0
  11. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/approval.py +0 -0
  12. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/approver_cli.py +0 -0
  13. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/approver_trust.py +0 -0
  14. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/approvers.py +0 -0
  15. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/consumer.py +0 -0
  16. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/entra_login.py +0 -0
  17. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/envelope.py +0 -0
  18. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/execution.py +0 -0
  19. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/fs_server.py +0 -0
  20. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/identity.py +0 -0
  21. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/issuer.py +0 -0
  22. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/issuer_service.py +0 -0
  23. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/jws.py +0 -0
  24. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/key_record_source.py +0 -0
  25. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/mcp_server.py +0 -0
  26. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/notify.py +0 -0
  27. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/opa.py +0 -0
  28. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/pending_store.py +0 -0
  29. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/policy.py +0 -0
  30. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/published_record_source.py +0 -0
  31. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/replay_cache.py +0 -0
  32. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/rules.py +0 -0
  33. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/static/approve.html +0 -0
  34. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/static/approve.js +0 -0
  35. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle/verifier.py +0 -0
  36. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle_receipts.egg-info/SOURCES.txt +0 -0
  37. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle_receipts.egg-info/dependency_links.txt +0 -0
  38. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle_receipts.egg-info/entry_points.txt +0 -0
  39. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle_receipts.egg-info/requires.txt +0 -0
  40. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/gargoyle_receipts.egg-info/top_level.txt +0 -0
  41. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/setup.cfg +0 -0
  42. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_annotations.py +0 -0
  43. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_approver_cli.py +0 -0
  44. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_approvers.py +0 -0
  45. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_canonical.py +0 -0
  46. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_console_js.py +0 -0
  47. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_consumer.py +0 -0
  48. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_entra_identity.py +0 -0
  49. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_entra_login.py +0 -0
  50. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_evidence.py +0 -0
  51. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_execution.py +0 -0
  52. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_fs_server.py +0 -0
  53. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_historical.py +0 -0
  54. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_identity.py +0 -0
  55. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_issuer_service.py +0 -0
  56. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_jws.py +0 -0
  57. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_mcp_proxy.py +0 -0
  58. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_mcp_self_issue.py +0 -0
  59. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_mcp_server.py +0 -0
  60. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_notify.py +0 -0
  61. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_opa.py +0 -0
  62. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_policy.py +0 -0
  63. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_published_record.py +0 -0
  64. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_rules.py +0 -0
  65. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_stdio_encoding.py +0 -0
  66. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_threshold.py +0 -0
  67. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_typescript_conformance.py +0 -0
  68. {gargoyle_receipts-0.6.0.dev0 → gargoyle_receipts-0.6.1.dev0}/tests/test_wire_spec.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gargoyle-receipts
3
- Version: 0.6.0.dev0
3
+ Version: 0.6.1.dev0
4
4
  Summary: Signed, single-use, argument-bound receipts and human-approval holds for agent tool calls.
5
5
  Author: Justin LaPorte
6
6
  License-Expression: Apache-2.0
@@ -59,7 +59,7 @@ your MCP server and lets through only what both agreed to.
59
59
 
60
60
  [![PyPI](https://img.shields.io/pypi/v/gargoyle-receipts)](https://pypi.org/project/gargoyle-receipts/)
61
61
 
62
- Status: pre-release (`0.6.0.dev0`, on PyPI as `gargoyle-receipts`). The wire format is `gargoyle/3` and may
62
+ Status: pre-release (`0.6.1.dev0`, on PyPI as `gargoyle-receipts`). The wire format is `gargoyle/3` and may
63
63
  still change before the first release; it is specified in [SPEC.md](SPEC.md).
64
64
 
65
65
  ## What a receipt gives you
@@ -21,7 +21,7 @@ your MCP server and lets through only what both agreed to.
21
21
 
22
22
  [![PyPI](https://img.shields.io/pypi/v/gargoyle-receipts)](https://pypi.org/project/gargoyle-receipts/)
23
23
 
24
- Status: pre-release (`0.6.0.dev0`, on PyPI as `gargoyle-receipts`). The wire format is `gargoyle/3` and may
24
+ Status: pre-release (`0.6.1.dev0`, on PyPI as `gargoyle-receipts`). The wire format is `gargoyle/3` and may
25
25
  still change before the first release; it is specified in [SPEC.md](SPEC.md).
26
26
 
27
27
  ## What a receipt gives you
@@ -244,6 +244,8 @@ def cmd_audit(args) -> int:
244
244
  for r in v["entries"]:
245
245
  # A refused row shows why the executor refused, beside the check outcome.
246
246
  why = (" (%s)" % r["verdict"]) if r["kind"] == "refused" and r["verdict"] else ""
247
+ if r.get("released_by"):
248
+ why += " released by " + ", ".join(r["released_by"])
247
249
  print("%4s %-5s %-8s %-24s %-28s %s%s" % (r["seq"] if r["seq"] is not None else "?",
248
250
  "ok" if r["accepted"] else "FAIL", r["kind"] or "?",
249
251
  (r["tool"] or "?")[:24], (r["principal"] or "?")[:28], r["reason"], why))
@@ -158,8 +158,9 @@ def verify_log(
158
158
  and describe the call the entry names; a refused entry that carries a
159
159
  receipt has it checked for issuer provenance. Returns
160
160
  {"accepted", "reason", "tail_sha256", "count", "honored", "refused",
161
- "entries": [{"seq", "kind", "tool", "principal", "accepted", "reason", "verdict"}, ...]},
162
- `reason` the verification outcome and `verdict` what the executor recorded.
161
+ "entries": [{"seq", "kind", "tool", "principal", "accepted", "reason", "verdict", "released_by"}, ...]},
162
+ `reason` the verification outcome, `verdict` what the executor recorded,
163
+ `released_by` the approver key ids of the grants an honored held call carried.
163
164
  Verification continues past a bad entry so the report names every one."""
164
165
  trust = dict(issuer_public_keys=issuer_public_keys, executor_public_keys=executor_public_keys,
165
166
  approver_public_keys=approver_public_keys)
@@ -177,7 +178,7 @@ def verify_log(
177
178
  rc = rc if isinstance(rc, dict) else {}
178
179
  report.append({"seq": None, "kind": None, "tool": rc.get("tool"), "principal": rc.get("principal"),
179
180
  "accepted": False, "reason": REF_EVIDENCE_UNCHAINED if legacy else REF_EVIDENCE_MALFORMED,
180
- "verdict": None})
181
+ "verdict": None, "released_by": []})
181
182
  all_ok = False
182
183
  continue
183
184
  e = raw
@@ -203,8 +204,10 @@ def verify_log(
203
204
  now=_parse_at(e["at"]), historical=True)
204
205
  ok, reason = p["accepted"], (ACCEPT_ENTRY_VERIFIED if p["accepted"] else p["reason"])
205
206
  counts[e["kind"]] += 1
207
+ released_by = [g.get("approver_key_id") for g in (e["grant"] if isinstance(e["grant"], list) else [e["grant"]])
208
+ if isinstance(g, dict)] if e["grant"] is not None else []
206
209
  report.append({"seq": e["seq"], "kind": e["kind"], "tool": e["tool"], "principal": e["principal"],
207
- "accepted": ok, "reason": reason, "verdict": e["reason"]})
210
+ "accepted": ok, "reason": reason, "verdict": e["reason"], "released_by": released_by})
208
211
  all_ok = all_ok and ok
209
212
  # The chain continues from what the file says, so one bad entry is
210
213
  # reported once rather than cascading into every later one.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gargoyle-receipts
3
- Version: 0.6.0.dev0
3
+ Version: 0.6.1.dev0
4
4
  Summary: Signed, single-use, argument-bound receipts and human-approval holds for agent tool calls.
5
5
  Author: Justin LaPorte
6
6
  License-Expression: Apache-2.0
@@ -59,7 +59,7 @@ your MCP server and lets through only what both agreed to.
59
59
 
60
60
  [![PyPI](https://img.shields.io/pypi/v/gargoyle-receipts)](https://pypi.org/project/gargoyle-receipts/)
61
61
 
62
- Status: pre-release (`0.6.0.dev0`, on PyPI as `gargoyle-receipts`). The wire format is `gargoyle/3` and may
62
+ Status: pre-release (`0.6.1.dev0`, on PyPI as `gargoyle-receipts`). The wire format is `gargoyle/3` and may
63
63
  still change before the first release; it is specified in [SPEC.md](SPEC.md).
64
64
 
65
65
  ## What a receipt gives you
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gargoyle-receipts"
7
- version = "0.6.0.dev0"
7
+ version = "0.6.1.dev0"
8
8
  description = "Signed, single-use, argument-bound receipts and human-approval holds for agent tool calls."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -112,6 +112,7 @@ def test_init_for_a_windows_client_and_audit_log_verification(tmp_path, monkeypa
112
112
  assert "4 entries (3 honored, 1 refused), 0 failed; chain EVIDENCE_VERIFIED" in out_text
113
113
  assert out_text.count(" ok ") == 4 and "refused delete_file" in out_text
114
114
  assert "ENTRY_VERIFIED (DESTRUCTIVE_TOOL)" in out_text
115
+ assert "released by approver-1" in out_text # the held write names who released it
115
116
  # A tampered entry is caught, and the hash-chain names it: editing the
116
117
  # execution receipt inside entry 2 changes its hash.
117
118
  lines = log.read_text().splitlines(); e = json.loads(lines[1]); e["execution"]["outputs_sha256"] = "0" * 64