Skip to content

Commit 2a27c57

Browse files
committed
chore: resolve merge conficts
2 parents 801e704 + f58649c commit 2a27c57

6 files changed

Lines changed: 54 additions & 131 deletions

File tree

app/cli/cmd/policy_develop_lint.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func newPolicyDevelopLintCmd() *cobra.Command {
6565
}
6666

6767
cmd.Flags().StringVarP(&policyPath, "policy", "p", "policy.yaml", "Path to policy file")
68-
cmd.Flags().BoolVar(&format, "format", false, "Auto-format file with opa fmt")
68+
cmd.Flags().BoolVar(&format, "format", false, "Auto-format standalone policy rego files with opa fmt (embedded policies not supported)")
6969
cmd.Flags().StringVar(&regalConfig, "regal-config", "", "Path to custom regal config (Default: https://github.com/chainloop-dev/chainloop/tree/main/app/cli/internal/policydevel/.regal.yaml)")
7070
return cmd
7171
}

app/cli/documentation/cli-reference.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2973,7 +2973,7 @@ chainloop policy develop lint [flags]
29732973
Options
29742974

29752975
```
2976-
--format Auto-format file with opa fmt
2976+
--format Auto-format standalone policy rego files with opa fmt (embedded policies not supported)
29772977
-h, --help help for lint
29782978
-p, --policy string Path to policy file (default "policy.yaml")
29792979
--regal-config string Path to custom regal config (Default: https://github.com/chainloop-dev/chainloop/tree/main/app/cli/internal/policydevel/.regal.yaml)

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)

app/cli/internal/policydevel/lint.go

Lines changed: 1 addition & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package policydevel
1717

1818
import (
19-
"bytes"
2019
"context"
2120
"embed"
2221
"errors"
@@ -123,8 +122,7 @@ func Lookup(absPath, config string, format bool) (*PolicyToLint, error) {
123122
return policy, nil
124123
}
125124

126-
// Loads referenced rego files from all YAML files in the policy
127-
// Loads referenced rego files from all YAML files in the policy
125+
// Loads referenced rego files from YAML files in the policy
128126
func (p *PolicyToLint) loadReferencedRegoFiles(baseDir string) error {
129127
seen := make(map[string]struct{})
130128
for _, yamlFile := range p.YAMLFiles {
@@ -184,77 +182,12 @@ func (p *PolicyToLint) processFile(filePath string) error {
184182
}
185183

186184
func (p *PolicyToLint) Validate() {
187-
// Validate all YAML files (including their embedded policies)
188-
for _, yamlFile := range p.YAMLFiles {
189-
p.validateYAMLFile(yamlFile)
190-
}
191-
192185
// Validate standalone rego files
193186
for _, regoFile := range p.RegoFiles {
194187
p.validateRegoFile(regoFile)
195188
}
196189
}
197190

198-
func (p *PolicyToLint) validateYAMLFile(file *File) {
199-
var policy v1.Policy
200-
if err := unmarshal.FromRaw(file.Content, unmarshal.RawFormatYAML, &policy, true); err != nil {
201-
p.AddError(file.Path, "failed to parse/validate policy", 0)
202-
return
203-
}
204-
205-
p.processEmbeddedPolicies(&policy, file)
206-
207-
// Update policy file with formatted content
208-
if p.Format {
209-
var root yaml.Node
210-
if err := yaml.Unmarshal(file.Content, &root); err != nil {
211-
p.AddError(file.Path, "failed to parse YAML", 0)
212-
return
213-
}
214-
215-
if err := p.updateEmbeddedRegoInYAML(file, &root); err != nil {
216-
p.AddError(file.Path, fmt.Sprintf("failed to update embedded Rego: %v", err), 0)
217-
return
218-
}
219-
220-
var buf bytes.Buffer
221-
enc := yaml.NewEncoder(&buf)
222-
enc.SetIndent(2)
223-
defer enc.Close()
224-
225-
if err := enc.Encode(&root); err != nil {
226-
p.AddError(file.Path, err.Error(), 0)
227-
return
228-
}
229-
230-
outYAML := buf.Bytes()
231-
if err := os.WriteFile(file.Path, outYAML, 0600); err != nil {
232-
p.AddError(file.Path, err.Error(), 0)
233-
} else {
234-
if err := os.WriteFile(file.Path, outYAML, 0600); err != nil {
235-
p.AddError(file.Path, fmt.Sprintf("failed to save updated file: %v", err), 0)
236-
} else {
237-
file.Content = outYAML
238-
}
239-
}
240-
}
241-
}
242-
243-
func (p *PolicyToLint) processEmbeddedPolicies(pa *v1.Policy, file *File) {
244-
for idx, spec := range pa.Spec.Policies {
245-
if regoSrc := spec.GetEmbedded(); regoSrc != "" {
246-
formatted := p.validateAndFormatRego(
247-
regoSrc,
248-
fmt.Sprintf("%s:(embedded #%d)", file.Path, idx+1),
249-
)
250-
251-
if p.Format && formatted != regoSrc {
252-
spec.Source = &v1.PolicySpecV2_Embedded{Embedded: formatted}
253-
}
254-
}
255-
}
256-
}
257-
258191
func (p *PolicyToLint) validateRegoFile(file *File) {
259192
original := string(file.Content)
260193
formatted := p.validateAndFormatRego(original, file.Path)
@@ -435,64 +368,6 @@ func (p *PolicyToLint) loadDefaultConfig() (*config.Config, error) {
435368
return &cfg, nil
436369
}
437370

438-
// Updates the embedded rego policies in a YAML file
439-
// Manual update required due to yaml.marshal limitations
440-
func (p *PolicyToLint) updateEmbeddedRegoInYAML(file *File, rootNode *yaml.Node) error {
441-
if rootNode.Kind != yaml.DocumentNode || len(rootNode.Content) == 0 {
442-
return fmt.Errorf("unexpected YAML root structure")
443-
}
444-
445-
doc := rootNode.Content[0]
446-
if doc.Kind != yaml.MappingNode {
447-
return fmt.Errorf("expected mapping node at document root")
448-
}
449-
450-
// Locate spec policy node
451-
var specNode *yaml.Node
452-
for i := 0; i < len(doc.Content)-1; i += 2 {
453-
if doc.Content[i].Value == "spec" && doc.Content[i+1].Kind == yaml.MappingNode {
454-
specNode = doc.Content[i+1]
455-
break
456-
}
457-
}
458-
if specNode == nil {
459-
return fmt.Errorf("spec node not found")
460-
}
461-
462-
// Locate policies node within spec
463-
var policiesNode *yaml.Node
464-
for i := 0; i < len(specNode.Content)-1; i += 2 {
465-
if specNode.Content[i].Value == "policies" && specNode.Content[i+1].Kind == yaml.SequenceNode {
466-
policiesNode = specNode.Content[i+1]
467-
break
468-
}
469-
}
470-
if policiesNode == nil {
471-
return fmt.Errorf("spec.policies node not found")
472-
}
473-
474-
// Iterate over and update each rego policy
475-
for _, policy := range policiesNode.Content {
476-
if policy.Kind != yaml.MappingNode {
477-
continue
478-
}
479-
480-
for i := 0; i < len(policy.Content)-1; i += 2 {
481-
key := policy.Content[i]
482-
val := policy.Content[i+1]
483-
484-
if key.Value == "embedded" && val.Kind == yaml.ScalarNode {
485-
formatted := p.validateAndFormatRego(val.Value, file.Path)
486-
if formatted != val.Value {
487-
val.Value = formatted
488-
}
489-
}
490-
}
491-
}
492-
493-
return nil
494-
}
495-
496371
// Creates a mapping from line numbers to Rego rule names
497372
func (p *PolicyToLint) buildRegoRuleMap(regoSrc string) map[int]string {
498373
ruleMap := make(map[int]string)

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)