From e58e969cce1dfb7aceebd6effe6037ed8c45fe31 Mon Sep 17 00:00:00 2001 From: "Jose I. Paris" Date: Tue, 24 Mar 2026 09:55:50 +0100 Subject: [PATCH 1/3] fix codeql SAST warning Signed-off-by: Jose I. Paris --- app/controlplane/internal/service/auth.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/controlplane/internal/service/auth.go b/app/controlplane/internal/service/auth.go index 21794c91d..60f10a24b 100644 --- a/app/controlplane/internal/service/auth.go +++ b/app/controlplane/internal/service/auth.go @@ -434,7 +434,15 @@ func generateUserJWT(userID, passphrase string, expiration time.Duration) (strin } func setOauthCookie(w http.ResponseWriter, name, value string) { - http.SetCookie(w, &http.Cookie{Name: name, Value: value, Path: "/", Expires: time.Now().Add(10 * time.Minute)}) + http.SetCookie(w, &http.Cookie{ + Name: name, + Value: value, + Path: "/", + Expires: time.Now().Add(10 * time.Minute), + HttpOnly: true, + Secure: true, + SameSite: http.SameSiteLaxMode, + }) } func generateAndLogDevUser(userUC *biz.UserUseCase, log *log.Helper, authConfig *conf.Auth) error { From 3774b55265dacfd1fc0f4fe951a810cce3882fe0 Mon Sep 17 00:00:00 2001 From: "Jose I. Paris" Date: Tue, 24 Mar 2026 12:29:25 +0100 Subject: [PATCH 2/3] fix: disable Secure cookie flag in development mode Set HttpOnly and SameSite on OAuth cookies to address CodeQL SAST findings. Secure flag is conditionally set based on server.Version to avoid breaking local development over HTTP. Signed-off-by: Jose I. Paris --- app/controlplane/cmd/wire.go | 3 ++- app/controlplane/cmd/wire_gen.go | 6 ++++-- app/controlplane/internal/service/auth.go | 16 +++++++++------- app/controlplane/internal/service/service.go | 5 ++++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/app/controlplane/cmd/wire.go b/app/controlplane/cmd/wire.go index c3ac9787c..53b92d8aa 100644 --- a/app/controlplane/cmd/wire.go +++ b/app/controlplane/cmd/wire.go @@ -1,5 +1,5 @@ // -// Copyright 2024-2025 The Chainloop Authors. +// Copyright 2024-2026 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -50,6 +50,7 @@ func wireApp(*conf.Bootstrap, credentials.ReaderWriter, log.Logger, sdk.Availabl wire.Bind(new(biz.CASClient), new(*biz.CASClientUseCase)), serviceOpts, wire.Value([]biz.CASClientOpts{}), + wire.Value(service.Version(server.Version)), wire.FieldsOf(new(*conf.Bootstrap), "Server", "Auth", "Data", "CasServer", "ReferrerSharedIndex", "Onboarding", "PrometheusIntegration", "PolicyProviders", "NatsServer", "FederatedAuthentication"), wire.FieldsOf(new(*conf.Data), "Database"), dispatcher.New, diff --git a/app/controlplane/cmd/wire_gen.go b/app/controlplane/cmd/wire_gen.go index 843d62557..badae2e86 100644 --- a/app/controlplane/cmd/wire_gen.go +++ b/app/controlplane/cmd/wire_gen.go @@ -146,7 +146,8 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l v5 := serviceOpts(logger, authzUseCase, projectUseCase, groupUseCase) workflowService := service.NewWorkflowService(workflowUseCase, workflowContractUseCase, projectUseCase, organizationUseCase, userUseCase, v5...) confServer := bootstrap.Server - authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, orgInvitationUseCase, auth, confServer, auditorUseCase, v5...) + version := _wireVersionValue + authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, orgInvitationUseCase, auth, confServer, auditorUseCase, version, v5...) if err != nil { cleanup() return nil, nil, err @@ -319,7 +320,8 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l } var ( - _wireValue = []biz.CASClientOpts{} + _wireValue = []biz.CASClientOpts{} + _wireVersionValue = service.Version(server.Version) ) // wire.go: diff --git a/app/controlplane/internal/service/auth.go b/app/controlplane/internal/service/auth.go index 60f10a24b..27ccddb1c 100644 --- a/app/controlplane/internal/service/auth.go +++ b/app/controlplane/internal/service/auth.go @@ -1,5 +1,5 @@ // -// Copyright 2024-2025 The Chainloop Authors. +// Copyright 2024-2026 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -114,9 +114,10 @@ type AuthService struct { orgInvitesUseCase *biz.OrgInvitationUseCase AuthURLs *AuthURLs auditorUseCase *biz.AuditorUseCase + version Version } -func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, inviteUC *biz.OrgInvitationUseCase, authConfig *conf.Auth, serverConfig *conf.Server, auc *biz.AuditorUseCase, opts ...NewOpt) (*AuthService, error) { +func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, inviteUC *biz.OrgInvitationUseCase, authConfig *conf.Auth, serverConfig *conf.Server, auc *biz.AuditorUseCase, version Version, opts ...NewOpt) (*AuthService, error) { oidcConfig := authConfig.GetOidc() if oidcConfig == nil { return nil, errors.New("oauth configuration missing") @@ -151,6 +152,7 @@ func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC membershipUseCase: mUC, orgInvitesUseCase: inviteUC, auditorUseCase: auc, + version: version, }, nil } @@ -223,13 +225,13 @@ func loginHandler(svc *AuthService, w http.ResponseWriter, r *http.Request) *oau // Store a random string to check it in the oauth callback state := base64.URLEncoding.EncodeToString(b) - setOauthCookie(w, cookieOauthStateName, state) + svc.setOauthCookie(w, cookieOauthStateName, state) // Store the final destination where the auth token will be pushed to, i.e the CLI - setOauthCookie(w, cookieCallback, r.URL.Query().Get(oauth.QueryParamCallback)) + svc.setOauthCookie(w, cookieCallback, r.URL.Query().Get(oauth.QueryParamCallback)) // Wether the token should be short lived or not - setOauthCookie(w, cookieLongLived, r.URL.Query().Get(oauth.QueryParamLongLived)) + svc.setOauthCookie(w, cookieLongLived, r.URL.Query().Get(oauth.QueryParamLongLived)) authorizationURI := svc.authenticator.AuthCodeURL(state) @@ -433,14 +435,14 @@ func generateUserJWT(userID, passphrase string, expiration time.Duration) (strin return b.GenerateJWT(userID) } -func setOauthCookie(w http.ResponseWriter, name, value string) { +func (svc *AuthService) setOauthCookie(w http.ResponseWriter, name, value string) { http.SetCookie(w, &http.Cookie{ Name: name, Value: value, Path: "/", Expires: time.Now().Add(10 * time.Minute), HttpOnly: true, - Secure: true, + Secure: string(svc.version) != "dev", SameSite: http.SameSiteLaxMode, }) } diff --git a/app/controlplane/internal/service/service.go b/app/controlplane/internal/service/service.go index a035414e2..61072d160 100644 --- a/app/controlplane/internal/service/service.go +++ b/app/controlplane/internal/service/service.go @@ -1,5 +1,5 @@ // -// Copyright 2023-2025 The Chainloop Authors. +// Copyright 2023-2026 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -36,6 +36,9 @@ import ( "google.golang.org/grpc/status" ) +// Version is a named type for the application version string, used for Wire injection. +type Version string + // ProviderSet is service providers. var ProviderSet = wire.NewSet( NewWorkflowService, From 7d5476491f02fa1189c10bb15c0a49384208cb8b Mon Sep 17 00:00:00 2001 From: "Jose I. Paris" Date: Tue, 24 Mar 2026 12:36:37 +0100 Subject: [PATCH 3/3] Revert "fix: disable Secure cookie flag in development mode" This reverts commit 3774b55265dacfd1fc0f4fe951a810cce3882fe0. Signed-off-by: Jose I. Paris --- app/controlplane/cmd/wire.go | 3 +-- app/controlplane/cmd/wire_gen.go | 6 ++---- app/controlplane/internal/service/auth.go | 16 +++++++--------- app/controlplane/internal/service/service.go | 5 +---- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/app/controlplane/cmd/wire.go b/app/controlplane/cmd/wire.go index 53b92d8aa..c3ac9787c 100644 --- a/app/controlplane/cmd/wire.go +++ b/app/controlplane/cmd/wire.go @@ -1,5 +1,5 @@ // -// Copyright 2024-2026 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -50,7 +50,6 @@ func wireApp(*conf.Bootstrap, credentials.ReaderWriter, log.Logger, sdk.Availabl wire.Bind(new(biz.CASClient), new(*biz.CASClientUseCase)), serviceOpts, wire.Value([]biz.CASClientOpts{}), - wire.Value(service.Version(server.Version)), wire.FieldsOf(new(*conf.Bootstrap), "Server", "Auth", "Data", "CasServer", "ReferrerSharedIndex", "Onboarding", "PrometheusIntegration", "PolicyProviders", "NatsServer", "FederatedAuthentication"), wire.FieldsOf(new(*conf.Data), "Database"), dispatcher.New, diff --git a/app/controlplane/cmd/wire_gen.go b/app/controlplane/cmd/wire_gen.go index badae2e86..843d62557 100644 --- a/app/controlplane/cmd/wire_gen.go +++ b/app/controlplane/cmd/wire_gen.go @@ -146,8 +146,7 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l v5 := serviceOpts(logger, authzUseCase, projectUseCase, groupUseCase) workflowService := service.NewWorkflowService(workflowUseCase, workflowContractUseCase, projectUseCase, organizationUseCase, userUseCase, v5...) confServer := bootstrap.Server - version := _wireVersionValue - authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, orgInvitationUseCase, auth, confServer, auditorUseCase, version, v5...) + authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, orgInvitationUseCase, auth, confServer, auditorUseCase, v5...) if err != nil { cleanup() return nil, nil, err @@ -320,8 +319,7 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l } var ( - _wireValue = []biz.CASClientOpts{} - _wireVersionValue = service.Version(server.Version) + _wireValue = []biz.CASClientOpts{} ) // wire.go: diff --git a/app/controlplane/internal/service/auth.go b/app/controlplane/internal/service/auth.go index 27ccddb1c..60f10a24b 100644 --- a/app/controlplane/internal/service/auth.go +++ b/app/controlplane/internal/service/auth.go @@ -1,5 +1,5 @@ // -// Copyright 2024-2026 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -114,10 +114,9 @@ type AuthService struct { orgInvitesUseCase *biz.OrgInvitationUseCase AuthURLs *AuthURLs auditorUseCase *biz.AuditorUseCase - version Version } -func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, inviteUC *biz.OrgInvitationUseCase, authConfig *conf.Auth, serverConfig *conf.Server, auc *biz.AuditorUseCase, version Version, opts ...NewOpt) (*AuthService, error) { +func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, inviteUC *biz.OrgInvitationUseCase, authConfig *conf.Auth, serverConfig *conf.Server, auc *biz.AuditorUseCase, opts ...NewOpt) (*AuthService, error) { oidcConfig := authConfig.GetOidc() if oidcConfig == nil { return nil, errors.New("oauth configuration missing") @@ -152,7 +151,6 @@ func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC membershipUseCase: mUC, orgInvitesUseCase: inviteUC, auditorUseCase: auc, - version: version, }, nil } @@ -225,13 +223,13 @@ func loginHandler(svc *AuthService, w http.ResponseWriter, r *http.Request) *oau // Store a random string to check it in the oauth callback state := base64.URLEncoding.EncodeToString(b) - svc.setOauthCookie(w, cookieOauthStateName, state) + setOauthCookie(w, cookieOauthStateName, state) // Store the final destination where the auth token will be pushed to, i.e the CLI - svc.setOauthCookie(w, cookieCallback, r.URL.Query().Get(oauth.QueryParamCallback)) + setOauthCookie(w, cookieCallback, r.URL.Query().Get(oauth.QueryParamCallback)) // Wether the token should be short lived or not - svc.setOauthCookie(w, cookieLongLived, r.URL.Query().Get(oauth.QueryParamLongLived)) + setOauthCookie(w, cookieLongLived, r.URL.Query().Get(oauth.QueryParamLongLived)) authorizationURI := svc.authenticator.AuthCodeURL(state) @@ -435,14 +433,14 @@ func generateUserJWT(userID, passphrase string, expiration time.Duration) (strin return b.GenerateJWT(userID) } -func (svc *AuthService) setOauthCookie(w http.ResponseWriter, name, value string) { +func setOauthCookie(w http.ResponseWriter, name, value string) { http.SetCookie(w, &http.Cookie{ Name: name, Value: value, Path: "/", Expires: time.Now().Add(10 * time.Minute), HttpOnly: true, - Secure: string(svc.version) != "dev", + Secure: true, SameSite: http.SameSiteLaxMode, }) } diff --git a/app/controlplane/internal/service/service.go b/app/controlplane/internal/service/service.go index 61072d160..a035414e2 100644 --- a/app/controlplane/internal/service/service.go +++ b/app/controlplane/internal/service/service.go @@ -1,5 +1,5 @@ // -// Copyright 2023-2026 The Chainloop Authors. +// Copyright 2023-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -36,9 +36,6 @@ import ( "google.golang.org/grpc/status" ) -// Version is a named type for the application version string, used for Wire injection. -type Version string - // ProviderSet is service providers. var ProviderSet = wire.NewSet( NewWorkflowService,