Skip to content

fix(sdk): stop GetManifest from splitting the key under the lock - #3941

Merged
dmihalcik-virtru merged 1 commit into
mainfrom
dspx-2604-12-getmanifest-lock
Sep 21, 2026
Merged

dmihalcik-virtru merged 1 commit into
mainfrom
dspx-2604-12-getmanifest-lock

Conversation

@dmihalcik-virtru

@dmihalcik-virtru dmihalcik-virtru commented Sep 1, 2026 •

Copy link
Copy Markdown
Member

Part 12 of 20 in the DSPX-2604 re-cut. Base branch: dspx-2604-11-chunked-writer.

This stack replaces #3782 / #3865 / #3921, which stay open and untouched
until it lands. Nothing here is a rebase of those branches — the work was
re-cut from the ticket so each PR stands on its own.

Proposed Changes

chunkedWriter.GetManifest held mu.RLock for its whole body, and that
body calls KeySplitter.Split. A real splitter resolves KAS public keys
over the network, so every WriteSegment racing a GetManifest sat on the
write lock until those round-trips finished. sync.RWMutex bars new
readers once a writer is queued, so a second GetManifest behind that
WriteSegment blocked as well -- one manifest snapshot could stall the
whole writer.

Splits the manifest build in two. snapshotLocked resolves the emission
order and copies each segment's metadata; buildManifest then works from
that snapshot and touches no mutable writer state, so it needs no lock --
the dek, the splitter, the integrity algorithms and the signature encoding
are all fixed at construction. GetManifest now releases the read lock as
soon as the snapshot is taken.

The snapshot copies Segment values rather than the *Segment pointers
w.segments holds. WriteSegment mutates those in place when the archive
accepts a write, so ranging over the pointers after releasing the lock
would be a data race, not merely a stale read.

Finalize deliberately keeps the write lock across the split. It is
terminal -- no WriteSegment may succeed after it returns -- so there is
no concurrency to preserve, and dropping the lock would open a window for a
segment to reach the archive after the snapshot that fixes the manifest.

This makes explicit a semantic that was already true: GetManifest returns
a point-in-time view. A segment committed after the snapshot is absent from
that manifest and present in the next one. The new test pins both halves,
along with the property that motivated the change -- a WriteSegment
issued while a split is in flight completes rather than blocking. It
deadlocks to a 10s timeout against the previous locking and passes against
this one.

Checklist

  • I have added or updated unit tests
  • I have added or updated integration tests (if appropriate)
  • I have added or updated documentation

Testing Instructions

cd sdk && go test ./... -race

The new test deadlocks to its 10s timeout against the previous locking and
passes against this one.

The full DSPX-2604 stack — 20 PRs
# PR Based on
01 #3930 chore: bump go.work toolchain to go1.25.12 and simplify an rt_test condition main
02 #3931 feat(sdk): make the zipstream clock injectable for deterministic ZIP output main
03 #3932 fix(sdk): reject a zipstream write set that omits segment 0 #3931
04 #3933 fix(sdk): map ReadAt plaintext offsets from cumulative segment sizes main
05 #3934 chore(sdk): extract integrityAlgorithmString, createPolicyBinding, signAssertions main
06 #3935 chore(sdk): add direct tests for createKeyAccess, encryptMetadata and tdfSalt main
07 #3936 fix(sdk): fill each segment with io.ReadFull and size the buffer to the input main
08 #3937 chore(cli): move streaming IO helpers into pkg main
09 #3938 fix(cli): stream encrypt instead of buffering the whole payload #3937
10 #3939 fix(cli): stream decrypt and inspect instead of buffering #3938
11 #3940 feat(sdk): add a chunked segment writer (experimental) dspx-2604-base-11 = #3932 + #3934 + #3935
12 #3941 fix(sdk): stop GetManifest from splitting the key under the lock #3940
13 #3942 fix(sdk): reject a chunked split naming a KAS with no resolved public key #3941
14 #3943 chore(sdk): alias experimental/tdf manifest and assertion types #3942
15 #3944 fix(sdk): emit spec-compliant key access in experimental/tdf and delegate Writer #3943
16 #3945 feat(sdk): accept io.Reader in CreateTDF and drop the 64 GB payload cap #3936
17 #3946 chore(sdk): rewrite CreateTDF on top of the chunked writer dspx-2604-base-17 = #3944 + #3945
18 #3947 chore(sdk): drop dead TDFConfig fields and deprecate the TDFFormat enum #3946
19 #3948 fix(cli): drop the encrypt-side stdin spool dspx-2604-base-19 = #3947 + #3939
20 #3949 feat(sdk): graduate the chunked writer to stable API #3948

