Skip to content

fix(cli): drop the encrypt-side stdin spool - #3948

Open
dmihalcik-virtru wants to merge 1 commit into
dspx-2604-base-19from
dspx-2604-19-drop-encrypt-spool
Open

fix(cli): drop the encrypt-side stdin spool#3948
dmihalcik-virtru wants to merge 1 commit into
dspx-2604-base-19from
dspx-2604-19-drop-encrypt-spool

Conversation

@dmihalcik-virtru

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

Copy link
Copy Markdown
Member

Part 19 of 20 in the DSPX-2604 re-cut. Base branch: dspx-2604-base-19.

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

DSPX-4499 fixed encrypt's OOM by streaming, but CreateTDF still required an
io.ReadSeeker, so piped stdin had to be spooled to a temporary file first. That
traded the whole-payload allocation for a disk write and a writable TMPDIR --
better, but not the point. Now that CreateTDF takes an io.Reader, the pipe goes
straight to the SDK.

A file is still opened seekably, on purpose. The SDK measures a seekable
payload and keeps the archive in the compact ZIP32 layout; an unmeasurable one
has to be ZIP64, because the choice is baked into the payload's local file
header before the first segment goes out. So encrypt file.txt is unchanged
byte for byte, and ... | encrypt produces a slightly larger TDF than it did
when it was spooled. That is the trade, and it is the right way round: nobody
should need a writable temp directory to encrypt a stream.

MIME sniffing is what made this more than a deletion. It reads the first
megabyte and previously seeked back to zero, which a pipe cannot do. Wrapping
the input in a bufio.Reader is not an option either -- that hides the Seeker
and would silently flip every file encrypt to ZIP64. detectMimeType now returns
a reader alongside the type: the same reader for a seekable input, rewound; the
sniffed prefix pushed back with io.MultiReader for anything else. A megabyte in
memory at most, and only when --mime-type was not given.

Testing: TestDetectMimeTypePreservesThePayload now runs each case twice, once
over a reader whose Seek method is hidden, and asserts the payload arrives
whole either way. TestDetectMimeTypeKeepsSeekability guards the ZIP32 layout
directly, since nothing else would fail if a file came back wrapped. e2e gains
"encrypt measures a file and streams a pipe", which reads the local file
header's extra field length to tell the two layouts apart -- both forms
round-trip, so a quiet return to spooling would show up nowhere else.

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 otdfctl && go test ./... -race

e2e, against a running platform:

cd otdfctl && bats e2e/streaming.bats

The file is tagged payload_streaming and runs in its own pass ahead of the
parallel batch — see #3939 for why that ordering is load-bearing (the platform
base key key-base.bats sets cannot be un-set, and breaks every unattributed
encrypt scheduled after it).

