Skip to content

Commit 2d70b6c

Browse files
feat(policies): allow gate=false to override org-wide blocking (#2777)
Signed-off-by: Matías Insaurralde <matias@chainloop.dev>
1 parent c93625c commit 2d70b6c

File tree

13 files changed

+149
-31
lines changed

13 files changed

+149
-31
lines changed

.github/workflows/lint.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ jobs:
5656
token: ${{ secrets.buf_api_token }}
5757
breaking: true
5858
pr_comment: false
59+
exclude_imports: true
5960

6061
lint-dagger-module:
6162
runs-on: ubuntu-latest

app/cli/cmd/attestation_push.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func newAttestationPushCmd() *cobra.Command {
6464
Annotations: map[string]string{
6565
useAPIToken: "true",
6666
},
67-
RunE: func(cmd *cobra.Command, args []string) error {
67+
RunE: func(cmd *cobra.Command, _ []string) error {
6868
info, err := executableInfo()
6969
if err != nil {
7070
return fmt.Errorf("getting executable information: %w", err)
@@ -163,8 +163,7 @@ func newAttestationPushCmd() *cobra.Command {
163163
const exceptionFlagName = "exception-bypass-policy-check"
164164

165165
var (
166-
ErrBlockedByPolicyViolation = fmt.Errorf("the operator requires all policies to pass before continuing, please fix them and try again or temporarily bypass the policy check using --%s", exceptionFlagName)
167-
exceptionBypassPolicyCheck = fmt.Sprintf("Attention: You have opted to bypass the policy enforcement check and an operator has been notified of this exception.\nPlease make sure you are back on track with the policy evaluations and remove the --%s as soon as possible.", exceptionFlagName)
166+
exceptionBypassPolicyCheck = fmt.Sprintf("Attention: You have opted to bypass the policy enforcement check and an operator has been notified of this exception.\nPlease make sure you are back on track with the policy evaluations and remove the --%s as soon as possible.", exceptionFlagName)
168167
)
169168

170169
type GateError struct {
@@ -202,9 +201,6 @@ func validatePolicyEnforcement(status *action.AttestationStatusResult, bypassPol
202201
return nil
203202
}
204203

205-
if status.HasPolicyViolations {
206-
return ErrBlockedByPolicyViolation
207-
}
208204
}
209205

210206
return nil

app/cli/cmd/attestation_push_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,25 @@ func TestValidatePolicyEnforcement(t *testing.T) {
6767
require.ErrorAs(t, err, &gateErr)
6868
require.Equal(t, "cdx-fresh", gateErr.PolicyName)
6969
})
70+
71+
t.Run("does not block when strategy is enforced and policy is explicitly not gated", func(t *testing.T) {
72+
status := &action.AttestationStatusResult{
73+
PolicyEvaluations: map[string][]*action.PolicyEvaluation{
74+
"materials": {
75+
{
76+
Name: "cdx-fresh",
77+
Gate: false,
78+
Violations: []*action.PolicyViolation{
79+
{Message: "policy violation"},
80+
},
81+
},
82+
},
83+
},
84+
HasPolicyViolations: true,
85+
MustBlockOnPolicyViolations: true,
86+
}
87+
88+
err := validatePolicyEnforcement(status, false)
89+
require.NoError(t, err)
90+
})
7091
}

app/cli/main.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2023-2025 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.
@@ -100,9 +100,6 @@ func errorInfo(err error, logger zerolog.Logger) (string, int) {
100100
logger.Debug().Msg("GracefulErrorExit enabled (exitCode 0). If you want to disable it set --graceful-exit=false")
101101
exitCode = 0
102102
}
103-
case errors.Is(err, cmd.ErrBlockedByPolicyViolation):
104-
// default exit code for policy violations
105-
exitCode = 3
106103
case errors.As(err, &gateErr):
107104
// exit code for gate errors
108105
exitCode = 4

app/controlplane/api/gen/frontend/workflowcontract/v1/crafting_schema.ts

Lines changed: 11 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/gen/jsonschema/workflowcontract.v1.PolicyAttachment.jsonschema.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/gen/jsonschema/workflowcontract.v1.PolicyAttachment.schema.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/workflowcontract/v1/crafting_schema.pb.go

Lines changed: 12 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/workflowcontract/v1/crafting_schema.proto

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,11 @@ message PolicyAttachment {
236236
}
237237
}];
238238

239-
// If true, the policy will act as a gate, returning an error code if the policy fails
240-
bool gate = 7;
239+
// Controls whether policy violations act as a gate.
240+
// - true: policy violations are blocking for this policy
241+
// - false: policy violations are non-blocking for this policy
242+
// - unset: inherit organization-level default behavior
243+
optional bool gate = 7;
241244

242245
message MaterialSelector {
243246
// material name

buf.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ modules:
4949
except:
5050
- EXTENSION_NO_DELETE
5151
- FIELD_SAME_DEFAULT
52+
- FIELD_SAME_CARDINALITY
5253
- path: app/controlplane/internal/conf
5354
lint:
5455
use:

0 commit comments

Comments
 (0)