Skip to content

Add uselesskey-axum crate with JWKS/OIDC routers and mock JWT middleware#337

Merged
EffortlessSteven merged 5 commits intomainfrom
codex/add-auth-test-helpers-for-rust-frameworks-8owqyk
Mar 30, 2026
Merged

Add uselesskey-axum crate with JWKS/OIDC routers and mock JWT middleware#337
EffortlessSteven merged 5 commits intomainfrom
codex/add-auth-test-helpers-for-rust-frameworks-8owqyk

Conversation

@EffortlessSteven
Copy link
Copy Markdown
Member

Motivation

  • Provide drop-in auth-test helpers for axum built on existing deterministic uselesskey fixtures so tests can easily exercise JWKS/OIDC and bearer-token flows.
  • Keep the crate tiny and test-focused (deterministic signing, JWKS rotation phases, negative/edge cases handled by test inputs).
  • Surface ergonomics needed by framework tests: router helpers, attachable middleware, and a deterministic auth context extractor/injector.

Description

  • Add a new crate crates/uselesskey-axum containing src/lib.rs and README.md that implements jwks_router(), oidc_router(), mock_jwt_verifier_layer() (attachable middleware), inject_auth_context_layer(), DeterministicJwksPhase, RotationPhase, AuthExpectations, and the typed extractor TestAuthContext.
  • Use deterministic Factory::deterministic(Seed) fixtures to produce RSA signing keys and JWKS payloads and provide issue_token() helpers that mint RS256 tokens for tests.
  • Wire workspace and dependency changes: register the crate in the workspace Cargo.toml, enable the jwk feature for uselesskey-rsa in the new crate, and update lockfiles to include axum and related deps.
  • Tests added in the crate exercise JWKS/OIDC router round-trips, deterministic rotation produces distinct kids, verification rejects wrong-audience and expired tokens, and deterministic auth-context injection works.

Testing

  • Ran cargo check -p uselesskey-axum which completed successfully.
  • Ran cargo test -p uselesskey-axum and all unit tests passed (5 tests covering router responses, rotation-phase kid differences, wrong-audience rejection, expired-token rejection, and auth-context injection).
  • Lockfiles were regenerated to include the new crate and its transitive dependencies (e.g. axum).

Codex Task

@gemini-code-assist
Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 28, 2026

Warning

Rate limit exceeded

@EffortlessSteven has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 22 minutes and 46 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 22 minutes and 46 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4b8a9f89-25dc-4aba-bf1c-9269613088b6

📥 Commits

Reviewing files that changed from the base of the PR and between d08ea64 and 9238e6c.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • Cargo.toml
  • README.md
  • crates/uselesskey-axum/Cargo.toml
  • crates/uselesskey-axum/README.md
  • crates/uselesskey-axum/src/lib.rs
  • crates/uselesskey-axum/tests/integration.rs
  • docs/metadata/workspace-docs.json
  • docs/reference/support-matrix.md

Walkthrough

Adds a new workspace crate uselesskey-axum providing deterministic, test-oriented Axum auth helpers: JWKS/OIDC discovery endpoints, JWT issuance/verification tied to deterministic keys, middleware to validate tokens and inject a typed TestAuthContext, plus integration tests and docs.

Changes