The case to look at is encrypt measures a file and streams a pipe, which
asserts the ZIP layout rather than the round trip: a file must stay ZIP32
(extra field length 0 at offset 28 of the payload's local file header) and a
pipe must be ZIP64 (non-zero). A quiet return to spooling would show up nowhere
else, since both forms round-trip fine.

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.

@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

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 04ecf613-53ad-450a-ae48-648e238357e4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actions github-actions Bot added the size/m label Sep 1, 2026
This was referenced 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 194.563002ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 358.100275ms
Throughput 279.25 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 39.629937716s
Average Latency 395.569546ms
Throughput 126.17 requests/second

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

X-Test Failure Report

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

X-Test Failure Report

@github-actions

github-actions Bot commented Sep 8, 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 222.968041ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 458.722073ms
Throughput 218.00 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 57.016748953s
Average Latency 568.286663ms
Throughput 87.69 requests/second

@github-actions

github-actions Bot commented Sep 8, 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 259.457169ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 431.266407ms
Throughput 231.88 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 1m2.677078068s
Average Latency 625.422189ms
Throughput 79.77 requests/second

@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-2604-19-drop-encrypt-spool branch from 9d4413f to fc84a3e Compare September 8, 2026 17:15
@github-actions

github-actions Bot commented Sep 8, 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 152.887074ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 285.568678ms
Throughput 350.18 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 41.363086923s
Average Latency 412.826111ms
Throughput 120.88 requests/second

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

X-Test Failure Report

@github-actions

github-actions Bot commented Sep 8, 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 224.925028ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 445.786299ms
Throughput 224.32 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 57.053405535s
Average Latency 569.080188ms
Throughput 87.64 requests/second

@github-actions

github-actions Bot commented Sep 8, 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 240.494897ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 434.041794ms
Throughput 230.39 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 1m2.252868154s
Average Latency 621.107119ms
Throughput 80.32 requests/second

@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-2604-19-drop-encrypt-spool branch 2 times, most recently from f460c5a to 67e4f20 Compare September 8, 2026 20:34
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

X-Test Failure Report

github-merge-queue Bot pushed a commit that referenced this pull request Sep 8, 2026
> **Part 08 of 20** in the DSPX-2604 re-cut. Base branch: `main`.
>
> 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

Adds otdfctl/pkg/streamio, holding the input and output plumbing that
the
streaming encrypt and decrypt work needs, and migrates `inspect` onto it
so
nothing is left calling the buffered helpers it supersedes.

This is groundwork with one user-visible consequence: `inspect` no
longer
reads the whole TDF into memory. Everything else is a move.

Why a new package rather than pkg/cli. The helpers in pkg/cli/pipe.go
call
ExitWithError -- which calls os.Exit -- from inside the read, so they
cannot
be used from anywhere that wants to handle the failure itself, and they
read
the entire input into memory. streamio returns errors and leaves the
decision
to exit with the command layer.

What moved in:

- PipeReader establishes whether stdin is a non-empty pipe with a
one-byte
    Peek instead of a read, so the payload still reaches the caller.
- Spool copies a pipe to a temporary file and rewinds it. A TDF's
manifest
sits at the end of the archive, so decrypt and inspect have to seek and
    cannot consume a pipe directly.
  - OpenSeekable resolves "file argument or piped stdin" to one seekable
    handle, reporting ErrNoInput for the shared "nothing to read" case.
- OutputFile writes to a temporary sibling of the destination and
renames it
into place on Commit, so a failed run leaves no partial output. The temp
file is a sibling so the rename stays atomic rather than degrading to a
    cross-filesystem copy.

Per review feedback on #3921:

- readPipedStdin now delegates its detection to streamio.PipeReader
rather
than answering "is there piped input?" a second way. Its read is still
unbounded; the callers that must stop buffering are changed separately.
- pkg/cli/pipe.go is deprecated rather than deleted, since the package
is
exported and may have callers outside this repository. Worth noting that
ReadFromFile has no size cap at all -- not even the 10 GB the tdf
commands
    apply -- which is its own argument for the notice.

InspectTDF takes an io.ReadSeeker instead of a byte slice. GetTdfType
already
rewinds to the start, so the reader is positioned for LoadTDF. Because
cli.ExitWithError calls os.Exit and skips deferred functions, inspectRun
invokes cleanup explicitly on every exit path, including the successful
one:
piped input is spooled to disk and the temp file would otherwise
survive.

### Checklist

- [x] 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 otdfctl && go test ./pkg/streamio/... ./cmd/... -race
```

`inspect` is the only command migrated in this PR; check it still reads
both a
file argument and piped stdin, and that no `otdfctl-spool-*` file
survives
either run.

<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

- **New Features**
- Added reliable support for inspecting TDF content from files, piped
input, and standard input.
- Added safer output handling that prevents incomplete files from
replacing existing results.
- Added clearer input errors when no content is provided or an input
cannot be opened.

- **Bug Fixes**
  - Improved handling of large and non-seekable input streams.
- Preserved piped input correctly while processing and inspecting
content.
- Non-fatal inspection issues are now reported as warnings where
possible, allowing processing to continue.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

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

github-actions Bot commented Sep 8, 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 264.344309ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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.628625ms
Throughput 238.31 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 1m0.120578846s
Average Latency 599.93971ms
Throughput 83.17 requests/second

@github-actions

github-actions Bot commented Sep 8, 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 246.492351ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 427.192452ms
Throughput 234.09 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 1m0.681139538s
Average Latency 605.48047ms
Throughput 82.40 requests/second

DSPX-4499 fixed encrypt's OOM by streaming, but CreateTDF still required an
io.ReadSeeker, so piped stdin had to be spooled to a temporary file first. That
traded the whole-payload allocation for a disk write and a writable TMPDIR --
better, but not the point. Now that CreateTDF takes an io.Reader, the pipe goes
straight to the SDK.

A file is still opened seekably, on purpose. The SDK measures a seekable
payload and keeps the archive in the compact ZIP32 layout; an unmeasurable one
has to be ZIP64, because the choice is baked into the payload's local file
header before the first segment goes out. So `encrypt file.txt` is unchanged
byte for byte, and `... | encrypt` produces a slightly larger TDF than it did
when it was spooled. That is the trade, and it is the right way round: nobody
should need a writable temp directory to encrypt a stream.

MIME sniffing is what made this more than a deletion. It reads the first
megabyte and previously seeked back to zero, which a pipe cannot do. Wrapping
the input in a bufio.Reader is not an option either -- that hides the Seeker
and would silently flip every file encrypt to ZIP64. detectMimeType now returns
a reader alongside the type: the same reader for a seekable input, rewound; the
sniffed prefix pushed back with io.MultiReader for anything else. A megabyte in
memory at most, and only when --mime-type was not given.

Testing: TestDetectMimeTypePreservesThePayload now runs each case twice, once
over a reader whose Seek method is hidden, and asserts the payload arrives
whole either way. TestDetectMimeTypeKeepsSeekability guards the ZIP32 layout
directly, since nothing else would fail if a file came back wrapped. e2e gains
"encrypt measures a file and streams a pipe", which reads the local file
header's extra field length to tell the two layouts apart -- both forms
round-trip, so a quiet return to spooling would show up nowhere else.

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

github-actions Bot commented Sep 8, 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 244.474111ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 420.508432ms
Throughput 237.81 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 1m0.574885074s
Average Latency 604.447434ms
Throughput 82.54 requests/second

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

  • otdfctl
  • service
  • tests-bdd

See the workflow run for details.

@github-actions

github-actions Bot commented Sep 8, 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 231.411257ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 412.876261ms
Throughput 242.20 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 59.188533843s
Average Latency 590.289207ms
Throughput 84.48 requests/second

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant