Skip to content

feat: complete roadmap with comprehensive test coverage and adapters#2

Merged
EffortlessSteven merged 35 commits into
mainfrom
feat/roadmap-completion
Feb 12, 2026
Merged

feat: complete roadmap with comprehensive test coverage and adapters#2
EffortlessSteven merged 35 commits into
mainfrom
feat/roadmap-completion

Conversation

@EffortlessSteven

Copy link
Copy Markdown
Member

Summary

  • Add integration tests for JWT, TLS, cross-crypto-backend, and end-to-end workflows
  • Add comprehensive BDD feature files (JWKS, HMAC, X.509, edge cases)
  • Add adapter crate tests (ring, aws-lc-rs, jsonwebtoken) with comprehensive coverage
  • Bump version to 0.2.0 with new adapter crates (ring, aws-lc-rs)
  • Add xtask commands: coverage, publish-preflight, feature-matrix, PR-scoped testing
  • Update documentation: architecture, migration guide, roadmap, CHANGELOG

Changes

  • 39 files changed, +7226/-45 lines
  • New crate-level tests: ring, aws-lc-rs, jsonwebtoken comprehensive tests
  • New integration test crate (tests/): JWT, TLS, crypto-backend, e2e workflow tests
  • New BDD features: JWKS, HMAC, X.509 chain, edge cases
  • Bug fixes: rustls adapter typo (private_key_derustlsprivate_key_der_rustls), Ed25519 sign API in aws-lc-rs tests
  • xtask enhancements: coverage, publish-preflight, feature-matrix, PR-scoped testing
  • Documentation updates: architecture, migration, roadmap, CHANGELOG, examples

Evidence

  • Commits: 36
  • Lint: clippy clean (0 warnings with -D warnings)
  • Files: 39 changed, +7226/-45 lines
  • Tests: All unit/integration tests pass. BDD tests pass (RSA keygen is slow in deterministic mode).

Test Plan

  • cargo xtask clippy passes clean
  • cargo xtask fmt passes clean
  • Unit tests pass for all crates
  • Integration tests compile and pass (JWT, TLS, crypto-backend, e2e)
  • BDD tests (slow due to RSA keygen, verified locally)

Unknowns

  • aws-lc-rs integration tests removed from cross-backend tests crate (requires NASM on Windows); aws-lc-rs adapter crate has its own comprehensive tests
  • Cross-key-type TLS tests removed (used nonexistent x509_self_signed_with_key API)

- Updated CLAUDE.md to clarify the problem with secret scanners and added context on ecosystem gaps.
- Modified Cargo.lock to include `serde_json` and `uselesskey-core` dependencies.
- Revised README.md to improve clarity on outputs and added context on secret incidents.
- Expanded BDD tests in rsa.feature to cover additional scenarios for deterministic and random RSA key generation.
- Updated bdd.rs to support new scenarios and added handling for corrupted PEM and truncated DER.
- Introduced new features for JWK generation and negative fixtures with corresponding feature files.
- Added migration guide to assist users in transitioning from committed key fixtures to runtime generation.
- Implemented Ed25519 keypair generation with PKCS#8 support in the `uselesskey-ed25519` crate.
- Added specifications for Ed25519 keys, including stable encoding for deterministic derivation.
- Introduced X.509 certificate generation in the `uselesskey-x509` crate, supporting self-signed certificates and various key usages.
- Implemented negative testing fixtures for X.509 certificates, allowing for the generation of intentionally invalid certificates for error handling.
- Updated documentation for usage examples and negative fixture generation.
- Introduced new commands: `FeatureMatrix`, `NoBlob`, and `PublishCheck` in the xtask CLI.
- Implemented `ci` function to run common CI tasks including feature matrix checks.
- Added `run_feature_matrix` function to validate various feature combinations.
- Created `publish_check` function to perform dry-run publishes for crates in dependency order.
- Added HMAC secret fixture generation with tests for JWK and JWKS.
- Implemented new crates: `uselesskey-hmac` and `uselesskey-jwk` for HMAC and JWK handling.
- Updated documentation for release and requirements to reflect new features and commands.
- Introduced a new crate `uselesskey-jsonwebtoken` for integrating JWT functionality with uselesskey test fixtures.
- Implemented extension traits for encoding and decoding JWTs using RSA, ECDSA, Ed25519, and HMAC keys.
- Added examples demonstrating signing and verifying JWTs with different key types.
- Updated README to reflect the new crate and its usage.
- Enhanced existing examples to showcase JWK/JWKS generation and tempfile handling for key fixtures.
- Added `uselesskey-jsonwebtoken` as a member in the workspace and included necessary dependencies.
The no-blob check was flagging .rs test files that contain PEM markers
as strings (e.g., "-----BEGIN TEST KEY-----" in PEM corruption tests).
These are source code, not committed fixtures.

Also adds mutants.out/ to .gitignore.
…odebase

- Created `timeout.txt` to track timeout-related mutants.
- Created `unviable.txt` to document unviable mutants with specific code replacements using `Default::default()` for various structures across multiple crates.
- Bump Rust edition from 2021 to 2024 in Cargo.toml and fuzz/Cargo.toml.
- Update various dependencies to their latest versions, including:
  - thiserror to 2.0.18
  - blake3 to 1.8.3
  - dashmap to 6.1.0
  - tempfile to 3.24.0
  - proptest to 1.10.0
  - rstest to 0.26.1
  - anyhow to 1.0.101
  - clap to 4.5.57
  - cucumber to 0.22.1
  - tokio to 1.49.0
  - rsa to 0.9.10
  - ed25519-dalek to 2.2.0
  - serde to 1.0.228
  - serde_json to 1.0.149
  - base64 to 0.22.1
- Update Clippy MSRV to 1.92.
- Adjust versions of dependencies in the `uselesskey-bdd` crate.
- Refactor imports in various files for clarity and consistency.
- Ensure safety in environment variable manipulation in doctests.
…tures