Cohort / File(s) Summary
Workspace membership
Cargo.toml
Added crates/uselesskey-axum to workspace members.
Crate manifest & docs
crates/uselesskey-axum/Cargo.toml, crates/uselesskey-axum/README.md, README.md
New crate manifest with Axum/JWT/serde dependencies and workspace path deps; README documents test helpers and adapter listing updated.
Implementation
crates/uselesskey-axum/src/lib.rs
New Axum-focused library (deterministic JWKS phases, token issuance, AuthExpectations, MockJwtVerifierState, TestAuthContext, routers and middleware, FromRequestParts extractor) with unit tests.
Integration tests
crates/uselesskey-axum/tests/integration.rs
New Tokio-based integration tests exercising JWKS/OIDC endpoints, mock_jwt_verifier_layer (valid/invalid tokens), and inject_auth_context_layer.
Docs metadata
docs/metadata/workspace-docs.json, docs/reference/support-matrix.md
Added uselesskey-axum entry to adapter_crates, support_matrix, and support-matrix documentation row.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Middleware as mock_jwt_verifier_layer
    participant Validator as JWT Validator
    participant JWKS as DeterministicJwksPhase
    participant App as Axum Router/Handler

    Client->>Middleware: HTTP request (Authorization: Bearer <token>)
    Middleware->>Validator: Parse header, decode JWT
    Validator->>JWKS: Resolve key by kid, verify RS256 signature
    alt signature fails or kid unknown
        Middleware->>Client: 401 Unauthorized
    else signature ok
        Validator->>Validator: Validate iss, aud, exp claims
        alt claims invalid or expired
            Middleware->>Client: 401 Unauthorized
        else claims valid
            Validator->>Middleware: Create TestAuthContext
            Middleware->>App: Insert TestAuthContext into request extensions
            App->>App: Handler extracts TestAuthContext
            App->>Client: 200 OK + response
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🐰 I carved keys from deterministic seed,

JWKS and tokens ready for need.
Axum routes and middleware neat,
Tests hop through checks, all complete—
A rabbit’s stamp: deterministic, sweet. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding a new crate with JWKS/OIDC routers and mock JWT middleware for axum.
Description check ✅ Passed The description is well-detailed and directly related to the changeset, providing clear motivation, implementation details, and testing evidence.

