gargoyle-receipts 0.7.0.dev0__tar.gz → 0.7.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.
- {gargoyle_receipts-0.7.0.dev0/gargoyle_receipts.egg-info → gargoyle_receipts-0.7.1.dev0}/PKG-INFO +2 -2
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/README.md +1 -1
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/cli.py +4 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/evidence.py +8 -3
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0/gargoyle_receipts.egg-info}/PKG-INFO +2 -2
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/pyproject.toml +1 -1
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_state.py +10 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/LICENSE +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/NOTICE +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/__init__.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/approval.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/approver_cli.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/approver_trust.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/approvers.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/consumer.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/entra_login.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/envelope.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/execution.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/fs_server.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/identity.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/issuer.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/issuer_service.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/jws.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/key_record_source.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/mcp_server.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/notify.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/opa.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/pending_store.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/policy.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/published_record_source.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/replay_cache.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/rules.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/state.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/static/approve.html +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/static/approve.js +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/verifier.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle_receipts.egg-info/SOURCES.txt +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle_receipts.egg-info/dependency_links.txt +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle_receipts.egg-info/entry_points.txt +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle_receipts.egg-info/requires.txt +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle_receipts.egg-info/top_level.txt +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/setup.cfg +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_annotations.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_approver_cli.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_approvers.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_canonical.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_cli.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_console_js.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_consumer.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_entra_identity.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_entra_login.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_evidence.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_execution.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_fs_server.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_historical.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_identity.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_issuer_service.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_jws.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_mcp_proxy.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_mcp_self_issue.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_mcp_server.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_notify.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_opa.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_policy.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_published_record.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_rules.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_stdio_encoding.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_threshold.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_typescript_conformance.py +0 -0
- {gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_wire_spec.py +0 -0
{gargoyle_receipts-0.7.0.dev0/gargoyle_receipts.egg-info → gargoyle_receipts-0.7.1.dev0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gargoyle-receipts
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.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
|
[](https://pypi.org/project/gargoyle-receipts/)
|
|
61
61
|
|
|
62
|
-
Status: pre-release (`0.7.
|
|
62
|
+
Status: pre-release (`0.7.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
|
[](https://pypi.org/project/gargoyle-receipts/)
|
|
23
23
|
|
|
24
|
-
Status: pre-release (`0.7.
|
|
24
|
+
Status: pre-release (`0.7.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
|
|
@@ -246,6 +246,10 @@ def cmd_audit(args) -> int:
|
|
|
246
246
|
why = (" (%s)" % r["verdict"]) if r["kind"] == "refused" and r["verdict"] else ""
|
|
247
247
|
if r.get("released_by"):
|
|
248
248
|
why += " released by " + ", ".join(r["released_by"])
|
|
249
|
+
if r.get("state"):
|
|
250
|
+
# A state-bound call: the target as it was approved, and as the run left it.
|
|
251
|
+
pre, post = (r["state"].get("pre") or "")[:8], (r["state"].get("post") or "")[:8]
|
|
252
|
+
why += " state %s -> %s" % (pre or "?", post or "?") if post else " state %s" % pre
|
|
249
253
|
print("%4s %-5s %-8s %-24s %-28s %s%s" % (r["seq"] if r["seq"] is not None else "?",
|
|
250
254
|
"ok" if r["accepted"] else "FAIL", r["kind"] or "?",
|
|
251
255
|
(r["tool"] or "?")[:24], (r["principal"] or "?")[:28], r["reason"], why))
|
|
@@ -160,7 +160,8 @@ def verify_log(
|
|
|
160
160
|
{"accepted", "reason", "tail_sha256", "count", "honored", "refused",
|
|
161
161
|
"entries": [{"seq", "kind", "tool", "principal", "accepted", "reason", "verdict", "released_by"}, ...]},
|
|
162
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
|
+
`released_by` the approver key ids of the grants an honored held call carried,
|
|
164
|
+
`state` {"pre", "post"} the target's state hashes when the call was state-bound.
|
|
164
165
|
Verification continues past a bad entry so the report names every one."""
|
|
165
166
|
trust = dict(issuer_public_keys=issuer_public_keys, executor_public_keys=executor_public_keys,
|
|
166
167
|
approver_public_keys=approver_public_keys)
|
|
@@ -178,7 +179,7 @@ def verify_log(
|
|
|
178
179
|
rc = rc if isinstance(rc, dict) else {}
|
|
179
180
|
report.append({"seq": None, "kind": None, "tool": rc.get("tool"), "principal": rc.get("principal"),
|
|
180
181
|
"accepted": False, "reason": REF_EVIDENCE_UNCHAINED if legacy else REF_EVIDENCE_MALFORMED,
|
|
181
|
-
"verdict": None, "released_by": []})
|
|
182
|
+
"verdict": None, "released_by": [], "state": None})
|
|
182
183
|
all_ok = False
|
|
183
184
|
continue
|
|
184
185
|
e = raw
|
|
@@ -206,8 +207,12 @@ def verify_log(
|
|
|
206
207
|
counts[e["kind"]] += 1
|
|
207
208
|
released_by = [g.get("approver_key_id") for g in (e["grant"] if isinstance(e["grant"], list) else [e["grant"]])
|
|
208
209
|
if isinstance(g, dict)] if e["grant"] is not None else []
|
|
210
|
+
ex = e["execution"] if isinstance(e["execution"], dict) else {}
|
|
211
|
+
state = ({"pre": ex.get("pre_state_sha256"), "post": ex.get("post_state_sha256")}
|
|
212
|
+
if ex.get("pre_state_sha256") or ex.get("post_state_sha256") else None)
|
|
209
213
|
report.append({"seq": e["seq"], "kind": e["kind"], "tool": e["tool"], "principal": e["principal"],
|
|
210
|
-
"accepted": ok, "reason": reason, "verdict": e["reason"], "released_by": released_by
|
|
214
|
+
"accepted": ok, "reason": reason, "verdict": e["reason"], "released_by": released_by,
|
|
215
|
+
"state": state})
|
|
211
216
|
all_ok = all_ok and ok
|
|
212
217
|
# The chain continues from what the file says, so one bad entry is
|
|
213
218
|
# reported once rather than cascading into every later one.
|
{gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0/gargoyle_receipts.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gargoyle-receipts
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.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
|
[](https://pypi.org/project/gargoyle-receipts/)
|
|
61
61
|
|
|
62
|
-
Status: pre-release (`0.7.
|
|
62
|
+
Status: pre-release (`0.7.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.7.
|
|
7
|
+
version = "0.7.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"
|
|
@@ -168,3 +168,13 @@ def test_middleware_refuses_when_the_file_moved_between_card_and_run(tmp_path):
|
|
|
168
168
|
chain = verify_chain(gate["envelope"], ex, grant=gate["grant"], issuer_public_keys=ISSUER_KEYS,
|
|
169
169
|
executor_public_keys={"executor-1": executor.public_key()}, approver_public_keys={"approver-1": approver.public_key()})
|
|
170
170
|
assert chain["reason"] == ACCEPT_CHAIN_VERIFIED
|
|
171
|
+
# The audit names the state transition.
|
|
172
|
+
from gargoyle.evidence import verify_log
|
|
173
|
+
entry = {"evidence_version": "gargoyle-evidence/2", "seq": 1, "prev_sha256": "0" * 64, "at": NOW.isoformat(), "kind": "honored",
|
|
174
|
+
"tool": "write_file", "args_sha256": gate["envelope"]["request_context"]["args_sha256"], "principal": "agent-7",
|
|
175
|
+
"reason": gate["reason"], "receipt": gate["envelope"], "grant": gate["grant"], "execution": ex}
|
|
176
|
+
from gargoyle.evidence import entry_sha256
|
|
177
|
+
entry["entry_sha256"] = entry_sha256(entry)
|
|
178
|
+
v = verify_log([entry], issuer_public_keys=ISSUER_KEYS, executor_public_keys={"executor-1": executor.public_key()},
|
|
179
|
+
approver_public_keys={"approver-1": approver.public_key()})
|
|
180
|
+
assert v["accepted"] and v["entries"][0]["state"] == {"pre": ex["pre_state_sha256"], "post": ex["post_state_sha256"]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle/published_record_source.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/gargoyle_receipts.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_published_record.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gargoyle_receipts-0.7.0.dev0 → gargoyle_receipts-0.7.1.dev0}/tests/test_typescript_conformance.py
RENAMED
|
File without changes
|
|
File without changes
|