Skip to content

Feat: Expose sign-from-context, deprecate settings Signer - #119

Open
redaranj wants to merge 3 commits into
mainfrom
feat/sign-from-context
Open

Feat: Expose sign-from-context, deprecate settings Signer#119
redaranj wants to merge 3 commits into
mainfrom
feat/sign-from-context

Conversation

@redaranj

Copy link
Copy Markdown
Member

Changes in this pull request

Adds Builder.signWithContext(format, source, dest), which signs using the signer configured on the builder's context, whether set programmatically via C2PAContextBuilder.setSigner or supplied through settings. Deprecates Signer.fromSettingsJson/fromSettingsToml/loadSettings in favor of this context path, since they rely on FFI the upstream library has deprecated.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • All applicable changes have been documented
  • Any TO DO items (or similar) have been entered as GitHub issues and the link to that issue has been included in a comment

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.21%. Comparing base (077035c) to head (3536736).

Files with missing lines Patch % Lines
...ry/src/main/kotlin/org/contentauth/c2pa/Builder.kt 50.00% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##               main     #119   +/-   ##
=========================================
  Coverage     72.21%   72.21%           
  Complexity       38       38           
=========================================
  Files            62       62           
  Lines          2350     2350           
  Branches        286      286           
=========================================
  Hits           1697     1697           
+ Misses          495      494    -1     
- Partials        158      159    +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@redaranj
redaranj requested a review from scouten-adobe August 12, 2026 10:52
Add Builder.signWithContext(format, source, dest) over
c2pa_builder_sign_context, which signs using the signer configured on the
builder's context (programmatic via C2PAContextBuilder.setSigner or
supplied via settings). This is the modern path for the settings-signer
workflow.

Deprecate Signer.fromSettingsJson/fromSettingsToml/loadSettings, which
rely on the deprecated c2pa_load_settings and c2pa_signer_from_settings,
pointing at the context path instead.
@redaranj
redaranj force-pushed the feat/sign-from-context branch from ea604a0 to aca7443 Compare August 12, 2026 12:43

@scouten-adobe scouten-adobe left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review summary

Overall this is a clean, well-scoped addition — signWithContext mirrors the upstream c2pa_builder_sign_context FFI call correctly, and the Signer deprecations are safe (every real call site is already @Suppress-annotated, no test coverage removed). A few issues worth addressing before merge, roughly in order of importance:

Correctness

  1. sign() throws the wrong exception type on native failure, exposed by contrast with the new code. Builder.kt:581 checks if (result.size < 0) throw C2PAError.Api(...), but signNative (c2pa_jni.c:1060) calls throw_c2pa_exception()ThrowNew(RuntimeException) on failure and returns NULL — the JVM delivers that pending exception at the call boundary before result.size is ever read, so the C2PAError.Api branch is dead code. A caller doing try { builder.sign(...) } catch (e: C2PAError) { ... } (matching sign()'s documented @Throws(C2PAError::class)) will see an uncaught RuntimeException instead. This predates the PR, but the new signWithContext()/signWithContextNative correctly uses the return-null-and-throw-C2PAError-in-Kotlin pattern, so the two "sibling" sign APIs now behave inconsistently. Worth fixing signNative to match (drop the native throw, let Kotlin raise C2PAError like the new path does).

  2. Native memory leak when size == 0 in the new JNI function. c2pa_jni.c:1160 only calls c2pa_free(manifestBytes) inside if (manifestBytes != NULL && size > 0). If c2pa_builder_sign_context ever succeeds with a non-NULL, zero-length manifest buffer, it leaks. Low severity (a real 0-byte signed manifest is unlikely) and it's a duplicate of the same pre-existing pattern in signNative, but worth fixing in both places.

  3. KDoc overstates the construction requirement. Builder.kt:592 says the builder "must have been created via Builder.fromContext", but Builder.fromJson(json, settings) (Builder.kt:276-286) also builds via fromContext internally and would work fine with signWithContext too.

Style — blank line before multi-line statements

Per this file's own established convention (e.g. the pre-existing testSignerFromSettingsToml), a statement that wraps across multiple lines should be set off by a blank line above and below:

  • SignerTests.kt:810 — no blank line after the two-line val settingsToml = ... ?: throw ....
  • SignerTests.kt:857 — no blank line before the multi-line C2PAContext.create().use { ... }.

Reuse

  1. Duplicated SignResult construction boilerplate. signWithContextNative copies ~45 lines of class/constructor lookup + byte-array construction verbatim from signNative. No shared helper exists for this; worth extracting a build_sign_result(env, size, manifestBytes) helper so a fix to one path (e.g. the leak above) doesn't need to be duplicated into the other.

Test coverage

  1. No test exercises signWithContext on a builder created via fromJson/fromArchive (context closed before the builder is returned) — only the fromContext-with-open-context path is covered.
  2. testSignWithContextWithoutSigner assumes a fresh C2PAContext has no signer, but the same test suite also mutates deprecated global settings state (Signer.loadSettings/fromSettingsJson/fromSettingsToml) elsewhere — it's unverified that c2pa_context_new()'s defaults are isolated from that legacy global state, which could make this test order-dependent/flaky.
  3. Minor: testSignWithContextWithoutSigner captures a var thrown: C2PAError? across nested .use {} blocks instead of building the TestResult directly in the catch block, as testCawgRejectsClosedSigner does for the same "expect a throw" shape elsewhere in this file.

Requesting changes mainly on #1 (exception-type inconsistency) and #2 (leak) — the rest are lower-severity polish that could go either way before or after merge.

Align sign() with the documented C2PAError contract by returning NULL
from the JNI on failure and throwing from the Kotlin wrapper, matching
signWithContext. Extract the duplicated SignResult construction into a
build_sign_result helper that frees the manifest buffer on every path,
including zero-length results. Correct the signWithContext KDoc: any
builder has a context, so fromJson with signer-bearing settings works
too. Add tests for signing from a fromJson builder and for the
unsupported-format error path.
@redaranj redaranj changed the title feat: Expose sign-from-context, deprecate settings Signer Feat: Expose sign-from-context, deprecate settings Signer Aug 20, 2026
C2PA.loadSettings and loadSettingsResult call the same deprecated
c2pa_load_settings as the already-deprecated Signer.loadSettings, so give
them the same deprecation notice pointing to C2PASettings and
C2PAContextBuilder, and suppress the warning in the internal callers and
the test that still exercise the old path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@redaranj
redaranj requested a review from scouten-adobe August 21, 2026 07:45
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.

2 participants