Reviewable in parallel right now, since they sit directly on main and depend on
nothing else: 01, 02, 04, 05, 06, 07, 08.

Why three PRs have a dspx-2604-base-* base. A GitHub PR takes one base branch,
but 11, 17 and 19 each build on more than one parent. The base-* branches are empty
merge commits that exist only to join those parents so the PR diff shows exactly its
own change and nothing else. They contain no code, have no PR of their own, and go
away once their parents land — retarget the child onto main at that point.

Wants a cross-SDK xtest run before merge: 15, 17 (and therefore 20). They touch
the KAS wire format.

Red checks you may see are network flakes, not this stack. Four distinct ones hit
this batch and all clear on re-run: golangci-lint config verify timing out on
https://golangci-lint.run/.../golangci.v2.8.jsonschema.json (fails the whole go (<module>) job and fail-fast cancels its siblings), the bats installer getting a 403,
Docker Hub timing out on keycloak/keycloak:26.4, and buf reporting "the server
hosted at that remote is unavailable" while the Java SDK generates sources. The
govulncheck step also emits ##[error] annotations against the go1.25.11 stdlib, but
it is continue-on-error: true and never fails a job — 01 bumps the toolchain and
clears those annotations.

Summary by CodeRabbit

  • New Features

    • Added experimental support for creating encrypted data in concurrent, out-of-order segments.
    • Added manifest previews, finalization controls, configurable metadata, MIME types, attributes, assertions, target modes, and key-splitting options.
    • Added validation and reconstruction checks for split encryption keys.
    • Added clearer errors for invalid segment operations and failed finalization.
  • Bug Fixes

    • Improved chunked writing responsiveness by preventing manifest generation from blocking concurrent segment writes.
    • Ensured manifests consistently reflect the segment state captured when generation begins.
    • Improved retry behavior after non-mutating finalization failures.

@dmihalcik-virtru
dmihalcik-virtru requested review from a team as code owners September 1, 2026 02:57
@coderabbitai

coderabbitai Bot commented Sep 1, 2026 •

Copy link
Copy Markdown

Review Change StackReview Change Stack

Warning

Review limit reached

Next included review available in 59 minutes.

Check out review usage here.

View limit details

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

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

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: f35e1277-ada8-419f-86dd-ecce7ca96d9c

📥 Commits

Reviewing files that changed from the base of the PR and between c08ed03 and c068a0c.

📒 Files selected for processing (3)
  • sdk/chunked_test.go
  • sdk/chunked_writer.go
  • sdk/key_splitter.go

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: f0fcd6ee-0b94-482e-9605-0a610b3ebb4f

📥 Commits

Reviewing files that changed from the base of the PR and between bd9f54e and c08ed03.

📒 Files selected for processing (8)
  • sdk/chunked_options.go
  • sdk/chunked_test.go
  • sdk/chunked_writer.go
  • sdk/internal/zipstream/segment_writer.go
  • sdk/internal/zipstream/segment_writer_test.go
  • sdk/internal/zipstream/writer.go
  • sdk/key_splitter.go
  • sdk/key_splitter_test.go

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


📝 Walkthrough

Walkthrough

The SDK adds a concurrent chunked TDF writer with configurable manifest construction, key splitting, archive recovery, and manifest snapshots. The change also adds archive mutation tracking and broad unit and integration coverage.

Changes

Chunked TDF writer

Layer / File(s) Summary
Key splitting and writer options
sdk/key_splitter.go, sdk/key_splitter_test.go, sdk/chunked_options.go
Adds XOR key-splitting contracts, KAS metadata validation, the default splitter, and chunked writer options.
Chunked writing and manifest finalization
sdk/chunked_writer.go, sdk/chunked_test.go
Adds concurrent segment writes, snapshot-based manifest construction, finalization, key access objects, assertions, target modes, MIME types, retained segments, and round-trip coverage.
Failure recovery and concurrent access
sdk/chunked_writer.go, sdk/chunked_test.go
Adds reservation cleanup, archive rollback, terminal fencing, retry handling, concurrent writes, and tests showing manifest splitting does not block WriteSegment.
Archive mutation tracking
sdk/internal/zipstream/writer.go, sdk/internal/zipstream/segment_writer.go, sdk/internal/zipstream/segment_writer_test.go
Adds the Error.Mutated flag and classifies archive failures as retryable or state-mutating.

