Skip to content

chore(xtest): DPoP nonce-challenge test coverage and CLI/CI hardening#529

Draft
dmihalcik-virtru wants to merge 16 commits into
mainfrom
fix-dpop-nonce-challenge
Draft

chore(xtest): DPoP nonce-challenge test coverage and CLI/CI hardening#529
dmihalcik-virtru wants to merge 16 commits into
mainfrom
fix-dpop-nonce-challenge

Conversation

@dmihalcik-virtru

@dmihalcik-virtru dmihalcik-virtru commented Jun 18, 2026

Copy link
Copy Markdown
Member

What

Wires up end-to-end DPoP (Demonstrating Proof-of-Possession) coverage in the
cross-client test suite, including the dpop_nonce_challenge capability, and
hardens the surrounding CLI shims and CI diagnostics.

Why

DPoP-bound clients were not actually exercised end-to-end: the shims read
CLIENTID but never enabled DPoP proof generation, so the tests passed
without verifying the bound flow. This branch makes the DPoP client provision
and emit proofs, validates the nonce-challenge path, and fixes the platform
action pins that carry the DPoP htu/htm validation fixes.

Changes

Tests

  • test_dpop.py: the autouse _dpop_client_env fixture now also sets
    XT_WITH_DPOP=ES256, so the DPoP-bound opentdf-dpop client actually
    generates proofs during encrypt/decrypt.

SDK CLI shims

  • sdk/js/cli.sh: wire CLIENTID, CLIENTSECRET, and DPoP into the shim.
  • sdk/java/cli.sh: delegate dpop_nonce_challenge detection to the binary;
    enable --verbose when available (checked on the root help, where it is
    ScopeType.INHERIT); cache the help capability probes by jar mtime to cut
    per-operation JVM startup overhead and keep JVM warnings out of logs.
  • tdfs.py: surface the dpop_nonce_challenge capability and log subprocess
    stdout/stderr on encrypt/decrypt failure for xdist visibility.

CI

  • xtest.yml: bump platform action SHA pins to pick up the DPoP htu/htm
    strict-validation fixes; enable dpop-nonce-challenge; pass OTDFCTL_HEADS
    to all pytest steps; upload platform and KAS server logs as artifacts on
    failure.

Test plan

  • uv run pytest test_dpop.py --sdks "go java js" -v against a platform built
    from the pinned action SHA (DPoP enabled).

Summary by CodeRabbit

  • New Features

    • Enhanced DPoP (Demonstration of Proof-of-Possession) support across test infrastructure with configurable authentication options.
  • Improvements

    • Better error diagnostics with enhanced logging for SDK operations.
    • Performance optimization through CLI help output caching.
    • Automatic server log capture on test failures for troubleshooting.

@dmihalcik-virtru dmihalcik-virtru requested review from a team as code owners June 18, 2026 15:58
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3c93592b-ddab-416a-8c72-9de34134a688

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
📝 Walkthrough

Walkthrough

Enables DPoP nonce-challenge support across the xtest infrastructure: the CI workflow activates dpop-challenge-enabled, updates action revisions, threads OTDFCTL_HEADS into all test environments, and adds a failure log upload. The JS SDK CLI gains DPoP argument passthrough and credential override handling. The Java SDK CLI adds a jar_help() cache and a --verbose probe. SDK.encrypt/SDK.decrypt switch to captured subprocess execution with error logging. The DPoP test fixture sets XT_WITH_DPOP=ES256.

Changes

DPoP Nonce-Challenge Test Infrastructure

