Repository navigation
Conversation
* chore: Update c2pa version to v0.90.16 * Bump version from 0.37.8 to 0.37.9 * Bump version from 0.37.8 to 0.37.9
…uth#320) * build: drop wheel, setuptools and pytest from runtime dependencies None of the three is imported anywhere under `src/`. `c2pa.py` and `lib.py` import only the standard library; `build.py` — the `download-artifacts` console script — imports `requests` and, lazily, `toml`. Those two stay. They are also already classified correctly elsewhere in the repo: * `[build-system] requires` already lists `setuptools>=68.0.0` and `wheel`, so the build has what it needs and the runtime entries are duplicates. * `requirements-dev.txt` lists `wheel` and `setuptools` under "# Build dependencies" and `pytest` under "# Testing dependencies". * `.github/workflows/build.yml` installs pytest explicitly (`pip install pytest`, lines 285 and 377), so CI does not rely on the runtime declaration either. Removing them is therefore a no-op for this repo's own build and test paths, and it keeps three packages out of every consumer's production environment. * build: declare pytest in a PEP 735 dev dependency group Dropping pytest from `[project.dependencies]` left it undeclared in pyproject.toml entirely, with `requirements-dev.txt` as the only manifest naming it. `[dependency-groups] dev` states it where it belongs: installed for contributors (`uv sync`, `pip install --group dev`) and, unlike `[project.optional-dependencies]`, absent from the published package metadata — which is the separation this branch is about. The bound matches requirements-dev.txt (`pytest>=8.1.0`) rather than the `>=7.4.0` the runtime entry carried; nothing installs the old one. The comment above the remaining dependencies goes with it. The rationale for keeping `toml` and `requests` belongs in the pull request, not in a manifest that has carried no comments so far. * build: keep pytest declared in requirements-dev.txt only Review feedback: the PEP 735 group restated a bound that `requirements-dev.txt` already carries, so the two could drift — which is what this branch set out to stop, not to reproduce one line further down. Nothing in the repo would have read the group. The Makefile's `install-deps` and every workflow that installs dependencies do so with `pip install -r requirements-dev.txt` (`build.yml` lines 52, 90/93, 164/167, 490/492), and the wheel test jobs install pytest by name. The group was a declaration with no consumer. The published metadata — the point of this branch — is unaffected either way, and the diff is now purely subtractive.
* Update c2pa version from v0.90.16 to v0.90.19 * Bump version from 0.37.9 to 0.37.10 * Bump version from 0.37.9 to 0.37.10
* chore: Update C2PA version to 0.90.22 * Bump version from 0.37.10 to 0.37.11 * Bump version from 0.37.10 to 0.37.11
…t-tooling Add reusable c2pa-rs RC-preflight workflow; fix latent test bugs
…#327) test_sdk_version compares the loaded native library's version against c2pa-native-version.txt, but an RC-preflight run (per test-c2pa-rs-source-build.yml) actually builds from whatever ref is in c2pa-rs-preflight-ref.txt instead, so the test always failed on that one assertion during a preflight even when everything else passed. parse_native_version() now prefers c2pa-rs-preflight-ref.txt when present, falling back to c2pa-native-version.txt otherwise -- the same precedence the workflow itself uses to decide what to build. Verified both paths locally: green against the pinned 0.90.22 with no preflight file, and green against a c2pa-rc-v0.91.0-rc.3 build with the file present. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
contentauth#328) contentauth#327's parse_native_version() fix preferred c2pa-rs-preflight-ref.txt whenever it existed in the checked-out tree. That broke the *real* build.yml jobs on contentauth#325: that PR adds the ref file to the branch, so an ordinary tests-unix/tests-windows run (which downloads and installs the actual pinned release, unrelated to the preflight workflow) picked up the file too and wrongly expected the RC's version string, failing with e.g. "'0.91.0-rc.3' not found in '0.90.22'". The file's mere presence was never a reliable signal -- only test-c2pa-rs-source-build.yml's own "Run tests" step actually builds from that ref. Gate on a new C2PA_PREFLIGHT_RUN env var that only that step sets instead. Verified locally: with the pinned 0.90.22 installed and no env var set, all 444 tests pass regardless of whether c2pa-rs-preflight-ref.txt happens to exist in the tree. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* Fix test_sdk_version regression: gate on an env var, not file presence contentauth#327's parse_native_version() fix preferred c2pa-rs-preflight-ref.txt whenever it existed in the checked-out tree. That broke the *real* build.yml jobs on contentauth#325: that PR adds the ref file to the branch, so an ordinary tests-unix/tests-windows run (which downloads and installs the actual pinned release, unrelated to the preflight workflow) picked up the file too and wrongly expected the RC's version string, failing with e.g. "'0.91.0-rc.3' not found in '0.90.22'". The file's mere presence was never a reliable signal -- only test-c2pa-rs-source-build.yml's own "Run tests" step actually builds from that ref. Gate on a new C2PA_PREFLIGHT_RUN env var that only that step sets instead. Verified locally: with the pinned 0.90.22 installed and no env var set, all 444 tests pass regardless of whether c2pa-rs-preflight-ref.txt happens to exist in the tree. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Point the RC preflight at c2pa-rs 0.91.0-rc.3 This is the entire diff this PR now carries on top of contentauth#328: pin the preflight workflow at c2pa-rc-v0.91.0-rc.3 so it builds from that git tag (no crates.io publish, no prebuilt GitHub release binaries for an RC) and runs the full unit test suite against it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Point the RC preflight at c2pa-rs 0.91.0-rc.3 This is the entire diff this PR now carries on top of contentauth#328: pin the preflight workflow at c2pa-rc-v0.91.0-rc.3 so it builds from that git tag (no crates.io publish, no prebuilt GitHub release binaries for an RC) and runs the full unit test suite against it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Preflight against c2pa-rs 0.91.0-rc.4 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * chore: bump c2pa-rs to v0.91.0 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* chore: Bump version from 0.37.11 to 0.37.12 * Bump version from 0.37.11 to 0.37.12
Pin native castlabs/c2pa-rs a2739fd6 (VSI + contentauth main 6c92bc32 + fMP4/TFRA fixes + validation time/trust purposes), Rust 1.96.0, and release from feat/conformance-validation-v02.
…l tests Install pytest explicitly in the installed-wheel test environments and pin native castlabs/c2pa-rs 6ca7fb16.
Register the native ladder export as optional, validate path arrays, preserve typed errors and allocation ownership, and use the modern single-sign builder lifecycle. Add focused binding tests and isolated stock/candidate native qualification lanes without changing release pins. Co-authored-by: bibinbaby444 <bibinbaby444@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Use c2pa_free for new manifest allocations, include focused ladder tests in existing CI runs, reject optimized verification harness execution, and document the modern builder lifecycle.
Include a documented synthetic fixture and offline native smoke in the existing CI selection. Enforce candidate capability on request, verify the native signature and shared manifest, and cover typed ctypes conversion without changing stock native pins or builder semantics. Co-authored-by: bibinbaby444 <bibinbaby444@gmail.com>
…idation # Conflicts: # docs/class-diagram.md # pyproject.toml # src/c2pa/c2pa.py # tests/test_unit_tests.py
|
@BibinBaby444 requesting your review (a formal review request isn't possible: you're not a collaborator on this repository). Companion draft PRs: castlabs/c2pa-rs#15, #4, castlabs/stardustproof-keystore#13, castlabs/stardustproof-c2pa-signer#25. |
|
The independently reviewed ownership follow-up |
BibinBaby444
left a comment
There was a problem hiding this comment.
Changes requested. One memory-safety bug reachable from plain Python, plus one native state that's invisible to Python. Verified at 12d265db against a native built from c2pa-rs d738fbb2 (debug, unstable_live_video). Note that CI is not evidence here yet: every test job on this PR was skipped, including "Trusted VSI paired-source API"; only format and tooling checks ran.
P1: closing a session during a native call frees callbacks native is still using.
TrustedVsiSession._releasedrops_signer_callback_cb,_dynamic_assertion_cbsand_trusted_vsi_callback, and_teardowncalls it beforec2pa_free.- Native
freedefers the actual drop while a call holds the borrow, so the in-flightfinalize_init_uuidkeeps calling through the freed thunks. - Once the Context has been closed (which the contract allows), the session holds the only reference to the claim-signer thunk.
- A single thread is enough. Close the session from inside its own
signer_bindingcallback, then allocate freshSignerCallbacks:finalize raised: _C2paSignature('Signature: internal error (bad parameter: signer callback returned error code -1)') real claim callback calls: [] impostor calls: [1876] - Native jumped through the freed claim thunk into an unrelated callback, which received the 1,876-byte claim payload. With different reuse that's a crash or a call into arbitrary code.
- Suggest keeping the callback pins alive for the object's lifetime (don't clear them in
_release), or deferringclose()until in-flight calls drain. - The same drop-on-close pattern exists in the older live-video VSI session and Builder
_releases, and the native contract text ("until the handle is freed") should say "until the deferred drop".
P2: blocked is never exposed.
- Native
C2paLiveVideoTrustedVsiStatusV1hasblocked: boolbetweenhas_exhaustion_reasonandexhaustion_reason, at offset 18. - The ctypes struct,
TrustedVsiStatusandstatus()all omit it. The layout still lines up, since Python treats the byte as padding, so there's no memory hazard. - But Python can't see the one state the contract tells adapters to act on ("After a failure once an external signing call began, the session is blocked. Discard it, construct a NEW session…"):
before failure: native blocked byte[18] = 0 -> status() has no blocked field after failure: native blocked byte[18] = 1 -> status() unchanged next call: _C2paOther Other: bad parameter: session is blocked after a failed external signing step; … - Add the field and a
blockedattribute onTrustedVsiStatus, update the offsets pinned intests/test_trusted_vsi_api.py, and add a paired test that assertsstatus().blockedafter a callback failure.
P2: the stock-native lane will fail, and CI hasn't run it. The dynamic variant of test_scripted_wrappers_store_base_exceptions_return_minus_one_and_reraise calls signer.add_dynamic_assertion unguarded. The -k "not paired" lane in build.yml downloads upstream c2pa-v0.91.0 (c2pa-native-version.txt), and v0.91.0 (e7cc666c) doesn't export c2pa_signer_add_dynamic_assertion, so those four parametrizations raise NotSupported. Guard the variant on has_dynamic_assertions() (or stub the export in _ScriptedNative), then get the skipped jobs to actually run.
P3
- Ladder error guidance drops a guarantee.
docs/ladder-signing.mdand thesign_ladderdocstring say "Errors may leave partial newly created outputs; discard these files", but leave out native's guarantee that "Existing files, including every source, are never overwritten". The native error doesn't say which path failed, so say callers should delete only destinations they confirmed absent before the call. Otherwise a cleanup-everything handler deletes a pre-existing file. - The version gate is a release label, not an ABI identity.
0.92.0-devis upstream's workspace version, so the gate effectively rests on the symbol plus mask 63. A native ABI-revision probe would make a future in-place V1 struct change detectable.
Defer physical teardown until admitted native calls drain, preserve callback pins through free, and expose trusted VSI blocked status. Cover reentrant close and stock-native behavior, adapt paired tests to the hardened native contract, and clarify output cleanup and qualification holds.
|
Resolution mapping for the existing review at Python
The integrated fragmented wrapper also restores the existing six-argument glob-aware ABI and shared-manifest segmented signing, without per-rendition fallback or ownership changes. Exact-head paired qualification 37688529697 passed on Linux/Windows: 286 focused, 831 non-threaded, 54 threaded and 286 installed-wheel tests per platform, plus the real-native ladder harness. Source/stock/installed evidence is in Ordinary stock-native hosted release jobs did not run in this paired lane. Immutable dev5 artifacts, release inputs and publication gates are unchanged; no release or universal platform guarantee is claimed. |
…gment_at_offset) Bind the Castlabs native c2pa_reader_with_fragment_at_offset(reader, format, stream, fragment, uint64 offset) and the c2pa_reader_fragment_at_offset_supported probe as optional symbols, so older native libraries still import. - has_fragment_at_offset(): true only when both exports exist and the probe returns true. The probe is called lazily on first use, never at import. - Reader.from_fragment_at_offset(format, init_stream, fragment_stream, fragment_offset, context=None) and Reader.with_fragment_at_offset(format, stream, fragment_stream, fragment_offset). They follow with_fragment ownership: the native call consumes the reader on success and failure. Gating raises C2paError.NotSupported before any argument or native work. The format must be a non-empty str (native fragment loading cannot auto-detect). The offset must be an int in 0..2**64-1 (bool rejected). The streams must be stream-like and distinct objects, and the context valid; all of this is checked before any native call. A wrong cut or offset gives an Invalid reader with assertion.bmffHash.mismatch. - Tests: scripted gating, validation and marshalling, plus real-native checks. Those sign the per-fragment-sidx single-file fixture (copied from castlabs/c2pa-rs ec9ac2f6), cut it at merkle uuid boundaries, verify each segment Trusted with bmffHash.match, and check wrong offsets (0, +/-1, sibling) are a mismatch. The real-native tests skip when the API is absent and fail under C2PA_FRAGMENT_OFFSET_REQUIRED=1. - Docs: README, usage and release notes.
feat: Reader offset-aware fragment verification; prepare 0.37.13.dev1
….8 line Merge origin/feat/conformance-validation-v02 (f55a1fb) to pair with the native castlabs/c2pa-rs conformance merge (PR contentauth#21). Resolution: - Release identity, pins and tooling stay on this line (0.37.13.* on feat/trusted-vsi-functional, trusted VSI API, fragment-offset binding and smoke); the conformance line's 0.37.12.dev1-dev4 release-prep pins are dropped. - Take the conformance line's genuine changes: contentauth main 0.37.12 merge content (already present here), 53ed862 native validation time and checked crJSON tests and fixture fixes, and the installed-wheel pytest install fix (Linux and Windows) with a tooling regression assertion. - Reader.crjson() documents the checked native export; add tests that a NULL return raises (with and without a native error message). - Move TestConformanceValidationSettings above the __main__ guard. - Keep both lines' release notes history.
Pin native castlabs/c2pa-rs afd6fffe5a066e0b5b1a14f3f8c7ac189e7f0c95 (the 1.0.8 trusted VSI native line merged with the conformance line; workspace 0.92.0-dev, Cargo.lock SHA-256 f7022b3e..., Rust 1.96.0) and release 0.37.13.dev2 from feat/trusted-vsi-functional as castlabs-v0.37.13.dev2. castlabs-v0.37.13.dev1 (run 38786913569) was not published: its installed-wheel test jobs lacked pytest. The paired qualification uses the same native commit; functional build identities dev1 and older are rejected.
The upstream prebuilt library used by build.yml has no verify.validation_time or crJSON 2.4. Document that strict_trust_purposes is accepted and ignored.
chore(release): 0.37.13.dev2 with conformance-validation-v02 merged
docs: plan signer-aligned +signer release versions
chore(release): Prepare signer-aligned 1.0.8 dependency
Functional trusted VSI Python binding plus ladder/fragmented signing and ownership hardening, paired with castlabs/c2pa-rs
feat/trusted-vsi-functional.Current Qualified Pair
Python
97c820efde96af75c900c02e05457aab1ba2e1e1, nativea6d4cdcc05638ee8dd0afce7fa5c850d7031a80c.TrustedVsiSessionand helpers admit only exact revision 3, native SDK tokenc2pa-rs/0.92.0-dev, required symbols and mask 63, before operational ctypes binding. No version range, fallback or trial operation. Contract:docs/trusted-vsi-python-contract.md.blockedis exposed by ctypes/status, with offset 18 and total native status size 24. Failure/recovery tests exercise it.has_dynamic_assertions(); source and installed-wheel paired jobs actually execute their functional checks.Merge Provenance
True merges retain ladder candidate
502b8bb2, generic ownership7ba8615, reviewed follow-upa303db8and callback-lifetime review fixes, without temporary CI-only commits or rewritten history. Ladder DynamicAssertion exceptions preserve identity and claim-signer interrupts propagate. Consume-first registry rejection parsing and opaque stream ownership remain anchored to rejected handle IDs.Unreleased source identity
0.37.13.dev0and immutable dev5 release inputs/locks/tooling remain distinct. Exact revision/version gating is intentionally coordinated, not source or binary authentication.Current Qualification
docs/archive/trusted-vsi-review-verification.md.0bf8949fpassed fresh exact-source public/operational qualification with the downloaded native artifact: 84 passed, zero skips/failures per version. Execution evidence and selected integration review.Historical Qualification And Limits
The old
12d265db/native6b506352pair (36808706395) is historical, superseded above. Stock 0.91.0 Windows x64 ownership/unit/ladder/threaded proof remains separate (36775608167); stock Windows ARM64 ownership was outside that scope. Ordinary stock-native hosted release jobs did not run in the current paired lane.Remaining generic opaque-native concurrency/sticky-slot work stays in the roadmap. No generic thread-safety, native composed event-ID carry, production provider or universal platform guarantee is claimed.
No publication; dev5 tooling still refuses this source. Immutable historical release artifacts are unchanged.