11//
2- // Copyright 2024 The Chainloop Authors.
2+ // Copyright 2024-2025 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,11 +27,58 @@ import (
2727 "golang.org/x/exp/maps"
2828)
2929
30- // Rego policy checker for chainloop attestations and materials
31- type Rego struct {
32- // OperatingMode defines the mode of running the policy engine
30+ // Engine policy checker for chainloop attestations and materials
31+ type Engine struct {
32+ // operatingMode defines the mode of running the policy engine
3333 // by restricting or not the operations allowed by the compiler
34- OperatingMode EnvironmentMode
34+ operatingMode EnvironmentMode
35+ // allowedNetworkDomains is a list of network domains that are allowed for the compiler to access
36+ // when using http.send built-in function
37+ allowedNetworkDomains []string
38+ }
39+
40+ type EngineOption func (* newEngineOptions )
41+
42+ func WithOperatingMode (mode EnvironmentMode ) EngineOption {
43+ return func (e * newEngineOptions ) {
44+ e .operatingMode = mode
45+ }
46+ }
47+
48+ func WithAllowedNetworkDomains (domains ... string ) EngineOption {
49+ return func (e * newEngineOptions ) {
50+ e .allowedNetworkDomains = domains
51+ }
52+ }
53+
54+ type newEngineOptions struct {
55+ operatingMode EnvironmentMode
56+ allowedNetworkDomains []string
57+ }
58+
59+ // NewEngine creates a new policy engine with the given options
60+ // default operating mode is EnvironmentModeRestrictive
61+ // default allowed network domains are www.chainloop.dev and www.cisa.gov
62+ // user provided allowed network domains are appended to the base ones
63+ func NewEngine (opts ... EngineOption ) * Engine {
64+ options := & newEngineOptions {
65+ operatingMode : EnvironmentModeRestrictive ,
66+ }
67+
68+ for _ , opt := range opts {
69+ opt (options )
70+ }
71+
72+ var baseAllowedNetworkDomains = []string {
73+ "www.chainloop.dev" ,
74+ "www.cisa.gov" ,
75+ }
76+
77+ return & Engine {
78+ operatingMode : options .operatingMode ,
79+ // append base allowed network domains to the user provided ones
80+ allowedNetworkDomains : append (baseAllowedNetworkDomains , options .allowedNetworkDomains ... ),
81+ }
3582}
3683
3784// EnvironmentMode defines the mode of running the policy engine
@@ -55,17 +102,10 @@ var builtinFuncNotAllowed = []*ast.Builtin{
55102 ast .Trace ,
56103}
57104
58- // allowedNetworkDomains is a list of network domains that are allowed for the compiler to access
59- // when using http.send built-in function
60- var allowedNetworkDomains = []string {
61- "www.chainloop.dev" ,
62- "www.cisa.gov" ,
63- }
64-
65105// Force interface
66- var _ engine.PolicyEngine = (* Rego )(nil )
106+ var _ engine.PolicyEngine = (* Engine )(nil )
67107
68- func (r * Rego ) Verify (ctx context.Context , policy * engine.Policy , input []byte , args map [string ]any ) (* engine.EvaluationResult , error ) {
108+ func (r * Engine ) Verify (ctx context.Context , policy * engine.Policy , input []byte , args map [string ]any ) (* engine.EvaluationResult , error ) {
69109 policyString := string (policy .Source )
70110 parsedModule , err := ast .ParseModule (policy .Name , policyString )
71111 if err != nil {
@@ -107,23 +147,23 @@ func (r *Rego) Verify(ctx context.Context, policy *engine.Policy, input []byte,
107147 // Function to execute the query with appropriate parameters
108148 executeQuery := func (rule string , strict bool ) error {
109149 if strict {
110- res , err = queryRego (ctx , rule , parsedModule , regoInput , regoFunc , rego .Capabilities (r .OperatingMode . Capabilities ()), rego .StrictBuiltinErrors (true ))
150+ res , err = queryRego (ctx , rule , parsedModule , regoInput , regoFunc , rego .Capabilities (r .Capabilities ()), rego .StrictBuiltinErrors (true ))
111151 } else {
112- res , err = queryRego (ctx , rule , parsedModule , regoInput , regoFunc , rego .Capabilities (r .OperatingMode . Capabilities ()))
152+ res , err = queryRego (ctx , rule , parsedModule , regoInput , regoFunc , rego .Capabilities (r .Capabilities ()))
113153 }
114154 return err
115155 }
116156
117157 // Try the main rule first
118- if err := executeQuery (mainRule , r .OperatingMode == EnvironmentModeRestrictive ); err != nil {
158+ if err := executeQuery (mainRule , r .operatingMode == EnvironmentModeRestrictive ); err != nil {
119159 return nil , err
120160 }
121161
122162 // If res is nil, it means that the rule hasn't been found
123163 // TODO: Remove when this deprecated rule is not used anymore
124164 if res == nil {
125165 // Try with the deprecated main rule
126- if err := executeQuery (deprecatedRule , r .OperatingMode == EnvironmentModeRestrictive ); err != nil {
166+ if err := executeQuery (deprecatedRule , r .operatingMode == EnvironmentModeRestrictive ); err != nil {
127167 return nil , err
128168 }
129169
@@ -230,11 +270,11 @@ func queryRego(ctx context.Context, ruleName string, parsedModule *ast.Module, o
230270
231271// Capabilities returns the capabilities of the environment based on the mode of operation
232272// defaulting to EnvironmentModeRestrictive if not provided.
233- func (em EnvironmentMode ) Capabilities () * ast.Capabilities {
273+ func (r * Engine ) Capabilities () * ast.Capabilities {
234274 capabilities := ast .CapabilitiesForThisVersion ()
235275 var enabledBuiltin []* ast.Builtin
236276
237- switch em {
277+ switch r . operatingMode {
238278 case EnvironmentModeRestrictive :
239279 // Copy all builtins functions
240280 localBuiltIns := make (map [string ]* ast.Builtin , len (ast .BuiltinMap ))
@@ -252,7 +292,7 @@ func (em EnvironmentMode) Capabilities() *ast.Capabilities {
252292 }
253293
254294 // Allow specific network domains
255- capabilities .AllowNet = allowedNetworkDomains
295+ capabilities .AllowNet = r . allowedNetworkDomains
256296
257297 case EnvironmentModePermissive :
258298 enabledBuiltin = capabilities .Builtins
0 commit comments