Skip to content

Commit 8843a00

Browse files
perf(protovalidate): cache validator instead of constructing per call (#3156)
1 parent 5647691 commit 8843a00

7 files changed

Lines changed: 16 additions & 56 deletions

File tree

app/controlplane/pkg/biz/casclient.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,7 @@ func (uc *CASClientUseCase) IsReady(ctx context.Context) (bool, error) {
167167
return false, errors.New("missing CAS server configuration")
168168
}
169169

170-
v, err := protovalidate.New()
171-
if err != nil {
172-
return false, fmt.Errorf("failed to create validator: %w", err)
173-
}
174-
175-
if err := v.Validate(uc.casServerConf); err != nil {
170+
if err := protovalidate.Validate(uc.casServerConf); err != nil {
176171
return false, fmt.Errorf("invalid CAS client configuration: %w", err)
177172
}
178173

app/controlplane/pkg/unmarshal/unmarshal.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2024-2025 The Chainloop Authors.
2+
// Copyright 2024-2026 The Chainloop Authors.
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -56,17 +56,11 @@ func (v *validatorAdapter) Validate(msg proto.Message) error {
5656
return v.validator.Validate(msg)
5757
}
5858

59-
func FromRaw(body []byte, format RawFormat, out proto.Message, doValidate bool) error {
60-
var validator protovalidate.Validator
61-
var err error
62-
63-
if doValidate {
64-
validator, err = protovalidate.New()
65-
if err != nil {
66-
return fmt.Errorf("could not create validator: %w", err)
67-
}
68-
}
59+
// yamlValidator wraps the protovalidate global Validator for use with protoyaml,
60+
// initialised once and reused across calls.
61+
var yamlValidator = &validatorAdapter{validator: protovalidate.GlobalValidator}
6962

63+
func FromRaw(body []byte, format RawFormat, out proto.Message, doValidate bool) error {
7064
switch format {
7165
case RawFormatJSON:
7266
if err := protojson.Unmarshal(body, out); err != nil {
@@ -76,7 +70,7 @@ func FromRaw(body []byte, format RawFormat, out proto.Message, doValidate bool)
7670
// protoyaml allows validating the contract while unmarshalling
7771
yamlOpts := protoyaml.UnmarshalOptions{}
7872
if doValidate {
79-
yamlOpts.Validator = &validatorAdapter{validator: validator}
73+
yamlOpts.Validator = yamlValidator
8074
}
8175

8276
if err := yamlOpts.Unmarshal(body, out); err != nil {
@@ -97,9 +91,8 @@ func FromRaw(body []byte, format RawFormat, out proto.Message, doValidate bool)
9791
return fmt.Errorf("unsupported format: %s", format)
9892
}
9993

100-
if validator != nil {
101-
err = validator.Validate(out)
102-
if err != nil {
94+
if doValidate {
95+
if err := protovalidate.Validate(out); err != nil {
10396
return fmt.Errorf("error validating raw message: %w", err)
10497
}
10598
}

pkg/attestation/crafter/api/attestation/v1/crafting_state_validations.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2024-2025 The Chainloop Authors.
2+
// Copyright 2024-2026 The Chainloop Authors.
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -27,15 +27,10 @@ import (
2727
// ValidateComplete makes sure that the crafting state has been completed
2828
// before it gets passed to the renderer
2929
func (state *CraftingState) ValidateComplete(dryRun bool) error {
30-
validator, err := protovalidate.New()
31-
if err != nil {
32-
return fmt.Errorf("could not create validator: %w", err)
33-
}
34-
3530
// We do not want to validate the schema of the state if we are just doing a dry run
3631
// since it's known to not to contain the workflow metadata information
3732
if !dryRun {
38-
if err := validator.Validate(state); err != nil {
33+
if err := protovalidate.Validate(state); err != nil {
3934
return fmt.Errorf("invalid crafting state: %w", err)
4035
}
4136
}

pkg/attestation/crafter/crafter.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ type Crafter struct {
6767
stateManager StateManager
6868
// Authn is used to authenticate with the OCI registry
6969
ociRegistryAuth authn.Keychain
70-
validator protovalidate.Validator
7170

7271
// attestation client is used to load chainloop policies
7372
attClient v1.AttestationServiceClient
@@ -166,19 +165,13 @@ func (c *Crafter) RunCollectors(ctx context.Context, attestationID string, casBa
166165
func NewCrafter(stateManager StateManager, attClient v1.AttestationServiceClient, opts ...NewOpt) (*Crafter, error) {
167166
noopLogger := zerolog.Nop()
168167

169-
validator, err := protovalidate.New()
170-
if err != nil {
171-
return nil, fmt.Errorf("creating proto validator: %w", err)
172-
}
173-
174168
cw, _ := os.Getwd()
175169
c := &Crafter{
176170
Logger: &noopLogger,
177171
workingDir: cw,
178172
stateManager: stateManager,
179173
// By default we authenticate with the current user's keychain (i.e ~/.docker/config.json)
180174
ociRegistryAuth: authn.DefaultKeychain,
181-
validator: validator,
182175
attClient: attClient,
183176
}
184177

@@ -684,7 +677,7 @@ func (c *Crafter) addMaterial(ctx context.Context, m *schemaapi.CraftingSchema_M
684677
}
685678
}
686679

687-
if err := c.validator.Validate(mt); err != nil {
680+
if err := protovalidate.Validate(mt); err != nil {
688681
return nil, fmt.Errorf("validation error: %w", err)
689682
}
690683

pkg/attestation/crafter/materials/materials.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,7 @@ func Craft(ctx context.Context, materialSchema *schemaapi.CraftingSchema_Materia
224224
var crafter Craftable
225225
var err error
226226

227-
validator, err := protovalidate.New()
228-
if err != nil {
229-
return nil, fmt.Errorf("could not create validator: %w", err)
230-
}
231-
232-
if err := validator.Validate(materialSchema); err != nil {
227+
if err := protovalidate.Validate(materialSchema); err != nil {
233228
return nil, fmt.Errorf("validating material: %w", err)
234229
}
235230

pkg/credentials/manager/manager.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2023 The Chainloop Authors.
2+
// Copyright 2023-2026 The Chainloop Authors.
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -56,12 +56,7 @@ func NewFromConfig(conf *api.Credentials, role credentials.Role, l log.Logger) (
5656
}
5757

5858
func validateConfig(msg protoreflect.ProtoMessage) error {
59-
validator, err := protovalidate.New()
60-
if err != nil {
61-
return fmt.Errorf("creating validator: %w", err)
62-
}
63-
64-
return validator.Validate(msg)
59+
return protovalidate.Validate(msg)
6560
}
6661

6762
func newAzureKBManager(conf *api.Credentials_AzureKeyVault, prefix string, r credentials.Role, l log.Logger) (*azurekv.Manager, error) {

pkg/policies/policies.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -705,15 +705,9 @@ func (pv *PolicyVerifier) getLoader(attachment *v1.PolicyAttachment) (Loader, er
705705
}
706706

707707
func validateResource(m proto.Message) error {
708-
validator, err := protovalidate.New()
709-
if err != nil {
708+
if err := protovalidate.Validate(m); err != nil {
710709
return fmt.Errorf("validating policy spec: %w", err)
711710
}
712-
err = validator.Validate(m)
713-
if err != nil {
714-
return fmt.Errorf("validating policy spec: %w", err)
715-
}
716-
717711
return nil
718712
}
719713

0 commit comments

Comments
 (0)