From f94bbff6c24c3a8a4b622e9df08d0a92318ae802 Mon Sep 17 00:00:00 2001 From: Markus Rudy Date: Fri, 26 Jul 2024 20:25:50 +0200 Subject: [PATCH] cli: factor out genpolicy --- cli/cmd/common.go | 8 - cli/cmd/generate.go | 165 +++--------------- cli/genpolicy/assets/allow-all.rego | 43 +++++ cli/{cmd => genpolicy}/assets/genpolicy | 0 .../assets/genpolicy-rules.rego | 0 .../assets/genpolicy-settings.json | 0 cli/genpolicy/genpolicy.go | 124 +++++++++++++ cli/genpolicy/genpolicy_test.go | 117 +++++++++++++ cli/genpolicy/logtranslator.go | 65 +++++++ .../logtranslator_test.go} | 2 +- packages/by-name/cli-release/package.nix | 6 +- packages/by-name/contrast/package.nix | 7 +- 12 files changed, 385 insertions(+), 152 deletions(-) create mode 100644 cli/genpolicy/assets/allow-all.rego rename cli/{cmd => genpolicy}/assets/genpolicy (100%) rename cli/{cmd => genpolicy}/assets/genpolicy-rules.rego (100%) rename cli/{cmd => genpolicy}/assets/genpolicy-settings.json (100%) 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/common.go b/cli/cmd/common.go index 0b862eecf2..c8ea42b4d5 100644 --- a/cli/cmd/common.go +++ b/cli/cmd/common.go @@ -22,21 +22,13 @@ const ( workloadOwnerPEM = "workload-owner.pem" seedshareOwnerPEM = "seedshare-owner.pem" manifestFilename = "manifest.json" - settingsFilename = "settings.json" seedSharesFilename = "seed-shares.json" - rulesFilename = "rules.rego" layersCacheFilename = "layers-cache.json" verifyDir = "verify" cacheDirEnv = "CONTRAST_CACHE_DIR" ) 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 e9184b7f5b..15ca9a97f9 100644 --- a/cli/cmd/generate.go +++ b/cli/cmd/generate.go @@ -4,25 +4,19 @@ 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/node-installer/platforms" @@ -60,9 +54,9 @@ subcommands.`, RunE: withTelemetry(runGenerate), } - cmd.Flags().StringP("policy", "p", rulesFilename, "path to policy (.rego) file") - cmd.Flags().StringP("settings", "s", settingsFilename, "path to settings (.json) file") - cmd.Flags().StringP("genpolicy-cache-path", "c", layersCacheFilename, "path to cache for the cache (.json) file containing the image layers") + cmd.Flags().StringP("policy", "p", "", "path to policy (.rego) file") + cmd.Flags().StringP("settings", "s", "", "path to settings (.json) file") + cmd.Flags().StringP("genpolicy-cache-path", "c", "", "path to cache for the cache (.json) file containing the image layers") cmd.Flags().StringP("manifest", "m", manifestFilename, "path to manifest (.json) file") cmd.Flags().String("reference-values", "", fmt.Sprintf("set the default reference values used for attestation (one of: %s)", @@ -106,7 +100,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("failed to generate policies: %w", err) } fmt.Fprintln(cmd.OutOrStdout(), "✔️ Generated workload policy annotations") @@ -239,36 +233,39 @@ 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 { - return fmt.Errorf("creating default policy file: %w", err) +func generatePolicies(ctx context.Context, flags *generateFlags, yamlPaths []string, logger *slog.Logger) error { + runner, err := genpolicy.New(flags.referenceValuesPlatform) + if err != nil { + return fmt.Errorf("creating genpolicy runner: %w", err) } - if err := createFileWithDefault(regoRulesPath, 0o644, func() ([]byte, error) { return defaultRules, nil }); err != nil { - return fmt.Errorf("creating default policy.rego file: %w", err) + if flags.genpolicyCachePath != "" { + runner.CacheFile = flags.genpolicyCachePath } - binaryInstallDir, err := installDir() - if err != nil { - return fmt.Errorf("failed to get install dir: %w", err) + if flags.policyPath != "" { + content, err := os.ReadFile(flags.policyPath) + if err != nil { + return fmt.Errorf("reading policy file: %w", err) + } + runner.Rules = content } - genpolicyInstall, err := embedbin.New().Install(binaryInstallDir, genpolicyBin) - if err != nil { - return fmt.Errorf("failed to install genpolicy: %w", err) + if flags.settingsPath != "" { + content, err := os.ReadFile(flags.settingsPath) + if err != nil { + return fmt.Errorf("reading policy file: %w", err) + } + runner.Settings = content } + defer func() { - if err := genpolicyInstall.Uninstall(); err != nil { - logger.Warn("Failed to uninstall genpolicy tool", "err", err) + if err := runner.Teardown(); err != nil { + logger.Warn("Error during cleanup: %v", err) } }() + for _, yamlPath := range yamlPaths { - policyHash, err := generatePolicyForFile(ctx, genpolicyInstall.Path(), regoRulesPath, policySettingsPath, yamlPath, genpolicyCachePath, logger) - if err != nil { + if err := runner.Run(ctx, yamlPath, logger); err != nil { return fmt.Errorf("failed to generate policy for %s: %w", yamlPath, err) } - if policyHash == [32]byte{} { - continue - } - - logger.Info("Calculated policy hash", "hash", hex.EncodeToString(policyHash[:]), "path", yamlPath) } return nil } @@ -413,95 +410,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 @@ -588,15 +496,6 @@ func parseGenerateFlags(cmd *cobra.Command) (*generateFlags, error) { } if workspaceDir != "" { // Prepend default paths with workspaceDir - if !cmd.Flags().Changed("settings") { - settingsPath = filepath.Join(workspaceDir, settingsFilename) - } - if !cmd.Flags().Changed("genpolicy-cache-path") { - genpolicyCachePath = filepath.Join(workspaceDir, genpolicyCachePath) - } - if !cmd.Flags().Changed("policy") { - policyPath = filepath.Join(workspaceDir, rulesFilename) - } if !cmd.Flags().Changed("manifest") { manifestPath = filepath.Join(workspaceDir, manifestFilename) } @@ -664,11 +563,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/assets/allow-all.rego b/cli/genpolicy/assets/allow-all.rego new file mode 100644 index 0000000000..7714e3e917 --- /dev/null +++ b/cli/genpolicy/assets/allow-all.rego @@ -0,0 +1,43 @@ +# Copyright (c) 2023 Microsoft Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +package agent_policy + +default AddARPNeighborsRequest := true +default AddSwapRequest := true +default CloseStdinRequest := true +default CopyFileRequest := true +default CreateContainerRequest := true +default CreateSandboxRequest := true +default DestroySandboxRequest := true +default ExecProcessRequest := true +default GetMetricsRequest := true +default GetOOMEventRequest := true +default GuestDetailsRequest := true +default ListInterfacesRequest := true +default ListRoutesRequest := true +default MemHotplugByProbeRequest := true +default OnlineCPUMemRequest := true +default PauseContainerRequest := true +default PullImageRequest := true +default ReadStreamRequest := true +default RemoveContainerRequest := true +default RemoveStaleVirtiofsShareMountsRequest := true +default ReseedRandomDevRequest := true +default ResumeContainerRequest := true +default SetGuestDateTimeRequest := true +default SetPolicyRequest := true +default SignalProcessRequest := true +default StartContainerRequest := true +default StartTracingRequest := true +default StatsContainerRequest := true +default StopTracingRequest := true +default TtyWinResizeRequest := true +default UpdateContainerRequest := true +default UpdateEphemeralMountsRequest := true +default UpdateInterfaceRequest := true +default UpdateRoutesRequest := true +default WaitProcessRequest := true +default WriteStreamRequest := true diff --git a/cli/cmd/assets/genpolicy b/cli/genpolicy/assets/genpolicy similarity index 100% rename from cli/cmd/assets/genpolicy rename to cli/genpolicy/assets/genpolicy diff --git a/cli/cmd/assets/genpolicy-rules.rego b/cli/genpolicy/assets/genpolicy-rules.rego similarity index 100% rename from cli/cmd/assets/genpolicy-rules.rego rename to cli/genpolicy/assets/genpolicy-rules.rego 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/genpolicy.go b/cli/genpolicy/genpolicy.go new file mode 100644 index 0000000000..4b6170aa09 --- /dev/null +++ b/cli/genpolicy/genpolicy.go @@ -0,0 +1,124 @@ +// Copyright 2024 Edgeless Systems GmbH +// SPDX-License-Identifier: AGPL-3.0-only + +package genpolicy + +import ( + "context" + _ "embed" + "errors" + "fmt" + "io" + "log/slog" + "os" + "os/exec" + "path/filepath" + "sync" + + "github.com/edgelesssys/contrast/internal/embedbin" + "github.com/edgelesssys/contrast/node-installer/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 +) + +// Runner is a wrapper around the genpolicy tool. +// +// Create an instance with New(), optionally configure it using the exported +// fields, call Run() to execute the tool, and call Teardown() afterwards to +// clean up temporary files. +type Runner struct { + Rules []byte + Settings []byte + CacheFile string + + once sync.Once + genpolicy embedbin.Installed + settings embedbin.Installed + rules embedbin.Installed +} + +// New creates a new Runner with the default configuration for the requested platform. +func New(platform platforms.Platform) (*Runner, error) { + cacheDir, err := os.UserCacheDir() + if err != nil { + return nil, fmt.Errorf("getting cache dir: %w", err) + } + runner := &Runner{ + Settings: defaultGenpolicySettings, + CacheFile: filepath.Join(cacheDir, "contrast", "layer-cache.json"), + } + switch platform { + case platforms.AKSCloudHypervisorSNP: + runner.Rules = aksCloudHypervisorSNPRules + default: + // TODO(burgerdev): use real rules for supported platforms. + runner.Rules = permissiveRules + } + + return runner, nil +} + +// Run runs the tool on the given yaml. +// +// Run can be called more than once, but if the first run fails during +// initialization subsequent runs won't succeed. +func (r *Runner) Run(ctx context.Context, yamlPath string, logger *slog.Logger) error { + var outerErr error + r.once.Do(func() { + var err error + e := embedbin.New() + r.genpolicy, err = e.Install("", genpolicyBin) + outerErr = errors.Join(outerErr, err) + r.settings, err = e.Install("", r.Settings) + outerErr = errors.Join(outerErr, err) + r.rules, err = e.Install("", r.Rules) + outerErr = errors.Join(outerErr, err) + }) + if outerErr != nil { + return fmt.Errorf("creating temp files: %w", outerErr) + } + + if err := os.MkdirAll(filepath.Dir(r.CacheFile), os.ModePerm); err != nil { + return fmt.Errorf("creating cache file: %w", err) + } + + args := []string{ + "--runtime-class-names", "contrast-cc", + "--rego-rules-path", r.rules.Path(), + "--json-settings-path", r.settings.Path(), + "--yaml-file", yamlPath, + "--layers-cache-file-path", r.CacheFile, + } + genpolicy := exec.CommandContext(ctx, r.genpolicy.Path(), args...) + genpolicy.Env = append(genpolicy.Env, "RUST_LOG=info", "RUST_BACKTRACE=1") + genpolicy.Env = append(genpolicy.Env, fmt.Sprintf("PATH=%s", os.Getenv("PATH"))) + + 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 { + var err error + for _, install := range []embedbin.Installed{r.genpolicy, r.settings, r.rules} { + err = errors.Join(err, install.Uninstall()) + } + return err +} diff --git a/cli/genpolicy/genpolicy_test.go b/cli/genpolicy/genpolicy_test.go new file mode 100644 index 0000000000..ba9445d699 --- /dev/null +++ b/cli/genpolicy/genpolicy_test.go @@ -0,0 +1,117 @@ +// 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/edgelesssys/contrast/node-installer/platforms" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const scriptTemplate = `#!/bin/sh +set -eu +cd %q + +env | grep -q RUST_LOG + +while [ $# -gt 0 ]; do + case $1 in + --rego-rules-path) + shift + cp "$1" rules.rego + ;; + --json-settings-path) + shift + cp "$1" settings.json + ;; + --yaml-file) + shift + printf "%%s" "$1" >yaml_path + ;; + --runtime-class-names|--layers-cache-file-path) + shift + ;; + *) + printf "unknown argument: %%s" "$1" >&2 + exit 1 + ;; + esac + shift +done +` + +func TestRunner(t *testing.T) { + ctx := context.Background() + logger := slog.Default() + + d := t.TempDir() + genpolicyBin = []byte(fmt.Sprintf(scriptTemplate, d)) + + rulesFile := filepath.Join(d, "rules.rego") + settingsFile := filepath.Join(d, "settings.json") + cachePath := filepath.Join(d, "cache", "cache.json") + yaml := filepath.Join(d, "test.yaml") + yamlPathFile := filepath.Join(d, "yaml_path") + + for _, tc := range []struct { + name string + rules, settings []byte + }{ + { + name: "defaults", + }, + { + name: "rules", + rules: []byte(`test rule`), + }, + { + name: "settings", + settings: []byte(`test settings`), + }, + } { + t.Run(tc.name, func(t *testing.T) { + require := require.New(t) + assert := assert.New(t) + + r, err := New(platforms.AKSCloudHypervisorSNP) + require.NoError(err) + r.CacheFile = cachePath + if tc.rules != nil { + r.Rules = tc.rules + } + if tc.settings != nil { + r.Settings = tc.settings + } + + require.NoError(r.Run(ctx, yaml, logger)) + + rules, err := os.ReadFile(rulesFile) + require.NoError(err) + if tc.rules != nil { + assert.Equal(tc.rules, rules) + } else { + assert.Equal(aksCloudHypervisorSNPRules, rules) + } + settings, err := os.ReadFile(settingsFile) + require.NoError(err) + if tc.settings != nil { + assert.Equal(tc.settings, settings) + } else { + assert.Equal(settings, defaultGenpolicySettings) + } + yamlPath, err := os.ReadFile(yamlPathFile) + require.NoError(err) + assert.Equal(yaml, 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" diff --git a/packages/by-name/cli-release/package.nix b/packages/by-name/cli-release/package.nix index 6e9d2a4b81..a1fc7f36b0 100644 --- a/packages/by-name/cli-release/package.nix +++ b/packages/by-name/cli-release/package.nix @@ -11,9 +11,9 @@ (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 ''; ldflags = previousAttrs.ldflags ++ [ diff --git a/packages/by-name/contrast/package.nix b/packages/by-name/contrast/package.nix index 9fff661a1a..f73085ebe5 100644 --- a/packages/by-name/contrast/package.nix +++ b/packages/by-name/contrast/package.nix @@ -73,6 +73,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 "node-installer") @@ -90,9 +91,9 @@ 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 ''; CGO_ENABLED = 0;