✏️ 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 codex/add-auth-test-helpers-for-rust-frameworks-8owqyk

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 and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f43c4eb9fe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +308 to +310
let mut validation = Validation::new(Algorithm::RS256);
validation.set_issuer(&[expected.issuer.clone()]);
validation.set_audience(&[expected.audience.clone()]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Require iss and aud claims during JWT verification

Validation::new(Algorithm::RS256) only requires exp by default, and set_issuer/set_audience validate those claims only when they are present. As written, a token with a valid signature and exp but no iss/aud is accepted, which lets malformed tokens pass this middleware and can hide auth regressions in tests that rely on issuer/audience enforcement.

Useful? React with 👍 / 👎.

Comment on lines +332 to +334
.get("aud")
.and_then(Value::as_str)
.unwrap_or_default()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle multi-valued aud claims when building auth context

JWT aud is allowed to be an array, and jsonwebtoken validation supports that form, but this extraction path only uses Value::as_str(). When a valid token contains aud as an array, verification succeeds but TestAuthContext.aud is populated as an empty string, which can produce incorrect downstream assertions in handlers/tests.

Useful? React with 👍 / 👎.

@EffortlessSteven EffortlessSteven force-pushed the codex/add-auth-test-helpers-for-rust-frameworks-8owqyk branch from f43c4eb to 741c566 Compare March 30, 2026 14:01
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@crates/uselesskey-axum/src/lib.rs`:
- Around line 317-322: The code currently synthesizes "unknown" when
token.claims.get("sub") is missing; instead either reject the token at
authentication time or make TestAuthContext.sub optional. Replace the
unwrap_or("unknown").to_owned() usage on token.claims.get("sub") with explicit
handling: return an authentication error (e.g., Err(AuthError::MissingSubject)
or similar) from the auth function when no "sub" is present, or change the
TestAuthContext.sub field to Option<String> and propagate None through the
context and callers; update any callers of TestAuthContext or the auth function
to handle the new error or optional sub accordingly.

In `@crates/uselesskey-axum/tests/integration.rs`:
- Around line 18-36: auth_state() and signer_fixture() produce different
deterministic keypairs so the negative-path tokens in
verifier_rejects_wrong_audience_and_expired_tokens() are signed with the wrong
key and fail signature verification before audience/expiry checks; fix by
creating the negative-case tokens using the same MockJwtVerifierState that
auth_state() returns (use MockJwtVerifierState::issue_token or
state.issue_token(...)) instead of signing with signer_fixture() so signature
verification passes and the test actually exercises audience and expiry
branches.
- Around line 52-53: Replace the #[tokio::test] attribute on the async
integration test function jwks_and_oidc_routes_round_trip with a plain #[test],
create a Tokio runtime via tokio::runtime::Runtime::new().unwrap(), and run the
existing async body inside runtime.block_on(async { ... }); do the same change
for the other integration test functions that currently use #[tokio::test] so
all integration tests use #[test] with an explicit runtime instead of the
attribute.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 99dc7644-1d4c-43e6-8334-e6aab963dff1

📥 Commits

Reviewing files that changed from the base of the PR and between e79ad4d and a6f2622.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • fuzz/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • Cargo.toml
  • crates/uselesskey-axum/Cargo.toml
  • crates/uselesskey-axum/README.md
  • crates/uselesskey-axum/src/lib.rs
  • crates/uselesskey-axum/tests/integration.rs

Comment on lines +317 to +322
let sub = token
.claims
.get("sub")
.and_then(Value::as_str)
.unwrap_or("unknown")
.to_owned();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t synthesize "unknown" for a missing sub.

A token with valid signature/issuer/audience/expiry but no subject currently becomes an authenticated request with sub = "unknown". That hides malformed fixtures and can make subject-dependent handler tests pass for the wrong reason. Reject the token here, or make TestAuthContext.sub optional instead of inventing an identity.

Proposed fix
-    let sub = token
-        .claims
-        .get("sub")
-        .and_then(Value::as_str)
-        .unwrap_or("unknown")
-        .to_owned();
+    let Some(sub) = token.claims.get("sub").and_then(Value::as_str) else {
+        return (StatusCode::UNAUTHORIZED, "missing sub claim").into_response();
+    };
+    let sub = sub.to_owned();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let sub = token
.claims
.get("sub")
.and_then(Value::as_str)
.unwrap_or("unknown")
.to_owned();
let Some(sub) = token.claims.get("sub").and_then(Value::as_str) else {
return (StatusCode::UNAUTHORIZED, "missing sub claim").into_response();
};
let sub = sub.to_owned();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/uselesskey-axum/src/lib.rs` around lines 317 - 322, The code currently
synthesizes "unknown" when token.claims.get("sub") is missing; instead either
reject the token at authentication time or make TestAuthContext.sub optional.
Replace the unwrap_or("unknown").to_owned() usage on token.claims.get("sub")
with explicit handling: return an authentication error (e.g.,
Err(AuthError::MissingSubject) or similar) from the auth function when no "sub"
is present, or change the TestAuthContext.sub field to Option<String> and
propagate None through the context and callers; update any callers of
TestAuthContext or the auth function to handle the new error or optional sub
accordingly.

Comment on lines +18 to +36
fn auth_state() -> MockJwtVerifierState {
let seed = Seed::from_env_value("uselesskey-axum-integration-v1").expect("seed");
let phase = DeterministicJwksPhase::new(
seed,
"auth-suite",
RotationPhase::Primary,
"https://issuer.example.test",
"api://example-aud",
);
MockJwtVerifierState::new(phase)
}

fn signer_fixture() -> (uselesskey_rsa::RsaKeyPair, String, String) {
let fx =
Factory::deterministic(Seed::from_env_value("uselesskey-axum-signer-v1").expect("seed"));
let key = fx.rsa("auth-suite-signer", RsaSpec::rs256());
let issuer = "https://issuer.example.test".to_string();
let audience = "api://example-aud".to_string();
(key, issuer, audience)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Negative-path tokens are signed with the wrong key.

auth_state() and signer_fixture() derive different deterministic keypairs, so both requests in verifier_rejects_wrong_audience_and_expired_tokens() fail during signature verification before the audience/expiry checks run. That means this test can pass without ever exercising the branches it claims to cover. Build those tokens with state.issue_token(...) instead.

Proposed fix
- fn signer_fixture() -> (uselesskey_rsa::RsaKeyPair, String, String) {
-     let fx =
-         Factory::deterministic(Seed::from_env_value("uselesskey-axum-signer-v1").expect("seed"));
-     let key = fx.rsa("auth-suite-signer", RsaSpec::rs256());
-     let issuer = "https://issuer.example.test".to_string();
-     let audience = "api://example-aud".to_string();
-     (key, issuer, audience)
- }
-
- fn signed_token(key: &uselesskey_rsa::RsaKeyPair, claims: serde_json::Value, kid: &str) -> String {
-     let mut header = Header::new(Algorithm::RS256);
-     header.kid = Some(kid.to_owned());
-
-     encode(
-         &header,
-         &claims,
-         &EncodingKey::from_rsa_pem(key.private_key_pkcs8_pem().as_bytes())
-             .expect("valid private key PEM"),
-     )
-     .expect("token encoding should succeed")
- }
-
 #[tokio::test]
 async fn verifier_rejects_wrong_audience_and_expired_tokens() {
     let state = auth_state();
-    let (key, issuer, audience) = signer_fixture();
+    let issuer = "https://issuer.example.test";
+    let audience = "api://example-aud";

     let app = mock_jwt_verifier_layer(
         Router::new().route("/me", get(|| async { StatusCode::OK })),
         state.clone(),
     );

-    let wrong_aud = signed_token(
-        &key,
+    let wrong_aud = state.issue_token(
         json!({
             "sub": "alice",
             "iss": issuer,
             "aud": "api://wrong-aud",
             "exp": 4_102_444_800i64,
         }),
-        &state.expectations().kid,
+        300,
     );
@@
-    let expired = signed_token(
-        &key,
+    let expired = state.issue_token(
         json!({
             "sub": "alice",
             "iss": issuer,
             "aud": audience,
             "exp": now.saturating_sub(5),
         }),
-        &state.expectations().kid,
+        300,
     );

Also applies to: 143-186

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/uselesskey-axum/tests/integration.rs` around lines 18 - 36,
auth_state() and signer_fixture() produce different deterministic keypairs so
the negative-path tokens in verifier_rejects_wrong_audience_and_expired_tokens()
are signed with the wrong key and fail signature verification before
audience/expiry checks; fix by creating the negative-case tokens using the same
MockJwtVerifierState that auth_state() returns (use
MockJwtVerifierState::issue_token or state.issue_token(...)) instead of signing
with signer_fixture() so signature verification passes and the test actually
exercises audience and expiry branches.

Comment on lines +52 to +53
#[tokio::test]
async fn jwks_and_oidc_routes_round_trip() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the integration test file
cd crates/uselesskey-axum && wc -l tests/integration.rs

Repository: EffortlessMetrics/uselesskey

Length of output: 96


🏁 Script executed:

# Read the relevant sections of the integration test file
head -n 210 crates/uselesskey-axum/tests/integration.rs | tail -n +40

Repository: EffortlessMetrics/uselesskey

Length of output: 5096


🏁 Script executed:

# Look for other test patterns in the codebase to understand convention
find . -name "*.rs" -path "*/tests/*" -type f | head -20

Repository: EffortlessMetrics/uselesskey

Length of output: 1131


🏁 Script executed:

# Check what test attributes are actually used across the project
rg "#\[(?:tokio::)?test\]" --type rs | head -30

Repository: EffortlessMetrics/uselesskey

Length of output: 98


🏁 Script executed:

# Search for test attributes across the codebase
rg "#\[(?:tokio::)?test\]" --type rust | head -40

Repository: EffortlessMetrics/uselesskey

Length of output: 1375


🏁 Script executed:

# Let's check a few test files to see what patterns they use
cat crates/uselesskey-core-base62/tests/integration.rs | head -50

Repository: EffortlessMetrics/uselesskey

Length of output: 1476


🏁 Script executed:

# Check if there are examples of explicit runtime wrapping vs #[tokio::test]
rg "fn test" --type rust crates/ | head -20

Repository: EffortlessMetrics/uselesskey

Length of output: 1701


🏁 Script executed:

# Look at the coding guidelines section more carefully - check if there's config
cat rustfmt.toml && cat clippy.toml

Repository: EffortlessMetrics/uselesskey

Length of output: 216


🏁 Script executed:

# Let's check the crates/uselesskey-axum/tests/integration.rs more carefully to see all test attributes
rg "#\[.*test.*\]" crates/uselesskey-axum/tests/integration.rs -A 1 | head -40

Repository: EffortlessMetrics/uselesskey

Length of output: 386


🏁 Script executed:

# Check if any crate has async tests with #[test] + explicit runtime
rg -B 1 "async fn.*test" crates/ --type rust | head -40

Repository: EffortlessMetrics/uselesskey

Length of output: 54


🏁 Script executed:

# Let's see if there are any examples of #[tokio::test] vs #[test] with runtime in other crates
find crates -name "*.rs" -path "*/tests/*" -type f -exec grep -l "tokio::test\|#\[test\].*async" {} \; | head -10

Repository: EffortlessMetrics/uselesskey

Length of output: 115


🏁 Script executed:

# Check what the actual test runner configuration is
find . -name "Cargo.toml" | head -5 | xargs grep -A 10 "\[dev-dependencies\]" | head -50

Repository: EffortlessMetrics/uselesskey

Length of output: 2614


🏁 Script executed:

# Let's check the entire codebase for #[tokio::test] usage
rg "#\[tokio::test\]" --type rust crates/

Repository: EffortlessMetrics/uselesskey

Length of output: 572


🏁 Script executed:

# Check crates/uselesskey-axum/Cargo.toml to see tokio dependency details
cat crates/uselesskey-axum/Cargo.toml | grep -A 20 "^\[dependencies\]\|^\[dev-dependencies\]"

Repository: EffortlessMetrics/uselesskey

Length of output: 526


🏁 Script executed:

# Look for examples of how async is handled with #[test] in the repo
rg "#\[test\].*async|async.*fn.*test" --type rust crates/ -B 1 -A 3 | head -50

Repository: EffortlessMetrics/uselesskey

Length of output: 54


🏁 Script executed:

# Let's check what the actual patterns are in the repo - check one of the test files more deeply
cat crates/uselesskey-core-base62/tests/integration.rs

Repository: EffortlessMetrics/uselesskey

Length of output: 2454


🏁 Script executed:

# Check if there's any documentation about testing conventions
find . -name "*.md" -type f | xargs grep -l "test\|#\[test\]" 2>/dev/null | head -5

Repository: EffortlessMetrics/uselesskey

Length of output: 333


🏁 Script executed:

# Let's check if tokio::test is mentioned in any contributing or guidelines
rg "tokio::test" --type rust --type md

Repository: EffortlessMetrics/uselesskey

Length of output: 572


Use #[test] with explicit runtime instead of #[tokio::test] in integration tests.

The coding guidelines specify #[test] for all integration tests. Replace #[tokio::test] with #[test] and wrap async bodies with an explicit tokio runtime (e.g., tokio::runtime::Runtime::new().unwrap().block_on(async { ... })).

Also applies to: lines 97-98, 140-141, 200-201

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/uselesskey-axum/tests/integration.rs` around lines 52 - 53, Replace
the #[tokio::test] attribute on the async integration test function
jwks_and_oidc_routes_round_trip with a plain #[test], create a Tokio runtime via
tokio::runtime::Runtime::new().unwrap(), and run the existing async body inside
runtime.block_on(async { ... }); do the same change for the other integration
test functions that currently use #[tokio::test] so all integration tests use
#[test] with an explicit runtime instead of the attribute.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/metadata/workspace-docs.json`:
- Around line 45-48: The adapter metadata now lists "uselesskey-axum" in
adapter_crates but adapter_feature_matrix lacks a corresponding row; update the
adapter_feature_matrix JSON to include a "uselesskey-axum" entry (with
appropriate capability booleans or explicit "N/A" values) so the generated docs
remain consistent, referencing the adapter_crates name "uselesskey-axum" and the
adapter_feature_matrix object to locate where to add the row.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 243c6b1e-dc33-44bb-83dd-8e114e290916

📥 Commits

Reviewing files that changed from the base of the PR and between a6f2622 and d08ea64.

📒 Files selected for processing (3)
  • README.md
  • docs/metadata/workspace-docs.json
  • docs/reference/support-matrix.md

@EffortlessSteven EffortlessSteven force-pushed the codex/add-auth-test-helpers-for-rust-frameworks-8owqyk branch 2 times, most recently from d5d647e to 43194ae Compare March 30, 2026 15:30
@EffortlessSteven EffortlessSteven force-pushed the codex/add-auth-test-helpers-for-rust-frameworks-8owqyk branch from 43194ae to 9238e6c Compare March 30, 2026 15:43
@EffortlessSteven EffortlessSteven merged commit 2fd5b22 into main Mar 30, 2026
5 checks passed
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