这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

@tolgaozen
Copy link
Member

@tolgaozen tolgaozen commented Nov 14, 2025

Summary by CodeRabbit

  • New Features

    • Restored CLI commands: Migrate, Version, Config and Repair are now available.
  • Bug Fixes

    • Added database version compatibility validation to prevent issues with unsupported servers.
  • Tests

    • Expanded OpenID Connect authentication tests with realistic provider behavior and retry/backoff scenarios.
    • Improved in-memory storage tests with full write-read-delete verification.
  • Refactor

    • Reworked coverage analysis into modular pipeline stages and simplified service/config initialization.

@coderabbitai
Copy link

coderabbitai bot commented Nov 14, 2025

Walkthrough

This pull request restores CLI command registration (adds NewMigrateCommand, NewVersionCommand, NewConfigCommand, NewRepairCommand), renames NewGenerateASTCommand → NewGenerateAstCommand, expands the OpenID Authn struct with JWKS/jwt parser and backoff/retry fields, implements/rewrites extensive tests and fakes for OIDC and in-memory storage, refactors coverage computation into modular functions, and adds a Postgres version compatibility check in the database factory.

Changes

Cohort / File(s) Summary
CLI Root & Command Constructors
cmd/permify/permify.go, pkg/cmd/ast.go
Restores and reorders command registrations; adds uses of NewMigrateCommand, NewVersionCommand, NewConfigCommand, NewRepairCommand; renames NewGenerateASTCommandNewGenerateAstCommand and corresponding run helper names.
CLI Implementations & Flags
pkg/cmd/config.go, pkg/cmd/version.go, pkg/cmd/coverage.go, pkg/cmd/serve.go, pkg/cmd/flags/coverage.go
Formatting/import reorgs and refactors for config loading, logger/tracer/meter setup, and coverage flag bindings; no behavioral API changes.
OpenID Authn Core
internal/authn/openid/authn.go
Expands Authn struct with fields: jwksSet *jwk.AutoRefresh, validMethods []string, jwtParser *jwt.Parser, backoffInterval time.Duration, backoffMaxRetries int, backoffFrequency time.Duration, globalRetryCount int, globalFirstSeen time.Time, retriedKeys map[string]bool, mutex sync.Mutex.
OpenID Tests & Fakes
internal/authn/openid/authn_test.go, internal/authn/openid/fakes_test.go
Rewrites tests to use Ginkgo/Gomega, implements a functional fake OIDC provider (keys, JWKS, discovery endpoints, signing, UpdateKeyID, HTTP helpers), and reorganizes test scenarios including backoff/retry and config error cases.
Database Factory / Postgres Check
internal/factories/database.go
Adds Postgres version compatibility validation via utils.EnsureDBVersion(...) and returns error on mismatch.
In-Memory Storage: Implementation & Tests
internal/storage/memory/bundle_reader.go, internal/storage/memory/bundle_reader_test.go, internal/storage/memory/bundle_writer.go, internal/storage/memory/bundle_writer_test.go, internal/storage/memory/memory_test.go
Implements concrete Read/Write tests against in-memory DB, updates Write/Delete transaction structure, makes isSameArray order-insensitive, and refactors test scaffolding into executed flows.
Storage/Postgres Refactors & Migrations
internal/storage/postgres/data_writer.go, internal/storage/migration.go, internal/storage/memory/migrations/schema.go, internal/storage/memory/constants/constants.go, internal/storage/memory/data_writer.go
Mostly formatting/comment cleanup; removes inline comments and tidies helper functions; no behavioral changes except context param marked unused in one function.
Servers & Misc Formatting
internal/servers/schema_server.go, internal/servers/server.go, internal/config/config.go, internal/config/config_test.go
Minor formatting/comment adjustments, repositioned httpNameFormatter, and small test formatting cleanups; no API changes.
Coverage Analysis Refactor
pkg/development/coverage/coverage.go
Replaces monolithic coverage calculation with a staged pipeline of helper functions (parse/compile, extract refs, calculate entity coverages, format helpers) while preserving public result types.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Authn as OpenID Authn
    participant AutoRefresh as JWKS AutoRefresh
    participant JWKS as JWKS Provider

    Client->>Authn: Validate token request
    Authn->>Authn: Check cached keys & retriedKeys

    alt Key not cached
        Authn->>AutoRefresh: Trigger fetch
        AutoRefresh->>JWKS: GET /.well-known/jwks.json
        JWKS-->>AutoRefresh: JWKS response
        AutoRefresh-->>Authn: Updated jwksSet
    else Key cached
        Note right of Authn: Use cached keys (fast path)
    end

    Authn->>Authn: Parse token with jwtParser
    Authn->>Authn: Validate claims (iss, aud, exp, iat, nbf)
    alt Valid
        Authn-->>Client: Success
    else Invalid / kid mismatch
        Authn-->>Client: Error (may trigger backoff/retry)
        Note right of Authn: Increment globalRetryCount, apply backoffInterval
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay extra attention to:
    • internal/authn/openid/authn.go — new fields and how JWKS auto-refresh, jwt.Parser, and backoff state interact with existing flows.
    • internal/authn/openid/fakes_test.go — correctness of fake OIDC provider, signing logic, JWKS serving, and concurrency (UpdateKeyID).
    • internal/factories/database.go — Postgres version check integration and error handling semantics.
    • pkg/development/coverage/coverage.go — new helper functions and aggregate correctness of coverage calculations.