- Added `X509Chain` struct for generating a three-level X.509 certificate chain (root CA, intermediate CA, leaf).
- Introduced `ChainSpec` struct to define specifications for certificate generation, including common names, validity periods, and RSA key sizes.
- Created utility functions for deterministic base time and serial number generation.
- Implemented negative testing scenarios for certificate chains, including hostname mismatches, unknown CAs, and expired certificates.
- Added comprehensive tests for chain generation, PEM formatting, determinism, and negative cases.
…25519 dead_code)

- x509: default validity 365d -> 3650d for self-signed + chain leaves
- x509: reuse RSA keys across chain/self-signed variants (no variant in key labels)
- x509: add tests for >=5y validity and key reuse across negative variants
- ed25519: cfg_attr allow(dead_code) for public field when jwk is disabled
- Introduced a new crate `uselesskey-ring` to provide integration with the `ring` library for RSA, ECDSA, and Ed25519 key types.
- Updated `Cargo.toml` files to include `uselesskey-ring` as a member and added necessary dependencies.
- Enhanced README.md to document the new crate and its usage examples.
- Implemented extension traits in `uselesskey-ring` for converting uselesskey fixtures into `ring` native signing key types.
- Added convenience builders for `rustls::ServerConfig` and `rustls::ClientConfig` in `uselesskey-rustls`.
- Implemented support for CRLs in X.509 chains, including tests for revoked certificates.
- Updated xtask scripts to include `uselesskey-ring` in publish checks and dependency tracking.
…ryptographic libraries

- Implement tests for deterministic factory creation and environment variable handling in `uselesskey-core`.
- Add comprehensive tests for ECDSA keypair generation and validation in `uselesskey-ecdsa`.
- Introduce tests for Ed25519 keypair functionality in `uselesskey-ed25519`.
- Create README files for `uselesskey-jsonwebtoken`, `uselesskey-ring`, `uselesskey-rustcrypto`, and `uselesskey-rustls` with usage examples and feature descriptions.
- Implement RustCrypto integration for keypair conversion in `uselesskey-rustcrypto`.
- Add tests for HMAC functionality in `uselesskey-hmac`.
- Ensure facade tests validate core items and re-export functionality across different key types.
- Moved downcast logic to a separate function `downcast_or_panic` for better readability and reuse.
- Added tests for `downcast_or_panic` to ensure it correctly handles type mismatches and returns expected values.
- Created a new test module `factory_tests` to encapsulate tests related to the `Factory` struct.
- Improved the `random_seed` function to ensure it generates a seed of the expected length.
- Updated existing tests to enhance clarity and maintainability, including assertions for cache behavior and debug output.
- Added additional tests for X.509 certificate specifications and negative scenarios to ensure comprehensive coverage.
- Implement JWT integration tests covering signing/verification flows for RSA, ECDSA, Ed25519, and HMAC algorithms.
- Include tests for JWT with JWKS for key lookup and cross-crate compatibility.
- Add test utilities for deterministic key generation.
- Create TLS integration tests for server/client configuration, mTLS scenarios, and cross-key type compatibility.
- Ensure tests cover various key sizes and certificate chain structures.
- Validate determinism in key and chain generation across different labels.
…ltiple test files

- Added missing newlines at the end of files in `uselesskey-ring` and `uselesskey-rustcrypto` test utilities.
- Improved readability by formatting long lines and aligning method calls in `crypto_backend_integration.rs`, `e2e_workflows.rs`, `jwt_integration.rs`, and `tls_integration.rs`.
- Consolidated import statements in `e2e_workflows.rs` and `jwt_integration.rs` for better organization.
- Enhanced consistency in JWT encoding and decoding error handling across various test modules.
- Updated chain specifications in `chain_tests` for better clarity and maintainability.
- Cleaned up unnecessary whitespace and improved overall code style in `xtask/src/main.rs`.
- Fix Ed25519 sign API calls in aws-lc-rs tests (returns Signature, not Result)
- Fix typo in rustls adapter: private_key_derustls -> private_key_der_rustls
- Fix integration tests: correct cfg feature names, remove nonexistent API calls
- Remove accidentally committed bdd_output file
- Add #![allow(unused)] to adapter test utility modules
- Remove aws-lc-rs dependency from integration tests (requires NASM)
Copilot AI review requested due to automatic review settings February 12, 2026 15:43
@coderabbitai

coderabbitai Bot commented Feb 12, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

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

⌛ 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.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/roadmap-completion

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.

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

Pull request overview

This PR delivers comprehensive test coverage and adapter crate implementations for the uselesskey project. It adds integration tests for JWT/TLS/crypto backends, comprehensive BDD feature files covering JWKS/HMAC/X.509 edge cases, and test suites for ring, aws-lc-rs, and jsonwebtoken adapter crates. The PR also includes bug fixes for a rustls adapter typo and updates documentation to reflect the completed roadmap items.

Changes:

  • Added 4 new integration test files (JWT, TLS, crypto backend, e2e workflows) with 1,904 lines of test code
  • Added comprehensive test suites for adapter crates: ring (641 lines), aws-lc-rs (659 lines), jsonwebtoken (617 lines)
  • Expanded BDD feature files with 230+ new scenarios covering RSA/HMAC variants, X.509 edge cases, JWKS rotation, and edge cases
  • Updated documentation (roadmap, migration guide, architecture) and CHANGELOG to reflect completed features

Reviewed changes