Layer / File(s) Summary
DPoP test fixture and subprocess error logging
xtest/test_dpop.py, xtest/tdfs.py
_dpop_client_env autouse fixture now sets XT_WITH_DPOP=ES256 alongside CLIENTID. SDK.encrypt and SDK.decrypt switch to subprocess.run with capture_output=True, logging decoded stdout/stderr on failure and raising CalledProcessError with captured streams.
JS SDK CLI: DPoP and credential override support
xtest/sdk/js/cli.sh
Snapshots and restores caller-set CLIENTID/CLIENTSECRET across test.env sourcing. Replaces hardcoded opentdf:secret with ${CLIENTID:-opentdf}:${CLIENTSECRET:-secret}. Conditionally appends --dpop and --dpop-key when XT_WITH_DPOP/XT_WITH_DPOP_KEY are set. Docs list the new env vars.
Java SDK CLI: jar_help caching and --verbose probe
xtest/sdk/java/cli.sh
Adds jar_help() that caches cmdline.jar help output keyed by jar mtime and arguments. Updates dpop_nonce_challenge and KAS allowlist capability probes to use the cache. Conditionally appends --verbose when the jar reports it as a supported flag.
CI: DPoP enablement, OTDFCTL_HEADS threading, and log upload
.github/workflows/xtest.yml
Platform startup gains dpop-challenge-enabled: true and updated action revisions. All multikas start-additional-kas actions are bumped. OTDFCTL_HEADS is threaded into helper-library, legacy, standard, focused, and attribute-config test environments. A new failure-only step uploads platform and KAS log files as a CI artifact.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • opentdf/tests#505: Modifies xtest/test_dpop.py DPoP client/proof enablement and xtest/sdk/java/cli.sh dpop_nonce_challenge feature detection, the same files and flows extended in this PR.

Suggested reviewers

  • pflynn-virtru

Poem

