From 6c5bd6ae397055c605e68f9c11054253ed109423 Mon Sep 17 00:00:00 2001 From: Markus Rudy Date: Wed, 31 Jul 2024 16:19:53 +0200 Subject: [PATCH 1/2] cli: move genpolicy into its own package Co-authored-by: Tom Dohrmann Co-authored-by: Paul Meyer <49727155+katexochen@users.noreply.github.com> --- cli/cmd/generate.go | 129 ++---------------- cli/genpolicy/genpolicy.go | 83 +++++++++++ cli/genpolicy/genpolicy_test.go | 79 +++++++++++ cli/genpolicy/logtranslator.go | 65 +++++++++ .../logtranslator_test.go} | 2 +- 5 files changed, 238 insertions(+), 120 deletions(-) create mode 100644 cli/genpolicy/genpolicy.go create mode 100644 cli/genpolicy/genpolicy_test.go create mode 100644 cli/genpolicy/logtranslator.go rename cli/{cmd/generate_test.go => genpolicy/logtranslator_test.go} (99%) diff --git a/cli/cmd/generate.go b/cli/cmd/generate.go index d6e7f0787e..459948a6b7 100644 --- a/cli/cmd/generate.go +++ b/cli/cmd/generate.go @@ -4,25 +4,20 @@ package cmd import ( - "bufio" "bytes" "context" "crypto/sha256" - "encoding/hex" "encoding/json" "errors" "fmt" - "io" "io/fs" "log/slog" "os" - "os/exec" "path/filepath" - "regexp" "slices" "strings" - "github.com/edgelesssys/contrast/internal/embedbin" + "github.com/edgelesssys/contrast/cli/genpolicy" "github.com/edgelesssys/contrast/internal/kuberesource" "github.com/edgelesssys/contrast/internal/manifest" "github.com/edgelesssys/contrast/internal/platforms" @@ -253,29 +248,22 @@ func generatePolicies(ctx context.Context, regoRulesPath, policySettingsPath, ge if err := createFileWithDefault(regoRulesPath, 0o644, func() ([]byte, error) { return defaultRules, nil }); err != nil { return fmt.Errorf("creating default policy.rego file: %w", err) } - binaryInstallDir, err := installDir() - if err != nil { - return fmt.Errorf("get install dir: %w", err) - } - genpolicyInstall, err := embedbin.New().Install(binaryInstallDir, genpolicyBin) + + runner, err := genpolicy.New(genpolicyBin, regoRulesPath, policySettingsPath, genpolicyCachePath) if err != nil { - return fmt.Errorf("install genpolicy: %w", err) + return fmt.Errorf("preparing genpolicy: %w", err) } + defer func() { - if err := genpolicyInstall.Uninstall(); err != nil { - logger.Warn("uninstall genpolicy tool", "err", err) + if err := runner.Teardown(); err != nil { + logger.Warn("Cleanup failed", "err", err) } }() + for _, yamlPath := range yamlPaths { - policyHash, err := generatePolicyForFile(ctx, genpolicyInstall.Path(), regoRulesPath, policySettingsPath, yamlPath, genpolicyCachePath, logger) - if err != nil { - return fmt.Errorf("generate policy for %s: %w", yamlPath, err) - } - if policyHash == [32]byte{} { - continue + if err := runner.Run(ctx, yamlPath, logger); err != nil { + return fmt.Errorf("failed to generate policy for %s: %w", yamlPath, err) } - - logger.Info("Calculated policy hash", "hash", hex.EncodeToString(policyHash[:]), "path", yamlPath) } return nil } @@ -419,95 +407,6 @@ func addSeedshareOwnerKeyToManifest(manifst *manifest.Manifest, keyPath string) return nil } -type logTranslator struct { - r *io.PipeReader - w *io.PipeWriter - logger *slog.Logger - stopDoneC chan struct{} -} - -func newLogTranslator(logger *slog.Logger) logTranslator { - r, w := io.Pipe() - l := logTranslator{ - r: r, - w: w, - logger: logger, - stopDoneC: make(chan struct{}), - } - l.startTranslate() - return l -} - -func (l logTranslator) Write(p []byte) (n int, err error) { - return l.w.Write(p) -} - -var genpolicyLogPrefixReg = regexp.MustCompile(`^\[[^\]\s]+\s+(\w+)\s+([^\]\s]+)\] (.*)`) - -func (l logTranslator) startTranslate() { - go func() { - defer close(l.stopDoneC) - scanner := bufio.NewScanner(l.r) - for scanner.Scan() { - line := scanner.Text() - match := genpolicyLogPrefixReg.FindStringSubmatch(line) - if len(match) != 4 { - // genpolicy prints some warnings without the logger - l.logger.Warn(line) - } else { - switch match[1] { - case "ERROR": - l.logger.Error(match[3], "position", match[2]) - case "WARN": - l.logger.Warn(match[3], "position", match[2]) - case "INFO": // prints quite a lot, only show on debug - l.logger.Debug(match[3], "position", match[2]) - } - } - } - }() -} - -func (l logTranslator) stop() { - l.w.Close() - <-l.stopDoneC -} - -func generatePolicyForFile(ctx context.Context, genpolicyPath, regoPath, policyPath, yamlPath, genpolicyCachePath string, logger *slog.Logger) ([32]byte, error) { - args := []string{ - "--raw-out", - fmt.Sprintf("--runtime-class-names=%s", "contrast-cc"), - fmt.Sprintf("--rego-rules-path=%s", regoPath), - fmt.Sprintf("--json-settings-path=%s", policyPath), - fmt.Sprintf("--yaml-file=%s", yamlPath), - fmt.Sprintf("--layers-cache-file-path=%s", genpolicyCachePath), - } - genpolicy := exec.CommandContext(ctx, genpolicyPath, args...) - genpolicy.Env = append(genpolicy.Env, "RUST_LOG=info", "RUST_BACKTRACE=1") - - logFilter := newLogTranslator(logger) - defer logFilter.stop() - var stdout bytes.Buffer - genpolicy.Stdout = &stdout - genpolicy.Stderr = logFilter - - if err := genpolicy.Run(); err != nil { - var exitErr *exec.ExitError - if errors.As(err, &exitErr) { - return [32]byte{}, fmt.Errorf("genpolicy failed with exit code %d", exitErr.ExitCode()) - } - return [32]byte{}, fmt.Errorf("genpolicy failed: %w", err) - } - - if stdout.Len() == 0 { - logger.Info("Policy output is empty, ignoring the file", "yamlPath", yamlPath) - return [32]byte{}, nil - } - policyHash := sha256.Sum256(stdout.Bytes()) - - return policyHash, nil -} - func generateWorkloadOwnerKey(flags *generateFlags) error { if flags.disableUpdates || len(flags.workloadOwnerKeys) != 1 { // No need to generate keys @@ -657,11 +556,3 @@ func createFileWithDefault(path string, perm fs.FileMode, dflt func() ([]byte, e _, err = file.Write(content) return err } - -func installDir() (string, error) { - home, err := os.UserHomeDir() - if err != nil { - return "", err - } - return filepath.Join(home, ".contrast"), nil -} diff --git a/cli/genpolicy/genpolicy.go b/cli/genpolicy/genpolicy.go new file mode 100644 index 0000000000..6d8315da60 --- /dev/null +++ b/cli/genpolicy/genpolicy.go @@ -0,0 +1,83 @@ +// Copyright 2024 Edgeless Systems GmbH +// SPDX-License-Identifier: AGPL-3.0-only + +package genpolicy + +import ( + "context" + "fmt" + "io" + "log/slog" + "os" + "os/exec" + "path/filepath" + + "github.com/edgelesssys/contrast/internal/embedbin" +) + +// Runner is a wrapper around the genpolicy tool. +// +// Create an instance with New(), call Run() to execute the tool, and call +// Teardown() afterwards to clean up temporary files. +type Runner struct { + genpolicy embedbin.Installed + + rulesPath string + settingsPath string + cachePath string +} + +// New creates a new Runner for the given configuration. +func New(genpolicyBin []byte, rulesPath, settingsPath, cachePath string) (*Runner, error) { + e := embedbin.New() + genpolicy, err := e.Install("", genpolicyBin) + if err != nil { + return nil, fmt.Errorf("installing genpolicy: %w", err) + } + if err := os.MkdirAll(filepath.Dir(cachePath), os.ModePerm); err != nil { + return nil, fmt.Errorf("creating cache file: %w", err) + } + + runner := &Runner{ + genpolicy: genpolicy, + rulesPath: rulesPath, + settingsPath: settingsPath, + cachePath: cachePath, + } + + return runner, nil +} + +// Run runs the tool on the given yaml. +// +// Run can be called more than once. +func (r *Runner) Run(ctx context.Context, yamlPath string, logger *slog.Logger) error { + args := []string{ + "--runtime-class-names=contrast-cc", + "--rego-rules-path=" + r.rulesPath, + "--json-settings-path=" + r.settingsPath, + "--layers-cache-file-path=" + r.cachePath, + "--yaml-file=" + yamlPath, + } + genpolicy := exec.CommandContext(ctx, r.genpolicy.Path(), args...) + genpolicy.Env = append(genpolicy.Env, "RUST_LOG=info", "RUST_BACKTRACE=1") + + logFilter := newLogTranslator(logger) + defer logFilter.stop() + genpolicy.Stdout = io.Discard + genpolicy.Stderr = logFilter + + if err := genpolicy.Run(); err != nil { + return fmt.Errorf("running genpolicy: %w", err) + } + + return nil +} + +// Teardown cleans up temporary files and should be called after the last Run. +func (r *Runner) Teardown() error { + if r.genpolicy != nil { + return r.genpolicy.Uninstall() + } + return nil +} diff --git a/cli/genpolicy/genpolicy_test.go b/cli/genpolicy/genpolicy_test.go new file mode 100644 index 0000000000..90f05d28f8 --- /dev/null +++ b/cli/genpolicy/genpolicy_test.go @@ -0,0 +1,79 @@ +// Copyright 2024 Edgeless Systems GmbH +// SPDX-License-Identifier: AGPL-3.0-only + +package genpolicy + +import ( + "context" + "fmt" + "log/slog" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const scriptTemplate = `#!/bin/sh +set -eu +cd %q + +while [ $# -gt 0 ]; do + case $1 in + --rego-rules-path=*) + printf "%%s" "${1#--rego-rules-path=}" >rules_path + ;; + --json-settings-path=*) + printf "%%s" "${1#--json-settings-path=}" >settings_path + ;; + --yaml-file=*) + printf "%%s" "${1#--yaml-file=}" >yaml_path + ;; + --runtime-class-names*|--layers-cache-file-path*) + ;; + *) + printf "unknown argument: %%s" "$1" >&2 + exit 1 + ;; + esac + shift +done +` + +func TestRunner(t *testing.T) { + require := require.New(t) + assert := assert.New(t) + ctx := context.Background() + logger := slog.Default() + + d := t.TempDir() + genpolicyBin := []byte(fmt.Sprintf(scriptTemplate, d)) + + expectedRulesPath := "/rules.rego" + rulesPathFile := filepath.Join(d, "rules_path") + expectedSettingsPath := "/settings.json" + settingsPathFile := filepath.Join(d, "settings_path") + cachePath := filepath.Join(d, "cache", "cache.json") + expectedYAMLPath := filepath.Join(d, "test.yaml") + yamlPathFile := filepath.Join(d, "yaml_path") + + r, err := New(genpolicyBin, expectedRulesPath, expectedSettingsPath, cachePath) + require.NoError(err) + + require.NoError(r.Run(ctx, expectedYAMLPath, logger)) + + rulesPath, err := os.ReadFile(rulesPathFile) + require.NoError(err) + assert.Equal(expectedRulesPath, string(rulesPath)) + + settingsPath, err := os.ReadFile(settingsPathFile) + require.NoError(err) + assert.Equal(expectedSettingsPath, string(settingsPath)) + + yamlPath, err := os.ReadFile(yamlPathFile) + require.NoError(err) + assert.Equal(expectedYAMLPath, string(yamlPath)) + + require.NoError(r.Teardown()) +} diff --git a/cli/genpolicy/logtranslator.go b/cli/genpolicy/logtranslator.go new file mode 100644 index 0000000000..8587f5c3d9 --- /dev/null +++ b/cli/genpolicy/logtranslator.go @@ -0,0 +1,65 @@ +// Copyright 2024 Edgeless Systems GmbH +// SPDX-License-Identifier: AGPL-3.0-only + +package genpolicy + +import ( + "bufio" + "io" + "log/slog" + "regexp" +) + +type logTranslator struct { + r *io.PipeReader + w *io.PipeWriter + logger *slog.Logger + stopDoneC chan struct{} +} + +func newLogTranslator(logger *slog.Logger) logTranslator { + r, w := io.Pipe() + l := logTranslator{ + r: r, + w: w, + logger: logger, + stopDoneC: make(chan struct{}), + } + l.startTranslate() + return l +} + +func (l logTranslator) Write(p []byte) (n int, err error) { + return l.w.Write(p) +} + +var genpolicyLogPrefixReg = regexp.MustCompile(`^\[[^\]\s]+\s+(\w+)\s+([^\]\s]+)\] (.*)`) + +func (l logTranslator) startTranslate() { + go func() { + defer close(l.stopDoneC) + scanner := bufio.NewScanner(l.r) + for scanner.Scan() { + line := scanner.Text() + match := genpolicyLogPrefixReg.FindStringSubmatch(line) + if len(match) != 4 { + // genpolicy prints some warnings without the logger + l.logger.Warn(line) + } else { + switch match[1] { + case "ERROR": + l.logger.Error(match[3], "position", match[2]) + case "WARN": + l.logger.Warn(match[3], "position", match[2]) + case "INFO": // prints quite a lot, only show on debug + l.logger.Debug(match[3], "position", match[2]) + } + } + } + }() +} + +func (l logTranslator) stop() { + l.w.Close() + <-l.stopDoneC +} diff --git a/cli/cmd/generate_test.go b/cli/genpolicy/logtranslator_test.go similarity index 99% rename from cli/cmd/generate_test.go rename to cli/genpolicy/logtranslator_test.go index 4da37b2f4d..3f347e0cf3 100644 --- a/cli/cmd/generate_test.go +++ b/cli/genpolicy/logtranslator_test.go @@ -1,7 +1,7 @@ // Copyright 2024 Edgeless Systems GmbH // SPDX-License-Identifier: AGPL-3.0-only -package cmd +package genpolicy import ( "testing" From 9163c4ae291952aa7a6a9a42faca6192ae79b4d9 Mon Sep 17 00:00:00 2001 From: Markus Rudy Date: Wed, 31 Jul 2024 16:23:42 +0200 Subject: [PATCH 2/2] cli: platform dependent genpolicy config --- cli/cmd/common.go | 6 --- cli/cmd/generate.go | 11 ++--- .../assets/allow-all.rego} | 0 .../assets/genpolicy} | 0 cli/genpolicy/assets/genpolicy-rules.rego | 1 + .../assets/genpolicy-settings.json | 0 cli/genpolicy/config.go | 44 +++++++++++++++++++ cli/genpolicy/genpolicy.go | 2 +- cli/genpolicy/genpolicy_test.go | 4 +- packages/by-name/cli-release/package.nix | 7 +-- packages/by-name/contrast/package.nix | 8 ++-- 11 files changed, 63 insertions(+), 20 deletions(-) rename cli/{cmd/assets/genpolicy => genpolicy/assets/allow-all.rego} (100%) rename cli/{cmd/assets/genpolicy-rules.rego => genpolicy/assets/genpolicy} (100%) mode change 100755 => 100644 create mode 100755 cli/genpolicy/assets/genpolicy-rules.rego rename cli/{cmd => genpolicy}/assets/genpolicy-settings.json (100%) create mode 100644 cli/genpolicy/config.go diff --git a/cli/cmd/common.go b/cli/cmd/common.go index 317f0868cd..5c875d5db7 100644 --- a/cli/cmd/common.go +++ b/cli/cmd/common.go @@ -30,12 +30,6 @@ const ( ) var ( - //go:embed assets/genpolicy - genpolicyBin []byte - //go:embed assets/genpolicy-settings.json - defaultGenpolicySettings []byte - //go:embed assets/genpolicy-rules.rego - defaultRules []byte // ReleaseImageReplacements contains the image replacements used by contrast. //go:embed assets/image-replacements.txt ReleaseImageReplacements []byte diff --git a/cli/cmd/generate.go b/cli/cmd/generate.go index 459948a6b7..56124d156c 100644 --- a/cli/cmd/generate.go +++ b/cli/cmd/generate.go @@ -126,7 +126,7 @@ func runGenerate(cmd *cobra.Command, args []string) error { } fmt.Fprintln(cmd.OutOrStdout(), "✔️ Patched targets") - if err := generatePolicies(cmd.Context(), flags.policyPath, flags.settingsPath, flags.genpolicyCachePath, paths, log); err != nil { + if err := generatePolicies(cmd.Context(), flags, paths, log); err != nil { return fmt.Errorf("generate policies: %w", err) } fmt.Fprintln(cmd.OutOrStdout(), "✔️ Generated workload policy annotations") @@ -241,15 +241,16 @@ func filterNonCoCoRuntime(runtimeClassNamePrefix string, paths []string, logger return filtered } -func generatePolicies(ctx context.Context, regoRulesPath, policySettingsPath, genpolicyCachePath string, yamlPaths []string, logger *slog.Logger) error { - if err := createFileWithDefault(policySettingsPath, 0o644, func() ([]byte, error) { return defaultGenpolicySettings, nil }); err != nil { +func generatePolicies(ctx context.Context, flags *generateFlags, yamlPaths []string, logger *slog.Logger) error { + cfg := genpolicy.NewConfig(flags.referenceValuesPlatform) + if err := createFileWithDefault(flags.settingsPath, 0o644, func() ([]byte, error) { return cfg.Settings, nil }); err != nil { return fmt.Errorf("creating default policy file: %w", err) } - if err := createFileWithDefault(regoRulesPath, 0o644, func() ([]byte, error) { return defaultRules, nil }); err != nil { + if err := createFileWithDefault(flags.policyPath, 0o644, func() ([]byte, error) { return cfg.Rules, nil }); err != nil { return fmt.Errorf("creating default policy.rego file: %w", err) } - runner, err := genpolicy.New(genpolicyBin, regoRulesPath, policySettingsPath, genpolicyCachePath) + runner, err := genpolicy.New(flags.policyPath, flags.settingsPath, flags.genpolicyCachePath) if err != nil { return fmt.Errorf("preparing genpolicy: %w", err) } diff --git a/cli/cmd/assets/genpolicy b/cli/genpolicy/assets/allow-all.rego similarity index 100% rename from cli/cmd/assets/genpolicy rename to cli/genpolicy/assets/allow-all.rego diff --git a/cli/cmd/assets/genpolicy-rules.rego b/cli/genpolicy/assets/genpolicy old mode 100755 new mode 100644 similarity index 100% rename from cli/cmd/assets/genpolicy-rules.rego rename to cli/genpolicy/assets/genpolicy diff --git a/cli/genpolicy/assets/genpolicy-rules.rego b/cli/genpolicy/assets/genpolicy-rules.rego new file mode 100755 index 0000000000..5c169759e7 --- /dev/null +++ b/cli/genpolicy/assets/genpolicy-rules.rego @@ -0,0 +1 @@ +# THIS FILE IS REPLACED DURING BUILD AND ONLY HERE TO SATISFY GO TOOLING diff --git a/cli/cmd/assets/genpolicy-settings.json b/cli/genpolicy/assets/genpolicy-settings.json similarity index 100% rename from cli/cmd/assets/genpolicy-settings.json rename to cli/genpolicy/assets/genpolicy-settings.json diff --git a/cli/genpolicy/config.go b/cli/genpolicy/config.go new file mode 100644 index 0000000000..f6004878b4 --- /dev/null +++ b/cli/genpolicy/config.go @@ -0,0 +1,44 @@ +// Copyright 2024 Edgeless Systems GmbH +// SPDX-License-Identifier: AGPL-3.0-only + +package genpolicy + +import ( + _ "embed" + + "github.com/edgelesssys/contrast/internal/platforms" +) + +var ( + //go:embed assets/genpolicy + genpolicyBin []byte + //go:embed assets/genpolicy-settings.json + defaultGenpolicySettings []byte + //go:embed assets/genpolicy-rules.rego + aksCloudHypervisorSNPRules []byte + //go:embed assets/allow-all.rego + permissiveRules []byte +) + +// Config contains configuration files for genpolicy. +type Config struct { + // Rules is a Rego module that verifies agent requests. + Rules []byte + // Settings is a json config file that holds platform-specific configuration. + Settings []byte +} + +// NewConfig selects the appropriate genpolicy configuration for the target platform. +func NewConfig(platform platforms.Platform) *Config { + cfg := &Config{ + Settings: defaultGenpolicySettings, + } + switch platform { + case platforms.AKSCloudHypervisorSNP: + cfg.Rules = aksCloudHypervisorSNPRules + default: + // TODO(burgerdev): use real rules for supported platforms. + cfg.Rules = permissiveRules + } + return cfg +} diff --git a/cli/genpolicy/genpolicy.go b/cli/genpolicy/genpolicy.go index 6d8315da60..787b436c18 100644 --- a/cli/genpolicy/genpolicy.go +++ b/cli/genpolicy/genpolicy.go @@ -28,7 +28,7 @@ type Runner struct { } // New creates a new Runner for the given configuration. -func New(genpolicyBin []byte, rulesPath, settingsPath, cachePath string) (*Runner, error) { +func New(rulesPath, settingsPath, cachePath string) (*Runner, error) { e := embedbin.New() genpolicy, err := e.Install("", genpolicyBin) if err != nil { diff --git a/cli/genpolicy/genpolicy_test.go b/cli/genpolicy/genpolicy_test.go index 90f05d28f8..4401f3eb8e 100644 --- a/cli/genpolicy/genpolicy_test.go +++ b/cli/genpolicy/genpolicy_test.go @@ -48,7 +48,7 @@ func TestRunner(t *testing.T) { logger := slog.Default() d := t.TempDir() - genpolicyBin := []byte(fmt.Sprintf(scriptTemplate, d)) + genpolicyBin = []byte(fmt.Sprintf(scriptTemplate, d)) expectedRulesPath := "/rules.rego" rulesPathFile := filepath.Join(d, "rules_path") @@ -58,7 +58,7 @@ func TestRunner(t *testing.T) { expectedYAMLPath := filepath.Join(d, "test.yaml") yamlPathFile := filepath.Join(d, "yaml_path") - r, err := New(genpolicyBin, expectedRulesPath, expectedSettingsPath, cachePath) + r, err := New(expectedRulesPath, expectedSettingsPath, cachePath) require.NoError(err) require.NoError(r.Run(ctx, expectedYAMLPath, logger)) diff --git a/packages/by-name/cli-release/package.nix b/packages/by-name/cli-release/package.nix index 00ebb3b27f..c7100ab81c 100644 --- a/packages/by-name/cli-release/package.nix +++ b/packages/by-name/cli-release/package.nix @@ -11,9 +11,10 @@ (contrast.overrideAttrs ( _finalAttrs: previousAttrs: { prePatch = '' - install -D ${lib.getExe genpolicy} cli/cmd/assets/genpolicy - install -D ${contrast.settings}/genpolicy-settings.json cli/cmd/assets/genpolicy-settings.json - install -D ${contrast.rules}/genpolicy-rules.rego cli/cmd/assets/genpolicy-rules.rego + install -D ${lib.getExe genpolicy} cli/genpolicy/assets/genpolicy + install -D ${contrast.settings}/genpolicy-settings.json cli/genpolicy/assets/genpolicy-settings.json + install -D ${contrast.rules}/genpolicy-rules.rego cli/genpolicy/assets/genpolicy-rules.rego + # TODO(burgerdev): cli/genpolicy/assets/allow-all.rego is insecure and deliberately omitted install -D ${contrast.embeddedReferenceValues} internal/manifest/assets/reference-values.json ''; diff --git a/packages/by-name/contrast/package.nix b/packages/by-name/contrast/package.nix index b3987629b6..448be295d9 100644 --- a/packages/by-name/contrast/package.nix +++ b/packages/by-name/contrast/package.nix @@ -90,6 +90,7 @@ buildGoModule rec { (path.append root "go.mod") (path.append root "go.sum") (path.append root "cli/cmd/assets/image-replacements.txt") + (path.append root "cli/genpolicy/assets/allow-all.rego") (path.append root "internal/attestation/snp/Milan.pem") (path.append root "internal/attestation/snp/Genoa.pem") (path.append root "nodeinstaller") @@ -107,9 +108,10 @@ buildGoModule rec { subPackages = packageOutputs ++ [ "internal/kuberesource/resourcegen" ]; prePatch = '' - install -D ${lib.getExe genpolicy} cli/cmd/assets/genpolicy - install -D ${genpolicy.settings-dev}/genpolicy-settings.json cli/cmd/assets/genpolicy-settings.json - install -D ${genpolicy.rules}/genpolicy-rules.rego cli/cmd/assets/genpolicy-rules.rego + install -D ${lib.getExe genpolicy} cli/genpolicy/assets/genpolicy + install -D ${genpolicy.settings-dev}/genpolicy-settings.json cli/genpolicy/assets/genpolicy-settings.json + install -D ${genpolicy.rules}/genpolicy-rules.rego cli/genpolicy/assets/genpolicy-rules.rego + install -D ${genpolicy.src}/src/kata-opa/allow-all.rego cli/genpolicy/assets/allow-all.rego install -D ${embeddedReferenceValues} internal/manifest/assets/reference-values.json '';