Possibly related PRs

Poem

🐇 I hopped through code to mend the trail,

Commands aligned, no more derail.
JWKS keys now dance with care,
Backoff counts and parsers there.
Tests and coverage bloom in spring —
A rabbit's cheer for fresh new string! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title is specific and accurately describes the primary change: restoring and streamlining CLI command registrations in the main entry point file (cmd/permify/permify.go).
Docstring Coverage ✅ Passed Docstring coverage is 84.21% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/update-cli-commands

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

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/storage/postgres/data_writer.go (1)

119-119: Inconsistent log level for max retries exceeded condition.

Line 119 uses slog.DebugContext for the "max retries reached" error, but the identical error condition at line 79 (in the Write method) uses slog.ErrorContext. This inconsistency in severity reporting could mask failures during troubleshooting. Both should use the same log level for consistency.

Suggested fix:

-	slog.DebugContext(ctx, "max retries reached", slog.Any("error", errors.New(base.ErrorCode_ERROR_CODE_ERROR_MAX_RETRIES.String())))
+	slog.ErrorContext(ctx, "max retries reached", slog.Any("error", errors.New(base.ErrorCode_ERROR_CODE_ERROR_MAX_RETRIES.String())))
🧹 Nitpick comments (3)
internal/storage/postgres/data_writer.go (1)

522-522: Remove redundant inline comment.

The comment // Build delete clauses at the end of line 522 is redundant with the function name buildDeleteClausesForAttributes. Inline comments should convey non-obvious intent rather than repeating what the code already states.

Suggested fix:

