Skip to content

feat(xtest): decrypt TDFs whose ZIP entries are deflate-compressed - #671

Open
pflynn-virtru wants to merge 2 commits into
mainfrom
feat/xtest-deflate-entries
Open

pflynn-virtru wants to merge 2 commits into
mainfrom
feat/xtest-deflate-entries

Conversation

@pflynn-virtru

@pflynn-virtru pflynn-virtru commented Oct 21, 2026 •

Copy link
Copy Markdown
Member

What this adds

A cross-SDK check that every SDK can decrypt a TDF whose ZIP entries are DEFLATE-compressed (method 8). All OpenTDF writers emit STORED entries, so until now no xtest TDF has gone through a reader's inflate path. A TDF written by another implementation may compress its manifest and payload.

test_tdf_roundtrip_deflated_entries (in xtest/test_tdfs.py, next to the roundtrip tests) runs over encrypt_sdk × decrypt_sdk × pt_file size, the same matrix as test_tdf_roundtrip. For each cell it:

  1. encrypts with encrypt_sdk (ztdf);
  2. rewrites the TDF with every entry DEFLATE-compressed, keeping the same names, order and bytes. It then asserts every entry in the new archive really is ZIP_DEFLATED, so the test can't pass on STORED data;
  3. decrypts the deflated TDF with decrypt_sdk, checks the plaintext matches the original, and checks the KAS rewrap audit event, as the neighbouring roundtrip tests do.

tdfs.deflate_entries(scenario_name, tdf_file) does the rewrite. Its output is named like update_manifest / update_payload name theirs, so it lands in the same tmp_dir / XT_TMP_DIR. It copies entry by entry from infolist() rather than extracting and re-walking a directory, because os.walk order is not archive order. Entries are streamed, so a multi-GiB payload is never held in memory.

The zip-deflate gate

zip-deflate is a new reader-side feature in feature_type. It is not platform-only, so XT_FORCE_SUPPORTS accepts it. Every SDK's supports answer is no for now, so the cells skip with <sdk> sdk doesn't yet support [zip-deflate]. Each supports case should become a version gate once a release carries its SDK's PR:

SDK supports case Reader support
go (otdfctl) xtest/sdk/go/cli.sh opentdf/platform#4247
java xtest/sdk/java/cli.sh opentdf/java-sdk#424
js xtest/sdk/js/cli.sh opentdf/web-sdk#1099

Encrypt needs no new feature.

Running it against the PR builds

Install the branch builds and force the feature:

otdf-sdk-mgr install tip --ref pr:424 java   # likewise for the other SDKs
XT_FORCE_SUPPORTS=zip-deflate uv run pytest test_tdfs.py -k deflated_entries --sdks "go java js" -v

In CI, dispatch X-Test with force-supports: zip-deflate and point platform-ref / otdfctl-ref / java-ref / js-ref at feat/zip-inbound-deflate. versions resolve takes branch names, not pr:N. Without the override, the pull_request run skips these cells.

Testing

From xtest/:

  • uv run ruff check .: All checks passed!
  • uv run ruff format .: 56 files left unchanged
  • uv run pyright: 0 errors, 0 warnings, 0 informations
  • uv run pytest test_tdfs_units.py test_zip64_units.py -q: 81 passed (7 new: names/order/bytes preserved for 0.manifest.json and manifest.json; DEFLATE in both the central directory and the local headers; the manifest actually shrinks; round-trips through zipfile with CRCs intact; written beside the source; zip-deflate is forceable from XT_FORCE_SUPPORTS). A temporary mutation that wrote STORED entries made 2 of them fail.
  • The CI offline-harness list (test_bench_*, test_sdk_commands.py, test_tdfs_units.py, test_encryption_units.py, test_sizes_units.py, test_zip64_units.py): 351 passed
  • shellcheck and shfmt -d on the three cli.sh files: clean
  • cli.sh supports zip-deflate exits 1 for go, java and js, run through throwaway dist copies. SDK.skip_if_unsupported("zip-deflate") skips for all three, and XT_FORCE_SUPPORTS=zip-deflate makes supports() return true for all three.

Not run: the integration test itself. It needs the platform stack and SDK builds, which I don't have locally. With no SDK dists it collects one cell, which skips with got empty parameter set. Against fake dists it collects all 9 encrypt × decrypt cells, but fixture setup needs the platform before the skip can run.

Cross-SDK verification

xtest run opentdf/tests actions/runs/39625561654 (2026-10-21) built the platform and otdfctl from opentdf/platform feat/zip-inbound-deflate (553e9623), java-sdk feat/zip-inbound-deflate (b02a4121) and web-sdk feat/zip-inbound-deflate (94e09e4d), and ran test_tdf_roundtrip_deflated_entries from this PR with force-supports=zip-deflate. The test encrypts with one SDK, rewrites every ZIP entry with DEFLATE, checks the entries are compressed, and decrypts with another SDK.