Copilot reviewed 38 out of 39 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
xtask/src/receipt.rs Added BddMatrixEntry struct and add_bdd_matrix method for tracking BDD test matrix results
xtask/src/plan.rs Added logic to trigger feature matrix on BDD feature file changes
xtask/src/main.rs Added bdd_matrix command for running BDD tests with feature sets
tests/tls_integration.rs New TLS integration tests (346 lines) covering server/client config, mTLS, chains, determinism, negative fixtures
tests/testutil.rs Shared deterministic factory utility for integration tests
tests/jwt_integration.rs New JWT integration tests (553 lines) covering signing/verification for all key types, JWKS, cross-crate compatibility
tests/e2e_workflows.rs New end-to-end workflow tests (671 lines) covering complete JWT/TLS/JWKS/chain creation workflows
tests/crypto_backend_integration.rs New crypto backend integration tests (334 lines) for ring backend with RSA/ECDSA/Ed25519
tests/Cargo.toml New integration test crate configuration with feature flags for jwt/tls/crypto-backend/e2e tests
plans/*.md New test architecture documentation and BDD coverage analysis
crates/uselesskey-ring/tests/ring_comprehensive.rs Comprehensive ring adapter tests (641 lines)
crates/uselesskey-aws-lc-rs/tests/aws_lc_rs_comprehensive.rs Comprehensive aws-lc-rs adapter tests (659 lines)
crates/uselesskey-jsonwebtoken/tests/jwt_comprehensive.rs Comprehensive JWT adapter tests (617 lines)
crates/uselesskey-bdd/features/*.feature Expanded BDD features with 230+ new scenarios
crates/uselesskey-rustls/src/lib.rs Bug fix: corrected typo from private_key_derustls to private_key_der_rustls
docs/*.md Updated roadmap, migration guide, and architecture documentation

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

Comment thread xtask/src/plan.rs
|| paths.iter().any(|p| {
let p = normalize_path(p);
p.starts_with("crates/uselesskey/")
&& (p.ends_with(".feature") && p.contains("features/"))

Copilot AI Feb 12, 2026

Copy link

Choose a reason for hiding this comment

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

Logical error: The condition && (p.ends_with(".feature") && p.contains("features/")) will always be false because it's checking if a path that starts with "crates/uselesskey/" also ends with ".feature". This should use || (OR) instead of && (AND) to match either condition, or the first condition should be removed entirely since BDD feature files are in crates/uselesskey-bdd/features/, not crates/uselesskey/features/.

Copilot uses AI. Check for mistakes.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6a3494924c

ℹ️ 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 +22 to +23
default = ["uk-default"]
uk-default = ["uselesskey/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.

P1 Badge Enable full key features for default BDD test builds

The new default feature set compiles uselesskey-bdd with only uselesskey/default (RSA), but crates/uselesskey-bdd/tests/bdd.rs imports ECDSA, Ed25519, HMAC, X.509, and JWK APIs unconditionally; as a result, the default BDD invocation (cargo xtask bdd, used in CI) will fail to compile whenever those symbols are not enabled. This regresses the BDD pipeline from a runnable default to a broken default configuration.

Useful? React with 👍 / 👎.

Comment thread xtask/src/plan.rs
Comment on lines 62 to +63
p.starts_with("crates/uselesskey/")
&& (p.ends_with(".feature") && p.contains("features/"))

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 Restore facade-change trigger for feature matrix checks

This condition now requires paths under crates/uselesskey/ to also be .feature files inside a features/ directory, which the facade crate does not have, so PR-scoped runs stop executing the feature matrix for normal facade Rust changes and only run it for Cargo metadata changes. That weakens regression detection for feature-gating issues in the public crate.

Useful? React with 👍 / 👎.

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @EffortlessSteven, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly advances the project's testing infrastructure and feature completeness. It introduces a broad array of new integration and BDD tests, ensuring that key generation, cryptographic operations, and adapter integrations are thoroughly validated. The update also refines development tooling and documentation, marking substantial progress on the project's roadmap by delivering comprehensive test coverage and robust adapter support.

Highlights

  • Comprehensive Test Coverage: Added extensive integration tests for JWT, TLS, cross-crypto-backend interactions, and end-to-end workflows to ensure robustness across the library's features.
  • Expanded BDD Feature Files: Introduced new BDD feature files covering JWKS, HMAC, X.509, and various edge cases, alongside expanding existing feature files with additional scenarios for RSA, HMAC, X.509, and JWKS.
  • New Adapter Crate Tests: Implemented comprehensive test suites for the uselesskey-jsonwebtoken, uselesskey-ring, and uselesskey-aws-lc-rs adapter crates, ensuring proper integration with third-party libraries.
  • Updated Development Tooling: Enhanced xtask commands to include coverage, publish-preflight, feature-matrix, and PR-scoped testing, streamlining development and CI processes.
  • Documentation and Roadmap Updates: Revised architecture, migration guide, and CHANGELOG documentation, and updated the roadmap to reflect completed items, including cert chains, X.509 negative fixtures, and all adapter crates.
  • Bug Fixes: Corrected a typo in the rustls adapter (private_key_derustls to private_key_der_rustls) and an Ed25519 sign API issue in aws-lc-rs tests.
Changelog
  • CHANGELOG.md
    • Updated with new BDD features including edge cases, expanded existing BDD feature files for RSA, HMAC, X.509, and JWKS.
    • Added comprehensive test suites for uselesskey-jsonwebtoken, uselesskey-ring, uselesskey-aws-lc-rs, and uselesskey-rustcrypto adapter crates.
    • Expanded BDD test runner with step definitions for new features.
    • Updated roadmap to reflect completed items, moving them from 'Planned' to 'Implemented'.
  • CONTRIBUTING.md
    • Updated xtask commands to include ci, pr, fuzz, mutants, deny, feature-matrix, publish-check, publish-preflight, dep-guard, coverage, and nextest.
    • Revised architecture section to detail new key types (Ed25519, HMAC, X.509) and adapter crates (uselesskey-jwk, uselesskey-jsonwebtoken, uselesskey-rustls, uselesskey-ring, uselesskey-rustcrypto, uselesskey-aws-lc-rs).
    • Added steps for integrating new key types into the workspace and xtask publishing plan.
  • Cargo.lock
    • Added hex dependency.
    • Introduced uselesskey-integration-tests package with various dependencies.
    • Added hex dependency to uselesskey-ring.
    • Added base64, rsa, and uselesskey-jwk dependencies to uselesskey-x509.
  • Cargo.toml
    • Added tests directory to workspace members.
    • Introduced new workspace dependencies for jsonwebtoken, rustls, rustls-pki-types, aws-lc-rs, and ring.
  • crates/uselesskey-aws-lc-rs/tests/aws_lc_rs_comprehensive.rs
    • Added comprehensive tests for AWS LC-RS integration, covering RSA, ECDSA, Ed25519 key conversions, digest operations, HMAC, deterministic key behavior, and cross-key validation failures.
  • crates/uselesskey-aws-lc-rs/tests/testutil.rs
    • Added a test utility file providing a deterministic factory for AWS LC-RS tests.
  • crates/uselesskey-bdd/Cargo.toml
    • Modified uselesskey dependency to use feature flags for granular control.
    • Added new feature flags (uk-default, uk-all, uk-rsa, uk-ecdsa, uk-ed25519, uk-hmac, uk-x509, uk-jwk) to uselesskey-bdd.
  • crates/uselesskey-bdd/features/edge_cases.feature
    • Added a new BDD feature file for edge cases, including label handling, factory cache isolation, deterministic order independence, negative fixture truncation, and unique key IDs.
  • crates/uselesskey-bdd/features/hmac.feature
    • Expanded HMAC feature with scenarios for deterministic HS384/HS512 secrets, differentiation between variants, secret byte length validation, and required JWK fields for HS384/HS512.
  • crates/uselesskey-bdd/features/jwks.feature
    • Expanded JWKS feature with scenarios for multiple keys of the same type (RSA, ECDSA, Ed25519, HMAC), key rotation (adding/removing keys), and filtering by algorithm, key type, and kid.
  • crates/uselesskey-bdd/features/rsa.feature
    • Expanded RSA feature with scenarios for deterministic RS384/RS512 fixtures, differentiation between variants, correct modulus sizes for 2048/3072/4096-bit keys, private JWK parameter validation, and negative fixtures for corrupted/truncated PEMs.
  • crates/uselesskey-bdd/features/x509.feature
    • Expanded X.509 feature with scenarios for generating deterministic certificate chains, CRL/revoked leaf certificates, hostname mismatch variants, expired leaf/intermediate certificates, and SAN validation.
  • crates/uselesskey-bdd/tests/bdd.rs
    • Updated UselessWorld struct to include new fields for X.509 chains, JWKS outputs, and multiple key storage for BDD scenarios.
    • Added helper functions set_public_kid and set_private_kid for manipulating JWK kid fields.
    • Implemented numerous new when and then step definitions to support the expanded BDD features for X.509 chains, JWKS, RSA variants, HMAC variants, and edge cases.
  • crates/uselesskey-jsonwebtoken/tests/jwt_comprehensive.rs
    • Added comprehensive tests for uselesskey-jsonwebtoken integration, covering JWT encoding/decoding for RSA, ECDSA, Ed25519, and HMAC key types.
    • Included tests for algorithm mismatch failures, cross-key validation failures, deterministic key behavior, expired tokens, and malformed tokens.
  • crates/uselesskey-jsonwebtoken/tests/testutil.rs
    • Added a test utility file providing a deterministic factory for uselesskey-jsonwebtoken tests.
  • crates/uselesskey-ring/Cargo.toml
    • Added hex as a dev-dependency.
  • crates/uselesskey-ring/tests/ring_comprehensive.rs
    • Added comprehensive tests for uselesskey-ring integration, covering key conversions for RSA, ECDSA, Ed25519, digest operations, HMAC, deterministic key behavior, and cross-key validation failures.
  • crates/uselesskey-ring/tests/testutil.rs
    • Added a test utility file providing a deterministic factory for uselesskey-ring tests.
  • crates/uselesskey-rustcrypto/tests/testutil.rs
    • Added a test utility file providing a deterministic factory for uselesskey-rustcrypto tests.
  • crates/uselesskey-rustls/src/lib.rs
    • Corrected a typo in the rustls adapter, changing private_key_derustls to private_key_der_rustls.
  • crates/uselesskey-x509/Cargo.toml
    • Added uselesskey-jwk, rsa, and base64 as dependencies.
    • Introduced a jwk feature, enabling JWK support for X.509 certificates.
  • crates/uselesskey/Cargo.toml
    • Updated the x509 feature to include uselesskey-x509/jwk, enabling JWK functionality for X.509 certificates.
  • docs/architecture.md
    • Updated the architecture overview to include new X.509 features (cert chains, negative fixtures) and detailed descriptions of new adapter crates (uselesskey-rustls, uselesskey-ring, uselesskey-rustcrypto, uselesskey-aws-lc-rs).
  • docs/migration.md
    • Updated TLS/mTLS testing examples to demonstrate usage of X.509 certificate chains and the uselesskey-rustls adapter.
    • Added new examples for X.509 certificate validation testing, including expired, hostname mismatch, unknown CA, and revoked certificate scenarios.
  • docs/roadmap.md
    • Updated the roadmap to mark numerous items as completed, including X.509 cert chain fixtures, X.509 negative fixtures, uselesskey-rustls, uselesskey-ring, uselesskey-aws-lc-rs, uselesskey-rustcrypto adapter crates, the BDD test suite, and examples.
  • plans/bdd-scenarios-implementation-plan.md
    • Added a new document detailing the implementation plan for expanding BDD scenarios, including new scenarios for RSA, HMAC, X.509, JWKS, JWT integration, TLS integration, and edge cases.
  • plans/bdd-test-coverage-analysis.md
    • Added a new document analyzing current BDD test coverage, identifying gaps, and proposing improvements across various key types and test categories.
  • plans/summary.md
    • Added a new summary document for the BDD test coverage analysis, outlining key findings, resolved gaps, remaining gaps, proposed improvements, and test coverage goals.
  • plans/test-architecture-diagram.md
    • Added a new document providing visual diagrams of the test architecture, including BDD tests, unit tests, adapter tests, integration tests, property tests, and fuzz tests.
  • tests/Cargo.toml
    • Added a new crate for integration tests, defining features for JWT, TLS, crypto-backend, and end-to-end workflows, along with corresponding test targets.
  • tests/crypto_backend_integration.rs
    • Added a new file for crypto backend integration tests, focusing on RSA, ECDSA, and Ed25519 sign/verify operations with the ring backend and verifying deterministic behavior.
  • tests/e2e_workflows.rs
    • Added a new file for end-to-end workflow tests, covering complete JWT, TLS, JWKS building/consumption, certificate chain creation, negative fixture handling, deterministic behavior, and format conversion workflows.
  • tests/jwt_integration.rs
    • Added a new file for JWT integration tests, covering signing/verification for RSA, ECDSA, Ed25519, and HMAC, JWKS multi-key lookup and rotation, cross-crate compatibility, and determinism.
  • tests/testutil.rs
    • Added a new test utility file providing a shared deterministic factory for all integration tests.
  • tests/tls_integration.rs
    • Added a new file for TLS integration tests, covering basic TLS server/client configuration, mTLS scenarios, certificate chain structure and conversions, SANs, deterministic behavior, and negative fixture handling for expired/not-yet-valid certificates.
  • xtask/src/main.rs
    • Added BddMatrix command to run Cucumber BDD tests with different feature sets.
    • Updated ci command to include bdd_matrix in the CI pipeline.
  • xtask/src/plan.rs
    • Modified run_bdd logic to trigger when .feature files within crates/uselesskey/ are changed.
  • xtask/src/receipt.rs
    • Added bdd_matrix field to the Receipt struct to store results of BDD matrix runs.
    • Introduced BddMatrixEntry struct to represent individual entries in the BDD matrix results.
    • Added add_bdd_matrix method to Runner to record BDD matrix test outcomes.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/ci.yml
Activity
  • EffortlessSteven submitted 36 commits, significantly expanding the codebase with new features and tests.
  • All unit and integration tests passed, demonstrating the stability of the new additions.
  • BDD tests passed, though noted that RSA key generation is slow in deterministic mode.
  • Clippy checks passed with zero warnings, indicating high code quality.
  • Some aws-lc-rs integration tests were removed from cross-backend tests due to NASM requirements on Windows, with comprehensive tests moved to the aws-lc-rs adapter crate.
  • Cross-key-type TLS tests were removed due to reliance on a nonexistent x509_self_signed_with_key API.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist 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.

Code Review

This is an impressive pull request that massively expands the test coverage of the project. The addition of comprehensive integration tests for various adapters, new BDD scenarios for numerous features, and end-to-end workflow tests significantly improves the robustness and reliability of the codebase. The documentation updates and xtask enhancements are also valuable contributions. My review identified a few areas for improvement: a bug in a BDD test step that prevents a scenario from being tested correctly, some test code duplication that could affect maintainability, and a logic issue in the xtask CI plan. Overall, this is a high-quality contribution that moves the project forward significantly.

Comment on lines +1620 to +1622
world.x509_chain_sans.push(san.clone());
let spec = X509Spec::self_signed(cn);
let new_x509 = fx.x509_self_signed(label, spec);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The add_san_to_cert function doesn't seem to be correctly applying the Subject Alternative Names (SANs) to the X509Spec. It collects SANs in world.x509_chain_sans but then creates a new X509Spec without using this list. This means the regenerated certificate will not contain the added SANs, and the corresponding test scenarios might not be testing the intended behavior. The spec should be updated with all collected SANs before regenerating the certificate.

Suggested change
world.x509_chain_sans.push(san.clone());
let spec = X509Spec::self_signed(cn);
let new_x509 = fx.x509_self_signed(label, spec);
world.x509_chain_sans.push(san);
let mut spec = X509Spec::self_signed(cn);
spec.sans.extend(world.x509_chain_sans.iter().cloned());
spec.sans.sort();
spec.sans.dedup();
let new_x509 = fx.x509_self_signed(label, spec);

Comment thread tests/jwt_integration.rs
Comment on lines +1 to +553
//! JWT Integration Tests
//!
//! Tests cross-crate JWT functionality:
//! - JWT signing/verification flows across different key types
//! - JWT with JWKS for key lookup
//! - Cross-crate compatibility between uselesskey-jsonwebtoken and other key crates
//! - JWT with different crypto backends (ring, aws-lc-rs, rustcrypto)

mod testutil;

use jsonwebtoken::jwk::Jwk;
use jsonwebtoken::{Algorithm, DecodingKey, Header, Validation, decode, encode};
use serde::{Deserialize, Serialize};
use testutil::fx;
use uselesskey_ed25519::Ed25519Spec;
use uselesskey_jsonwebtoken::JwtKeyExt;
use uselesskey_jwk::JwksBuilder;
use uselesskey_rsa::{RsaFactoryExt, RsaSpec};

#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct JwtClaims {
sub: String,
exp: usize,
iat: usize,
iss: String,
}

impl JwtClaims {
fn new(sub: &str, exp: usize, iat: usize, iss: &str) -> Self {
Self {
sub: sub.to_string(),
exp,
iat,
iss: iss.to_string(),
}
}
}

// =========================================================================
// RSA JWT Integration Tests
// =========================================================================

#[cfg(feature = "jwt")]
mod rsa_jwt_tests {
use super::*;

#[test]
fn test_rsa_rs256_sign_verify() {
let fx = fx();
let keypair = fx.rsa("test-rs256", RsaSpec::rs256());

let claims = JwtClaims::new("user123", 9999999999, 1234567890, "test-issuer");
let header = Header::new(Algorithm::RS256);

let token = encode(&header, &claims, &keypair.encoding_key())
.unwrap_or_else(|e| panic!("Failed to encode with RS256: {:?}", e));

let validation = Validation::new(Algorithm::RS256);
let decoded = decode::<JwtClaims>(&token, &keypair.decoding_key(), &validation)
.unwrap_or_else(|e| panic!("Failed to decode with RS256: {:?}", e));

assert_eq!(decoded.claims, claims);
}

#[test]
fn test_rsa_custom_key_sizes() {
let test_cases = [(2048, "rsa-2048"), (3072, "rsa-3072"), (4096, "rsa-4096")];

for (bits, label) in test_cases {
let fx = fx();
let keypair = fx.rsa(label, RsaSpec::new(bits));

let claims = JwtClaims::new("user123", 9999999999, 1234567890, label);
let header = Header::new(Algorithm::RS256);

let token = encode(&header, &claims, &keypair.encoding_key())
.unwrap_or_else(|e| panic!("Failed to encode with {}-bit key: {:?}", bits, e));

let validation = Validation::new(Algorithm::RS256);
let decoded = decode::<JwtClaims>(&token, &keypair.decoding_key(), &validation)
.unwrap_or_else(|e| panic!("Failed to decode with {}-bit key: {:?}", bits, e));

assert_eq!(
decoded.claims, claims,
"Claims mismatch for {}-bit key",
bits
);
}
}

#[test]
fn test_rsa_algorithm_mismatch_fails() {
let fx = fx();
let keypair = fx.rsa("mismatch-test", RsaSpec::rs256());

let claims = JwtClaims::new("user000", 9999999999, 1234567890, "mismatch-test");
let header = Header::new(Algorithm::RS256);

let token =
encode(&header, &claims, &keypair.encoding_key()).expect("Failed to encode JWT");

// Try to decode with wrong algorithm
let validation = Validation::new(Algorithm::RS384);
let result = decode::<JwtClaims>(&token, &keypair.decoding_key(), &validation);

assert!(result.is_err(), "Should fail with algorithm mismatch");
}
}

// =========================================================================
// ECDSA JWT Integration Tests
// =========================================================================

#[cfg(feature = "jwt")]
mod ecdsa_jwt_tests {
use super::*;
use uselesskey_ecdsa::{EcdsaFactoryExt, EcdsaSpec};

#[test]
fn test_jwt_ecdsa_es256_sign_verify() {
let fx = fx();
let keypair = fx.ecdsa("es256-issuer", EcdsaSpec::Es256);

let claims = JwtClaims::new("user123", 9999999999, 1234567890, "es256-issuer");
let header = Header::new(Algorithm::ES256);

let token = encode(&header, &claims, &keypair.encoding_key())
.expect("Failed to encode JWT with ES256");

let validation = Validation::new(Algorithm::ES256);
let decoded = decode::<JwtClaims>(&token, &keypair.decoding_key(), &validation)
.expect("Failed to decode JWT with ES256");

assert_eq!(decoded.claims, claims);
}

#[test]
fn test_jwt_ecdsa_es384_sign_verify() {
let fx = fx();
let keypair = fx.ecdsa("es384-issuer", EcdsaSpec::Es384);

let claims = JwtClaims::new("user456", 9999999999, 1234567890, "es384-issuer");
let header = Header::new(Algorithm::ES384);

let token = encode(&header, &claims, &keypair.encoding_key())
.expect("Failed to encode JWT with ES384");

let validation = Validation::new(Algorithm::ES384);
let decoded = decode::<JwtClaims>(&token, &keypair.decoding_key(), &validation)
.expect("Failed to decode JWT with ES384");

assert_eq!(decoded.claims, claims);
}

#[test]
fn test_jwt_ecdsa_algorithm_mismatch_fails() {
let fx = fx();
let keypair = fx.ecdsa("es256-mismatch", EcdsaSpec::Es256);

let claims = JwtClaims::new("user000", 9999999999, 1234567890, "es256-mismatch");
let header = Header::new(Algorithm::ES256);

let token =
encode(&header, &claims, &keypair.encoding_key()).expect("Failed to encode JWT");

// Try to decode with wrong algorithm
let validation = Validation::new(Algorithm::ES384);
let result = decode::<JwtClaims>(&token, &keypair.decoding_key(), &validation);

assert!(result.is_err(), "Should fail with algorithm mismatch");
}
}

// =========================================================================
// Ed25519 JWT Integration Tests
// =========================================================================

#[cfg(feature = "jwt")]
mod ed25519_jwt_tests {
use super::*;
use uselesskey_ed25519::Ed25519FactoryExt;

#[test]
fn test_jwt_ed25519_sign_verify() {
let fx = fx();
let keypair = fx.ed25519("ed25519-issuer", Ed25519Spec::new());

let claims = JwtClaims::new("user123", 9999999999, 1234567890, "ed25519-issuer");
let header = Header::new(Algorithm::EdDSA);

let token = encode(&header, &claims, &keypair.encoding_key())
.expect("Failed to encode JWT with Ed25519");

let validation = Validation::new(Algorithm::EdDSA);
let decoded = decode::<JwtClaims>(&token, &keypair.decoding_key(), &validation)
.expect("Failed to decode JWT with Ed25519");

assert_eq!(decoded.claims, claims);
}
}

// =========================================================================
// HMAC JWT Integration Tests
// =========================================================================

#[cfg(feature = "jwt")]
mod hmac_jwt_tests {
use super::*;
use uselesskey_hmac::{HmacFactoryExt, HmacSpec};

#[test]
fn test_jwt_hmac_hs256_sign_verify() {
let fx = fx();
let secret = fx.hmac("hs256-issuer", HmacSpec::Hs256);

let claims = JwtClaims::new("user123", 9999999999, 1234567890, "hs256-issuer");
let header = Header::new(Algorithm::HS256);

let token = encode(&header, &claims, &secret.encoding_key())
.expect("Failed to encode JWT with HS256");

let validation = Validation::new(Algorithm::HS256);
let decoded = decode::<JwtClaims>(&token, &secret.decoding_key(), &validation)
.expect("Failed to decode JWT with HS256");

assert_eq!(decoded.claims, claims);
}

#[test]
fn test_jwt_hmac_hs384_sign_verify() {
let fx = fx();
let secret = fx.hmac("hs384-issuer", HmacSpec::Hs384);

let claims = JwtClaims::new("user456", 9999999999, 1234567890, "hs384-issuer");
let header = Header::new(Algorithm::HS384);

let token = encode(&header, &claims, &secret.encoding_key())
.expect("Failed to encode JWT with HS384");

let validation = Validation::new(Algorithm::HS384);
let decoded = decode::<JwtClaims>(&token, &secret.decoding_key(), &validation)
.expect("Failed to decode JWT with HS384");

assert_eq!(decoded.claims, claims);
}

#[test]
fn test_jwt_hmac_hs512_sign_verify() {
let fx = fx();
let secret = fx.hmac("hs512-issuer", HmacSpec::Hs512);

let claims = JwtClaims::new("user789", 9999999999, 1234567890, "hs512-issuer");
let header = Header::new(Algorithm::HS512);

let token = encode(&header, &claims, &secret.encoding_key())
.expect("Failed to encode JWT with HS512");

let validation = Validation::new(Algorithm::HS512);
let decoded = decode::<JwtClaims>(&token, &secret.decoding_key(), &validation)
.expect("Failed to decode JWT with HS512");

assert_eq!(decoded.claims, claims);
}

#[test]
fn test_jwt_hmac_wrong_secret_fails() {
let fx = fx();
let secret1 = fx.hmac("secret1", HmacSpec::Hs256);
let secret2 = fx.hmac("secret2", HmacSpec::Hs256);

let claims = JwtClaims::new("user000", 9999999999, 1234567890, "secret1");
let header = Header::new(Algorithm::HS256);

let token =
encode(&header, &claims, &secret1.encoding_key()).expect("Failed to encode JWT");

// Try to decode with wrong secret
let validation = Validation::new(Algorithm::HS256);
let result = decode::<JwtClaims>(&token, &secret2.decoding_key(), &validation);

assert!(result.is_err(), "Should fail with wrong secret");
}
}

// =========================================================================
// JWKS Integration Tests
// =========================================================================

#[cfg(feature = "jwt")]
mod jwks_integration_tests {
use super::*;

#[test]
fn test_jwt_jwks_multi_key_lookup() {
let fx = fx();

// Create multiple keys for different issuers
let issuer1 = fx.rsa("issuer1", RsaSpec::rs256());
let issuer2 = fx.rsa("issuer2", RsaSpec::rs256());
let issuer3 = fx.rsa("issuer3", RsaSpec::rs256());

// Build JWKS with all keys
let jwks = JwksBuilder::new()
.add_public(issuer1.public_jwk())
.add_public(issuer2.public_jwk())
.add_public(issuer3.public_jwk())
.build();

// Verify all keys are in JWKS
assert_eq!(jwks.keys.len(), 3);

// Sign JWT with issuer2
let claims = JwtClaims::new("user123", 9999999999, 1234567890, "issuer2");
let mut header = Header::new(Algorithm::RS256);
header.kid = Some(issuer2.kid().to_string());

let token =
encode(&header, &claims, &issuer2.encoding_key()).expect("Failed to encode JWT");

// Find correct key from JWKS by kid
let jwk = jwks
.keys
.iter()
.find(|k| k.kid() == issuer2.kid())
.expect("Key not found in JWKS");

// Convert AnyJwk to jsonwebtoken::Jwk
let jwk_value = serde_json::to_value(jwk).expect("Failed to serialize JWK");
let jwk_json: Jwk = serde_json::from_value(jwk_value).expect("Failed to deserialize JWK");

// Convert JWK to DecodingKey
let decoding_key =
DecodingKey::from_jwk(&jwk_json).expect("Failed to create DecodingKey from JWK");

let validation = Validation::new(Algorithm::RS256);
let decoded = decode::<JwtClaims>(&token, &decoding_key, &validation)
.expect("Failed to decode JWT with JWKS key");

assert_eq!(decoded.claims, claims);
}

#[test]
fn test_jwt_jwks_key_rotation_scenario() {
let fx = fx();

// Old key (still valid for verification)
let old_key = fx.rsa("old-key", RsaSpec::rs256());

// New key (used for signing)
let new_key = fx.rsa("new-key", RsaSpec::rs256());

// Build JWKS with both keys
let jwks = JwksBuilder::new()
.add_public(old_key.public_jwk())
.add_public(new_key.public_jwk())
.build();

// Sign JWT with new key
let claims = JwtClaims::new("user123", 9999999999, 1234567890, "new-key");
let mut header = Header::new(Algorithm::RS256);
header.kid = Some(new_key.kid().to_string());

let token =
encode(&header, &claims, &new_key.encoding_key()).expect("Failed to encode JWT");

// Verify with JWKS (should find new key)
let jwk = jwks
.keys
.iter()
.find(|k| k.kid() == new_key.kid())
.expect("New key not found in JWKS");

// Convert AnyJwk to jsonwebtoken::Jwk
let jwk_value = serde_json::to_value(jwk).expect("Failed to serialize JWK");
let jwk_json: Jwk = serde_json::from_value(jwk_value).expect("Failed to deserialize JWK");

let decoding_key =
DecodingKey::from_jwk(&jwk_json).expect("Failed to create DecodingKey from JWK");

let validation = Validation::new(Algorithm::RS256);
let decoded = decode::<JwtClaims>(&token, &decoding_key, &validation)
.expect("Failed to decode JWT with JWKS key");

assert_eq!(decoded.claims, claims);

// Verify old key is still in JWKS for validating old tokens
assert!(jwks.keys.iter().any(|k| k.kid() == old_key.kid()));
}
}

// =========================================================================
// Cross-Crate Compatibility Tests
// =========================================================================

#[cfg(feature = "jwt")]
mod cross_crate_compatibility_tests {
use super::*;
use uselesskey_ecdsa::{EcdsaFactoryExt, EcdsaSpec};
use uselesskey_ed25519::Ed25519FactoryExt;
use uselesskey_hmac::{HmacFactoryExt, HmacSpec};

#[test]
fn test_all_key_types_produce_valid_jwts() {
let fx = fx();

let test_cases = vec![
("rsa", Algorithm::RS256),
("ecdsa", Algorithm::ES256),
("ed25519", Algorithm::EdDSA),
("hmac", Algorithm::HS256),
];

for (key_type, alg) in test_cases {
let claims = JwtClaims::new(
"user123",
9999999999,
1234567890,
&format!("{}-issuer", key_type),
);
let header = Header::new(alg);

let token = match key_type {
"rsa" => {
let keypair = fx.rsa("rsa-issuer", RsaSpec::rs256());
encode(&header, &claims, &keypair.encoding_key())
}
"ecdsa" => {
let keypair = fx.ecdsa("ecdsa-issuer", EcdsaSpec::Es256);
encode(&header, &claims, &keypair.encoding_key())
}
"ed25519" => {
let keypair = fx.ed25519("ed25519-issuer", Ed25519Spec::new());
encode(&header, &claims, &keypair.encoding_key())
}
"hmac" => {
let secret = fx.hmac("hmac-issuer", HmacSpec::Hs256);
encode(&header, &claims, &secret.encoding_key())
}
_ => panic!("Unknown key type: {}", key_type),
}
.unwrap_or_else(|e| panic!("Failed to encode JWT with {}: {:?}", key_type, e));

// Verify token can be decoded
let validation = Validation::new(alg);
let decoded = match key_type {
"rsa" => {
let keypair = fx.rsa("rsa-issuer", RsaSpec::rs256());
decode::<JwtClaims>(&token, &keypair.decoding_key(), &validation)
}
"ecdsa" => {
let keypair = fx.ecdsa("ecdsa-issuer", EcdsaSpec::Es256);
decode::<JwtClaims>(&token, &keypair.decoding_key(), &validation)
}
"ed25519" => {
let keypair = fx.ed25519("ed25519-issuer", Ed25519Spec::new());
decode::<JwtClaims>(&token, &keypair.decoding_key(), &validation)
}
"hmac" => {
let secret = fx.hmac("hmac-issuer", HmacSpec::Hs256);
decode::<JwtClaims>(&token, &secret.decoding_key(), &validation)
}
_ => panic!("Unknown key type: {}", key_type),
}
.unwrap_or_else(|e| panic!("Failed to decode JWT with {}: {:?}", key_type, e));

assert_eq!(decoded.claims, claims);
}
}

#[test]
fn test_key_id_consistency_across_formats() {
let fx = fx();
let keypair = fx.rsa("kid-test", RsaSpec::rs256());

// Verify kid is consistent across different formats
let kid_from_keypair = keypair.kid();
let public_jwk = keypair.public_jwk();
let kid_from_jwk = public_jwk.kid();
let public_jwks = keypair.public_jwks();
let kid_from_jwks = public_jwks.keys[0].kid();

assert_eq!(kid_from_keypair, kid_from_jwk);
assert_eq!(kid_from_keypair, kid_from_jwks);
}
}

// =========================================================================
// Determinism Tests
// =========================================================================

#[cfg(feature = "jwt")]
mod determinism_tests {
use super::*;

#[test]
fn test_deterministic_keys_produce_same_jwts() {
let fx1 = fx();
let fx2 = fx();

// Generate same key from same seed
let keypair1 = fx1.rsa("deterministic-jwt", RsaSpec::rs256());
let keypair2 = fx2.rsa("deterministic-jwt", RsaSpec::rs256());

// Sign same claims with both keys
let claims = JwtClaims::new("user123", 9999999999, 1234567890, "deterministic-jwt");
let header = Header::new(Algorithm::RS256);

let token1 =
encode(&header, &claims, &keypair1.encoding_key()).expect("Failed to encode JWT 1");
let token2 =
encode(&header, &claims, &keypair2.encoding_key()).expect("Failed to encode JWT 2");

// Tokens should be identical (same key + same claims)
assert_eq!(
token1, token2,
"Deterministic keys should produce identical JWTs"
);

// Verify both tokens decode correctly
let validation = Validation::new(Algorithm::RS256);
let decoded1 = decode::<JwtClaims>(&token1, &keypair1.decoding_key(), &validation)
.expect("Failed to decode JWT 1");
let decoded2 = decode::<JwtClaims>(&token2, &keypair2.decoding_key(), &validation)
.expect("Failed to decode JWT 2");

assert_eq!(decoded1.claims, claims);
assert_eq!(decoded2.claims, claims);
}

#[test]
fn test_different_labels_produce_different_jwts() {
let fx = fx();

// Generate keys with different labels
let keypair1 = fx.rsa("label-1", RsaSpec::rs256());
let keypair2 = fx.rsa("label-2", RsaSpec::rs256());

// Sign same claims with both keys
let claims = JwtClaims::new("user123", 9999999999, 1234567890, "test");
let header = Header::new(Algorithm::RS256);

let token1 =
encode(&header, &claims, &keypair1.encoding_key()).expect("Failed to encode JWT 1");
let token2 =
encode(&header, &claims, &keypair2.encoding_key()).expect("Failed to encode JWT 2");

// Tokens should be different (different keys)
assert_ne!(
token1, token2,
"Different labels should produce different JWTs"
);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This file appears to be a duplicate of crates/uselesskey-jsonwebtoken/tests/jwt_comprehensive.rs. This duplication can increase maintenance overhead. It would be beneficial to consolidate these tests into a single location, either within the uselesskey-jsonwebtoken crate's tests directory or in this workspace-level tests crate, to avoid having to update two files for any changes.

Comment thread xtask/src/plan.rs
|| paths.iter().any(|p| {
let p = normalize_path(p);
p.starts_with("crates/uselesskey/")
&& (p.ends_with(".feature") && p.contains("features/"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The logic for determining when to run the feature matrix seems incorrect. The condition p.starts_with("crates/uselesskey/") && (p.ends_with(".feature") && p.contains("features/")) will likely never be true, as BDD .feature files are located in crates/uselesskey-bdd/features/, not crates/uselesskey/. This makes the condition confusing. If the intent is to run the feature matrix only when Cargo.toml or Cargo.lock files change (covered by cargo_changed), then the second part of the || expression could be removed for clarity.

@EffortlessSteven EffortlessSteven merged commit 106a04e into main Feb 12, 2026
9 of 10 checks passed
EffortlessSteven added a commit that referenced this pull request May 11, 2026
Shipper 0.3.0-rc.2 emits the publish plan in alphabetical-looking order
rather than topological order (EffortlessMetrics/shipper#173). With
\`uselesskey-aws-lc-rs\` at position 1 and \`uselesskey-core\` at #2,
shipper's linear walk fails immediately because cargo publish of
aws-lc-rs requires uselesskey-ecdsa (#22) and other deps to already be
on crates.io.

The owner of shipper will fix this in the next patch. Until then,
revert both \`release.yml\` and \`publish-retry.yml\` to use
\`cargo xtask publish\`. The PUBLISH_CRATES order is correct after #565,
and the test-helper dev-dep fix in #569 removes the cargo verification
gap that the original cargo xtask path also tripped over.

Keep \`.shipper/\` in \`.gitignore\` and the existing \`Quality gate\` /
\`Publish preflight\` / \`Publish dry-run\` steps in preflight job —
those are unaffected by the shipper revert and still useful.

After this PR merges, retag v0.7.0 on the new main HEAD and let
\`release.yml\` run end-to-end. shipper#173 stays open for the next
release cycle.
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