-func buildDeleteClausesForAttributes(attributeCollection *database.AttributeCollection) []squirrel.Eq { // Build delete clauses
+func buildDeleteClausesForAttributes(attributeCollection *database.AttributeCollection) []squirrel.Eq {
pkg/development/coverage/coverage.go (1)

301-336: Total coverage aggregation is correct, with minor naming clarity opportunity.

The averaging logic is sound: it sums per-entity coverage percentages and divides by entity count (or by entity+scenario count for assertions) to compute the total. The zero-division guards are appropriate.

One minor note: variable names in calculateTotalCoverage could be clearer. For example, totalRelationships actually counts the number of entities (or entity+scenario pairs), not the number of relationships. Renaming to relationshipEntityCount or similar would improve readability, but this is a nice-to-have.

pkg/cmd/serve.go (1)

210-218: Consider extracting duplicated header parsing logic.

The header parsing logic (splitting by ":" and validating format) is duplicated across log, tracer, and meter configuration. Extracting this into a helper function would improve maintainability.

Example helper function:

// parseHeaders converts a slice of "key:value" strings into a map
func parseHeaders(headers []string) (map[string]string, error) {
    result := map[string]string{}
    for _, header := range headers {
        parts := strings.Split(header, ":")
        if len(parts) != 2 {
            return nil, errors.New("invalid header format; expected 'key:value'")
        }
        result[parts[0]] = parts[1]
    }
    return result, nil
}

Then use it as:

headers, err := parseHeaders(cfg.Log.Headers)
if err != nil {
    return err
}

Also applies to: 282-289, 336-344

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19935ce and e2f9878.

📒 Files selected for processing (26)
  • cmd/permify/permify.go (1 hunks)
  • internal/authn/openid/authn.go (10 hunks)
  • internal/authn/openid/authn_test.go (25 hunks)
  • internal/authn/openid/fakes_test.go (1 hunks)
  • internal/config/config.go (1 hunks)
  • internal/config/config_test.go (3 hunks)
  • internal/factories/database.go (1 hunks)
  • internal/servers/schema_server.go (1 hunks)
  • internal/servers/server.go (1 hunks)
  • internal/storage/memory/bundle_reader.go (1 hunks)
  • internal/storage/memory/bundle_reader_test.go (1 hunks)
  • internal/storage/memory/bundle_writer.go (1 hunks)
  • internal/storage/memory/bundle_writer_test.go (1 hunks)
  • internal/storage/memory/constants/constants.go (1 hunks)
  • internal/storage/memory/data_writer.go (1 hunks)
  • internal/storage/memory/memory_test.go (1 hunks)
  • internal/storage/memory/migrations/schema.go (3 hunks)
  • internal/storage/migration.go (1 hunks)
  • internal/storage/postgres/data_writer.go (1 hunks)
  • pkg/cmd/ast.go (2 hunks)
  • pkg/cmd/config.go (4 hunks)
  • pkg/cmd/coverage.go (2 hunks)
  • pkg/cmd/flags/coverage.go (1 hunks)
  • pkg/cmd/serve.go (7 hunks)
  • pkg/cmd/version.go (1 hunks)
  • pkg/development/coverage/coverage.go (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (13)
internal/storage/memory/migrations/schema.go (1)
internal/storage/memory/constants/constants.go (2)
  • TenantsTable (8-8)
  • BundlesTable (9-9)
pkg/cmd/coverage.go (1)
pkg/development/coverage/coverage.go (1)
  • Run (74-84)
internal/storage/memory/bundle_writer.go (3)
internal/storage/memory/constants/constants.go (1)
  • BundlesTable (9-9)
pkg/database/memory/memory.go (1)
  • New (20-25)
pkg/pb/base/v1/errors.pb.go (2)
  • ErrorCode_ERROR_CODE_EXECUTION (87-87)
  • ErrorCode_ERROR_CODE_BUNDLE_NOT_FOUND (78-78)
internal/servers/schema_server.go (1)
pkg/database/pagination.go (2)
  • NewPagination (27-36)
  • Size (7-11)
internal/storage/memory/bundle_writer_test.go (5)
pkg/database/memory/memory.go (1)
  • Memory (11-17)
internal/storage/memory/bundle_writer.go (2)
  • BundleWriter (14-16)
  • NewBundleWriter (18-22)
internal/storage/memory/bundle_reader.go (2)
  • BundleReader (14-16)
  • NewBundleReader (18-22)
internal/storage/memory/migrations/schema.go (1)
  • Schema (10-181)
pkg/pb/base/v1/errors.pb.go (1)
  • ErrorCode_ERROR_CODE_BUNDLE_NOT_FOUND (78-78)
internal/storage/memory/bundle_reader_test.go (5)
pkg/database/memory/memory.go (1)
  • Memory (11-17)
internal/storage/memory/bundle_writer.go (2)
  • BundleWriter (14-16)
  • NewBundleWriter (18-22)
internal/storage/memory/bundle_reader.go (2)
  • BundleReader (14-16)
  • NewBundleReader (18-22)
internal/storage/memory/migrations/schema.go (1)
  • Schema (10-181)
pkg/pb/base/v1/errors.pb.go (1)
  • ErrorCode_ERROR_CODE_BUNDLE_NOT_FOUND (78-78)
pkg/cmd/version.go (1)
internal/info.go (1)
  • Version (26-26)
pkg/cmd/serve.go (8)
internal/config/config.go (8)
  • Config (15-26)
  • NewConfigWithFile (237-272)
  • NewConfig (201-232)
  • Log (89-99)
  • Database (160-178)
  • Tracer (102-110)
  • GarbageCollection (180-185)
  • Meter (113-122)
pkg/telemetry/log.go (1)
  • HandlerFactory (26-35)
internal/factories/database.go (1)
  • DatabaseFactory (32-82)
pkg/telemetry/logexporters/factory.go (1)
  • ExporterFactory (10-17)
pkg/telemetry/meterexporters/factory.go (1)
  • ExporterFactory (10-19)
pkg/telemetry/tracerexporters/factory.go (1)
  • ExporterFactory (10-25)
internal/storage/postgres/gc/gc.go (1)
  • NewGC (31-45)
pkg/telemetry/meter.go (1)
  • NewMeter (25-62)
internal/factories/database.go (2)
internal/storage/postgres/utils/common.go (1)
  • EnsureDBVersion (214-224)
pkg/database/postgres/postgres.go (1)
  • Postgres (22-35)
internal/storage/postgres/data_writer.go (4)
pkg/database/postgres/xid8.go (1)
  • XID8 (10-10)
pkg/tuple/tuple.go (1)
  • ELLIPSIS (19-19)
internal/storage/memory/constants/constants.go (2)
  • RelationTuplesTable (5-5)
  • AttributesTable (6-6)
internal/storage/postgres/utils/common.go (1)
  • ActiveRecordTxnID (32-32)
pkg/development/coverage/coverage.go (6)
pkg/pb/base/v1/base.pb.go (15)
  • Attributes (1710-1715)
  • Attributes (1728-1728)
  • Attributes (1743-1745)
  • EntityDefinition (815-829)
  • EntityDefinition (842-842)
  • EntityDefinition (857-859)
  • Tuple (1543-1550)
  • Tuple (1563-1563)
  • Tuple (1578-1580)
  • Attribute (1604-1611)
  • Attribute (1624-1624)
  • Attribute (1639-1641)
  • Entity (1755-1761)
  • Entity (1774-1774)
  • Entity (1789-1791)
pkg/development/file/shape.go (1)
  • Shape (4-18)
pkg/dsl/parser/parser.go (1)
  • NewParser (59-78)
pkg/dsl/compiler/compiler.go (1)
  • NewCompiler (25-30)
pkg/tuple/tuple.go (2)
  • Tuple (160-182)
  • E (215-234)
pkg/attribute/attribute.go (1)
  • Attribute (22-131)
cmd/permify/permify.go (1)
pkg/cmd/ast.go (1)
  • NewGenerateAstCommand (21-37)
internal/authn/openid/authn.go (2)
internal/config/config.go (1)
  • Authn (59-64)
pkg/pb/base/v1/errors.pb.go (5)
  • ErrorCode_ERROR_CODE_MISSING_BEARER_TOKEN (29-29)
  • ErrorCode_ERROR_CODE_INVALID_BEARER_TOKEN (35-35)
  • ErrorCode_ERROR_CODE_INVALID_CLAIMS (33-33)
  • ErrorCode_ERROR_CODE_INVALID_ISSUER (34-34)
  • ErrorCode_ERROR_CODE_INVALID_AUDIENCE (32-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Test with Coverage
  • GitHub Check: Analyze (go)
  • GitHub Check: Test with Coverage
🔇 Additional comments (47)
internal/storage/postgres/data_writer.go (1)

432-535: Batch operation refactoring looks solid.

The refactored batch operation helpers maintain correct transaction semantics and error handling. The queueing pattern (batching SQL operations then executing in a single round-trip) is appropriate for PostgreSQL performance. Retry logic with serialization error detection and backoff across Write, Delete, and RunBundle methods is consistently applied and well-structured.

pkg/development/coverage/coverage.go (5)

1-70: Solid structural foundation for the modular refactoring.

Imports and type definitions are clean and appropriate. The documentation in SchemaCoverage is clear and helpful for understanding the coverage concept. No concerns.


72-99: Error handling pattern acceptable but worth noting.

Line 76: When schema parsing or compilation fails, Run silently returns an empty SchemaCoverageInfo{}. This prevents error propagation to the caller, making it impossible to distinguish between legitimate empty coverage and a schema error. For coverage analysis (an auxiliary feature), this is acceptable; however, if robust error diagnostics are needed, consider returning an error as well (e.g., (SchemaCoverageInfo, error)).


101-162: Extract functions are well-decomposed and consistent.

The extraction functions form a clean pipeline: schema definitions → per-entity references → per-type references. Each function has a single responsibility, and the use of format helpers ensures consistency. No concerns.


164-299: Coverage calculation logic is sound and properly defensive.

The per-entity coverage calculation is straightforward and correct. The zero-division guards in calculateCoveragePercent and calculateAverageCoverage are appropriate. The conditional check on line 211–213 (only adding uncovered assertions if non-empty) is a nice touch that avoids unnecessary map entries. Initialization via newEntityCoverageInfo() ensures all fields are safe. No concerns.


338-437: Extraction and formatting functions are robust and consistent.

The covered-extraction functions use a sensible continue-on-error pattern to gracefully skip invalid tuples, attributes, or entities. Format helpers are simple and reusable. Line 423–425 in formatRelationship correctly handles the optional subject relation. No concerns.


Summary

Your refactoring of the coverage analysis into a modular, staged pipeline is well-executed. The code is clean, readable, and maintainable. Here are the key takeaways:

Strengths:

  • Excellent decomposition into focused, single-responsibility functions
  • Consistent error handling throughout (parse/compile errors, malformed tuple/attribute parsing)
  • Defensive initialization via newEntityCoverageInfo() prevents nil issues
  • Smart conditional on line 211–213 avoids unnecessary map entries
  • Format helpers ensure consistent string representation

⚠️ Minor observation (optional refactor):

  • Variable names in calculateTotalCoverage (lines 313–322) could be clearer; consider renaming totalRelationships to reflect that it counts entities, not relationships.

No critical or major issues detected. The code is production-ready.

internal/config/config.go (1)

69-69: LGTM!

The removal of the trailing comment improves code consistency and readability without affecting functionality.

pkg/cmd/version.go (1)

1-21: LGTM!

The formatting improvements enhance code organization and readability. The function implementation remains correct and unchanged functionally.

internal/storage/memory/migrations/schema.go (1)

151-181: LGTM!

The formatting realignment improves code consistency without altering the table definitions or schema structure.

internal/servers/server.go (1)

398-408: LGTM!

The addition of a descriptive comment and improved spacing enhances code clarity. The function behavior remains unchanged.

pkg/cmd/coverage.go (1)

1-161: LGTM!

The import organization and formatting improvements enhance code readability. The coverage analysis logic, validation flow, and threshold enforcement remain functionally unchanged.

internal/storage/memory/memory_test.go (1)

16-36: LGTM!

The refactored isSameArray function now performs an order-insensitive comparison by sorting copies of the input slices. This is a more robust approach for test assertions where element order doesn't matter.

internal/servers/schema_server.go (1)

229-258: LGTM!

The formatting improvements (removal of trailing inline comments and spacing adjustments) enhance code cleanliness without affecting the RPC logic or behavior.

internal/config/config_test.go (1)

171-221: LGTM!

The removal of trailing end-of-block comments improves code cleanliness. The test logic and assertions remain unchanged.

internal/storage/memory/constants/constants.go (1)

1-10: LGTM! Clean formatting update.

The comment clarification and formatting improvements enhance readability without affecting functionality.

internal/storage/memory/bundle_writer.go (2)

24-38: LGTM! Improved transaction handling.

The Write method now correctly collects bundle names during insertion and commits the transaction, which aligns with the method signature returning []string.


40-58: LGTM! Consistent transaction management.

The Delete method properly checks for bundle existence, returns a specific error when not found, and commits the transaction before returning.

internal/storage/memory/bundle_reader.go (1)

24-41: LGTM! Formatting improvement.

The added whitespace improves code readability without changing functionality.

pkg/cmd/flags/coverage.go (1)

1-19: LGTM! Clean formatting update.

Comment cleanup improves readability while preserving all flag binding functionality.

internal/factories/database.go (1)

64-69: LGTM! Important version validation added.

Adding the Postgres version compatibility check early in the database initialization flow is a good practice. This ensures unsupported database versions are caught before any operations are performed.

pkg/cmd/serve.go (3)

159-181: LGTM! Clearer configuration loading flow.

The refactored config loading logic with explicit branching for file vs. environment sources improves readability and maintains consistent error handling.


192-240: LGTM! Well-structured logger initialization.

The switch-based output selection and Fanout strategy for combining multiple handlers provide a clean, maintainable approach to logger configuration.


263-265: LGTM! Consistent error logging.

Error logging has been standardized across database operations, improving observability.

Also applies to: 271-272, 276-277

internal/storage/migration.go (1)

48-53: LGTM! Comment cleanup.

Removing redundant inline comments improves code clarity.

internal/storage/memory/data_writer.go (2)

139-163: LGTM! Improved bundle operation handling.

The RunBundle method now correctly iterates through all operations, processes each one, and commits the transaction before returning the snapshot token. The error handling is appropriate throughout.


166-172: LGTM! Explicit unused parameter.

Renaming the context parameter to _ clearly indicates it's intentionally unused in this in-memory implementation, which is a good practice for code clarity.

internal/storage/memory/bundle_writer_test.go (3)

21-33: LGTM! Clean test setup with proper resource management.

The BeforeEach/AfterEach pattern ensures each test starts with a fresh database and properly releases resources.


36-154: Good test coverage of write and update scenarios.

The test validates both initial writes and overwrites, including the important case where attributes are removed (empty arrays). The assertions at lines 152-153 correctly verify that the empty arrays replaced the previous non-empty values.


158-227: LGTM! Comprehensive deletion test.

The test properly validates:

  • Bundle deletion succeeds
  • Reading deleted bundle returns the expected BUNDLE_NOT_FOUND error
  • Other bundles remain unaffected
pkg/cmd/config.go (1)

18-117: LGTM! No functional changes detected.

The refactoring maintains the existing behavior while improving code organization. The command constructor and flag setup remain semantically identical.

internal/storage/memory/bundle_reader_test.go (3)

22-33: LGTM! Consistent test setup pattern.

The BeforeEach/AfterEach pattern matches the writer test, ensuring proper initialization and cleanup.


36-93: Good end-to-end validation.

The test validates the complete write-then-read flow with proper assertions on all bundle properties including relationships, attributes, and their operations.


95-100: LGTM! Proper error handling test.

Correctly validates that reading a non-existent bundle returns the expected BUNDLE_NOT_FOUND error.

pkg/cmd/ast.go (1)

21-37: LGTM! Consistent naming convention.

The rename from NewGenerateASTCommand to NewGenerateAstCommand aligns with Go's MixedCaps convention for acronyms in identifiers.

cmd/permify/permify.go (1)

15-56: LGTM! Clean and consistent command registration.

The refactoring achieves the PR objective by establishing a clear, uniform pattern for CLI command registration. All commands (serve, validate, coverage, ast, migrate, version, config, repair) are now registered consistently.

internal/authn/openid/authn.go (4)

24-49: LGTM! Well-documented struct expansion.

The new fields support JWKS auto-refresh and backoff/retry logic. Good inline documentation explains each field's purpose. The mutex ensures thread-safe access to shared retry state.


52-106: LGTM! Thorough configuration validation.

The constructor properly validates all backoff configuration parameters (lines 68-81), ensuring they are positive values before use. The immediate JWKS fetch (lines 101-103) validates connectivity during initialization.


327-397: LGTM! Comprehensive HTTP error handling.

The doHTTPRequest and parseOIDCConfiguration functions include proper:

  • Status code validation (line 378)
  • Required field validation (lines 412-420)
  • Error wrapping with context

169-278: No issues found - test coverage validates all concerns.

The test file includes comprehensive concurrent testing:

  • Case 4 (line 401) tests concurrent requests with sync.WaitGroup, sending multiple goroutines with invalid keys simultaneously
  • State reset logic (lines 220-223 in authn.go) is validated: the test verifies that valid keys successfully authenticate and trigger global state reset during the backoff period
  • Race condition handling (lines 247-253) is covered by concurrent retry scenarios, ensuring snapshot comparison works correctly when multiple goroutines refresh JWKS

All three concerns raised in the review are properly addressed by existing tests. The retry logic implementation is sound.

internal/authn/openid/fakes_test.go (2)

46-88: LGTM! Comprehensive test provider setup.

The fake OIDC provider properly initializes cryptographic keys (RSA, ECDSA, HMAC) and constructs a valid JWKS. The signingKeyMap and mutex ensure thread-safe key management.


146-155: LGTM! Thread-safe key ID updates.

The UpdateKeyID method properly uses mutex lock/unlock to safely update both the signingKeyMap and JWKS entries, preventing race conditions during concurrent access.

internal/authn/openid/authn_test.go (6)

31-50: LGTM! Proper test fixture setup.

The BeforeEach initializes a fake OIDC provider and test server on a fixed address. AfterEach properly closes the server to prevent resource leaks.


52-105: LGTM! Clear signing method validation.

The test validates RS256 signing with proper token creation, authentication, and error checking. The test structure is clear and maintainable.


324-399: Excellent backoff behavior validation.

This test (Case 3) thoroughly validates:

  • Maximum retry attempts with proper timing (lines 377-379)
  • Immediate rejection during backoff period (lines 382-385)
  • State reset after backoff interval expires (lines 388-397)

The timing assertions ensure the backoff logic works as designed.


401-509: Comprehensive concurrent backoff test.

This test validates complex concurrent scenarios:

  • Multiple goroutines triggering retries simultaneously (lines 444-457)
  • Immediate rejection during backoff (lines 463-471)
  • Valid keys continuing to work (lines 474-481)
  • Invalid keys remaining blocked (lines 485-493)
  • Behavior after backoff expiration (lines 497-508)

Excellent coverage of the global backoff state management.


682-736: Good context cancellation test.

The test properly validates that context cancellation during retry is handled gracefully. The use of goroutines and channels (lines 711-716) correctly simulates concurrent cancellation scenarios.


895-917: LGTM! Clean claims override helper.

The claimOverride function provides a clear way to selectively override JWT claims for negative testing scenarios, checking each field before overriding.

Copy link

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

🧹 Nitpick comments (1)
internal/authn/openid/fakes_test.go (1)

51-59: Consider removing unused cryptographic keys.

The PS-RSA key (lines 51-54), ECDSA key (lines 55-58), and HMAC key (line 59) are generated but never used, since SignIDToken only implements RS256 and the JWKS only contains the RS256 public key. If these keys are intended for future algorithm support, consider adding a TODO comment; otherwise, remove them to simplify the test setup.

Diff to remove unused keys
-	rsaPrivateKeyForPS, err := rsa.GenerateKey(rand.Reader, 2048)
-	if err != nil {
-		return nil, fmt.Errorf("failed to generate RSA key for PS: %w", err)
-	}
-	ecdsaPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
-	if err != nil {
-		return nil, fmt.Errorf("failed to generate ECDSA key: %w", err)
-	}
-	hmacKey := []byte("hmackeysecret")
 
 	// Initialize signing key mapping
 	signingKeyMap := map[jwt.SigningMethod]string{
 		jwt.SigningMethodRS256: "rs256keyid",
 	}
 	jwks := []jose.JSONWebKey{
 		{
 			Key:       rsaPrivateKey.Public(),
 			KeyID:     signingKeyMap[jwt.SigningMethodRS256],
 			Algorithm: "RS256",
 			Use:       "sig",
 		},
 	}
 	return &fakeOidcProvider{
 		issuerURL:          config.IssuerURL,
 		authPath:           config.AuthPath,
 		tokenPath:          config.TokenPath,
 		userInfoPath:       config.UserInfoPath,
 		JWKSPath:           config.JWKSPath,
 		algorithms:         config.Algorithms,
 		rsaPrivateKey:      rsaPrivateKey,
-		rsaPrivateKeyForPS: rsaPrivateKeyForPS,
-		hmacKey:            hmacKey,
 		jwks:               jwks,
-		ecdsaPrivateKey:    ecdsaPrivateKey,
 		signingKeyMap:      signingKeyMap,
-		mu:                 sync.RWMutex{},
+		mu:                 sync.RWMutex{}, // or just omit; zero value is fine
 	}, nil
 }

Also applies to: 80-85

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e2f9878 and bdf992d.

📒 Files selected for processing (1)
  • internal/authn/openid/fakes_test.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Test with Coverage
  • GitHub Check: Analyze (go)
  • GitHub Check: Test with Coverage
🔇 Additional comments (1)
internal/authn/openid/fakes_test.go (1)

158-170: Good fix from previous review.

The error message now accurately reflects that only RS256 is implemented in the test fake (line 168), addressing the previous review concern about inconsistency.

@tolgaozen tolgaozen merged commit d0dd8df into master Nov 14, 2025
15 checks passed
@tolgaozen tolgaozen deleted the feature/update-cli-commands branch November 14, 2025 15:00
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