🐇 Hop, hop, through the DPoP gate,
The nonce is challenged — isn't that great?
jar_help caches so the JVM won't spin,
XT_WITH_DPOP lets the proofs begin.
Logs upload on failure, never to hide —
This rabbit ships with confidence and pride! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title directly and specifically addresses the main objectives: DPoP test coverage enablement and CLI/CI hardening across xtest files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-dpop-nonce-challenge

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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces caching for the Java CLI help output to avoid JVM startup overhead, adds support for DPoP-related environment variables and client overrides in the JS CLI shim, improves subprocess error logging in Python tests, and updates DPoP test fixtures. Feedback highlights a potential race condition in the Java CLI caching mechanism under parallel test execution, where concurrent processes could read an incomplete cache file, and suggests using an atomic write-and-rename pattern to resolve it.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread xtest/sdk/java/cli.sh Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@xtest/sdk/java/cli.sh`:
- Around line 58-61: The cache file is being written to directly after checking
existence, creating a race condition where concurrent invocations can read a
partially written cache file. Instead of writing directly to the final cache
file location in the line that runs the java command, write to a temporary file
first (using a temp filename derived from the cache variable), then atomically
move that temporary file to the final cache location using the mv command. This
ensures that other processes reading the cache file will either see the old
complete version or the new complete version, never a partial write. Reference
the cache variable and the java jar invocation in your fix.

In `@xtest/sdk/js/cli.sh`:
- Around line 149-150: The --auth argument containing CLIENTSECRET is being
logged/echoed in subsequent command output, which exposes sensitive credentials
in CI logs. Locate where the command arguments are being printed or logged (the
echo statement that prints full args), and add logic to redact or mask the
--auth argument value before logging while keeping the actual command execution
intact with the real credentials. Ensure the secret portion of the auth
credentials is not visible in any log output or CI artifacts.
- Around line 139-140: Replace the single bracket conditionals `[ -n ... ]` with
double bracket syntax `[[ -n ... ]]` for the two conditional checks involving
$_pre_clientid and $_pre_clientsecret variables. Update both lines that check
$_pre_clientid and $_pre_clientsecret to use `[[ ... ]]` instead of `[ ... ]` to
comply with ShellCheck best practices and improve code robustness.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4855622a-9727-479f-a484-91316676a003

📥 Commits

Reviewing files that changed from the base of the PR and between 55c03e0 and a2f609c.

📒 Files selected for processing (5)
  • .github/workflows/xtest.yml
  • xtest/sdk/java/cli.sh
  • xtest/sdk/js/cli.sh
  • xtest/tdfs.py
  • xtest/test_dpop.py

Comment thread xtest/sdk/java/cli.sh Outdated
Comment thread xtest/sdk/js/cli.sh Outdated
Comment thread xtest/sdk/js/cli.sh
@dmihalcik-virtru dmihalcik-virtru changed the title DPoP nonce-challenge test coverage and CLI/CI hardening chore(xtest): DPoP nonce-challenge test coverage and CLI/CI hardening Jun 18, 2026
@dmihalcik-virtru dmihalcik-virtru marked this pull request as draft June 18, 2026 17:05
dmihalcik-virtru and others added 12 commits June 24, 2026 09:38
Update start-up-with-containers and start-additional-kas action SHAs
to DSPX-3397-platform-service tip, and pass dpop-challenge-enabled: true
so the DPoP nonce challenge tests are not skipped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Capture caller env vars before sourcing test.env (which unconditionally
  resets them), then restore them — allows pytest monkeypatch to override
  CLIENTID=opentdf-dpop for DPoP-specific tests.
- Replace hardcoded --auth opentdf:secret with ${CLIENTID:-opentdf}:${CLIENTSECRET:-secret}.
- Add XT_WITH_DPOP (algorithm, e.g. ES256) and XT_WITH_DPOP_KEY (PEM path)
  support, wired to --dpop / --dpop-key CLI flags.
- Update _dpop_client_env fixture to also export XT_WITH_DPOP=ES256 so
  DPoP proof generation is actually exercised in test_dpop.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…st binary

load_otdfctl() in conftest.py reads OTDFCTL_HEADS to resolve sdk/go/dist/{tag}/otdfctl.sh.
Without it, every test step fell through to sdk/go/dist/main/otdfctl.sh or the non-dist
sdk/go/otdfctl.sh, which falls back to go run github.com/opentdf/otdfctl@latest instead
of the built branch binary.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Running 'java -jar cmdline.jar help' on every encrypt/decrypt paid
150-500ms of JVM startup per probe (kas-allowlist and --verbose checks).
Add a jar_help() helper that caches help output to a tmpfile keyed by the
jar's mtime, and discards stderr to keep JVM warnings out of test logs.
- java cli.sh: write jar_help cache to a temp file then mv, so concurrent
  xdist workers never read a partially written cache (gemini/coderabbit).
- java/js cli.sh: use [[ ]] for the new conditionals (SonarCloud SC2292).
- js cli.sh: mask the --auth secret in echoed commands so CI logs don't
  capture client credentials (coderabbit).
@dmihalcik-virtru dmihalcik-virtru force-pushed the fix-dpop-nonce-challenge branch from e61eb55 to 7746ba2 Compare June 24, 2026 13:42
Pass dpop-challenge-enabled:true to the alpha/beta/gamma/delta/km1/km2
start-additional-kas steps and re-pin that action to the go-branch commit
(2305c4ab) that adds the input. Fixes test_dpop_rejects_tampered_nonce,
which targets the alpha KAS that previously never set require_nonce.
…once-agnostic

- Repin start-up-with-containers and all start-additional-kas steps to
  opentdf/platform DSPX-3397-platform-go-sdk @4a19b297 (adds dpop enforce
  alongside require_nonce on additional KAS).
- test_dpop_bearer_scheme: route both rewrap calls through a new
  _post_rewrap_with_nonce_retry helper so the test passes whether or not the
  target KAS enforces require_nonce (satisfies the use_dpop_nonce challenge
  before asserting lenient 200 + WARN).
Platform action split DPoP enforcement into a separate dpop-enforce-required
input (default false); xtest only passes dpop-challenge-enabled, so require_nonce
stays on and global enforce stays off, restoring the non-DPoP suite.
@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