Priority: ⬇️ Low

Estimated code review effort: 5 (Critical) | ~90 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant ChunkedWriter
  participant ArchiveWriter
  participant KeySplitter
  Caller->>ChunkedWriter: WriteSegment
  ChunkedWriter->>ArchiveWriter: encrypt and archive segment
  Caller->>ChunkedWriter: GetManifest or Finalize
  ChunkedWriter->>KeySplitter: split DEK from snapshot
  KeySplitter-->>ChunkedWriter: return shares
  ChunkedWriter->>ArchiveWriter: finalize archive
  ChunkedWriter-->>Caller: manifest and TDF data
Loading

Suggested reviewers: elizabethhealy

Merge Risk: ⚪ Minimal · up to c08ed

No actionable merge-blocking risk remains after the documented concurrency and recovery coverage.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: GetManifest no longer performs key splitting while holding the lock.
Docstring Coverage ✅ Passed Docstring coverage is 96.77% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 93 functions across 8 files.
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
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch dspx-2604-12-getmanifest-lock
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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

I am a rabbit with segments to share
I split every secret with careful repair
The manifest hops free while writers proceed
Failed trails are cleaned when retries are needed
Archives mark changes, both gentle and dire
Chunked TDFs bloom from the burrow’s bright wire

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

@github-actions github-actions Bot added comp:sdk A software development kit, including library, for client applications and inter-service communicati size/s labels Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 192.120501ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 102.223492ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 356.125965ms
Throughput 280.80 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 36.845874452s
Average Latency 367.93731ms
Throughput 135.70 requests/second

@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-2604-12-getmanifest-lock branch from 912b24c to e7d3d2d Compare September 1, 2026 03:36
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 229.029738ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 118.452978ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 448.441681ms
Throughput 222.99 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 40.97330209s
Average Latency 409.124271ms
Throughput 122.03 requests/second

@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-2604-12-getmanifest-lock branch from e7d3d2d to 41aaa77 Compare September 1, 2026 15:08
@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-2604-12-getmanifest-lock branch from 9288bef to 7fffc53 Compare September 15, 2026 23:57
@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-2604-11-chunked-writer branch from 4664236 to 78f2ee4 Compare September 15, 2026 23:57
@github-actions

Copy link
Copy Markdown
Contributor

X-Test Failure Report

@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 176.470035ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 95.183733ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 346.476667ms
Throughput 288.62 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 44.392433211s
Average Latency 442.899359ms
Throughput 112.63 requests/second

@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 254.218744ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 146.016331ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 450.225727ms
Throughput 222.11 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 1m4.128727138s
Average Latency 640.070602ms
Throughput 77.97 requests/second

@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-2604-11-chunked-writer branch from 78f2ee4 to 546457a Compare September 16, 2026 00:13
@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-2604-12-getmanifest-lock branch from 7fffc53 to 5a27c0e Compare September 16, 2026 00:14
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 234.071606ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 133.171602ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 419.277864ms
Throughput 238.51 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 59.61892394s
Average Latency 594.903695ms
Throughput 83.87 requests/second

@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-2604-11-chunked-writer branch from 546457a to 74243e8 Compare September 16, 2026 14:50
@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-2604-12-getmanifest-lock branch from 5a27c0e to c08ed03 Compare September 16, 2026 15:05
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 247.40021ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 137.513973ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 424.56193ms
Throughput 235.54 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 1m0.625131691s
Average Latency 605.067072ms
Throughput 82.47 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

  • otdfctl
  • service
  • tests-bdd

See the workflow run for details.

Base automatically changed from dspx-2604-11-chunked-writer to main September 17, 2026 13:29
GetManifest held the writer's read lock across KeySplitter.Split. A
real splitter resolves KAS keys over the network, and RWMutex bars new
readers once a writer is queued, so a single GetManifest stalled every
concurrent WriteSegment commit -- and every other GetManifest -- for
the duration of that I/O. That defeats the point of a writer built to
let segments be encrypted in parallel.

