From e615b2c544d00042ec12913af61938233e7f4941 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Trivino Date: Sat, 14 Mar 2026 22:56:08 +0100 Subject: [PATCH 1/2] fix(cas): move CORS config under server.http in proto and Helm template The CORS configuration was placed at the server level instead of under server.http, causing it to not be loaded correctly in production. Signed-off-by: Miguel Martinez Trivino --- app/artifact-cas/configs/config.devel.yaml | 6 +- app/artifact-cas/internal/conf/conf.pb.go | 124 +++++++++--------- app/artifact-cas/internal/conf/conf.proto | 10 +- app/artifact-cas/internal/server/http.go | 2 +- deployment/chainloop/Chart.yaml | 2 +- .../chainloop/templates/cas/configmap.yaml | 30 ++--- 6 files changed, 87 insertions(+), 87 deletions(-) diff --git a/app/artifact-cas/configs/config.devel.yaml b/app/artifact-cas/configs/config.devel.yaml index 8496219ab..654b0519b 100644 --- a/app/artifact-cas/configs/config.devel.yaml +++ b/app/artifact-cas/configs/config.devel.yaml @@ -8,6 +8,9 @@ server: # Timeouts for http downloads # grpc downloads/uploads don't require this because they don't have timeouts timeout: 300s + # cors: + # allow_origins: + # - "http://localhost:3000" grpc: addr: 0.0.0.0:9001 # Some unary RPCs are slow, so we need to increase the timeout @@ -18,9 +21,6 @@ server: # private_key: "../../devel/devkeys/selfsigned/cas.key" http_metrics: addr: 0.0.0.0:5001 - # cors: - # allow_origins: - # - "http://localhost:3000" credentials_service: # we will check that we can read there diff --git a/app/artifact-cas/internal/conf/conf.pb.go b/app/artifact-cas/internal/conf/conf.pb.go index 6033422df..008df29a5 100644 --- a/app/artifact-cas/internal/conf/conf.pb.go +++ b/app/artifact-cas/internal/conf/conf.pb.go @@ -113,9 +113,7 @@ type Server struct { // GRPC API endpoint Grpc *Server_GRPC `protobuf:"bytes,2,opt,name=grpc,proto3" json:"grpc,omitempty"` // hHTTP server where the prometheus metrics will get exposed - HttpMetrics *Server_HTTP `protobuf:"bytes,3,opt,name=http_metrics,json=httpMetrics,proto3" json:"http_metrics,omitempty"` - // CORS configuration for the HTTP download endpoint - Cors *Server_CORS `protobuf:"bytes,4,opt,name=cors,proto3" json:"cors,omitempty"` + HttpMetrics *Server_HTTP `protobuf:"bytes,3,opt,name=http_metrics,json=httpMetrics,proto3" json:"http_metrics,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -171,13 +169,6 @@ func (x *Server) GetHttpMetrics() *Server_HTTP { return nil } -func (x *Server) GetCors() *Server_CORS { - if x != nil { - return x.Cors - } - return nil -} - type Auth struct { state protoimpl.MessageState `protogen:"open.v1"` // Public key used to verify the received JWT token @@ -333,29 +324,27 @@ func (x *Bootstrap_Observability_Sentry) GetEnvironment() string { return "" } -type Server_HTTP struct { +type Server_CORS struct { state protoimpl.MessageState `protogen:"open.v1"` - Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` - Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` - Timeout *durationpb.Duration `protobuf:"bytes,3,opt,name=timeout,proto3" json:"timeout,omitempty"` + AllowOrigins []string `protobuf:"bytes,1,rep,name=allow_origins,json=allowOrigins,proto3" json:"allow_origins,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *Server_HTTP) Reset() { - *x = Server_HTTP{} +func (x *Server_CORS) Reset() { + *x = Server_CORS{} mi := &file_conf_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Server_HTTP) String() string { +func (x *Server_CORS) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Server_HTTP) ProtoMessage() {} +func (*Server_CORS) ProtoMessage() {} -func (x *Server_HTTP) ProtoReflect() protoreflect.Message { +func (x *Server_CORS) ProtoReflect() protoreflect.Message { mi := &file_conf_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -367,53 +356,43 @@ func (x *Server_HTTP) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Server_HTTP.ProtoReflect.Descriptor instead. -func (*Server_HTTP) Descriptor() ([]byte, []int) { +// Deprecated: Use Server_CORS.ProtoReflect.Descriptor instead. +func (*Server_CORS) Descriptor() ([]byte, []int) { return file_conf_proto_rawDescGZIP(), []int{1, 0} } -func (x *Server_HTTP) GetNetwork() string { - if x != nil { - return x.Network - } - return "" -} - -func (x *Server_HTTP) GetAddr() string { - if x != nil { - return x.Addr - } - return "" -} - -func (x *Server_HTTP) GetTimeout() *durationpb.Duration { +func (x *Server_CORS) GetAllowOrigins() []string { if x != nil { - return x.Timeout + return x.AllowOrigins } return nil } -type Server_CORS struct { - state protoimpl.MessageState `protogen:"open.v1"` - AllowOrigins []string `protobuf:"bytes,1,rep,name=allow_origins,json=allowOrigins,proto3" json:"allow_origins,omitempty"` +type Server_HTTP struct { + state protoimpl.MessageState `protogen:"open.v1"` + Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` + Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` + Timeout *durationpb.Duration `protobuf:"bytes,3,opt,name=timeout,proto3" json:"timeout,omitempty"` + // CORS configuration for the HTTP download endpoint + Cors *Server_CORS `protobuf:"bytes,4,opt,name=cors,proto3" json:"cors,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *Server_CORS) Reset() { - *x = Server_CORS{} +func (x *Server_HTTP) Reset() { + *x = Server_HTTP{} mi := &file_conf_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Server_CORS) String() string { +func (x *Server_HTTP) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Server_CORS) ProtoMessage() {} +func (*Server_HTTP) ProtoMessage() {} -func (x *Server_CORS) ProtoReflect() protoreflect.Message { +func (x *Server_HTTP) ProtoReflect() protoreflect.Message { mi := &file_conf_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -425,14 +404,35 @@ func (x *Server_CORS) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Server_CORS.ProtoReflect.Descriptor instead. -func (*Server_CORS) Descriptor() ([]byte, []int) { +// Deprecated: Use Server_HTTP.ProtoReflect.Descriptor instead. +func (*Server_HTTP) Descriptor() ([]byte, []int) { return file_conf_proto_rawDescGZIP(), []int{1, 1} } -func (x *Server_CORS) GetAllowOrigins() []string { +func (x *Server_HTTP) GetNetwork() string { if x != nil { - return x.AllowOrigins + return x.Network + } + return "" +} + +func (x *Server_HTTP) GetAddr() string { + if x != nil { + return x.Addr + } + return "" +} + +func (x *Server_HTTP) GetTimeout() *durationpb.Duration { + if x != nil { + return x.Timeout + } + return nil +} + +func (x *Server_HTTP) GetCors() *Server_CORS { + if x != nil { + return x.Cors } return nil } @@ -573,18 +573,18 @@ const file_conf_proto_rawDesc = "" + "\x06sentry\x18\x01 \x01(\v2\x1f.Bootstrap.Observability.SentryR\x06sentry\x1a<\n" + "\x06Sentry\x12\x10\n" + "\x03dsn\x18\x01 \x01(\tR\x03dsn\x12 \n" + - "\venvironment\x18\x02 \x01(\tR\venvironment\"\x99\x04\n" + + "\venvironment\x18\x02 \x01(\tR\venvironment\"\x9a\x04\n" + "\x06Server\x12 \n" + "\x04http\x18\x01 \x01(\v2\f.Server.HTTPR\x04http\x12 \n" + "\x04grpc\x18\x02 \x01(\v2\f.Server.GRPCR\x04grpc\x12/\n" + - "\fhttp_metrics\x18\x03 \x01(\v2\f.Server.HTTPR\vhttpMetrics\x12 \n" + - "\x04cors\x18\x04 \x01(\v2\f.Server.CORSR\x04cors\x1ai\n" + + "\fhttp_metrics\x18\x03 \x01(\v2\f.Server.HTTPR\vhttpMetrics\x1a+\n" + + "\x04CORS\x12#\n" + + "\rallow_origins\x18\x01 \x03(\tR\fallowOrigins\x1a\x8b\x01\n" + "\x04HTTP\x12\x18\n" + "\anetwork\x18\x01 \x01(\tR\anetwork\x12\x12\n" + "\x04addr\x18\x02 \x01(\tR\x04addr\x123\n" + - "\atimeout\x18\x03 \x01(\v2\x19.google.protobuf.DurationR\atimeout\x1a+\n" + - "\x04CORS\x12#\n" + - "\rallow_origins\x18\x01 \x03(\tR\fallowOrigins\x1aH\n" + + "\atimeout\x18\x03 \x01(\v2\x19.google.protobuf.DurationR\atimeout\x12 \n" + + "\x04cors\x18\x04 \x01(\v2\f.Server.CORSR\x04cors\x1aH\n" + "\x03TLS\x12 \n" + "\vcertificate\x18\x01 \x01(\tR\vcertificate\x12\x1f\n" + "\vprivate_key\x18\x02 \x01(\tR\n" + @@ -618,8 +618,8 @@ var file_conf_proto_goTypes = []any{ (*Auth)(nil), // 2: Auth (*Bootstrap_Observability)(nil), // 3: Bootstrap.Observability (*Bootstrap_Observability_Sentry)(nil), // 4: Bootstrap.Observability.Sentry - (*Server_HTTP)(nil), // 5: Server.HTTP - (*Server_CORS)(nil), // 6: Server.CORS + (*Server_CORS)(nil), // 5: Server.CORS + (*Server_HTTP)(nil), // 6: Server.HTTP (*Server_TLS)(nil), // 7: Server.TLS (*Server_GRPC)(nil), // 8: Server.GRPC (*v1.Credentials)(nil), // 9: credentials.v1.Credentials @@ -630,12 +630,12 @@ var file_conf_proto_depIdxs = []int32{ 2, // 1: Bootstrap.auth:type_name -> Auth 3, // 2: Bootstrap.observability:type_name -> Bootstrap.Observability 9, // 3: Bootstrap.credentials_service:type_name -> credentials.v1.Credentials - 5, // 4: Server.http:type_name -> Server.HTTP + 6, // 4: Server.http:type_name -> Server.HTTP 8, // 5: Server.grpc:type_name -> Server.GRPC - 5, // 6: Server.http_metrics:type_name -> Server.HTTP - 6, // 7: Server.cors:type_name -> Server.CORS - 4, // 8: Bootstrap.Observability.sentry:type_name -> Bootstrap.Observability.Sentry - 10, // 9: Server.HTTP.timeout:type_name -> google.protobuf.Duration + 6, // 6: Server.http_metrics:type_name -> Server.HTTP + 4, // 7: Bootstrap.Observability.sentry:type_name -> Bootstrap.Observability.Sentry + 10, // 8: Server.HTTP.timeout:type_name -> google.protobuf.Duration + 5, // 9: Server.HTTP.cors:type_name -> Server.CORS 10, // 10: Server.GRPC.timeout:type_name -> google.protobuf.Duration 7, // 11: Server.GRPC.tls_config:type_name -> Server.TLS 12, // [12:12] is the sub-list for method output_type diff --git a/app/artifact-cas/internal/conf/conf.proto b/app/artifact-cas/internal/conf/conf.proto index ff07c967c..5a50eef9b 100644 --- a/app/artifact-cas/internal/conf/conf.proto +++ b/app/artifact-cas/internal/conf/conf.proto @@ -38,13 +38,15 @@ message Bootstrap { } message Server { + message CORS { + repeated string allow_origins = 1; + } message HTTP { string network = 1; string addr = 2; google.protobuf.Duration timeout = 3; - } - message CORS { - repeated string allow_origins = 1; + // CORS configuration for the HTTP download endpoint + CORS cors = 4; } message TLS { // path to certificate and private key @@ -63,8 +65,6 @@ message Server { GRPC grpc = 2; // hHTTP server where the prometheus metrics will get exposed HTTP http_metrics = 3; - // CORS configuration for the HTTP download endpoint - CORS cors = 4; } message Auth { diff --git a/app/artifact-cas/internal/server/http.go b/app/artifact-cas/internal/server/http.go index 56b0a902d..3a0189a66 100644 --- a/app/artifact-cas/internal/server/http.go +++ b/app/artifact-cas/internal/server/http.go @@ -66,7 +66,7 @@ func NewHTTPServer(c *conf.Server, authConf *conf.Auth, downloadSvc *service.Dow srv := http.NewServer(opts...) downloadHandler := middlewares_http.AuthFromQueryParam(loadPublicKey(rawKey), claimsFunc(), casJWT.SigningMethod, downloadSvc) - srv.Handle(service.DownloadPath, CORSMiddleware(c.GetCors().GetAllowOrigins(), downloadHandler)) + srv.Handle(service.DownloadPath, CORSMiddleware(c.GetHttp().GetCors().GetAllowOrigins(), downloadHandler)) api.RegisterStatusServiceHTTPServer(srv, service.NewStatusService(Version, providers)) return srv, nil } diff --git a/deployment/chainloop/Chart.yaml b/deployment/chainloop/Chart.yaml index 5a66e45dc..9d742bafc 100644 --- a/deployment/chainloop/Chart.yaml +++ b/deployment/chainloop/Chart.yaml @@ -7,7 +7,7 @@ description: Chainloop is an open source software supply chain control plane, a type: application # Bump the patch (not minor, not major) version on each change in the Chart Source code -version: 1.343.0 +version: 1.343.1 # Do not update appVersion, this is handled automatically by the release process appVersion: v1.82.0 diff --git a/deployment/chainloop/templates/cas/configmap.yaml b/deployment/chainloop/templates/cas/configmap.yaml index fef2c170e..ae17ba695 100644 --- a/deployment/chainloop/templates/cas/configmap.yaml +++ b/deployment/chainloop/templates/cas/configmap.yaml @@ -20,6 +20,21 @@ data: # Timeouts for http downloads # grpc downloads/uploads don't require this because they don't have timeouts timeout: 300s + {{- if .Values.cas.allowedOrigins }} + cors: + allow_origins: + {{- if kindIs "string" .Values.cas.allowedOrigins }} + {{- range splitList "," .Values.cas.allowedOrigins }} + {{- if (trim .) }} + - {{ trim . | quote }} + {{- end }} + {{- end }} + {{- else }} + {{- range .Values.cas.allowedOrigins }} + - {{ . | quote }} + {{- end }} + {{- end }} + {{- end }} grpc: {{- if include "cas.tls-secret-name" . }} tls_config: @@ -31,18 +46,3 @@ data: timeout: 5s http_metrics: addr: "0.0.0.0:{{ .Values.cas.containerPorts.metrics}}" - {{- if .Values.cas.allowedOrigins }} - cors: - allow_origins: - {{- if kindIs "string" .Values.cas.allowedOrigins }} - {{- range splitList "," .Values.cas.allowedOrigins }} - {{- if (trim .) }} - - {{ trim . | quote }} - {{- end }} - {{- end }} - {{- else }} - {{- range .Values.cas.allowedOrigins }} - - {{ . | quote }} - {{- end }} - {{- end }} - {{- end }} From 8a93594bd217d20e6f60252c4c3221435888f69d Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Sat, 14 Mar 2026 23:05:22 +0100 Subject: [PATCH 2/2] fix(cas): allow CORS field deletion in buf breaking check The CORS field was moved from Server to Server.HTTP in the proto, which triggers buf's FIELD_NO_DELETE rule. Add an ignore_only exception for this internal config proto. Signed-off-by: Miguel Martinez Entire-Checkpoint: 657a990875a2 --- buf.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/buf.yaml b/buf.yaml index 7a9c5041b..1375c638d 100644 --- a/buf.yaml +++ b/buf.yaml @@ -31,6 +31,9 @@ modules: except: - EXTENSION_NO_DELETE - FIELD_SAME_DEFAULT + ignore_only: + FIELD_NO_DELETE: + - app/artifact-cas/internal/conf/conf.proto - path: app/controlplane/api lint: use: