ep-verify 0.1.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.
ep_verify/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """ep-verify: thin CLI alias over emilia_verify (same verifier, one verb)."""
3
+ from emilia_verify import verify_receipt # re-export the real verifier
4
+
5
+ __all__ = ["verify_receipt"]
ep_verify/cli.py ADDED
@@ -0,0 +1,87 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """ep-verify <receipt.json> [--keys keys.json]
3
+
4
+ Verifies one EP-RECEIPT-v1 document fully offline against issuer public
5
+ key(s) you pin (base64url SPKI, a JSON string, array, or {kid: key} map).
6
+ Prints VERIFIED or REFUSED plus a machine-readable JSON line; exit 0 only
7
+ on VERIFIED. Fail closed: any error, missing key, or malformed input
8
+ refuses. Verification proves signature/binding/anchor integrity against
9
+ the pinned keys; it never proves the action was correct or sufficient.
10
+ """
11
+ import json
12
+ import sys
13
+
14
+ from emilia_verify import verify_receipt
15
+
16
+ USAGE = "usage: ep-verify <receipt.json> [--keys keys.json]"
17
+
18
+
19
+ def _load_keys(path):
20
+ with open(path, "r", encoding="utf-8") as f:
21
+ data = json.load(f)
22
+ if isinstance(data, str):
23
+ return [data]
24
+ if isinstance(data, list):
25
+ return [k for k in data if isinstance(k, str)]
26
+ if isinstance(data, dict):
27
+ return [v for v in data.values() if isinstance(v, str)]
28
+ return []
29
+
30
+
31
+ def main(argv=None):
32
+ argv = list(sys.argv[1:] if argv is None else argv)
33
+ if not argv or argv[0] in ("-h", "--help"):
34
+ print(__doc__ if argv and argv[0] in ("-h", "--help") else USAGE)
35
+ return 0 if argv else 1
36
+ receipt_path, keys_path = argv[0], None
37
+ if "--keys" in argv:
38
+ i = argv.index("--keys")
39
+ if i + 1 >= len(argv):
40
+ print("REFUSED")
41
+ print(json.dumps({"result": "refused", "reason": "keys_flag_without_path"}))
42
+ return 1
43
+ keys_path = argv[i + 1]
44
+
45
+ try:
46
+ with open(receipt_path, "r", encoding="utf-8") as f:
47
+ doc = json.load(f)
48
+ except Exception:
49
+ print("REFUSED")
50
+ print(json.dumps({"result": "refused", "reason": "receipt_unreadable_or_malformed"}))
51
+ return 1
52
+
53
+ keys = []
54
+ if keys_path:
55
+ try:
56
+ keys = _load_keys(keys_path)
57
+ except Exception:
58
+ print("REFUSED")
59
+ print(json.dumps({"result": "refused", "reason": "keys_unreadable_or_malformed"}))
60
+ return 1
61
+ if not keys:
62
+ print("REFUSED")
63
+ print(json.dumps({"result": "refused", "reason": "no_pinned_keys"}))
64
+ return 1
65
+
66
+ last_error = None
67
+ for key in keys:
68
+ try:
69
+ result = verify_receipt(doc, key)
70
+ except Exception as e: # verifier crash on hostile input = refusal
71
+ last_error = f"verifier_error:{type(e).__name__}"
72
+ continue
73
+ if getattr(result, "valid", False) or (isinstance(result, dict) and result.get("valid")):
74
+ checks = getattr(result, "checks", None) or (result.get("checks") if isinstance(result, dict) else None)
75
+ print("VERIFIED")
76
+ print(json.dumps({"result": "verified", "receipt_id": (doc.get("payload") or {}).get("receipt_id"), "checks": checks}, default=str))
77
+ return 0
78
+ err = getattr(result, "error", None) or (result.get("error") if isinstance(result, dict) else None)
79
+ last_error = err or "signature_invalid"
80
+
81
+ print("REFUSED")
82
+ print(json.dumps({"result": "refused", "reason": last_error or "no_key_verified"}, default=str))
83
+ return 1
84
+
85
+
86
+ if __name__ == "__main__":
87
+ sys.exit(main())
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.4
2
+ Name: ep-verify
3
+ Version: 0.1.0
4
+ Summary: One-line offline verifier for EMILIA Protocol authorization receipts (EP-RECEIPT-v1). Thin CLI over emilia-verify: proves signature, binding, and anchor integrity against keys you pin; never business correctness.
5
+ Project-URL: Homepage, https://www.emiliaprotocol.ai
6
+ Project-URL: Repository, https://github.com/emiliaprotocol/emilia-protocol
7
+ Author-email: Iman Schrock <team@emiliaprotocol.ai>
8
+ License: Apache-2.0
9
+ Requires-Python: >=3.10
10
+ Requires-Dist: emilia-verify>=2.2.0
11
+ Description-Content-Type: text/markdown
12
+
13
+ # ep-verify
14
+
15
+ One-line offline verifier for EMILIA Protocol authorization receipts
16
+ (EP-RECEIPT-v1). A thin CLI over [`emilia-verify`](https://pypi.org/project/emilia-verify/),
17
+ so `ep-verify` is the same verb on PyPI and npm.
18
+
19
+ ```bash
20
+ pip install ep-verify
21
+ ep-verify receipt.json --keys keys.json
22
+ ```
23
+
24
+ Prints `VERIFIED` or `REFUSED` plus one machine-readable JSON line;
25
+ exit code 0 only on VERIFIED. Fully offline, fail closed: a missing key,
26
+ unreadable file, or verifier error is a refusal, never a pass.
27
+
28
+ What VERIFIED means: the Ed25519 signature over the canonical (RFC 8785)
29
+ payload validates against a key **you** pinned, and any Merkle anchor is
30
+ consistent. What it does NOT mean: that the action was correct, sufficient,
31
+ or accepted by any relying party; acceptance is a relying-party decision.
32
+
33
+ Apache-2.0. Part of the EMILIA Protocol reference tooling:
34
+ https://github.com/emiliaprotocol/emilia-protocol
@@ -0,0 +1,6 @@
1
+ ep_verify/__init__.py,sha256=5Zz0vQOwVBykyZA3d9aYh7ukHCBnfqpt3oGVgsUm5GY,218
2
+ ep_verify/cli.py,sha256=q0DYcnnJMAOBPbDxJp3i8oFvbL33Sp0oN1592FYNmEg,3203
3
+ ep_verify-0.1.0.dist-info/METADATA,sha256=D3w3jKKAdhonxn_zeg_HEfbuDh4RzxysU_SPnFRB0Xo,1487
4
+ ep_verify-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
5
+ ep_verify-0.1.0.dist-info/entry_points.txt,sha256=_J9YEtB6NfeBBXirEmBuJbQcGL2HBzVbrWaL5dGUMA4,49
6
+ ep_verify-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ep-verify = ep_verify.cli:main