Skip to content

Commit f58649c

Browse files
authored
feat(policy-devel): allow rego print statement output (#2373)
Signed-off-by: Sylwester Piskozub <[email protected]>
1 parent 6ae620d commit f58649c

File tree

3 files changed

+51
-3
lines changed

3 files changed

+51
-3
lines changed

app/cli/internal/policydevel/eval.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ import (
2929
"github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials"
3030
)
3131

32+
const (
33+
enablePrint = true
34+
)
35+
3236
type EvalOptions struct {
3337
PolicyPath string
3438
MaterialKind string
@@ -100,6 +104,7 @@ func verifyMaterial(schema *v1.CraftingSchema, material *v12.Attestation_Materia
100104
}
101105

102106
opts = append(opts, policies.WithIncludeRawData(debug))
107+
opts = append(opts, policies.WithEnablePrint(enablePrint))
103108

104109
v := policies.NewPolicyVerifier(schema, nil, logger, opts...)
105110
policyEvs, err := v.VerifyMaterial(context.Background(), material, materialPath)

pkg/policies/engine/rego/rego.go

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/chainloop-dev/chainloop/pkg/policies/engine"
2525
"github.com/open-policy-agent/opa/ast"
2626
"github.com/open-policy-agent/opa/rego"
27+
"github.com/open-policy-agent/opa/v1/topdown/print"
2728
"golang.org/x/exp/maps"
2829
)
2930

@@ -37,6 +38,8 @@ type Engine struct {
3738
allowedNetworkDomains []string
3839
// includeRawData determines whether to collect raw evaluation data
3940
includeRawData bool
41+
// enablePrint determines whether to enable print statements in rego policies
42+
enablePrint bool
4043
}
4144

4245
type EngineOption func(*newEngineOptions)
@@ -59,10 +62,17 @@ func WithIncludeRawData(include bool) EngineOption {
5962
}
6063
}
6164

65+
func WithEnablePrint(enable bool) EngineOption {
66+
return func(e *newEngineOptions) {
67+
e.enablePrint = enable
68+
}
69+
}
70+
6271
type newEngineOptions struct {
6372
operatingMode EnvironmentMode
6473
allowedNetworkDomains []string
6574
includeRawData bool
75+
enablePrint bool
6676
}
6777

6878
// NewEngine creates a new policy engine with the given options
@@ -88,6 +98,7 @@ func NewEngine(opts ...EngineOption) *Engine {
8898
// append base allowed network domains to the user provided ones
8999
allowedNetworkDomains: append(baseAllowedNetworkDomains, options.allowedNetworkDomains...),
90100
includeRawData: options.includeRawData,
101+
enablePrint: options.enablePrint,
91102
}
92103
}
93104

@@ -112,6 +123,15 @@ var builtinFuncNotAllowed = []*ast.Builtin{
112123
ast.Trace,
113124
}
114125

126+
// Implements the OPA print.Hook interface to capture and output
127+
// print statements from Rego policies during evaluation.
128+
type regoOutputHook struct{}
129+
130+
func (p *regoOutputHook) Print(_ print.Context, msg string) error { //nolint:forbidigo
131+
fmt.Println(msg)
132+
return nil
133+
}
134+
115135
// Force interface
116136
var _ engine.PolicyEngine = (*Engine)(nil)
117137

@@ -156,11 +176,21 @@ func (r *Engine) Verify(ctx context.Context, policy *engine.Policy, input []byte
156176
var res rego.ResultSet
157177
// Function to execute the query with appropriate parameters
158178
executeQuery := func(rule string, strict bool) error {
179+
options := []func(r *rego.Rego){regoInput, regoFunc, rego.Capabilities(r.Capabilities())}
180+
181+
// Add print support if enabled
182+
if r.enablePrint {
183+
options = append(options,
184+
rego.EnablePrintStatements(true),
185+
rego.PrintHook(&regoOutputHook{}),
186+
)
187+
}
188+
159189
if strict {
160-
res, err = queryRego(ctx, rule, regoInput, regoFunc, rego.Capabilities(r.Capabilities()), rego.StrictBuiltinErrors(true))
161-
} else {
162-
res, err = queryRego(ctx, rule, regoInput, regoFunc, rego.Capabilities(r.Capabilities()))
190+
options = append(options, rego.StrictBuiltinErrors(true))
163191
}
192+
193+
res, err = queryRego(ctx, rule, options...)
164194
return err
165195
}
166196

pkg/policies/policies.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,15 @@ type PolicyVerifier struct {
6666
client v13.AttestationServiceClient
6767
allowedHostnames []string
6868
includeRawData bool
69+
enablePrint bool
6970
}
7071

7172
var _ Verifier = (*PolicyVerifier)(nil)
7273

7374
type PolicyVerifierOptions struct {
7475
AllowedHostnames []string
7576
IncludeRawData bool
77+
EnablePrint bool
7678
}
7779

7880
type PolicyVerifierOption func(*PolicyVerifierOptions)
@@ -89,6 +91,12 @@ func WithIncludeRawData(include bool) PolicyVerifierOption {
8991
}
9092
}
9193

94+
func WithEnablePrint(enable bool) PolicyVerifierOption {
95+
return func(o *PolicyVerifierOptions) {
96+
o.EnablePrint = enable
97+
}
98+
}
99+
92100
func NewPolicyVerifier(schema *v1.CraftingSchema, client v13.AttestationServiceClient, logger *zerolog.Logger, opts ...PolicyVerifierOption) *PolicyVerifier {
93101
options := &PolicyVerifierOptions{}
94102
for _, opt := range opts {
@@ -101,6 +109,7 @@ func NewPolicyVerifier(schema *v1.CraftingSchema, client v13.AttestationServiceC
101109
logger: logger,
102110
allowedHostnames: options.AllowedHostnames,
103111
includeRawData: options.IncludeRawData,
112+
enablePrint: options.EnablePrint,
104113
}
105114
}
106115

@@ -349,6 +358,10 @@ func (pv *PolicyVerifier) executeScript(ctx context.Context, script *engine.Poli
349358
engineOpts = append(engineOpts, rego.WithIncludeRawData(true))
350359
}
351360

361+
if pv.enablePrint {
362+
engineOpts = append(engineOpts, rego.WithEnablePrint(true))
363+
}
364+
352365
// verify the policy
353366
ng := rego.NewEngine(engineOpts...)
354367
res, err := ng.Verify(ctx, script, material, getInputArguments(args))

0 commit comments

Comments
 (0)