All 9 cells ran (none skipped) and passed:

encrypt ↓ / decrypt → go java js
go ✅ ✅ ✅
java ✅ ✅ ✅
js ✅ ✅ ✅

These are the cells this PR adds. On this PR's own CI, which builds released SDKs and main, they skip for released SDKs and fail for main builds until the three reader PRs merge: opentdf/platform#4247, opentdf/java-sdk#424 and opentdf/web-sdk#1099.

For comparison, the same test fails wherever an SDK built from main decrypts (this PR's CI):

  • go: json.Unmarshal failed: invalid character 'u' looking for beginning of value
  • java: InvalidZipException: Archive ended 1110 bytes into the 1438 byte entry [0.manifest.json]
  • js: InvalidFileError: entry [0.payload] uses unsupported compression method [8]

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added explicit support detection for DEFLATE-compressed ZIP entries across the Go, Java, and JavaScript SDK compatibility checks.
    • Compatibility checks now clearly report when zip-deflate is unavailable and provide guidance to use a release with support.
  • Tests

    • Added coverage for converting TDF archives to DEFLATE compression while preserving contents, metadata, and archive structure.
    • Added end-to-end validation for decrypting and rewrapping DEFLATE-compressed TDF archives when supported.

Add test_tdf_roundtrip_deflated_entries. It encrypts with each SDK,
rewrites the TDF with every ZIP entry DEFLATE-compressed (same names,
order and bytes), and requires each decrypting SDK to recover the
original plaintext. It asserts the rewritten archive really is deflated,
so it cannot pass on STORED data.

Gate the reader side behind a new zip-deflate feature. Every SDK shim
answers no until a release carries opentdf/platform#4247 (go),
opentdf/java-sdk#424 (java) or opentdf/web-sdk#1099 (js). Set
XT_FORCE_SUPPORTS=zip-deflate, or the force-supports workflow input, to
run it against builds of those branches.

tdfs.deflate_entries does the rewrite, streaming each entry so a large
payload is never held in memory; offline unit tests cover it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Paul Flynn <pflynn-virtru@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 22 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 43907c36-c127-4b67-8bfe-77570d449713
📥 Commits

Reviewing files that changed from the base of the PR and between de5c3c1 and 0c89362.

📒 Files selected for processing: 2
  • xtest/tdfs.py
  • xtest/test_tdfs_units.py

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c7b13066-85f1-4859-8f93-befa5ef78b89
📥 Commits

Reviewing files that changed from the base of the PR and between 966c443 and de5c3c1.

📒 Files selected for processing: 6
  • xtest/sdk/go/cli.sh
  • xtest/sdk/java/cli.sh
  • xtest/sdk/js/cli.sh
  • xtest/tdfs.py
  • xtest/test_tdfs.py
  • xtest/test_tdfs_units.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

The changes add a ZIP DEFLATE capability probe for three SDKs, a helper that rewrites TDF ZIP entries using DEFLATE, and unit and integration tests for archive integrity and SDK decryption.

Changes: ZIP DEFLATE support and validation

Layer / File(s) Summary
Declare ZIP DEFLATE capability
xtest/tdfs.py, xtest/sdk/go/cli.sh, xtest/sdk/java/cli.sh, xtest/sdk/js/cli.sh
The feature declaration describes reader-side DEFLATE support. The three SDK probes report the feature as unsupported and exit with status 1.
Rewrite entries and verify archive integrity
xtest/tdfs.py, xtest/test_tdfs_units.py
deflate_entries rewrites archive entries with DEFLATE. Unit tests check compression headers, preserved contents and ordering, manifest compression, output naming, and source immutability.
Validate SDK decryption
xtest/test_tdfs.py
The integration test checks decryption and rewrap auditing for a TDF whose entries use DEFLATE.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Other

Suggested reviewers: dmihalcik-virtru

Merge Risk: ⚪ Minimal · up to de5c3

No merge-blocking issue was identified. The cross-SDK integration test still needs a compatible platform stack and SDK builds for validation.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 6 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: adding xtest coverage for decrypting TDFs with DEFLATE-compressed ZIP entries.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • 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

A rabbit zipped files with a soft little thump,
Then checked every entry from tail to its rump.
The headers said “DEFLATE,” the contents stayed clear,
The tests made the archive’s good order appear.
The payload came back, and the audit drew near.

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

@pflynn-virtru
pflynn-virtru marked this pull request as ready for review October 21, 2026 14:22
@pflynn-virtru
pflynn-virtru requested review from a team as code owners October 21, 2026 14:22
The zip-deflate gate skipped every cell, so CI never decrypted a
deflated TDF with a real SDK. Answer yes for builds of main without
asking the shim, so CI runs the cells against main and they fail until
each SDK's reader PR merges. Released builds still defer to their shim
and skip.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Paul Flynn <pflynn-virtru@users.noreply.github.com>
@sonarqubecloud

Copy link
Copy Markdown

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