Skip to content

feat(auth): rfc 0029 green — dex end-to-end acceptance and status flip - #426

Merged
jensholdgaard merged 4 commits into
mainfrom
rfc0029-green-dex
Jul 7, 2026
Merged

feat(auth): rfc 0029 green — dex end-to-end acceptance and status flip#426
jensholdgaard merged 4 commits into
mainfrom
rfc0029-green-dex

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jul 7, 2026

Copy link
Copy Markdown
Owner

What

RFC 0029 → green. The final §5 arm (.7) goes live: a real Dex container (testcontainers, CI-gated exactly like s3 integration (localstack)) mints client-credentials tokens that the served binary verifies against Dex's real JWKS — the OTel Collector oauth2client flow, verbatim.

.7 arm Evidence
Startup discovery against real Dex receiver + querier + MCP serve
Client-credentials mint scope=openid profile groups; tenant list from staticClients[].clientCredentialsClaims.groups (tenant_claim: groups), name label from the client display name (name_claim: name)
Ingest in-claim tenant acks; cross-tenant whole-batch PERMISSION_DENIED
Query / MCP in-claim 200; MCP 401 bearer-less, success with the Dex bearer
Expiry real 8-second TTL + zero skew → the same token collapses to the undifferentiated 401
Telemetry parity (audit half) SIGTERM-flushed audit read-back: exactly one ingest_denied carrying the name_claim value
No JWT material token absent from denial messages, 401 bodies, and the whole captured log surface

The image decision (called out for review)

