arkova 2.2.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.
- arkova/__init__.py +61 -0
- arkova/agents.md +76 -0
- arkova/client.py +603 -0
- arkova/errors.py +32 -0
- arkova/models.py +364 -0
- arkova/proofs.py +816 -0
- arkova/py.typed +1 -0
- arkova-2.2.0.dist-info/METADATA +229 -0
- arkova-2.2.0.dist-info/RECORD +10 -0
- arkova-2.2.0.dist-info/WHEEL +4 -0
arkova/__init__.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from .client import BULK_ANCHOR_MAX_ROWS, Arkova, AsyncArkova
|
|
2
|
+
from .errors import ArkovaError
|
|
3
|
+
from .models import (
|
|
4
|
+
Anchor,
|
|
5
|
+
AnchorReceipt,
|
|
6
|
+
BulkAnchorCredentialType,
|
|
7
|
+
BulkAnchorDuplicate,
|
|
8
|
+
BulkAnchorDuplicateStrategy,
|
|
9
|
+
BulkAnchorInput,
|
|
10
|
+
BulkAnchorResponse,
|
|
11
|
+
BulkAnchorResultRow,
|
|
12
|
+
BulkAnchorRowError,
|
|
13
|
+
FingerprintVerification,
|
|
14
|
+
MerkleProofEntry,
|
|
15
|
+
MerkleProofResponse,
|
|
16
|
+
Org,
|
|
17
|
+
OrgList,
|
|
18
|
+
ProblemDetail,
|
|
19
|
+
ProofBundle,
|
|
20
|
+
ProofBundleSignature,
|
|
21
|
+
SearchResponse,
|
|
22
|
+
SearchResult,
|
|
23
|
+
VerificationResult,
|
|
24
|
+
)
|
|
25
|
+
from .proofs import (
|
|
26
|
+
REASON_CODES,
|
|
27
|
+
VerifyOutcome,
|
|
28
|
+
verify_bundle,
|
|
29
|
+
verify_merkle_inclusion,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
__all__ = [
|
|
33
|
+
"BULK_ANCHOR_MAX_ROWS",
|
|
34
|
+
"REASON_CODES",
|
|
35
|
+
"Anchor",
|
|
36
|
+
"AnchorReceipt",
|
|
37
|
+
"Arkova",
|
|
38
|
+
"ArkovaError",
|
|
39
|
+
"AsyncArkova",
|
|
40
|
+
"BulkAnchorCredentialType",
|
|
41
|
+
"BulkAnchorDuplicate",
|
|
42
|
+
"BulkAnchorDuplicateStrategy",
|
|
43
|
+
"BulkAnchorInput",
|
|
44
|
+
"BulkAnchorResponse",
|
|
45
|
+
"BulkAnchorResultRow",
|
|
46
|
+
"BulkAnchorRowError",
|
|
47
|
+
"FingerprintVerification",
|
|
48
|
+
"MerkleProofEntry",
|
|
49
|
+
"MerkleProofResponse",
|
|
50
|
+
"Org",
|
|
51
|
+
"OrgList",
|
|
52
|
+
"ProblemDetail",
|
|
53
|
+
"ProofBundle",
|
|
54
|
+
"ProofBundleSignature",
|
|
55
|
+
"SearchResponse",
|
|
56
|
+
"SearchResult",
|
|
57
|
+
"VerificationResult",
|
|
58
|
+
"VerifyOutcome",
|
|
59
|
+
"verify_bundle",
|
|
60
|
+
"verify_merkle_inclusion",
|
|
61
|
+
]
|
arkova/agents.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# packages/arkova-py/src/arkova/agents.md
|
|
2
|
+
|
|
3
|
+
Python SDK for the Arkova Verification API v2. Sync + async clients using `httpx` and `pydantic`.
|
|
4
|
+
|
|
5
|
+
## Files
|
|
6
|
+
- **`__init__.py`** — package exports: `Arkova`, `AsyncArkova`, `ArkovaError`, `BULK_ANCHOR_MAX_ROWS`, all model classes, and the offline proof helpers (`verify_bundle`, `verify_merkle_inclusion`, `REASON_CODES`, `VerifyOutcome`).
|
|
7
|
+
- **`client.py`** — `Arkova` (sync) and `AsyncArkova` (async) clients. Supports search, verify, anchor, anchor_bulk, org listing. Auto-retry on 429/5xx with exponential backoff.
|
|
8
|
+
- **`models.py`** — Pydantic models: `Anchor`, `VerificationResult`, `FingerprintVerification`, `SearchResponse`, `ProblemDetail`, `AnchorReceipt`, `BulkAnchorInput` (plain dataclass, not pydantic — it's a request shape, not a parsed response), `BulkAnchorResponse`, etc.
|
|
9
|
+
- **`errors.py`** — `ArkovaError` exception with `status_code`, `code` (machine-readable error code), `problem` (RFC 7807), and `retry_after`.
|
|
10
|
+
- **`proofs.py`** — DEV-02 / S3-B standalone OFFLINE proof-bundle verifier:
|
|
11
|
+
`verify_bundle(packet, node=None, signed_bundle=None, published_keys=None,
|
|
12
|
+
public_key_pem=None)` (`public_key_pem` = legacy single-key path, no id
|
|
13
|
+
resolution). An INDEPENDENT re-derivation of the bundle format from spec
|
|
14
|
+
(double-SHA256 positional Merkle + CVE-2012-2459 structural guard,
|
|
15
|
+
`ARKV||root` OP_RETURN at fixed offset [4,36), 80-byte header rules +
|
|
16
|
+
LE-uint32 observed time, §1.5 timestamp honesty, canonical-JSON +
|
|
17
|
+
pure-python RFC 8032 Ed25519 with signing_key_id resolution) — deliberately
|
|
18
|
+
NOT a port of the TS verifier. Emits the FROZEN S3-B reason enum (mirrored
|
|
19
|
+
byte-for-byte in `packages/verifier-cli/fixtures/manifest.json`). Stdlib
|
|
20
|
+
only, zero network, zero Arkova calls, Python >= 3.9. A passing signature
|
|
21
|
+
never substitutes for the recompute; a failing explicitly-requested one
|
|
22
|
+
fails the verdict closed. Fail-closed gates guard Python/JSON type
|
|
23
|
+
coercions the TS side cannot even express: `proof_schema_version` rejects
|
|
24
|
+
bool (`True == 1`) but accepts float 1.0 (JSON parity with TS), and a
|
|
25
|
+
missing/blank `signing_key_id` is DID_UNRESOLVED (never matched to a
|
|
26
|
+
kid-less key via `None == None`). Never "fix" it by copying TS code across
|
|
27
|
+
— independence IS the deliverable; parity is enforced by `npm run parity`
|
|
28
|
+
in packages/verifier-cli.
|
|
29
|
+
- **`py.typed`** — PEP 561 marker for typed package.
|
|
30
|
+
|
|
31
|
+
## Conventions
|
|
32
|
+
- Default base URL: `https://api.arkova.ai/v2`. Auth via `Authorization: Bearer ak_*` header.
|
|
33
|
+
- Published to PyPI via `.github/workflows/publish-python-sdk.yml`.
|
|
34
|
+
- **Lint gate:** that workflow's `ruff check src tests` is the publish gate, and
|
|
35
|
+
`ruff` is pinned to an EXACT version in `pyproject.toml` — see the comment on
|
|
36
|
+
the pin there for why a range is not sufficient. Bump it deliberately and
|
|
37
|
+
clear any new findings in the same PR.
|
|
38
|
+
- **Five `# noqa`s here are load-bearing** — each carries its own inline
|
|
39
|
+
justification, so read the code, not a line number (these drift). Do not
|
|
40
|
+
"clean them up":
|
|
41
|
+
- `UP007` on `proofs.py`'s `NodeSource` — that file holds a Python 3.9 floor
|
|
42
|
+
deliberately NARROWER than the package's `requires-python = ">=3.10"`,
|
|
43
|
+
because it is meant to be copy-pasteable standalone.
|
|
44
|
+
- `BLE001` in `proofs.py` and `models.py` — deliberate fail-closed catches
|
|
45
|
+
(injected-node trust boundary; frozen-response proof-bundle validator).
|
|
46
|
+
- `PYI034` ×2 in `client.py` — `typing.Self` is 3.11+, the floor is 3.10, and
|
|
47
|
+
the package carries no `typing_extensions` dependency.
|
|
48
|
+
|
|
49
|
+
## Write path (anchor / anchor_bulk, added 2026-07-28)
|
|
50
|
+
HAKI-REQ-02 (SCRUM-1171): this package was entirely read-only until this
|
|
51
|
+
change — `POST /api/v1/anchor` and `/api/v1/anchor/bulk` were complete on
|
|
52
|
+
the worker (`services/worker/src/api/v1/anchor-bulk.ts`) and already wired
|
|
53
|
+
into the TS SDK (`packages/sdk`), but nothing called them from Python.
|
|
54
|
+
- `Arkova.anchor()` / `AsyncArkova.anchor()` — provide `data` (fingerprinted
|
|
55
|
+
in-process via the same SHA-256 algorithm as `Arkova.fingerprint()`,
|
|
56
|
+
matching `integrations/shared/src/fingerprint.ts` / the TS SDK) or a
|
|
57
|
+
pre-computed `fingerprint`, never both/neither (`ArkovaError(code=
|
|
58
|
+
"invalid_request")` client-side otherwise, no network call).
|
|
59
|
+
- `Arkova.anchor_bulk()` / `AsyncArkova.anchor_bulk()` — takes
|
|
60
|
+
`list[BulkAnchorInput]`, same fingerprint/data contract per row. Caps at
|
|
61
|
+
`BULK_ANCHOR_MAX_ROWS` (1000, mirrors the worker's zod `.max(1000)`);
|
|
62
|
+
raises client-side (`code="batch_too_large"`) rather than auto-chunking —
|
|
63
|
+
chunking would split intra-batch duplicate detection and credit deduction
|
|
64
|
+
across requests. `dry_run` / `duplicate_strategy` / `batch_id` map through
|
|
65
|
+
to the server's `dry_run` / `duplicate_strategy` / `batch_id`.
|
|
66
|
+
- Auth for the new write methods matches the existing read methods exactly:
|
|
67
|
+
`Authorization: Bearer ak_*`, no separate credential path.
|
|
68
|
+
- `_raise_for_error` (in `client.py`) was extended to parse the plain
|
|
69
|
+
`{"error": ..., "message": ...}` JSON body v1 write-path endpoints return
|
|
70
|
+
(not RFC 7807 `application/problem+json`, which only the v2 API emits) and
|
|
71
|
+
populate the new `ArkovaError.code` — additive, the RFC 7807 path is
|
|
72
|
+
unchanged. See `errors.py` docstring for the full precedence.
|
|
73
|
+
- Test coverage in `tests/test_client.py` (search `# anchor() / anchor_bulk()
|
|
74
|
+
write path`): cap boundary, mixed fingerprint+data rows, dry-run, per-row
|
|
75
|
+
errors on a partial success, 409 duplicate-fail, 402 insufficient-credits,
|
|
76
|
+
plus sync + async wiring.
|