From 918991cc64a39d969f2d0d49876633b79aa0d738 Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Fri, 8 Nov 2024 14:47:33 +0100 Subject: [PATCH] gopherpolicy: remove explicit YAML dependency Callers can still support policy.yaml files, but they have to explicitly provide a YAML parser function of their choice. --- gopherpolicy/pkg.go | 21 ++++++++++++++++++--- liquidapi/liquidapi.go | 7 ++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/gopherpolicy/pkg.go b/gopherpolicy/pkg.go index 95694d5..1413d5f 100644 --- a/gopherpolicy/pkg.go +++ b/gopherpolicy/pkg.go @@ -28,13 +28,13 @@ import ( "fmt" "net/http" "os" + "strings" "time" policy "github.com/databus23/goslo.policy" "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/openstack" "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens" - "gopkg.in/yaml.v2" "github.com/sapcc/go-bits/logg" ) @@ -72,13 +72,28 @@ type TokenValidator struct { } // LoadPolicyFile creates v.Enforcer from the given policy file. -func (v *TokenValidator) LoadPolicyFile(path string) error { +// +// The second argument must be set to `yaml.Unmarshal` if you want to support +// policy.yaml files. This explicit dependency injection slot allows you to choose +// whether to use gopkg.in/yaml.v2 or gopkg.in/yaml.v3 or anything else. +// +// If `yamlUnmarshal` is given as nil, `json.Unmarshal` from the standard +// library will be used, so only policy.json files will be understood. +func (v *TokenValidator) LoadPolicyFile(path string, yamlUnmarshal func(in []byte, out any) error) error { + unmarshal := yamlUnmarshal + if yamlUnmarshal == nil { + unmarshal = json.Unmarshal + if strings.HasSuffix(path, ".yaml") { + return fmt.Errorf("LoadPolicyFile cannot parse %s because YAML support is not available", path) + } + } + bytes, err := os.ReadFile(path) if err != nil { return err // no fmt.Errorf() necessary, errors from package os are already very descriptive } var rules map[string]string - err = yaml.Unmarshal(bytes, &rules) + err = unmarshal(bytes, &rules) if err != nil { return fmt.Errorf("while parsing structure of %s: %w", path, err) } diff --git a/liquidapi/liquidapi.go b/liquidapi/liquidapi.go index 7cfc4dc..ddab0bd 100644 --- a/liquidapi/liquidapi.go +++ b/liquidapi/liquidapi.go @@ -84,6 +84,11 @@ type RunOpts struct { // the Logic instance to supply configuration to it, before Init() is called. TakesConfiguration bool + // If set, when the runtime loads its oslo.policy from $LIQUID_POLICY_PATH, + // YAML will be supported in addition to JSON. This is an explicit dependency + // injection slot to allow the caller to choose their YAML library. + YAMLUnmarshal func(in []byte, out any) error + // How often the runtime will call BuildServiceInfo() to refresh the // ServiceInfo of the liquid. The zero value can be used for liquids with // static ServiceInfo; no polling will be performed then. @@ -177,7 +182,7 @@ func Run(ctx context.Context, logic Logic, opts RunOpts) error { if err != nil { return err } - err = tv.LoadPolicyFile(policyPath) + err = tv.LoadPolicyFile(policyPath, opts.YAMLUnmarshal) if err != nil { return err }