The client-credentials grant and clientCredentialsClaims are merged upstream (dexidp/dex#4691) but not in any Dex release — v2.45.1 predates both. The job pins Dex master by image digest (reproducible; comment + RFC §6 note record the bump path to v2.46 when it ships). The alternative was deviating the scenario to the password-grant mock connector, which would not test the machine-to-machine path the RFC §3 names as the Collector flow.

Status flip

red → green: .1 (config, #420/#422) · .2/.6 (verifier, #423) · .3/.4/.5 (bindings, #424/#425) · .7 (here, run by this PR's own required dex oidc (testcontainers) job).

Full local gate: 978 / 0, clippy -D warnings, rustdoc, fmt, cargo-deny. The .7 arm itself is validated by this PR's CI (no Docker locally, by design — the localstack precedent).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a new end-to-end OIDC acceptance check to CI for Dex-based login and token handling.
    • Expanded integration coverage for authenticated ingest, query behavior, and transport access.
  • Bug Fixes

    • Improved CI gating so the release pipeline now waits for the new OIDC verification before passing.
    • Added stronger validation around expired and unauthorized token responses.
  • Documentation

    • Updated the RFC notes with setup guidance for the Dex test image and release readiness.

…s flip

The last §5 arm: a real Dex container (testcontainers, CI-gated like
the localstack job) mints client-credentials tokens the served binary
verifies against Dex's real JWKS.

- The static client carries the tenant list via
  clientCredentialsClaims.groups (tenant_claim: groups) and the name
  label via its display name (name_claim: name, scope profile) — the
  OTel Collector oauth2client flow verbatim.
- Arms: startup discovery against Dex; in-claim gRPC ingest acks;
  cross-tenant batch PERMISSION_DENIED; in-claim query 200; MCP 401
  bearer-less / success with the Dex bearer; real-TTL expiry (8 s
  tokens, zero skew) collapses to the undifferentiated 401; SIGTERM
  flushes the audit sink and the read-back ingest_denied event carries
  the name_claim value; no JWT material in error bodies or the log
  surface.
- Image: Dex `master` pinned by digest — the client-credentials grant
  and clientCredentialsClaims are merged upstream (dexidp/dex#4691)
  but post-v2.45.1; the RFC §6 note + ci.yml comment record the bump
  path to v2.46. New required `dex oidc (testcontainers)` CI job runs
  the arm by exact name.
- reqwest (rustls + json) joins the server dev-deps for minting and
  readiness polling — the same stack the verifier itself uses.

RFC 0029 status red → green: .1–.6 discharged across #420#425, .7
lands here and runs in this PR's own required CI job.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jensholdgaard, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 39 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f276a79e-cec3-4ddb-9e4b-6396f11106c8

📥 Commits

Reviewing files that changed from the base of the PR and between 2639e0e and b2f7785.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • crates/ourios-server/tests/it/rfc0029_oidc.rs
  • docs/rfcs/0029-oidc-bearer-layer.md
📝 Walkthrough

Walkthrough

Adds a Docker-based Dex OIDC end-to-end integration test replacing a stub, exercising ingest/query/MCP flows, token expiry, and audit denial telemetry. Adds a reqwest dev-dependency, a new dex-oidc CI job gating ci-success, and updates the RFC document status from red to green with a testing note.

Changes

Dex OIDC End-to-End Acceptance Test

Layer / File(s) Summary
Dex integration test implementation
crates/ourios-server/tests/it/rfc0029_oidc.rs, crates/ourios-server/Cargo.toml
Replaces the todo! stub with a mod dex block that starts a pinned Dex container, mints tokens via client credentials, verifies in-tenant ingest, cross-tenant denial, query, and MCP bearer gating, checks expired-token 401 behavior, and validates parquet audit telemetry for denial events; adds reqwest dev-dependency to support this.
CI job wiring and RFC documentation update
.github/workflows/ci.yml, docs/rfcs/0029-oidc-bearer-layer.md
Adds a dex-oidc CI job running the ignored exact Dex acceptance test, adds it to ci-success needs, and updates the RFC status from red to green with a note on pinning Dex by image digest.

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

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is detailed but does not follow the required template and omits Summary, Related, and Checklist sections. Rewrite it using the repository template with Summary, Related, and Checklist headings, and add the missing links and checklist items.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: RFC 0029 is made green with a Dex end-to-end acceptance test and CI status flip.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rfc0029-green-dex

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.

Copilot AI 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.

Pull request overview

Advances RFC 0029 to green by adding a CI-gated, real-Dex end-to-end acceptance test (testcontainers) that mints client-credentials tokens and validates ingest/query/MCP behavior and “no JWT material” surfaces, plus wiring a dedicated CI job to run the ignored test.

Changes:

  • Flip RFC 0029 status to green and document the Dex image-digest pin rationale.
  • Implement RFC0029.7 as an ignored, Docker-required Dex acceptance test in ourios-server integration tests.
  • Add a required GitHub Actions job (dex oidc (testcontainers)) to run the exact ignored test in CI, and add reqwest as a dev-dependency for minting/polling.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
docs/rfcs/0029-oidc-bearer-layer.md Status flip to green; adds Dex image pin note for RFC0029.7 acceptance.
crates/ourios-server/tests/it/rfc0029_oidc.rs Adds RFC0029.7 real-Dex container scenario exercising mint/ingest/query/MCP/expiry/audit checks.
crates/ourios-server/Cargo.toml Adds reqwest (dev-dep) for Dex readiness polling and token minting in RFC0029.7.
Cargo.lock Locks new dependency graph including reqwest.
.github/workflows/ci.yml Adds required dex-oidc job running the ignored RFC0029.7 test by exact name.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/ourios-server/tests/it/rfc0029_oidc.rs Outdated
Comment thread crates/ourios-server/tests/it/rfc0029_oidc.rs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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: 1

🧹 Nitpick comments (2)
crates/ourios-server/tests/it/rfc0029_oidc.rs (1)

1038-1052: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a signal API over shelling out to kill.

Sending SIGTERM by invoking the external kill binary works on the Linux CI runner but ties the test to kill being on PATH. A crate like nix::sys::signal::kill (or libc::kill) would send the signal in-process without spawning a subprocess.

♻️ Alternative using a signal crate
-        let pid = child.id().expect("child pid").to_string();
-        std::process::Command::new("kill")
-            .args(["-TERM", &pid])
-            .status()
-            .expect("send SIGTERM");
+        let pid = child.id().expect("child pid") as i32;
+        nix::sys::signal::kill(
+            nix::unistd::Pid::from_raw(pid),
+            nix::sys::signal::Signal::SIGTERM,
+        )
+        .expect("send SIGTERM");
🤖 Prompt for 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.

In `@crates/ourios-server/tests/it/rfc0029_oidc.rs` around lines 1038 - 1052, The
test is shelling out to the external kill binary to send SIGTERM, which makes it
depend on PATH and a subprocess. Update the graceful shutdown logic in the
rfc0029_oidc test to send the signal in-process using a signal API such as
nix::sys::signal::kill or libc::kill, targeting the child PID from child.id(),
and keep the existing timeout/wait/drain flow unchanged.
.github/workflows/ci.yml (1)

144-152: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Set persist-credentials: false on the new job's checkout.

Static analysis flags credential persistence via this checkout step. Since this job runs cargo test (compiling third-party dependencies/build scripts) right after checkout, leaving the GitHub token persisted in .git/config is unnecessary exposure — nothing in this job pushes back to the repo.

🔒️ Proposed fix
       - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
+        with:
+          persist-credentials: false
       - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master (pinned); channel via toolchain input
🤖 Prompt for 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.

In @.github/workflows/ci.yml around lines 144 - 152, The new dex-oidc job’s
checkout step is leaving GitHub credentials persisted in the repo config. Update
the actions/checkout step in the dex-oidc job to set persist-credentials to
false so the token is not stored in .git/config; keep the rest of the job steps
unchanged.

Source: Linters/SAST tools

🤖 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 `@docs/rfcs/0029-oidc-bearer-layer.md`:
- Around line 269-278: The new “Image note” blockquote in the RFC 0029 document
is accidentally absorbing the following paragraph because the note and the next
text run together without a proper separation. Update the markdown around the
Image note block so the blockquote ends cleanly and the “The RFC 0026 §5 suite
re-runs…” paragraph starts as its own paragraph, following the same blank-line
separation pattern used earlier in the document.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 144-152: The new dex-oidc job’s checkout step is leaving GitHub
credentials persisted in the repo config. Update the actions/checkout step in
the dex-oidc job to set persist-credentials to false so the token is not stored
in .git/config; keep the rest of the job steps unchanged.

In `@crates/ourios-server/tests/it/rfc0029_oidc.rs`:
- Around line 1038-1052: The test is shelling out to the external kill binary to
send SIGTERM, which makes it depend on PATH and a subprocess. Update the
graceful shutdown logic in the rfc0029_oidc test to send the signal in-process
using a signal API such as nix::sys::signal::kill or libc::kill, targeting the
child PID from child.id(), and keep the existing timeout/wait/drain flow
unchanged.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d06cb55a-9251-42cf-9bad-4dec48e5f249

📥 Commits

Reviewing files that changed from the base of the PR and between a2602fc and 2639e0e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • .github/workflows/ci.yml
  • crates/ourios-server/Cargo.toml
  • crates/ourios-server/tests/it/rfc0029_oidc.rs
  • docs/rfcs/0029-oidc-bearer-layer.md

Comment thread docs/rfcs/0029-oidc-bearer-layer.md

Copilot AI 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.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 4 comments.

Comment thread docs/rfcs/0029-oidc-bearer-layer.md Outdated
Comment thread .github/workflows/ci.yml
Comment thread crates/ourios-server/tests/it/rfc0029_oidc.rs Outdated
Comment thread crates/ourios-server/tests/it/rfc0029_oidc.rs Outdated
…ent-credentials

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.

Comment thread docs/rfcs/0029-oidc-bearer-layer.md
Comment thread crates/ourios-server/tests/it/rfc0029_oidc.rs Outdated
Comment thread .github/workflows/ci.yml
…rm; ci creds + rfc quote

20s tokens with the expiry wait driven by the response's expires_in;
container start retries a fresh port on the reserve race; SIGTERM via
tokio Command with an asserted status; persist-credentials: false on
the dex job checkout; the RFC image note no longer swallows the
following paragraph.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated no new comments.

@jensholdgaard
jensholdgaard merged commit 69400a8 into main Jul 7, 2026
23 checks passed
@jensholdgaard
jensholdgaard deleted the rfc0029-green-dex branch July 7, 2026 21:27
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.

2 participants