Skip to content

Add Python SDK core with wrap and signed outbox#51

Merged
negillett merged 10 commits into
mainfrom
python-sdk-core
May 19, 2026
Merged

Add Python SDK core with wrap and signed outbox#51
negillett merged 10 commits into
mainfrom
python-sdk-core

Conversation

@negillett
Copy link
Copy Markdown
Member

Summary

  • Implement the five public SDK entry points: configure, wrap,
    run_with_correlation_id, push_subject_mapping (no-op stub), and
    flush.
  • Add SQLite WAL outbox with per-correlation hash chains, Ed25519 signing
    over JCS canonical bytes, and background HTTP ingest export.
  • Commit golden signing fixtures verified byte-for-byte against the Node
    SDK canonicalizer and signer.

Test plan

  • cd intentproof-sdk-python && pytest -q (33 passed locally)
  • Node cross-check: canonicalizeIntentProof + Ed25519 on
    tests/fixtures/signing_unsigned_event.json matches Python fixtures

Review

  • Internal review found no blocking issues. push_subject_mapping is
    intentionally a no-op until reconciliation storage lands. Node does not
    ship this API yet.

Implement configure, wrap, correlation context, flush, SQLite
outbox, Ed25519 signing, and ingest export. Golden signing fixtures
match the Node SDK byte-for-byte in CI.

Signed-off-by: Nathan Gillett <nathan@intentproof.io>
@cursor
Copy link
Copy Markdown

cursor Bot commented May 19, 2026

PR Summary

High Risk
High risk because it introduces new cryptographic signing/key persistence, multithreaded background exporting, and SQLite state management that affect data integrity and runtime behavior across threads/reconfiguration.

Overview
Adds the SDK’s public surface (configure, wrap, run_with_correlation_id, flush, and push_subject_mapping) and wires it to a new runtime client that persists an instance Ed25519 keypair, maintains tenant/instance state, and manages a SQLite WAL outbox.

wrap() now records execution events as per-correlation hash chains, signs them using JCS-canonical bytes, stores them transactionally in the outbox, and optionally enqueues background HTTP export to ingest (with flush() joining exporter threads).

Updates packaging/CI to use pyproject.toml dependencies (adds cryptography, ulid-py, and pytest) and switches GitHub Actions to install .[dev] and run pytest; adds extensive tests including byte-for-byte golden fixtures for canonicalization, hashing, and signatures.

Reviewed by Cursor Bugbot for commit c0cf402. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread src/intentproof/instrumentation.py
Comment thread src/intentproof/instrumentation.py Outdated
Record event and chain state in one transaction; chain app
exceptions when outbox recording fails after a wrapped failure.

Signed-off-by: Nathan Gillett <nathan@intentproof.io>
Comment thread src/intentproof/http_exporter.py Outdated
Prevents flush() from joining a thread that is still in _pending
but not yet started.

Signed-off-by: Nathan Gillett <nathan@intentproof.io>
Comment thread src/intentproof/http_exporter.py
Comment thread src/intentproof/client.py Outdated
Drop finished threads from the exporter pending list on enqueue;
flush and close prior outbox and exporter when configure() runs.

Signed-off-by: Nathan Gillett <nathan@intentproof.io>
Comment thread src/intentproof/keys.py Outdated
Comment thread src/intentproof/client.py Outdated
Create keypair.json with mode 0600 via O_CREAT|O_EXCL; resolve
Path.home() only in default_data_dir() so import works in containers.

Signed-off-by: Nathan Gillett <nathan@intentproof.io>
Comment thread src/intentproof/outbox.py Outdated
Open SQLite with check_same_thread=False and serialize access
with a lock so wrap() works under Flask/gunicorn workers.

Signed-off-by: Nathan Gillett <nathan@intentproof.io>
Comment thread src/intentproof/instrumentation.py Outdated
record_chained_event holds the outbox lock from chain read
through signing to commit so concurrent workers cannot reuse
the same chain position.

Signed-off-by: Nathan Gillett <nathan@intentproof.io>
Comment thread src/intentproof/client.py Outdated
Comment thread src/intentproof/instrumentation.py
Comment thread src/intentproof/signing.py Outdated
Swap outbox only after new config succeeds; use Exception in
wrap so CancelledError propagates; remove unused public_key_bytes.

Signed-off-by: Nathan Gillett <nathan@intentproof.io>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 932b68a. Configure here.

Comment thread src/intentproof/keys.py
Nathan Gillett added 2 commits May 18, 2026 22:37
If another process creates keypair.json first, catch
FileExistsError and read the file instead of failing.

Signed-off-by: Nathan Gillett <nathan@intentproof.io>
Losers on O_EXCL can read an empty or partial file; retry JSON
load and fsync on create so CI concurrent test is stable.

Signed-off-by: Nathan Gillett <nathan@intentproof.io>
@negillett negillett merged commit 0a9fd42 into main May 19, 2026
3 checks passed
@negillett negillett deleted the python-sdk-core branch May 19, 2026 03:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant