Skip to content

test(xtest): verify assertion bindings in Python; split out test_tdf_assertions.py - #656

Draft
dmihalcik-virtru wants to merge 2 commits into
mainfrom
DSPX-5229-xtest-assertion-checks
Draft

dmihalcik-virtru wants to merge 2 commits into
mainfrom
DSPX-5229-xtest-assertion-checks

Conversation

@dmihalcik-virtru

Copy link
Copy Markdown
Member

Prep for DSPX-5229 (constant-size assertion bindings). Until now xtest only checked that assertion TDFs decrypt. It never checked what the writer actually put in the manifest, so if two SDKs agreed on a wrong binding the tests still passed. This PR adds a Python-side reference check so we can test the new binding form against something independent of the SDKs.

Two commits, reviewable separately:

  1. refactor: move assertion tests into test_tdf_assertions.py. A pure move out of test_tdfs.py. The X-Test workflow lists modules explicitly, so xtest.yml now lists the new file. Without that, the tests would silently drop out of CI.

  2. test: check assertion contents and bindings in Python. Adds assertions.assert_bound, called after encrypt in the round-trip and manifest-validity tests. It checks that:

    • each requested assertion is present and was written unchanged, and no signingKey leaked into the manifest
    • the binding is a compact JWS, its assertionHash claim equals the JCS SHA-256 of the assertion, and its assertionSig claim equals base64(aggregateHash ‖ hash). Manifests with no schemaVersion use the hex form of the hash.
    • RS256 and HS256 signatures verify against the fixture keys. An assertion with no key of its own must be HS256, since it's signed with the payload key.

    test_assertions_units.py tests the helper without services (added to check.yml).

The binding format was taken from the Go SDK (sdk/assertion.go, tdf.go), the web SDK (lib/tdf3/src/assertions.ts) and the Java and otdfctl CLIs' key handling. Once DSPX-5229 lands, assertion_sig is where the new digest form gets accepted.

Pure move: the assertion round-trip, manifest-validity, and assertion
tamper tests (and change_assertion_statement) leave test_tdfs.py
unchanged. The X-Test workflow lists test modules explicitly, so add
the new module there so the tests keep running in CI.

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
The assertion tests only checked that decrypt succeeds, so two SDKs
that agreed on a wrong binding would pass. assertions.assert_bound now
re-derives each binding from the written manifest:

- each requested assertion is present and was copied through unchanged
- no signingKey leaks into the manifest
- binding is a compact JWS whose assertionHash is the JCS hash of the
  assertion and whose assertionSig is base64(aggregateHash || hash),
  using the hex form for manifests without a schemaVersion
- RS256/HS256 signatures verify against the fixture keys; assertions
  without their own key must be HS256 (over the payload key)

test_assertions_units.py covers the helper offline and runs in check.yml.

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai

coderabbitai Bot commented Oct 19, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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