From 8906b254d37f45cfff7e18c5cc9bd19c5f8236b6 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Thu, 11 Dec 2025 21:37:12 -0800 Subject: [PATCH] policy: move custom functions to separate file Signed-off-by: Tonis Tiigi --- policy/funcs.go | 133 +++++++++++++++++++++++++++++++++++++++++++++ policy/validate.go | 122 ----------------------------------------- 2 files changed, 133 insertions(+), 122 deletions(-) create mode 100644 policy/funcs.go diff --git a/policy/funcs.go b/policy/funcs.go new file mode 100644 index 000000000..98cf26f38 --- /dev/null +++ b/policy/funcs.go @@ -0,0 +1,133 @@ +package policy + +import ( + "encoding/json" + "io" + "log" + + "github.com/moby/buildkit/util/gitutil/gitsign" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/rego" + "github.com/open-policy-agent/opa/v1/types" + "github.com/pkg/errors" +) + +func (p *Policy) initBuiltinFuncs() { + builtinLoadJSON := ®o.Function{ + Name: "load_json", + Decl: types.NewFunction( + types.Args( + types.S, + ), + types.A, + ), + Memoize: true, + } + p.funcs = append(p.funcs, fun{ + decl: builtinLoadJSON, + impl: funcNoInput(rego.Function1(builtinLoadJSON, p.builtinLoadJSONImpl)), + }) + + verifyGitSignature := ®o.Function{ + Name: "verify_git_signature", + Decl: types.NewFunction( + types.Args( + types.S, + ), + types.B, + ), + Memoize: false, // TODO:optimize + } + p.funcs = append(p.funcs, fun{ + decl: verifyGitSignature, + impl: func(s *state) func(*rego.Rego) { + return rego.Function1(verifyGitSignature, func(bctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) { + return p.builtinVerifyGitSignatureImpl(bctx, a, s) + }) + }, + }) +} + +func (p *Policy) builtinVerifyGitSignatureImpl(_ rego.BuiltinContext, a *ast.Term, s *state) (*ast.Term, error) { + inp := s.Input + if inp.Git == nil { + return ast.BooleanTerm(false), nil + } + + if inp.Git.Commit == nil { + s.addUnknown("verify_git_signature") + return ast.BooleanTerm(false), nil + } + + path, ok := a.Value.(ast.String) + if !ok { + return nil, errors.Errorf("load_json: expected string path, got %T", a.Value) + } + + pubkey, err := p.readFile(string(path), 128*1024) + if err != nil { + return nil, err + } + + obj := inp.Git.Commit.obj + if inp.Git.Tag != nil { + obj = inp.Git.Tag.obj + } + + if err := gitsign.VerifySignature(obj, pubkey, &gitsign.VerifyPolicy{ + RejectExpiredKeys: false, + }); err != nil { + log.Printf("git signature verification failed: %+v", err) + return nil, err + } + + return ast.BooleanTerm(true), nil +} + +func (p *Policy) readFile(path string, limit int64) ([]byte, error) { + if p.opt.FS == nil { + return nil, errors.Errorf("no policy FS defined for reading context files") + } + fs, cf, err := p.opt.FS() + if err != nil { + return nil, errors.Wrapf(err, "failed to get policy FS for reading context files") + } + defer cf() + + f, err := fs.Open(path) + if err != nil { + return nil, errors.Wrapf(err, "failed opening file %q", path) + } + defer f.Close() + + rdr := io.LimitReader(f, limit) + data, err := io.ReadAll(rdr) + if err != nil { + return nil, errors.Wrapf(err, "failed reading %q", path) + } + return data, nil +} + +func (p *Policy) builtinLoadJSONImpl(bctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) { + path, ok := a.Value.(ast.String) + if !ok { + return nil, errors.Errorf("load_json: expected string path, got %T", a.Value) + } + + data, err := p.readFile(string(path), 4*1024*1024) + if err != nil { + return nil, err + } + + var v any + if err := json.Unmarshal(data, &v); err != nil { + return nil, errors.Wrapf(err, "load_json: invalid JSON in %q", path) + } + + astVal, err := ast.InterfaceToValue(v) + if err != nil { + return nil, errors.Wrapf(err, "load_json: failed converting JSON from %q", path) + } + + return ast.NewTerm(astVal), nil +} diff --git a/policy/validate.go b/policy/validate.go index a7c7aa58a..133920c8a 100644 --- a/policy/validate.go +++ b/policy/validate.go @@ -3,7 +3,6 @@ package policy import ( "context" "encoding/json" - "io" "io/fs" "log" "net/url" @@ -25,12 +24,10 @@ import ( "github.com/moby/buildkit/sourcepolicy/policysession" "github.com/moby/buildkit/util/gitutil" "github.com/moby/buildkit/util/gitutil/gitobject" - "github.com/moby/buildkit/util/gitutil/gitsign" policyverifier "github.com/moby/policy-helpers" "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/rego" "github.com/open-policy-agent/opa/v1/topdown/print" - "github.com/open-policy-agent/opa/v1/types" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) @@ -123,125 +120,6 @@ func (p *Policy) getVerifier() (*policyverifier.Verifier, error) { return p.verifier, nil } -func (p *Policy) initBuiltinFuncs() { - builtinLoadJSON := ®o.Function{ - Name: "load_json", - Decl: types.NewFunction( - types.Args( - types.S, - ), - types.A, - ), - Memoize: true, - } - p.funcs = append(p.funcs, fun{ - decl: builtinLoadJSON, - impl: funcNoInput(rego.Function1(builtinLoadJSON, p.builtinLoadJSONImpl)), - }) - - verifyGitSignature := ®o.Function{ - Name: "verify_git_signature", - Decl: types.NewFunction( - types.Args( - types.S, - ), - types.B, - ), - Memoize: false, // TODO:optimize - } - p.funcs = append(p.funcs, fun{ - decl: verifyGitSignature, - impl: func(s *state) func(*rego.Rego) { - return rego.Function1(verifyGitSignature, func(bctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) { - return p.builtinVerifyGitSignatureImpl(bctx, a, s) - }) - }, - }) -} - -func (p *Policy) builtinVerifyGitSignatureImpl(_ rego.BuiltinContext, a *ast.Term, s *state) (*ast.Term, error) { - inp := s.Input - if inp.Git == nil { - return ast.BooleanTerm(false), nil - } - - if inp.Git.Commit == nil { - s.addUnknown("verify_git_signature") - return ast.BooleanTerm(false), nil - } - - path, ok := a.Value.(ast.String) - if !ok { - return nil, errors.Errorf("load_json: expected string path, got %T", a.Value) - } - - pubkey, err := p.readFile(string(path), 128*1024) - if err != nil { - return nil, err - } - - obj := inp.Git.Commit.obj - if inp.Git.Tag != nil { - obj = inp.Git.Tag.obj - } - - if err := gitsign.VerifySignature(obj, pubkey, &gitsign.VerifyPolicy{ - RejectExpiredKeys: false, - }); err != nil { - return nil, err - } - - return ast.BooleanTerm(true), nil -} - -func (p *Policy) readFile(path string, limit int64) ([]byte, error) { - if p.opt.FS == nil { - return nil, errors.Errorf("no policy FS defined for reading context files") - } - fs, cf, err := p.opt.FS() - if err != nil { - return nil, errors.Wrapf(err, "failed to get policy FS for reading context files") - } - defer cf() - - f, err := fs.Open(path) - if err != nil { - return nil, errors.Wrapf(err, "failed opening file %q", path) - } - defer f.Close() - - rdr := io.LimitReader(f, limit) - data, err := io.ReadAll(rdr) - if err != nil { - return nil, errors.Wrapf(err, "failed reading %q", path) - } - return data, nil -} - -func (p *Policy) builtinLoadJSONImpl(bctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) { - path, ok := a.Value.(ast.String) - if !ok { - return nil, errors.Errorf("load_json: expected string path, got %T", a.Value) - } - - data, err := p.readFile(string(path), 4*1024*1024) - if err != nil { - return nil, err - } - - var v any - if err := json.Unmarshal(data, &v); err != nil { - return nil, errors.Wrapf(err, "load_json: invalid JSON in %q", path) - } - - astVal, err := ast.InterfaceToValue(v) - if err != nil { - return nil, errors.Wrapf(err, "load_json: failed converting JSON from %q", path) - } - - return ast.NewTerm(astVal), nil -} - func (p *Policy) CheckPolicy(ctx context.Context, req *policysession.CheckPolicyRequest) (*policysession.DecisionResponse, *gwpb.ResolveSourceMetaRequest, error) { var inp Input var unknowns []string