-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
test: add tests #10189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
test: add tests #10189
Conversation
ArtifactsThese changes are published for testing on Buildkite, DockerHub and GitHub Container Registry. Docker Container
|
️✅ There are no secrets present in this pull request anymore.If these secrets were true positive and are still valid, we highly recommend you to revoke them. 🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request. |
WalkthroughRefactors provider wiring: Clock and Random moved into Providers with ServiceContext accessors; many call sites switched from direct clock fields to ctx.GetClock()/ctx.GetRandom(); random.New() constructor added and used; clock gained JWT time-fn option; Duo provider signatures and error handling updated; CLI commands refactored to writer/FlagSet helpers; X.509 cert-pool factory added. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant Handler
participant Ctx as ServiceContext
participant Provider
participant External as ExternalAPI
Note over Handler,Ctx: Handler obtains services via ctx accessors
Client->>Handler: trigger operation (e.g., Duo/auth, CLI action)
Handler->>Ctx: ctx.GetLogger(), ctx.GetClock(), ctx.GetRandom()
Handler->>Provider: Provider.Call(ctx, session, values, method, path)
Provider->>Ctx: ctx.GetLogger()
Provider->>External: send signed HTTP request
External-->>Provider: {stat, code, response}
alt stat == "OK" and code in [200,404]
Provider-->>Handler: success response
else stat == "OK" and code unexpected
Provider-->>Handler: wrapped error (unexpected OK code)
else stat == "FAIL"
Provider-->>Handler: wrapped error (FAIL)
else
Provider-->>Handler: wrapped error (unknown stat)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 19
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (8)
internal/handlers/handler_sign_duo.go (2)
263-265: Wrong auth type in log—fix it before it bites, suckaThis Duo handler logs with
regulation.AuthTypeTOTP. That’s misleading.Apply this diff:
- ctx.Logger.WithError(err).Errorf(logFmtErrSessionSave, "authentication time", regulation.AuthTypeTOTP, logFmtActionAuthentication, userSession.Username) + ctx.Logger.WithError(err).Errorf(logFmtErrSessionSave, "authentication time", regulation.AuthTypeDuo, logFmtActionAuthentication, userSession.Username)
293-295: URL-encode pushinfo to stop injection shenanigans
pushinfoconcatenates rawtargetURL. A crafted value could smuggle&foo=barinto Duo’s display payload. Encode it properly, fool.Use
url.Valuesto build and encode:- if targetURL != "" { - values.Set("pushinfo", fmt.Sprintf("target%%20url=%s", targetURL)) - } + if targetURL != "" { + pi := url.Values{} + pi.Set("target url", targetURL) + values.Set("pushinfo", pi.Encode()) + }internal/handlers/handler_oauth2_oidc_userinfo.go (1)
164-165: Use injected clock for iat, not wall time, fool!Keep all times from the same source.
- claims[oidc.ClaimIssuedAt] = time.Now().UTC().Unix() + claims[oidc.ClaimIssuedAt] = ctx.GetClock().Now().UTC().Unix()internal/middlewares/util.go (1)
36-49: Use one clock instance everywhere.You’re creating two Real clocks: one for Regulator and one for Providers. If tests swap Providers.Clock, Regulator will still hold a different clock. Initialize Providers.Clock first and pass it into Regulator.
Apply:
func NewProviders(config *schema.Configuration, caCertPool *x509.CertPool) (providers Providers, warns, errs []error) { providers.Random = random.New() + providers.Clock = clock.New() providers.StorageProvider = storage.NewProvider(config, caCertPool) providers.Authorizer = authorization.NewAuthorizer(config) providers.NTP = ntp.NewProvider(&config.NTP) providers.PasswordPolicy = NewPasswordPolicyProvider(config.PasswordPolicy) - providers.Regulator = regulation.NewRegulator(config.Regulation, providers.StorageProvider, clock.New()) + providers.Regulator = regulation.NewRegulator(config.Regulation, providers.StorageProvider, providers.Clock) providers.SessionProvider = session.NewProvider(config.Session, caCertPool) providers.TOTP = totp.NewTimeBasedProvider(config.TOTP) providers.UserAttributeResolver = expression.NewUserAttributes(config) providers.UserProvider = NewAuthenticationProvider(config, caCertPool) - providers.Clock = clock.New()One clock to rule ‘em all, fool!
internal/duo/duo_test.go (1)
3-25: Fix import formatting per goimports.golangci-lint flags this file. Run goimports to sort/group imports.
I pity the fool who fights the linter!
internal/middlewares/startup.go (1)
12-46: Use the receiver’s providers, not ctx providers.You call
p.StartupChecks(ctx)but ignorepand keep pulling fromctx.GetProviders(). That’s confusing and risks mismatch, fool. Usepdirectly.- provider, disable = ctx.GetProviders().StorageProvider, false + provider, disable = p.StorageProvider, false doStartupCheck(ctx, ProviderNameStorage, provider, nil, disable, log, e.errors) - provider, disable = ctx.GetProviders().UserProvider, false + provider, disable = p.UserProvider, false doStartupCheck(ctx, ProviderNameUser, provider, nil, disable, log, e.errors) - provider, disable = ctx.GetProviders().Notifier, ctx.GetConfiguration().Notifier.DisableStartupCheck + provider, disable = p.Notifier, ctx.GetConfiguration().Notifier.DisableStartupCheck doStartupCheck(ctx, ProviderNameNotification, provider, nil, disable, log, e.errors) - provider, disable = ctx.GetProviders().NTP, ctx.GetConfiguration().NTP.DisableStartupCheck + provider, disable = p.NTP, ctx.GetConfiguration().NTP.DisableStartupCheck doStartupCheck(ctx, ProviderNameNTP, provider, nil, disable, log, e.errors) - provider, disable = ctx.GetProviders().UserAttributeResolver, false + provider, disable = p.UserAttributeResolver, false doStartupCheck(ctx, ProviderNameExpressions, provider, nil, disable, log, e.errors) - provider = ctx.GetProviders().MetaDataService - disable = !ctx.GetConfiguration().WebAuthn.Metadata.Enabled || ctx.GetProviders().MetaDataService == nil + provider = p.MetaDataService + disable = !ctx.GetConfiguration().WebAuthn.Metadata.Enabled || p.MetaDataService == nil doStartupCheck(ctx, ProviderNameWebAuthnMetaData, provider, []string{ProviderNameStorage}, disable, log, e.errors)internal/commands/debug.go (1)
138-239: Fix gocyclo failure on runDebugOIDCClaims or annotate the intent.Function complexity is 18; pipeline blocks, sucka. Either split flag parsing/provider init/encoding into helpers or add a targeted nolint on this function.
Minimal unblock:
- func runDebugOIDCClaims(ctx context.Context, w io.Writer, flags *pflag.FlagSet, config *schema.Configuration, caCertPool *x509.CertPool, username string) (err error) { + //nolint:gocyclo // debug helper: verbose flow with multiple early returns. + func runDebugOIDCClaims(ctx context.Context, w io.Writer, flags *pflag.FlagSet, config *schema.Configuration, caCertPool *x509.CertPool, username string) (err error) {Preferred: split into
parseOIDCClaimsFlags,initOIDCProviders, andencodeOIDCClaims.internal/commands/crypto.go (1)
290-350: Harden dir/file handling: MkdirAll perms check is ineffective; add symlink defenses and umask-safe chmod.
os.MkdirAllreturns nil when the dir already exists; youros.IsExistbranch won’t run, so the “wrong permissions” check never triggers. Also, withoutLstatchecks you can write through symlinks. I pity the fool who trusts the filesystem blindly—tighten this up.Apply this diff inside
runCryptoRandFiles:@@ - if dir != "" { - if err = os.MkdirAll(dir, dmode); err != nil { - if !os.IsExist(err) { - return fmt.Errorf("error making directory for file '%s': %w", name, err) - } else if info, err = os.Stat(dir); err == nil { - if info.Mode().Perm() != dmode { - return fmt.Errorf("error making directory for file '%s': directory '%s' already exists with wrong permissions: %v", name, dir, info.Mode().Perm()) - } - } - } - } + if dir != "" { + if err = os.MkdirAll(dir, dmode); err != nil { + return fmt.Errorf("error making directory for file '%s': %w", name, err) + } + if info, err = os.Lstat(dir); err != nil { + return fmt.Errorf("error stating directory for file '%s': %w", name, err) + } + if info.Mode()&os.ModeSymlink != 0 { + return fmt.Errorf("refusing to use symlinked directory '%s' for file '%s'", dir, name) + } + if info.Mode().Perm() != dmode { + if err = os.Chmod(dir, dmode); err != nil { + return fmt.Errorf("error setting permissions on directory '%s': %w", dir, err) + } + } + } @@ - if file, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fmode); err != nil { + if fi, err := os.Lstat(name); err == nil && fi.Mode()&os.ModeSymlink != 0 { + return fmt.Errorf("refusing to write to symlink '%s'", name) + } + if file, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fmode); err != nil { return fmt.Errorf("error opening file '%s': %w", name, err) } @@ - if err = file.Close(); err != nil { + if err = file.Close(); err != nil { return fmt.Errorf("error closing file '%s': %w", name, err) } + // Ensure final mode despite process umask. + if err = os.Chmod(name, fmode); err != nil { + return fmt.Errorf("error setting permissions on file '%s': %w", name, err) + }Want me to add tests covering: existing dir with wrong perms (chmod fix), and symlink refusal for dir/file targets?
🧹 Nitpick comments (47)
internal/handlers/func_test.go (1)
73-82: LGTM on accessor; tiny math nit to avoid narrowing.Use int64 division to dodge unnecessary casts even in tests.
Apply:
- return uint64(int(step) / period) //nolint:gosec // This is a testing func. + return uint64(step / int64(period)) //nolint:gosec // This is a testing func.internal/commands/debug_test.go (1)
10-27: Beef up these tests just a tad, suckaNon-nil is fine, but add t.Parallel and minimal shape checks (e.g., Use not empty) to catch regressions without coupling too hard.
Example tweak:
func TestNewDebugCmds(t *testing.T) { + t.Parallel() var cmd *cobra.Command cmd = newDebugCmd(&CmdCtx{}) assert.NotNil(t, cmd) + assert.NotEmpty(t, cmd.Use) cmd = newDebugExpressionCmd(&CmdCtx{}) assert.NotNil(t, cmd) + assert.NotEmpty(t, cmd.Use) cmd = newDebugOIDCCmd(&CmdCtx{}) assert.NotNil(t, cmd) + assert.NotEmpty(t, cmd.Use) cmd = newDebugOIDCClaimsCmd(&CmdCtx{}) assert.NotNil(t, cmd) + assert.NotEmpty(t, cmd.Use) cmd = newDebugTLSCmd(&CmdCtx{}) assert.NotNil(t, cmd) + assert.NotEmpty(t, cmd.Use) }internal/handlers/handler_sign_duo.go (2)
261-261: Clock accessor swap looks right—consistency check on timezone, foolGood move to
ctx.GetClock().Now(). Consider normalizing to UTC like other 2FA paths to avoid mixed timezones in comparisons.Would you like me to scan usages of
SetTwoFactor*to confirm all timestamps are consistently UTC?
142-149: Don’t swallow errors—make intent explicitOn preauth error you log + respond then
return "", "", nil. That relies on the caller’s empty-device/method branch. It works but obscures flow.Prefer returning a sentinel error so the call-site short-circuits explicitly.
internal/handlers/handler_sign_webauthn.go (1)
215-221: Defer-save is clever, but be explicit post-regenerationYou rely on the deferred
SaveSessionto persist both challenge cleanup and the final 2FA timestamp afterRegenerateSession. It works, but it’s subtle.Consider clearing
WebAuthnbefore validation errors and doing an explicitSaveSessionafterSetTwoFactorWebAuthnto mirror TOTP/Duo flows.internal/random/cryptographical.go (1)
10-14: Tiny polish: docs + interface assertionTighten the comment and add a compile-time interface check, fool.
Apply:
-// New returns a new random provider, specifically and strictly a production ready variant which uses inbuilt -// system randomness (i.e solely crypto/rand and the *Cryptographical provider). +// New returns a production-ready Provider backed solely by crypto/rand (Cryptographical).And add after the type definition:
var _ Provider = (*Cryptographical)(nil)internal/clock/provider.go (1)
6-7: Decouple the clock interface from jwt to cut coupling, fool.Pulling github.com/golang-jwt/jwt/v5 into the clock interface leaks JWT concerns. Consider keeping Provider pure (Now/After/AfterFunc) and building options at call sites:
Example at call site:
// instead of: ctx.GetClock().GetJWTWithTimeFuncOption() jwt.WithTimeFunc(ctx.GetClock().Now)Keeps the clock generic and avoids forcing every implementer to import jwt.
internal/handlers/handler_oauth2_wellknown.go (1)
53-55: Cache time once to avoid tiny drift, sucka.Call Now() once; prevents issued/expiry skew.
- claims[oidc.ClaimIssuedAt] = ctx.GetClock().Now().UTC().Unix() - claims[oidc.ClaimExpirationTime] = ctx.GetClock().Now().Add(time.Hour).UTC().Unix() + now := ctx.GetClock().Now().UTC() + claims[oidc.ClaimIssuedAt] = now.Unix() + claims[oidc.ClaimExpirationTime] = now.Add(time.Hour).Unix()internal/handlers/handler_oauth2_authorization_consent_core.go (1)
289-293: Compute “now” once for PAR/non-PAR paths, fool.Minor polish: assign now := ctx.GetClock().Now().UTC() once and reuse for both branches to avoid double sampling.
internal/handlers/handler_authz_authn.go (1)
501-504: Capture now once to avoid drift in logs/check, ya hear!Minor cleanup: compute now once; cheaper and consistent.
- ctx.Logger.WithField("username", userSession.Username).Tracef("Inactivity report for user. Current Time: %d, Last Activity: %d, Maximum Inactivity: %d.", ctx.GetClock().Now().Unix(), userSession.LastActivity, int(provider.Config.Inactivity.Seconds())) - - return time.Unix(userSession.LastActivity, 0).Add(provider.Config.Inactivity).Before(ctx.GetClock().Now()) + now := ctx.GetClock().Now() + ctx.Logger.WithField("username", userSession.Username).Tracef("Inactivity report for user. Current Time: %d, Last Activity: %d, Maximum Inactivity: %d.", now.Unix(), userSession.LastActivity, int(provider.Config.Inactivity.Seconds())) + return time.Unix(userSession.LastActivity, 0).Add(provider.Config.Inactivity).Before(now)internal/totp/totp_test.go (1)
112-113: Factory DI for clock/random looks tight, sucka. One tiny polish.Use context.Background() in tests for clarity.
- ctx := NewContext(context.TODO(), clock.New(), random.New()) + ctx := NewContext(context.Background(), clock.New(), random.New())- ctx := NewContext(context.TODO(), clock.New(), random.New()) + ctx := NewContext(context.Background(), clock.New(), random.New())- ctx := NewContext(context.TODO(), clock.NewFixed(time.Unix(10000000, 0)), random.New()) + ctx := NewContext(context.Background(), clock.NewFixed(time.Unix(10000000, 0)), random.New())Also applies to: 159-161, 223-224
internal/clock/real.go (1)
22-25: Ditch the named return for clarity, fool.
Lean it up; same behavior, less noise.-func (r Real) GetJWTWithTimeFuncOption() (option jwt.ParserOption) { - return jwt.WithTimeFunc(r.Now) -} +func (r Real) GetJWTWithTimeFuncOption() jwt.ParserOption { + return jwt.WithTimeFunc(r.Now) +}internal/handlers/handler_session_elevation_test.go (1)
353-361: Stabilize time expectations with a single capture.
Multiple Now() calls can drift in some clocks. Capture once, reuse. Don’t get bit by flaky nanoseconds, fool.- gomock.InOrder( + now := mock.Clock.Now() + gomock.InOrder( mock.RandomMock.EXPECT(). Read(gomock.Any()). SetArg(0, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x22, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15}). Return(16, nil), mock.RandomMock.EXPECT(). BytesCustomErr(10, []byte(random.CharSetUnambiguousUpper)). Return([]byte("ABC123ABC1"), nil), mock.StorageMock.EXPECT(). SaveOneTimeCode(mock.Ctx, model.OneTimeCode{ PublicID: uuid.Must(uuid.Parse("01020304-0506-4722-8910-111213141500")), - IssuedAt: mock.Clock.Now(), + IssuedAt: now, IssuedIP: model.NewIP(net.ParseIP("0.0.0.0")), - ExpiresAt: mock.Clock.Now().Add(time.Minute), + ExpiresAt: now.Add(time.Minute),internal/commands/crypto_test.go (1)
1-27: Add table-driven cases and t.Parallel to toughen this test.
Make it meaner and leaner, chump: parallelize and assert basic command traits (Use/Short/subcommands) for real value.func TestNewCrypto(t *testing.T) { - var cmd *cobra.Command - - cmd = newCryptoCmd(&CmdCtx{}) - assert.NotNil(t, cmd) - ... - cmd = newCryptoPairSubCmd(&CmdCtx{}, "verify") - assert.NotNil(t, cmd) + t.Parallel() + tests := []struct{ + name string + make func() *cobra.Command + }{ + {"crypto", func() *cobra.Command { return newCryptoCmd(&CmdCtx{}) }}, + {"certificate", func() *cobra.Command { return newCryptoCertificateCmd(&CmdCtx{}) }}, + {"pair", func() *cobra.Command { return newCryptoPairCmd(&CmdCtx{}) }}, + {"pair-generate", func() *cobra.Command { return newCryptoPairSubCmd(&CmdCtx{}, "generate") }}, + {"pair-verify", func() *cobra.Command { return newCryptoPairSubCmd(&CmdCtx{}, "verify") }}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + cmd := tc.make() + assert.NotNil(t, cmd) + assert.NotEmpty(t, cmd.Use) + assert.NotEmpty(t, cmd.Short) + }) + } }internal/handlers/handler_oauth2_authorization_consent_core_test.go (2)
217-217: Clock provider wiring LGTM — keep it DRY, fool!Setting
mock.Ctx.Providers.Clock = &mock.Clockis correct. Consider a small helper (e.g.,setupTestClock(mock, ts)) to avoid repetition across tests.Also applies to: 379-379, 719-719, 1021-1021, 1358-1358
877-877: ExpiresAt via provider clock is solid — snapshot ‘now’ onceUsing
mock.Ctx.Providers.Clock.Now()is right. For stability, computenow := mock.Ctx.Providers.Clock.Now()once per test case and reuse to avoid any micro-drift. I pity the flaky test, fool!Also applies to: 916-916, 1005-1005, 1183-1183, 1237-1237
internal/handlers/handler_firstfactor_passkey_test.go (3)
546-547: SessionData/CreatedAt now rely on provider clock — consistent timingGreat alignment with the clock refactor. Consider standardizing remaining
time.Now()usages in this file too for full determinism.Also applies to: 556-556, 652-653, 661-661, 754-755, 763-763
556-556: Mixingmock.Clock.Now()and provider clock — unify for clarity, foolWhile both point to the same mock, prefer
mock.Ctx.Providers.Clock.Now()everywhere (e.g.,LastUsedAt) for consistency.Apply pattern (example):
- LastUsedAt: sql.NullTime{Time: mock.Clock.Now().UTC(), Valid: true}, + LastUsedAt: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC(), Valid: true},Also applies to: 661-661, 763-763
151-151: Optional: Replace raw time.Now() calls in internal/handlers/handler_firstfactor_passkey_test.go with mock.Clock.Now(), fool! I count ~28 occurrences (Expires, CreatedAt, LastUsedAt)—use the injected clock for deterministic tests.internal/handlers/handler_session_elevation.go (2)
79-82: Switched toGetClock()— good; grabnowonceTwo calls to
ctx.GetClock().Now()back-to-back can drift a second boundary. Capture once and reuse.- response.Expires = int(userSession.Elevations.User.Expires.Sub(ctx.GetClock().Now()).Seconds()) - if userSession.Elevations.User.Expires.Before(ctx.GetClock().Now()) { + now := ctx.GetClock().Now() + response.Expires = int(userSession.Elevations.User.Expires.Sub(now).Seconds()) + if userSession.Elevations.User.Expires.Before(now) {
282-283: PUT path uses provider clock — finalize with a singlenowSame story here: snapshot once for the expiry check and assignment.
- if code.ExpiresAt.Before(ctx.GetClock().Now()) { + now := ctx.GetClock().Now() + if code.ExpiresAt.Before(now) { ... - Expires: ctx.GetClock().Now().Add(ctx.Configuration.IdentityValidation.ElevatedSession.ElevationLifespan), + Expires: now.Add(ctx.Configuration.IdentityValidation.ElevatedSession.ElevationLifespan),Also applies to: 342-342
internal/handlers/handler_oauth2_consent.go (2)
301-302: Pre-config and responded-at timestamps now provider-backed — solidNice swap to
ctx.GetClock().Now(). Consider capturingnow := ctx.GetClock().Now()once in the function to reuse. Don’t make time a moving target, fool!Also applies to: 355-356
545-546: Device flow consent session uses provider clock — correctCreating the consent with
Now().Add(10*time.Second)and marking responded-at via provider is right. Optional: computenowonce to avoid drift.Also applies to: 566-566
internal/handlers/handler_sign_password.go (1)
17-17: Optional: use provider clock forrequestTimetooFor full determinism in timing-attack delays, consider:
- requestTime := time.Now() + requestTime := ctx.GetClock().Now()internal/handlers/handler_firstfactor_passkey.go (1)
311-345: Drop the duplicated RefreshTTL assignment.RefreshTTL is set twice (Line 311 and Line 345). Set it once after SetOneFactorPasskey to avoid drift and confusion. I pity the fool who sets the same TTL twice!
Apply this diff:
- if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { - userSession.RefreshTTL = ctx.GetClock().Now().Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) - } ... userSession.SetOneFactorPasskey( ctx.GetClock().Now(), details, keepMeLoggedIn, response.AuthenticatorAttachment == protocol.CrossPlatform, response.Response.AuthenticatorData.Flags.HasUserPresent(), response.Response.AuthenticatorData.Flags.HasUserVerified(), ) if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { - userSession.RefreshTTL = ctx.GetClock().Now().Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) + userSession.RefreshTTL = ctx.GetClock().Now().Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) }internal/handlers/handler_firstfactor_password.go (2)
136-140: Good move to provider-backed time for password 1FA.SetOneFactorPassword and RefreshTTL using ctx.GetClock() look tight. Keep it consistent, sucka.
Consider capturing now := ctx.GetClock().Now() once and reuse to avoid micro-drift:
- userSession.SetOneFactorPassword(ctx.GetClock().Now(), details, keepMeLoggedIn) - if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { - userSession.RefreshTTL = ctx.GetClock().Now().Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) - } + now := ctx.GetClock().Now() + userSession.SetOneFactorPassword(now, details, keepMeLoggedIn) + if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { + userSession.RefreshTTL = now.Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) + }
267-271: Reauth flow clock usage looks correct.Same note: capture now once to keep timestamps aligned. Don’t play games with time, fool.
- userSession.SetOneFactorReauthenticate(ctx.GetClock().Now(), userDetails) - if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { - userSession.RefreshTTL = ctx.GetClock().Now().Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) - } + now := ctx.GetClock().Now() + userSession.SetOneFactorReauthenticate(now, userDetails) + if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { + userSession.RefreshTTL = now.Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) + }internal/handlers/handler_oauth2_authorization_consent_preconfigured.go (3)
89-109: Avoid TOCTOU drift: capture now once in WithID path.Use a single now := ctx.GetClock().Now() for CanGrant and SetRespondedAt to keep decisions and writes aligned. Don’t let time slip, sucka.
Apply this diff within the function:
- if !consent.CanGrant(ctx.GetClock().Now()) { + now := ctx.GetClock().Now() + if !consent.CanGrant(now) { ... - consent.SetRespondedAt(ctx.GetClock().Now(), config.ID) + consent.SetRespondedAt(now, config.ID)Add the
now :=declaration right before the CanGrant check.
207-207: Same here in WithoutID path: reuse a single now.Keep RespondedAt consistent with earlier checks. Consistency is king, fool.
- consent.SetRespondedAt(ctx.GetClock().Now(), config.ID) + now := ctx.GetClock().Now() + consent.SetRespondedAt(now, config.ID)If a now already exists earlier in the scope, reuse it.
227-260: Deterministic pre-config filtering: pass one timestamp through.LoadOAuth2ConsentPreConfigurations and config.CanConsentAt both use Now(); compute once and reuse to prevent edge-case mismatches at expiry boundaries. Don’t get caught on the line, sucka.
- if rows, err = ctx.Providers.StorageProvider.LoadOAuth2ConsentPreConfigurations(ctx, client.GetID(), subject, ctx.GetClock().Now()); err != nil { + now := ctx.GetClock().Now() + if rows, err = ctx.Providers.StorageProvider.LoadOAuth2ConsentPreConfigurations(ctx, client.GetID(), subject, now); err != nil { ... - if !config.CanConsentAt(ctx.GetClock().Now()) { + if !config.CanConsentAt(now) {internal/handlers/handler_oauth2_authorization_consent_implicit.go (2)
79-93: Implicit WithID: compute now once for CanGrant and Grant.Single timestamp avoids micro-drifts across checks and writes. Tighten it up, fool.
- if !consent.CanGrant(ctx.GetClock().Now()) { + now := ctx.GetClock().Now() + if !consent.CanGrant(now) { ... - oidc.ConsentGrantImplicit(consent, requests.ToSlice(), subject, ctx.GetClock().Now()) + oidc.ConsentGrantImplicit(consent, requests.ToSlice(), subject, now) ... - oidc.ConsentGrantImplicit(consent, nil, subject, ctx.GetClock().Now()) + oidc.ConsentGrantImplicit(consent, nil, subject, now)
149-151: Implicit WithoutID: same single-now pattern.Keep that timestamp steady, sucka.
- oidc.ConsentGrantImplicit(consent, requests.ToSlice(), subject, ctx.GetClock().Now()) + now := ctx.GetClock().Now() + oidc.ConsentGrantImplicit(consent, requests.ToSlice(), subject, now) ... - oidc.ConsentGrantImplicit(consent, nil, subject, ctx.GetClock().Now()) + oidc.ConsentGrantImplicit(consent, nil, subject, now)internal/commands/context.go (1)
88-94: Avoid naming return values that shadow package names.Named results ‘clock’ and ‘random’ shadow imports; drop the names for clarity.
Apply:
-func (ctx *CmdCtx) GetClock() (clock clock.Provider) { - return ctx.providers.Clock -} - -func (ctx *CmdCtx) GetRandom() (random random.Provider) { - return ctx.providers.Random -} +func (ctx *CmdCtx) GetClock() clock.Provider { + return ctx.providers.Clock +} + +func (ctx *CmdCtx) GetRandom() random.Provider { + return ctx.providers.Random +}Don’t let shadows spook your readers, sucker!
internal/commands/storage_run.go (1)
1752-1755: Reuse ctx’s Random for directory names.Keeps RNG consistent and mockable.
Apply:
if dir == "" { - rand := random.New() - dir = rand.StringCustom(8, random.CharSetAlphaNumeric) + var rnd random.Provider + if svc, ok := ctx.(middlewares.Context); ok { + rnd = svc.GetRandom() + } else { + rnd = random.New() + } + dir = rnd.StringCustom(8, random.CharSetAlphaNumeric) }Keep it tight and testable, fool!
internal/handlers/handler_register_totp_test.go (1)
858-859: Clock rebinding in test setup is correct.Setting mock.Ctx.Providers.Clock ensures all code under test uses the mock time.
Consider updating other CreatedAt expectations in this file to uniformly reference mock.Ctx.Providers.Clock.Now() for clarity.
Don’t mix clocks like a fool!internal/duo/duo_test.go (2)
458-473: Use pointer receivers for GetClock/GetRandom.With value receivers, assignment to t.providers.* doesn’t persist. Pointer receivers make the lazy init stick.
Apply:
-func (t TestCtx) GetClock() clock.Provider { - if t.providers.Clock == nil { - t.providers.Clock = clock.New() - } - return t.providers.Clock -} +func (t *TestCtx) GetClock() clock.Provider { + if t.providers.Clock == nil { + t.providers.Clock = clock.New() + } + return t.providers.Clock +} -func (t TestCtx) GetRandom() random.Provider { - if t.providers.Random == nil { - t.providers.Random = random.New() - } - return t.providers.Random -} +func (t *TestCtx) GetRandom() random.Provider { + if t.providers.Random == nil { + t.providers.Random = random.New() + } + return t.providers.Random +}Make those setters stick, sucka!
433-445: Nit: NewTextCtx likely meant NewTestCtx.Function name mismatches the type (TestCtx). Rename for clarity and update call sites.
Example:
-func NewTextCtx(ip net.IP) *TestCtx { +func NewTestCtx(ip net.IP) *TestCtx { @@ - ctx := &TestCtx{ + ctx := &TestCtx{ @@ - return ctx + return ctx }And replace calls like:
-ctx := NewTextCtx(net.ParseIP("127.0.0.1")) +ctx := NewTestCtx(net.ParseIP("127.0.0.1"))Names matter, fool!
Also applies to: 283-285, 408-410, 469-481
internal/commands/util.go (2)
382-425: Avoid per-call map allocations; precompute and just lookup.Right now you build a new map on every call, sucka. Precompute once and return by key; also document that unknown
useyields nil to signal “unsupported”.Apply within this function:
-func getCryptoHashGenerateMapFlagsFromUse(use string) (flags map[string]string) { - flags = make(map[string]string) - switch use { +func getCryptoHashGenerateMapFlagsFromUse(use string) (flags map[string]string) { + switch use { case cmdUseHashArgon2: - flags = map[string]string{ + return map[string]string{ cmdFlagNameVariant: prefixFilePassword + suffixArgon2Variant, cmdFlagNameIterations: prefixFilePassword + suffixArgon2Iterations, cmdFlagNameMemory: prefixFilePassword + suffixArgon2Memory, cmdFlagNameParallelism: prefixFilePassword + suffixArgon2Parallelism, cmdFlagNameKeySize: prefixFilePassword + suffixArgon2KeyLength, cmdFlagNameSaltSize: prefixFilePassword + suffixArgon2SaltLength, } case cmdUseHashSHA2Crypt: - flags = map[string]string{ + return map[string]string{ cmdFlagNameVariant: prefixFilePassword + suffixSHA2CryptVariant, cmdFlagNameIterations: prefixFilePassword + suffixSHA2CryptIterations, cmdFlagNameSaltSize: prefixFilePassword + suffixSHA2CryptSaltLength, } case cmdUseHashPBKDF2: - flags = map[string]string{ + return map[string]string{ cmdFlagNameVariant: prefixFilePassword + suffixPBKDF2Variant, cmdFlagNameIterations: prefixFilePassword + suffixPBKDF2Iterations, cmdFlagNameKeySize: prefixFilePassword + suffixPBKDF2KeyLength, cmdFlagNameSaltSize: prefixFilePassword + suffixPBKDF2SaltLength, } case cmdUseHashBcrypt: - flags = map[string]string{ + return map[string]string{ cmdFlagNameVariant: prefixFilePassword + suffixBcryptVariant, cmdFlagNameCost: prefixFilePassword + suffixBcryptCost, } case cmdUseHashScrypt: - flags = map[string]string{ + return map[string]string{ cmdFlagNameVariant: prefixFilePassword + suffixScryptVariant, cmdFlagNameIterations: prefixFilePassword + suffixScryptIterations, cmdFlagNameBlockSize: prefixFilePassword + suffixScryptBlockSize, cmdFlagNameParallelism: prefixFilePassword + suffixScryptParallelism, cmdFlagNameKeySize: prefixFilePassword + suffixScryptKeyLength, cmdFlagNameSaltSize: prefixFilePassword + suffixScryptSaltLength, } } - - return flags + return nil }If you prefer zero allocations entirely, define a package-level
varwith these maps and justreturn cryptoHashFlagMap[use].
103-106: Renamerandtorng, fool!Provider interface defines
StringCustom(n int, characters string) string(internal/random/provider.go:32–33). I pity the fool who confuses it with math/rand—userngfor clarity at internal/commands/util.go:103.internal/commands/debug.go (1)
292-489: Consider splitting runDebugTLS to cut complexity and improve readability.Break into helpers: dialing, cipher summary, chain verification, cert printing, and config suggestion. Keeps the fools from crying over 30+ complexity.
Sketch:
func tlsDial(address *schema.Address, hostname string, suites []uint16) (*tls.Conn, error) { ... } func printTLSGeneral(w io.Writer, cs tls.ConnectionState) { ... } func verifyChains(cs tls.ConnectionState, roots, system *x509.CertPool) (valid, validSys bool, inter, interSys *x509.CertPool) { ... } func printCerts(w io.Writer, cs tls.ConnectionState, hostname string, valid, validSys bool) (validHostname bool) { ... } func suggestConfig(w io.Writer, cs tls.ConnectionState, hostname, override string, validHostname bool) { ... }internal/duo/types.go (1)
20-23: Context-based Provider: good evolution, sucka!Switching to middlewares.Context cleans up dependencies and aligns with new accessors.
If duo_api_golang ever supports context-aware calls, wire ctx for cancellation/timeouts end-to-end. I pity the fool who ignores cancelation!
experimental/embed/context.go (1)
121-123: Don’t return nil IP unless you mean it, fool!Downstream logs show “”. Return an unspecified/loopback IP to keep logs tidy.
func (c *ctxEmbed) RemoteIP() net.IP { - return nil + return net.IPv4zero // or net.ParseIP("127.0.0.1") }internal/duo/duo.go (2)
68-81: Preserve context in wrapping errors, chump.Include path/username so callers can trace failures without logs.
- return nil, fmt.Errorf("error occurred making the preauth call to the duo api: %w", err) + return nil, fmt.Errorf("duo preauth call failed (user=%s): %w", userSession.Username, err) ... - return nil, fmt.Errorf("error occurred parsing the duo api preauth json response: %w", err) + return nil, fmt.Errorf("duo preauth JSON parse failed: %w", err)Also consider returning the raw Response alongside the error if callers need Duo codes.
84-97: Same story for AuthCall, fool.Mirror the improved context in errors for consistency.
- return nil, fmt.Errorf("error occurred making the auth call to the duo api: %w", err) + return nil, fmt.Errorf("duo auth call failed (user=%s): %w", userSession.Username, err) ... - return nil, fmt.Errorf("error occurred parsing the duo api auth json response: %w", err) + return nil, fmt.Errorf("duo auth JSON parse failed: %w", err)internal/commands/crypto_hash.go (1)
244-252: Echoing random password is intentional, but warn users, fool!Since this prints secrets to stdout, ensure docs/examples show redirecting or handling securely.
internal/commands/crypto.go (2)
633-634: Nice extraction of pair generation printing. Consider taming the arg list.That parameter list is louder than Clubber Lang. Wrap into an options struct to reduce churn and improve clarity, fool.
type pairGenOpts struct { W io.Writer Legacy bool PrivateKey any Dir string PrivateKeyPath, PrivateKeyLegacyPath string PublicKeyPath, PublicKeyLegacyPath string ExtLegacy string }Then call
runCryptoPairGenerate(opts)and pass&pairGenOpts{...}.
641-648: Clarify RSA algorithm printout.Current string mixes bytes and bits without labels. Make it unambiguous, sucka.
- case *rsa.PrivateKey: - b.WriteString(fmt.Sprintf("\tAlgorithm: RSA-%d %d bits\n\n", k.Size(), k.N.BitLen())) + case *rsa.PrivateKey: + b.WriteString(fmt.Sprintf("\tAlgorithm: RSA %d-bit (%d bytes)\n\n", k.N.BitLen(), k.Size()))
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
internal/configuration/test_resources/userdb/debug-tests.ymlis excluded by!**/*.yml
📒 Files selected for processing (66)
cmd/authelia-gen/openid_conformance.go(1 hunks)experimental/embed/context.go(3 hunks)experimental/embed/provider/general.go(1 hunks)internal/clock/fixed.go(2 hunks)internal/clock/provider.go(1 hunks)internal/clock/real.go(2 hunks)internal/commands/context.go(3 hunks)internal/commands/crypto.go(6 hunks)internal/commands/crypto_hash.go(6 hunks)internal/commands/crypto_test.go(1 hunks)internal/commands/debug.go(13 hunks)internal/commands/debug_test.go(1 hunks)internal/commands/storage_run.go(2 hunks)internal/commands/util.go(2 hunks)internal/duo/duo.go(2 hunks)internal/duo/duo_test.go(2 hunks)internal/duo/types.go(3 hunks)internal/handlers/func_test.go(1 hunks)internal/handlers/handler_authz_authn.go(5 hunks)internal/handlers/handler_authz_test.go(16 hunks)internal/handlers/handler_firstfactor_passkey.go(3 hunks)internal/handlers/handler_firstfactor_passkey_test.go(26 hunks)internal/handlers/handler_firstfactor_password.go(2 hunks)internal/handlers/handler_firstfactor_password_test.go(2 hunks)internal/handlers/handler_oauth2_authorization.go(1 hunks)internal/handlers/handler_oauth2_authorization_claims.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core_test.go(10 hunks)internal/handlers/handler_oauth2_authorization_consent_explicit.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_implicit.go(3 hunks)internal/handlers/handler_oauth2_authorization_consent_preconfigured.go(5 hunks)internal/handlers/handler_oauth2_consent.go(6 hunks)internal/handlers/handler_oauth2_device_authorization.go(1 hunks)internal/handlers/handler_oauth2_introspection.go(1 hunks)internal/handlers/handler_oauth2_oidc_userinfo.go(2 hunks)internal/handlers/handler_oauth2_oidc_wellknown.go(1 hunks)internal/handlers/handler_oauth2_token.go(1 hunks)internal/handlers/handler_oauth2_wellknown.go(1 hunks)internal/handlers/handler_register_totp.go(3 hunks)internal/handlers/handler_register_totp_test.go(3 hunks)internal/handlers/handler_reset_password.go(1 hunks)internal/handlers/handler_session_elevation.go(3 hunks)internal/handlers/handler_session_elevation_test.go(4 hunks)internal/handlers/handler_sign_duo.go(1 hunks)internal/handlers/handler_sign_password.go(1 hunks)internal/handlers/handler_sign_password_test.go(1 hunks)internal/handlers/handler_sign_totp.go(2 hunks)internal/handlers/handler_sign_totp_test.go(2 hunks)internal/handlers/handler_sign_webauthn.go(2 hunks)internal/middlewares/authelia_context.go(1 hunks)internal/middlewares/identity_verification.go(1 hunks)internal/middlewares/require_auth_test.go(1 hunks)internal/middlewares/startup.go(2 hunks)internal/middlewares/timing_attack_delay_test.go(2 hunks)internal/middlewares/types.go(2 hunks)internal/middlewares/util.go(2 hunks)internal/mocks/authelia_context.go(1 hunks)internal/mocks/duo_api.go(3 hunks)internal/model/webauthn_test.go(1 hunks)internal/notification/smtp_notifier.go(1 hunks)internal/oidc/types.go(2 hunks)internal/oidc/types_test.go(1 hunks)internal/random/cryptographical.go(1 hunks)internal/regulation/regulator_blackbox_test.go(2 hunks)internal/totp/totp_test.go(3 hunks)internal/utils/const_test.go(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (47)
internal/handlers/handler_register_totp.go (1)
internal/session/types.go (1)
TOTP(51-58)
internal/commands/debug_test.go (1)
internal/commands/context.go (1)
CmdCtx(45-55)
experimental/embed/provider/general.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/mocks/authelia_context.go (1)
internal/clock/real.go (1)
New(10-12)
internal/handlers/handler_oauth2_device_authorization.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/oidc/session.go (1)
NewSessionWithRequestedAt(22-38)
internal/handlers/handler_oauth2_authorization.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/oidc/session.go (1)
NewSessionWithRequestedAt(22-38)
internal/notification/smtp_notifier.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/random/cryptographical.go (2)
internal/clock/real.go (1)
New(10-12)internal/clock/provider.go (1)
Provider(10-15)
internal/commands/crypto_test.go (1)
internal/commands/context.go (1)
CmdCtx(45-55)
internal/commands/storage_run.go (2)
internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)
internal/utils/const_test.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/model/webauthn_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/handlers/handler_firstfactor_password.go (1)
internal/configuration/schema/authentication.go (1)
AuthenticationBackend(10-19)
internal/handlers/handler_sign_password_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/totp/totp_test.go (3)
internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)internal/clock/fixed.go (1)
NewFixed(10-12)
internal/handlers/handler_oauth2_consent.go (1)
internal/model/oidc.go (1)
NewOAuth2ConsentSession(20-22)
internal/handlers/handler_oauth2_token.go (1)
internal/oidc/session.go (1)
NewSessionWithRequestedAt(22-38)
internal/handlers/handler_oauth2_oidc_wellknown.go (2)
internal/oidc/const.go (2)
ClaimIssuedAt(28-28)ClaimExpirationTime(31-31)internal/utils/const.go (1)
Hour(58-58)
cmd/authelia-gen/openid_conformance.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/handlers/handler_authz_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/handlers/handler_oauth2_oidc_userinfo.go (3)
internal/middlewares/types.go (2)
Providers(40-58)Context(60-69)internal/oidc/types.go (1)
Context(211-220)internal/oidc/session.go (1)
NewSessionWithRequestedAt(22-38)
internal/handlers/handler_sign_totp_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/handlers/handler_oauth2_authorization_consent_implicit.go (1)
internal/oidc/session.go (1)
ConsentGrantImplicit(212-217)
internal/handlers/handler_oauth2_introspection.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/oidc/session.go (1)
NewSessionWithRequestedAt(22-38)
internal/mocks/duo_api.go (1)
internal/middlewares/types.go (1)
Context(60-69)
internal/regulation/regulator_blackbox_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/handlers/handler_session_elevation_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/handlers/handler_oauth2_authorization_consent_core_test.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/model/oidc.go (1)
OAuth2ConsentSession(254-276)
internal/duo/duo_test.go (4)
internal/duo/duo.go (1)
NewDuoAPI(15-19)internal/duo/types.go (6)
BaseProvider(14-16)Response(42-48)PreAuthResponse(59-67)Device(31-39)AuthResponse(51-56)Provider(19-23)internal/session/types.go (1)
UserSession(20-48)internal/middlewares/types.go (2)
Context(60-69)Providers(40-58)
internal/middlewares/timing_attack_delay_test.go (2)
internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)
internal/middlewares/startup.go (3)
internal/middlewares/types.go (2)
Providers(40-58)ServiceContext(71-79)experimental/embed/context.go (1)
ServiceContext(78-85)internal/model/types.go (1)
StartupCheck(168-170)
internal/handlers/handler_register_totp_test.go (2)
internal/model/totp_configuration.go (1)
TOTPConfiguration(28-38)internal/middlewares/types.go (1)
Providers(40-58)
internal/handlers/handler_oauth2_authorization_consent_preconfigured.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/oidc/types_test.go (1)
internal/oidc/config.go (1)
Config(80-130)
internal/commands/debug.go (9)
experimental/embed/context.go (1)
Context(65-74)internal/middlewares/types.go (1)
Context(60-69)internal/oidc/types.go (1)
Context(211-220)internal/middlewares/util.go (1)
NewAuthenticationProvider(76-85)internal/expression/user_attributes.go (1)
NewUserAttributes(13-24)internal/commands/context.go (1)
CmdCtx(45-55)internal/configuration/schema/types_address.go (1)
NewAddress(16-18)internal/utils/crypto.go (1)
IsInsecureCipherSuite(735-743)internal/utils/const.go (1)
BlockTypeCertificate(32-32)
internal/handlers/handler_firstfactor_password_test.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/authentication/types.go (1)
UserDetails(12-17)
internal/duo/duo.go (3)
internal/duo/types.go (3)
Response(42-48)PreAuthResponse(59-67)AuthResponse(51-56)internal/middlewares/types.go (1)
Context(60-69)internal/session/types.go (1)
UserSession(20-48)
internal/handlers/handler_firstfactor_passkey_test.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/model/regulation.go (3)
BannedUser(26-35)AuthenticationAttempt(9-19)BannedIP(37-46)
internal/commands/context.go (4)
experimental/embed/context.go (1)
New(18-61)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)internal/clock/provider.go (1)
Provider(10-15)
internal/middlewares/require_auth_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/commands/util.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/duo/types.go (2)
internal/middlewares/types.go (1)
Context(60-69)internal/session/types.go (1)
UserSession(20-48)
internal/middlewares/authelia_context.go (4)
internal/middlewares/types.go (2)
Providers(40-58)AutheliaCtx(29-37)experimental/embed/types.go (2)
Providers(19-19)Configuration(10-10)internal/clock/provider.go (1)
Provider(10-15)internal/logging/logger.go (1)
Logger(15-17)
internal/middlewares/util.go (4)
experimental/embed/context.go (1)
New(18-61)experimental/embed/provider/general.go (1)
New(26-28)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)
experimental/embed/context.go (5)
internal/middlewares/types.go (2)
Providers(40-58)Context(60-69)experimental/embed/types.go (2)
Providers(19-19)Configuration(10-10)internal/clock/provider.go (1)
Provider(10-15)internal/service/provider.go (2)
Provider(13-28)Context(46-52)internal/oidc/types.go (1)
Context(211-220)
internal/commands/crypto_hash.go (2)
internal/configuration/schema/authentication.go (1)
AuthenticationBackend(10-19)internal/authentication/file_user_provider.go (1)
NewFileCryptoHashFromConfig(242-288)
internal/middlewares/types.go (4)
internal/clock/provider.go (1)
Provider(10-15)internal/service/provider.go (2)
Provider(13-28)Context(46-52)experimental/embed/context.go (1)
Context(65-74)internal/oidc/types.go (1)
Context(211-220)
🪛 GitHub Check: golangci
internal/duo/duo_test.go
[failure] 12-12: [golangci] internal/duo/duo_test.go#L12
File is not properly formatted (goimports)
[failure] 450-450: [golangci] internal/duo/duo_test.go#L450
field clock is unused (unused)
[failure] 451-451: [golangci] internal/duo/duo_test.go#L451
field random is unused (unused)
internal/middlewares/timing_attack_delay_test.go
[failure] 8-8: [golangci] internal/middlewares/timing_attack_delay_test.go#L8
File is not properly formatted (goimports)
internal/commands/debug.go
[failure] 138-138: [golangci] internal/commands/debug.go#L138
cyclomatic complexity 18 of func runDebugOIDCClaims is high (> 15) (gocyclo)
[failure] 244-244: [golangci] internal/commands/debug.go#L244
runDebugExpression - ctx is unused (unparam)
[failure] 292-292: [golangci] internal/commands/debug.go#L292
cyclomatic complexity 30 of func runDebugTLS is high (> 15) (gocyclo)
[failure] 287-287: [golangci] internal/commands/debug.go#L287
directive //nolint:gocyclo is unused for linter "gocyclo" (nolintlint)
internal/duo/duo.go
[failure] 47-47: [golangci] internal/duo/duo.go#L47
missing whitespace above this line (too many lines above return) (wsl_v5)
[failure] 52-52: [golangci] internal/duo/duo.go#L52
missing whitespace above this line (too many lines above return) (wsl_v5)
[failure] 58-58: [golangci] internal/duo/duo.go#L58
missing whitespace above this line (too many lines above return) (wsl_v5)
[failure] 63-63: [golangci] internal/duo/duo.go#L63
missing whitespace above this line (too many lines above return) (wsl_v5)
internal/commands/context.go
[failure] 14-14: [golangci] internal/commands/context.go#L14
File is not properly formatted (goimports)
experimental/embed/context.go
[failure] 7-7: [golangci] experimental/embed/context.go#L7
File is not properly formatted (goimports)
⏰ 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). (2)
- GitHub Check: Analyze (go)
- GitHub Check: StepSecurity Harden-Runner
97f0593 to
3123566
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
internal/handlers/handler_oauth2_authorization_consent_preconfigured.go (1)
225-231: Use a single now for filtering and validation to avoid time TOCTOUI pity the fool who checks with one timestamp and validates with another. Capture now once, use it for the rows query and CanConsentAt to avoid edge inconsistencies.
ctx.Logger.Debugf(logFmtDbgConsentPreConfTryingLookup, requester.GetID(), client.GetID(), client.GetConsentPolicy(), client.GetID(), subject, strings.Join(requester.GetRequestedScopes(), " ")) - if rows, err = ctx.Providers.StorageProvider.LoadOAuth2ConsentPreConfigurations(ctx, client.GetID(), subject, ctx.GetClock().Now()); err != nil { + now := ctx.GetClock().Now() + if rows, err = ctx.Providers.StorageProvider.LoadOAuth2ConsentPreConfigurations(ctx, client.GetID(), subject, now); err != nil { return nil, fmt.Errorf("error loading rows: %w", err) } ... - if !config.CanConsentAt(ctx.GetClock().Now()) { + if !config.CanConsentAt(now) { log.Debugf("Authorization Request with id '%s' on client with id '%s' using consent mode '%s' found a matching pre-configuration with id '%d' but it is revoked, expired, or otherwise can no longer provide consent", requester.GetID(), client.GetID(), client.GetConsentPolicy(), config.ID) continue }Want me to add/update tests to assert consistent behavior at expiry boundaries with a frozen clock?
Also applies to: 260-262
internal/middlewares/util.go (1)
43-43: One clock to rule them all, fool!
Moveproviders.Clock = clock.New()before creating the Regulator and passproviders.Clockintoregulation.NewRegulator(instead of callingclock.New()), then remove the final redundantclock.New()assignment.experimental/embed/context.go (1)
53-58: Initialize the embedded context, fool!ctxEmbed embeds context.Context but never sets it. Any Context method call (Value, Done, etc.) will panic. Set a base context.
Example fix (struct literal snippet):
ctx = &ctxEmbed{ Configuration: (*Configuration)(config), ConfigurationPaths: paths, Logger: logrus.NewEntry(logrus.StandardLogger()), Providers: Providers(providers), Context: context.Background(), // or context.WithCancel(...) if you need cancellation }
♻️ Duplicate comments (4)
internal/commands/crypto_hash.go (1)
228-236: Fix nil dereference before setting Algorithm, fool!config.AuthenticationBackend.File may be nil; mutating or reading Password will panic. Initialize sane defaults before the switch and before NewFileCryptoHashFromConfig. I pity the fool who dereferences nil.
Apply this diff:
switch use { case cmdUseGenerate: break default: - config.AuthenticationBackend.File.Password.Algorithm = use + // Ensure password config exists before mutation. + if config.AuthenticationBackend.File == nil { + config.AuthenticationBackend.File = &schema.AuthenticationBackendFile{} + } + if config.AuthenticationBackend.File.Password.Algorithm == "" { + // Populate with sane defaults so downstream hashing always has parameters. + config.AuthenticationBackend.File.Password = schema.DefaultPasswordConfig + } + config.AuthenticationBackend.File.Password.Algorithm = use } -if hash, err = authentication.NewFileCryptoHashFromConfig(config.AuthenticationBackend.File.Password); err != nil { +// Guard again in case File was absent and we’re on the root 'generate' path. +if config.AuthenticationBackend.File == nil { + return fmt.Errorf("file authentication backend password settings are not configured") +} +if hash, err = authentication.NewFileCryptoHashFromConfig(config.AuthenticationBackend.File.Password); err != nil { return err }internal/duo/duo_test.go (1)
446-454: Nice: removed unused clock/random fields from TestCtx. No dead weight on my watch!This resolves prior lint failures.
internal/oidc/types_test.go (1)
167-171: Return pointer to a copy to avoid test pollution: good; mind shallow-copy semanticsSolid move. Note it’s a shallow copy—nested pointers (e.g., HTTPClient, Templates) still alias. I pity the fool who mutates those thinking they’re isolated.
Optionally deep-copy critical subfields if tests mutate them.
To ensure callers don’t rely on pointer identity or mutate via the returned pointer:
#!/bin/bash set -euo pipefail rg -nP '\.GetConfiguration\(\)\.[A-Za-z_]+\s*=' --type=go -S || true rg -nP '(GetConfiguration\(\)\s*==)|(\s==\s*GetConfiguration\(\))' --type=go -S || trueexperimental/embed/context.go (1)
113-119: Nil-guard GetClock/GetRandom or face the panic, sucka!These accessors will panic when Providers or the specific provider is nil. Add safe fallbacks. This echoes prior feedback.
Apply this diff:
func (c *ctxEmbed) GetClock() (clock clock.Provider) { - return c.Providers.Clock + if c == nil || c.Providers.Clock == nil { + return clock.New() + } + return c.Providers.Clock } func (c *ctxEmbed) GetRandom() (random random.Provider) { - return c.Providers.Random + if c == nil || c.Providers.Random == nil { + return random.New() + } + return c.Providers.Random }
🧹 Nitpick comments (10)
internal/handlers/handler_oauth2_oidc_wellknown.go (2)
53-54: Use a single base time, sucka.Compute Now() once to avoid micro-drift and double clock calls. I pity the fool who lets exp and iat diverge!
- claims[oidc.ClaimIssuedAt] = ctx.GetClock().Now().UTC().Unix() - claims[oidc.ClaimExpirationTime] = ctx.GetClock().Now().Add(time.Hour).UTC().Unix() + now := ctx.GetClock().Now().UTC() + claims[oidc.ClaimIssuedAt] = now.Unix() + claims[oidc.ClaimExpirationTime] = now.Add(time.Hour).Unix()
54-54: Consider configurable TTL, fool.Hardcoding 1h may fight future policy/tests. Consider a config-driven or const TTL for the discovery JWT.
internal/duo/duo_test.go (6)
39-60: Deduplicate PreAuth tests — keep the table-driven suite. Double work is for fools!These single-case tests duplicate the scenarios covered by TestDuoProvider_PreAuthCall. Consolidate to the table-driven test to reduce runtime and maintenance.
Suggested action:
- Remove the six single-case PreAuth tests and rely on the table-driven test.
Also applies to: 61-82, 83-104, 105-126, 127-148, 149-170
182-191: *Avoid passing nil http.Response in JSON-error cases. Don’t risk a nil-deref later, fool!If the implementation starts reading StatusCode before JSON parsing, a nil response will panic. Use an empty http.Response to be safe.
Apply:
- nil, + &http.Response{},Also applies to: 319-328
3-25: Drop gomock.InOrder when there’s only one expectation. Keep it simple, sucka!Wrapping a single EXPECT in InOrder adds noise without value.
Apply pattern:
-gomock.InOrder( - base.EXPECT(). - SignedCall(...). - Return(...), -) +base.EXPECT(). + SignedCall(...). + Return(...)Also applies to: 34-37, 43-55, 65-76
6-6: Use errors.New instead of fmt.Errorf for static strings and drop fmt import. Trim the fat!Apply:
-import ( - "context" - "errors" - "fmt" +import ( + "context" + "errors" @@ - Return(nil, nil, fmt.Errorf("uguu")), + Return(nil, nil, errors.New("uguu")),Also applies to: 74-75
20-22: Avoid dot-imports; alias the package. Namespaces are for winners, fool!Dot-importing internal/duo hides where types/funcs come from and risks name collisions. Prefer an explicit alias (e.g., duo.NewDuoAPI, duo.PreAuthResponse).
57-59: Loosen brittle error assertions — match substrings, not full strings. Don’t handcuff tests to exact wording!Use assert.ErrorContains to reduce churn when error wrapping changes.
Example:
-assert.EqualError(t, err, "error occurred making the preauth call to the duo api: error occurred parsing response: unexpected end of JSON input") +assert.ErrorContains(t, err, "preauth call") +assert.ErrorContains(t, err, "unexpected end of JSON input")Also applies to: 79-81, 101-103, 123-125, 145-147, 167-169, 297-303, 424-428
internal/clock/real.go (1)
22-25: Minor receiver nit: drop the named receiverYou don't use r; keep it tidy. I pity the fool who keeps unused identifiers.
Apply:
-func (r Real) GetJWTWithTimeFuncOption() (option jwt.ParserOption) { - return jwt.WithTimeFunc(r.Now) +func (Real) GetJWTWithTimeFuncOption() (option jwt.ParserOption) { + return jwt.WithTimeFunc(time.Now) }experimental/embed/context.go (1)
121-123: Use explicit zero IP in ctxEmbed.RemoteIP
I pity the fool who returns nil! ChangectxEmbed.RemoteIPto signal “unknown” by returningnet.IPv4(0,0,0,0)instead ofnil, removing the need for callers to nil-check.func (c *ctxEmbed) RemoteIP() net.IP { - return nil + return net.IPv4(0, 0, 0, 0) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
internal/configuration/test_resources/userdb/debug-tests.ymlis excluded by!**/*.yml
📒 Files selected for processing (66)
cmd/authelia-gen/openid_conformance.go(1 hunks)experimental/embed/context.go(3 hunks)experimental/embed/provider/general.go(1 hunks)internal/clock/fixed.go(2 hunks)internal/clock/provider.go(1 hunks)internal/clock/real.go(2 hunks)internal/commands/context.go(3 hunks)internal/commands/crypto.go(6 hunks)internal/commands/crypto_hash.go(6 hunks)internal/commands/crypto_test.go(1 hunks)internal/commands/debug.go(13 hunks)internal/commands/debug_test.go(1 hunks)internal/commands/storage_run.go(2 hunks)internal/commands/util.go(2 hunks)internal/duo/duo.go(2 hunks)internal/duo/duo_test.go(2 hunks)internal/duo/types.go(2 hunks)internal/handlers/func_test.go(1 hunks)internal/handlers/handler_authz_authn.go(5 hunks)internal/handlers/handler_authz_test.go(16 hunks)internal/handlers/handler_firstfactor_passkey.go(3 hunks)internal/handlers/handler_firstfactor_passkey_test.go(26 hunks)internal/handlers/handler_firstfactor_password.go(2 hunks)internal/handlers/handler_firstfactor_password_test.go(2 hunks)internal/handlers/handler_oauth2_authorization.go(1 hunks)internal/handlers/handler_oauth2_authorization_claims.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core_test.go(10 hunks)internal/handlers/handler_oauth2_authorization_consent_explicit.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_implicit.go(3 hunks)internal/handlers/handler_oauth2_authorization_consent_preconfigured.go(5 hunks)internal/handlers/handler_oauth2_consent.go(6 hunks)internal/handlers/handler_oauth2_device_authorization.go(1 hunks)internal/handlers/handler_oauth2_introspection.go(1 hunks)internal/handlers/handler_oauth2_oidc_userinfo.go(2 hunks)internal/handlers/handler_oauth2_oidc_wellknown.go(1 hunks)internal/handlers/handler_oauth2_token.go(1 hunks)internal/handlers/handler_oauth2_wellknown.go(1 hunks)internal/handlers/handler_register_totp.go(3 hunks)internal/handlers/handler_register_totp_test.go(3 hunks)internal/handlers/handler_reset_password.go(1 hunks)internal/handlers/handler_session_elevation.go(3 hunks)internal/handlers/handler_session_elevation_test.go(4 hunks)internal/handlers/handler_sign_duo.go(1 hunks)internal/handlers/handler_sign_password.go(1 hunks)internal/handlers/handler_sign_password_test.go(1 hunks)internal/handlers/handler_sign_totp.go(2 hunks)internal/handlers/handler_sign_totp_test.go(2 hunks)internal/handlers/handler_sign_webauthn.go(2 hunks)internal/middlewares/authelia_context.go(1 hunks)internal/middlewares/identity_verification.go(1 hunks)internal/middlewares/require_auth_test.go(1 hunks)internal/middlewares/startup.go(2 hunks)internal/middlewares/timing_attack_delay_test.go(2 hunks)internal/middlewares/types.go(2 hunks)internal/middlewares/util.go(2 hunks)internal/mocks/authelia_context.go(1 hunks)internal/mocks/duo_api.go(3 hunks)internal/model/webauthn_test.go(1 hunks)internal/notification/smtp_notifier.go(1 hunks)internal/oidc/types.go(1 hunks)internal/oidc/types_test.go(1 hunks)internal/random/cryptographical.go(1 hunks)internal/regulation/regulator_blackbox_test.go(2 hunks)internal/totp/totp_test.go(3 hunks)internal/utils/const_test.go(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (54)
- internal/clock/provider.go
- internal/commands/crypto_test.go
- experimental/embed/provider/general.go
- cmd/authelia-gen/openid_conformance.go
- internal/handlers/handler_oauth2_oidc_userinfo.go
- internal/handlers/handler_oauth2_wellknown.go
- internal/handlers/handler_sign_totp.go
- internal/handlers/handler_oauth2_authorization.go
- internal/handlers/handler_sign_duo.go
- internal/commands/util.go
- internal/notification/smtp_notifier.go
- internal/handlers/handler_reset_password.go
- internal/commands/context.go
- internal/handlers/handler_sign_totp_test.go
- internal/handlers/handler_oauth2_authorization_consent_explicit.go
- internal/middlewares/identity_verification.go
- internal/middlewares/timing_attack_delay_test.go
- internal/handlers/handler_authz_authn.go
- internal/handlers/handler_firstfactor_password.go
- internal/handlers/handler_oauth2_authorization_consent_core_test.go
- internal/handlers/handler_authz_test.go
- internal/mocks/duo_api.go
- internal/commands/storage_run.go
- internal/clock/fixed.go
- internal/handlers/handler_sign_password.go
- internal/handlers/handler_oauth2_token.go
- internal/handlers/handler_oauth2_authorization_claims.go
- internal/random/cryptographical.go
- internal/handlers/handler_oauth2_authorization_consent_implicit.go
- internal/mocks/authelia_context.go
- internal/middlewares/types.go
- internal/handlers/handler_oauth2_consent.go
- internal/middlewares/startup.go
- internal/handlers/handler_session_elevation_test.go
- internal/duo/duo.go
- internal/handlers/handler_firstfactor_password_test.go
- internal/handlers/handler_register_totp_test.go
- internal/utils/const_test.go
- internal/handlers/func_test.go
- internal/handlers/handler_sign_password_test.go
- internal/regulation/regulator_blackbox_test.go
- internal/duo/types.go
- internal/handlers/handler_session_elevation.go
- internal/handlers/handler_sign_webauthn.go
- internal/handlers/handler_firstfactor_passkey_test.go
- internal/handlers/handler_register_totp.go
- internal/oidc/types.go
- internal/middlewares/require_auth_test.go
- internal/commands/debug.go
- internal/commands/crypto.go
- internal/handlers/handler_oauth2_authorization_consent_core.go
- internal/handlers/handler_firstfactor_passkey.go
- internal/middlewares/authelia_context.go
- internal/commands/debug_test.go
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-29T10:47:45.888Z
Learnt from: james-d-elliott
PR: authelia/authelia#10189
File: internal/clock/provider.go:14-15
Timestamp: 2025-08-29T10:47:45.888Z
Learning: The internal/mocks directory does not contain any mock clock implementations. Tests use concrete clock instances like clock.New(), clock.NewFixed(), and direct assignment to mock.Ctx.Providers.Clock instead of generated mocks for the clock.Provider interface.
Applied to files:
internal/model/webauthn_test.gointernal/duo/duo_test.gointernal/totp/totp_test.go
🧬 Code graph analysis (10)
internal/model/webauthn_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/handlers/handler_oauth2_device_authorization.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/oidc/session.go (1)
NewSessionWithRequestedAt(22-38)
internal/oidc/types_test.go (1)
internal/oidc/config.go (1)
Config(80-130)
internal/handlers/handler_oauth2_authorization_consent_preconfigured.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/middlewares/util.go (4)
experimental/embed/context.go (1)
New(18-61)experimental/embed/provider/general.go (1)
New(26-28)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)
internal/handlers/handler_oauth2_introspection.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/oidc/session.go (1)
NewSessionWithRequestedAt(22-38)
internal/commands/crypto_hash.go (2)
internal/configuration/schema/authentication.go (1)
AuthenticationBackend(10-19)internal/authentication/file_user_provider.go (1)
NewFileCryptoHashFromConfig(242-288)
internal/duo/duo_test.go (3)
internal/duo/types.go (6)
BaseProvider(15-17)Response(43-49)PreAuthResponse(60-68)Device(32-40)AuthResponse(52-57)Provider(20-24)internal/session/types.go (1)
UserSession(20-48)internal/middlewares/types.go (2)
Context(60-69)Providers(40-58)
experimental/embed/context.go (5)
internal/middlewares/types.go (2)
Providers(40-58)Context(60-69)experimental/embed/types.go (2)
Providers(19-19)Configuration(10-10)internal/clock/provider.go (1)
Provider(10-15)internal/service/provider.go (2)
Provider(13-28)Context(46-52)internal/oidc/types.go (1)
Context(212-221)
internal/totp/totp_test.go (3)
internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)internal/clock/fixed.go (1)
NewFixed(10-12)
⏰ 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). (2)
- GitHub Check: Analyze (go)
- GitHub Check: StepSecurity Harden-Runner
🔇 Additional comments (18)
internal/handlers/handler_oauth2_device_authorization.go (1)
43-43: Clock injection is righteous—LGTM, fool!Good swap to ctx.GetClock().Now() for deterministic, testable time. Plays nice with oidc.NewSessionWithRequestedAt’s UTC normalization.
internal/handlers/handler_oauth2_authorization_consent_preconfigured.go (2)
205-209: LGTM on switching to ctx.GetClock().Now()Looks tight, fool. Centralized clock keeps tests deterministic.
89-96: Freeze time once in this handler
Capture now := ctx.GetClock().Now() and reuse for both CanGrant and SetRespondedAt to avoid drift.- if !consent.CanGrant(ctx.GetClock().Now()) { + now := ctx.GetClock().Now() + if !consent.CanGrant(now) { ctx.Logger.Errorf(logFmtErrConsentCantGrantPreConf, requester.GetID(), client.GetID(), client.GetConsentPolicy(), consent.ChallengeID) ctx.Providers.OpenIDConnect.WriteDynamicAuthorizeError(ctx, rw, requester, oidc.ErrConsentCouldNotPerform) return nil, true } … - consent.SetRespondedAt(ctx.GetClock().Now(), config.ID) + consent.SetRespondedAt(now, config.ID)Verify no bypasses remain
rg -n -C2 -g '!/vendor/' -P '\bctx.GetClock().Now()|\btime.Now(' internalI pity the fool who doesn’t!
internal/commands/crypto_hash.go (8)
5-5: LGTM: decoupled I/O and flag parsing, fool!Importing io and pflag tightens the seams around CLI and output. Clean move.
Also applies to: 12-12
72-76: LGTM: PreRunE chain centralizationDefaults + flag-map + config load + section validate is a tight sequence. I pity the fool who duplicates this elsewhere.
173-175: LGTM: updated password retrieval pathValidate now uses the writer/flags-aware getter. Solid.
198-205: LGTM: flag mapping by useCentralizing flag-to-config mapping via getCryptoHashGenerateMapFlagsFromUse keeps things sane across subcommands.
209-210: LGTM: generation flow extractedDelegating to runCryptoHashGenerate keeps RunE lean. Respect.
212-219: LGTM: writer-first helperNew helper signature with io.Writer and *pflag.FlagSet is the right abstraction for testability and UX. Good hustle.
244-252: LGTM: explicit outputs to provided writerRandom password, URL-encoded variant, and digest all go to w. Scriptable and testable. That’s how you do it.
288-295: LGTM: skip confirm on validate pathComparing use against validate Use and short-circuiting confirmation keeps UX sharp.
internal/duo/duo_test.go (2)
27-37: LGTM: basic API construction test is sound. Winner move!Constructor wiring and basic nil-check are appropriate.
308-431: LGTM: thorough AuthCall table tests. That’s how you cover code paths, sucka!Good breadth: API errors, stat handling (FAIL/unknown/OK), status code checks, and happy-path unmarshal validations.
internal/model/webauthn_test.go (1)
459-459: Replace direct ctx.Clock assignment in internal/oidc/types_test.go
Line 71: usectx.Providers.Clock = clock.NewFixed(time.Unix(10000000000, 0))instead ofctx.Clock = …. I pity the fool who leaves a stray direct clock assignment.⛔ Skipped due to learnings
Learnt from: james-d-elliott PR: authelia/authelia#10189 File: internal/clock/provider.go:14-15 Timestamp: 2025-08-29T10:47:45.888Z Learning: The internal/mocks directory does not contain any mock clock implementations. Tests use concrete clock instances like clock.New(), clock.NewFixed(), and direct assignment to mock.Ctx.Providers.Clock instead of generated mocks for the clock.Provider interface.internal/handlers/handler_oauth2_introspection.go (1)
30-30: Approve: consistent use of ctx.GetClock().Now(). No stray ctx.Clock.Now() calls found—I pity the fool who leaves stray calls behind.internal/clock/real.go (1)
5-7: Add jwt/v5 import for time-func option: LGTMDependency aligns with new clock interface. I pity the fool who forgets to keep go.mod in sync.
internal/totp/totp_test.go (1)
112-112: Switch to constructors clock.New()/random.New(): LGTMCleaner and consistent with provider interfaces. I pity the fool who new’s structs directly when factories exist.
Also applies to: 159-159, 223-223
internal/middlewares/util.go (1)
38-38: Good move to a factory RNG.Switching to random.New() is clean and centralizes construction. I pity the fool who hand-rolls RNGs.
0ad7da8 to
a39e3d8
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #10189 +/- ##
==========================================
+ Coverage 73.53% 74.03% +0.49%
==========================================
Files 402 403 +1
Lines 37480 37531 +51
Branches 1183 1183
==========================================
+ Hits 27561 27786 +225
+ Misses 8710 8556 -154
+ Partials 1209 1189 -20
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
a39e3d8 to
0fc7311
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
internal/handlers/handler_firstfactor_passkey_test.go (2)
185-201: Use the constant, fool: replace"Passkey"withregulation.AuthTypePasskey.Avoid stringly-typed enums; you already use the constant elsewhere in this file. Make it consistent to prevent typos.
Example edits (apply across these expectations):
- Type: "Passkey", + Type: regulation.AuthTypePasskey,Also applies to: 898-927, 1019-1031, 1119-1129, 1215-1226, 1287-1297, 1382-1393, 1432-1441, 1478-1487, 1508-1517, 1550-1559, 1636-1646, 1668-1677, 1711-1720
185-230: Standardize time source in handler_firstfactor_passkey_test.go, sucka!
I pity the fool who mixestime.Now()andmock.Clock.Now()—replace every instance withmock.Ctx.Providers.Clock.Now().UTC()(plus.Add(...)where needed) to drive all timestamps off the provider and prevent flaky tests.internal/commands/crypto_hash.go (1)
119-121: Align crypto_hash flags with their config mappings, fool!
- Argon2: I pity the fool who added
--profilewithout mapping it—addcmdFlagNameProfiletogetCryptoHashGenerateMapFlagsFromUse(e.g.password.argon2.profile), and either define the missingiterations/parallelismflags ininternal/commands/crypto_hash.goor remove those keys from its mapping.- PBKDF2: I pity the fool who mapped
key-sizebut never defined its flag—addcmdFlagKeySize(cmd, schema.DefaultPasswordConfig.PBKDF2.KeyLength)under the PBKDF2 case, and confirm the variant-based default foriterationsbehaves as intended.internal/commands/debug.go (1)
291-333: Add a dial timeout to avoid hanging TLS probes.Without a timeout, this can block indefinitely on dead hosts. Don’t leave users waitin’.
Apply:
+ "net" ... - if conn, err = tls.Dial(address.Network(), address.NetworkAddress(), config); err != nil { + d := &net.Dialer{Timeout: 10 * time.Second} + if conn, err = tls.DialWithDialer(d, address.Network(), address.NetworkAddress(), config); err != nil { switch errStr := err.Error(); {
♻️ Duplicate comments (6)
internal/middlewares/types.go (2)
56-58: Providers now carry Random/Clock — never leave ’em nil, fool.Constructor NewProvidersBasic sets both; verify no stray Providers{} literals bypass it.
#!/bin/bash # Find Providers literals that might omit Random/Clock rg -nP --type=go 'middlewares\.Providers\s*{[^}]*}' -C2 # Prefer uses of NewProvidersBasic rg -nP --type=go 'NewProvidersBasic\(' -n
61-69: Context interface expanded — make sure AutheliaCtx walks the walk.Confirm AutheliaCtx implements GetClock/GetRandom/GetLogger/GetProviders/GetConfiguration/RemoteIP and satisfies context.Context.
#!/bin/bash # AutheliaCtx definition rg -nP --type=go 'type\s+AutheliaCtx\b' # Methods required by Context for m in GetClock GetRandom GetLogger GetProviders GetConfiguration RemoteIP; do rg -nP --type=go "func\s+\(\s*\*?AutheliaCtx\s*\)\s+$m\s*\(" -C2 done # Does AutheliaCtx satisfy context.Context (Deadline/Done/Err/Value)? for m in Deadline Done Err Value; do rg -nP --type=go "func\s+\(\s*\*?AutheliaCtx\s*\)\s+$m\s*\(" -C2 doneinternal/duo/duo.go (2)
22-36: Quit spillin’ PII in logs, fool — don’t log raw Duo bodies. Also enrich error context.Trace logs include the full response body which can contain PII/secret material. Log metadata only, and add path/user to wrapped errors from SignedCall/parse.
Apply:
- return nil, fmt.Errorf("error occurred making signed call: %w", err) + return nil, fmt.Errorf("duo signed call failed (path=%s user=%s): %w", path, userSession.Username, err) ... - ctx.GetLogger().Tracef("Duo endpoint: %s response raw data for %s from IP %s: %s", path, userSession.Username, ctx.RemoteIP().String(), string(body)) + ctx.GetLogger().WithFields(map[string]any{ + "path": path, "username": userSession.Username, "remote_ip": ctx.RemoteIP().String(), "response_bytes": len(body), + }).Trace("Duo endpoint response received") ... - return nil, fmt.Errorf("error occurred parsing response: %w", err) + return nil, fmt.Errorf("duo response parse failed (path=%s user=%s): %w", path, userSession.Username, err)
38-68: Return actionable errors with Duo status/code/message.Generic messages make operators suffer. Surface Stat/Code/Message in errors, sucker.
Apply:
- return &response, fmt.Errorf("failure status code was returned") + return &response, fmt.Errorf("duo returned failure status code %d (%s): %s", response.Code, response.Stat, response.Message) ... - return &response, fmt.Errorf("failure status was returned") + return &response, fmt.Errorf("duo returned failure status (%s): %s", response.Stat, response.Message) ... - return &response, fmt.Errorf("unknown status was returned") + return &response, fmt.Errorf("duo returned unknown status (%s) code %d: %s", response.Stat, response.Code, response.Message)internal/duo/duo_test.go (2)
433-444: Drop unused hook; it’s dead weight.Field ‘hook’ isn’t used; keep logger only.
-func NewTestCtx(ip net.IP) *TestCtx { - logger, hook := test.NewNullLogger() +func NewTestCtx(ip net.IP) *TestCtx { + logger, _ := test.NewNullLogger() @@ type TestCtx struct { ip net.IP logger *logrus.Entry - hook *test.Hook - providers middlewares.ProvidersAlso applies to: 446-454
480-482: Don’t return nil config, fool — avoid NPEs.Return an empty configuration to keep code-under-test safe.
-func (t *TestCtx) GetConfiguration() (config *schema.Configuration) { - return nil -} +func (t *TestCtx) GetConfiguration() (config *schema.Configuration) { + cfg := &schema.Configuration{} + return cfg +}
🧹 Nitpick comments (15)
internal/notification/smtp_notifier.go (1)
95-95: Make RNG injectable for tighter tests, sucka!Offer an alternate constructor that accepts
random.Provider(fallback torandom.New()). This lets tests inject deterministic RNGs and matches the Providers pattern across the codebase.// New constructor enabling DI of RNG; default to crypto RNG when nil. func NewSMTPNotifierWithProviders(config *schema.NotifierSMTP, certPool *x509.CertPool, rng random.Provider) *SMTPNotifier { if rng == nil { rng = random.New() } log := logging.Logger().WithFields(map[string]any{"provider": "notifier"}) var configTLS *tls.Config if config.TLS != nil { configTLS = utils.NewTLSConfig(config.TLS, certPool) } var opts []gomail.Option switch { case config.Address.IsExplicitlySecure(): opts = []gomail.Option{gomail.WithSSLPort(false), gomail.WithTLSPortPolicy(gomail.TLSMandatory)} log.Trace("Configuring with Explicit TLS") case config.DisableStartTLS: opts = []gomail.Option{gomail.WithTLSPortPolicy(gomail.NoTLS), gomail.WithPort(int(config.Address.Port()))} log.Trace("Configuring without TLS") case config.DisableRequireTLS: opts = []gomail.Option{gomail.WithTLSPortPolicy(gomail.TLSOpportunistic)} log.Trace("Configuring with Opportunistic TLS") default: opts = []gomail.Option{gomail.WithTLSPortPolicy(gomail.TLSMandatory)} log.Trace("Configuring with Mandatory TLS") } opts = append(opts, gomail.WithTLSConfig(configTLS), gomail.WithTimeout(config.Timeout), gomail.WithHELO(config.Identifier), gomail.WithoutNoop(), gomail.WithPort(int(config.Address.Port())), ) var domain string if at := strings.Index(config.Sender.Address, "@"); at >= 0 { domain = config.Sender.Address[at+1:] } else { domain = "localhost.localdomain" } return &SMTPNotifier{ factory: &StandardSMTPClientFactory{config: config, opts: opts}, config: config, domain: domain, random: rng, tls: configTLS, log: log, opts: opts, } } // Preserve current API and delegate. func NewSMTPNotifier(config *schema.NotifierSMTP, certPool *x509.CertPool) *SMTPNotifier { return NewSMTPNotifierWithProviders(config, certPool, nil) }internal/middlewares/authelia_context_blackbox_test.go (3)
333-333: Keep it consistent: don’t inline the factory when creating AutheliaCtx, sucka.Most tests bind the providers to a var first; do the same here for symmetry and easier overrides.
- middleware := middlewares.NewAutheliaCtx(ctx, config, middlewares.NewProvidersBasic()) + providers := middlewares.NewProvidersBasic() + middleware := middlewares.NewAutheliaCtx(ctx, config, providers)- middleware := middlewares.NewAutheliaCtx(ctx, config, middlewares.NewProvidersBasic()) + providers := middlewares.NewProvidersBasic() + middleware := middlewares.NewAutheliaCtx(ctx, config, providers)Also applies to: 935-935
775-778: Fix that test name, fool: “Cryptographical” → “Cryptographic”.Minor wording nit, but it reads cleaner and matches common usage.
- "ShouldHandleCryptographical", + "ShouldHandleCryptographic",
986-987: Consider mocking SessionProvider to keep tests lean, fool.Using the real session.NewProvider is fine, but a lightweight mock can cut setup time and isolate behavior.
I can sketch a minimal gomock for SessionProvider if you want to trim dependencies in this test.
internal/handlers/handler_oauth2_authorization_consent_core_test.go (2)
877-877: Nit: avoid referencing mock clock in gomock Return payloads.Tests already pin time to 1970-01-12 13:46:40 UTC (1000000s). Using
mock.Ctx.Providers.Clock.Now()in Return structs couples the fixture to the clock field unnecessarily. Prefer a fixed var so expectations read cleaner and won’t break if the setup changes. I pity the fool who over-couples tests.Apply these focused replacements:
- Return(&model.OAuth2ConsentSession{ChallengeID: challenge, Subject: uuid.NullUUID{UUID: sub, Valid: true}, ExpiresAt: mock.Ctx.Providers.Clock.Now().Add(time.Second * 10)}, nil), + Return(&model.OAuth2ConsentSession{ChallengeID: challenge, Subject: uuid.NullUUID{UUID: sub, Valid: true}, ExpiresAt: fixedTime.Add(10 * time.Second)}, nil),- Return(&model.OAuth2ConsentSession{ID: 40, ChallengeID: challenge, ClientID: "test", Subject: uuid.NullUUID{UUID: sub, Valid: true}, Form: "prompt=login", RequestedAt: time.Unix(1000000, 0), ExpiresAt: mock.Ctx.Providers.Clock.Now().Add(time.Second * 10)}, nil), + Return(&model.OAuth2ConsentSession{ID: 40, ChallengeID: challenge, ClientID: "test", Subject: uuid.NullUUID{UUID: sub, Valid: true}, Form: "prompt=login", RequestedAt: fixedTime, ExpiresAt: fixedTime.Add(10 * time.Second)}, nil),- Return(&model.OAuth2ConsentSession{ID: 40, ChallengeID: challenge, ClientID: "test", Subject: uuid.NullUUID{UUID: sub, Valid: true}, Form: "max_age=10", RequestedAt: time.Unix(1000000, 0), ExpiresAt: mock.Ctx.Providers.Clock.Now().Add(time.Second * 10)}, nil), + Return(&model.OAuth2ConsentSession{ID: 40, ChallengeID: challenge, ClientID: "test", Subject: uuid.NullUUID{UUID: sub, Valid: true}, Form: "max_age=10", RequestedAt: fixedTime, ExpiresAt: fixedTime.Add(10 * time.Second)}, nil),- Return(&model.OAuth2ConsentSession{ID: 44, ChallengeID: challenge, Subject: uuid.NullUUID{UUID: sub, Valid: true}, Authorized: true, ExpiresAt: mock.Ctx.Providers.Clock.Now().Add(time.Second * 10), RespondedAt: sql.NullTime{Time: time.Unix(1000000, 0), Valid: true}}, nil), + Return(&model.OAuth2ConsentSession{ID: 44, ChallengeID: challenge, Subject: uuid.NullUUID{UUID: sub, Valid: true}, Authorized: true, ExpiresAt: fixedTime.Add(10 * time.Second), RespondedAt: sql.NullTime{Time: fixedTime, Valid: true}}, nil),- Return(&model.OAuth2ConsentSession{ID: 44, ChallengeID: challenge, Subject: uuid.NullUUID{UUID: sub, Valid: true}, ExpiresAt: mock.Ctx.Providers.Clock.Now().Add(time.Second * 10), RespondedAt: sql.NullTime{Time: time.Unix(1000000, 0), Valid: true}}, nil), + Return(&model.OAuth2ConsentSession{ID: 44, ChallengeID: challenge, Subject: uuid.NullUUID{UUID: sub, Valid: true}, ExpiresAt: fixedTime.Add(10 * time.Second), RespondedAt: sql.NullTime{Time: fixedTime, Valid: true}}, nil),Add once near top of the file (outside tests) or at the start of each test func:
var fixedTime = time.Unix(1_000_000, 0)Also applies to: 916-916, 1005-1005, 1183-1183, 1237-1237
217-217: Nit: DRY up clock setup across suites.You repeat the same two lines in each suite. Wrap it. I pity the fool who likes boilerplate.
Add a tiny helper in this test file:
func setFixedClock(mock *mocks.MockAutheliaCtx, t time.Time) { mock.Ctx.Providers.Clock = &mock.Clock mock.Clock.Set(t) }Then replace occurrences:
- mock.Ctx.Providers.Clock = &mock.Clock - mock.Clock.Set(time.Unix(1000000, 0)) + setFixedClock(mock, fixedTime)Also applies to: 379-379, 719-719, 1021-1021, 1358-1358
internal/handlers/handler_firstfactor_passkey_test.go (1)
1665-1666: Drop redundant clock setup.
setUpMockClock(mock)is called inside the test case and again in the test runner. One call is enough, fool. Keep the runner call; remove the per-case one.- setUpMockClock(mock)Also applies to: 1757-1759
internal/commands/crypto_hash.go (2)
220-223: Defensive nil guard: add top-level config check, fool.You guard
config.AuthenticationBackend.File, but ifconfigis ever nil this will panic. Cheap insurance:func runCryptoHashGenerate(w io.Writer, flags *pflag.FlagSet, use string, args []string, config *schema.Configuration) (err error) { var ( hash algorithm.Hash digest algorithm.Digest password string random bool ) - if config.AuthenticationBackend.File == nil { + if config == nil { + return fmt.Errorf("configuration is not loaded") + } + if config.AuthenticationBackend.File == nil { return fmt.Errorf("authentication backend file is not configured") }
316-333: Minor UX nit: extra blank lines.Multiple
Fprintln(w)calls can stack blank lines. Consider emitting a single trailing newline per prompt sequence, fool.internal/handlers/handler_oauth2_oidc_userinfo.go (1)
128-128: Hydration now clock-injected — keep it consistent, fool.One more spot still uses time.Now() for iat; consider using ctx.GetClock().Now() for testability and determinism.
Example:
claims[oidc.ClaimIssuedAt] = ctx.GetClock().Now().UTC().Unix()internal/handlers/handler_firstfactor_password.go (2)
136-140: Switch to ctx.GetClock().Now() is right — finish the job for determinism.Use the provider clock for requestTime too so tests don’t flake.
Apply:
- requestTime := time.Now() + requestTime := ctx.GetClock().Now()
267-271: Same here: great change — also replace time.Now() earlier in this handler.Keep all timing via the injected clock, sucka.
Apply:
- requestTime := time.Now() + requestTime := ctx.GetClock().Now()internal/duo/duo.go (2)
72-82: Wrap with path/user context in PreAuth error flows.Make troubleshooting faster, fool.
Apply:
- return nil, fmt.Errorf("error occurred making the preauth call to the duo api: %w", err) + return nil, fmt.Errorf("duo preauth call failed (path=/auth/v2/preauth user=%s): %w", userSession.Username, err) ... - return nil, fmt.Errorf("error occurred parsing the duo api preauth json response: %w", err) + return nil, fmt.Errorf("duo preauth JSON parse failed: %w", err)
88-98: Same story for Auth call — add context and clearer parse error.Don’t make folks dig through logs.
Apply:
- return nil, fmt.Errorf("error occurred making the auth call to the duo api: %w", err) + return nil, fmt.Errorf("duo auth call failed (path=/auth/v2/auth user=%s): %w", userSession.Username, err) ... - return nil, fmt.Errorf("error occurred parsing the duo api auth json response: %w", err) + return nil, fmt.Errorf("duo auth JSON parse failed: %w", err)internal/duo/duo_test.go (1)
57-59: Loosen brittle error assertions.Use ErrorContains to reduce coupling to exact strings.
-assert.EqualError(t, err, "error occurred making the preauth call to the duo api: failure status was returned") +assert.ErrorContains(t, err, "preauth") +assert.ErrorContains(t, err, "failure status")Apply similarly across these cases.
Also applies to: 79-81, 101-103, 123-125, 145-147, 167-169, 327-329, 347-349, 367-369, 377-379, 391-393
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
internal/configuration/test_resources/userdb/debug-tests.ymlis excluded by!**/*.yml
📒 Files selected for processing (73)
cmd/authelia-gen/openid_conformance.go(1 hunks)experimental/embed/context.go(3 hunks)experimental/embed/provider/general.go(1 hunks)internal/clock/fixed.go(2 hunks)internal/clock/provider.go(1 hunks)internal/clock/real.go(2 hunks)internal/commands/context.go(3 hunks)internal/commands/crypto.go(6 hunks)internal/commands/crypto_hash.go(6 hunks)internal/commands/crypto_test.go(1 hunks)internal/commands/debug.go(13 hunks)internal/commands/debug_test.go(1 hunks)internal/commands/storage_run.go(4 hunks)internal/commands/util.go(2 hunks)internal/duo/duo.go(2 hunks)internal/duo/duo_test.go(2 hunks)internal/duo/types.go(2 hunks)internal/handlers/func_test.go(1 hunks)internal/handlers/handler_authz_authn.go(5 hunks)internal/handlers/handler_authz_test.go(16 hunks)internal/handlers/handler_firstfactor_passkey.go(3 hunks)internal/handlers/handler_firstfactor_passkey_test.go(26 hunks)internal/handlers/handler_firstfactor_password.go(2 hunks)internal/handlers/handler_firstfactor_password_test.go(2 hunks)internal/handlers/handler_oauth2_authorization.go(1 hunks)internal/handlers/handler_oauth2_authorization_claims.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core_test.go(10 hunks)internal/handlers/handler_oauth2_authorization_consent_explicit.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_implicit.go(3 hunks)internal/handlers/handler_oauth2_authorization_consent_preconfigured.go(5 hunks)internal/handlers/handler_oauth2_consent.go(6 hunks)internal/handlers/handler_oauth2_device_authorization.go(1 hunks)internal/handlers/handler_oauth2_introspection.go(1 hunks)internal/handlers/handler_oauth2_oidc_userinfo.go(2 hunks)internal/handlers/handler_oauth2_oidc_wellknown.go(1 hunks)internal/handlers/handler_oauth2_token.go(1 hunks)internal/handlers/handler_oauth2_wellknown.go(1 hunks)internal/handlers/handler_register_totp.go(3 hunks)internal/handlers/handler_register_totp_test.go(3 hunks)internal/handlers/handler_reset_password.go(1 hunks)internal/handlers/handler_session_elevation.go(3 hunks)internal/handlers/handler_session_elevation_test.go(4 hunks)internal/handlers/handler_sign_duo.go(1 hunks)internal/handlers/handler_sign_password.go(1 hunks)internal/handlers/handler_sign_password_test.go(1 hunks)internal/handlers/handler_sign_totp.go(2 hunks)internal/handlers/handler_sign_totp_test.go(2 hunks)internal/handlers/handler_sign_webauthn.go(2 hunks)internal/middlewares/authelia_context.go(1 hunks)internal/middlewares/authelia_context_blackbox_test.go(13 hunks)internal/middlewares/identity_verification.go(1 hunks)internal/middlewares/require_auth_test.go(1 hunks)internal/middlewares/startup.go(2 hunks)internal/middlewares/timing_attack_delay_test.go(2 hunks)internal/middlewares/types.go(2 hunks)internal/middlewares/util.go(2 hunks)internal/mocks/authelia_context.go(2 hunks)internal/mocks/duo_api.go(3 hunks)internal/model/webauthn_test.go(1 hunks)internal/notification/smtp_notifier.go(1 hunks)internal/oidc/types.go(1 hunks)internal/oidc/types_test.go(1 hunks)internal/random/cryptographical.go(1 hunks)internal/regulation/regulator_blackbox_test.go(2 hunks)internal/server/server_test.go(1 hunks)internal/service/file_watcher_test.go(2 hunks)internal/service/sever_test.go(4 hunks)internal/service/signal_test.go(2 hunks)internal/suites/example/compose/duo-api/duo_api.js(3 hunks)internal/totp/totp_test.go(3 hunks)internal/utils/const_test.go(1 hunks)internal/utils/exec.go(0 hunks)
💤 Files with no reviewable changes (1)
- internal/utils/exec.go
🚧 Files skipped from review as they are similar to previous changes (54)
- internal/commands/crypto_test.go
- internal/handlers/handler_sign_totp.go
- internal/commands/debug_test.go
- internal/oidc/types_test.go
- internal/middlewares/timing_attack_delay_test.go
- experimental/embed/provider/general.go
- internal/handlers/handler_oauth2_token.go
- internal/model/webauthn_test.go
- internal/random/cryptographical.go
- internal/handlers/handler_firstfactor_password_test.go
- internal/mocks/duo_api.go
- internal/handlers/handler_oauth2_authorization.go
- internal/handlers/handler_sign_password.go
- internal/handlers/handler_reset_password.go
- cmd/authelia-gen/openid_conformance.go
- internal/handlers/handler_authz_test.go
- internal/handlers/func_test.go
- internal/clock/provider.go
- internal/handlers/handler_oauth2_authorization_consent_explicit.go
- internal/handlers/handler_sign_duo.go
- internal/utils/const_test.go
- internal/handlers/handler_oauth2_authorization_consent_implicit.go
- internal/handlers/handler_session_elevation.go
- internal/handlers/handler_register_totp.go
- internal/handlers/handler_oauth2_introspection.go
- internal/handlers/handler_firstfactor_passkey.go
- internal/handlers/handler_oauth2_authorization_consent_core.go
- internal/handlers/handler_session_elevation_test.go
- internal/handlers/handler_sign_password_test.go
- internal/middlewares/identity_verification.go
- internal/handlers/handler_oauth2_wellknown.go
- internal/middlewares/util.go
- internal/handlers/handler_sign_webauthn.go
- internal/clock/real.go
- internal/totp/totp_test.go
- internal/handlers/handler_oauth2_consent.go
- internal/handlers/handler_sign_totp_test.go
- internal/handlers/handler_oauth2_device_authorization.go
- internal/commands/context.go
- internal/commands/util.go
- internal/mocks/authelia_context.go
- internal/clock/fixed.go
- internal/handlers/handler_oauth2_oidc_wellknown.go
- internal/handlers/handler_register_totp_test.go
- internal/regulation/regulator_blackbox_test.go
- internal/middlewares/startup.go
- experimental/embed/context.go
- internal/commands/crypto.go
- internal/handlers/handler_authz_authn.go
- internal/handlers/handler_oauth2_authorization_claims.go
- internal/middlewares/require_auth_test.go
- internal/handlers/handler_oauth2_authorization_consent_preconfigured.go
- internal/middlewares/authelia_context.go
- internal/duo/types.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-29T10:47:45.888Z
Learnt from: james-d-elliott
PR: authelia/authelia#10189
File: internal/clock/provider.go:14-15
Timestamp: 2025-08-29T10:47:45.888Z
Learning: The internal/mocks directory does not contain any mock clock implementations. Tests use concrete clock instances like clock.New(), clock.NewFixed(), and direct assignment to mock.Ctx.Providers.Clock instead of generated mocks for the clock.Provider interface.
Applied to files:
internal/handlers/handler_oauth2_authorization_consent_core_test.gointernal/handlers/handler_firstfactor_passkey_test.go
📚 Learning: 2025-08-27T21:37:17.083Z
Learnt from: james-d-elliott
PR: authelia/authelia#10059
File: internal/commands/storage_run.go:23-23
Timestamp: 2025-08-27T21:37:17.083Z
Learning: The Authelia project uses "go.yaml.in/yaml/v4" as their YAML package import path, not the standard "gopkg.in/yaml.v3" or "gopkg.in/yaml.v2". This is used consistently across their codebase.
Applied to files:
internal/commands/storage_run.go
🧬 Code graph analysis (15)
internal/handlers/handler_oauth2_oidc_userinfo.go (3)
internal/middlewares/types.go (2)
Providers(40-58)Context(60-69)internal/oidc/types.go (1)
Context(212-221)internal/oidc/session.go (1)
NewSessionWithRequestedAt(22-38)
internal/service/signal_test.go (1)
internal/middlewares/util.go (1)
NewProvidersBasic(76-81)
internal/server/server_test.go (2)
internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/random/mathematical.go (1)
NewMathematical(13-18)
internal/notification/smtp_notifier.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/service/file_watcher_test.go (2)
internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/middlewares/types.go (1)
Providers(40-58)
internal/commands/crypto_hash.go (2)
internal/configuration/schema/authentication.go (1)
AuthenticationBackend(10-19)internal/authentication/file_user_provider.go (1)
NewFileCryptoHashFromConfig(242-288)
internal/duo/duo_test.go (4)
internal/mocks/duo_base_api.go (1)
NewMockDuoBaseProvider(34-38)internal/duo/types.go (6)
BaseProvider(15-17)Response(43-49)PreAuthResponse(60-68)Device(32-40)AuthResponse(52-57)Provider(20-24)internal/session/types.go (1)
UserSession(20-48)internal/middlewares/types.go (2)
Context(60-69)Providers(40-58)
internal/middlewares/authelia_context_blackbox_test.go (2)
internal/middlewares/authelia_context.go (1)
NewAutheliaCtx(43-51)internal/middlewares/util.go (1)
NewProvidersBasic(76-81)
internal/handlers/handler_oauth2_authorization_consent_core_test.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/model/oidc.go (1)
OAuth2ConsentSession(254-276)
internal/handlers/handler_firstfactor_passkey_test.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/model/regulation.go (3)
BannedUser(26-35)AuthenticationAttempt(9-19)BannedIP(37-46)
internal/commands/storage_run.go (2)
internal/middlewares/types.go (1)
ServiceContext(71-79)internal/storage/provider.go (1)
Provider(15-328)
internal/service/sever_test.go (3)
internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/middlewares/types.go (1)
Providers(40-58)internal/metrics/prometheus.go (1)
NewPrometheus(12-18)
internal/duo/duo.go (3)
internal/duo/types.go (3)
Response(43-49)PreAuthResponse(60-68)AuthResponse(52-57)internal/middlewares/types.go (1)
Context(60-69)internal/session/types.go (1)
UserSession(20-48)
internal/commands/debug.go (4)
internal/middlewares/util.go (1)
NewAuthenticationProvider(84-93)internal/expression/user_attributes.go (1)
NewUserAttributes(13-24)internal/oidc/claims.go (1)
NewCustomClaimsStrategy(444-506)internal/commands/context.go (1)
CmdCtx(42-52)
internal/middlewares/types.go (4)
internal/clock/provider.go (1)
Provider(10-15)internal/service/provider.go (2)
Provider(13-28)Context(46-52)experimental/embed/context.go (1)
Context(65-74)internal/oidc/types.go (1)
Context(212-221)
⏰ 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). (2)
- GitHub Check: Analyze (go)
- GitHub Check: StepSecurity Harden-Runner
🔇 Additional comments (39)
internal/notification/smtp_notifier.go (1)
95-95: Solid swap to random.New(), fool — crypto-grade and consistent.This aligns with the centralized provider pattern and preserves cryptographic strength via the
randompackage’sNew()implementation. No behavior regression spotted. I pity the fool who hand-wires RNGs!internal/middlewares/authelia_context_blackbox_test.go (1)
404-404: Solid move centralizing providers with NewProvidersBasic(). I like that hustle, fool.Clean, DRY, and consistent test wiring. Reduces boilerplate and future churn.
Also applies to: 485-485, 558-558, 633-633, 684-684, 743-743, 785-785, 865-865, 986-986, 1012-1012, 1081-1081
internal/handlers/handler_oauth2_authorization_consent_core_test.go (6)
217-217: LGTM: switched to Providers.Clock.Clean alignment with the providers refactor. I pity the fool who keeps using mock.Ctx.Clock.
379-379: LGTM: consistent clock provider usage.Keep it tight and consistent across tests, sucka.
719-719: LGTM: provider-based clock in implicit-no-id tests.Right move, fool.
1021-1021: LGTM: provider clock set before expectations.Deterministic time, no jibber-jabber.
1358-1358: LGTM: explicit-with-id suite uses Providers.Clock too.Uniformity wins, chump.
217-219: No legacy Ctx.Clock references remain
I pity the fool who splits time sources – all clock usages now consistently go through Providers.Clock.internal/handlers/handler_firstfactor_passkey_test.go (1)
189-201: LGTM: moved auth log timestamps to Providers.Clock.Nice refactor. Deterministic times make mocks happy. I pity the flaky test, but you ain’t one.
Also applies to: 249-260, 286-297, 409-418, 616-626, 717-728, 918-927, 1022-1031, 1121-1130, 1217-1226, 1289-1297, 1384-1393, 1434-1442, 1479-1487, 1509-1517, 1552-1560, 1638-1646, 1669-1677, 1712-1720
internal/commands/crypto_hash.go (10)
5-5: LGTM on new deps, fool.
ioandpflagare used correctly by the writer/flag refactor. I pity the fool who adds imports they don't use!Also applies to: 12-12
71-77: Confirm intent: parent uses PreRunE while children use PersistentPreRunE.Cobra won’t run a parent’s PreRunE for subcommands. You duplicated the chain on subs (via PersistentPreRunE), which is fine, but verify this split is intentional to avoid surprises later, fool.
Would you like me to scan the repo to list all crypto subcommands and ensure the config load/validate chain runs for each invocation path?
173-175: Unified password acquisition looks solid.Routing validate through
cmdFlagsCryptoHashGetPasswordwithuseRandom=falseis correct, fool.
198-205: Flags mapping source wiring is right.Appending
NewCommandLineSourceWithMappingonly when non-nil is clean.
209-210: Good delegation to writer/flags-driven generator.Cleaner separation of concerns. Respect.
232-237: Algorithm override strategy is fine.Only mutate the algo when a specific subcommand is used; otherwise honor config. Good discipline.
239-245: Hash init and digest flow LGTM.Errors are surfaced properly. Rock solid.
247-256: Output UX is clear.Printing URL-encoded when it differs is a nice touch, fool.
260-276: Helper correctly infers randomness from setters.Function is sound. Just make sure all relevant setters are passed by the caller (see next comment).
Would you like me to add a test ensuring any single random-* flag (length/charset/characters) toggles random generation?
310-314: Nice special-case for validate.Early newline and return avoid unnecessary confirm logic. Clean.
internal/server/server_test.go (2)
142-142: Good move using NewProvidersBasic — I pity the fool who hand-wires providers!Centralizing defaults for Clock/Random tightens test scaffolding consistency.
144-144: Keep the deterministic RNG override in tests — Multiple tests across the codebase rely onrandom.NewMathematical()for determinism; reverting to crypto RNG will break them. I pity the fool who does otherwise!Likely an incorrect or invalid review comment.
internal/oidc/types.go (1)
217-217: Pointer return for GetConfiguration is already aligned. I pity the fool who misses that all implementations and callers already use *schema.Configuration — no changes required.internal/middlewares/types.go (1)
5-5: net import for RemoteIP: that’s right, fool.internal/service/file_watcher_test.go (2)
29-32: Providers via NewProvidersBasic with Templates wiring — that’s tight.
49-50: Passing Providers and Logger into ctx is consistent — no jive.internal/handlers/handler_oauth2_oidc_userinfo.go (1)
39-39: Swapping to ctx.GetClock().Now() for session time — righteous.internal/service/signal_test.go (2)
63-68: Good move: use NewProvidersBasic() to avoid zero-value Providers.Centralizing Clock/Random in tests is solid, fool.
205-211: Consistent provider init here too — nice.Keeps the mock ctx sane across tests. I pity the fool who leaves Providers zeroed.
internal/service/sever_test.go (4)
20-25: Providers + Templates wiring looks clean.Straightforward and readable. No complaints.
36-41: Context now carries Providers — thumbs up.Keeps setup DRY across tests. Good hustle.
62-70: Metrics provider init is correct.Prometheus wired via Providers keeps things consistent.
83-88: Consistent ctx wiring in metrics test.LGTM, fool.
internal/commands/debug.go (2)
137-139: Drop the extra //nolint:gocyclo if it isn’t suppressing anything.If runDebugOIDCClaims isn’t over the threshold, nolintlint will bark. Keep lint clean, sucka.
Run golangci-lint and remove this directive if unused.
240-245: Refactor to writer-based output: solid.Decoupling from cobra I/O is the right pattern here.
internal/suites/example/compose/duo-api/duo_api.js (1)
47-47: LGTM: added top-level code field aligns with types.Response.Code.Consistent with the provider and tests. I pity the fool who forgets to keep mocks in sync!
Also applies to: 57-57, 83-83
internal/duo/duo_test.go (2)
456-462: LGTM: lazy provider init with pointer receivers is correct.State persists across calls. Solid.
Also applies to: 464-470
171-269: Nice coverage on OK/FAIL/unknown + JSON edges.Broad scenarios, parallel subtests, good table design. Respect.
Also applies to: 308-394
internal/commands/storage_run.go (2)
27-27: LGTM: importing middlewares fits new context usage.Stay consistent, sucka.
1420-1420: LGTM: use ctx-provided Clock/Random.Deterministic and test-friendly. That’s how you do it.
bda7f70 to
35b7ba3
Compare
✅ Deploy Preview for authelia-staging ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
internal/utils/crypto.go (1)
775-778: Fix nil-pointer panic when adding to Intermediates.opts.Intermediates can be nil; AddCert on nil will blow up. Don’t get KO’d at runtime, fool.
- if certs[i+1].IsCA { - if _, err = certs[i+1].Verify(opts); err == nil { - opts.Intermediates.AddCert(certs[i+1]) - } - } + if certs[i+1].IsCA { + if _, err = certs[i+1].Verify(opts); err == nil { + if opts.Intermediates == nil { + opts.Intermediates = x509.NewCertPool() + } + opts.Intermediates.AddCert(certs[i+1]) + } + }internal/commands/storage_run.go (2)
1405-1421: Guard against nil Clock/Random to avoid panics, chump.If
GetClock()/GetRandom()return nil,totp.NewContextmay blow up. Add safe fallbacks.func runStorageUserTOTPGenerate(ctx middlewares.ServiceContext, w io.Writer, store storage.Provider, config *schema.Configuration, filename, username, secret string, force bool) (err error) { @@ totpProvider := totp.NewTimeBasedProvider(config.TOTP) - if c, err = totpProvider.GenerateCustom(totp.NewContext(ctx, ctx.GetClock(), ctx.GetRandom()), username, config.TOTP.DefaultAlgorithm, secret, uint32(config.TOTP.DefaultDigits), uint(config.TOTP.DefaultPeriod), uint(config.TOTP.SecretSize)); err != nil { //nolint:gosec // Validated at runtime. + clk := ctx.GetClock() + if clk == nil { + clk = clock.New() + } + rnd := ctx.GetRandom() + if rnd == nil { + rnd = random.New() + } + if c, err = totpProvider.GenerateCustom(totp.NewContext(ctx, clk, rnd), username, config.TOTP.DefaultAlgorithm, secret, uint32(config.TOTP.DefaultDigits), uint(config.TOTP.DefaultPeriod), uint(config.TOTP.SecretSize)); err != nil { //nolint:gosec // Validated at runtime. return err }Add import outside this hunk:
// imports "github.com/authelia/authelia/v4/internal/clock"
1426-1450: Fix TOCTOU and error masking when creating PNGs, foo'.Current
Stat+Createinvites a race and hides unexpected errors.if filename != "" { - if _, err = os.Stat(filename); !os.IsNotExist(err) { - return errors.New("image output filepath already exists") - } - - if file, err = os.Create(filename); err != nil { + switch _, err = os.Stat(filename); { + case os.IsNotExist(err): + // OK + case err == nil: + return fmt.Errorf("image output filepath '%s' already exists", filename) + default: + return fmt.Errorf("error checking output filepath '%s': %w", filename, err) + } + + if file, err = os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600); err != nil { return err } @@ - if err = png.Encode(file, img); err != nil { + if err = png.Encode(file, img); err != nil { return err } }
♻️ Duplicate comments (11)
internal/commands/crypto_hash.go (1)
278-289: Fixed: length-only and characters flag handling—no more gotchasUsing cmdFlagsCryptoHashPasswordRandom(..., RandomLength) and passing cmdFlagNameRandomCharacters to flagsGetRandomCharacters means length-only and characters-only cases now trigger randomness as users expect. I like that, fool.
internal/commands/build_info_test.go (1)
15-20: Fix S1021: merge declaration and assignment, sucka.No need for a separate var. Merge it to keep the linter off your back.
- var cmd *cobra.Command - - cmd = newBuildInfoCmd(&CmdCtx{}) + cmd := newBuildInfoCmd(&CmdCtx{})internal/commands/storage_run.go (1)
1751-1755: Fallback RNG so dir gen never panics, sucka.Use context RNG if present; else construct one.
-func runStorageUserTOTPExportPNG(ctx middlewares.ServiceContext, w io.Writer, store storage.Provider, dir string) (err error) { +func runStorageUserTOTPExportPNG(ctx middlewares.ServiceContext, w io.Writer, store storage.Provider, dir string) (err error) { if dir == "" { - rand := ctx.GetRandom() + rand := ctx.GetRandom() + if rand == nil { + rand = random.New() + } dir = rand.StringCustom(8, random.CharSetAlphaNumeric) }internal/handlers/handler_firstfactor_passkey_test.go (1)
717-717: Fix bad duration math:time.Second - 10ain’t minus 10s, fool!
Use a negative duration so the ban time is 10 seconds ago.- Return([]model.BannedIP{{ID: 1, Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Second - 10), Expires: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Minute), Valid: true}}}, nil), + Return([]model.BannedIP{{ID: 1, Time: mock.Ctx.Providers.Clock.Now().UTC().Add(-10 * time.Second), Expires: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Minute), Valid: true}}}, nil),internal/commands/context_test.go (1)
9-13: Format imports with goimports, fool.Linter flagged goimports. Run goimports/gofmt on this file.
internal/middlewares/types.go (2)
56-57: Always initialize Providers.Random and Providers.Clock.I pity the fool who leaves these nil. Ensure constructors/mocks set both to non-nil defaults.
60-79: All Context/ServiceContext implementers must add the new getters.Confirm AutheliaCtx, embed ctx, server/providers, and test contexts implement GetClock/GetRandom/GetLogger/GetProviders/GetConfiguration (and RemoteIP where required).
internal/duo/duo_test.go (1)
480-482: Return a non-nil config to avoid future nil derefs.Safer test context.
-func (t *TestCtx) GetConfiguration() (config *schema.Configuration) { - return nil -} +func (t *TestCtx) GetConfiguration() (config *schema.Configuration) { + cfg := &schema.Configuration{} + return cfg +}internal/duo/duo.go (3)
28-36: Stop logging raw Duo bodies; add nil-guarded username and redact, fool!Raw bodies can leak PII and OTPs. Also avoid dereferencing a nil userSession in logs.
Apply this diff:
func (d *Production) Call(ctx middlewares.Context, userSession *session.UserSession, values url.Values, method string, path string) (r *Response, err error) { var ( response Response body []byte ) - if _, body, err = d.SignedCall(method, path, values); err != nil { + // safe username for logs + username := "unknown" + if userSession != nil && userSession.Username != "" { + username = userSession.Username + } + + if _, body, err = d.SignedCall(method, path, values); err != nil { return nil, fmt.Errorf("error occurred making signed call: %w", err) } - ctx.GetLogger().Tracef("Duo endpoint: %s response raw data for %s from IP %s: %s", path, userSession.Username, ctx.RemoteIP().String(), string(body)) + ctx.GetLogger().WithFields(map[string]any{ + "path": path, "username": username, "remote_ip": ctx.RemoteIP().String(), "response_bytes": len(body), + }).Trace("Duo endpoint response received") @@ - .WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). + .WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": username}). @@ - .WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). + .WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": username}). @@ - .WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). + .WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": username}). @@ - .WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). + .WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": username}).Also applies to: 45-46, 51-52, 58-59, 64-65
29-29: Wrap errors with context (method/path/user) and no raw body, sucka!Give callers actionable details; include body size on parse error.
Apply this diff:
- return nil, fmt.Errorf("error occurred making signed call: %w", err) + return nil, fmt.Errorf("duo signed call failed (method=%s path=%s user=%s): %w", method, path, username, err) @@ - return nil, fmt.Errorf("error occurred parsing response: %w", err) + return nil, fmt.Errorf("duo response parse failed (path=%s user=%s body_bytes=%d): %w", path, username, len(body), err)Also applies to: 35-35
38-67: Return precise Duo failures; drop the vague jive.Include stat/code/message in returned errors.
Apply this diff:
- return &response, fmt.Errorf("failure status code was returned") + return &response, fmt.Errorf("duo returned failure status code %d (%s): %s", response.Code, response.Stat, response.Message) @@ - return &response, fmt.Errorf("failure status was returned") + return &response, fmt.Errorf("duo returned failure status (%s) code %d: %s", response.Stat, response.Code, response.Message) @@ - return &response, fmt.Errorf("unknown status was returned") + return &response, fmt.Errorf("duo returned unknown status (%s) code %d: %s", response.Stat, response.Code, response.Message)
🧹 Nitpick comments (32)
internal/utils/crypto.go (5)
378-378: Include the cert path in the wrapped error, fool.Add the filename to speed up triage when reads fail.
- errors = append(errors, fmt.Errorf("error occurred trying to read certificate: %w", err)) + errors = append(errors, fmt.Errorf("error occurred trying to read certificate %q: %w", certPath, err))
379-381: Report the full path when append-from-PEM fails.Using entry.Name() hides where the bad cert lives. Show the path, sucka.
- } else if ok := certPool.AppendCertsFromPEM(data); !ok { - errors = append(errors, fmt.Errorf("could not import certificate %s", entry.Name())) + } else if ok := certPool.AppendCertsFromPEM(data); !ok { + errors = append(errors, fmt.Errorf("could not import certificate %q: no valid PEM blocks found", certPath)) }
361-365: Wrap and annotate dir read errors.Carry the directory in the message and use %w, or I pity the debugging fool.
- if entries, err = os.ReadDir(directory); err != nil { - errors = append(errors, fmt.Errorf("could not read certificates from directory %v", err)) + if entries, err = os.ReadDir(directory); err != nil { + errors = append(errors, fmt.Errorf("could not read certificates from directory %q: %w", directory, err)) return certPool, warnings, errors }
347-349: Use %w for system pool warning.Preserve the original error, fool.
- warnings = append(warnings, fmt.Errorf("could not load system certificate pool which may result in untrusted certificate issues: %v", err)) + warnings = append(warnings, fmt.Errorf("could not load system certificate pool which may result in untrusted certificate issues: %w", err))
344-388: Consider renaming the return/result slice ‘errors’.It shadows the imported errors package within this scope and hurts readability. Rename to errs for clarity, or I’ll pity future you reading this.
internal/commands/acl_test.go (5)
17-25: Broaden command assertions, sucka.Asserting only NotNil is too weak. Verify basic command metadata so regressions get caught early.
func TestNewACLCommand(t *testing.T) { var cmd *cobra.Command cmd = newAccessControlCommand(&CmdCtx{}) assert.NotNil(t, cmd) + assert.NotEmpty(t, cmd.Use) + assert.True(t, cmd.RunE != nil || cmd.Run != nil, "expected either RunE or Run to be set") cmd = newAccessControlCheckCommand(&CmdCtx{}) assert.NotNil(t, cmd) + assert.NotEmpty(t, cmd.Use) + assert.True(t, cmd.RunE != nil || cmd.Run != nil, "expected either RunE or Run to be set") }
152-154: Sharper diffs for failures, sucka: assert fields not full structs.Deep-equality on url.URL can hide tiny diffs. Compare fields for clearer failure output.
- assert.Equal(t, tc.subject, subject) - assert.Equal(t, tc.object, object) + assert.Equal(t, tc.subject.Username, subject.Username) + assert.ElementsMatch(t, tc.subject.Groups, subject.Groups) + assert.Equal(t, tc.subject.IP.String(), subject.IP.String()) + + if tc.object.URL != nil && object.URL != nil { + assert.Equal(t, tc.object.URL.Scheme, object.URL.Scheme) + assert.Equal(t, tc.object.URL.Host, object.URL.Host) + assert.Equal(t, tc.object.URL.Path, object.URL.Path) + } else { + assert.Nil(t, tc.object.URL) + assert.Nil(t, object.URL) + } + assert.Equal(t, tc.object.Domain, object.Domain) + assert.Equal(t, tc.object.Path, object.Path) + assert.Equal(t, tc.object.Method, object.Method)
158-177: Edge case missing: what’s the verdict for empty input, fool?Add a case for hitMissMay() with no args to lock down default behavior.
testCases := []struct { name string input []bool expected string }{ + {name: "ShouldReturnMissForEmpty", input: []bool{}, expected: "miss"}, }If "miss" isn’t the intended default, adjust expected accordingly.
344-346: Use require when output parsing depends on success.Fail fast on error so we don’t assert on garbage output.
- err := runAccessControlCheck(&buf, object, subject, tc.results, tc.defaultPolicy, tc.verbose) - assert.NoError(t, err) + err := runAccessControlCheck(&buf, object, subject, tc.results, tc.defaultPolicy, tc.verbose) + require.NoError(t, err)
264-294: Confirm break-on-skipped semantics, fool
I pity the fool who doesn’t see thatrunAccessControlCheckstops at the firstSkippedwhenverboseis false (acl.go:112–114). The testShouldBreakOnSkippedWhenNotVerbosematches this behavior. If you expect later non-skipped rules to be evaluated, update the code or test. Otherwise, add a comment above thebreakto clarify this early exit.internal/commands/crypto_hash.go (4)
112-144: Help text nit: keep variant option quoting consistent, suckaSome variants are quoted, some ain’t. Pick one style for a cleaner UX.
- cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.Argon2.Variant, "variant, options are 'argon2id', 'argon2i', and 'argon2d'") + cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.Argon2.Variant, "variant, options are 'argon2id', 'argon2i', 'argon2d'") - cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.SHA2Crypt.Variant, "variant, options are sha256 and sha512") + cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.SHA2Crypt.Variant, "variant, options are 'sha256', 'sha512'") - cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.PBKDF2.Variant, "variant, options are 'sha1', 'sha224', 'sha256', 'sha384', and 'sha512'") + cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.PBKDF2.Variant, "variant, options are 'sha1', 'sha224', 'sha256', 'sha384', 'sha512'") - cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.Bcrypt.Variant, "variant, options are 'standard' and 'sha256'") + cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.Bcrypt.Variant, "variant, options are 'standard', 'sha256'") - cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.Scrypt.Variant, "variant, options are 'scrypt', and 'yescrypt'") + cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.Scrypt.Variant, "variant, options are 'scrypt', 'yescrypt'")
232-241: Avoid mutating global config just to pick an algorithmSide-effects on ctx.config aren’t needed; derive a local copy with the selected algorithm. Keep your hands off shared state, sucka.
-switch use { - case cmdUseGenerate: - break - default: - config.AuthenticationBackend.File.Password.Algorithm = use -} - -if hash, err = authentication.NewFileCryptoHashFromConfig(config.AuthenticationBackend.File.Password); err != nil { +passwordCfg := config.AuthenticationBackend.File.Password +switch use { +case cmdUseGenerate: + // no-op; use existing/default algorithm +default: + passwordCfg.Algorithm = use +} +if hash, err = authentication.NewFileCryptoHashFromConfig(passwordCfg); err != nil { return err }
310-317: Don’t key control flow off cmd.Use stringsComparing use to a formatted string is brittle. Plumb an explicit mode (e.g., isValidate) into cmdFlagsCryptoHashGetPassword or pass a confirm bool. Don’t let a help-text tweak break behavior.
Example minimal change (call sites would pass confirmNeeded):
-func cmdFlagsCryptoHashGetPassword(w io.Writer, flags *pflag.FlagSet, use string, args []string, useArgs, useRandom bool) (password string, random bool, err error) { +func cmdFlagsCryptoHashGetPassword(w io.Writer, flags *pflag.FlagSet, use string, args []string, useArgs, useRandom bool, confirmNeeded bool) (password string, random bool, err error) { ... - if use == fmt.Sprintf(cmdUseFmtValidate, cmdUseValidate) { + if !confirmNeeded { _, _ = fmt.Fprintln(w) return }Call sites:
- Validate: confirmNeeded=false
- Generate: confirmNeeded=!noConfirm
212-258: Add tests for the key flowsCover these so no fool breaks them later:
- no File backend configured → still generates (post-defaults init)
- random toggles: only length, only charset, only characters, and explicit --random
- precedence: --random takes priority over --password
- subcommand algorithm selection doesn’t mutate ctx.config
I can draft table-driven tests for runCryptoHashGenerate and cmdFlagsCryptoHashGetPassword. Want me to open a test PR?
internal/commands/build_info_test.go (2)
3-12: Trim unused import and add fmt, fool.After merging decl/assign you don’t need the cobra import; you’ll need fmt for dynamic expectations below.
import ( "bytes" + "fmt" "runtime/debug" "testing" - "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" )
96-115: Add a “Settings” coverage case, sucka.You cover deps; add a settings case to lock the verbose path fully.
I can draft a test case with info.Settings = []debug.BuildSetting{{Key:"-tags", Value:"foo"}} and assert it prints under “Settings:”.
internal/commands/build_info.go (1)
55-84: Deterministic verbose output: sort settings/deps, sucka.For reproducible logs/tests, sort by key/path before printing.
import ( "fmt" "io" "runtime" "runtime/debug" + "sort" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ if verbose { if len(info.Settings) != 0 { _, _ = fmt.Fprintf(w, " Settings:\n") - for _, setting := range info.Settings { + sort.Slice(info.Settings, func(i, j int) bool { return info.Settings[i].Key < info.Settings[j].Key }) + for _, setting := range info.Settings { _, _ = fmt.Fprintf(w, " %s: %s\n", setting.Key, setting.Value) } } if len(info.Deps) != 0 { _, _ = fmt.Fprintf(w, " Dependencies:\n") - for _, dep := range info.Deps { + sort.Slice(info.Deps, func(i, j int) bool { return info.Deps[i].Path < info.Deps[j].Path }) + for _, dep := range info.Deps { _, _ = fmt.Fprintf(w, " %s@%s (%s)\n", dep.Path, dep.Version, dep.Sum) } } }internal/commands/storage_run.go (2)
1780-1784: Sanitize filenames from usernames—don’t let paths punk you.Usernames with separators could create nested paths. Sanitize before writing.
- if file, err = os.Create(filepath.Join(dir, fmt.Sprintf("%s.png", c.Username))); err != nil { + name := sanitizeFilename(c.Username) + ".png" + if file, err = os.Create(filepath.Join(dir, name)); err != nil { return err }Helper outside this hunk:
func sanitizeFilename(s string) string { s = filepath.Base(s) s = strings.Map(func(r rune) rune { switch { case r >= 'a' && r <= 'z', r >= 'A' && r <= 'Z', r >= '0' && r <= '9', r == '-', r == '_': return r default: return '_' } }, s) if s == "" { return "user" } return s }
1808-1808: Pluralization nit—talk right, fool.“configuration” → “configurations”.
- _, _ = fmt.Fprintf(w, "Successfully exported %d TOTP configuration as QR codes in PNG format to the '%s' directory\n", count, dir) + _, _ = fmt.Fprintf(w, "Successfully exported %d TOTP configurations as QR codes in PNG format to the '%s' directory\n", count, dir)internal/random/cryptographical.go (1)
10-12: Polish the docstring punctuation, sucka.
Add the missing comma after “i.e.” for clarity.-// system randomness (i.e solely crypto/rand and the *Cryptographical provider). +// system randomness (i.e., solely crypto/rand and the *Cryptographical provider).internal/handlers/handler_firstfactor_passkey_test.go (2)
186-197: Replace literal"Passkey"withregulation.AuthTypePasskeyin tests
I pity the fool who hardcodes strings when a constant’s at hand—update all instances ininternal/handlers/handler_firstfactor_passkey_test.go:- Type: "Passkey", + Type: regulation.AuthTypePasskey,
345-371: Unify LastUsedAt to use mock.Ctx.Providers.Clock.Now(), fool! I pity the fool who splits time sources—replace all directmock.Clock.Now()/time.Now()inLastUsedAtfields withmock.Ctx.Providers.Clock.Now().- LastUsedAt: sql.NullTime{Time: mock.Clock.Now().UTC(), Valid: true}, + LastUsedAt: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC(), Valid: true},internal/handlers/handler_oauth2_authorization_consent_preconfigured.go (1)
266-274: Fix typos in debug logs (“coes” → “does”).Keep logs clean, sucka.
- log.Debugf("Authorization Request with id '%s' on client with id '%s' using consent mode '%s' found a matching pre-configuration with id '%d' but the configuration has scopes '%s' and audience '%s' which coes not match the request", requester.GetID(), client.GetID(), client.GetConsentPolicy(), config.ID, strings.Join(config.Scopes, " "), strings.Join(config.Audience, " ")) + log.Debugf("Authorization Request with id '%s' on client with id '%s' using consent mode '%s' found a matching pre-configuration with id '%d' but the configuration has scopes '%s' and audience '%s' which does not match the request", requester.GetID(), client.GetID(), client.GetConsentPolicy(), config.ID, strings.Join(config.Scopes, " "), strings.Join(config.Audience, " ")) @@ - log.Debugf("Authorization Request with id '%s' on client with id '%s' using consent mode '%s' found a matching pre-configuration with id '%d' but the configuration had the requested claims '%s' which coes not match the request", requester.GetID(), client.GetID(), client.GetConsentPolicy(), config.ID, config.RequestedClaims.String) + log.Debugf("Authorization Request with id '%s' on client with id '%s' using consent mode '%s' found a matching pre-configuration with id '%d' but the configuration had the requested claims '%s' which does not match the request", requester.GetID(), client.GetID(), client.GetConsentPolicy(), config.ID, config.RequestedClaims.String)internal/commands/context_test.go (2)
48-51: Add the required blank line to satisfy wsl_v5.Silence that linter, sucka.
require.NoError(t, os.WriteFile(filepath.Join(dir, "file2.pem"), []byte("invalid"), 0600)) - ctx := NewCmdCtx() + + ctx := NewCmdCtx()
91-93: Reset flags before second ChainRunE to avoid false positives.Without reset, prior state leaks and weakens the test.
- cmd = ctx.ChainRunE(one, three) + oneRun, twoRun, threeRun = false, false, false + cmd = ctx.ChainRunE(one, three)internal/duo/duo_test.go (2)
433-441: Drop the unused hook; keep it lean, fool.Simplify NewTestCtx.
-func NewTestCtx(ip net.IP) *TestCtx { - logger, hook := test.NewNullLogger() +func NewTestCtx(ip net.IP) *TestCtx { + logger, _ := test.NewNullLogger() @@ ctx := &TestCtx{ ip: ip, logger: logger.WithFields(map[string]any{}), - hook: hook, Context: context.Background(), }
446-454: Remove unused field from TestCtx.Dead weight slows you down.
type TestCtx struct { ip net.IP logger *logrus.Entry - hook *test.Hook - providers middlewares.Providers context.Context }internal/duo/duo.go (2)
72-85: Tighten PreAuth errors; guard username.Standardize wording and avoid nil deref.
Apply this diff:
func (d *Production) PreAuthCall(ctx middlewares.Context, userSession *session.UserSession, values url.Values) (r *PreAuthResponse, err error) { var preAuthResponse PreAuthResponse + username := "unknown" + if userSession != nil && userSession.Username != "" { + username = userSession.Username + } @@ - if err != nil { - return nil, fmt.Errorf("error occurred making the preauth call to the duo api: %w", err) - } + if err != nil { + return nil, fmt.Errorf("duo preauth call failed (path=/auth/v2/preauth user=%s): %w", username, err) + } @@ - return nil, fmt.Errorf("error occurred parsing the duo api preauth json response: %w", err) + return nil, fmt.Errorf("duo preauth response parse failed (user=%s): %w", username, err)
88-101: Tighten Auth errors; guard username.Same treatment for Auth.
Apply this diff:
func (d *Production) AuthCall(ctx middlewares.Context, userSession *session.UserSession, values url.Values) (r *AuthResponse, err error) { var authResponse AuthResponse + username := "unknown" + if userSession != nil && userSession.Username != "" { + username = userSession.Username + } @@ - if err != nil { - return nil, fmt.Errorf("error occurred making the auth call to the duo api: %w", err) - } + if err != nil { + return nil, fmt.Errorf("duo auth call failed (path=/auth/v2/auth user=%s): %w", username, err) + } @@ - return nil, fmt.Errorf("error occurred parsing the duo api auth json response: %w", err) + return nil, fmt.Errorf("duo auth response parse failed (user=%s): %w", username, err)internal/middlewares/authelia_context.go (3)
603-609: Lazy clock init LGTM; watch for concurrent access.If ctx is shared across goroutines, this write isn’t synchronized.
Consider initializing providers in NewAutheliaCtx to avoid races:
// in NewAutheliaCtx after assigning ctx.Providers = providers if ctx.Providers.Clock == nil { ctx.Providers.Clock = clock.New() }
612-617: Same note for random provider.Mirror the clock approach in constructor to avoid concurrent lazy writes.
if ctx.Providers.Random == nil { ctx.Providers.Random = random.New() }
626-630: Clarify copy semantics in doc.Method returns a pointer to a copy; update comment to prevent accidental mutation assumptions.
Proposed comment:
// GetConfiguration returns a pointer to a copy of the current configuration.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
internal/configuration/test_resources/userdb/debug-tests.ymlis excluded by!**/*.yml
📒 Files selected for processing (78)
cmd/authelia-gen/openid_conformance.go(1 hunks)experimental/embed/context.go(3 hunks)experimental/embed/provider/general.go(1 hunks)internal/clock/fixed.go(2 hunks)internal/clock/provider.go(1 hunks)internal/clock/real.go(2 hunks)internal/commands/acl_test.go(4 hunks)internal/commands/build_info.go(2 hunks)internal/commands/build_info_test.go(3 hunks)internal/commands/context.go(4 hunks)internal/commands/context_test.go(1 hunks)internal/commands/crypto.go(6 hunks)internal/commands/crypto_hash.go(6 hunks)internal/commands/crypto_test.go(1 hunks)internal/commands/debug.go(13 hunks)internal/commands/debug_test.go(1 hunks)internal/commands/storage_run.go(4 hunks)internal/commands/util.go(2 hunks)internal/duo/duo.go(2 hunks)internal/duo/duo_test.go(2 hunks)internal/duo/types.go(2 hunks)internal/handlers/func_test.go(1 hunks)internal/handlers/handler_authz_authn.go(5 hunks)internal/handlers/handler_authz_test.go(16 hunks)internal/handlers/handler_firstfactor_passkey.go(3 hunks)internal/handlers/handler_firstfactor_passkey_test.go(26 hunks)internal/handlers/handler_firstfactor_password.go(2 hunks)internal/handlers/handler_firstfactor_password_test.go(2 hunks)internal/handlers/handler_oauth2_authorization.go(1 hunks)internal/handlers/handler_oauth2_authorization_claims.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core_test.go(10 hunks)internal/handlers/handler_oauth2_authorization_consent_explicit.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_implicit.go(3 hunks)internal/handlers/handler_oauth2_authorization_consent_preconfigured.go(5 hunks)internal/handlers/handler_oauth2_consent.go(6 hunks)internal/handlers/handler_oauth2_device_authorization.go(1 hunks)internal/handlers/handler_oauth2_introspection.go(1 hunks)internal/handlers/handler_oauth2_oidc_userinfo.go(2 hunks)internal/handlers/handler_oauth2_oidc_wellknown.go(1 hunks)internal/handlers/handler_oauth2_token.go(1 hunks)internal/handlers/handler_oauth2_wellknown.go(1 hunks)internal/handlers/handler_register_totp.go(3 hunks)internal/handlers/handler_register_totp_test.go(3 hunks)internal/handlers/handler_reset_password.go(1 hunks)internal/handlers/handler_session_elevation.go(3 hunks)internal/handlers/handler_session_elevation_test.go(4 hunks)internal/handlers/handler_sign_duo.go(1 hunks)internal/handlers/handler_sign_password.go(1 hunks)internal/handlers/handler_sign_password_test.go(1 hunks)internal/handlers/handler_sign_totp.go(2 hunks)internal/handlers/handler_sign_totp_test.go(2 hunks)internal/handlers/handler_sign_webauthn.go(2 hunks)internal/middlewares/authelia_context.go(1 hunks)internal/middlewares/authelia_context_blackbox_test.go(13 hunks)internal/middlewares/identity_verification.go(1 hunks)internal/middlewares/require_auth_test.go(1 hunks)internal/middlewares/startup.go(2 hunks)internal/middlewares/timing_attack_delay_test.go(2 hunks)internal/middlewares/types.go(2 hunks)internal/middlewares/util.go(2 hunks)internal/mocks/authelia_context.go(2 hunks)internal/mocks/duo_api.go(3 hunks)internal/model/webauthn_test.go(1 hunks)internal/notification/smtp_notifier.go(1 hunks)internal/oidc/types.go(1 hunks)internal/oidc/types_test.go(1 hunks)internal/random/cryptographical.go(1 hunks)internal/regulation/regulator_blackbox_test.go(2 hunks)internal/server/server_test.go(1 hunks)internal/service/file_watcher_test.go(2 hunks)internal/service/sever_test.go(4 hunks)internal/service/signal_test.go(2 hunks)internal/suites/example/compose/duo-api/duo_api.js(3 hunks)internal/totp/totp_test.go(3 hunks)internal/utils/const_test.go(1 hunks)internal/utils/crypto.go(1 hunks)internal/utils/exec.go(0 hunks)
💤 Files with no reviewable changes (1)
- internal/utils/exec.go
🚧 Files skipped from review as they are similar to previous changes (55)
- internal/handlers/func_test.go
- internal/handlers/handler_firstfactor_password_test.go
- internal/mocks/authelia_context.go
- internal/middlewares/require_auth_test.go
- internal/handlers/handler_oauth2_authorization_claims.go
- internal/suites/example/compose/duo-api/duo_api.js
- internal/commands/crypto_test.go
- internal/model/webauthn_test.go
- internal/handlers/handler_sign_totp_test.go
- internal/oidc/types_test.go
- internal/handlers/handler_sign_webauthn.go
- internal/handlers/handler_oauth2_authorization_consent_core.go
- cmd/authelia-gen/openid_conformance.go
- internal/handlers/handler_oauth2_oidc_userinfo.go
- internal/mocks/duo_api.go
- internal/handlers/handler_oauth2_authorization_consent_explicit.go
- internal/handlers/handler_register_totp.go
- internal/regulation/regulator_blackbox_test.go
- internal/clock/provider.go
- internal/server/server_test.go
- internal/handlers/handler_oauth2_authorization.go
- internal/service/file_watcher_test.go
- internal/middlewares/timing_attack_delay_test.go
- internal/handlers/handler_authz_test.go
- internal/commands/debug.go
- internal/handlers/handler_oauth2_consent.go
- internal/handlers/handler_firstfactor_password.go
- internal/commands/debug_test.go
- internal/handlers/handler_reset_password.go
- internal/handlers/handler_firstfactor_passkey.go
- internal/handlers/handler_authz_authn.go
- internal/handlers/handler_oauth2_wellknown.go
- internal/handlers/handler_oauth2_authorization_consent_core_test.go
- internal/handlers/handler_oauth2_device_authorization.go
- internal/handlers/handler_oauth2_introspection.go
- internal/duo/types.go
- internal/totp/totp_test.go
- internal/oidc/types.go
- internal/handlers/handler_session_elevation.go
- internal/middlewares/util.go
- internal/handlers/handler_oauth2_oidc_wellknown.go
- internal/middlewares/startup.go
- internal/handlers/handler_oauth2_token.go
- internal/commands/util.go
- internal/middlewares/identity_verification.go
- internal/handlers/handler_oauth2_authorization_consent_implicit.go
- internal/service/signal_test.go
- internal/service/sever_test.go
- internal/handlers/handler_sign_duo.go
- internal/handlers/handler_sign_password.go
- internal/handlers/handler_register_totp_test.go
- internal/middlewares/authelia_context_blackbox_test.go
- internal/commands/crypto.go
- internal/handlers/handler_session_elevation_test.go
- internal/commands/context.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-29T10:47:45.888Z
Learnt from: james-d-elliott
PR: authelia/authelia#10189
File: internal/clock/provider.go:14-15
Timestamp: 2025-08-29T10:47:45.888Z
Learning: The internal/mocks directory does not contain any mock clock implementations. Tests use concrete clock instances like clock.New(), clock.NewFixed(), and direct assignment to mock.Ctx.Providers.Clock instead of generated mocks for the clock.Provider interface.
Applied to files:
internal/handlers/handler_sign_password_test.gointernal/handlers/handler_firstfactor_passkey_test.go
📚 Learning: 2025-08-27T21:37:17.083Z
Learnt from: james-d-elliott
PR: authelia/authelia#10059
File: internal/commands/storage_run.go:23-23
Timestamp: 2025-08-27T21:37:17.083Z
Learning: The Authelia project uses "go.yaml.in/yaml/v4" as their YAML package import path, not the standard "gopkg.in/yaml.v3" or "gopkg.in/yaml.v2". This is used consistently across their codebase.
Applied to files:
internal/commands/storage_run.go
🧬 Code graph analysis (16)
experimental/embed/provider/general.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/notification/smtp_notifier.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/commands/context_test.go (5)
internal/commands/context.go (2)
NewCmdCtx(30-39)NewCmdCtxConfig(55-60)internal/commands/root.go (1)
NewRootCmd(16-61)internal/configuration/schema/storage.go (2)
Storage(10-16)StorageLocal(19-21)internal/model/types.go (1)
StartupCheck(168-170)internal/configuration/schema/log.go (1)
Log(4-9)
internal/commands/build_info_test.go (1)
internal/commands/context.go (1)
CmdCtx(42-52)
internal/handlers/handler_sign_password_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/utils/const_test.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/handlers/handler_firstfactor_passkey_test.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/model/regulation.go (3)
BannedUser(26-35)AuthenticationAttempt(9-19)BannedIP(37-46)
experimental/embed/context.go (4)
internal/middlewares/types.go (2)
Providers(40-58)Context(60-69)experimental/embed/types.go (2)
Providers(19-19)Configuration(10-10)internal/service/provider.go (2)
Provider(13-28)Context(46-52)internal/oidc/types.go (1)
Context(212-221)
internal/commands/acl_test.go (2)
internal/commands/context.go (1)
CmdCtx(42-52)internal/authorization/types.go (3)
Subject(49-54)Object(67-73)RuleMatchResult(100-112)
internal/commands/storage_run.go (1)
internal/middlewares/types.go (1)
ServiceContext(71-79)
internal/handlers/handler_oauth2_authorization_consent_preconfigured.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/middlewares/types.go (4)
internal/clock/provider.go (1)
Provider(10-15)internal/service/provider.go (2)
Provider(13-28)Context(46-52)experimental/embed/context.go (1)
Context(65-74)internal/oidc/types.go (1)
Context(212-221)
internal/duo/duo_test.go (4)
internal/duo/duo.go (1)
NewDuoAPI(15-19)internal/duo/types.go (6)
BaseProvider(15-17)Response(43-49)PreAuthResponse(60-68)Device(32-40)AuthResponse(52-57)Provider(20-24)internal/session/types.go (1)
UserSession(20-48)internal/middlewares/types.go (2)
Context(60-69)Providers(40-58)
internal/duo/duo.go (3)
internal/duo/types.go (4)
Production(27-29)Response(43-49)PreAuthResponse(60-68)AuthResponse(52-57)internal/middlewares/types.go (1)
Context(60-69)internal/session/types.go (1)
UserSession(20-48)
internal/middlewares/authelia_context.go (5)
internal/middlewares/types.go (2)
AutheliaCtx(29-37)Providers(40-58)internal/clock/provider.go (1)
Provider(10-15)experimental/embed/context.go (1)
New(18-61)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)
internal/commands/crypto_hash.go (2)
internal/configuration/schema/authentication.go (1)
AuthenticationBackend(10-19)internal/authentication/file_user_provider.go (1)
NewFileCryptoHashFromConfig(242-288)
🪛 GitHub Check: golangci
internal/commands/context_test.go
[failure] 9-9: [golangci] internal/commands/context_test.go#L9
File is not properly formatted (goimports)
[failure] 50-50: [golangci] internal/commands/context_test.go#L50
missing whitespace above this line (invalid statement above assign) (wsl_v5)
internal/commands/build_info_test.go
[failure] 15-15: [golangci] internal/commands/build_info_test.go#L15
S1021: should merge variable declaration with assignment on next line (staticcheck)
internal/commands/acl_test.go
[failure] 107-107: [golangci] internal/commands/acl_test.go#L107
missing whitespace above this line (invalid statement above assign) (wsl_v5)
🔇 Additional comments (27)
internal/commands/acl_test.go (3)
197-206: LGTM: default-policy messaging test is tight.Clear, focused assertion on no-rules scenario. I pity the fool who breaks this contract.
228-262: LGTM: potential vs. applied ordering covered.Good coverage proving “potential” messaging precedes “applied.” Solid.
295-337: Maybe-match case looks fine, but double-check policy fallback rules.Given no exact subject match, falling back to default makes sense. Ensure this aligns with business rules.
internal/commands/crypto_hash.go (8)
3-13: Solid import changes, fool!Adding io and pflag is correct and used. No strays. I pity the fool who leaves unused imports.
173-175: Password acquisition path looks tightRouting through cmdFlagsCryptoHashGetPassword with writer + flags is the right move here.
195-205: Flag mapping hook LGTMgetCryptoHashGenerateMapFlagsFromUse result is safely appended when non-nil. No footguns spotted.
207-211: Nice decoupling into runCryptoHashGeneratePassing writer/flags/use keeps RunE lean and testable. Good separation, fool.
247-256: Output behavior is spot onPrinting the random password (and URL-encoded when it changes) plus the digest to the provided writer is exactly what we want.
260-276: Randomness toggles are correct nowReading --random and any setter flags (charset/characters/length) covers the UX nicely. Good hustle.
337-350: Password/random flags are well-exposedFlags and defaults look correct (including bcrypt’s 72-char practical limit via default length).
Please confirm the default charset is strictly single-byte; otherwise 72 runes could exceed bcrypt’s 72-byte limit.
38-62: Defaults mapping confirmed I pity the fool who doubts: allauthentication_backend.file.password.*keys align with the schema and are loaded byHelperConfigSetDefaultsRunE, so the defaults correctly hydrate the config tree.internal/commands/build_info.go (2)
33-35: Clean handoff to runner—LGTM, fool.
37-53: Flag handling and error propagation look solid.internal/handlers/handler_sign_password_test.go (1)
38-41: Clock injection via Providers is tight, sucka!Setting
s.mock.Ctx.Providers.Clock = &s.mock.Clockafter fixing the time makes the expectations align with the code under test. I pity the fool who still usesctx.Clock!internal/clock/real.go (1)
22-25: JWT time-func option wired correctly, fool!
jwt.WithTimeFunc(r.Now)is the right move; keeps parsing time bound to the provider. Interface compliance is clean.internal/clock/fixed.go (1)
24-27: Fixed clock gets JWT time-func—nice symmetry.Matches the Real clock behavior; deterministic tests will thank you. I pity the fool who forgets parity!
internal/utils/const_test.go (1)
11-11: Constructor-based RNG FTW.
random.New()keeps tests aligned with the provider pattern. I pity the fool who new’s structs by hand!internal/random/cryptographical.go (1)
10-14: LGTM: clean factory for prod RNG. I pity the fool who new’s structs directly!internal/handlers/handler_sign_totp.go (1)
184-184: LGTM: time source via ctx.GetClock().Now(). That’s right, foo—centralize it.Also applies to: 195-195
experimental/embed/provider/general.go (1)
98-98: LGTM: use random.New(). Factory all the things, fool.internal/notification/smtp_notifier.go (1)
95-95: LGTM: swap to random.New(). Keep that concrete type outta here, sucka.internal/handlers/handler_firstfactor_passkey_test.go (2)
191-197: LGTM: tests now log auth attempts with provider clock. That’s disciplined, fool.Also applies to: 252-258, 289-295, 410-416, 515-521, 619-625, 721-727, 1023-1030, 1123-1129, 1218-1225, 1290-1296, 1386-1392, 1435-1442, 1481-1488, 1510-1517, 1552-1559, 1671-1677, 1714-1721
547-547: Nice: moved Expires/CreatedAt to provider clock. Keep it consistent, sucka.Also applies to: 556-556, 652-652, 661-661, 754-754, 763-763
internal/handlers/handler_oauth2_authorization_consent_preconfigured.go (1)
89-95: Clock provider migration LGTM—verify no nil clocks, fool.Good swap to ctx.GetClock().Now(). I pity the fool who forgets to initialize Providers.Clock everywhere (builders, mocks, embed). Add guards or ensure NewProvidersBasic()/mocks always set non-nil clocks so these calls never panic.
Also applies to: 108-110, 207-208, 227-229, 260-263
internal/duo/duo_test.go (1)
456-470: Lazy provider init is fine here.GetClock/GetRandom with pointer receiver preserves state. Solid.
internal/duo/duo.go (1)
41-45: Duo Auth API 404-with-OK is expected for “not found” cases
I pity the fool who doubts it—Duo’s docs confirm some lookup endpoints return HTTP 404 with"stat":"OK"to signal a missing resource (e.g., no such user). TreatingStatusNotFoundalongsideStatusOKas a normal response is correct.internal/middlewares/authelia_context.go (1)
620-623: LGTM: GetLogger accessor is clean and consistent.Rock-solid, fool.
35b7ba3 to
88c82d2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
internal/commands/crypto.go (1)
290-351: Tighten dir handling and always close files on write errors, fool.
- MkdirAll doesn’t return IsExist for existing dirs; the permission check branch is dead code and over-strict.
- If WriteString fails, the file stays open—close it before returning.
Apply this diff:
if dir != "" { - if err = os.MkdirAll(dir, dmode); err != nil { - if !os.IsExist(err) { - return fmt.Errorf("error making directory for file '%s': %w", name, err) - } else if info, err = os.Stat(dir); err == nil { - if info.Mode().Perm() != dmode { - return fmt.Errorf("error making directory for file '%s': directory '%s' already exists with wrong permissions: %v", name, dir, info.Mode().Perm()) - } - } - } + if err = os.MkdirAll(dir, dmode); err != nil { + return fmt.Errorf("error making directory for file '%s': %w", name, err) + } } if file, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fmode); err != nil { return fmt.Errorf("error opening file '%s': %w", name, err) } - if _, err = file.WriteString(values[i]); err != nil { - return err - } + if _, err = file.WriteString(values[i]); err != nil { + _ = file.Close() + return fmt.Errorf("error writing file '%s': %w", name, err) + } if err = file.Close(); err != nil { return fmt.Errorf("error closing file '%s': %w", name, err) }internal/random/cryptographical.go (1)
54-57: Fix potential modulo-by-zero and bias, sucka.Using byte(t) truncates for len(charset) >= 256; when len%256 == 0, byte(t) == 0 and panics. Use int modulus.
- if t > 0 { - for i := 0; i < n; i++ { - data[i] = charset[data[i]%byte(t)] - } - } + if t > 0 { + for i := 0; i < n; i++ { + // avoid uint8 truncation; prevents panic when len(charset) % 256 == 0 + data[i] = charset[int(data[i])%t] + } + }
♻️ Duplicate comments (13)
internal/commands/build_info_test.go (3)
14-20: Inline the var and assignment, fool.Collapse the separate declaration and assignment to satisfy staticcheck S1021.
- var cmd *cobra.Command - - cmd = newBuildInfoCmd(&CmdCtx{}) + cmd := newBuildInfoCmd(&CmdCtx{})
36-54: Stop hard-coding env-specific output; build expectations from runtime info.Make the test stable across OS/ARCH/Go versions by deriving the “Go” block from debug.ReadBuildInfo().
- testCases := []struct { + info, ok := debug.ReadBuildInfo() + require.True(t, ok) + expectedGo := "Go:\n Version: " + info.GoVersion + "\n Module Path: " + info.Main.Path + "\n" + + testCases := []struct { @@ - newFlags(false), - "Last Tag: unknown\nState: untagged dirty\nBranch: master\nCommit: unknown\nBuild Number: 0\nBuild OS: linux\nBuild Arch: amd64\nBuild Compiler: gc\nBuild Date: \nDevelopment: false\nExtra: \n\nGo:\n Version: go1.25.0\n Module Path: github.com/authelia/authelia/v4\n Executable Path: github.com/authelia/authelia/v4/internal/commands.test\n", + newFlags(false), + expectedGo, @@ - newFlags(true), - "Last Tag: unknown\nState: untagged dirty\nBranch: master\nCommit: unknown\nBuild Number: 0\nBuild OS: linux\nBuild Arch: amd64\nBuild Compiler: gc\nBuild Date: \nDevelopment: false\nExtra: \n\nGo:\n Version: go1.25.0\n Module Path: github.com/authelia/authelia/v4\n Executable Path: github.com/authelia/authelia/v4/internal/commands.test\n", + newFlags(true), + expectedGo,
23-34: Initialize FlagSet correctly or face nil-map pain.Use pflag.NewFlagSet; the zero value can bite. This keeps tests robust.
- newFlags := func(verbose bool) *pflag.FlagSet { - flags := &pflag.FlagSet{} + newFlags := func(verbose bool) *pflag.FlagSet { + flags := pflag.NewFlagSet("test", pflag.ContinueOnError) flags.Bool("verbose", false, "") if verbose { err := flags.Set("verbose", "true") require.NoError(t, err) } return flags }internal/commands/acl_test.go (2)
146-150: Make error assertions resilient, sucka.Exact error strings vary across Go/pflag; assert on substrings.
Apply this diff:
- if tc.err == "" { - assert.NoError(t, err) - } else { - assert.EqualError(t, err, tc.err) - } + if tc.err == "" { + assert.NoError(t, err) + } else { + assert.ErrorContains(t, err, tc.err) + }
106-107: Fix golangci-lint: add blank line after t.Parallel(), fool.wsl_v5 trips here. Drop a spacer.
Apply this diff:
t.Run(tc.name, func(t *testing.T) { t.Parallel() + cmd := &cobra.Command{Use: "test"}internal/commands/crypto_hash.go (1)
220-223: Don’t bail when File backend is nil—hydrate sane defaults, fool.Generating a hash shouldn’t require a configured file backend. Initialize defaults so users can run the command without config boilerplate.
Apply this diff:
- if config.AuthenticationBackend.File == nil { - return fmt.Errorf("authentication backend file is not configured") - } + if config.AuthenticationBackend.File == nil { + config.AuthenticationBackend.File = &schema.AuthenticationBackendFile{ + Password: schema.DefaultPasswordConfig, + } + }internal/commands/context_test.go (2)
9-9: Fix goimports formatting before the club pities youFormat imports to satisfy golangci-lint.
Run:
#!/bin/bash gofmt -s -w internal/commands/context_test.go goimports -w internal/commands/context_test.go
50-50: Add required whitespace to appease wsl_v5 linterInsert a blank line where the linter complains.
internal/middlewares/types.go (2)
56-58: Providers now own Clock/Random — good. Ensure no nils sneak in.Scan for raw Providers{} literals that don’t set Clock/Random; replace with NewProvidersBasic() or populate both fields.
#!/bin/bash # Find Providers literals missing Clock/Random initializations rg -nP --type=go 'Providers\s*{\s*[^}]*}' | sed -n '1,200p' # Prefer NewProvidersBasic() over bare literals rg -n 'NewProvidersBasic\('
60-79: Interface surface expanded—verify AutheliaCtx implements all methods.GetClock/GetRandom/GetLogger/GetProviders/GetConfiguration/RemoteIP must exist on AutheliaCtx. I pity the fool who leaves interfaces half-done.
#!/bin/bash # Check AutheliaCtx has required methods for m in GetClock GetRandom GetLogger GetProviders GetConfiguration RemoteIP; do rg -nP "func\\s+\\(\\s*\\*AutheliaCtx\\s*\\)\\s+$m\\s*\\(" --type=go || echo "Missing: $m" doneinternal/duo/duo_test.go (3)
433-444: Lose the log hook dead weight. I pity the fool who keeps unused fields!The hook is stored but never read. Drop the field and ignore the return value to appease linters.
func NewTestCtx(ip net.IP) *TestCtx { - logger, hook := test.NewNullLogger() + logger, _ := test.NewNullLogger() @@ ctx := &TestCtx{ ip: ip, logger: logger.WithFields(map[string]any{}), - hook: hook, Context: context.Background(), }type TestCtx struct { ip net.IP logger *logrus.Entry - hook *test.Hook - providers middlewares.Providers context.Context }Also applies to: 446-454
446-454: Option: export Providers for direct test tweaking. Make it easy on yourself, fool!If tests need to pre-wire providers, exporting simplifies setup without extra helpers.
type TestCtx struct { @@ - providers middlewares.Providers + Providers middlewares.Providers @@ -func (t *TestCtx) GetClock() clock.Provider { - if t.providers.Clock == nil { - t.providers.Clock = clock.New() +func (t *TestCtx) GetClock() clock.Provider { + if t.Providers.Clock == nil { + t.Providers.Clock = clock.New() } - return t.providers.Clock + return t.Providers.Clock } @@ -func (t *TestCtx) GetRandom() random.Provider { - if t.providers.Random == nil { - t.providers.Random = random.New() +func (t *TestCtx) GetRandom() random.Provider { + if t.Providers.Random == nil { + t.Providers.Random = random.New() } - return t.providers.Random + return t.Providers.Random } @@ -func (t *TestCtx) GetProviders() (providers middlewares.Providers) { - return t.providers +func (t *TestCtx) GetProviders() (providers middlewares.Providers) { + return t.Providers }Also applies to: 456-470, 472-478
480-482: Never return nil config from a context. Prevent panics, fool!Returning nil can blow up code under test. Hand back an empty config.
func (t *TestCtx) GetConfiguration() (config *schema.Configuration) { - return nil + return &schema.Configuration{} }
🧹 Nitpick comments (19)
internal/clock/provider.go (1)
6-6: Optional: decouple clock from jwt, fool.Wiring the clock interface to jwt.ParserOption couples packages. Consider alternatively returning a func() time.Time (or a tiny adapter interface) and letting callers wrap with jwt.WithTimeFunc. If you keep it as-is, a brief interface comment noting the jwt dependency would help future readers.
Also applies to: 14-15
internal/clock/real.go (1)
22-25: Nit: align receiver style, sucka.Other methods on Real use an unnamed value receiver (func (Real)...). This one names it (r Real). Pick one style for consistency.
internal/commands/crypto_hash.go (1)
278-335: Minor robustness around flag read, sucka.If flags.GetBool(cmdFlagNameNoConfirm) errors, we silently skip confirm. Consider returning that error to the caller so users get clear feedback on bad flags.
internal/commands/crypto.go (2)
641-642: Clarify RSA size output, sucka.k.Size() is bytes; printing both bytes and bits confuses users. Show bits only.
Apply this diff:
- b.WriteString(fmt.Sprintf("\tAlgorithm: RSA-%d %d bits\n\n", k.Size(), k.N.BitLen())) + b.WriteString(fmt.Sprintf("\tAlgorithm: RSA %d bits\n\n", k.N.BitLen()))
655-665: Use filepath.Ext for OS paths, fool.path.Ext is for slash-separated paths; filepath.Ext handles OS-specific separators.
Apply this diff:
- if ext := path.Ext(privateKeyPath); len(ext) == 0 { + if ext := filepath.Ext(privateKeyPath); len(ext) == 0 { privateKeyLegacyPath = fmt.Sprintf("%s.%s", privateKeyPath, extLegacy) } else { - privateKeyLegacyPath = fmt.Sprintf("%s.%s%s", strings.TrimSuffix(privateKeyPath, ext), extLegacy, ext) + privateKeyLegacyPath = fmt.Sprintf("%s.%s%s", strings.TrimSuffix(privateKeyPath, ext), extLegacy, ext) } - if ext := path.Ext(publicKeyPath); len(ext) == 0 { + if ext := filepath.Ext(publicKeyPath); len(ext) == 0 { publicKeyLegacyPath = fmt.Sprintf("%s.%s", publicKeyPath, extLegacy) } else { - publicKeyLegacyPath = fmt.Sprintf("%s.%s%s", strings.TrimSuffix(publicKeyPath, ext), extLegacy, ext) + publicKeyLegacyPath = fmt.Sprintf("%s.%s%s", strings.TrimSuffix(publicKeyPath, ext), extLegacy, ext) }internal/commands/crypto_test.go (1)
10-27: Make these tests earn their keep, fool.Asserting only NotNil is weak. Table-drive and assert basic command invariants (e.g., Use not empty). I pity the fool who ships noop tests.
func TestNewCrypto(t *testing.T) { - var cmd *cobra.Command - - cmd = newCryptoCmd(&CmdCtx{}) - assert.NotNil(t, cmd) - - cmd = newCryptoCertificateCmd(&CmdCtx{}) - assert.NotNil(t, cmd) - - cmd = newCryptoPairCmd(&CmdCtx{}) - assert.NotNil(t, cmd) - - cmd = newCryptoPairSubCmd(&CmdCtx{}, "generate") - assert.NotNil(t, cmd) - - cmd = newCryptoPairSubCmd(&CmdCtx{}, "verify") - assert.NotNil(t, cmd) + ctx := &CmdCtx{} + tests := []struct { + name string + build func() *cobra.Command + }{ + {"crypto", func() *cobra.Command { return newCryptoCmd(ctx) }}, + {"crypto-cert", func() *cobra.Command { return newCryptoCertificateCmd(ctx) }}, + {"crypto-pair", func() *cobra.Command { return newCryptoPairCmd(ctx) }}, + {"crypto-pair-generate", func() *cobra.Command { return newCryptoPairSubCmd(ctx, "generate") }}, + {"crypto-pair-verify", func() *cobra.Command { return newCryptoPairSubCmd(ctx, "verify") }}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + cmd := tc.build() + assert.NotNil(t, cmd) + assert.NotEmpty(t, cmd.Use) + }) + } }internal/utils/const_test.go (1)
11-11: Make the intent explicit.Type the var as the interface to lock API usage and aid refactors. I pity the fool who leaves types implicit.
-var r = random.New() +var r random.Provider = random.New()internal/random/cryptographical.go (1)
10-14: Constructor LGTM; polish the doc, fool.Great symmetry with clock.New(). Minor grammar touch-ups.
-// New returns a new random provider, specifically and strictly a production ready variant which uses inbuilt -// system randomness (i.e solely crypto/rand and the *Cryptographical provider). +// New returns a new random provider: a production-ready variant using built-in +// system randomness (i.e., solely crypto/rand and the *Cryptographical provider).internal/handlers/handler_firstfactor_passkey.go (1)
223-223: Consistent time source via GetClock—nice. Consider de-duplicating Now() callsCapture Now() once per request path to reduce drift and tighten tests.
Apply this diff:
@@ - if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { - userSession.RefreshTTL = ctx.GetClock().Now().Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) - } + now := ctx.GetClock().Now() + if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { + userSession.RefreshTTL = now.Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) + } @@ - userSession.SetOneFactorPasskey( - ctx.GetClock().Now(), details, + userSession.SetOneFactorPasskey( + now, details, keepMeLoggedIn, response.AuthenticatorAttachment == protocol.CrossPlatform, response.Response.AuthenticatorData.Flags.HasUserPresent(), response.Response.AuthenticatorData.Flags.HasUserVerified(), ) @@ - if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { - userSession.RefreshTTL = ctx.GetClock().Now().Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) - } + if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { + userSession.RefreshTTL = now.Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) + }Also applies to: 312-312, 337-337, 345-345
internal/commands/context_test.go (2)
121-123: Make permission error assertions resilientExact error strings vary by OS/filesystem. Assert by type/contains instead.
Apply:
-assert.EqualError(t, errs[0], fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file.pem"))) -assert.EqualError(t, errs[1], fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file2.pem"))) +assert.ErrorContains(t, errs[0], "error occurred trying to read certificate") +assert.ErrorContains(t, errs[0], "permission") +assert.ErrorContains(t, errs[1], "error occurred trying to read certificate") +assert.ErrorContains(t, errs[1], "permission")Or, if you plumb wrapped errors, prefer errors.Is(err, os.ErrPermission).
145-146: Avoid hardcoding storage schema versions in assertionsFuture bumps will make this brittle. Check for the condition, not the exact wording/version numbers.
Apply:
-assert.EqualError(t, ctx.CheckSchemaVersion(), "storage schema outdated: version 0 is outdated please migrate to version 22 in order to use this command or use an older binary") +assert.ErrorContains(t, ctx.CheckSchemaVersion(), "storage schema outdated")internal/handlers/handler_firstfactor_password.go (1)
136-140: Clock provider usage: solid move; apply it consistently, fool.Good swap to ctx.GetClock().Now() for session timestamps and TTL. I pity the fool who forgets the requestTime still uses time.Now() and makes tests flaky; consider using the contextual clock there too.
Outside this hunk, adjust requestTime initialization:
// before requestTime := time.Now() // after requestTime := ctx.GetClock().Now()Also applies to: 267-271
internal/middlewares/util.go (1)
75-81: NewProvidersBasic is clean; document defaults and keep it extensible.LGTM. Add a brief doc comment noting it returns real (non-mocked) Clock/Random; consider future options pattern if you need alternate providers in tests.
internal/service/sever_test.go (2)
22-25: Good: using NewProvidersBasic. Add t.Cleanup to always shut down the server, fool.Ensure cleanup runs even on assertion failures.
Example:
server, err := ProvisionServer(ctx) require.NoError(t, err) t.Cleanup(func(){ server.Shutdown() })
22-25: Ditch fixed sleeps; wait for readiness instead.I pity the fool who trusts time.Sleep in CI. Poll the port with require.Eventually for robustness.
Example:
require.Eventually(t, func() bool { conn, err := net.DialTimeout("tcp", "127.0.0.1:9091", 50*time.Millisecond) if err == nil { _ = conn.Close(); return true } return false }, 3*time.Second, 50*time.Millisecond)Also applies to: 64-70
internal/commands/debug.go (2)
137-239: Deterministic timing for debug claims (optional).Using time.Now() is fine for a CLI, but if you want reproducible outputs in tests, accept a time source or now func.
292-489: Per-certificate validity display is misleading—compute per-cert flags.You print Valid/Valid (System) using chain-level booleans for every cert. I pity the fool who debugs with the wrong signal. Compute validity per certificate, and keep the chain summary at the end.
Apply within the cert loop:
- valid, validSystem, validHostname := true, true, true + valid, validSystem, validHostname := true, true, true for i, cert := range conn.ConnectionState().PeerCertificates { - if _, err = cert.Verify(optsSystem); err != nil { - validSystem = false - } - if _, err = cert.Verify(opts); err != nil { - valid = false - } + perValidSystem, perValid := true, true + if _, err = cert.Verify(optsSystem); err != nil { perValidSystem = false; validSystem = false } + if _, err = cert.Verify(opts); err != nil { perValid = false; valid = false } _, _ = fmt.Fprintf(w, "\n\tCertificate #%d:\n", i+1) ... - _, _ = fmt.Fprintf(w, "\t\tValid: %t\n", valid) - _, _ = fmt.Fprintf(w, "\t\tValid (System): %t\n", validSystem) + _, _ = fmt.Fprintf(w, "\t\tValid: %t\n", perValid) + _, _ = fmt.Fprintf(w, "\t\tValid (System): %t\n", perValidSystem)internal/duo/duo_test.go (2)
57-58: Ease up on brittle exact error matches. Don’t box yourself in, fool!Exact strings are fragile. Prefer assert.ErrorContains on stable substrings.
-assert.EqualError(t, err, "error occurred making the preauth call to the duo api: error occurred parsing response: unexpected end of JSON input") +assert.ErrorContains(t, err, "preauth call") +assert.ErrorContains(t, err, "parsing")Repeat similarly for other EqualError checks.
Also applies to: 79-81, 101-103, 123-125, 145-147, 167-169, 297-304, 422-429
12-16: Use http.MethodPost and remove fasthttp importRemove the
github.com/valyala/fasthttpimport, addnet/http, and replace allfasthttp.MethodPostcalls (lines 51, 73, 95, 117, 139, 161, 292, 417) withhttp.MethodPost. I pity the fool who doesn’t!
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
internal/configuration/test_resources/userdb/debug-tests.ymlis excluded by!**/*.yml
📒 Files selected for processing (78)
cmd/authelia-gen/openid_conformance.go(1 hunks)experimental/embed/context.go(3 hunks)experimental/embed/provider/general.go(1 hunks)internal/clock/fixed.go(2 hunks)internal/clock/provider.go(1 hunks)internal/clock/real.go(2 hunks)internal/commands/acl_test.go(4 hunks)internal/commands/build_info.go(2 hunks)internal/commands/build_info_test.go(3 hunks)internal/commands/context.go(4 hunks)internal/commands/context_test.go(1 hunks)internal/commands/crypto.go(6 hunks)internal/commands/crypto_hash.go(6 hunks)internal/commands/crypto_test.go(1 hunks)internal/commands/debug.go(13 hunks)internal/commands/debug_test.go(1 hunks)internal/commands/storage_run.go(4 hunks)internal/commands/util.go(2 hunks)internal/duo/duo.go(2 hunks)internal/duo/duo_test.go(2 hunks)internal/duo/types.go(2 hunks)internal/handlers/func_test.go(1 hunks)internal/handlers/handler_authz_authn.go(5 hunks)internal/handlers/handler_authz_test.go(16 hunks)internal/handlers/handler_firstfactor_passkey.go(3 hunks)internal/handlers/handler_firstfactor_passkey_test.go(26 hunks)internal/handlers/handler_firstfactor_password.go(2 hunks)internal/handlers/handler_firstfactor_password_test.go(2 hunks)internal/handlers/handler_oauth2_authorization.go(1 hunks)internal/handlers/handler_oauth2_authorization_claims.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core_test.go(10 hunks)internal/handlers/handler_oauth2_authorization_consent_explicit.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_implicit.go(3 hunks)internal/handlers/handler_oauth2_authorization_consent_preconfigured.go(5 hunks)internal/handlers/handler_oauth2_consent.go(6 hunks)internal/handlers/handler_oauth2_device_authorization.go(1 hunks)internal/handlers/handler_oauth2_introspection.go(1 hunks)internal/handlers/handler_oauth2_oidc_userinfo.go(2 hunks)internal/handlers/handler_oauth2_oidc_wellknown.go(1 hunks)internal/handlers/handler_oauth2_token.go(1 hunks)internal/handlers/handler_oauth2_wellknown.go(1 hunks)internal/handlers/handler_register_totp.go(3 hunks)internal/handlers/handler_register_totp_test.go(3 hunks)internal/handlers/handler_reset_password.go(1 hunks)internal/handlers/handler_session_elevation.go(3 hunks)internal/handlers/handler_session_elevation_test.go(4 hunks)internal/handlers/handler_sign_duo.go(1 hunks)internal/handlers/handler_sign_password.go(1 hunks)internal/handlers/handler_sign_password_test.go(1 hunks)internal/handlers/handler_sign_totp.go(2 hunks)internal/handlers/handler_sign_totp_test.go(2 hunks)internal/handlers/handler_sign_webauthn.go(2 hunks)internal/middlewares/authelia_context.go(1 hunks)internal/middlewares/authelia_context_blackbox_test.go(13 hunks)internal/middlewares/identity_verification.go(1 hunks)internal/middlewares/require_auth_test.go(1 hunks)internal/middlewares/startup.go(2 hunks)internal/middlewares/timing_attack_delay_test.go(2 hunks)internal/middlewares/types.go(2 hunks)internal/middlewares/util.go(2 hunks)internal/mocks/authelia_context.go(2 hunks)internal/mocks/duo_api.go(3 hunks)internal/model/webauthn_test.go(1 hunks)internal/notification/smtp_notifier.go(1 hunks)internal/oidc/types.go(1 hunks)internal/oidc/types_test.go(1 hunks)internal/random/cryptographical.go(1 hunks)internal/regulation/regulator_blackbox_test.go(2 hunks)internal/server/server_test.go(1 hunks)internal/service/file_watcher_test.go(2 hunks)internal/service/sever_test.go(4 hunks)internal/service/signal_test.go(2 hunks)internal/suites/example/compose/duo-api/duo_api.js(3 hunks)internal/totp/totp_test.go(3 hunks)internal/utils/const_test.go(1 hunks)internal/utils/crypto.go(1 hunks)internal/utils/exec.go(0 hunks)
💤 Files with no reviewable changes (1)
- internal/utils/exec.go
🚧 Files skipped from review as they are similar to previous changes (55)
- internal/handlers/handler_sign_webauthn.go
- internal/middlewares/identity_verification.go
- internal/handlers/handler_oauth2_introspection.go
- internal/handlers/handler_oauth2_oidc_wellknown.go
- internal/commands/debug_test.go
- internal/handlers/func_test.go
- internal/handlers/handler_sign_duo.go
- internal/handlers/handler_oauth2_oidc_userinfo.go
- internal/server/server_test.go
- internal/middlewares/startup.go
- internal/oidc/types_test.go
- internal/handlers/handler_register_totp.go
- internal/handlers/handler_reset_password.go
- internal/handlers/handler_sign_password.go
- internal/service/file_watcher_test.go
- internal/middlewares/timing_attack_delay_test.go
- internal/handlers/handler_oauth2_device_authorization.go
- internal/handlers/handler_oauth2_authorization_consent_core.go
- internal/handlers/handler_oauth2_wellknown.go
- internal/clock/fixed.go
- internal/utils/crypto.go
- internal/handlers/handler_sign_totp.go
- internal/handlers/handler_oauth2_authorization_consent_explicit.go
- internal/handlers/handler_sign_password_test.go
- internal/handlers/handler_firstfactor_password_test.go
- internal/handlers/handler_authz_authn.go
- internal/handlers/handler_oauth2_authorization_claims.go
- internal/handlers/handler_authz_test.go
- internal/totp/totp_test.go
- internal/handlers/handler_oauth2_token.go
- internal/handlers/handler_oauth2_authorization_consent_core_test.go
- internal/handlers/handler_session_elevation.go
- cmd/authelia-gen/openid_conformance.go
- internal/mocks/authelia_context.go
- experimental/embed/context.go
- internal/handlers/handler_session_elevation_test.go
- internal/handlers/handler_firstfactor_passkey_test.go
- internal/regulation/regulator_blackbox_test.go
- internal/duo/types.go
- internal/commands/util.go
- internal/handlers/handler_oauth2_authorization.go
- internal/notification/smtp_notifier.go
- internal/middlewares/require_auth_test.go
- internal/suites/example/compose/duo-api/duo_api.js
- internal/commands/context.go
- internal/duo/duo.go
- internal/mocks/duo_api.go
- internal/service/signal_test.go
- internal/middlewares/authelia_context_blackbox_test.go
- internal/handlers/handler_oauth2_authorization_consent_preconfigured.go
- internal/handlers/handler_oauth2_consent.go
- internal/commands/build_info.go
- internal/handlers/handler_register_totp_test.go
- internal/middlewares/authelia_context.go
- internal/commands/storage_run.go
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-29T10:47:45.888Z
Learnt from: james-d-elliott
PR: authelia/authelia#10189
File: internal/clock/provider.go:14-15
Timestamp: 2025-08-29T10:47:45.888Z
Learning: The internal/mocks directory does not contain any mock clock implementations. Tests use concrete clock instances like clock.New(), clock.NewFixed(), and direct assignment to mock.Ctx.Providers.Clock instead of generated mocks for the clock.Provider interface.
Applied to files:
internal/clock/provider.gointernal/model/webauthn_test.gointernal/handlers/handler_sign_totp_test.go
🧬 Code graph analysis (16)
experimental/embed/provider/general.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/service/sever_test.go (5)
internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/server/server.go (1)
New(19-94)internal/middlewares/types.go (1)
Providers(40-58)internal/logging/logger.go (1)
Logger(15-17)internal/metrics/prometheus.go (1)
NewPrometheus(12-18)
internal/model/webauthn_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/handlers/handler_sign_totp_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/random/cryptographical.go (2)
internal/clock/real.go (1)
New(10-12)internal/clock/provider.go (1)
Provider(10-15)
internal/utils/const_test.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/commands/build_info_test.go (1)
internal/commands/context.go (1)
CmdCtx(42-52)
internal/commands/crypto_test.go (1)
internal/commands/context.go (1)
CmdCtx(42-52)
internal/middlewares/types.go (4)
internal/clock/provider.go (1)
Provider(10-15)internal/service/provider.go (2)
Provider(13-28)Context(46-52)experimental/embed/context.go (1)
Context(65-74)internal/oidc/types.go (1)
Context(212-221)
internal/duo/duo_test.go (5)
internal/mocks/duo_base_api.go (1)
NewMockDuoBaseProvider(34-38)internal/duo/duo.go (1)
NewDuoAPI(15-19)internal/duo/types.go (6)
BaseProvider(15-17)Response(43-49)PreAuthResponse(60-68)Device(32-40)AuthResponse(52-57)Provider(20-24)internal/session/types.go (1)
UserSession(20-48)internal/middlewares/types.go (2)
Context(60-69)Providers(40-58)
internal/middlewares/util.go (4)
internal/middlewares/types.go (1)
Providers(40-58)experimental/embed/provider/general.go (1)
New(26-28)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)
internal/commands/debug.go (7)
internal/middlewares/util.go (1)
NewAuthenticationProvider(84-93)internal/expression/user_attributes.go (1)
NewUserAttributes(13-24)internal/configuration/schema/identity_providers.go (1)
IdentityProviders(11-13)internal/oidc/claims.go (1)
NewCustomClaimsStrategy(444-506)internal/commands/context.go (1)
CmdCtx(42-52)internal/utils/crypto.go (1)
IsInsecureCipherSuite(735-743)internal/utils/const.go (1)
BlockTypeCertificate(32-32)
internal/handlers/handler_oauth2_authorization_consent_implicit.go (1)
internal/oidc/session.go (1)
ConsentGrantImplicit(212-217)
internal/commands/crypto_hash.go (2)
internal/configuration/schema/authentication.go (1)
AuthenticationBackend(10-19)internal/authentication/file_user_provider.go (1)
NewFileCryptoHashFromConfig(242-288)
internal/commands/acl_test.go (2)
internal/commands/context.go (1)
CmdCtx(42-52)internal/authorization/types.go (3)
Subject(49-54)Object(67-73)RuleMatchResult(100-112)
internal/commands/context_test.go (5)
internal/commands/context.go (2)
NewCmdCtx(30-39)NewCmdCtxConfig(55-60)internal/commands/root.go (1)
NewRootCmd(16-61)internal/configuration/schema/storage.go (2)
Storage(10-16)StorageLocal(19-21)internal/model/types.go (1)
StartupCheck(168-170)internal/configuration/schema/log.go (1)
Log(4-9)
🪛 GitHub Check: golangci
internal/commands/build_info_test.go
[failure] 15-15: [golangci] internal/commands/build_info_test.go#L15
S1021: should merge variable declaration with assignment on next line (staticcheck)
internal/commands/acl_test.go
[failure] 107-107: [golangci] internal/commands/acl_test.go#L107
missing whitespace above this line (invalid statement above assign) (wsl_v5)
internal/commands/context_test.go
[failure] 9-9: [golangci] internal/commands/context_test.go#L9
File is not properly formatted (goimports)
[failure] 50-50: [golangci] internal/commands/context_test.go#L50
missing whitespace above this line (invalid statement above assign) (wsl_v5)
⏰ 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). (2)
- GitHub Check: Analyze (go)
- GitHub Check: StepSecurity Harden-Runner
🔇 Additional comments (18)
internal/clock/provider.go (1)
14-15: LGTM: Provider grows a JWT time-func hook, sucka.Interface addition is clean and matches usage across the PR. I pity the fool who breaks clock determinism—this keeps JWT parsing testable.
internal/clock/real.go (1)
22-25: LGTM: Real clock hands jwt its time-func right.Returning jwt.WithTimeFunc(r.Now) preserves injection and testability. Solid.
internal/commands/acl_test.go (1)
17-25: LGTM: command constructors sanity-check.Simple existence tests are fine here; catches wiring regressions with minimal cost. Respect.
internal/commands/crypto_hash.go (1)
173-175: LGTM: password source unified via helper.Routing through cmdFlagsCryptoHashGetPassword keeps I/O and prompts consistent. Good move.
internal/commands/crypto.go (1)
268-271: LGTM: split print/files paths via helpers.Clear separation improves testability; passing writers/flags is the right pattern. Respect.
internal/commands/crypto_test.go (1)
13-26: Verify ctx isn’t nil-dereferenced by constructors.You’re passing &CmdCtx{} with zero Providers. Ensure newCrypto* tolerate that or initialize a minimal CmdCtx in tests. I pity the fool who panics on nil.
internal/model/webauthn_test.go (1)
459-459: Approve Providers.Clock refactor
No occurrences ofmock.Ctx.Clockremain in the codebase – I pity the fool who thought otherwise!experimental/embed/provider/general.go (1)
96-99: Right call moving to random.New(), fool.Centralized factory keeps production randomness consistent.
internal/handlers/handler_sign_totp_test.go (1)
41-41: No direct .Ctx.Clock usages remain
The ripgrep run returned zero.Ctx.Clockhits—onlyctx.GetClock().Now()calls are present. I pity the fool who’d leave old clock paths behind!internal/oidc/types.go (1)
217-217: I pity the fool who returns a live schema.Configuration
Ensure GetConfiguration implementations either return a defensive copy of schema.Configuration or clearly document that the returned instance is immutable to prevent accidental mutation. No matching implementations were found in our scan—verify manually across the codebase.internal/handlers/handler_oauth2_authorization_consent_implicit.go (1)
79-79: Clock provider swap looks clean, foolUsing ctx.GetClock().Now() for CanGrant and ConsentGrantImplicit keeps time deterministic and testable.
Also applies to: 90-93, 149-152
internal/commands/context_test.go (3)
36-43: LGTM: happy path for trusted certsCovers empty dir path; simple and effective.
59-97: LGTM: ChainRunE behaviorStops on first error and skips remaining; tests assert both branches.
100-109: Providers init smoke test is tightAsserts Clock/Random presence and no warns/errs in default case.
internal/commands/debug.go (2)
133-135: Wrapper call pattern looks tight.Decoupling from cobra IO via writer is clean. Keep it up.
244-285: Expression debug wrapper LGTM.Straightforward and testable via writer. No issues.
internal/duo/duo_test.go (2)
456-470: LGTM: pointer receivers + lazy provider init.State persists as intended; no more loss of Clock/Random on copies. Solid.
271-306: LGTM: parallel table tests done right.Capturing tc and creating isolated gomock controllers per subtest keeps concurrency clean. Good hustle.
Also applies to: 396-431
33e0724 to
13cc0a1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
internal/commands/crypto.go (2)
318-327: Fix dir creation/perm check; MkdirAll won’t return IsExist on existing dir.Today the permission check only runs on error and compares Perm() to the full mode, which can miss real mismatches and skip non-dir checks. Verify after success, ensure it’s a directory, compare Perm() to dmode.Perm(), and chmod if needed. Don’t play games with file permissions, fool.
Apply this diff:
- if err = os.MkdirAll(dir, dmode); err != nil { - if !os.IsExist(err) { - return fmt.Errorf("error making directory for file '%s': %w", name, err) - } else if info, err = os.Stat(dir); err == nil { - if info.Mode().Perm() != dmode { - return fmt.Errorf("error making directory for file '%s': directory '%s' already exists with wrong permissions: %v", name, dir, info.Mode().Perm()) - } - } - } + if err = os.MkdirAll(dir, dmode); err != nil { + return fmt.Errorf("error making directory for file '%s': %w", name, err) + } + if info, err = os.Stat(dir); err != nil { + return fmt.Errorf("error stating directory for file '%s': %w", name, err) + } + if !info.IsDir() { + return fmt.Errorf("error making directory for file '%s': path '%s' exists and is not a directory", name, dir) + } + if info.Mode().Perm() != dmode.Perm() { + if err = os.Chmod(dir, dmode); err != nil { + return fmt.Errorf("error setting permissions on directory '%s': %w", dir, err) + } + }
330-341: Prevent FD leak on write error.If WriteString fails, file isn’t closed. Defer the close so you don’t leave handles dangling like a chump.
- if file, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fmode); err != nil { + if file, err = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fmode); err != nil { return fmt.Errorf("error opening file '%s': %w", name, err) } + defer func() { _ = file.Close() }() - if _, err = file.WriteString(values[i]); err != nil { + if _, err = file.WriteString(values[i]); err != nil { return err } - if err = file.Close(); err != nil { - return fmt.Errorf("error closing file '%s': %w", name, err) - } + // close handled by deferinternal/handlers/handler_firstfactor_passkey_test.go (1)
1-1784: Correct duration arithmetic misuse Replace theAdd(time.Second - 10)call withAdd(-10 * time.Second)in internal/handlers/handler_firstfactor_passkey_test.go at line 717—I pity the fool who doesn’t!
♻️ Duplicate comments (8)
internal/commands/acl_test.go (3)
103-108: Blank line after t.Parallel(): fixed right.You added the spacer and shut that linter up. Nice hustle.
49-57: Stop matching full error strings—use substrings or you’ll chase flaky CI, sucka.pflag/net/url error texts drift across versions. Keep expectations looser.
Apply this tweak to the URL parse case (others can stay as-is once you switch to ErrorContains below):
- err: "parse \"http://%@#(*$@()#*&$invalid\": invalid character \"#\" in host name", + err: "invalid character",Also applies to: 59-66, 67-73, 75-81, 83-89
147-151: Use assert.ErrorContains instead of EqualError, fool.Makes tests resilient to upstream wording changes.
- if tc.err == "" { - assert.NoError(t, err) - } else { - assert.EqualError(t, err, tc.err) - } + if tc.err == "" { + assert.NoError(t, err) + } else { + assert.ErrorContains(t, err, tc.err) + }internal/handlers/handler_firstfactor_passkey_test.go (1)
717-717: Fix duration math, fool!time.Second - 10ain’t -10s.Use a negative duration to subtract 10 seconds.
Apply this diff:
- Return([]model.BannedIP{{ID: 1, Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Second - 10), Expires: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Minute), Valid: true}}}, nil), + Return([]model.BannedIP{{ID: 1, Time: mock.Ctx.Providers.Clock.Now().UTC().Add(-10 * time.Second), Expires: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Minute), Valid: true}}}, nil),internal/commands/build_info_test.go (2)
41-51: Make expectations env-agnostic, fool.These hard-coded GOOS/GOARCH/compiler/Go version/module/executable strings will flake across CI. Build the expected “Go” block from runtime/debug.
Apply:
@@ func TestRunBuildInfo(t *testing.T) { + info, ok := debug.ReadBuildInfo() + require.True(t, ok) + expectedGo := fmt.Sprintf("Go:\n Version: %s\n Module Path: %s\n Executable Path: %s\n", info.GoVersion, info.Main.Path, info.Path) @@ - { - "Successful", - newFlags(false), - "Last Tag: unknown\nState: untagged dirty\nBranch: master\nCommit: unknown\nBuild Number: 0\nBuild OS: linux\nBuild Arch: amd64\nBuild Compiler: gc\nBuild Date: \nDevelopment: false\nExtra: \n\nGo:\n Version: go1.25.0\n Module Path: github.com/authelia/authelia/v4\n Executable Path: github.com/authelia/authelia/v4/internal/commands.test\n", - "", - }, + { + "Successful", + newFlags(false), + expectedGo, + "", + }, @@ - { - "SuccessfulVerbose", - newFlags(true), - "Last Tag: unknown\nState: untagged dirty\nBranch: master\nCommit: unknown\nBuild Number: 0\nBuild OS: linux\nBuild Arch: amd64\nBuild Compiler: gc\nBuild Date: \nDevelopment: false\nExtra: \n\nGo:\n Version: go1.25.0\n Module Path: github.com/authelia/authelia/v4\n Executable Path: github.com/authelia/authelia/v4/internal/commands.test\n", - "", - }, + { + "SuccessfulVerbose", + newFlags(true), + expectedGo, + "", + },
73-143: Env-agnostic assertions for output, sucka.Don’t pin linux/amd64/gc; assert dynamic substrings from runtime/debug.
Apply:
@@ -import ( - "bytes" - "runtime/debug" - "testing" - - "github.com/spf13/pflag" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) +import ( + "bytes" + "runtime" + "runtime/debug" + "testing" + + "github.com/spf13/pflag" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) @@ - { - "ShouldHandleNormal", - false, - &debug.BuildInfo{ - Main: debug.Module{ - Path: "github.com/authelia/authelia/v4", - }, - }, - []string{ - "Last Tag: unknown\nState: untagged dirty\nBranch: master\nCommit: unknown\nBuild Number: 0\nBuild OS: linux\nBuild Arch: amd64\nBuild Compiler: gc\nBuild Date: \nDevelopment: false\nExtra: \n\nGo:\n Version: \n Module Path: github.com/authelia/authelia/v4", - }, - "", - }, + { + "ShouldHandleNormal", + false, + &debug.BuildInfo{ + Main: debug.Module{ Path: "github.com/authelia/authelia/v4" }, + }, + []string{ + "Go:\n", "Module Path: github.com/authelia/authelia/v4", + "Build OS: " + runtime.GOOS, + "Build Arch: " + runtime.GOARCH, + "Build Compiler: " + runtime.Compiler, + }, + "", + }, @@ - { - "ShouldHandleVerbose", - true, - &debug.BuildInfo{ - Main: debug.Module{ - Path: "github.com/authelia/authelia/v4", - }, - Deps: []*debug.Module{ - { Path: "github.com/a/fake/pkg", Version: "v1.0.0" }, - }, - }, - []string{ - "Last Tag: unknown\nState: untagged dirty\nBranch: master\nCommit: unknown\nBuild Number: 0\nBuild OS: linux\nBuild Arch: amd64\nBuild Compiler: gc\nBuild Date: \nDevelopment: false\nExtra: \n\nGo:\n Version: \n Module Path: github.com/authelia/authelia/v4", - "Dependencies:\n github.com/a/fake/pkg@v1.0.0 ()\n", - }, - "", - }, + { + "ShouldHandleVerbose", + true, + &debug.BuildInfo{ + Main: debug.Module{ Path: "github.com/authelia/authelia/v4" }, + Deps: []*debug.Module{ { Path: "github.com/a/fake/pkg", Version: "v1.0.0" } }, + }, + []string{ + "Go:\n", "Module Path: github.com/authelia/authelia/v4", + "Dependencies:", "github.com/a/fake/pkg@v1.0.0", + "Build OS: " + runtime.GOOS, + "Build Arch: " + runtime.GOARCH, + "Build Compiler: " + runtime.Compiler, + }, + "", + },internal/middlewares/types.go (1)
56-57: Providers now own Random/Clock — keep ’em non-nil or feel the pain.Great relocation. I pity the fool who leaves these nil. Ensure all constructors/tests use a helper (e.g., NewProvidersBasic) or lazy-getters to guarantee non-nil.
Run to spot risky zero-value literals:
#!/bin/bash rg -nP --type=go '\bProviders\s*{\s*}' -C2 || trueinternal/middlewares/authelia_context_blackbox_test.go (1)
780-783: Stop comparing random.New() instances — brittle test, sucka.Instance equality can bite you. Check type/non-nil for default, identity when provided.
- { - "ShouldHandleCryptographical", - random.New(), - }, + { + "ShouldHandleCryptographical", + random.New(), + }, @@ - if tc.have == nil { - assert.Equal(t, random.New(), middleware.GetRandom()) - } else { - assert.Equal(t, tc.have, middleware.GetRandom()) - } + got := middleware.GetRandom() + if tc.have == nil { + assert.NotNil(t, got) + assert.IsType(t, random.New(), got) + } else { + assert.Same(t, tc.have, got) + }Also applies to: 796-800
🧹 Nitpick comments (19)
internal/commands/acl_test.go (3)
153-155: Only assert subject/object on success path.On errors, helpers may return partially populated structs; don’t make the test brittle, fool.
- assert.Equal(t, tc.subject, subject) - assert.Equal(t, tc.object, object) + if tc.err == "" { + assert.Equal(t, tc.subject, subject) + assert.Equal(t, tc.object, object) + }
91-100: Build expected Object via constructor to avoid drift.Mirror production logic and reduce field-mismatch risk.
- subject: authorization.Subject{Username: "john", Groups: []string{"example"}, IP: net.ParseIP("127.0.0.1")}, - object: authorization.Object{URL: &url.URL{Scheme: "https", Host: "example.com", Path: "/"}, Domain: "example.com", Method: fasthttp.MethodGet, Path: "/"}, + subject: authorization.Subject{Username: "john", Groups: []string{"example"}, IP: net.ParseIP("127.0.0.1")}, + object: func() authorization.Object { + u, _ := url.ParseRequestURI("https://example.com/") + return authorization.NewObject(u, fasthttp.MethodGet) + }(),
345-347: Prefer require.NoError here to fail fast.No point checking output when the run errored, fool.
- assert.NoError(t, err) + require.NoError(t, err)internal/commands/crypto.go (1)
641-646: Tighten RSA algorithm printout.“RSA-256 2048 bits” mixes byte and bit sizes. Say “RSA 2048 bits”, fool.
- b.WriteString(fmt.Sprintf("\tAlgorithm: RSA-%d %d bits\n\n", k.Size(), k.N.BitLen())) + b.WriteString(fmt.Sprintf("\tAlgorithm: RSA %d bits\n\n", k.N.BitLen()))internal/handlers/handler_sign_totp.go (1)
184-184: Capture time once to avoid drift.Call Now() once and reuse so both updates share the same timestamp. Keep that timeline tight, fool.
- config.UpdateSignInInfo(ctx.GetClock().Now()) + now := ctx.GetClock().Now() + config.UpdateSignInInfo(now) @@ - userSession.SetTwoFactorTOTP(ctx.GetClock().Now()) + userSession.SetTwoFactorTOTP(now)Also applies to: 195-195
internal/random/cryptographical.go (1)
10-14: Polish that doc, fool.Tiny grammar/punctuation nit on the New() comment: “i.e solely” → “i.e., solely”; drop “inbuilt” phrasing for clarity.
Apply this diff:
-// New returns a new random provider, specifically and strictly a production ready variant which uses inbuilt -// system randomness (i.e solely crypto/rand and the *Cryptographical provider). +// New returns a new random provider: a production-ready variant using the system RNG +// (i.e., solely crypto/rand and the *Cryptographical provider).cmd/authelia/main.go (1)
12-17: Exit logic is solid; consider simpler flow, sucka.Functionally correct. Slightly leaner with if/else.
Apply this diff:
- switch { - case errors.Is(err, commands.ErrConfigCreated): - os.Exit(0) - default: - os.Exit(1) - } + if errors.Is(err, commands.ErrConfigCreated) { + os.Exit(0) + } + os.Exit(1)internal/commands/crypto_test.go (1)
13-27: Use NewCmdCtx() instead of zero-value CmdCtx, fool.Pass a fully initialized context to mirror production wiring and avoid nil surprises.
Apply this diff:
- cmd = newCryptoCmd(&CmdCtx{}) + cmd = newCryptoCmd(NewCmdCtx()) @@ - cmd = newCryptoCertificateCmd(&CmdCtx{}) + cmd = newCryptoCertificateCmd(NewCmdCtx()) @@ - cmd = newCryptoPairCmd(&CmdCtx{}) + cmd = newCryptoPairCmd(NewCmdCtx()) @@ - cmd = newCryptoPairSubCmd(&CmdCtx{}, "generate") + cmd = newCryptoPairSubCmd(NewCmdCtx(), "generate") @@ - cmd = newCryptoPairSubCmd(&CmdCtx{}, "verify") + cmd = newCryptoPairSubCmd(NewCmdCtx(), "verify")internal/handlers/handler_authz_test.go (1)
2404-2406: Set the clock once, use it everywhere.Good init of Providers.Clock with mock.Clock. Consider a small helper to reduce repetition when building AuthenticationAttempt timestamps.
internal/handlers/handler_session_elevation.go (1)
79-82: Clamp negative expires, sucka.Expires can go negative before you nuke the elevation; clamp to 0 for cleaner API semantics and less client-side fuss.
Apply this diff:
- response.Elevated = true - response.Expires = int(userSession.Elevations.User.Expires.Sub(ctx.GetClock().Now()).Seconds()) + response.Elevated = true + now := ctx.GetClock().Now() + response.Expires = int(userSession.Elevations.User.Expires.Sub(now).Seconds()) + if response.Expires < 0 { + response.Expires = 0 + } - - if userSession.Elevations.User.Expires.Before(ctx.GetClock().Now()) { + if userSession.Elevations.User.Expires.Before(now) {internal/commands/context_test.go (1)
114-127: OS-specific permission error strings can be brittle.If CI runs on non-Linux, consider asserting on os.IsPermission or substring match.
internal/handlers/handler_register_totp_test.go (2)
780-786: Keep it consistent, sucka.Same note as above: standardize on mock.Ctx.Providers.Clock.Now() (or mock.Ctx.GetClock().Now()) across this test.
733-741: Unify clock source, fool! Replace all 21 calls tomock.Clock.Now()in internal/handlers/handler_register_totp_test.go withmock.Ctx.Providers.Clock.Now()to keep your gomock expectations in sync—I pity the fool who leaves time mismatches.internal/commands/storage_run.go (3)
1424-1456: Avoid orphan PNG when Save fails, fool.If SaveTOTPConfiguration errors after writing the image, you leave junk on disk. Save first, then write the PNG.
Apply:
- extraInfo := "" - - if filename != "" { + // Save first to avoid orphaned files on error. + if err = store.SaveTOTPConfiguration(ctx, *c); err != nil { + return err + } + + extraInfo := "" + if filename != "" { if _, err = os.Stat(filename); !os.IsNotExist(err) { return errors.New("image output filepath already exists") } @@ - extraInfo = fmt.Sprintf(" and saved it as a PNG image at the path '%s'", filename) + extraInfo = fmt.Sprintf(" and saved it as a PNG image at the path '%s'", filename) } - -if err = store.SaveTOTPConfiguration(ctx, *c); err != nil { - return err -}
1751-1755: Nil-safe RNG fallback, sucka.ctx.GetRandom() could be nil outside full provider wiring. Fall back to random.New().
Apply:
func runStorageUserTOTPExportPNG(ctx middlewares.ServiceContext, w io.Writer, store storage.Provider, dir string) (err error) { if dir == "" { - rand := ctx.GetRandom() + rand := ctx.GetRandom() + if rand == nil { + rand = random.New() + } dir = rand.StringCustom(8, random.CharSetAlphaNumeric) }
1808-1809: Grammar nit: pluralize output, fool.Say “configurations” for multiple items.
Apply:
-_, _ = fmt.Fprintf(w, "Successfully exported %d TOTP configuration as QR codes in PNG format to the '%s' directory\n", count, dir) +_, _ = fmt.Fprintf(w, "Successfully exported %d TOTP configurations as QR codes in PNG format to the '%s' directory\n", count, dir)internal/commands/context.go (1)
40-52: Assert interface compliance at compile time, chump.Add a static assertion that CmdCtx implements middlewares.ServiceContext to catch regressions early.
Apply:
type CmdCtx struct { context.Context @@ cconfig *CmdCtxConfig } +// Ensure CmdCtx satisfies the ServiceContext interface at compile time. +var _ middlewares.ServiceContext = (*CmdCtx)(nil)internal/middlewares/types.go (1)
60-69: Add missing compile-time assertion for AutheliaCtx
The check is absent—add this so missing methods on AutheliaCtx fail at compile time. I pity the fool who skips it.+var _ middlewares.Context = (*AutheliaCtx)(nil)experimental/embed/context.go (1)
129-131: RemoteIP returns nil — call it out.Optional: add a doc comment stating RemoteIP is not meaningful in embed and returns nil.
-func (c *ctxEmbed) RemoteIP() net.IP { +// RemoteIP returns nil as embedded contexts are not bound to a client address. +func (c *ctxEmbed) RemoteIP() net.IP { return nil }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
internal/configuration/test_resources/userdb/debug-tests.ymlis excluded by!**/*.yml
📒 Files selected for processing (80)
cmd/authelia-gen/openid_conformance.go(1 hunks)cmd/authelia/main.go(1 hunks)experimental/embed/context.go(3 hunks)experimental/embed/provider/general.go(1 hunks)internal/clock/fixed.go(2 hunks)internal/clock/provider.go(1 hunks)internal/clock/real.go(2 hunks)internal/commands/acl_test.go(4 hunks)internal/commands/build_info.go(2 hunks)internal/commands/build_info_test.go(3 hunks)internal/commands/context.go(6 hunks)internal/commands/context_test.go(1 hunks)internal/commands/crypto.go(6 hunks)internal/commands/crypto_hash.go(6 hunks)internal/commands/crypto_test.go(1 hunks)internal/commands/debug.go(13 hunks)internal/commands/debug_test.go(1 hunks)internal/commands/errors.go(1 hunks)internal/commands/storage_run.go(4 hunks)internal/commands/util.go(2 hunks)internal/duo/duo.go(2 hunks)internal/duo/duo_test.go(2 hunks)internal/duo/types.go(2 hunks)internal/handlers/func_test.go(1 hunks)internal/handlers/handler_authz_authn.go(5 hunks)internal/handlers/handler_authz_test.go(16 hunks)internal/handlers/handler_firstfactor_passkey.go(3 hunks)internal/handlers/handler_firstfactor_passkey_test.go(26 hunks)internal/handlers/handler_firstfactor_password.go(2 hunks)internal/handlers/handler_firstfactor_password_test.go(2 hunks)internal/handlers/handler_oauth2_authorization.go(1 hunks)internal/handlers/handler_oauth2_authorization_claims.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core_test.go(10 hunks)internal/handlers/handler_oauth2_authorization_consent_explicit.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_implicit.go(3 hunks)internal/handlers/handler_oauth2_authorization_consent_preconfigured.go(5 hunks)internal/handlers/handler_oauth2_consent.go(6 hunks)internal/handlers/handler_oauth2_device_authorization.go(1 hunks)internal/handlers/handler_oauth2_introspection.go(1 hunks)internal/handlers/handler_oauth2_oidc_userinfo.go(2 hunks)internal/handlers/handler_oauth2_oidc_wellknown.go(1 hunks)internal/handlers/handler_oauth2_token.go(1 hunks)internal/handlers/handler_oauth2_wellknown.go(1 hunks)internal/handlers/handler_register_totp.go(3 hunks)internal/handlers/handler_register_totp_test.go(3 hunks)internal/handlers/handler_reset_password.go(1 hunks)internal/handlers/handler_session_elevation.go(3 hunks)internal/handlers/handler_session_elevation_test.go(4 hunks)internal/handlers/handler_sign_duo.go(1 hunks)internal/handlers/handler_sign_password.go(1 hunks)internal/handlers/handler_sign_password_test.go(1 hunks)internal/handlers/handler_sign_totp.go(2 hunks)internal/handlers/handler_sign_totp_test.go(2 hunks)internal/handlers/handler_sign_webauthn.go(2 hunks)internal/middlewares/authelia_context.go(1 hunks)internal/middlewares/authelia_context_blackbox_test.go(15 hunks)internal/middlewares/identity_verification.go(1 hunks)internal/middlewares/require_auth_test.go(1 hunks)internal/middlewares/startup.go(2 hunks)internal/middlewares/timing_attack_delay_test.go(2 hunks)internal/middlewares/types.go(2 hunks)internal/middlewares/util.go(2 hunks)internal/mocks/authelia_context.go(2 hunks)internal/mocks/duo_api.go(3 hunks)internal/model/webauthn_test.go(1 hunks)internal/notification/smtp_notifier.go(1 hunks)internal/oidc/types.go(1 hunks)internal/oidc/types_test.go(1 hunks)internal/random/cryptographical.go(1 hunks)internal/regulation/regulator_blackbox_test.go(2 hunks)internal/server/server_test.go(1 hunks)internal/service/file_watcher_test.go(2 hunks)internal/service/sever_test.go(4 hunks)internal/service/signal_test.go(2 hunks)internal/suites/example/compose/duo-api/duo_api.js(3 hunks)internal/totp/totp_test.go(3 hunks)internal/utils/const_test.go(1 hunks)internal/utils/crypto.go(1 hunks)internal/utils/exec.go(0 hunks)
💤 Files with no reviewable changes (1)
- internal/utils/exec.go
🚧 Files skipped from review as they are similar to previous changes (54)
- internal/handlers/handler_sign_password.go
- internal/handlers/handler_oauth2_authorization_consent_explicit.go
- internal/handlers/handler_sign_webauthn.go
- internal/clock/provider.go
- internal/oidc/types.go
- internal/oidc/types_test.go
- internal/handlers/handler_sign_password_test.go
- internal/handlers/handler_firstfactor_password.go
- internal/handlers/handler_oauth2_device_authorization.go
- internal/handlers/func_test.go
- internal/handlers/handler_sign_totp_test.go
- experimental/embed/provider/general.go
- internal/handlers/handler_register_totp.go
- internal/handlers/handler_oauth2_oidc_wellknown.go
- internal/handlers/handler_oauth2_authorization_consent_core_test.go
- internal/service/signal_test.go
- internal/utils/crypto.go
- internal/handlers/handler_oauth2_token.go
- internal/handlers/handler_oauth2_wellknown.go
- internal/utils/const_test.go
- internal/handlers/handler_oauth2_authorization_claims.go
- internal/clock/real.go
- internal/handlers/handler_oauth2_introspection.go
- internal/handlers/handler_session_elevation_test.go
- internal/mocks/authelia_context.go
- internal/handlers/handler_firstfactor_password_test.go
- internal/mocks/duo_api.go
- internal/commands/util.go
- internal/handlers/handler_oauth2_authorization_consent_preconfigured.go
- internal/suites/example/compose/duo-api/duo_api.js
- internal/middlewares/require_auth_test.go
- internal/regulation/regulator_blackbox_test.go
- internal/middlewares/timing_attack_delay_test.go
- internal/handlers/handler_sign_duo.go
- internal/notification/smtp_notifier.go
- internal/handlers/handler_authz_authn.go
- internal/handlers/handler_oauth2_authorization_consent_implicit.go
- internal/handlers/handler_oauth2_consent.go
- internal/middlewares/util.go
- internal/clock/fixed.go
- internal/service/file_watcher_test.go
- internal/commands/debug_test.go
- internal/handlers/handler_oauth2_authorization.go
- internal/commands/crypto_hash.go
- internal/handlers/handler_oauth2_authorization_consent_core.go
- internal/duo/duo.go
- internal/model/webauthn_test.go
- internal/service/sever_test.go
- internal/duo/types.go
- internal/handlers/handler_oauth2_oidc_userinfo.go
- internal/duo/duo_test.go
- internal/commands/debug.go
- cmd/authelia-gen/openid_conformance.go
- internal/middlewares/startup.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-29T10:47:45.888Z
Learnt from: james-d-elliott
PR: authelia/authelia#10189
File: internal/clock/provider.go:14-15
Timestamp: 2025-08-29T10:47:45.888Z
Learning: The internal/mocks directory does not contain any mock clock implementations. Tests use concrete clock instances like clock.New(), clock.NewFixed(), and direct assignment to mock.Ctx.Providers.Clock instead of generated mocks for the clock.Provider interface.
Applied to files:
internal/handlers/handler_authz_test.gointernal/totp/totp_test.gointernal/handlers/handler_register_totp_test.gointernal/handlers/handler_firstfactor_passkey_test.gointernal/commands/context.go
📚 Learning: 2025-08-27T21:37:17.083Z
Learnt from: james-d-elliott
PR: authelia/authelia#10059
File: internal/commands/storage_run.go:23-23
Timestamp: 2025-08-27T21:37:17.083Z
Learning: The Authelia project uses "go.yaml.in/yaml/v4" as their YAML package import path, not the standard "gopkg.in/yaml.v3" or "gopkg.in/yaml.v2". This is used consistently across their codebase.
Applied to files:
internal/commands/storage_run.go
🧬 Code graph analysis (18)
cmd/authelia/main.go (2)
internal/commands/root.go (1)
NewRootCmd(16-61)internal/commands/errors.go (1)
ErrConfigCreated(14-14)
internal/server/server_test.go (2)
internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/random/mathematical.go (1)
NewMathematical(13-18)
internal/middlewares/authelia_context_blackbox_test.go (7)
internal/middlewares/authelia_context.go (1)
NewAutheliaCtx(43-51)internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/mocks/authelia_context.go (1)
NewMockAutheliaCtx(47-239)internal/handlers/types.go (1)
StateResponse(200-205)internal/middlewares/const.go (1)
ContentTypeApplicationJSON(116-116)internal/middlewares/types.go (1)
Providers(40-58)internal/metrics/prometheus.go (1)
NewPrometheus(12-18)
internal/commands/crypto_test.go (1)
internal/commands/context.go (1)
CmdCtx(41-51)
internal/handlers/handler_session_elevation.go (1)
internal/session/types.go (1)
Elevations(74-76)
internal/handlers/handler_authz_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/random/cryptographical.go (2)
internal/clock/real.go (1)
New(10-12)internal/clock/provider.go (1)
Provider(10-15)
internal/totp/totp_test.go (3)
internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)internal/clock/fixed.go (1)
NewFixed(10-12)
internal/commands/build_info_test.go (2)
internal/commands/context.go (1)
CmdCtx(41-51)internal/utils/version.go (1)
Version(37-39)
internal/middlewares/types.go (4)
internal/clock/provider.go (1)
Provider(10-15)internal/service/provider.go (2)
Provider(13-28)Context(46-52)experimental/embed/context.go (1)
Context(65-74)internal/oidc/types.go (1)
Context(212-221)
experimental/embed/context.go (7)
internal/middlewares/types.go (2)
Providers(40-58)Context(60-69)experimental/embed/types.go (2)
Providers(19-19)Configuration(10-10)internal/clock/provider.go (1)
Provider(10-15)internal/service/provider.go (2)
Provider(13-28)Context(46-52)internal/oidc/types.go (1)
Context(212-221)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)
internal/handlers/handler_register_totp_test.go (2)
internal/model/totp_configuration.go (1)
TOTPConfiguration(28-38)internal/middlewares/types.go (1)
Providers(40-58)
internal/commands/storage_run.go (2)
internal/middlewares/types.go (1)
ServiceContext(71-79)internal/totp/provider.go (1)
Provider(8-13)
internal/middlewares/authelia_context.go (3)
internal/middlewares/types.go (2)
AutheliaCtx(29-37)Providers(40-58)internal/clock/provider.go (1)
Provider(10-15)internal/random/cryptographical.go (1)
New(12-14)
internal/handlers/handler_firstfactor_passkey_test.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/model/regulation.go (3)
BannedUser(26-35)AuthenticationAttempt(9-19)BannedIP(37-46)
internal/commands/context.go (5)
experimental/embed/context.go (1)
Context(65-74)internal/middlewares/types.go (1)
Context(60-69)internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/clock/provider.go (1)
Provider(10-15)internal/commands/errors.go (1)
ErrConfigCreated(14-14)
internal/commands/acl_test.go (2)
internal/commands/context.go (1)
CmdCtx(41-51)internal/authorization/types.go (3)
Subject(49-54)Object(67-73)RuleMatchResult(100-112)
internal/commands/context_test.go (6)
internal/commands/context.go (2)
NewCmdCtx(29-38)NewCmdCtxConfig(54-59)internal/commands/root.go (1)
NewRootCmd(16-61)internal/configuration/schema/storage.go (2)
Storage(10-16)StorageLocal(19-21)internal/model/types.go (1)
StartupCheck(168-170)internal/configuration/schema/log.go (1)
Log(4-9)internal/commands/errors.go (1)
ErrConfigCreated(14-14)
🪛 GitHub Check: golangci
internal/middlewares/authelia_context_blackbox_test.go
[failure] 9-9: [golangci] internal/middlewares/authelia_context_blackbox_test.go#L9
File is not properly formatted (goimports)
internal/commands/context_test.go
[failure] 186-186: [golangci] internal/commands/context_test.go#L186
Error return value of (*github.com/spf13/pflag.FlagSet).Set is not checked (errcheck)
[failure] 10-10: [golangci] internal/commands/context_test.go#L10
File is not properly formatted (goimports)
🪛 Gitleaks (8.27.2)
internal/commands/context_test.go
136-136: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
⏰ 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). (2)
- GitHub Check: Analyze (go)
- GitHub Check: StepSecurity Harden-Runner
🔇 Additional comments (46)
internal/commands/acl_test.go (2)
17-25: Command constructors smoke test: LGTM, fool.Solid sanity checks for newAccessControlCommand/newAccessControlCheckCommand. I pity the fool who skips these.
296-338: Nice “maybe-match” coverage.Good job asserting the default policy path with mixed Skipped/Subjects states. I pity the fool who forgets edge cases.
internal/commands/crypto.go (4)
18-18: pflag import is a solid move, fool.Clean alignment with the new FlagSet-driven helpers.
267-272: Clean split between print vs files path.Refactoring to helper funcs keeps RunE lean. I pity the fool who stuffs I/O in command glue.
274-287: Helper looks tight.Flag-driven random + conditional URL-encoding reads well and is easy to test.
631-633: Good abstraction: delegate to runCryptoPairGenerate.Keeps Cobra glue thin and testable. Nice work.
internal/middlewares/identity_verification.go (1)
151-151: Clock provider option swap LGTM.Moving to ctx.GetClock().GetJWTWithTimeFuncOption() matches the new provider pattern. I pity the fool who hardcodes time.
internal/handlers/handler_reset_password.go (1)
42-42: Consistent JWT time source via clock provider.Nice alignment with the refactor; keeps tests deterministic, sucka.
internal/server/server_test.go (1)
142-145: Providers factory usage looks good.NewProvidersBasic() + overriding Random is clear and future-proof for tests.
internal/commands/errors.go (1)
13-14: LGTM, sucka! Sentinel error looks clean and purposeful.Good exported var with clear doc, ready for errors.Is checks. I pity the fool who mixes exit codes with os.Exit(1) here.
cmd/authelia/main.go (1)
4-4: LGTM on import, fool.Bringing in errors for sentinel matching is right.
internal/totp/totp_test.go (1)
112-113: Nice DI swap to clock.New()/random.New(), fool.Tests now cleanly bind providers via constructors; aligns with the new pattern.
Also applies to: 159-160, 223-224
internal/handlers/handler_firstfactor_passkey_test.go (1)
191-191: LGTM on migrating time refs to Providers.Clock, sucka.Consistent use of mock.Ctx.Providers.Clock.Now() in expectations and session fields tightens determinism. I pity the fool who lets wall clock sneak into tests.
Also applies to: 252-252, 288-288, 410-410, 515-515, 547-547, 556-556, 615-615, 619-619, 652-652, 661-661, 720-720, 754-754, 763-763, 919-919, 1023-1023, 1123-1123, 1218-1218, 1290-1290, 1385-1385, 1435-1435, 1510-1510, 1553-1553, 1671-1671, 1714-1714
internal/handlers/handler_authz_test.go (2)
185-193: Clock provider migration looks tight.Nice swap to Providers.Clock.Now() across auth attempts. I pity the fool who mixes clocks.
Also applies to: 294-302, 361-369, 420-428, 538-546, 650-658, 774-782, 983-991, 1060-1068, 1169-1177, 1238-1246, 1312-1320, 1387-1395, 1534-1542
1825-1826: Consistent injection FTW.Assigning mock.Ctx.Providers.Clock is aligned with the new pattern. Solid.
internal/handlers/handler_session_elevation.go (2)
282-289: Expiry check via GetClock is correct.Right source of truth. Clean.
338-343: Setting elevation expiry with provider clock is legit.Matches the new clock contract. Proceed.
internal/handlers/handler_firstfactor_passkey.go (1)
223-223: Passkey flow now uses provider clock—LGTM.UTC on UpdateSignInInfo and consistent RefreshTTL updates. Respect.
Also applies to: 311-313, 335-341, 343-345
internal/commands/context_test.go (2)
18-28: LGTM on context accessors test.Solid assertions on getters wiring.
3-16: Fix formatting with goimports and gofmt
Pity the fool whose imports ain’t in order—CI’s barking! Run:goimports -w internal/commands/context_test.go gofmt -s -w internal/commands/context_test.gointernal/handlers/handler_register_totp_test.go (1)
857-859: LGTM: provider injection is tight.Setting mock.Ctx.Providers.Clock = &mock.Clock after fixing the time is the right move. I pity the fool who forgets to wire the provider!
internal/commands/build_info.go (1)
37-59: Solid refactor to FlagSet and output split.Passing *pflag.FlagSet into runBuildInfo and introducing runBuildInfoOutput with a nil-check is clean and testable. No notes.
internal/commands/build_info_test.go (1)
20-32: Nice: initialized FlagSet avoids nil-map pain.Using pflag.NewFlagSet and require.NoError on Set is correct. Clean work.
internal/commands/storage_run.go (1)
1405-1421: Provider-based TOTP ctx is the real deal.Switching to middlewares.ServiceContext and passing ctx.GetClock()/ctx.GetRandom() into totp.NewContext makes generation deterministic and test-friendly. Respect.
internal/commands/context.go (4)
32-37: LGTM: default providers wired up.Using middlewares.NewProvidersBasic gives you real Clock/Random out of the box. Clean.
84-91: LGTM: ServiceContext getters added.GetClock/GetRandom complete the ServiceContext contract for CmdCtx. I pity the fool who hand-rolls time!
399-401: Verify callers handle ErrConfigCreated, fool.Returning ErrConfigCreated changes control flow; ensure cmd/authelia/main.go and any wrappers treat it as a non-fatal success path.
Would you like me to scan call sites and add a test to assert the behavior?
160-164: LGTM: delegated cert loading.LoadTrustedCertificatesRunE now reuses the helper; simpler and DRY.
internal/middlewares/types.go (2)
5-5: Net import looks right, sucka.Needed for net.IP in interfaces. LGTM.
71-79: Sweep each ServiceContext implementation to ensure GetClock, GetRandom, GetLogger, GetProviders and GetConfiguration methods are defined—I pity the fool who doesn’t!experimental/embed/context.go (3)
66-74: Embed Context additions: solid.Interface lines up with middlewares.Context. Compile-time checks below back it up. Good job.
113-119: Nil-guarded GetClock — that’s how you dodge runtime smackdowns.Lazy init to clock.New() is right.
121-127: Nil-guarded GetRandom — no flakes on my watch.Lazy init to random.New() is correct.
internal/middlewares/authelia_context.go (4)
603-609: GetClock lazy init — righteous.No more nil clock surprises. LGTM.
612-617: GetRandom lazy init — keep it rolling.Cryptographic default on demand is the right call.
620-623: GetLogger passthrough — clean and mean.Straightforward accessor. LGTM.
626-630: Returning a copy pointer is safe — no callers mutate the returned config.internal/middlewares/authelia_context_blackbox_test.go (9)
338-339: Adopting NewProvidersBasic across tests — that’s tight.Standardized, non-nil Clock/Random in tests. Override only what you need. Love it.
Also applies to: 409-409, 490-491, 563-564, 639-639, 689-690, 749-749, 790-793, 870-870, 940-940, 991-991, 1017-1020, 1086-1086
1240-1246: ReplyJSON error-path test — nice coverage.Infinity should fail marshal; assertion matches behavior. LGTM.
1248-1262: SetJSONBody happy-path — crisp.Asserts content type and body shape. Looks good.
1264-1274: Session ops error-paths — thorough.Great guardrail tests for missing X-Forwarded-Host.
1276-1295: Lazy init tests for Clock/Random/UserAttributeResolver — solid.Proves defaults materialize. LGTM.
1297-1303: Value passthrough — tidy verification.Confirms AutheliaCtx storage in context. LGTM.
1304-1330: WebAuthn provider matrix — good spread.Covers config permutations cleanly.
1332-1344: Metrics path smoke test — no panics on my watch.Covers both nil and Prometheus providers. LGTM.
4-4: Fix import grouping with goimports
I pity the fool who doesn’t run goimports—install it (go install golang.org/x/tools/cmd/goimports@latest), ensure$(go env GOPATH)/bin(or$(go env GOBIN)) is in your PATH, then run:goimports -w internal/middlewares/authelia_context_blackbox_test.go
8663a37 to
ca093a2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
internal/commands/context.go (1)
382-401: Guard against index out of range on configs[0].If result isn’t CLIExplicit and env didn’t yield exactly one path, configs can be empty and this panics. I pity the fool who trusts empty slices!
} - if created, err = configuration.EnsureConfigurationExists(configs[0]); err != nil { + if len(configs) == 0 { + return fmt.Errorf("no configuration path determined") + } + + if created, err = configuration.EnsureConfigurationExists(configs[0]); err != nil { ctx.log.Fatal(err) } if created { ctx.log.Warnf("Configuration did not exist so a default one has been generated at %s, you will need to configure this", configs[0]) return ErrConfigCreated }internal/commands/util.go (1)
61-101: Fix bogus error message listing for --charset, sucka!Accepted values include -lower/-upper variants, but the error lists only a subset. Tighten the UX.
Apply this diff:
- return "", fmt.Errorf("flag '--%s' with value '%s' is invalid, must be one of 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', or 'rfc3986'", flagNameCharSet, c) + return "", fmt.Errorf("flag '--%s' with value '%s' is invalid, must be one of 'ascii', 'alphanumeric', 'alphanumeric-lower', 'alphanumeric-upper', 'alphabetic', 'alphabetic-lower', 'alphabetic-upper', 'numeric', 'numeric-hex', 'rfc3986', 'rfc3986-lower', or 'rfc3986-upper'", flagNameCharSet, c)internal/commands/crypto_hash.go (1)
198-205: Don’t append an empty mapping source, fool!getCryptoHashGenerateMapFlagsFromUse can return nil (and should). Gate on length to avoid no-op sources.
Apply this diff:
- if flagsMap != nil { + if flagsMap != nil && len(flagsMap) != 0 { ctx.cconfig.sources = append(ctx.cconfig.sources, configuration.NewCommandLineSourceWithMapping(cmd.Flags(), flagsMap, false, false)) }
♻️ Duplicate comments (11)
internal/handlers/handler_firstfactor_passkey_test.go (1)
717-717: Fix duration math, fool!time.Second - 10ain’t -10s.Use a negative duration so the ban time is 10 seconds in the past.
- Return([]model.BannedIP{{ID: 1, Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Second - 10), Expires: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Minute), Valid: true}}}, nil), + Return([]model.BannedIP{{ID: 1, Time: mock.Ctx.Providers.Clock.Now().UTC().Add(-10 * time.Second), Expires: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Minute), Valid: true}}}, nil),#!/bin/bash # Find any remaining bad patterns like time.Second - <n> rg -nP --glob '!**/vendor/**' 'Add\(\s*time\.Second\s*-\s*\d+\s*\)'internal/oidc/types_test.go (1)
167-171: Pointer-to-copy GetConfiguration: solid move, sucka.Prevents tests from clobbering the base config. Note it’s a shallow copy; nested pointers/maps still alias. If that ever bites, we can add a deep-clone helper. I pity the fool who mutates shared state!
internal/duo/duo.go (4)
22-30: Include path/username in signed-call error.Give callers context without digging through logs, fool.
- if _, body, err = d.SignedCall(method, path, values); err != nil { - return nil, fmt.Errorf("error occurred making signed call: %w", err) + if _, body, err = d.SignedCall(method, path, values); err != nil { + return nil, fmt.Errorf("duo signed call failed (path=%s user=%s): %w", path, userSession.Username, err) }
34-36: Wrap parse error with context.Callers need to know which endpoint blew up.
- if err = json.Unmarshal(body, &response); err != nil { - return nil, fmt.Errorf("error occurred parsing response: %w", err) + if err = json.Unmarshal(body, &response); err != nil { + return nil, fmt.Errorf("duo response parse failed (path=%s user=%s): %w", path, userSession.Username, err) }
38-67: Return actionable errors and fix whitespace-before-return.Include stat/code/message; remove blank lines before returns per wsl_v5, fool.
case "OK": switch response.Code { case fasthttp.StatusOK, fasthttp.StatusNotFound: ctx.GetLogger(). WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). Trace("Duo Push Auth success response.") - - return &response, nil + return &response, nil default: ctx.GetLogger(). WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). Warn("Duo Push Auth call returned a failure status code.") - - return &response, fmt.Errorf("failure status code was returned") + return &response, fmt.Errorf("duo returned failure status code %d (%s): %s", response.Code, response.Stat, response.Message) } case "FAIL": ctx.GetLogger(). WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). Warn("Duo Push Auth call returned a failure status.") - - return &response, fmt.Errorf("failure status was returned") + return &response, fmt.Errorf("duo returned failure status (%s) code %d: %s", response.Stat, response.Code, response.Message) default: ctx.GetLogger(). WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). Warn("Duo Push API call returned an unknown status.") - - return &response, fmt.Errorf("unknown status was returned") + return &response, fmt.Errorf("duo returned unknown status (%s) code %d: %s", response.Stat, response.Code, response.Message) }
32-32: Don’t log raw Duo bodies — that’s PII, sucka!Strip the body; log metadata only.
- ctx.GetLogger().Tracef("Duo endpoint: %s response raw data for %s from IP %s: %s", path, userSession.Username, ctx.RemoteIP().String(), string(body)) + ctx.GetLogger().WithFields(map[string]any{ + "path": path, "username": userSession.Username, "remote_ip": ctx.RemoteIP(), + }).Trace("Duo endpoint response received")internal/middlewares/authelia_context_blackbox_test.go (1)
781-799: Don’t compare random.New() instances for equality, fool.Use type/non-nil for default case; Same instance for provided case.
- if tc.have == nil { - assert.Equal(t, random.New(), middleware.GetRandom()) - } else { - assert.Equal(t, tc.have, middleware.GetRandom()) - } + got := middleware.GetRandom() + if tc.have == nil { + assert.NotNil(t, got) + assert.IsType(t, random.New(), got) + } else { + assert.Same(t, tc.have, got) + }internal/commands/build_info_test.go (3)
20-32: Nice fix: no more nil-map FlagSet panics, sucka.Using pflag.NewFlagSet with ContinueOnError avoids nil-map blowups. Clean and correct.
3-11: I pity the fool who hard-codes GOOS/GOARCH/compiler and Go version. Make expectations env-agnostic.These tests will flake off Linux/amd64/gc or different Go versions. Assert dynamic substrings instead of a giant literal.
Apply:
@@ import ( "bytes" + "runtime" "runtime/debug" "testing" @@ "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ func TestRunBuildInfo(t *testing.T) { - newFlags := func(verbose bool) *pflag.FlagSet { + newFlags := func(verbose bool) *pflag.FlagSet { flags := pflag.NewFlagSet("test", pflag.ContinueOnError) @@ return flags } - testCases := []struct { - name string - flags *pflag.FlagSet - expected string - err string - }{ + // Build dynamic expectations so tests pass across environments. + info, ok := debug.ReadBuildInfo() + require.True(t, ok) + osExp := "Build OS: " + runtime.GOOS + archExp := "Build Arch: " + runtime.GOARCH + compilerExp := "Build Compiler: " + runtime.Compiler + goHdr := "Go:\n" + modExp := "Module Path: " + info.Main.Path + + testCases := []struct { + name string + flags *pflag.FlagSet + expected []string + err string + }{ { "Successful", - newFlags(false), - "Last Tag: unknown\nState: untagged dirty\nBranch: master\nCommit: unknown\nBuild Number: 0\nBuild OS: linux\nBuild Arch: amd64\nBuild Compiler: gc\nBuild Date: \nDevelopment: false\nExtra: \n\nGo:\n Version: go1.25.0\n Module Path: github.com/authelia/authelia/v4\n Executable Path: github.com/authelia/authelia/v4/internal/commands.test\n", + newFlags(false), + []string{osExp, archExp, compilerExp, goHdr, modExp}, "", }, { "SuccessfulVerbose", - newFlags(true), - "Last Tag: unknown\nState: untagged dirty\nBranch: master\nCommit: unknown\nBuild Number: 0\nBuild OS: linux\nBuild Arch: amd64\nBuild Compiler: gc\nBuild Date: \nDevelopment: false\nExtra: \n\nGo:\n Version: go1.25.0\n Module Path: github.com/authelia/authelia/v4\n Executable Path: github.com/authelia/authelia/v4/internal/commands.test\n", + newFlags(true), + []string{osExp, archExp, compilerExp, goHdr, modExp}, "", }, } @@ - err := runBuildInfo(buf, tc.flags) - - assert.Contains(t, buf.String(), tc.expected) + err := runBuildInfo(buf, tc.flags) + for _, s := range tc.expected { + assert.Contains(t, buf.String(), s) + } if tc.err != "" { assert.EqualError(t, err, tc.err) } else { assert.NoError(t, err) }Also applies to: 34-52, 58-66
73-143: Make TestRunBuildInfoOutput env-agnostic too. Assert stable substrings, not full blobs.Stop pinning linux/amd64/gc. Check GOOS/GOARCH/compiler, “Go:” header, module path, and verbose deps.
Apply:
func TestRunBuildInfoOutput(t *testing.T) { + osExp := "Build OS: " + runtime.GOOS + archExp := "Build Arch: " + runtime.GOARCH + compilerExp := "Build Compiler: " + runtime.Compiler + modExp := "Module Path: github.com/authelia/authelia/v4" @@ []string{ - "Last Tag: unknown\nState: untagged dirty\nBranch: master\nCommit: unknown\nBuild Number: 0\nBuild OS: linux\nBuild Arch: amd64\nBuild Compiler: gc\nBuild Date: \nDevelopment: false\nExtra: \n\nGo:\n Version: \n Module Path: github.com/authelia/authelia/v4", + osExp, archExp, compilerExp, "Go:\n", modExp, }, @@ []string{ - "Last Tag: unknown\nState: untagged dirty\nBranch: master\nCommit: unknown\nBuild Number: 0\nBuild OS: linux\nBuild Arch: amd64\nBuild Compiler: gc\nBuild Date: \nDevelopment: false\nExtra: \n\nGo:\n Version: \n Module Path: github.com/authelia/authelia/v4", - "Dependencies:\n github.com/a/fake/pkg@v1.0.0 ()\n", + osExp, archExp, compilerExp, "Go:\n", modExp, + "Dependencies:", "github.com/a/fake/pkg@v1.0.0", },Remember to add the runtime import if you didn’t in the earlier change:
import ( "bytes" + "runtime" "runtime/debug"internal/commands/crypto_hash.go (1)
220-223: Don’t bail if File backend is nil—hydrate sane defaultsLet users generate hashes without preconfiguring the file backend. Initialize with defaults.
Apply this diff:
- if config.AuthenticationBackend.File == nil { - return fmt.Errorf("authentication backend file is not configured") - } + if config.AuthenticationBackend.File == nil { + config.AuthenticationBackend.File = &schema.AuthenticationBackendFile{ + Password: schema.DefaultPasswordConfig, + } + }
🧹 Nitpick comments (17)
internal/handlers/handler_firstfactor_passkey_test.go (2)
336-341: Standardize time source in tests, sucka.Some spots still use
time.Now(); prefer the provider clock for consistency and flake-free tests.- Expires: time.Now().Add(time.Minute), + Expires: mock.Ctx.Providers.Clock.Now().Add(time.Minute),- CreatedAt: time.Now(), + CreatedAt: mock.Ctx.Providers.Clock.Now(),Also applies to: 338-338, 444-446, 546-549, 651-653, 754-756
919-925: Use the constant, fool.Replace string literal
"Passkey"withregulation.AuthTypePasskeyfor consistency.- Type: "Passkey", + Type: regulation.AuthTypePasskey,Also applies to: 1290-1296, 1385-1391, 1435-1441, 1481-1487, 1510-1516, 1553-1559, 1671-1677, 1714-1720
internal/handlers/handler_oauth2_consent.go (2)
296-306: Capture ‘now’ once per handler block.Avoid minor drift and improve readability by computing
nowonce.- if bodyJSON.PreConfigure { + if bodyJSON.PreConfigure { + now := ctx.GetClock().Now() if client.GetConsentPolicy().Mode == oidc.ClientConsentModePreConfigured { config := model.OAuth2ConsentPreConfig{ ClientID: consent.ClientID, Subject: consent.Subject.UUID, - CreatedAt: ctx.GetClock().Now(), - ExpiresAt: sql.NullTime{Time: ctx.GetClock().Now().Add(client.GetConsentPolicy().Duration), Valid: true}, + CreatedAt: now, + ExpiresAt: sql.NullTime{Time: now.Add(client.GetConsentPolicy().Duration), Valid: true}, Scopes: consent.GrantedScopes, Audience: consent.GrantedAudience, GrantedClaims: bodyJSON.Claims, } … } } - consent.SetRespondedAt(ctx.GetClock().Now(), 0) + consent.SetRespondedAt(now, 0)Also applies to: 352-356
545-566: Same deal in Device Authorization.Compute
nowonce and reuse for session creation and response time.- if consent, err = model.NewOAuth2ConsentSession(ctx.GetClock().Now().Add(10*time.Second), subject, r); err != nil { + now := ctx.GetClock().Now() + if consent, err = model.NewOAuth2ConsentSession(now.Add(10*time.Second), subject, r); err != nil { … } … - consent.SetRespondedAt(ctx.GetClock().Now(), 0) + consent.SetRespondedAt(now, 0)internal/handlers/handler_session_elevation.go (1)
78-86: Reuse ‘now’ to avoid double reads, sucka.Minor polish: compute once, use for
Expiresand the expiry check.- response.Elevated = true - response.Expires = int(userSession.Elevations.User.Expires.Sub(ctx.GetClock().Now()).Seconds()) - - if userSession.Elevations.User.Expires.Before(ctx.GetClock().Now()) { + response.Elevated = true + now := ctx.GetClock().Now() + response.Expires = int(userSession.Elevations.User.Expires.Sub(now).Seconds()) + + if userSession.Elevations.User.Expires.Before(now) { ctx.Logger.WithFields(map[string]any{"username": userSession.Username, "expired": userSession.Elevations.User.Expires.Unix()}). Info("The user session elevation has already expired so it has been destroyed")internal/commands/storage_run.go (1)
1751-1755: Guard against nil RNG to avoid surprises.If a custom ctx ever returns nil, this panics. Add a safe fallback.
-func runStorageUserTOTPExportPNG(ctx middlewares.ServiceContext, w io.Writer, store storage.Provider, dir string) (err error) { +func runStorageUserTOTPExportPNG(ctx middlewares.ServiceContext, w io.Writer, store storage.Provider, dir string) (err error) { if dir == "" { - rand := ctx.GetRandom() - dir = rand.StringCustom(8, random.CharSetAlphaNumeric) + rnd := ctx.GetRandom() + if rnd == nil { + rnd = random.New() + } + dir = rnd.StringCustom(8, random.CharSetAlphaNumeric) }internal/commands/debug.go (1)
291-488: Disambiguate verification errors for clearer hints.You reuse a single err across system/custom verifies, making hints ambiguous. Track both to print accurate guidance, fool.
- for i, cert := range conn.ConnectionState().PeerCertificates { - if _, err = cert.Verify(optsSystem); err != nil { - validSystem = false - } - if _, err = cert.Verify(opts); err != nil { - valid = false - } + for i, cert := range conn.ConnectionState().PeerCertificates { + var errSystem, errCustom error + if _, errSystem = cert.Verify(optsSystem); errSystem != nil { + validSystem = false + } + if _, errCustom = cert.Verify(opts); errCustom != nil { + valid = false + } // ... - if err != nil { + if errCustom != nil || errSystem != nil { + e := errCustom + if e == nil { + e = errSystem + } var ( errUA x509.UnknownAuthorityError errH x509.HostnameError errCI x509.CertificateInvalidError ) - switch { - case errors.As(err, &errUA): + switch { + case errors.As(e, &errUA): // ... - case errors.As(err, &errH): + case errors.As(e, &errH): // ... - case errors.As(err, &errCI): + case errors.As(e, &errCI): // ... } - _, _ = fmt.Fprintf(w, "\t\tValidation Error: %v\n", err) + _, _ = fmt.Fprintf(w, "\t\tValidation Error: %v\n", e) }internal/commands/context.go (2)
84-91: Nil‑guard the accessors to never return a nil provider.After LoadProviders(), Clock/Random could be unset depending on wiring. Be bulletproof in the getters, fool.
-func (ctx *CmdCtx) GetClock() (clock clock.Provider) { - return ctx.providers.Clock -} +func (ctx *CmdCtx) GetClock() (provider clock.Provider) { + if ctx.providers.Clock == nil { + ctx.providers.Clock = clock.New() + } + return ctx.providers.Clock +} -func (ctx *CmdCtx) GetRandom() (random random.Provider) { - return ctx.providers.Random -} +func (ctx *CmdCtx) GetRandom() (provider random.Provider) { + if ctx.providers.Random == nil { + ctx.providers.Random = random.New() + } + return ctx.providers.Random +}
159-186: Simplify error aggregation with errors.Join, fool.Current loops are noisy. Join them and wrap once.
- warns, errs = ctx.LoadTrustedCertificates() - - if len(warns) != 0 || len(errs) != 0 { - for _, e := range warns { - if err == nil { - err = e - continue - } - err = fmt.Errorf("%v, %w", err, e) - } - - for _, e := range errs { - if err == nil { - err = e - continue - } - err = fmt.Errorf("%v, %w", err, e) - } - - return fmt.Errorf("failed to load trusted certificates: %w", err) - } + warns, errs = ctx.LoadTrustedCertificates() + if len(warns) != 0 || len(errs) != 0 { + err = errors.Join(append(warns, errs...)...) + return fmt.Errorf("failed to load trusted certificates: %w", err) + }Add this import:
- "errors"
internal/duo/duo.go (2)
72-79: PreAuth: add context to errors.Name the endpoint in returns, fool.
- if err != nil { - return nil, fmt.Errorf("error occurred making the preauth call to the duo api: %w", err) + if err != nil { + return nil, fmt.Errorf("duo preauth call failed (path=/auth/v2/preauth user=%s): %w", userSession.Username, err) } - if err = json.Unmarshal(response.Response, &preAuthResponse); err != nil { - return nil, fmt.Errorf("error occurred parsing the duo api preauth json response: %w", err) + if err = json.Unmarshal(response.Response, &preAuthResponse); err != nil { + return nil, fmt.Errorf("duo preauth parse failed (path=/auth/v2/preauth user=%s): %w", userSession.Username, err) }
88-98: Auth: add context to errors.Same treatment for /auth, sucker.
- if err != nil { - return nil, fmt.Errorf("error occurred making the auth call to the duo api: %w", err) + if err != nil { + return nil, fmt.Errorf("duo auth call failed (path=/auth/v2/auth user=%s): %w", userSession.Username, err) } - if err = json.Unmarshal(response.Response, &authResponse); err != nil { - return nil, fmt.Errorf("error occurred parsing the duo api auth json response: %w", err) + if err = json.Unmarshal(response.Response, &authResponse); err != nil { + return nil, fmt.Errorf("duo auth parse failed (path=/auth/v2/auth user=%s): %w", userSession.Username, err) }experimental/embed/context.go (1)
129-131: Optional: return a zero IP instead of nil.Returning net.IPv4zero (or v6 ::) avoids "" in logs. Minor polish, sucka.
-func (c *ctxEmbed) RemoteIP() net.IP { - return nil -} +func (c *ctxEmbed) RemoteIP() net.IP { + return net.IPv4zero +}internal/middlewares/authelia_context_blackbox_test.go (1)
26-33: Nit: consider t.Parallel() in pure, isolated tests.Most of these don’t share state; parallelize to speed up the suite, sucka.
internal/commands/build_info_test.go (1)
55-69: Parallelize subtests for speed, fool.Safe here; each case uses its own buffer/flags.
Apply:
t.Run(tc.name, func(t *testing.T) { + t.Parallel() buf := new(bytes.Buffer)internal/commands/build_info.go (1)
3-13: Deduplicate the “failed to read build info” error.Use a shared sentinel to keep tests and code consistent.
Apply:
import ( + "errors" "fmt" "io" "runtime" "runtime/debug" @@ func runBuildInfo(w io.Writer, flags *pflag.FlagSet) (err error) { @@ - if info, ok = debug.ReadBuildInfo(); !ok { - return fmt.Errorf("failed to read build info") - } + if info, ok = debug.ReadBuildInfo(); !ok { + return errBuildInfoUnavailable + } @@ -func runBuildInfoOutput(w io.Writer, verbose bool, info *debug.BuildInfo) (err error) { - if info == nil { - return fmt.Errorf("failed to read build info") - } +func runBuildInfoOutput(w io.Writer, verbose bool, info *debug.BuildInfo) (err error) { + if info == nil { + return errBuildInfoUnavailable + } @@ +var errBuildInfoUnavailable = errors.New("failed to read build info")Also applies to: 48-50, 56-58
cmd/authelia/main.go (1)
12-17: Return instead of os.Exit(0) so defers/logs can flush.os.Exit(0) skips defers in main and any buffered logs; returning achieves the same exit code without that risk. I pity the fool who drops logs on the floor.
- switch { - case errors.Is(err, commands.ErrConfigCreated): - os.Exit(0) - default: - os.Exit(1) - } + switch { + case errors.Is(err, commands.ErrConfigCreated): + return + default: + os.Exit(1) + }internal/commands/crypto_hash.go (1)
278-335: Minor UX nit: consistent newline after non-interactive inputsWhen password comes from --password or random, no newline is printed before subsequent output; interactive path prints one. Consider a small spacer for parity.
One option:
case random: - password, err = flagsGetRandomCharacters(flags, cmdFlagNameRandomLength, cmdFlagNameRandomCharSet, cmdFlagNameRandomCharacters) - return + password, err = flagsGetRandomCharacters(flags, cmdFlagNameRandomLength, cmdFlagNameRandomCharSet, cmdFlagNameRandomCharacters) + if err == nil { _, _ = fmt.Fprintln(w) } + return case flags.Changed(cmdFlagNamePassword): - password, err = flags.GetString(cmdFlagNamePassword) - return + password, err = flags.GetString(cmdFlagNamePassword) + if err == nil { _, _ = fmt.Fprintln(w) } + return
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
internal/configuration/test_resources/userdb/debug-tests.ymlis excluded by!**/*.yml
📒 Files selected for processing (80)
cmd/authelia-gen/openid_conformance.go(1 hunks)cmd/authelia/main.go(1 hunks)experimental/embed/context.go(3 hunks)experimental/embed/provider/general.go(1 hunks)internal/clock/fixed.go(2 hunks)internal/clock/provider.go(1 hunks)internal/clock/real.go(2 hunks)internal/commands/acl_test.go(4 hunks)internal/commands/build_info.go(2 hunks)internal/commands/build_info_test.go(3 hunks)internal/commands/context.go(6 hunks)internal/commands/context_test.go(1 hunks)internal/commands/crypto.go(6 hunks)internal/commands/crypto_hash.go(6 hunks)internal/commands/crypto_test.go(1 hunks)internal/commands/debug.go(13 hunks)internal/commands/debug_test.go(1 hunks)internal/commands/errors.go(1 hunks)internal/commands/storage_run.go(4 hunks)internal/commands/util.go(2 hunks)internal/duo/duo.go(2 hunks)internal/duo/duo_test.go(2 hunks)internal/duo/types.go(2 hunks)internal/handlers/func_test.go(1 hunks)internal/handlers/handler_authz_authn.go(5 hunks)internal/handlers/handler_authz_test.go(16 hunks)internal/handlers/handler_firstfactor_passkey.go(3 hunks)internal/handlers/handler_firstfactor_passkey_test.go(26 hunks)internal/handlers/handler_firstfactor_password.go(2 hunks)internal/handlers/handler_firstfactor_password_test.go(2 hunks)internal/handlers/handler_oauth2_authorization.go(1 hunks)internal/handlers/handler_oauth2_authorization_claims.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core_test.go(10 hunks)internal/handlers/handler_oauth2_authorization_consent_explicit.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_implicit.go(3 hunks)internal/handlers/handler_oauth2_authorization_consent_preconfigured.go(5 hunks)internal/handlers/handler_oauth2_consent.go(6 hunks)internal/handlers/handler_oauth2_device_authorization.go(1 hunks)internal/handlers/handler_oauth2_introspection.go(1 hunks)internal/handlers/handler_oauth2_oidc_userinfo.go(2 hunks)internal/handlers/handler_oauth2_oidc_wellknown.go(1 hunks)internal/handlers/handler_oauth2_token.go(1 hunks)internal/handlers/handler_oauth2_wellknown.go(1 hunks)internal/handlers/handler_register_totp.go(3 hunks)internal/handlers/handler_register_totp_test.go(3 hunks)internal/handlers/handler_reset_password.go(1 hunks)internal/handlers/handler_session_elevation.go(3 hunks)internal/handlers/handler_session_elevation_test.go(4 hunks)internal/handlers/handler_sign_duo.go(1 hunks)internal/handlers/handler_sign_password.go(1 hunks)internal/handlers/handler_sign_password_test.go(1 hunks)internal/handlers/handler_sign_totp.go(2 hunks)internal/handlers/handler_sign_totp_test.go(2 hunks)internal/handlers/handler_sign_webauthn.go(2 hunks)internal/middlewares/authelia_context.go(1 hunks)internal/middlewares/authelia_context_blackbox_test.go(15 hunks)internal/middlewares/identity_verification.go(1 hunks)internal/middlewares/require_auth_test.go(1 hunks)internal/middlewares/startup.go(2 hunks)internal/middlewares/timing_attack_delay_test.go(2 hunks)internal/middlewares/types.go(2 hunks)internal/middlewares/util.go(2 hunks)internal/mocks/authelia_context.go(2 hunks)internal/mocks/duo_api.go(3 hunks)internal/model/webauthn_test.go(1 hunks)internal/notification/smtp_notifier.go(1 hunks)internal/oidc/types.go(1 hunks)internal/oidc/types_test.go(1 hunks)internal/random/cryptographical.go(1 hunks)internal/regulation/regulator_blackbox_test.go(2 hunks)internal/server/server_test.go(1 hunks)internal/service/file_watcher_test.go(2 hunks)internal/service/sever_test.go(4 hunks)internal/service/signal_test.go(2 hunks)internal/suites/example/compose/duo-api/duo_api.js(3 hunks)internal/totp/totp_test.go(3 hunks)internal/utils/const_test.go(1 hunks)internal/utils/crypto.go(1 hunks)internal/utils/exec.go(0 hunks)
💤 Files with no reviewable changes (1)
- internal/utils/exec.go
🚧 Files skipped from review as they are similar to previous changes (55)
- cmd/authelia-gen/openid_conformance.go
- internal/random/cryptographical.go
- internal/handlers/handler_reset_password.go
- internal/service/signal_test.go
- internal/commands/errors.go
- internal/handlers/handler_oauth2_wellknown.go
- internal/handlers/handler_sign_totp.go
- internal/handlers/handler_sign_duo.go
- internal/totp/totp_test.go
- internal/commands/crypto_test.go
- internal/handlers/handler_oauth2_authorization.go
- experimental/embed/provider/general.go
- internal/handlers/handler_firstfactor_password_test.go
- internal/handlers/handler_sign_password.go
- internal/handlers/handler_oauth2_device_authorization.go
- internal/utils/const_test.go
- internal/handlers/handler_sign_password_test.go
- internal/handlers/handler_oauth2_authorization_consent_core_test.go
- internal/middlewares/startup.go
- internal/commands/debug_test.go
- internal/handlers/handler_oauth2_oidc_wellknown.go
- internal/handlers/handler_register_totp.go
- internal/utils/crypto.go
- internal/middlewares/types.go
- internal/mocks/authelia_context.go
- internal/handlers/handler_firstfactor_password.go
- internal/middlewares/timing_attack_delay_test.go
- internal/mocks/duo_api.go
- internal/service/file_watcher_test.go
- internal/handlers/handler_authz_test.go
- internal/handlers/handler_oauth2_authorization_consent_core.go
- internal/handlers/handler_authz_authn.go
- internal/handlers/handler_oauth2_oidc_userinfo.go
- internal/clock/real.go
- internal/handlers/handler_oauth2_authorization_claims.go
- internal/handlers/handler_oauth2_authorization_consent_explicit.go
- internal/duo/duo_test.go
- internal/handlers/handler_oauth2_authorization_consent_preconfigured.go
- internal/handlers/handler_oauth2_authorization_consent_implicit.go
- internal/service/sever_test.go
- internal/handlers/handler_sign_totp_test.go
- internal/oidc/types.go
- internal/middlewares/require_auth_test.go
- internal/handlers/handler_oauth2_introspection.go
- internal/handlers/handler_oauth2_token.go
- internal/commands/acl_test.go
- internal/handlers/handler_register_totp_test.go
- internal/model/webauthn_test.go
- internal/server/server_test.go
- internal/suites/example/compose/duo-api/duo_api.js
- internal/middlewares/authelia_context.go
- internal/handlers/handler_firstfactor_passkey.go
- internal/commands/crypto.go
- internal/commands/context_test.go
- internal/handlers/func_test.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-29T10:47:45.888Z
Learnt from: james-d-elliott
PR: authelia/authelia#10189
File: internal/clock/provider.go:14-15
Timestamp: 2025-08-29T10:47:45.888Z
Learning: The internal/mocks directory does not contain any mock clock implementations. Tests use concrete clock instances like clock.New(), clock.NewFixed(), and direct assignment to mock.Ctx.Providers.Clock instead of generated mocks for the clock.Provider interface.
Applied to files:
internal/regulation/regulator_blackbox_test.gointernal/handlers/handler_session_elevation_test.gointernal/clock/provider.gointernal/handlers/handler_firstfactor_passkey_test.go
📚 Learning: 2025-08-27T21:37:17.083Z
Learnt from: james-d-elliott
PR: authelia/authelia#10059
File: internal/commands/storage_run.go:23-23
Timestamp: 2025-08-27T21:37:17.083Z
Learning: The Authelia project uses "go.yaml.in/yaml/v4" as their YAML package import path, not the standard "gopkg.in/yaml.v3" or "gopkg.in/yaml.v2". This is used consistently across their codebase.
Applied to files:
internal/commands/storage_run.go
🧬 Code graph analysis (17)
internal/regulation/regulator_blackbox_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/handlers/handler_session_elevation_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/oidc/types_test.go (1)
internal/oidc/config.go (1)
Config(80-130)
internal/notification/smtp_notifier.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/middlewares/util.go (7)
internal/storage/sql_provider.go (1)
NewProvider(24-35)experimental/embed/provider/general.go (2)
NewRegulator(52-54)New(26-28)internal/regulation/types.go (1)
Regulator(16-25)internal/middlewares/types.go (1)
Providers(40-58)experimental/embed/context.go (1)
New(18-61)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)
internal/commands/util.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/duo/types.go (2)
internal/middlewares/types.go (1)
Context(60-69)internal/session/types.go (1)
UserSession(20-48)
experimental/embed/context.go (7)
internal/middlewares/types.go (2)
Providers(40-58)Context(60-69)experimental/embed/types.go (2)
Providers(19-19)Configuration(10-10)internal/clock/provider.go (1)
Provider(10-15)internal/service/provider.go (2)
Provider(13-28)Context(46-52)internal/oidc/types.go (1)
Context(212-221)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)
internal/handlers/handler_oauth2_consent.go (1)
internal/model/oidc.go (1)
NewOAuth2ConsentSession(20-22)
internal/commands/storage_run.go (3)
internal/middlewares/types.go (1)
ServiceContext(71-79)internal/storage/provider.go (1)
Provider(15-328)internal/totp/provider.go (1)
Provider(8-13)
internal/duo/duo.go (3)
internal/duo/types.go (4)
Production(27-29)Response(43-49)PreAuthResponse(60-68)AuthResponse(52-57)internal/middlewares/types.go (1)
Context(60-69)internal/session/types.go (1)
UserSession(20-48)
internal/middlewares/authelia_context_blackbox_test.go (10)
internal/middlewares/authelia_context.go (1)
NewAutheliaCtx(43-51)internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)internal/mocks/authelia_context.go (1)
NewMockAutheliaCtx(47-239)internal/handlers/types.go (1)
StateResponse(200-205)internal/middlewares/const.go (1)
ContentTypeApplicationJSON(116-116)internal/middlewares/types.go (1)
Providers(40-58)internal/expression/user_attributes.go (1)
NewUserAttributes(13-24)internal/metrics/prometheus.go (1)
NewPrometheus(12-18)
cmd/authelia/main.go (2)
internal/commands/root.go (1)
NewRootCmd(16-61)internal/commands/errors.go (1)
ErrConfigCreated(14-14)
internal/commands/crypto_hash.go (2)
internal/configuration/schema/authentication.go (1)
AuthenticationBackend(10-19)internal/authentication/file_user_provider.go (1)
NewFileCryptoHashFromConfig(242-288)
internal/commands/context.go (5)
experimental/embed/context.go (1)
Context(65-74)internal/middlewares/types.go (1)
Context(60-69)internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/clock/provider.go (1)
Provider(10-15)internal/commands/errors.go (1)
ErrConfigCreated(14-14)
internal/handlers/handler_firstfactor_passkey_test.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/model/regulation.go (3)
BannedUser(26-35)AuthenticationAttempt(9-19)BannedIP(37-46)
internal/commands/debug.go (8)
internal/middlewares/util.go (1)
NewAuthenticationProvider(84-93)internal/expression/user_attributes.go (1)
NewUserAttributes(13-24)internal/configuration/schema/identity_providers.go (1)
IdentityProviders(11-13)internal/oidc/claims.go (1)
NewCustomClaimsStrategy(444-506)internal/commands/context.go (1)
CmdCtx(41-51)internal/configuration/schema/types_address.go (1)
NewAddress(16-18)internal/utils/crypto.go (1)
IsInsecureCipherSuite(735-743)internal/utils/const.go (1)
BlockTypeCertificate(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). (2)
- GitHub Check: Analyze (go)
- GitHub Check: StepSecurity Harden-Runner
🔇 Additional comments (38)
internal/notification/smtp_notifier.go (1)
95-95: LGTM: switched to random.New() cleanlyGood move to the provider constructor. I pity the fool who new()s concrete types directly. No further action.
internal/clock/provider.go (1)
5-7: JWT time option on clock interface: solidInterface addition is coherent with usages. I pity the fool who forgets to implement it—looks like Fixed/Real have it covered.
Also applies to: 14-15
internal/handlers/handler_sign_webauthn.go (1)
227-228: UTC normalization + GetClock(): nice consistencyBoth credential update and session flags now use ctx.GetClock().Now().UTC(). That kills timezone drift, sucka.
Also applies to: 273-276
internal/clock/fixed.go (1)
24-27: Fixed clock JWT time-func: correct bindingReturning jwt.WithTimeFunc(c.Now) is exactly right. Pity the fool who uses real time in tests—this keeps it deterministic.
internal/middlewares/identity_verification.go (1)
151-151: I pity the fool without the JWT time option—no stragglers remain!Both
jwt.ParseWithClaimssites now includectx.GetClock().GetJWTWithTimeFuncOption().internal/handlers/handler_firstfactor_passkey_test.go (1)
191-198: Clock provider migration LGTM.Switching to
mock.Ctx.Providers.Clock.Now()makes these tests deterministic. I pity the fool who mixes time sources.Also applies to: 252-259, 288-296, 410-417, 618-626, 721-727, 919-926, 1290-1297, 1385-1393, 1435-1442, 1481-1488, 1510-1517, 1553-1560, 1671-1678, 1714-1721
internal/handlers/handler_oauth2_consent.go (1)
75-75: LGTM on switching to ctx.GetClock().Now().Good move centralizing time. I pity the fool who hardcodes wall time.
Also applies to: 301-302, 355-356, 545-546, 565-566, 661-661
internal/handlers/handler_session_elevation_test.go (1)
303-304: Providers.Clock injection LGTM.Tests now align with handler usage of
ctx.GetClock(). Good hustle.Also applies to: 563-565, 1057-1059, 1386-1388
internal/regulation/regulator_blackbox_test.go (1)
30-31: Clock wiring LGTM, fool.Moving to
Ctx.Providers.Clockkeeps the suite in step with the refactor.Also applies to: 1234-1235
internal/handlers/handler_session_elevation.go (1)
80-82: Nice shift to ctx.GetClock().Time reads and writes are now injectable. That’s tight.
Also applies to: 282-283, 342-342
internal/middlewares/util.go (2)
38-45: Regulator now uses providers.Clock — test determinism secured.Good wiring. Single clock source across providers is the right hook-up, fool.
75-81: NewProvidersBasic: clean defaults.Clock/Random non-nil by default; that’s the baseline we need. Nice and simple.
internal/commands/storage_run.go (1)
1405-1421: TOTP generate now uses ctx Clock/Random — that’s how you do it.Great swap to ServiceContext. Deterministic and test-friendly, fool.
internal/commands/debug.go (3)
133-135: Wrapper call for OIDC claims: tidy abstraction.Plumbs writer/flags/config cleanly. Good form, fool.
137-239: runDebugOIDCClaims: provider/resolver init and hydration flow look right.Validates inputs, builds strategy, and prints JSON with proper indent. No beef.
240-245: runDebugExpression: slimmer signature, same punch.Dropped unused ctx/flags; routes output via writer. That’s tight.
internal/duo/types.go (2)
21-23: Interface now takes middlewares.Context — verify all impls updated.Breaking change; ensure Production, mocks, and tests implement the new ctx type and method set. I pity the fool who leaves a stale mock.
61-68: PreAuthResponse fields extended — looks good.JSON tags match Duo payloads; additive change is safe for callers reading only older fields.
internal/commands/context.go (3)
17-17: LGTM on adding clock import, sucka.Keeps the accessor signature legit. I pity the fool who forgets the import!
33-37: Good move to NewProvidersBasic().Solid defaults for Clock/Random at construction time. Clean and testable.
343-343: Param rename to_is fine.Silences the unused var cleanly. Keep it tight.
experimental/embed/context.go (2)
66-74: Expanded embed Context looks good.Interfaces line up with middlewares.Context; keepin’ it consistent, fool.
113-127: Nice lazy init for Clock/Random.Never returns nil, just like a champ.
internal/middlewares/authelia_context_blackbox_test.go (4)
338-341: LGTM using NewProvidersBasic in tests.Keeps defaults aligned with prod wiring. I pity the fool who hand-rolls providers!
1240-1262: JSON helpers test is solid.Covers failure path (+Inf) and content-type/body on success. Nice work.
1265-1274: Session error-path tests read well.Good assertions on exact error strings. Keep ‘em precise.
1277-1295: Great coverage for lazy getters.Asserting nil->non-nil transitions for Clock/Random/UserAttributeResolver is on point.
internal/commands/build_info.go (2)
37-53: Clean split of flag parsing and output. LGTM.runBuildInfo reads flags then delegates to runBuildInfoOutput. Simple and testable.
63-64: Verify label: don’t lie about “Executable Path”, fool.debug.BuildInfo.Path is the main module path, not an executable filesystem path. Ensure fmtAutheliaBuildGo labels match semantics (e.g., “Path” or “Main Module Path”), and sync tests accordingly.
cmd/authelia/main.go (2)
4-4: Solid use of errors.Is for sentinel matching.Clean and idiomatic. I pity the fool who compares errors with ==.
12-17: No silent exits—errors print by default
Verified there are no SilenceErrors or SilenceUsage flags set in NewRootCmd or elsewhere, so Cobra’s default behavior writes any returned error to stderr before main’s os.Exit(1). I pity the fool who fails silently!internal/commands/util.go (1)
103-106: RNG ctor switch is good, fool!Using random.New() aligns with the provider factory. Solid.
internal/commands/crypto_hash.go (6)
3-13: Importing io and pflag is the right move, sucka!Decoupling I/O and explicit flag handling is on point for testability.
173-175: Password retrieval via writer/flags looks tightGood switch to cmdFlagsCryptoHashGetPassword with cmd.OutOrStdout().
209-211: Extraction to runCryptoHashGenerate is cleanNice separation of concerns for easier unit testing. I like it.
232-241: Algorithm selection and hasher init look correctSetting Algorithm on subcommands before NewFileCryptoHashFromConfig is the right flow.
247-256: Output UX is solidPrinting Random Password (+ URL-encoded) and Digest to the provided writer is clean and script-friendly.
260-276: Randomness toggles are sensible, foolHonors --random or any setter change (charset/characters/length). Good ergonomics.
82d131b to
33fbc86
Compare
There was a problem hiding this 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 (5)
internal/utils/crypto_test.go (1)
39-44: Undefined identifier ‘windows’ will KO your build. Quote it, fool.runtime.GOOS is a string; compare to "windows".
- if runtime.GOOS == windows { + if runtime.GOOS == "windows" { @@ - if runtime.GOOS == windows { + if runtime.GOOS == "windows" {Also applies to: 61-66
internal/handlers/func_test.go (1)
73-82: Guard period==0 and avoid int overflow in test helper.Current code panics if period==0 and does int(step)/period. Use uint64 math and treat <=0 as default. I pity the fool who divides by zero!
Apply:
- step := ctx.GetClock().Now().Unix() + now := ctx.GetClock().Now().Unix() - if period < 0 { + if period <= 0 { period = ctx.Configuration.TOTP.DefaultPeriod } - return uint64(int(step) / period) //nolint:gosec // This is a testing func. + return uint64(now) / uint64(period) //nolint:gosec // This is a testing func.internal/handlers/handler_firstfactor_passkey_test.go (1)
1-1784: Fix duration arithmetic and replace raw time.Now() in tests
- In internal/handlers/handler_firstfactor_passkey_test.go line 717, change
UTC().Add(time.Second - 10)toUTC().Add(-10 * time.Second).- Eliminate all direct
time.Now()/time.Now().Add(...)calls in that test (e.g. lines 213, 304, 338, 347, 443, 452, 857, 1610, etc.); usemock.Ctx.Providers.Clock.Now()instead and invokesetUpMockClock(mock)at the start of eacht.Run.internal/duo/duo.go (1)
1-102: Update duo tests error assertions
Adjust expected error strings in internal/duo/duo_test.go for JSON parsing errors in PreAuthCall and AuthCall to match the new messages (e.g. use “error occurred parsing the duo api preauth json response…” and “error occurred parsing the duo api auth json response…”).internal/commands/storage_run.go (1)
40-61: I pity the fool who fails on certificate warnings—only certificate errors should be fatal!
Replace the switch in LoadProvidersStorageRunE (internal/commands/storage_run.go) so it returns onerrsonly, logs eachwarnviactx.GetLogger().WithError(w).Warn(...), then proceeds:- switch warns, errs := ctx.LoadTrustedCertificates(); { - case len(errs) != 0: - err = fmt.Errorf("had the following errors loading the trusted certificates") - - for _, e := range errs { - err = fmt.Errorf("%+v: %w", err, e) - } - - return err - case len(warns) != 0: - err = fmt.Errorf("had the following warnings loading the trusted certificates") - - for _, e := range warns { - err = fmt.Errorf("%+v: %w", err, e) - } - - return err - default: - ctx.providers.StorageProvider = getStorageProvider(ctx) - - return nil - } + warns, errs := ctx.LoadTrustedCertificates() + if len(errs) != 0 { + err = fmt.Errorf("had the following errors loading the trusted certificates") + for _, e := range errs { + err = fmt.Errorf("%+v: %w", err, e) + } + return err + } + for _, w := range warns { + ctx.GetLogger().WithError(w).Warn("warning loading trusted certificates") + } + ctx.providers.StorageProvider = getStorageProvider(ctx) + return nil
♻️ Duplicate comments (8)
internal/middlewares/authelia_context_blackbox_test.go (1)
780-783: Don’t compare fresh random.New() instances for equality. I pity the flaky test, fool!Instance-equality against random.New() will flake. Assert type/non-nil for default and identity for injected.
Apply this diff:
- if tc.have == nil { - assert.Equal(t, random.New(), middleware.GetRandom()) - } else { - assert.Equal(t, tc.have, middleware.GetRandom()) - } + got := middleware.GetRandom() + if tc.have == nil { + assert.NotNil(t, got) + // Ensure default is the cryptographic provider type. + assert.IsType(t, random.New(), got) + } else { + // When provided, we expect the exact same instance to be returned. + assert.Same(t, tc.have, got) + }Also applies to: 790-793, 796-800
internal/middlewares/authelia_context.go (1)
603-609: Lazy default Clock provider — now you’re cooking.Nil-guard + on-demand init prevents panics in tests/embeds. Matches prior guidance.
internal/handlers/handler_firstfactor_passkey_test.go (1)
717-717: Fix your time math, sucka!time.Second - 10 adds ~1s, not minus 10s. Use a negative duration.
Apply this diff:
- Return([]model.BannedIP{{ID: 1, Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Second - 10), Expires: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Minute), Valid: true}}}, nil), + Return([]model.BannedIP{{ID: 1, Time: mock.Ctx.Providers.Clock.Now().UTC().Add(-10 * time.Second), Expires: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Minute), Valid: true}}}, nil),internal/duo/duo.go (3)
32-32: Quit logging raw Duo bodies, fool — that’s PII!Don’t leak phone numbers/codes at trace.
- ctx.GetLogger().Tracef("Duo endpoint: %s response raw data for %s from IP %s: %s", path, userSession.Username, ctx.RemoteIP().String(), string(body)) + ctx.GetLogger().WithFields(map[string]any{ + "path": path, "username": userSession.Username, "remote_ip": ctx.RemoteIP().String(), "len": len(body), + }).Trace("Duo endpoint response received")
29-29: Wrap errors with context: path and user.Make failures actionable without spelunking logs.
- return nil, fmt.Errorf("error occurred making signed call: %w", err) + return nil, fmt.Errorf("duo signed call failed (path=%s user=%s): %w", path, userSession.Username, err) @@ - return nil, fmt.Errorf("error occurred parsing response: %w", err) + return nil, fmt.Errorf("duo response parse failed (path=%s user=%s): %w", path, userSession.Username, err)Also applies to: 35-35
44-67: Error messages too generic; include Duo stat/code, and fix whitespace lint.Give callers the stat/code/message; remove blank lines before returns to satisfy wsl_v5.
@@ - ctx.GetLogger(). - WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). - Trace("Duo Push Auth success response.") - - return &response, nil + ctx.GetLogger(). + WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). + Trace("Duo Push Auth success response.") + return &response, nil @@ - ctx.GetLogger(). - WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). - Warn("Duo Push Auth call returned a failure status code.") - - return &response, fmt.Errorf("failure status code was returned") + ctx.GetLogger(). + WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). + Warn("Duo Push Auth call returned a failure status code.") + return &response, fmt.Errorf("duo returned failure status code %d (%s): %s", response.Code, response.Stat, response.Message) @@ - ctx.GetLogger(). - WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). - Warn("Duo Push Auth call returned a failure status.") - - return &response, fmt.Errorf("failure status was returned") + ctx.GetLogger(). + WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). + Warn("Duo Push Auth call returned a failure status.") + return &response, fmt.Errorf("duo returned failure status (%s) code %d: %s", response.Stat, response.Code, response.Message) @@ - ctx.GetLogger(). - WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). - Warn("Duo Push API call returned an unknown status.") - - return &response, fmt.Errorf("unknown status was returned") + ctx.GetLogger(). + WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). + Warn("Duo Push API call returned an unknown status.") + return &response, fmt.Errorf("duo returned unknown status (%s) code %d: %s", response.Stat, response.Code, response.Message)internal/duo/duo_test.go (2)
433-444: Drop the unused hook, fool.No one reads the hook; keep the logger and move on.
-func NewTestCtx(ip net.IP) *TestCtx { - logger, hook := test.NewNullLogger() +func NewTestCtx(ip net.IP) *TestCtx { + logger, _ := test.NewNullLogger() @@ - hook: hook,
446-454: Prune dead field.Remove hook from TestCtx to appease linters.
type TestCtx struct { ip net.IP logger *logrus.Entry - hook *test.Hook - providers middlewares.Providers context.Context }
🧹 Nitpick comments (17)
internal/random/cryptographical.go (1)
10-14: Tighten GoDoc, fool — lose the blank line and clean the phrasing.Blank line breaks GoDoc association; wording/punctuation can be sharper.
-// New returns a new random provider, specifically and strictly a production ready variant which uses inbuilt -// system randomness (i.e solely crypto/rand and the *Cryptographical provider). - -func New() Provider { +// New returns a new random provider: a production-ready variant using built-in +// system randomness (i.e., solely crypto/rand and the Cryptographical provider). +func New() Provider { return &Cryptographical{} }internal/utils/types.go (1)
31-39: Exported types need GoDoc, foo.Add brief comments so linters and readers don’t get confused.
+// X509SystemCertPoolFactory abstracts obtaining the system x509 cert pool. type X509SystemCertPoolFactory interface { SystemCertPool() (pool *x509.CertPool, err error) } +// StandardX509SystemCertPoolFactory uses x509.SystemCertPool from the stdlib. type StandardX509SystemCertPoolFactory struct{} func (StandardX509SystemCertPoolFactory) SystemCertPool() (*x509.CertPool, error) { return x509.SystemCertPool() }internal/utils/crypto.go (1)
355-360: Wrap errors with %w so diagnosis don’t get beat, fool.Use %w for consistent cause wrapping; string output stays the same.
- warnings = append(warnings, fmt.Errorf("could not load system certificate pool which may result in untrusted certificate issues: %v", err)) + warnings = append(warnings, fmt.Errorf("could not load system certificate pool which may result in untrusted certificate issues: %w", err)) ... - errors = append(errors, fmt.Errorf("could not read certificates from directory %v", err)) + errors = append(errors, fmt.Errorf("could not read certificates from directory %w", err))Also applies to: 371-375
internal/utils/crypto_test.go (1)
26-33: Test reads fine; consider looser match to future-proof, sucka.Exact string match couples to wording. Match a stable substring instead.
- require.Len(t, errors, 1) - assert.EqualError(t, errors[0], "failed to create x509 cert pool as no factory was provided") + require.Len(t, errors, 1) + assert.ErrorContains(t, errors[0], "no factory was provided")internal/middlewares/authelia_context_blackbox_test.go (2)
844-849: Duplicate test case detected — trim the fat, fool.The "ShouldHandleBadObject" case appears twice back-to-back. Drop one to avoid confusion.
- { - "ShouldHandleBadObject", - []byte(`{"123": 123}`), - nil, - nil, - "unable to validate body: function only accepts structs; got map", - },
1265-1274: Ease up on brittle exact error strings, chump.Exact string matches can break across Go versions. Prefer ErrorContains for stability.
Example:
-assert.EqualError(t, ctx.RegenerateSession(), "unable to regenerate user session: unable to retrieve session cookie domain: missing required X-Forwarded-Host header") +assert.ErrorContains(t, ctx.RegenerateSession(), "unable to retrieve session cookie domain") +assert.ErrorContains(t, ctx.RegenerateSession(), "missing required X-Forwarded-Host header")Want me to sweep similar assertions here with a quick patch?
internal/middlewares/authelia_context.go (1)
603-618: Tiny concurrency nit: consider once-guard if ctx may be shared.If AutheliaCtx ever spans goroutines, wrap lazy in sync.Once to avoid racy double-inits. Low priority given per-request scope.
internal/commands/debug.go (1)
389-397: Guard against empty peer certs when suggesting config, fool.Indexing certs[0] assumes at least one cert. Add a quick length check to avoid panic on odd endpoints.
- certs := conn.ConnectionState().PeerCertificates + certs := conn.ConnectionState().PeerCertificates ... - c := struct { + c := struct { TLS schema.TLS `yaml:"tls"` }{ TLS: schema.TLS{ ServerName: conn.ConnectionState().ServerName, SkipVerify: false, MinimumVersion: schema.TLSVersion{Value: conn.ConnectionState().Version}, MaximumVersion: schema.TLSVersion{Value: tls.VersionTLS13}, }, } - if !validHostname && len(certs[0].DNSNames) != 0 { - c.TLS.ServerName = certs[0].DNSNames[0] - } else if validHostname && hostnameOverride != "" { + if len(certs) > 0 && !validHostname && len(certs[0].DNSNames) != 0 { + c.TLS.ServerName = certs[0].DNSNames[0] + } else if validHostname && hostnameOverride != "" { c.TLS.ServerName = hostnameOverride } ... - block := &pem.Block{ + if len(conn.ConnectionState().PeerCertificates) > 0 { + block := &pem.Block{ Type: utils.BlockTypeCertificate, Bytes: conn.ConnectionState().PeerCertificates[0].Raw, - } + } - if err = pem.Encode(w, block); err != nil { - _, _ = fmt.Fprintf(w, "Error writing certificate to stdout: %v\n", err) - } + if err = pem.Encode(w, block); err != nil { + _, _ = fmt.Fprintf(w, "Error writing certificate to stdout: %v\n", err) + } + }Also applies to: 408-414, 436-447, 466-474, 474-485
internal/handlers/handler_firstfactor_passkey.go (1)
310-346: Avoid double-setting RefreshTTL; compute now once to prevent skew.Set RefreshTTL once using a single now value; also pass that now into SetOneFactorPasskey. I pity the fool who lets clocks drift!
- if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { - userSession.RefreshTTL = ctx.GetClock().Now().Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) - } + // Compute 'now' once to avoid skew between fields. + now := ctx.GetClock().Now() @@ - userSession.SetOneFactorPasskey( - ctx.GetClock().Now(), details, + userSession.SetOneFactorPasskey( + now, details, keepMeLoggedIn, response.AuthenticatorAttachment == protocol.CrossPlatform, response.Response.AuthenticatorData.Flags.HasUserPresent(), response.Response.AuthenticatorData.Flags.HasUserVerified(), ) @@ - if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { - userSession.RefreshTTL = ctx.GetClock().Now().Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) - } + if ctx.Configuration.AuthenticationBackend.RefreshInterval.Update() { + userSession.RefreshTTL = now.Add(ctx.Configuration.AuthenticationBackend.RefreshInterval.Value()) + }internal/handlers/handler_firstfactor_passkey_test.go (1)
213-214: Standardize on the provider clock for determinism.Mixing time.Now() with mock clocks risks flakes. Prefer mock.Ctx.Providers.Clock.Now().
Example change (apply similarly across file):
- Expires: time.Now().Add(time.Minute), + Expires: mock.Ctx.Providers.Clock.Now().Add(time.Minute),Want me to sweep and patch all occurrences?
Also applies to: 304-306, 338-340, 443-445, 847-849, 951-953, 1251-1252, 1260-1261
internal/commands/storage_run_test.go (3)
11-15: Format your imports, sucker!golangci flagged goimports. Run goimports/gofmt to appease the linter.
Use:
goimports -w internal/commands/storage_run_test.go gofmt -s -w internal/commands/storage_run_test.go
51-52: Trim trailing whitespace/newline.Kill the lint noise.
- assert.Nil(t, ctx.providers.StorageProvider) - + assert.Nil(t, ctx.providers.StorageProvider)
31-31: Make error assertion resilient across OS/filesystems.Exact string with path/“permission denied” is brittle. Match the important bits.
- assert.EqualError(t, err, fmt.Sprintf("had the following errors loading the trusted certificates: could not read certificates from directory open %s: permission denied", filepath.Join(dir, "invalid"))) + assert.ErrorContains(t, err, "had the following errors loading the trusted certificates") + assert.ErrorContains(t, err, "could not read certificates from directory") + assert.ErrorContains(t, err, filepath.Join(dir, "invalid"))internal/duo/duo_test.go (1)
480-482: Return a non-nil config to avoid surprise panics.Safer default for future callers.
-func (t *TestCtx) GetConfiguration() (config *schema.Configuration) { - return nil -} +func (t *TestCtx) GetConfiguration() (config *schema.Configuration) { + cfg := &schema.Configuration{} + return cfg +}internal/commands/storage_run.go (3)
982-1013: Use a single computed expiry and print that exact value.Avoid two time.Now().Add() calls that can drift by milliseconds; compute once and reuse for message consistency.
Apply:
- if !permanent { - ban.Expires = sql.NullTime{Valid: true, Time: time.Now().Add(duration)} - } + if !permanent { + expiry := time.Now().Add(duration) + ban.Expires = sql.NullTime{Valid: true, Time: expiry} + } @@ - } else { - _, _ = fmt.Fprintf(w, "Successfully banned IP '%s' until '%s'.\n", ban.IP, time.Now().Add(duration).Format(time.RFC3339)) - } + } else { + _, _ = fmt.Fprintf(w, "Successfully banned IP '%s' until '%s'.\n", ban.IP, ban.Expires.Time.Format(time.RFC3339)) + }
1768-1772: Guard RNG: fall back if ctx.GetRandom() is nil.If any ServiceContext impl ever returns nil, dir gen will panic. Add a safe fallback.
Apply:
func runStorageUserTOTPExportPNG(ctx middlewares.ServiceContext, w io.Writer, store storage.Provider, dir string) (err error) { if dir == "" { - rand := ctx.GetRandom() + rand := ctx.GetRandom() + if rand == nil { + rand = random.New() + } dir = rand.StringCustom(8, random.CharSetAlphaNumeric) }
1825-1825: Nit: pluralize message.Say “configurations” for correct grammar.
Apply:
- _, _ = fmt.Fprintf(w, "Successfully exported %d TOTP configuration as QR codes in PNG format to the '%s' directory\n", count, dir) + _, _ = fmt.Fprintf(w, "Successfully exported %d TOTP configurations as QR codes in PNG format to the '%s' directory\n", count, dir)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
internal/configuration/test_resources/userdb/debug-tests.ymlis excluded by!**/*.yml
📒 Files selected for processing (84)
cmd/authelia-gen/openid_conformance.go(1 hunks)cmd/authelia/main.go(1 hunks)experimental/embed/context.go(3 hunks)experimental/embed/provider/general.go(1 hunks)internal/clock/fixed.go(2 hunks)internal/clock/provider.go(1 hunks)internal/clock/real.go(2 hunks)internal/commands/acl_test.go(4 hunks)internal/commands/build_info.go(2 hunks)internal/commands/build_info_test.go(3 hunks)internal/commands/context.go(8 hunks)internal/commands/context_test.go(1 hunks)internal/commands/crypto.go(6 hunks)internal/commands/crypto_hash.go(6 hunks)internal/commands/crypto_test.go(1 hunks)internal/commands/debug.go(13 hunks)internal/commands/debug_test.go(1 hunks)internal/commands/errors.go(1 hunks)internal/commands/storage_run.go(9 hunks)internal/commands/storage_run_test.go(1 hunks)internal/commands/util.go(2 hunks)internal/commands/util_test.go(2 hunks)internal/duo/duo.go(2 hunks)internal/duo/duo_test.go(2 hunks)internal/duo/types.go(2 hunks)internal/handlers/func_test.go(1 hunks)internal/handlers/handler_authz_authn.go(5 hunks)internal/handlers/handler_authz_test.go(16 hunks)internal/handlers/handler_firstfactor_passkey.go(3 hunks)internal/handlers/handler_firstfactor_passkey_test.go(26 hunks)internal/handlers/handler_firstfactor_password.go(2 hunks)internal/handlers/handler_firstfactor_password_test.go(2 hunks)internal/handlers/handler_oauth2_authorization.go(1 hunks)internal/handlers/handler_oauth2_authorization_claims.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core_test.go(10 hunks)internal/handlers/handler_oauth2_authorization_consent_explicit.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_implicit.go(3 hunks)internal/handlers/handler_oauth2_authorization_consent_preconfigured.go(5 hunks)internal/handlers/handler_oauth2_consent.go(6 hunks)internal/handlers/handler_oauth2_device_authorization.go(1 hunks)internal/handlers/handler_oauth2_introspection.go(1 hunks)internal/handlers/handler_oauth2_oidc_userinfo.go(2 hunks)internal/handlers/handler_oauth2_oidc_wellknown.go(1 hunks)internal/handlers/handler_oauth2_token.go(1 hunks)internal/handlers/handler_oauth2_wellknown.go(1 hunks)internal/handlers/handler_register_totp.go(3 hunks)internal/handlers/handler_register_totp_test.go(3 hunks)internal/handlers/handler_reset_password.go(1 hunks)internal/handlers/handler_session_elevation.go(3 hunks)internal/handlers/handler_session_elevation_test.go(4 hunks)internal/handlers/handler_sign_duo.go(1 hunks)internal/handlers/handler_sign_password.go(1 hunks)internal/handlers/handler_sign_password_test.go(1 hunks)internal/handlers/handler_sign_totp.go(2 hunks)internal/handlers/handler_sign_totp_test.go(2 hunks)internal/handlers/handler_sign_webauthn.go(2 hunks)internal/middlewares/authelia_context.go(1 hunks)internal/middlewares/authelia_context_blackbox_test.go(15 hunks)internal/middlewares/identity_verification.go(1 hunks)internal/middlewares/require_auth_test.go(1 hunks)internal/middlewares/startup.go(2 hunks)internal/middlewares/timing_attack_delay_test.go(2 hunks)internal/middlewares/types.go(2 hunks)internal/middlewares/util.go(2 hunks)internal/mocks/authelia_context.go(2 hunks)internal/mocks/duo_api.go(3 hunks)internal/model/webauthn_test.go(1 hunks)internal/notification/smtp_notifier.go(1 hunks)internal/oidc/types.go(1 hunks)internal/oidc/types_test.go(1 hunks)internal/random/cryptographical.go(1 hunks)internal/regulation/regulator_blackbox_test.go(2 hunks)internal/server/server_test.go(1 hunks)internal/service/file_watcher_test.go(2 hunks)internal/service/sever_test.go(4 hunks)internal/service/signal_test.go(2 hunks)internal/suites/example/compose/duo-api/duo_api.js(3 hunks)internal/totp/totp_test.go(3 hunks)internal/utils/const_test.go(1 hunks)internal/utils/crypto.go(2 hunks)internal/utils/crypto_test.go(1 hunks)internal/utils/exec.go(0 hunks)internal/utils/types.go(2 hunks)
💤 Files with no reviewable changes (1)
- internal/utils/exec.go
🚧 Files skipped from review as they are similar to previous changes (62)
- internal/mocks/authelia_context.go
- internal/handlers/handler_oauth2_wellknown.go
- internal/server/server_test.go
- internal/clock/real.go
- internal/handlers/handler_reset_password.go
- internal/handlers/handler_authz_test.go
- internal/commands/errors.go
- internal/middlewares/timing_attack_delay_test.go
- internal/handlers/handler_sign_totp.go
- internal/handlers/handler_register_totp.go
- internal/handlers/handler_sign_webauthn.go
- internal/notification/smtp_notifier.go
- internal/handlers/handler_sign_duo.go
- internal/middlewares/identity_verification.go
- internal/handlers/handler_session_elevation_test.go
- internal/oidc/types.go
- internal/handlers/handler_oauth2_token.go
- internal/handlers/handler_oauth2_oidc_userinfo.go
- internal/handlers/handler_authz_authn.go
- internal/handlers/handler_oauth2_introspection.go
- internal/handlers/handler_sign_totp_test.go
- internal/middlewares/types.go
- internal/model/webauthn_test.go
- internal/suites/example/compose/duo-api/duo_api.js
- cmd/authelia/main.go
- internal/commands/crypto_hash.go
- internal/service/file_watcher_test.go
- internal/clock/provider.go
- internal/handlers/handler_oauth2_authorization_consent_core.go
- internal/handlers/handler_sign_password.go
- internal/handlers/handler_firstfactor_password.go
- internal/commands/context_test.go
- experimental/embed/provider/general.go
- internal/commands/debug_test.go
- cmd/authelia-gen/openid_conformance.go
- internal/handlers/handler_oauth2_authorization_consent_explicit.go
- internal/utils/const_test.go
- internal/commands/util.go
- internal/handlers/handler_oauth2_consent.go
- internal/oidc/types_test.go
- internal/commands/crypto_test.go
- internal/handlers/handler_oauth2_authorization_consent_core_test.go
- internal/duo/types.go
- internal/handlers/handler_session_elevation.go
- internal/handlers/handler_register_totp_test.go
- internal/regulation/regulator_blackbox_test.go
- internal/service/sever_test.go
- internal/service/signal_test.go
- internal/middlewares/startup.go
- internal/mocks/duo_api.go
- internal/commands/context.go
- internal/handlers/handler_oauth2_authorization_consent_preconfigured.go
- internal/commands/acl_test.go
- experimental/embed/context.go
- internal/totp/totp_test.go
- internal/commands/build_info.go
- internal/commands/build_info_test.go
- internal/handlers/handler_oauth2_oidc_wellknown.go
- internal/handlers/handler_oauth2_device_authorization.go
- internal/middlewares/util.go
- internal/commands/crypto.go
- internal/handlers/handler_firstfactor_password_test.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-29T10:47:45.888Z
Learnt from: james-d-elliott
PR: authelia/authelia#10189
File: internal/clock/provider.go:14-15
Timestamp: 2025-08-29T10:47:45.888Z
Learning: The internal/mocks directory does not contain any mock clock implementations. Tests use concrete clock instances like clock.New(), clock.NewFixed(), and direct assignment to mock.Ctx.Providers.Clock instead of generated mocks for the clock.Provider interface.
Applied to files:
internal/handlers/handler_sign_password_test.gointernal/middlewares/require_auth_test.gointernal/handlers/handler_firstfactor_passkey_test.go
📚 Learning: 2025-08-27T21:37:17.083Z
Learnt from: james-d-elliott
PR: authelia/authelia#10059
File: internal/commands/storage_run.go:23-23
Timestamp: 2025-08-27T21:37:17.083Z
Learning: The Authelia project uses "go.yaml.in/yaml/v4" as their YAML package import path, not the standard "gopkg.in/yaml.v3" or "gopkg.in/yaml.v2". This is used consistently across their codebase.
Applied to files:
internal/commands/storage_run.go
🧬 Code graph analysis (14)
internal/commands/storage_run_test.go (5)
internal/commands/context.go (2)
NewCmdCtx(29-38)NewCmdCtxConfig(56-61)internal/commands/util_test.go (1)
TestX509SystemCertPoolFactory(16-19)internal/configuration/schema/storage.go (2)
Storage(10-16)StorageLocal(19-21)internal/storage/sql_provider.go (1)
NewProvider(24-35)internal/model/types.go (1)
StartupCheck(168-170)
internal/utils/crypto_test.go (1)
internal/utils/crypto.go (1)
NewX509CertPoolWithFactory(350-398)
internal/duo/duo_test.go (3)
internal/duo/types.go (6)
BaseProvider(15-17)Response(43-49)PreAuthResponse(60-68)Device(32-40)AuthResponse(52-57)Provider(20-24)internal/session/types.go (1)
UserSession(20-48)internal/middlewares/types.go (2)
Context(60-69)Providers(40-58)
internal/handlers/handler_oauth2_authorization_consent_implicit.go (1)
internal/oidc/session.go (1)
ConsentGrantImplicit(212-217)
internal/handlers/handler_sign_password_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/handlers/handler_oauth2_authorization.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/oidc/session.go (1)
NewSessionWithRequestedAt(22-38)
internal/middlewares/authelia_context.go (5)
internal/middlewares/types.go (2)
AutheliaCtx(29-37)Providers(40-58)internal/clock/provider.go (1)
Provider(10-15)experimental/embed/context.go (1)
New(18-61)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)
internal/middlewares/authelia_context_blackbox_test.go (8)
internal/middlewares/authelia_context.go (1)
NewAutheliaCtx(43-51)internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/mocks/authelia_context.go (1)
NewMockAutheliaCtx(47-239)internal/handlers/types.go (1)
StateResponse(200-205)internal/middlewares/const.go (1)
ContentTypeApplicationJSON(116-116)internal/middlewares/types.go (1)
Providers(40-58)internal/expression/user_attributes.go (1)
NewUserAttributes(13-24)internal/metrics/prometheus.go (1)
NewPrometheus(12-18)
internal/duo/duo.go (4)
internal/duo/types.go (4)
Production(27-29)Response(43-49)PreAuthResponse(60-68)AuthResponse(52-57)experimental/embed/context.go (1)
Context(65-74)internal/middlewares/types.go (1)
Context(60-69)internal/session/types.go (1)
UserSession(20-48)
internal/middlewares/require_auth_test.go (1)
internal/middlewares/types.go (1)
Providers(40-58)
internal/commands/debug.go (7)
internal/middlewares/util.go (1)
NewAuthenticationProvider(84-93)internal/expression/user_attributes.go (1)
NewUserAttributes(13-24)internal/oidc/claims.go (1)
NewCustomClaimsStrategy(444-506)internal/commands/context.go (1)
CmdCtx(41-53)internal/configuration/schema/types_address.go (1)
NewAddress(16-18)internal/utils/crypto.go (1)
IsInsecureCipherSuite(745-753)internal/utils/const.go (1)
BlockTypeCertificate(32-32)
internal/handlers/handler_firstfactor_passkey_test.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/model/regulation.go (3)
BannedUser(26-35)AuthenticationAttempt(9-19)BannedIP(37-46)
internal/utils/crypto.go (1)
internal/utils/types.go (3)
StandardX509SystemCertPoolFactory(35-35)StandardX509SystemCertPoolFactory(37-39)X509SystemCertPoolFactory(31-33)
internal/commands/storage_run.go (3)
internal/middlewares/types.go (2)
Context(60-69)ServiceContext(71-79)internal/storage/provider.go (1)
Provider(15-328)internal/totp/provider.go (1)
Provider(8-13)
🪛 GitHub Check: golangci
internal/commands/storage_run_test.go
[failure] 11-11: [golangci] internal/commands/storage_run_test.go#L11
File is not properly formatted (goimports)
[failure] 52-52: [golangci] internal/commands/storage_run_test.go#L52
unnecessary trailing newline (whitespace)
[failure] 51-51: [golangci] internal/commands/storage_run_test.go#L51
unnecessary whitespace (trailing-whitespace) (wsl_v5)
⏰ 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). (2)
- GitHub Check: Analyze (go)
- GitHub Check: StepSecurity Harden-Runner
🔇 Additional comments (26)
internal/clock/fixed.go (1)
24-27: JWT time option hook looks solid, sucka.Correctly wires jwt.WithTimeFunc to Fixed.Now. Ship it.
internal/utils/crypto.go (2)
343-347: Factory default helper reads clean.Delegation to the standard factory is tidy and backwards-compatible. Nice.
348-354: Nil-factory guard is righteous.Early return with explicit error keeps fools from passing nil.
internal/middlewares/authelia_context_blackbox_test.go (2)
338-339: Solid switch to NewProvidersBasic across tests, sucka.Consistent provider wiring makes these tests cleaner and future-proof.
Also applies to: 409-410, 490-491, 563-564, 638-639, 689-690, 748-751, 1086-1086
1240-1263: JSON reply tests look tight.Good negative/positive coverage for ReplyJSON and SetJSONBody.
internal/middlewares/authelia_context.go (2)
612-618: Random provider lazy-init mirrors Clock — thumbs up.Sane cryptographic default without forcing callers to wire it.
626-630: Return a copy of Configuration — smart move, fool.Prevents accidental mutation of request-scoped config.
internal/handlers/handler_sign_password_test.go (1)
39-41: Clock injection via Providers: that’s the way, fool.Fixes the direct ctx.Clock assignment pattern and aligns with the new provider model.
internal/middlewares/require_auth_test.go (1)
203-205: Providers.Clock wiring LGTM.Keeps elevation timing deterministic without touching ctx internals.
internal/commands/debug.go (2)
133-139: Clean separation with run helpers and writer injection — respect.*Decoupling logic from cobra handlers and routing output via io.Writer improves testability and UX.
Also applies to: 240-246, 287-293
220-235: Nice touch on human-readable output and hints.The formatting and validation hints are clear and actionable.
Also applies to: 344-354, 389-397
internal/handlers/handler_oauth2_authorization.go (2)
236-236: Clock provider swap is correct.Passing ctx.GetClock().Now() into oidc.NewSessionWithRequestedAt is consistent with the provider-based clock and the session constructor normalizes to UTC. I pity the fool who hard-codes time!
236-236: Replace all direct time.Now() calls in production code
Found direct time.Now() usages in production files (e.g. internal/oidc/session.go:16, internal/storage/sql_provider.go:141, internal/middlewares/rate_limiting.go:70). Replace each with the context clock (ctx.GetClock().Now() or ctx.Providers.Clock.Now()) to complete the migration.⛔ Skipped due to learnings
Learnt from: james-d-elliott PR: authelia/authelia#10189 File: internal/clock/provider.go:14-15 Timestamp: 2025-08-29T10:47:45.888Z Learning: The internal/mocks directory does not contain any mock clock implementations. Tests use concrete clock instances like clock.New(), clock.NewFixed(), and direct assignment to mock.Ctx.Providers.Clock instead of generated mocks for the clock.Provider interface.internal/handlers/func_test.go (1)
75-75: Nice: test now uses provider clock.This aligns tests with the injectable clock. I pity the fool who fights flaky time!
internal/handlers/handler_oauth2_authorization_claims.go (1)
63-63: GetClock() migration looks solid.HydrateIDTokenClaims now receives the provider time; matches the refactor. I pity the fool who mixes time sources.
internal/commands/util_test.go (1)
16-23: Test factory is clean and matches the interface.Simple, deterministic cert pool injection for tests. I pity the fool who mocks the system pool the hard way.
internal/handlers/handler_firstfactor_passkey.go (1)
223-223: All GetClock() swaps are correct.UTC applied where needed; consistent provider usage elsewhere. I pity the fool who time-travels without a provider.
Also applies to: 311-312, 337-337, 345-345
internal/handlers/handler_oauth2_authorization_consent_implicit.go (3)
79-85: LGTM, fool! Clock check wired right.Switch to ctx.GetClock().Now() fixes testability and keeps time injection consistent.
89-93: Solid move using injected clock for ConsentGrantImplicit.Passing ctx.GetClock().Now() keeps consent timestamps deterministic under tests.
Also applies to: 148-152
1-164: Sweep complete—only test uses direct ctx.Clock, sucka! Only occurrence is in internal/oidc/types_test.go for fixed‐time injection in tests. No handlers call ctx.Clock directly.internal/duo/duo_test.go (1)
1-487: Verify hook removal leftovers and run go vet
– No references toTestCtx.hookininternal/duo/duo_test.go(rg found nothing).
– I pity the fool who skips runninggo vet ./…locally to catch any vet issues.internal/commands/storage_run.go (5)
23-31: LGTM: imports and YAML path are on-point, fool.pflag and middlewares imports make sense, and you kept go.yaml.in/yaml/v4 consistent with the project’s choice. I pity the fool who mixes YAML packages.
149-161: LGTM: extracted cache delete helper keeps output consistent.Good reuse and cleaner RunE. I pity the fool who duplicates I/O messaging.
708-721: LGTM: centralized bans-list dispatcher.Clear routing to IP/User paths. Tight and readable.
821-843: LGTM: bans-revoke flag/arg extraction and dispatch look solid.Early parse + simple switch is clean. Rock on.
1422-1439: LGTM: TOTP generation now uses ctx clock/RNG—testable and deterministic, fool.Nice move wiring ServiceContext and totp.NewContext with ctx providers.
| func runStorageBansAdd(ctx context.Context, w io.Writer, flags *pflag.FlagSet, args []string, store storage.Provider, use string) (err error) { | ||
| var ( | ||
| permanent bool | ||
| reason, durationStr string | ||
| ) | ||
|
|
||
| if reason, err = cmd.Flags().GetString("reason"); err != nil { | ||
| return err | ||
| } | ||
| if permanent, err = flags.GetBool("permanent"); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if durationStr, err = cmd.Flags().GetString("duration"); err != nil { | ||
| return err | ||
| } | ||
| if reason, err = flags.GetString("reason"); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| duration, err := utils.ParseDurationString(durationStr) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to parse duration string: %w", err) | ||
| } | ||
| if durationStr, err = flags.GetString("duration"); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if duration <= 0 { | ||
| return fmt.Errorf("duration must be a positive value") | ||
| } | ||
| duration, err := utils.ParseDurationString(durationStr) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to parse duration string: %w", err) | ||
| } | ||
|
|
||
| target := args[0] | ||
| if duration <= 0 { | ||
| return fmt.Errorf("duration must be a positive value") | ||
| } | ||
|
|
||
| switch use { | ||
| case cmdUseIP: | ||
| return runStorageBansAddIP(ctx, cmd.OutOrStdout(), ctx.providers.StorageProvider, target, reason, duration, permanent) | ||
| case cmdUseUser: | ||
| return runStorageBansAddUser(ctx, cmd.OutOrStdout(), ctx.providers.StorageProvider, target, reason, duration, permanent) | ||
| default: | ||
| return fmt.Errorf("unknown command %q", use) | ||
| } | ||
| target := args[0] | ||
|
|
||
| switch use { | ||
| case cmdUseIP: | ||
| return runStorageBansAddIP(ctx, w, store, target, reason, duration, permanent) | ||
| case cmdUseUser: | ||
| return runStorageBansAddUser(ctx, w, store, target, reason, duration, permanent) | ||
| default: | ||
| return fmt.Errorf("unknown command %q", use) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix panic when args are empty and align permanent/duration semantics, sucka.
- args[0] is used without a length check (Line 970) ⇒ index panic.
- You require a positive duration even when --permanent is set. Permanent bans shouldn’t need duration.
Apply:
func runStorageBansAdd(ctx context.Context, w io.Writer, flags *pflag.FlagSet, args []string, store storage.Provider, use string) (err error) {
var (
permanent bool
reason, durationStr string
)
if permanent, err = flags.GetBool("permanent"); err != nil {
return err
}
if reason, err = flags.GetString("reason"); err != nil {
return err
}
if durationStr, err = flags.GetString("duration"); err != nil {
return err
}
- duration, err := utils.ParseDurationString(durationStr)
- if err != nil {
- return fmt.Errorf("failed to parse duration string: %w", err)
- }
- if duration <= 0 {
- return fmt.Errorf("duration must be a positive value")
- }
-
- target := args[0]
+ if len(args) == 0 || strings.TrimSpace(args[0]) == "" {
+ want := map[string]string{cmdUseIP: "IP address", cmdUseUser: "username"}[use]
+ if want == "" {
+ want = "target"
+ }
+ return fmt.Errorf("%s is required", want)
+ }
+ target := args[0]
+
+ var duration time.Duration
+ if !permanent {
+ if duration, err = utils.ParseDurationString(durationStr); err != nil {
+ return fmt.Errorf("failed to parse duration string: %w", err)
+ }
+ if duration <= 0 {
+ return fmt.Errorf("duration must be a positive value")
+ }
+ } else {
+ duration = 0
+ }
switch use {
case cmdUseIP:
return runStorageBansAddIP(ctx, w, store, target, reason, duration, permanent)
case cmdUseUser:
return runStorageBansAddUser(ctx, w, store, target, reason, duration, permanent)
default:
return fmt.Errorf("unknown command %q", use)
}
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In internal/commands/storage_run.go around lines 943 to 980, the function reads
args[0] and enforces a positive duration even when --permanent is set; add a
guard to return a clear error if args is empty before accessing args[0], and
change the duration validation so that when permanent==true the duration is not
required/validated (ignore any provided duration or accept zero/negative as
irrelevant); ensure you still parse duration only when not permanent (or treat
empty/zero as valid for permanent) and then call the appropriate
runStorageBansAddIP/runStorageBansAddUser with the resolved duration and
permanent flag.
33fbc86 to
bad0f39
Compare
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
internal/commands/crypto.go (2)
318-328: Fix directory permissions handling; enforce mode reliablyThis MkdirAll + IsExist branch won’t run as intended; MkdirAll returns nil if the dir exists. You also never enforce dmode on existing dirs. For secrets, that’s risky, fool.
Use MkdirAll then Chmod to ensure the desired permissions regardless of umask/existing state:
- if dir != "" { - if err = os.MkdirAll(dir, dmode); err != nil { - if !os.IsExist(err) { - return fmt.Errorf("error making directory for file '%s': %w", name, err) - } else if info, err = os.Stat(dir); err == nil { - if info.Mode().Perm() != dmode { - return fmt.Errorf("error making directory for file '%s': directory '%s' already exists with wrong permissions: %v", name, dir, info.Mode().Perm()) - } - } - } - } + if dir != "" { + if err = os.MkdirAll(dir, dmode); err != nil { + return fmt.Errorf("error making directory for file '%s': %w", name, err) + } + // Enforce final permissions (umask may have interfered). + if err = os.Chmod(dir, dmode); err != nil { + return fmt.Errorf("error setting permissions on directory '%s': %w", dir, err) + } + }Optionally mirror this for files: after OpenFile, call file.Chmod(fmode) to force exact perms.
641-641: Fix RSA algorithm label: bytes vs bits mismatchYou’re printing “RSA-%d %d bits” using Size() (bytes) and BitLen() (bits). That’s confusing, fool. Use bits once.
Apply this correction:
- b.WriteString(fmt.Sprintf("\tAlgorithm: RSA-%d %d bits\n\n", k.Size(), k.N.BitLen())) + b.WriteString(fmt.Sprintf("\tAlgorithm: RSA-%d bits\n\n", k.N.BitLen()))internal/utils/crypto.go (1)
349-397: Don’t trust a nil system pool; include paths in errors, sucka!
- If factory.SystemCertPool() returns (nil, nil) you’ll deref a nil pool later. Fallback to x509.NewCertPool() and warn.
- Include the directory/cert path in error messages for triage.
Apply:
func NewX509CertPoolWithFactory(directory string, factory X509SystemCertPoolFactory) (certPool *x509.CertPool, warnings []error, errors []error) { @@ - if certPool, err = factory.SystemCertPool(); err != nil { + if certPool, err = factory.SystemCertPool(); err != nil { warnings = append(warnings, fmt.Errorf("could not load system certificate pool which may result in untrusted certificate issues: %v", err)) certPool = x509.NewCertPool() - } + } else if certPool == nil { + warnings = append(warnings, fmt.Errorf("system certificate pool factory returned a nil pool; using empty pool")) + certPool = x509.NewCertPool() + } @@ - if entries, err = os.ReadDir(directory); err != nil { - errors = append(errors, fmt.Errorf("could not read certificates from directory %v", err)) + if entries, err = os.ReadDir(directory); err != nil { + errors = append(errors, fmt.Errorf("could not read certificates from directory '%s': %w", directory, err)) return certPool, warnings, errors } @@ - if data, err = os.ReadFile(certPath); err != nil { - errors = append(errors, fmt.Errorf("error occurred trying to read certificate: %w", err)) + if data, err = os.ReadFile(certPath); err != nil { + errors = append(errors, fmt.Errorf("error occurred trying to read certificate '%s': %w", certPath, err))internal/commands/storage_run.go (1)
1768-1828: Harden PNG export: nil RNG fallback and path-safe filenames, fool!
- ctx.GetRandom() might be nil from custom contexts.
- Username in filename can contain path separators; sanitize to prevent traversal/FS errors.
- Minor: pluralize success message.
Apply:
func runStorageUserTOTPExportPNG(ctx middlewares.ServiceContext, w io.Writer, store storage.Provider, dir string) (err error) { if dir == "" { - rand := ctx.GetRandom() - dir = rand.StringCustom(8, random.CharSetAlphaNumeric) + rnd := ctx.GetRandom() + if rnd == nil { + rnd = random.New() + } + dir = rnd.StringCustom(8, random.CharSetAlphaNumeric) } @@ - if file, err = os.Create(filepath.Join(dir, fmt.Sprintf("%s.png", c.Username))); err != nil { + safe := strings.NewReplacer("/", "_", "\\", "_", ":", "_").Replace(c.Username) + if file, err = os.Create(filepath.Join(dir, fmt.Sprintf("%s.png", safe))); err != nil { return err } @@ - _, _ = fmt.Fprintf(w, "Successfully exported %d TOTP configuration as QR codes in PNG format to the '%s' directory\n", count, dir) + _, _ = fmt.Fprintf(w, "Successfully exported %d TOTP configurations as QR codes in PNG format to the '%s' directory\n", count, dir)
♻️ Duplicate comments (9)
internal/commands/acl_test.go (3)
41-47: Stop matching exact error strings; assert substrings, fool.Cobra/pflag and Go versions tweak error phrasing. Make cases resilient by expecting substrings (e.g., just "url", "method", etc.) instead of full messages.
Apply this to loosen expectations:
@@ - err: "flag accessed but not defined: url", + err: "url", @@ - err: "parse \"http://%@#(*$@()#*&$invalid\": invalid character \"#\" in host name", + err: "invalid", @@ - err: "flag accessed but not defined: method", + err: "method", @@ - err: "flag accessed but not defined: username", + err: "username", @@ - err: "flag accessed but not defined: groups", + err: "groups", @@ - err: "flag accessed but not defined: ip", + err: "ip",Also applies to: 49-57, 59-66, 67-73, 75-81, 83-89
103-107: Good parallel subtests pattern and capture.tc := tc plus t.Parallel with a spacer keeps races at bay and the linter happy. I pity the fool who forgets the blank line.
147-151: Use ErrorContains over EqualError. Don’t marry exact text, sucker.Prevents brittle failures across versions.
- if tc.err == "" { - assert.NoError(t, err) - } else { - assert.EqualError(t, err, tc.err) - } + if tc.err == "" { + assert.NoError(t, err) + } else { + assert.ErrorContains(t, err, tc.err) + }internal/handlers/handler_firstfactor_passkey_test.go (1)
717-717: Fix the bad duration, fool!time.Second - 10ain’t -10s.Use a negative duration so the ban time is actually 10 seconds ago.
Apply this diff:
- Return([]model.BannedIP{{ID: 1, Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Second - 10), Expires: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Minute), Valid: true}}}, nil), + Return([]model.BannedIP{{ID: 1, Time: mock.Ctx.Providers.Clock.Now().UTC().Add(-10 * time.Second), Expires: sql.NullTime{Time: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Minute), Valid: true}}}, nil),Run to smoke out any remaining slip-ups:
#!/bin/bash rg -nP '\.Add\(\s*time\.Second\s*-\s*\d+\s*\)' --glob '!**/vendor/**' -C2internal/middlewares/util.go (1)
38-39: Regulator wired to providers.Clock — deterministic at last.
This addresses the earlier concern about stray clocks. Good hustle.Also applies to: 44-45
internal/duo/duo.go (2)
28-36: Stop spillin’ PII and add context to errors, fool!
- Don’t log raw Duo bodies; log safe metadata.
- Wrap errors with path/user.
Apply:
- if _, body, err = d.SignedCall(method, path, values); err != nil { - return nil, fmt.Errorf("error occurred making signed call: %w", err) - } + if _, body, err = d.SignedCall(method, path, values); err != nil { + return nil, fmt.Errorf("duo signed call failed (path=%s user=%s): %w", path, userSession.Username, err) + } @@ - ctx.GetLogger().Tracef("Duo endpoint: %s response raw data for %s from IP %s: %s", path, userSession.Username, ctx.RemoteIP().String(), string(body)) + ctx.GetLogger().WithFields(map[string]any{ + "path": path, "username": userSession.Username, "remote_ip": ctx.RemoteIP().String(), "bytes": len(body), + }).Trace("Duo endpoint response received") @@ - if err = json.Unmarshal(body, &response); err != nil { - return nil, fmt.Errorf("error occurred parsing response: %w", err) - } + if err = json.Unmarshal(body, &response); err != nil { + return nil, fmt.Errorf("duo response parse failed (path=%s user=%s): %w", path, userSession.Username, err) + }
38-67: Return actionable Duo errors and fix whitespace-before-return, sucka!
- Include stat/code/message in returned errors.
- Remove blank lines immediately before return (wsl_v5).
Apply:
case "OK": switch response.Code { case fasthttp.StatusOK, fasthttp.StatusNotFound: ctx.GetLogger(). WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). Trace("Duo Push Auth success response.") - return &response, nil default: ctx.GetLogger(). WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). Warn("Duo Push Auth call returned a failure status code.") - - return &response, fmt.Errorf("failure status code was returned") + return &response, fmt.Errorf("duo returned failure status code %d (%s): %s", response.Code, response.Stat, response.Message) } case "FAIL": ctx.GetLogger(). WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). Warn("Duo Push Auth call returned a failure status.") - - return &response, fmt.Errorf("failure status was returned") + return &response, fmt.Errorf("duo returned failure status (%s) code %d: %s", response.Stat, response.Code, response.Message) default: ctx.GetLogger(). WithFields(map[string]any{"status": response.Stat, "status_code": response.Code, "message": response.Message, "message_detail": response.MessageDetail, "username": userSession.Username}). Warn("Duo Push API call returned an unknown status.") - - return &response, fmt.Errorf("unknown status was returned") + return &response, fmt.Errorf("duo returned unknown status (%s) code %d: %s", response.Stat, response.Code, response.Message)internal/commands/storage_run.go (1)
943-980: Fix crash on missing args and permanent-ban semantics, fool!
- args[0] can panic when empty.
- Permanent bans shouldn’t require a positive duration.
Apply:
func runStorageBansAdd(ctx context.Context, w io.Writer, flags *pflag.FlagSet, args []string, store storage.Provider, use string) (err error) { @@ - duration, err := utils.ParseDurationString(durationStr) - if err != nil { - return fmt.Errorf("failed to parse duration string: %w", err) - } - - if duration <= 0 { - return fmt.Errorf("duration must be a positive value") - } - - target := args[0] + if len(args) == 0 || strings.TrimSpace(args[0]) == "" { + want := map[string]string{cmdUseIP: "IP address", cmdUseUser: "username"}[use] + if want == "" { + want = "target" + } + return fmt.Errorf("%s is required", want) + } + target := args[0] + + var duration time.Duration + if permanent { + duration = 0 + } else { + if duration, err = utils.ParseDurationString(durationStr); err != nil { + return fmt.Errorf("failed to parse duration string: %w", err) + } + if duration <= 0 { + return fmt.Errorf("duration must be a positive value") + } + }internal/middlewares/authelia_context_blackbox_test.go (1)
796-800: Don’t compare fresh random.New() instances; assert type/identity instead, fool.Equality vs a new instance is brittle or wrong. Check type when defaulted, and identity when provided.
Apply this diff:
- if tc.have == nil { - assert.Equal(t, random.New(), middleware.GetRandom()) - } else { - assert.Equal(t, tc.have, middleware.GetRandom()) - } + got := middleware.GetRandom() + if tc.have == nil { + assert.NotNil(t, got) + // Ensure default is the cryptographic provider type. + assert.IsType(t, random.New(), got) + } else { + // When provided, we expect the exact same instance to be returned. + assert.Same(t, tc.have, got) + }
🧹 Nitpick comments (19)
internal/handlers/handler_oauth2_consent.go (5)
75-83: Drop redundant expiry check; rely on CanGrant().The earlier helper already blocks expired sessions via CanGrant(now). This duplicate check adds noise and divergent log text. I pity the fool who keeps two sources of truth!
Apply this diff:
- if consent.ExpiresAt.Before(ctx.GetClock().Now()) { - ctx.Logger. - WithFields(map[string]any{logging.FieldClientID: consent.ClientID, logging.FieldSessionID: consent.ID, logging.FieldFlowID: consent.ChallengeID.String(), logging.FieldUsername: userSession.Username, logging.FieldExpiration: consent.ExpiresAt.Unix()}). - Error("Failed providing consent flow information as the consent session is expired") - - ctx.SetJSONError(messageOperationFailed) - - return - } + // Expiry is validated in handleOAuth2ConsentGetSessionsAndClient via CanGrant(now).
300-302: Capture now once for deterministic timestamps.Use a single now for CreatedAt and ExpiresAt to avoid test flakes and micro-skew. I pity the fool who chases nondeterministic tests.
Apply this diff:
- CreatedAt: ctx.GetClock().Now(), - ExpiresAt: sql.NullTime{Time: ctx.GetClock().Now().Add(client.GetConsentPolicy().Duration), Valid: true}, + CreatedAt: now, + ExpiresAt: sql.NullTime{Time: now.Add(client.GetConsentPolicy().Duration), Valid: true},And add this just before constructing config (outside selected lines):
now := ctx.GetClock().Now()
355-355: Reuse the same timestamp for RespondedAt.Set RespondedAt with the same now captured in this handler to keep events coherent in logs.
Apply this diff:
- consent.SetRespondedAt(ctx.GetClock().Now(), 0) + consent.SetRespondedAt(now, 0)Add or reuse:
now := ctx.GetClock().Now()near the top of handleOAuth2ConsentFlowIDPOST.
545-545: Avoid magic 10s; extract to const and reuse now.Make the skew a named constant and compute from a single now. Cleaner and easier to tune.
Apply this diff:
- if consent, err = model.NewOAuth2ConsentSession(ctx.GetClock().Now().Add(10*time.Second), subject, r); err != nil { + if consent, err = model.NewOAuth2ConsentSession(now.Add(oauth2ConsentCreationSkew), subject, r); err != nil {Support code (outside selected lines):
const oauth2ConsentCreationSkew = 10 * time.Second // near top of handleOAuth2ConsentDeviceAuthorizationPOST: now := ctx.GetClock().Now()
565-565: Also reuse now for RespondedAt here.Keep timestamps consistent within the request.
Apply this diff:
- consent.SetRespondedAt(ctx.GetClock().Now(), 0) + consent.SetRespondedAt(now, 0)internal/commands/acl_test.go (2)
153-155: Optional: fail fast on subject/object equality.Switch to require.Equal so you don’t wade through noisy asserts after a mismatch.
- assert.Equal(t, tc.subject, subject) - assert.Equal(t, tc.object, object) + require.Equal(t, tc.subject, subject) + require.Equal(t, tc.object, object)
296-338: Confirm “maybe-match” semantics align with runAccessControlCheck, fool.Non-verbose path expecting default-policy despite potential/skimmed matches looks right—add a verbose=true twin asserting the explanatory lines to cement intent.
internal/commands/build_info.go (2)
37-53: Optional: name the "verbose" flag to a constTiny polish: avoid magic string "verbose" in multiple places; makes refactors safer.
Apply this minimal tweak:
func runBuildInfo(w io.Writer, flags *pflag.FlagSet) (err error) { var ( verbose bool info *debug.BuildInfo ok bool ) - if verbose, err = flags.GetBool("verbose"); err != nil { + const flagVerbose = "verbose" + if verbose, err = flags.GetBool(flagVerbose); err != nil { return err } if info, ok = debug.ReadBuildInfo(); !ok { return fmt.Errorf("failed to read build info") } return runBuildInfoOutput(w, verbose, info) }
55-84: Propagate write errors and stabilize output orderDon’t swallow writer errors, sucka. Also consider sorting to make tests deterministic.
Apply this focused diff:
func runBuildInfoOutput(w io.Writer, verbose bool, info *debug.BuildInfo) (err error) { if info == nil { return fmt.Errorf("failed to read build info") } - _, _ = fmt.Fprintf(w, fmtAutheliaBuild, utils.BuildTag, utils.BuildState, utils.BuildBranch, utils.BuildCommit, - utils.BuildNumber, runtime.GOOS, runtime.GOARCH, runtime.Compiler, utils.BuildDate, utils.Dev, utils.BuildExtra) + writef := func(format string, args ...any) error { + _, err := fmt.Fprintf(w, format, args...) + return err + } + if err := writef(fmtAutheliaBuild, utils.BuildTag, utils.BuildState, utils.BuildBranch, utils.BuildCommit, + utils.BuildNumber, runtime.GOOS, runtime.GOARCH, runtime.Compiler, utils.BuildDate, utils.Dev, utils.BuildExtra); err != nil { + return err + } - _, _ = fmt.Fprintf(w, "\n"+fmtAutheliaBuildGo, info.GoVersion, info.Main.Path, info.Path) + if err := writef("\n"+fmtAutheliaBuildGo, info.GoVersion, info.Main.Path, info.Path); err != nil { + return err + } if verbose { if len(info.Settings) != 0 { - _, _ = fmt.Fprintf(w, " Settings:\n") + if err := writef(" Settings:\n"); err != nil { + return err + } - for _, setting := range info.Settings { - _, _ = fmt.Fprintf(w, " %s: %s\n", setting.Key, setting.Value) + for _, setting := range info.Settings { + if err := writef(" %s: %s\n", setting.Key, setting.Value); err != nil { + return err + } } } if len(info.Deps) != 0 { - _, _ = fmt.Fprintf(w, " Dependencies:\n") + if err := writef(" Dependencies:\n"); err != nil { + return err + } - for _, dep := range info.Deps { - _, _ = fmt.Fprintf(w, " %s@%s (%s)\n", dep.Path, dep.Version, dep.Sum) + for _, dep := range info.Deps { + if err := writef(" %s@%s (%s)\n", dep.Path, dep.Version, dep.Sum); err != nil { + return err + } } } } return nil }If you want deterministic output, I can follow up with a small sort of Settings/Deps (requires importing sort).
internal/commands/crypto.go (3)
274-288: Don’t ignore writer errorsCheck fmt.Fprintf results so failures (e.g., broken pipe) don’t pass silently.
Apply this diff:
func runCryptoRandPrint(w io.Writer, flags *pflag.FlagSet) (err error) { var random string if random, err = flagsGetRandomCharacters(flags, cmdFlagNameLength, cmdFlagNameCharSet, cmdFlagNameCharacters); err != nil { return err } - _, _ = fmt.Fprintf(w, "Random Value: %s\n", random) + if _, err = fmt.Fprintf(w, "Random Value: %s\n", random); err != nil { + return err + } if value := url.QueryEscape(random); random != value { - _, _ = fmt.Fprintf(w, "Random Value (URL Encoded): %s\n", value) + if _, err = fmt.Fprintf(w, "Random Value (URL Encoded): %s\n", value); err != nil { + return err + } } return nil }
343-347: Check print errors when summarizing created filesDon’t drop I/O errors, sucka.
- _, _ = fmt.Fprintf(w, "Created %d files with unique random values:\n", len(files)) + if _, err = fmt.Fprintf(w, "Created %d files with unique random values:\n", len(files)); err != nil { + return err + } for _, name = range files { - _, _ = fmt.Fprintf(w, "\t- %s\n", name) + if _, err = fmt.Fprintf(w, "\t- %s\n", name); err != nil { + return err + } }
708-708: Propagate write error from final outputCapture and return the error from fmt.Fprint.
- _, _ = fmt.Fprint(w, b.String()) + if _, err = fmt.Fprint(w, b.String()); err != nil { + return err + }internal/handlers/handler_firstfactor_passkey_test.go (2)
924-924: Be consistent: use the AuthType constant instead of a raw string.You already use
regulation.AuthTypePasskeyelsewhere in this file. Standardize it here to cut brittle string literals.Example patch (apply similarly to the other occurrences listed):
- Type: "Passkey", + Type: regulation.AuthTypePasskey,Also applies to: 1027-1027, 1126-1126, 1223-1223, 1294-1294, 1390-1390, 1440-1440, 1485-1485, 1514-1514, 1557-1557, 1675-1675, 1718-1718
555-555: Nit: prefer idiomatic negative durations.
-10 * time.Secondreads cleaner thantime.Second * -10. Keep it smooth, sucka.- CreatedAt: mock.Ctx.Providers.Clock.Now().UTC().Add(time.Second * -10), + CreatedAt: mock.Ctx.Providers.Clock.Now().UTC().Add(-10 * time.Second),Also applies to: 660-660, 762-762
internal/utils/const_test.go (1)
11-11: Make the interface type explicit for clarity.
Minor, but being explicit helps future readers and prevents accidental concrete-type coupling.-var r = random.New() +var r random.Provider = random.New()internal/handlers/handler_register_totp_test.go (1)
735-736: Use Providers clock everywhere, fool! Replace all direct calls tomock.Clock.Now()(andmock.Ctx.Clock) withmock.Ctx.Providers.Clock.Now()ininternal/handlers/handler_register_totp_test.goto keep expectations in sync withctx.GetClock(). I pity the fool who lets time drift!internal/middlewares/util.go (1)
75-81: NewProvidersBasic is handy; tighten the doc so no fool misreads it.
Spell out which “simple providers” are initialized.-// NewProvidersBasic returns a new Providers with the simple providers. +// NewProvidersBasic returns a new Providers initializing only the simple providers: +// Clock and Random.internal/commands/context.go (1)
145-149: Don’t fail the whole run on mere warnings, sucker.LoadTrustedCertificatesRunE turns warnings into fatal errors. Consider logging warns and proceeding.
Also applies to: 168-169
internal/middlewares/authelia_context_blackbox_test.go (1)
844-849: Duplicate test case detected, sucka.Two identical “ShouldHandleBadObject” entries; drop one to keep the suite lean.
- { - "ShouldHandleBadObject", - []byte(`{"123": 123}`), - nil, - nil, - "unable to validate body: function only accepts structs; got map", - },
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
internal/configuration/test_resources/userdb/debug-tests.ymlis excluded by!**/*.yml
📒 Files selected for processing (84)
cmd/authelia-gen/openid_conformance.go(1 hunks)cmd/authelia/main.go(1 hunks)experimental/embed/context.go(3 hunks)experimental/embed/provider/general.go(1 hunks)internal/clock/fixed.go(2 hunks)internal/clock/provider.go(1 hunks)internal/clock/real.go(2 hunks)internal/commands/acl_test.go(4 hunks)internal/commands/build_info.go(2 hunks)internal/commands/build_info_test.go(3 hunks)internal/commands/context.go(8 hunks)internal/commands/context_test.go(1 hunks)internal/commands/crypto.go(6 hunks)internal/commands/crypto_hash.go(6 hunks)internal/commands/crypto_test.go(1 hunks)internal/commands/debug.go(13 hunks)internal/commands/debug_test.go(1 hunks)internal/commands/errors.go(1 hunks)internal/commands/storage_run.go(9 hunks)internal/commands/storage_run_test.go(1 hunks)internal/commands/util.go(2 hunks)internal/commands/util_test.go(2 hunks)internal/duo/duo.go(2 hunks)internal/duo/duo_test.go(2 hunks)internal/duo/types.go(2 hunks)internal/handlers/func_test.go(1 hunks)internal/handlers/handler_authz_authn.go(5 hunks)internal/handlers/handler_authz_test.go(16 hunks)internal/handlers/handler_firstfactor_passkey.go(3 hunks)internal/handlers/handler_firstfactor_passkey_test.go(26 hunks)internal/handlers/handler_firstfactor_password.go(2 hunks)internal/handlers/handler_firstfactor_password_test.go(2 hunks)internal/handlers/handler_oauth2_authorization.go(1 hunks)internal/handlers/handler_oauth2_authorization_claims.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core_test.go(10 hunks)internal/handlers/handler_oauth2_authorization_consent_explicit.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_implicit.go(3 hunks)internal/handlers/handler_oauth2_authorization_consent_preconfigured.go(5 hunks)internal/handlers/handler_oauth2_consent.go(6 hunks)internal/handlers/handler_oauth2_device_authorization.go(1 hunks)internal/handlers/handler_oauth2_introspection.go(1 hunks)internal/handlers/handler_oauth2_oidc_userinfo.go(2 hunks)internal/handlers/handler_oauth2_oidc_wellknown.go(1 hunks)internal/handlers/handler_oauth2_token.go(1 hunks)internal/handlers/handler_oauth2_wellknown.go(1 hunks)internal/handlers/handler_register_totp.go(3 hunks)internal/handlers/handler_register_totp_test.go(3 hunks)internal/handlers/handler_reset_password.go(1 hunks)internal/handlers/handler_session_elevation.go(3 hunks)internal/handlers/handler_session_elevation_test.go(4 hunks)internal/handlers/handler_sign_duo.go(1 hunks)internal/handlers/handler_sign_password.go(1 hunks)internal/handlers/handler_sign_password_test.go(1 hunks)internal/handlers/handler_sign_totp.go(2 hunks)internal/handlers/handler_sign_totp_test.go(2 hunks)internal/handlers/handler_sign_webauthn.go(2 hunks)internal/middlewares/authelia_context.go(1 hunks)internal/middlewares/authelia_context_blackbox_test.go(15 hunks)internal/middlewares/identity_verification.go(1 hunks)internal/middlewares/require_auth_test.go(1 hunks)internal/middlewares/startup.go(2 hunks)internal/middlewares/timing_attack_delay_test.go(2 hunks)internal/middlewares/types.go(2 hunks)internal/middlewares/util.go(2 hunks)internal/mocks/authelia_context.go(2 hunks)internal/mocks/duo_api.go(3 hunks)internal/model/webauthn_test.go(1 hunks)internal/notification/smtp_notifier.go(1 hunks)internal/oidc/types.go(1 hunks)internal/oidc/types_test.go(1 hunks)internal/random/cryptographical.go(1 hunks)internal/regulation/regulator_blackbox_test.go(2 hunks)internal/server/server_test.go(1 hunks)internal/service/file_watcher_test.go(2 hunks)internal/service/sever_test.go(4 hunks)internal/service/signal_test.go(2 hunks)internal/suites/example/compose/duo-api/duo_api.js(3 hunks)internal/totp/totp_test.go(3 hunks)internal/utils/const_test.go(1 hunks)internal/utils/crypto.go(2 hunks)internal/utils/crypto_test.go(1 hunks)internal/utils/exec.go(0 hunks)internal/utils/types.go(2 hunks)
💤 Files with no reviewable changes (1)
- internal/utils/exec.go
🚧 Files skipped from review as they are similar to previous changes (66)
- internal/commands/errors.go
- internal/middlewares/identity_verification.go
- internal/commands/crypto_test.go
- internal/handlers/handler_sign_duo.go
- internal/handlers/handler_oauth2_wellknown.go
- internal/handlers/handler_oauth2_authorization_consent_core.go
- internal/model/webauthn_test.go
- cmd/authelia/main.go
- internal/mocks/authelia_context.go
- internal/handlers/handler_sign_password.go
- internal/notification/smtp_notifier.go
- internal/random/cryptographical.go
- internal/handlers/func_test.go
- internal/commands/storage_run_test.go
- internal/handlers/handler_oauth2_authorization.go
- internal/handlers/handler_oauth2_authorization_consent_explicit.go
- internal/commands/debug_test.go
- experimental/embed/provider/general.go
- internal/handlers/handler_sign_password_test.go
- internal/utils/crypto_test.go
- internal/handlers/handler_oauth2_device_authorization.go
- internal/handlers/handler_firstfactor_password_test.go
- internal/middlewares/timing_attack_delay_test.go
- internal/handlers/handler_oauth2_token.go
- internal/commands/util_test.go
- internal/handlers/handler_sign_webauthn.go
- internal/regulation/regulator_blackbox_test.go
- internal/service/signal_test.go
- internal/handlers/handler_oauth2_oidc_wellknown.go
- internal/server/server_test.go
- internal/clock/fixed.go
- internal/clock/provider.go
- internal/handlers/handler_oauth2_authorization_consent_preconfigured.go
- internal/handlers/handler_register_totp.go
- internal/service/file_watcher_test.go
- internal/handlers/handler_oauth2_introspection.go
- internal/duo/duo_test.go
- internal/handlers/handler_oauth2_oidc_userinfo.go
- internal/duo/types.go
- internal/handlers/handler_session_elevation_test.go
- internal/handlers/handler_firstfactor_passkey.go
- internal/handlers/handler_oauth2_authorization_consent_implicit.go
- internal/utils/types.go
- internal/handlers/handler_firstfactor_password.go
- experimental/embed/context.go
- internal/oidc/types.go
- internal/handlers/handler_reset_password.go
- internal/middlewares/require_auth_test.go
- internal/handlers/handler_sign_totp.go
- cmd/authelia-gen/openid_conformance.go
- internal/handlers/handler_session_elevation.go
- internal/mocks/duo_api.go
- internal/handlers/handler_authz_test.go
- internal/handlers/handler_authz_authn.go
- internal/handlers/handler_sign_totp_test.go
- internal/commands/context_test.go
- internal/oidc/types_test.go
- internal/middlewares/authelia_context.go
- internal/handlers/handler_oauth2_authorization_claims.go
- internal/commands/debug.go
- internal/commands/crypto_hash.go
- internal/clock/real.go
- internal/service/sever_test.go
- internal/commands/build_info_test.go
- internal/suites/example/compose/duo-api/duo_api.js
- internal/totp/totp_test.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-29T10:47:45.888Z
Learnt from: james-d-elliott
PR: authelia/authelia#10189
File: internal/clock/provider.go:14-15
Timestamp: 2025-08-29T10:47:45.888Z
Learning: The internal/mocks directory does not contain any mock clock implementations. Tests use concrete clock instances like clock.New(), clock.NewFixed(), and direct assignment to mock.Ctx.Providers.Clock instead of generated mocks for the clock.Provider interface.
Applied to files:
internal/handlers/handler_oauth2_authorization_consent_core_test.gointernal/handlers/handler_firstfactor_passkey_test.gointernal/handlers/handler_register_totp_test.go
📚 Learning: 2025-08-27T21:37:17.083Z
Learnt from: james-d-elliott
PR: authelia/authelia#10059
File: internal/commands/storage_run.go:23-23
Timestamp: 2025-08-27T21:37:17.083Z
Learning: The Authelia project uses "go.yaml.in/yaml/v4" as their YAML package import path, not the standard "gopkg.in/yaml.v3" or "gopkg.in/yaml.v2". This is used consistently across their codebase.
Applied to files:
internal/commands/storage_run.go
🧬 Code graph analysis (15)
internal/middlewares/util.go (6)
internal/storage/sql_provider.go (1)
NewProvider(24-35)experimental/embed/provider/general.go (2)
NewRegulator(52-54)New(26-28)internal/regulation/types.go (1)
Regulator(16-25)internal/middlewares/types.go (1)
Providers(40-58)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)
internal/handlers/handler_oauth2_authorization_consent_core_test.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/model/oidc.go (1)
OAuth2ConsentSession(254-276)
internal/handlers/handler_oauth2_consent.go (1)
internal/model/oidc.go (1)
NewOAuth2ConsentSession(20-22)
internal/commands/util.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/utils/const_test.go (1)
internal/random/cryptographical.go (1)
New(12-14)
internal/duo/duo.go (2)
internal/duo/types.go (4)
Production(27-29)Response(43-49)PreAuthResponse(60-68)AuthResponse(52-57)internal/middlewares/types.go (1)
Context(60-69)
internal/commands/acl_test.go (2)
internal/commands/context.go (1)
CmdCtx(41-53)internal/authorization/types.go (3)
Subject(49-54)Object(67-73)RuleMatchResult(100-112)
internal/commands/context.go (7)
experimental/embed/context.go (1)
Context(65-74)internal/middlewares/types.go (1)
Context(60-69)internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/utils/types.go (1)
X509SystemCertPoolFactory(31-33)internal/clock/provider.go (1)
Provider(10-15)internal/utils/crypto.go (2)
NewX509CertPool(344-346)NewX509CertPoolWithFactory(350-398)internal/commands/errors.go (1)
ErrConfigCreated(14-14)
internal/handlers/handler_firstfactor_passkey_test.go (2)
internal/middlewares/types.go (1)
Providers(40-58)internal/model/regulation.go (3)
BannedUser(26-35)AuthenticationAttempt(9-19)BannedIP(37-46)
internal/middlewares/startup.go (2)
internal/middlewares/types.go (2)
Providers(40-58)ServiceContext(71-79)internal/model/types.go (1)
StartupCheck(168-170)
internal/commands/storage_run.go (4)
internal/middlewares/types.go (2)
Context(60-69)ServiceContext(71-79)internal/storage/provider.go (1)
Provider(15-328)internal/totp/provider.go (1)
Provider(8-13)internal/utils/time.go (1)
ParseDurationString(85-103)
internal/middlewares/authelia_context_blackbox_test.go (8)
internal/middlewares/authelia_context.go (1)
NewAutheliaCtx(43-51)internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/mocks/authelia_context.go (1)
NewMockAutheliaCtx(47-239)internal/handlers/types.go (1)
StateResponse(200-205)internal/middlewares/const.go (1)
ContentTypeApplicationJSON(116-116)internal/middlewares/types.go (1)
Providers(40-58)internal/expression/user_attributes.go (1)
NewUserAttributes(13-24)internal/metrics/prometheus.go (1)
NewPrometheus(12-18)
internal/handlers/handler_register_totp_test.go (2)
internal/model/totp_configuration.go (1)
TOTPConfiguration(28-38)internal/middlewares/types.go (1)
Providers(40-58)
internal/middlewares/types.go (4)
internal/clock/provider.go (1)
Provider(10-15)internal/service/provider.go (2)
Provider(13-28)Context(46-52)experimental/embed/context.go (1)
Context(65-74)internal/oidc/types.go (1)
Context(212-221)
internal/utils/crypto.go (1)
internal/utils/types.go (3)
StandardX509SystemCertPoolFactory(35-35)StandardX509SystemCertPoolFactory(37-39)X509SystemCertPoolFactory(31-33)
⏰ 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). (2)
- GitHub Check: Analyze (go)
- GitHub Check: StepSecurity Harden-Runner
🔇 Additional comments (37)
internal/handlers/handler_oauth2_consent.go (1)
660-660: LGTM: Use injected clock in CanGrant.Good move to ctx.GetClock().Now(); improves testability and consistency across the flow.
internal/commands/acl_test.go (3)
17-25: LGTM: command constructors sanity test is clean, sucka.Non-nil checks for both constructors are tight. I pity the fool who skips basic instantiation tests.
31-38: Nice matrix expansion for inputs/expectations.Adding urlValue, subject, and object makes the cases explicit and future-proof.
345-347: LGTM: exercising the new runAccessControlCheck signature.No-error path and buffered output checks are solid.
internal/commands/util.go (2)
382-422: Nil-on-unknown and PBKDF2 KeySize removal—LGTM, sucka!Returning nil on unknown
useand dropping the PBKDF2 KeySize mapping align with caller intent and actual options. Clean and precise.
382-422: All good: nil map handled & no PBKDF2 KeySize mapping
CryptoHashGenerateMapFlagsRunE checksflagsMap != nilbefore appending, andgetCryptoHashGenerateMapFlagsFromUsenever returns a PBKDF2 key_length entry – I pity the fool who thinks otherwise!internal/commands/build_info.go (2)
10-10: LGTM: pflag import aligns with FlagSet-based helpersClean move, fool. Keeps the command plumbing consistent across the codebase.
34-34: Delegate to runBuildInfo(w, flags): solid splitGood separation of concerns. Writer in, FlagSet in. I pity the fool who mixes CLI glue with logic.
internal/commands/crypto.go (3)
18-18: LGTM: pflag import keeps the command API uniformRight move, fool. Consistent FlagSet usage across commands.
268-271: LGTM: clean split to runCryptoRandPrint/runCryptoRandFilesGood delegation based on presence of files. Clear and testable. I pity the fool who buries logic in RunE.
631-632: LGTM: extraction to runCryptoPairGenerate(w, …)Nice decoupling from Cobra. Testable and consistent.
internal/handlers/handler_firstfactor_passkey_test.go (1)
191-191: LGTM on migrating timestamps to Providers.Clock.Solid move hooking all auth-attempt timestamps to the injected clock. Deterministic tests, no flakes. I pity the fool who trusts wall-clock in tests.
Also applies to: 252-252, 288-288, 410-410, 515-515, 619-619, 721-721, 1023-1023, 1122-1122, 1218-1218, 1290-1290, 1385-1385, 1435-1435, 1480-1480, 1510-1510, 1553-1553, 1671-1671, 1714-1714
internal/utils/const_test.go (1)
11-11: LGTM on switching to random.New(); aligns with provider pattern. I pity the fool who keeps struct literals around!internal/handlers/handler_register_totp_test.go (1)
858-859: Binding mock clock via Providers before exercising code: solid.
This keeps tests deterministic with ctx.GetClock(). I pity the flaky tests that don’t!internal/handlers/handler_oauth2_authorization_consent_core_test.go (2)
217-218: Clock injection via Providers across test tables looks good.
Consistent setup of mock.Ctx.Providers.Clock = &mock.Clock keeps time flow tight, fool.Also applies to: 379-381, 719-721, 1021-1023, 1358-1360
877-881: No remaining direct mock.Clock references—resolved
I pity the fool who thinks there’s still a straymock.Ctx.Clockormock.Clock.Now—sweep confirms no matches in the test file.internal/middlewares/startup.go (2)
48-48: Helper signature synced to ServiceContext: consistent.
No logic changes; just the right kind of plumbing.
12-12: Good job, fool — all StartupChecks callers now correctly use ServiceContext.internal/utils/crypto.go (1)
343-346: Factory wrapper LGTM, fool!Good delegation to the standard factory via NewX509CertPoolWithFactory.
internal/middlewares/types.go (2)
56-58: Providers now own Clock/Random — nice consolidation, chump!Centralizing time/RNG in Providers is clean and test-friendly.
60-69: Ensure zero-nil safety for Context API Guarantee GetClock/GetRandom never return nil at runtime (constructors must initialize defaults)—I pity the fool who skips verifying the AutheliaCtx/Server/Provider implementations.internal/commands/context.go (4)
32-37: NewCmdCtx defaults are sane, fool!Using NewProvidersBasic and a pointer config avoids nils. LGTM.
86-93: Expose Clock/Random — good API, chump!These accessors align with ServiceContext and keep tests deterministic.
349-349: Incorrect signature change claim
I pity the fool thinking the cmd/args were dropped! The method still declares two parameters (_ *cobra.Command, _ []string), so all existing callers (including tests) remain valid. No changes required.Likely an incorrect or invalid review comment.
404-407: ErrConfigCreated properly handled – existing tests in context_test.go and the command switch in main.go cover this error; I pity the fool who thinks otherwise, yo!internal/commands/storage_run.go (5)
52-56: Good: accumulate warnings cleanly, fool!Switched from errors to warns accumulation when reporting warnings. LGTM.
149-161: Nice UX touch on cache delete, chump!Helper prints a consistent success message and keeps logic tidy.
708-721: Dispatcher LGTM.runStorageBansList routes cleanly by use.
821-843: Revoke dispatcher LGTM.Flag parsing and routing look correct.
1422-1476: TOTP generation via ctx clock/RNG — righteous!Deterministic and testable; image write flow looks solid.
internal/middlewares/authelia_context_blackbox_test.go (7)
4-4: Imports LGTM, fool.Each new import is exercised by added tests. No bloat.
Also applies to: 9-9, 16-18
338-338: Good move to NewProvidersBasic().Factory centralizes defaults (Clock/Random) and reduces boilerplate. I pity the fool who hand-rolls providers everywhere.
Also applies to: 409-409, 490-490, 563-563, 638-638, 689-689, 748-748, 871-871, 940-940, 991-991, 1017-1017, 1086-1086, 1265-1265
781-783: Nice coverage for cryptographic RNG path.Extra case strengthens GetRandom() guarantees.
1240-1246: ReplyJSON error-path test is tight.Catches +Inf marshal edge; clear expectation.
1248-1263: SetJSONBody happy-path nailed.Asserts content-type and envelope precisely. That’s good testing, fool.
1277-1295: Lazy defaults behavior verified.Starting with empty Providers{} and asserting GetClock/GetRandom population is spot on.
1305-1330: WebAuthn provider scenarios covered well.Host requirement and selection criteria variants exercised. Solid.
| rand := random.New() | ||
|
|
||
| return rand.StringCustom(n, charset), nil | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Validate empty charset and tighten UX, fool!
Switch to crypto RNG is solid. Add a guard so an empty --characters doesn't blow up, and list all supported charsets in the error to match the switch.
Apply this diff within this hunk to guard against empty custom charsets:
- rand := random.New()
+ rand := random.New()
+ // Guard: when using --characters explicitly, it must not be empty.
+ if !useCharSet && useCharacters && charset == "" {
+ return "", fmt.Errorf("flag '--%s' must not be empty when provided", flagNameCharacters)
+ }Outside this hunk (no diff provided), consider updating the error at Line 95 to reflect all accepted values:
return "", fmt.Errorf(
"flag '--%s' with value '%s' is invalid, must be one of 'ascii', 'alphanumeric', 'alphanumeric-lower', 'alphanumeric-upper', 'alphabetic', 'alphabetic-lower', 'alphabetic-upper', 'numeric', 'numeric-hex', 'rfc3986', 'rfc3986-lower', or 'rfc3986-upper'",
flagNameCharSet, c,
)Optional nit: rename local var rand to rng to avoid confusion with the common name for PRNGs. I pity the fool who shadows!
🤖 Prompt for AI Agents
In internal/commands/util.go around lines 103-106, the function returns
rand.StringCustom(n, charset) without validating that a user-supplied custom
charset is non-empty and the error message at line 95 should enumerate all
supported charsets; add a guard before calling StringCustom that returns a clear
error if the custom charset is empty, update the earlier error at line 95 to
list all accepted values exactly as provided in the review, and optionally
rename the local variable rand to rng to avoid confusion with PRNG naming.
| ctx := middlewares.NewAutheliaCtx(&fasthttp.RequestCtx{}, schema.Configuration{}, middlewares.Providers{}) | ||
|
|
||
| assert.NotPanics(t, func() { | ||
| ctx.RecordAuthn(true, true, "password") | ||
| }) | ||
|
|
||
| ctx.Providers.Metrics = metrics.NewPrometheus() | ||
|
|
||
| assert.NotPanics(t, func() { | ||
| ctx.RecordAuthn(true, true, "password") | ||
| }) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Metrics registration: verify no duplicate panics, fool.
metrics.NewPrometheus() often registers collectors; multiple registrations can panic in Prometheus. Ensure register() is idempotent or not called elsewhere in the same process.
🏁 Script executed:
#!/bin/bash
# Scan for additional Prometheus provider constructions that could double-register.
rg -n -C2 'metrics\.NewPrometheus\s*\('Length of output: 1313
I pity the fool who can’t trace where NewPrometheus lives—let’s dig it up!
🏁 Script executed:
#!/bin/bash
# List metrics-related directories
find internal -type d | grep metrics
# Locate the NewPrometheus definition
rg -n 'func NewPrometheus' -C5 internal
# Check for any global prometheus.MustRegister calls
rg -n 'MustRegister' -C5 internalLength of output: 786
I pity the fool who ain't checked what register() really does—let’s tear into that code!
🏁 Script executed:
#!/bin/bash
# Show the Prometheus struct and its register method
rg -n 'type Prometheus' -C5 internal/metrics/prometheus.go
rg -n 'func (p \*Prometheus) register' -C20 internal/metrics/prometheus.goLength of output: 506
I pity the fool who skips the register() body—let’s see it in full!
🏁 Script executed:
#!/bin/bash
# Display the Prometheus.register() implementation
awk '/func (p \\*Prometheus) register\\(\\)/, /}/' internal/metrics/prometheus.goLength of output: 83
I pity the fool who skips straight to conclusions—let’s grab that register() body!
🏁 Script executed:
#!/bin/bash
# Show the register() implementation with context
rg -nP 'func\s+\(p \*Prometheus\)\s+register' -C20 internal/metrics/prometheus.goLength of output: 83
I pity the fool who won’t show me what register() actually does—let’s rip open that file!
🏁 Script executed:
#!/bin/bash
# Dump the beginning of the Prometheus metrics implementation, including register()
sed -n '1,200p' internal/metrics/prometheus.goLength of output: 4883
Guard Prometheus.register() against duplicate registrations, fool!
register() uses promauto.New* (which calls prometheus.MustRegister) and will panic if NewPrometheus() is invoked more than once in the same process. Wrap register() in sync.Once or adopt a custom CollectorRegistry to prevent duplicate collector registration.
| type ServiceContext interface { | ||
| GetClock() (clock clock.Provider) | ||
| GetRandom() (random random.Provider) | ||
| GetLogger() (logger *logrus.Entry) | ||
| GetProviders() (providers Providers) | ||
| GetConfiguration() (config *schema.Configuration) | ||
|
|
||
| context.Context | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
ServiceContext introduced — verify all impls satisfy it, sucka!
Double-check CmdCtx, HTTP contexts, and tests implement all getters plus embed context.Context.
🏁 Script executed:
#!/bin/bash
# Who implements ServiceContext?
rg -n 'ServiceContext' -g '!**/vendor/**'
# Ensure CmdCtx implements required methods
rg -nP 'type\s+\*?CmdCtx\b' internal/commands -n
rg -nP 'func\s+\(\*CmdCtx\)\s+Get(Clock|Random|Logger|Providers|Configuration)\s*\(' internal/commands -n
# Spot any structs named Context/AutheliaCtx missing getters
rg -nP 'type\s+AutheliaCtx\b.*' -C2 internal/middlewares
rg -nP 'func\s+\(\*AutheliaCtx\)\s+Get(Clock|Random|Logger|Providers|Configuration|RemoteIP)\s*\(' internal -nLength of output: 1679
Implement missing ServiceContext getters on CmdCtx and AutheliaCtx
CmdCtx (internal/commands/context.go) and AutheliaCtx (internal/middlewares/types.go) don’t implement GetClock, GetRandom, GetLogger, GetProviders or GetConfiguration—add these methods and embed context.Context, or I pity the fool who doesn’t!
🤖 Prompt for AI Agents
In internal/middlewares/types.go around lines 71 to 79, the ServiceContext
interface defines GetClock, GetRandom, GetLogger, GetProviders and
GetConfiguration and embeds context.Context, but CmdCtx
(internal/commands/context.go) and AutheliaCtx (internal/middlewares/types.go)
do not implement those getters; update both structs to embed context.Context (or
add a ctx field) and implement the five getter methods returning the underlying
clock.Provider, random.Provider, *logrus.Entry, Providers and
*schema.Configuration fields respectively (or nil/defaults if unavailable),
ensuring method receivers match the struct types and signatures exactly to
satisfy the ServiceContext interface.
Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>
bad0f39 to
481455d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
internal/middlewares/types.go (1)
39-58: Use NewProvidersBasic for all Providers initializations
I pity the fool who fails to initialize Clock and Random! Replace literalProviders{}withNewProvidersBasic()in:
- internal/middlewares/authelia_context_blackbox_test.go at lines 1277, 1298, 1305, 1333
- internal/middlewares/cors_test.go at line 723
- experimental/embed/types_test.go at line 13
internal/commands/storage_run.go (1)
52-56: Log non-fatal warnings and proceed (don’t treat warnings as errors)Replace the
warnscase ininternal/commands/storage_run.go’sLoadProvidersStorageRunE:case len(warns) != 0: - err = fmt.Errorf("had the following warnings loading the trusted certificates") - - for _, e := range warns { - err = fmt.Errorf("%+v: %w", err, e) - } - - return err + for _, e := range warns { + ctx.GetLogger().Warnf("warning loading trusted certificates: %v", e) + } + // proceed despite warningsexperimental/embed/context.go (1)
53-61: Back your context, fool. Set a real Context.Embed field is nil; method promotion on a nil interface can bite. Initialize with
context.Background().ctx = &ctxEmbed{ Configuration: (*Configuration)(config), ConfigurationPaths: paths, Logger: logrus.NewEntry(logrus.StandardLogger()), Providers: Providers(providers), + Context: context.Background(), }
♻️ Duplicate comments (4)
internal/commands/acl_test.go (1)
104-107: Parallel subtests and capture fix—now you’re cookin’.tc := tc and t.Parallel() with spacing keeps things safe and lint-friendly. I pity the fool who races tests.
internal/duo/duo_test.go (1)
480-482: Don’t hand out nil configs.Returning nil here is a trap waiting to spring a panic. Hand back an empty config instead.
-func (t *TestCtx) GetConfiguration() (config *schema.Configuration) { - return nil -} +func (t *TestCtx) GetConfiguration() (config *schema.Configuration) { + cfg := &schema.Configuration{} + return cfg +}internal/commands/storage_run.go (1)
943-980: Fix arg panic and permanent duration logic, fool.
- Accessing
args[0]unguarded will blow up.- Permanent bans shouldn’t require a positive duration.
func runStorageBansAdd(ctx context.Context, w io.Writer, flags *pflag.FlagSet, args []string, store storage.Provider, use string) (err error) { var ( permanent bool reason, durationStr string ) @@ - duration, err := utils.ParseDurationString(durationStr) - if err != nil { - return fmt.Errorf("failed to parse duration string: %w", err) - } - - if duration <= 0 { - return fmt.Errorf("duration must be a positive value") - } - - target := args[0] + // target required + if len(args) == 0 || strings.TrimSpace(args[0]) == "" { + want := map[string]string{cmdUseIP: "IP address", cmdUseUser: "username"}[use] + if want == "" { + want = "target" + } + return fmt.Errorf("%s is required", want) + } + target := args[0] + + var duration time.Duration + if !permanent { + if duration, err = utils.ParseDurationString(durationStr); err != nil { + return fmt.Errorf("failed to parse duration string: %w", err) + } + if duration <= 0 { + return fmt.Errorf("duration must be a positive value") + } + } else { + duration = 0 + }internal/middlewares/authelia_context.go (1)
603-609: Nil-guard fixed—nice. Add a trace so future fools ain’t confused.Lazy init is solid. Consider tracing when you fall back to the default clock to aid debugging in tests and embeds, sucka.
func (ctx *AutheliaCtx) GetClock() (provider clock.Provider) { - if ctx.Providers.Clock == nil { - ctx.Providers.Clock = clock.New() - } + if ctx.Providers.Clock == nil { + ctx.Logger.Trace("Clock provider is nil; using default real clock") + ctx.Providers.Clock = clock.New() + } return ctx.Providers.Clock }
🧹 Nitpick comments (15)
internal/clock/fixed.go (1)
24-27: Name nit: make intent jump out.Consider renaming to JWTTimeFuncOption or JWTParserTimeOption for clarity; behavior is solid as-is.
internal/handlers/handler_oauth2_authorization_consent_core_test.go (2)
510-511: Log message reads like the wrong operation—verify intent.Test case “ShouldHandleLoadSessionFromDBError” expects “…saving consent session: bad” though the stubbed failure is LoadOAuth2ConsentSessionByChallengeID. Confirm the production log wording and align the regex or code accordingly, fool.
220-235: DRY up repeated test setup.Clock init, OIDC provider wiring, and recorder creation repeat across suites. Extract a helper (e.g., newConsentTestCtx(t)) to cut noise and ease future changes.
internal/commands/acl_test.go (2)
147-151: Don’t marry exact error strings—use contains.Error texts vary by Go/pflag; match substrings instead to avoid brittle flakes, fool.
- if tc.err == "" { - assert.NoError(t, err) - } else { - assert.EqualError(t, err, tc.err) - } + if tc.err == "" { + assert.NoError(t, err) + } else { + assert.ErrorContains(t, err, tc.err) + }
49-57: Brittle expectations flow from exact net/url and pflag messages.Given the switch above, ensure tc.err holds a stable substring (e.g., “invalid character” or “flag accessed”) not full sentences.
Also applies to: 59-66, 67-73, 91-100
internal/utils/types.go (1)
31-39: Document platform caveats for SystemCertPool.On some platforms SystemCertPool may be empty or error; a short comment helps future maintainers.
Apply this diff to add a note:
type X509SystemCertPoolFactory interface { - SystemCertPool() (pool *x509.CertPool, err error) + // SystemCertPool returns the system trust store. On some platforms this may + // be empty or return an error; callers should handle both cases. + SystemCertPool() (pool *x509.CertPool, err error) }internal/commands/context_test.go (3)
176-186: Brittle exact-version assertion.Hard-coding “migrate to version 22” will break when schema bumps. Prefer contains/prefix or derive the expected version constant.
Proposed change:
- assert.EqualError(t, ctx.CheckSchemaVersion(), "storage schema outdated: version 0 is outdated please migrate to version 22 in order to use this command or use an older binary") + err = ctx.CheckSchemaVersion() + require.Error(t, err) + assert.Contains(t, err.Error(), "storage schema outdated: version 0 is outdated")
178-181: Guard against nil StorageProvider before StartupCheck.If provider init ever fails, this becomes a nil deref.
Apply this diff:
- assert.NoError(t, ctx.providers.StorageProvider.StartupCheck()) + require.NotNil(t, ctx.providers.StorageProvider) + assert.NoError(t, ctx.providers.StorageProvider.StartupCheck())
60-70: Parallelize safe tests for speed.These tests don’t share state; add t.Parallel() to cut runtime.
Example:
func TestCmdCtx_LoadTrustedCertificatesRunE(t *testing.T) { + t.Parallel()Repeat for similar tests where no shared globals are touched.
Also applies to: 72-86, 188-215, 239-274, 299-347
internal/service/sever_test.go (2)
47-53: Replace sleep with readiness signaling, fool.time.Sleep is flaky on slow CI. Prefer a readiness channel or probe.
Sketch:
- // Give the service a moment to start. - time.Sleep(100 * time.Millisecond) + ready := make(chan struct{}) + go func() { + require.NoError(t, server.Run()) + close(ready) + }() + select { + case <-server.Ready(): // if you can expose one + case <-time.After(5 * time.Second): + t.Fatal("server not ready") + }If Ready() isn’t available, consider adding one to the service type.
Also applies to: 94-100
1-18: Typo in filename: sever_test.go.Rename to server_test.go for clarity.
internal/middlewares/types.go (1)
39-58: Tiny grammar nit on comment.“Providers contain all provider provided to Authelia.” reads odd.
Apply this diff:
-// Providers contain all provider provided to Authelia. +// Providers aggregates all providers used by Authelia.internal/duo/duo_test.go (1)
39-59: Ease up on brittle error strings.Exact string matches make tests flaky when upstream wording shifts. Prefer
assert.ErrorContainsorrequire.ErrorContains.Example:
-assert.EqualError(t, err, "error occurred making the preauth call to the duo api: error occurred parsing response: unexpected end of JSON input") +assert.ErrorContains(t, err, "preauth") +assert.ErrorContains(t, err, "parsing")Apply similarly across these cases.
Also applies to: 61-81, 83-103, 105-125, 127-147, 149-169, 171-306, 308-431
internal/commands/storage_run.go (1)
1825-1825: Tiny grammar nit.“configuration as QR codes” → “configurations as QR codes”.
-_, _ = fmt.Fprintf(w, "Successfully exported %d TOTP configuration as QR codes in PNG format to the '%s' directory\n", count, dir) +_, _ = fmt.Fprintf(w, "Successfully exported %d TOTP configurations as QR codes in PNG format to the '%s' directory\n", count, dir)internal/middlewares/authelia_context.go (1)
612-617: Good lazy init. Drop a trace when defaulting random, fool.Same pattern as clock—tiny trace helps when providers are unset.
func (ctx *AutheliaCtx) GetRandom() (provider random.Provider) { - if ctx.Providers.Random == nil { - ctx.Providers.Random = random.New() - } + if ctx.Providers.Random == nil { + ctx.Logger.Trace("Random provider is nil; using cryptographical provider") + ctx.Providers.Random = random.New() + } return ctx.Providers.Random }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
internal/configuration/test_resources/userdb/debug-tests.ymlis excluded by!**/*.yml
📒 Files selected for processing (84)
cmd/authelia-gen/openid_conformance.go(1 hunks)cmd/authelia/main.go(1 hunks)experimental/embed/context.go(3 hunks)experimental/embed/provider/general.go(1 hunks)internal/clock/fixed.go(2 hunks)internal/clock/provider.go(1 hunks)internal/clock/real.go(2 hunks)internal/commands/acl_test.go(4 hunks)internal/commands/build_info.go(2 hunks)internal/commands/build_info_test.go(3 hunks)internal/commands/context.go(8 hunks)internal/commands/context_test.go(1 hunks)internal/commands/crypto.go(6 hunks)internal/commands/crypto_hash.go(6 hunks)internal/commands/crypto_test.go(1 hunks)internal/commands/debug.go(13 hunks)internal/commands/debug_test.go(1 hunks)internal/commands/errors.go(1 hunks)internal/commands/storage_run.go(9 hunks)internal/commands/storage_run_test.go(1 hunks)internal/commands/util.go(2 hunks)internal/commands/util_test.go(2 hunks)internal/duo/duo.go(2 hunks)internal/duo/duo_test.go(2 hunks)internal/duo/types.go(2 hunks)internal/handlers/func_test.go(1 hunks)internal/handlers/handler_authz_authn.go(5 hunks)internal/handlers/handler_authz_test.go(16 hunks)internal/handlers/handler_firstfactor_passkey.go(3 hunks)internal/handlers/handler_firstfactor_passkey_test.go(26 hunks)internal/handlers/handler_firstfactor_password.go(2 hunks)internal/handlers/handler_firstfactor_password_test.go(2 hunks)internal/handlers/handler_oauth2_authorization.go(1 hunks)internal/handlers/handler_oauth2_authorization_claims.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_core_test.go(10 hunks)internal/handlers/handler_oauth2_authorization_consent_explicit.go(1 hunks)internal/handlers/handler_oauth2_authorization_consent_implicit.go(3 hunks)internal/handlers/handler_oauth2_authorization_consent_preconfigured.go(5 hunks)internal/handlers/handler_oauth2_consent.go(6 hunks)internal/handlers/handler_oauth2_device_authorization.go(1 hunks)internal/handlers/handler_oauth2_introspection.go(1 hunks)internal/handlers/handler_oauth2_oidc_userinfo.go(2 hunks)internal/handlers/handler_oauth2_oidc_wellknown.go(1 hunks)internal/handlers/handler_oauth2_token.go(1 hunks)internal/handlers/handler_oauth2_wellknown.go(1 hunks)internal/handlers/handler_register_totp.go(3 hunks)internal/handlers/handler_register_totp_test.go(3 hunks)internal/handlers/handler_reset_password.go(1 hunks)internal/handlers/handler_session_elevation.go(3 hunks)internal/handlers/handler_session_elevation_test.go(4 hunks)internal/handlers/handler_sign_duo.go(1 hunks)internal/handlers/handler_sign_password.go(1 hunks)internal/handlers/handler_sign_password_test.go(1 hunks)internal/handlers/handler_sign_totp.go(2 hunks)internal/handlers/handler_sign_totp_test.go(2 hunks)internal/handlers/handler_sign_webauthn.go(2 hunks)internal/middlewares/authelia_context.go(1 hunks)internal/middlewares/authelia_context_blackbox_test.go(15 hunks)internal/middlewares/identity_verification.go(1 hunks)internal/middlewares/require_auth_test.go(1 hunks)internal/middlewares/startup.go(2 hunks)internal/middlewares/timing_attack_delay_test.go(2 hunks)internal/middlewares/types.go(2 hunks)internal/middlewares/util.go(2 hunks)internal/mocks/authelia_context.go(2 hunks)internal/mocks/duo_api.go(3 hunks)internal/model/webauthn_test.go(1 hunks)internal/notification/smtp_notifier.go(1 hunks)internal/oidc/types.go(1 hunks)internal/oidc/types_test.go(1 hunks)internal/random/cryptographical.go(1 hunks)internal/regulation/regulator_blackbox_test.go(2 hunks)internal/server/server_test.go(1 hunks)internal/service/file_watcher_test.go(2 hunks)internal/service/sever_test.go(4 hunks)internal/service/signal_test.go(2 hunks)internal/suites/example/compose/duo-api/duo_api.js(3 hunks)internal/totp/totp_test.go(3 hunks)internal/utils/const_test.go(1 hunks)internal/utils/crypto.go(2 hunks)internal/utils/crypto_test.go(1 hunks)internal/utils/exec.go(0 hunks)internal/utils/types.go(2 hunks)
💤 Files with no reviewable changes (1)
- internal/utils/exec.go
🚧 Files skipped from review as they are similar to previous changes (66)
- internal/handlers/handler_oauth2_oidc_userinfo.go
- internal/middlewares/identity_verification.go
- internal/clock/provider.go
- internal/handlers/handler_sign_totp.go
- internal/handlers/handler_sign_password_test.go
- internal/handlers/handler_reset_password.go
- internal/handlers/handler_sign_duo.go
- internal/model/webauthn_test.go
- internal/handlers/handler_firstfactor_password_test.go
- internal/commands/debug_test.go
- internal/handlers/handler_oauth2_authorization.go
- internal/handlers/handler_oauth2_authorization_claims.go
- internal/handlers/handler_oauth2_authorization_consent_explicit.go
- internal/handlers/handler_oauth2_authorization_consent_preconfigured.go
- internal/suites/example/compose/duo-api/duo_api.js
- internal/commands/crypto_test.go
- internal/service/signal_test.go
- internal/handlers/handler_sign_webauthn.go
- internal/oidc/types_test.go
- internal/handlers/handler_oauth2_introspection.go
- internal/notification/smtp_notifier.go
- cmd/authelia-gen/openid_conformance.go
- internal/commands/util.go
- internal/handlers/func_test.go
- internal/clock/real.go
- internal/regulation/regulator_blackbox_test.go
- internal/handlers/handler_register_totp_test.go
- internal/handlers/handler_oauth2_authorization_consent_core.go
- internal/handlers/handler_firstfactor_password.go
- cmd/authelia/main.go
- internal/middlewares/util.go
- internal/random/cryptographical.go
- internal/handlers/handler_sign_totp_test.go
- internal/totp/totp_test.go
- internal/commands/context.go
- internal/middlewares/timing_attack_delay_test.go
- internal/middlewares/require_auth_test.go
- internal/handlers/handler_session_elevation_test.go
- internal/middlewares/authelia_context_blackbox_test.go
- internal/mocks/authelia_context.go
- internal/handlers/handler_oauth2_device_authorization.go
- internal/oidc/types.go
- internal/middlewares/startup.go
- internal/handlers/handler_authz_test.go
- internal/commands/build_info_test.go
- internal/handlers/handler_sign_password.go
- internal/mocks/duo_api.go
- internal/handlers/handler_firstfactor_passkey.go
- internal/commands/storage_run_test.go
- internal/handlers/handler_authz_authn.go
- internal/handlers/handler_oauth2_wellknown.go
- internal/commands/errors.go
- internal/handlers/handler_oauth2_token.go
- internal/service/file_watcher_test.go
- internal/commands/build_info.go
- internal/handlers/handler_session_elevation.go
- internal/handlers/handler_oauth2_oidc_wellknown.go
- internal/handlers/handler_oauth2_consent.go
- internal/duo/duo.go
- internal/commands/crypto_hash.go
- internal/utils/const_test.go
- internal/commands/debug.go
- experimental/embed/provider/general.go
- internal/handlers/handler_firstfactor_passkey_test.go
- internal/commands/crypto.go
- internal/utils/crypto.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-29T10:47:45.919Z
Learnt from: james-d-elliott
PR: authelia/authelia#10189
File: internal/clock/provider.go:14-15
Timestamp: 2025-08-29T10:47:45.919Z
Learning: The internal/mocks directory does not contain any mock clock implementations. Tests use concrete clock instances like clock.New(), clock.NewFixed(), and direct assignment to mock.Ctx.Providers.Clock instead of generated mocks for the clock.Provider interface.
Applied to files:
internal/handlers/handler_oauth2_authorization_consent_core_test.go
📚 Learning: 2025-08-27T21:37:17.108Z
Learnt from: james-d-elliott
PR: authelia/authelia#10059
File: internal/commands/storage_run.go:23-23
Timestamp: 2025-08-27T21:37:17.108Z
Learning: The Authelia project uses "go.yaml.in/yaml/v4" as their YAML package import path, not the standard "gopkg.in/yaml.v3" or "gopkg.in/yaml.v2". This is used consistently across their codebase.
Applied to files:
internal/commands/storage_run.go
🧬 Code graph analysis (11)
internal/handlers/handler_oauth2_authorization_consent_implicit.go (1)
internal/oidc/session.go (1)
ConsentGrantImplicit(212-217)
internal/handlers/handler_register_totp.go (1)
internal/session/types.go (1)
TOTP(51-58)
internal/server/server_test.go (2)
internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/random/mathematical.go (1)
NewMathematical(13-18)
internal/utils/crypto_test.go (1)
internal/utils/crypto.go (1)
NewX509CertPoolWithFactory(350-398)
internal/duo/duo_test.go (6)
internal/duo/duo.go (1)
NewDuoAPI(15-19)internal/duo/types.go (6)
BaseProvider(15-17)Response(43-49)PreAuthResponse(60-68)Device(32-40)AuthResponse(52-57)Provider(20-24)internal/session/types.go (1)
UserSession(20-48)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)internal/middlewares/types.go (2)
Context(60-69)Providers(40-58)
internal/middlewares/authelia_context.go (5)
internal/middlewares/types.go (2)
AutheliaCtx(29-37)Providers(40-58)internal/clock/provider.go (1)
Provider(10-15)internal/clock/real.go (1)
New(10-12)internal/random/cryptographical.go (1)
New(12-14)internal/server/server.go (1)
New(19-94)
internal/handlers/handler_oauth2_authorization_consent_core_test.go (3)
internal/middlewares/types.go (1)
Providers(40-58)internal/model/oidc.go (1)
OAuth2ConsentSession(254-276)internal/model/uuid.go (1)
NullUUID(29-31)
internal/duo/types.go (2)
internal/middlewares/types.go (1)
Context(60-69)internal/session/types.go (1)
UserSession(20-48)
internal/service/sever_test.go (5)
internal/middlewares/util.go (1)
NewProvidersBasic(76-81)internal/templates/types.go (1)
Templates(10-14)internal/server/server.go (1)
New(19-94)internal/middlewares/types.go (1)
Providers(40-58)internal/metrics/prometheus.go (1)
NewPrometheus(12-18)
internal/middlewares/types.go (4)
internal/clock/provider.go (1)
Provider(10-15)internal/service/provider.go (2)
Provider(13-28)Context(46-52)internal/model/types.go (1)
IP(41-43)internal/oidc/types.go (1)
Context(212-221)
internal/commands/acl_test.go (1)
internal/authorization/types.go (3)
Subject(49-54)Object(67-73)RuleMatchResult(100-112)
⏰ 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). (2)
- GitHub Check: Analyze (go)
- GitHub Check: StepSecurity Harden-Runner
🔇 Additional comments (24)
internal/clock/fixed.go (1)
5-7: JWT time-func import wired right—nice and tight, fool.Clean addition to support provider-scoped JWT parsing time. I pity the fool who hardcodes global time.
internal/handlers/handler_oauth2_authorization_consent_core_test.go (2)
217-217: Clock via Providers: that’s the way, sucka.Switching to mock.Ctx.Providers.Clock aligns with the provider refactor and the learnings; deterministic and future-proof.
Also applies to: 379-379, 719-719, 1021-1021, 1358-1358
877-877: ExpiresAt derived from provider clock—on point.Using mock.Ctx.Providers.Clock.Now() keeps tests consistent with runtime wiring. I like that discipline.
Also applies to: 916-916, 1005-1005, 1237-1237
internal/commands/acl_test.go (4)
17-25: Sanity checks for command constructors—good hustle.Non-nil assertions keep regressions out. Simple and effective.
204-205: Default-policy messaging updated—reads clear.Good user-facing copy; no confusion about ALL requests. Keep it crisp.
296-338: “Maybe match” scenario covered—smart case, sucka.Validates fallback to default when nothing fully applies. Solid guard against logic regressions.
345-347: runAccessControlCheck no-error path—clean.Asserting NoError then content keeps behavior precise without overspecifying formatting.
internal/utils/crypto_test.go (1)
26-33: LGTM on nil-factory error path, sucka!Solid negative-path test with exact error assertion. I pity the fool who doesn’t cover this case.
internal/server/server_test.go (1)
142-145: Clean providers setup with deterministic-friendly Random overrideUsing NewProvidersBasic then swapping in random.NewMathematical() is clear and test-friendly. Looks good, fool.
internal/handlers/handler_register_totp.go (1)
114-114: Clock access via ctx.GetClock() is the right moveUsing the provider clock for Expires, validation, and CreatedAt improves testability and consistency. I pity the fool who hardcodes time.
Also applies to: 183-183, 193-193
internal/commands/util_test.go (1)
4-4: Handy test factory for system cert poolSimple mock with clear semantics. Tight and effective, sucka.
Also applies to: 16-23
internal/handlers/handler_oauth2_authorization_consent_implicit.go (1)
79-79: Swapping to ctx.GetClock().Now() across consent flow is spot onTime sourcing is consistent and injectable. That’s how you keep tests tough, fool.
Also applies to: 90-90, 92-92, 149-149, 151-151
internal/utils/types.go (1)
31-39: X509 cert-pool factory looks solid, fool.Interface + default impl are clean and testable. No blockers.
internal/service/sever_test.go (2)
19-26: Initialize providers via constructor — good move.Using middlewares.NewProvidersBasic() ensures Clock/Random aren’t nil. Solid.
Also applies to: 61-68
108-127: Keep testCtx aligned with service.Context
testCtx currently implements only service.Context; if ProvisionServer begins requiring middlewares.ServiceContext (with GetClock/GetRandom), update testCtx to satisfy the new interface.internal/duo/types.go (2)
61-68: PreAuthResponse field additions LGTM.New fields use clear JSON tags and won’t break decoding for old payloads.
20-24: Ensure all duo.Provider implementations and mocks use middlewares.Context
I pity the fool who doesn’t verify each Call, PreAuthCall, and AuthCall compiles with the new signature—no lingering context.Context!internal/duo/duo_test.go (1)
456-462: LGTM: lazy-init providers.Clock/Random lazy-init looks correct and thread-safe for tests. No complaints here.
Also applies to: 464-470
internal/commands/storage_run.go (3)
153-161: LGTM: cache delete helper.Wrapper cleanly delegates and prints a clear success message. Solid.
1422-1440: LGTM: service-context TOTP generation.Good move using
ctx.GetClock()/ctx.GetRandom()withtotp.NewContext. Deterministic and testable.
1768-1772: No action required: GetRandom always returns a non-nil provider
Verified that CmdCtx uses NewProvidersBasic (random.New()), AutheliaCtx and embed ctx lazily init with random.New(), and all test contexts supply a default or lazy-init RNG. I pity the fool who thinks GetRandom can be nil!experimental/embed/context.go (1)
113-119: LGTM: nil-guarded Clock/Random.Solid lazy init. No fools returning nil providers on your watch.
Also applies to: 121-127
internal/middlewares/authelia_context.go (2)
620-622: LGTM: simple, direct logger accessor.Clean and clear, sucka.
626-629: Remove deep copy suggestion—config is never mutated
Shallow copy suffices as all usages of GetConfiguration() only read fields; no code mutates returned config.
| assert.EqualError(t, err, "failed to load trusted certificates: could not import certificate file.pem, could not import certificate file2.pem") | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Deflake: don’t assert full error order when reading dirs.
Directory iteration order isn’t guaranteed; this assertion can flake on CI.
Apply this diff:
- assert.EqualError(t, err, "failed to load trusted certificates: could not import certificate file.pem, could not import certificate file2.pem")
+ require.Error(t, err)
+ msg := err.Error()
+ assert.Contains(t, msg, "failed to load trusted certificates")
+ assert.Contains(t, msg, "file.pem")
+ assert.Contains(t, msg, "file2.pem")🤖 Prompt for AI Agents
In internal/commands/context_test.go around lines 84-85, the test currently
asserts the exact error string which depends on directory iteration order and
can flake; change the assertion to not depend on ordering by checking the error
is non-nil and that its message contains both expected substrings (e.g., "could
not import certificate file.pem" and "could not import certificate file2.pem")
using separate contains assertions or a combined check that both substrings
exist in err.Error().
| warns, errs = ctx.LoadProviders() | ||
| assert.Empty(t, warns) | ||
| require.Len(t, errs, 2) | ||
|
|
||
| assert.EqualError(t, errs[0], fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file.pem"))) | ||
| assert.EqualError(t, errs[1], fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file2.pem"))) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Deflake permission-denied assertions, fool.
Maintain the count but avoid relying on slice order; compare as sets.
Apply this diff:
- assert.Empty(t, warns)
- require.Len(t, errs, 2)
-
- assert.EqualError(t, errs[0], fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file.pem")))
- assert.EqualError(t, errs[1], fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file2.pem")))
+ assert.Empty(t, warns)
+ require.Len(t, errs, 2)
+ got := []string{errs[0].Error(), errs[1].Error()}
+ want := []string{
+ fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file.pem")),
+ fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file2.pem")),
+ }
+ assert.ElementsMatch(t, want, got)📝 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.
| warns, errs = ctx.LoadProviders() | |
| assert.Empty(t, warns) | |
| require.Len(t, errs, 2) | |
| assert.EqualError(t, errs[0], fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file.pem"))) | |
| assert.EqualError(t, errs[1], fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file2.pem"))) | |
| } | |
| warns, errs = ctx.LoadProviders() | |
| assert.Empty(t, warns) | |
| require.Len(t, errs, 2) | |
| got := []string{errs[0].Error(), errs[1].Error()} | |
| want := []string{ | |
| fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file.pem")), | |
| fmt.Sprintf("error occurred trying to read certificate: open %s: permission denied", filepath.Join(dir, "file2.pem")), | |
| } | |
| assert.ElementsMatch(t, want, got) | |
| } |
🤖 Prompt for AI Agents
In internal/commands/context_test.go around lines 145 to 151, the test currently
asserts exact errors by index which flakes due to slice ordering; keep the
require.Len(t, errs, 2) check but replace the two indexed assert.EqualError
calls with a set-style comparison: build the two expected error strings (using
filepath.Join(dir, "file.pem") and filepath.Join(dir, "file2.pem")) and assert
that the actual error messages form the same set (e.g., collect errs' Error()
strings and compare with the expected slice via assert.ElementsMatch or by using
a map/set comparison) so the test no longer depends on slice order.
| //gitleaks:allo // This is not an actual secret. | ||
| EncryptionKey: "authelia-test-key-not-a-secret-authelia-test-key-not-a-secret", | ||
| Local: &schema.StorageLocal{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix gitleaks directive typo, sucka.
gitleaks:allo won’t silence scanners. Use gitleaks:allow.
Apply this diff:
- //gitleaks:allo // This is not an actual secret.
+ // gitleaks:allow This is not a secret; test-only value.
EncryptionKey: "authelia-test-key-not-a-secret-authelia-test-key-not-a-secret",📝 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.
| //gitleaks:allo // This is not an actual secret. | |
| EncryptionKey: "authelia-test-key-not-a-secret-authelia-test-key-not-a-secret", | |
| Local: &schema.StorageLocal{ | |
| // gitleaks:allow This is not a secret; test-only value. | |
| EncryptionKey: "authelia-test-key-not-a-secret-authelia-test-key-not-a-secret", | |
| Local: &schema.StorageLocal{ |
🤖 Prompt for AI Agents
In internal/commands/context_test.go around lines 161 to 163, the gitleaks
directive is misspelled as "gitleaks:allo" which won't silence the scanner;
change it to "gitleaks:allow" so the directive is recognized, keeping the rest
of the comment and the EncryptionKey value intact.
| func NewTestCtx(ip net.IP) *TestCtx { | ||
| logger, hook := test.NewNullLogger() | ||
|
|
||
| ctx := &TestCtx{ | ||
| ip: ip, | ||
| logger: logger.WithFields(map[string]any{}), | ||
| hook: hook, | ||
| Context: context.Background(), | ||
| } | ||
|
|
||
| return ctx | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Drop the dead hook; keep it lean.
That hook ain’t used anywhere, fool. Nuke the field and stop capturing it in the constructor.
func NewTestCtx(ip net.IP) *TestCtx {
- logger, hook := test.NewNullLogger()
+ logger, _ := test.NewNullLogger()
ctx := &TestCtx{
ip: ip,
logger: logger.WithFields(map[string]any{}),
- hook: hook,
Context: context.Background(),
}
@@
type TestCtx struct {
ip net.IP
logger *logrus.Entry
- hook *test.Hook
-
providers middlewares.Providers
context.Context
}Also applies to: 446-454
🤖 Prompt for AI Agents
In internal/duo/duo_test.go around lines 433-444 (and also apply the same change
for 446-454), remove the unused 'hook' capture: delete the hook field from the
TestCtx struct, stop assigning the returned hook from test.NewNullLogger() in
NewTestCtx, and construct the logger without capturing the hook (e.g., call
test.NewNullLogger() and only keep the logger). Remove any hook-related
fields/assignments and unused imports so the test context stays lean.
| type Context interface { | ||
| GetLogger() *logrus.Entry | ||
| GetProviders() Providers | ||
| GetConfiguration() *schema.Configuration | ||
| GetClock() (clock clock.Provider) | ||
| GetRandom() (random random.Provider) | ||
| GetLogger() (logger *logrus.Entry) | ||
| GetProviders() (providers Providers) | ||
| GetConfiguration() (config *schema.Configuration) | ||
| RemoteIP() (ip net.IP) | ||
|
|
||
| context.Context | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
Context/ServiceContext expansion — prove AutheliaCtx satisfies them, fool.
These interfaces require getters and embed context.Context. Ensure AutheliaCtx implements all methods (GetClock/GetRandom/GetLogger/GetProviders/GetConfiguration/RemoteIP) somewhere (e.g., authelia_context.go) and that it embeds or wraps context.
Run:
If missing, add the methods. Example stub (in authelia_context.go):
func (a *AutheliaCtx) GetClock() clock.Provider { return a.Providers.Clock }
func (a *AutheliaCtx) GetRandom() random.Provider { return a.Providers.Random }
func (a *AutheliaCtx) GetLogger() *logrus.Entry { return a.Logger }
func (a *AutheliaCtx) GetProviders() Providers { return a.Providers }
func (a *AutheliaCtx) GetConfiguration() *schema.Configuration { return &a.Configuration }
func (a *AutheliaCtx) RemoteIP() net.IP { return a.RequestCtx.RemoteIP() }Also applies to: 71-79
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check AutheliaCtx method set
rg -nP 'func\s+\(\s*\*?AutheliaCtx\s*\)\s+Get(Clock|Random|Logger|Providers|Configuration|RemoteIP)\s*\(' internal -n
# Compile-time assert patterns
rg -nP 'var\s+_+\s*Context\s*=\s*\(\*\s*AutheliaCtx\s*\)\(nil\)' internal -n || trueLength of output: 139
Add missing AutheliaCtx methods and interface assertion, fool
- Define on
*AutheliaCtx:GetClock,GetRandom,GetLogger,GetProviders,GetConfigurationandRemoteIP(e.g., inauthelia_context.go) - Add at package level:
var _ Context = (*AutheliaCtx)(nil)
I pity the fool who ships without these!
🤖 Prompt for AI Agents
In internal/middlewares/types.go around lines 60 to 69, the Context interface
methods GetClock, GetRandom, GetLogger, GetProviders, GetConfiguration and
RemoteIP are missing implementations on *AutheliaCtx; add these receiver methods
(e.g., in a new or existing authelia_context.go) with correct return types
matching the interface signatures and ensure they read from the underlying
AutheliaCtx fields, and add the package-level assertion var _ Context =
(*AutheliaCtx)(nil) to guarantee compile-time conformance.
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Chores
Tests