Split the manifest build in two. snapshotLocked resolves the emission
order and copies each segment's metadata (values, not the *segmentSlot
pointers WriteSegment mutates in place) out from under the lock,
together with the archive-wide byte totals that read slots outside the
emission order. buildManifest then runs entirely unlocked: everything
else it touches -- dek, splitter, useHex -- is fixed at construction.

GetManifest therefore describes the writer as of the snapshot rather
than as of the return; a segment that lands mid-split is absent from
that call and present in the next. Its interface doc now says so.
Finalize keeps the lock throughout: it is terminal, and
ErrChunkedWriteInFlight has already established that no write is
outstanding, so there is no concurrency left to preserve and dropping
the lock would only reopen the snapshot/archive race.

Adds TestChunkedGetManifestDoesNotBlockWriteSegment, which blocks a
splitter mid-Split and asserts a concurrent WriteSegment still
completes. It deadlocks on the old shape.

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-2604-12-getmanifest-lock branch from c08ed03 to c068a0c Compare September 17, 2026 16:47
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 177.091049ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 100.40523ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 354.796397ms
Throughput 281.85 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 47.881871217s
Average Latency 477.482559ms
Throughput 104.42 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

  • otdfctl
  • service
  • tests-bdd

See the workflow run for details.

@dmihalcik-virtru
dmihalcik-virtru added this pull request to the merge queue Sep 21, 2026
Merged via the queue into main with commit cf1b083 Sep 21, 2026
47 checks passed
@dmihalcik-virtru
dmihalcik-virtru deleted the dspx-2604-12-getmanifest-lock branch September 21, 2026 21:21
github-merge-queue Bot pushed a commit that referenced this pull request Sep 22, 2026
> **Part 14 of 20** in the DSPX-2604 re-cut. Base branch:
`dspx-2604-13-unresolved-kas`.
>
> This stack replaces #3782 / #3865 / #3921, which stay open and
untouched
> until it lands. Nothing here is a rebase of those branches — the work
was
> re-cut from the ticket so each PR stands on its own.

### Proposed Changes

`sdk/experimental/tdf` carried its own copies of the manifest and
assertion
types -- `Manifest`, `Segment`, `KeyAccess`, `Assertion`, `Statement`,
`AssertionKey` and the rest -- structurally identical to the ones in
`sdk`
but distinct to the type system, so anything crossing the boundary
needed
conversion. Two copies of the JWT signing and verification logic also
had
to be kept in step by hand.

Replaces both files' definitions with type aliases. `sdk` owns the
definitions; this package re-exports them. Every exported name and every
method survives: `Assertion.Sign` / `Verify` / `GetHash`,
`Statement.UnmarshalJSON`, `AssertionKey.IsEmpty` / `Algorithm`,
`AssertionVerificationKeys.Get` / `IsEmpty` and the five `String()`
methods
all come along with the aliased types, so importers compile unchanged. A
manifest produced here can now be handed to the stable SDK without
conversion, which is what the follow-up delegation needs.

Two deliberate non-aliases:

`Policy`, `PolicyBody` and `PolicyAttribute` stay local.
`sdk.PolicyObject`
declares `Body` as an anonymous struct over an unexported element type,
so
there is no nameable sdk equivalent to alias to. Exporting those in
`sdk`
first would make the alias possible; that is a separate change.

`IntegrityAlgorithm` stays a distinct `int` type.
`sdk.IntegrityAlgorithm`
is itself `= int`, so no method can be attached to it, and aliasing
would
silently drop `String()` from this package's public API. The underlying
values match, so the two convert freely.

`kSplitKeyType`, `kPolicyBindingAlg`, `kGMACPayloadLength` and
`calculateSignature` are retained verbatim: this package still builds
its
own manifests and they have callers in `writer.go` and `key_access.go`.
The change that removes those callers removes these too.

No behavior change. The package's existing tests pass unmodified.

### Checklist

- [ ] I have added or updated unit tests
- [ ] I have added or updated integration tests (if appropriate)
- [ ] I have added or updated documentation

### Testing Instructions

```
cd sdk && go test ./experimental/... -race
```

No behavior change — the point is that the package's existing tests pass
unmodified against aliased types.

<details>
<summary><b>The full DSPX-2604 stack — 20 PRs</b></summary>

| # | PR | Based on |
|---|----|----------|
| 01 | #3930 chore: bump go.work toolchain to go1.25.12 and simplify an
rt_test condition | `main` |
| 02 | #3931 feat(sdk): make the zipstream clock injectable for
deterministic ZIP output | `main` |
| 03 | #3932 fix(sdk): reject a zipstream write set that omits segment 0
| #3931 |
| 04 | #3933 fix(sdk): map ReadAt plaintext offsets from cumulative
segment sizes | `main` |
| 05 | #3934 chore(sdk): extract integrityAlgorithmString,
createPolicyBinding, signAssertions | `main` |
| 06 | #3935 chore(sdk): add direct tests for createKeyAccess,
encryptMetadata and tdfSalt | `main` |
| 07 | #3936 fix(sdk): fill each segment with io.ReadFull and size the
buffer to the input | `main` |
| 08 | #3937 chore(cli): move streaming IO helpers into pkg | `main` |
| 09 | #3938 fix(cli): stream encrypt instead of buffering the whole
payload | #3937 |
| 10 | #3939 fix(cli): stream decrypt and inspect instead of buffering |
#3938 |
| 11 | #3940 feat(sdk): add a chunked segment writer (experimental) |
`dspx-2604-base-11` = #3932 + #3934 + #3935 |
| 12 | #3941 fix(sdk): stop GetManifest from splitting the key under the
lock | #3940 |
| 13 | #3942 fix(sdk): reject a chunked split naming a KAS with no
resolved public key | #3941 |
| 14 | #3943 chore(sdk): alias experimental/tdf manifest and assertion
types | #3942 |
| 15 | #3944 fix(sdk): emit spec-compliant key access in
experimental/tdf and delegate Writer | #3943 |
| 16 | #3945 feat(sdk): accept io.Reader in CreateTDF and drop the 64 GB
payload cap | #3936 |
| 17 | #3946 chore(sdk): rewrite CreateTDF on top of the chunked writer
| `dspx-2604-base-17` = #3944 + #3945 |
| 18 | #3947 chore(sdk): drop dead TDFConfig fields and deprecate the
TDFFormat enum | #3946 |
| 19 | #3948 fix(cli): drop the encrypt-side stdin spool |
`dspx-2604-base-19` = #3947 + #3939 |
| 20 | #3949 feat(sdk): graduate the chunked writer to stable API |
#3948 |

**Reviewable in parallel right now**, since they sit directly on `main`
and depend on
nothing else: 01, 02, 04, 05, 06, 07, 08.

**Why three PRs have a `dspx-2604-base-*` base.** A GitHub PR takes one
base branch,
but 11, 17 and 19 each build on more than one parent. The `base-*`
branches are empty
merge commits that exist only to join those parents so the PR diff shows
exactly its
own change and nothing else. They contain no code, have no PR of their
own, and go
away once their parents land — retarget the child onto `main` at that
point.

**Wants a cross-SDK xtest run before merge:** 15, 17 (and therefore 20).
They touch
the KAS wire format.

**Red checks you may see are network flakes, not this stack.** Four
distinct ones hit
this batch and all clear on re-run: `golangci-lint config verify` timing
out on
`https://golangci-lint.run/.../golangci.v2.8.jsonschema.json` (fails the
whole `go
(<module>)` job and fail-fast cancels its siblings), the bats installer
getting a 403,
Docker Hub timing out on `keycloak/keycloak:26.4`, and `buf` reporting
"the server
hosted at that remote is unavailable" while the Java SDK generates
sources. The
`govulncheck` step also emits `##[error]` annotations against the
go1.25.11 stdlib, but
it is `continue-on-error: true` and never fails a job — 01 bumps the
toolchain and
clears those annotations.

</details>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Compatibility**
* Experimental TDF manifest and assertion types now align with the
stable SDK, enabling direct interoperability without type conversion.
* Existing assertion and manifest behavior is provided through the
stable SDK definitions.

* **Documentation**
* Clarified the relationship between the experimental TDF package and
the stable SDK.
* Updated documentation for missing assertion verification keys to
reflect current behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:sdk A software development kit, including library, for client applications and inter-service communicati size/s

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants