From 258055ab91342ea56c2a3309616b81c8755b6a40 Mon Sep 17 00:00:00 2001 From: Hari N <99889761+hnadiminti-equinix@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:24:25 +0000 Subject: [PATCH] Added cosign plugin in the dynamic buildkite template (#20) * In addition to command line options, a dynamic buildkite template will provide config.yaml for overrides * updte main.go * updte main.go * Added cosign plugin in the dynamic buildkite template * update README.md * update pipeline test.go * update output to default stderr * deleted github util.go file * update * updated the code as per the review notes * adding co-sign * updated bug fix * version fix and update * update README and cosign file * Update varname correctly * added docker metatadata plugin * update plugin step * update test file * update conf.yaml keyless is false * add ssm plugin config * update pugin and test file * updated keyless for cosign * Added docker build plugin into the dynamic template * updated conf file * updated conf file * updated conf file * changed the order of the plugins * changed the order of the plugins and conf file --- README.md | 61 +++---- cmd/cosign.go | 40 +++++ cmd/docker-build.go | 40 +++++ cmd/docker-metadata.go | 40 +++++ cmd/generate.go | 53 +++++- cmd/ssm.go | 40 +++++ cmd/trivy.go | 98 ++-------- cmd/util.go | 74 +------- conf.yaml | 41 ++++- generator/common-pipeline.go | 44 ++--- generator/common-pipeline_test.go | 199 ++++++++++++++++++++- generator/cosign-plugin-config.go | 21 +++ generator/docker-build-config.go | 13 ++ generator/docker-metadata-plugin-config.go | 11 ++ generator/generator.go | 16 ++ generator/ssm-plugin-config.go | 12 ++ generator/trivy-plugin-config.go | 15 ++ go.mod | 11 +- go.sum | 22 +-- main.go | 2 +- templates/plugins-step.tmpl | 136 ++++++++++++++ templates/trivy-step.tmpl | 33 ---- util/constants.go | 5 + 23 files changed, 736 insertions(+), 291 deletions(-) create mode 100644 cmd/cosign.go create mode 100644 cmd/docker-build.go create mode 100644 cmd/docker-metadata.go create mode 100644 cmd/ssm.go create mode 100644 generator/cosign-plugin-config.go create mode 100644 generator/docker-build-config.go create mode 100644 generator/docker-metadata-plugin-config.go create mode 100644 generator/generator.go create mode 100644 generator/ssm-plugin-config.go create mode 100644 generator/trivy-plugin-config.go create mode 100644 templates/plugins-step.tmpl delete mode 100644 templates/trivy-step.tmpl create mode 100644 util/constants.go diff --git a/README.md b/README.md index 48aecb4..74be85f 100644 --- a/README.md +++ b/README.md @@ -19,44 +19,45 @@ make deb ``` # Usage -Here's how you can generate the trivy plugin template +Here's how you can generate the buildkite template ``` -$ ./dynamic-buildkite-template trivy --version=v1.18.2 --skip-files="cosign.key" +$ ./dynamic-buildkite-template steps: - command: ls plugins: - - equinixmetal-buildkite/trivy#v1.18.2: + - equinixmetal-buildkite/cosign#v0.1.0: + image: ghcr.io/my-project/my-image:latest + keyless-config: + fulcio-url: https://fulcio.sigstore.dev + rekor-url: https://rekor.sigstore.dev + cosign-version: v0.1.0 + - equinixmetal-buildkite/trivy#v1.18.3: timeout : 5m0s severity: HIGH,CRITICAL ignore-unfixed: true security-checks: vuln,config - skip-files: 'cosign.key' ``` ## Configuration and Overrides -* Configurations are stored in `conf.yaml` and it has default values. -* Configurations from the file `conf.yaml` can be overridden by command line flags as this example: - Using default configs - ``` - $ go run main.go trivy - steps: - - command: ls - plugins: - - equinixmetal-buildkite/trivy#v1.18.2: - timeout : 5m0s - severity: HIGH,CRITICAL - ignore-unfixed: true - security-checks: vuln,config - ``` +* Configurations are stored in `resources/config/conf.yaml` and it has default values. +* Configurations from the file `resources/config/conf.yaml` can be overridden by command line flags by using the yaml configuration path as below: +``` +$ ./dynamic-buildkite-template --overrides plugins.trivy.skip-files="x.txt,y.txt" --overrides plugins.cosign.keyless=false +steps: + - command: ls + plugins: + - equinixmetal-buildkite/cosign#v0.1.0: + image: ghcr.io/my-project/my-image:latest + keyless : false + keyed-config: + key: sample-key + cosign-version: v0.1.0 + - equinixmetal-buildkite/trivy#v1.18.3: + timeout : 5m0s + severity: HIGH,CRITICAL + ignore-unfixed: true + security-checks: vuln,config + skip-files: 'x.txt,y.txt' +``` +If you notice you can provide multiple `--overrides` flags and this would in turn collate to a `map[string]string` being passed to the program. The keys in override are in the yaml path format. So for a given config override you can check the path hierarchy in the `conf.yaml` and mention the override accordingly. - Using command line flags to override timeout - ``` - $ go run main.go trivy --timeout=7m15s - steps: - - command: ls - plugins: - - equinixmetal-buildkite/trivy#v1.18.2: - timeout : 7m15s - severity: HIGH,CRITICAL - ignore-unfixed: true - security-checks: vuln,config - ``` \ No newline at end of file +For long term config changes, it's suggested to update the `conf.yaml` file itself. \ No newline at end of file diff --git a/cmd/cosign.go b/cmd/cosign.go new file mode 100644 index 0000000..76f2736 --- /dev/null +++ b/cmd/cosign.go @@ -0,0 +1,40 @@ +package cmd + +import ( + "dynamic-buildkite-template/generator" + "strings" + + log "github.com/sirupsen/logrus" + + "github.com/spf13/viper" +) + +var ( + cosignPluginConfig generator.CosignPluginConfig +) + +// LoadCosignConfigs loads cosign plugin configuration from conf.yaml using "plugins.cosign" key +func LoadCosignConfigs() { + // load from config + s := viper.Sub("plugins.cosign") + if s == nil { + log.Warn("Cosign Plugin configuration not found in the config file. .") + return + } + + log.Info("Cosign plugin found in the config file") + + err := s.Unmarshal(&cosignPluginConfig) // unmarshal to the cosignPluginConfig object + if err != nil { + log.Error("Error unmarshalling cosign plugin from config file", err) + return + } + + // fetch latest cosign plugin version, if not defined in the config + if strings.TrimSpace(cosignPluginConfig.CosignVersion) == "" { + cosignPluginConfig.CosignVersion = GetLatestPluginTag("cosign-buildkite-plugin") + } + g.CosignConfig = cosignPluginConfig + // mark cosign plugin as enabled + g.CosignPluginEnabled = true +} diff --git a/cmd/docker-build.go b/cmd/docker-build.go new file mode 100644 index 0000000..47d2809 --- /dev/null +++ b/cmd/docker-build.go @@ -0,0 +1,40 @@ +package cmd + +import ( + "dynamic-buildkite-template/generator" + "strings" + + log "github.com/sirupsen/logrus" + + "github.com/spf13/viper" +) + +var ( + dockerBuildPluginConfig generator.DockerBuildConfig +) + +// LoadDockerBuildConfigs loads docker build plugin configuration from conf.yaml using "plugins.docker-build" key +func LoadDockerBuildConfigs() { + // load from config + s := viper.Sub("plugins.docker-build") + if s == nil { + log.Warn("Docker Build Plugin configuration not found in the config file. .") + return + } + + log.Info("Docker Build plugin found in the config file") + + err := s.Unmarshal(&dockerBuildPluginConfig) // unmarshal to the dockerBuildPluginConfig object + if err != nil { + log.Error("Error unmarshalling docker plugin from config file", err) + return + } + + // fetch latest docker build plugin version, if not defined in the config + if strings.TrimSpace(dockerBuildPluginConfig.Version) == "" { + dockerBuildPluginConfig.Version = GetLatestPluginTag("docker-build-buildkite-plugin") + } + g.DockerBuildConfig = dockerBuildPluginConfig + // mark docker build plugin as enabled + g.DockerBuildPluginEnabled = true +} diff --git a/cmd/docker-metadata.go b/cmd/docker-metadata.go new file mode 100644 index 0000000..5b8a2d4 --- /dev/null +++ b/cmd/docker-metadata.go @@ -0,0 +1,40 @@ +package cmd + +import ( + "dynamic-buildkite-template/generator" + "strings" + + log "github.com/sirupsen/logrus" + + "github.com/spf13/viper" +) + +var ( + dockermetadaPluginConfig generator.DockerMetadataPluginConfig +) + +// LoadDockerMetaDataConfigs loads docker metadata plugin configuration from conf.yaml using "plugins.dockermetadata" key +func LoadDockerMetaDataConfigs() { + // load from config + s := viper.Sub("plugins.docker-metadata") + if s == nil { + log.Warn("docker-metadata Plugin configuration not found in the config file. .") + return + } + + log.Info("docker-metadata plugin found in the config file") + + err := s.Unmarshal(&dockermetadaPluginConfig) // unmarshal to the dockermetadataPluginConfig object + if err != nil { + log.Error("Error unmarshalling docker-metadata plugin from config file", err) + return + } + + // fetch latest docker-metadata plugin version, if not defined in the config + if strings.TrimSpace(dockermetadaPluginConfig.Version) == "" { + dockermetadaPluginConfig.Version = GetLatestPluginTag("docker-metadata-buildkite-plugin") + } + g.DockerMetadataConfig = dockermetadaPluginConfig + // mark docker-metadata plugin as enabled + g.DockerMetadataPluginEnabled = true +} diff --git a/cmd/generate.go b/cmd/generate.go index 1ae3dca..082adf6 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -3,10 +3,13 @@ package cmd import ( "dynamic-buildkite-template/config" "dynamic-buildkite-template/generator" + "dynamic-buildkite-template/util" "fmt" + "os" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/spf13/viper" ) var ( @@ -15,6 +18,14 @@ var ( defaultConfigFilePath = "conf.yaml" ) +func init() { + cobra.OnInitialize(initConfig) + // set the flag for passing overrides + generateCmd.Flags().StringToString("overrides", nil, `pass the overrides in the maps syntax as --overrides plugins.trivy.skip-files="x.txt,y.txt" --overrides plugins.cosign.keyless=false`) + + generateCmd.PersistentFlags().StringVar(&ConfigFilePath, "config", "", fmt.Sprintf("config file path (default %q)", defaultConfigFilePath)) +} + var generateCmd = &cobra.Command{ Use: "generate", Short: "Generates plugin step for the provided plugins with configurations", @@ -23,14 +34,26 @@ Usage of dynamic-buildkite-template This Program generates step for the provided plugins with configurations `, Run: func(cmd *cobra.Command, args []string) { + // check for overrides + ParseOverrides(g, cmd) + // load trivy plugin config + LoadTrivyConfigs() + // load cosign plugin config + LoadCosignConfigs() + // load docker-metadata plugin config + LoadDockerMetaDataConfigs() + // load docker build plugin config + LoadDockerBuildConfigs() + // load SSM plugin + LoadSSMDataConfigs() + // generate the build template + err := generator.GenerateBuildSteps(g, os.Stdout, util.TemplateFilePath) + if err != nil { + log.Fatalf("Failed to generate build steps. %s", err.Error()) + } }, } -func init() { - cobra.OnInitialize(initConfig) - generateCmd.PersistentFlags().StringVar(&ConfigFilePath, "config", "", fmt.Sprintf("config file path (default %q)", defaultConfigFilePath)) -} - func initConfig() { if ConfigFilePath != "" { log.Debug("config path: ", ConfigFilePath) @@ -42,10 +65,28 @@ func initConfig() { log.Debug("config path:", defaultConfigFilePath) if err := config.LoadConfig(defaultConfigFilePath); err != nil { - log.Debug("error while loading the configuration file. Loading the defaults") + log.Fatalf("error while loading the configuration file: %s. Configuration file must be present.", defaultConfigFilePath) } } func Execute() error { return generateCmd.Execute() } + +// ParseOverrides checks for command line flags for the overrides and updates the viper global object +func ParseOverrides(g generator.Generator, cmd *cobra.Command) { + m, err := cmd.Flags().GetStringToString("overrides") // check for --overrides flag for map[string]string + if err != nil { + log.Warn("No overrides defined. Continuing with defaults defined in the config file.") + return + } + vNew := viper.New() // new viper object for storing overrides + for k, v := range m { + vNew.Set(k, v) + } + + err = viper.MergeConfigMap(vNew.AllSettings()) // merge to global viper object + if err != nil { + log.Fatalf("Failed merging the configuration with command line overrides. %s", err.Error()) + } +} diff --git a/cmd/ssm.go b/cmd/ssm.go new file mode 100644 index 0000000..74ce328 --- /dev/null +++ b/cmd/ssm.go @@ -0,0 +1,40 @@ +package cmd + +import ( + "dynamic-buildkite-template/generator" + "strings" + + log "github.com/sirupsen/logrus" + + "github.com/spf13/viper" +) + +var ( + ssmPluginConfig generator.SSMPluginConfig +) + +// LoadDockerMetaDataConfigs loads ssm-buildkite plugin configuration from conf.yaml using "plugins.dockermetadata" key +func LoadSSMDataConfigs() { + // load from config + s := viper.Sub("plugins.ssm-buildkite-plugin") + if s == nil { + log.Warn("ssm-buildkite Plugin configuration not found in the config file. .") + return + } + + log.Info("ssm-buildkite plugin found in the config file") + + err := s.Unmarshal(&ssmPluginConfig) // unmarshal to the dockermetadataPluginConfig object + if err != nil { + log.Error("Error unmarshalling ssm-buildkite plugin from config file", err) + return + } + + // fetch latest ssm-buildkite plugin version, if not defined in the config + if strings.TrimSpace(ssmPluginConfig.Version) == "" { + ssmPluginConfig.Version = GetLatestPluginTag("ssm-buildkite-plugin") + } + g.SSMConfig = ssmPluginConfig + // mark ssm-buildkite plugin as enabled + g.SSMPluginEnabled = true +} diff --git a/cmd/trivy.go b/cmd/trivy.go index 8bbe4e8..04c6bb2 100644 --- a/cmd/trivy.go +++ b/cmd/trivy.go @@ -2,12 +2,10 @@ package cmd import ( "dynamic-buildkite-template/generator" - "os" "strings" log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -15,99 +13,27 @@ var ( trivyPluginConfig generator.TrivyPluginConfig ) -var trivyCmd = &cobra.Command{ - Use: "trivy", - Short: "Generates trivy plugin step for the given configurations", - Long: ` -Generates trivy plugin step for the given configurations - `, - Run: func(cmd *cobra.Command, args []string) { - CreateGenerator(cmd, args) - }, -} - -func init() { - // Defaults are placeholders here. Actual defaults are defined in the config file - trivyCmd.Flags().Int("exit-code", 0, "Controls whether the security scan is blocking or not for trivy buildkite plugin") - trivyCmd.Flags().String("timeout", "5m0s", "Controls the maximum amount of time a scan will run for trivy buildkite plugin") - trivyCmd.Flags().String("severity", "HIGH,CRITICAL", "Controls the severity of the vulnerabilities to be scanned for trivy buildkite plugin") - trivyCmd.Flags().Bool("ignore-unfixed", true, "Controls whether to display only fixed vulnerabilities for trivy buildkite plugin") - trivyCmd.Flags().String("security-checks", "vuln,config", "Controls the security checks to be performed for trivy buildkite plugin") - trivyCmd.Flags().String("skip-files", "", "Controls the files to be skipped during the scan for trivy buildkite plugin") - trivyCmd.Flags().String("skip-dirs", "", "Controls the directories to be skipped during the scan for trivy buildkite plugin") - trivyCmd.Flags().String("image-ref", "", "Controls the image reference to be scanned for trivy buildkite plugin") - trivyCmd.Flags().String("version", "", "Controls the version of trivy to be used for trivy buildkite plugin") - trivyCmd.Flags().String("helm-overrides-file", "", "To pass helm override values to trivy config scan for trivy buildkite pluginn") - - generateCmd.AddCommand(trivyCmd) -} - -// CreateGenerator populates the TrivyPluginConfig by reading the values from the command line flags -func CreateGenerator(cmd *cobra.Command, args []string) { - g.TrivyPluginEnabled = true +// LoadTrivyConfigs loads the trivy plugin config using "plugins.trivy" key +func LoadTrivyConfigs() { // load from config s := viper.Sub("plugins.trivy") - doLookup := true if s == nil { - log.Debug("trivy plugin configuration not found in the config file or wrong config file. Proceeding with defaults from command line flags.") - doLookup = false - } else { - err := s.Unmarshal(&trivyPluginConfig) - if err != nil { - log.Error("error unmarshalling config file", err) - } + log.Warn("Trivy Plugin configuration not found in the config file. .") + return } - // initializing nil fields for the cases when conf file is not present or there is command line flag override - if (!doLookup || cmd.Flags().Lookup("exit-code").Changed) && trivyPluginConfig.ExitCode == nil { - trivyPluginConfig.ExitCode = new(int) - } - if (!doLookup || cmd.Flags().Lookup("timeout").Changed) && trivyPluginConfig.Timeout == nil { - trivyPluginConfig.Timeout = new(string) - } - if (!doLookup || cmd.Flags().Lookup("severity").Changed) && trivyPluginConfig.Severity == nil { - trivyPluginConfig.Severity = new(string) - } - if (!doLookup || cmd.Flags().Lookup("ignore-unfixed").Changed) && trivyPluginConfig.IgnoreUnfixed == nil { - trivyPluginConfig.IgnoreUnfixed = new(bool) + err := s.Unmarshal(&trivyPluginConfig) // unmarshal to the trivyPluginConfig object + if err != nil { + log.Error("Error unmarshalling config file", err) + return } - if (!doLookup || cmd.Flags().Lookup("security-checks").Changed) && trivyPluginConfig.SecurityChecks == nil { - trivyPluginConfig.SecurityChecks = new(string) - } - if (!doLookup || cmd.Flags().Lookup("skip-files").Changed) && trivyPluginConfig.SkipFiles == nil { - trivyPluginConfig.SkipFiles = new(string) - } - if (!doLookup || cmd.Flags().Lookup("skip-dirs").Changed) && trivyPluginConfig.SkipDirs == nil { - trivyPluginConfig.SkipDirs = new(string) - } - if (!doLookup || cmd.Flags().Lookup("image-ref").Changed) && trivyPluginConfig.ImageRef == nil { - trivyPluginConfig.ImageRef = new(string) - } - if (!doLookup || cmd.Flags().Lookup("version").Changed) && trivyPluginConfig.TrivyVersion == nil { - trivyPluginConfig.TrivyVersion = new(string) - } - if (!doLookup || cmd.Flags().Lookup("helm-overrides-file").Changed) && trivyPluginConfig.HelmOverridesFile == nil { - trivyPluginConfig.HelmOverridesFile = new(string) - } - - setFromIntFlag(trivyPluginConfig.ExitCode, cmd, "exit-code", doLookup) - setFromStringFlag(trivyPluginConfig.Timeout, cmd, "timeout", doLookup) - setFromStringFlag(trivyPluginConfig.Severity, cmd, "severity", doLookup) - setFromBoolFlag(trivyPluginConfig.IgnoreUnfixed, cmd, "ignore-unfixed", doLookup) - setFromStringFlag(trivyPluginConfig.SecurityChecks, cmd, "security-checks", doLookup) - setFromStringFlag(trivyPluginConfig.SkipFiles, cmd, "skip-files", doLookup) - setFromStringFlag(trivyPluginConfig.SkipDirs, cmd, "skip-dirs", doLookup) - setFromStringFlag(trivyPluginConfig.ImageRef, cmd, "image-ref", doLookup) - setFromStringFlag(trivyPluginConfig.TrivyVersion, cmd, "version", doLookup) - setFromStringFlag(trivyPluginConfig.HelmOverridesFile, cmd, "helm-overrides-file", doLookup) - if trivyPluginConfig.TrivyVersion == nil { - trivyPluginConfig.TrivyVersion = new(string) - } + // fetch latest trivy plugin version, if not defined in the config if strings.TrimSpace(*trivyPluginConfig.TrivyVersion) == "" { - lv := GetLatestTrivyPluginTag() + lv := GetLatestPluginTag("trivy-buildkite-plugin") trivyPluginConfig.TrivyVersion = &lv } g.TPConfig = trivyPluginConfig - generator.GenerateTrivyStep(g, os.Stdout, "templates/*") + // mark trivy plugin as enabled + g.TrivyPluginEnabled = true } diff --git a/cmd/util.go b/cmd/util.go index 6a815f1..1b7d1a7 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -5,83 +5,15 @@ import ( "os" log "github.com/sirupsen/logrus" - - "github.com/spf13/cobra" ) -func setFromStringFlag(f *string, cmd *cobra.Command, name string, doLookup bool) { - // if doLookup is set then it would check for command line overrides before overriding the configuration - // if doLookup is not set then it would pick the from default command line flag values - if f == nil { - return - } - if doLookup { - if cmd.Flags().Lookup(name).Changed { - *f = mustGetStringFlag(cmd, name) - } - } else { - *f = mustGetStringFlag(cmd, name) - } -} - -func setFromBoolFlag(f *bool, cmd *cobra.Command, name string, doLookup bool) { - if f == nil { - return - } - if doLookup { - if cmd.Flags().Lookup(name).Changed { - *f = mustGetBoolFlag(cmd, name) - } - } else { - *f = mustGetBoolFlag(cmd, name) - } -} - -func setFromIntFlag(f *int, cmd *cobra.Command, name string, doLookup bool) { - if f == nil { - return - } - if doLookup { - if cmd.Flags().Lookup(name).Changed { - *f = mustGetIntFlag(cmd, name) - } - } else { - *f = mustGetIntFlag(cmd, name) - } -} - -func mustGetStringFlag(cmd *cobra.Command, name string) string { - flagVal, err := cmd.Flags().GetString(name) - if err != nil { - log.Fatalf("failed to get value of %s. %s", name, err.Error()) - } - return flagVal -} - -func mustGetBoolFlag(cmd *cobra.Command, name string) bool { - flagVal, err := cmd.Flags().GetBool(name) - if err != nil { - log.Fatalf("failed to get value of %s. %s", name, err.Error()) - } - return flagVal -} - -func mustGetIntFlag(cmd *cobra.Command, name string) int { - flagVal, err := cmd.Flags().GetInt(name) - if err != nil { - log.Fatalf("failed to get value of %s. %s", name, err.Error()) - } - return flagVal -} - -func GetLatestTrivyPluginTag() string { +func GetLatestPluginTag(repoName string) string { githubPAT := os.Getenv("GITHUB_PAT") githubOrg := "equinixmetal-buildkite" - repo := "trivy-buildkite-plugin" - tag, err := util.GetLatestTag(githubPAT, githubOrg, repo) + tag, err := util.GetLatestTag(githubPAT, githubOrg, repoName) if err != nil { log.Fatal(err) } - log.Info("latest trivy plugin tag: ", tag) + log.Infof("Latest %s plugin tag: %s", repoName, tag) return tag } diff --git a/conf.yaml b/conf.yaml index de89c74..6129848 100644 --- a/conf.yaml +++ b/conf.yaml @@ -2,11 +2,48 @@ plugins: trivy: exit-code: 0 timeout: 5m0s - severity: HIGH + severity: HIGH,CRITICAL ignore-unfixed: true security-checks: vuln,config skip-files: "" skip-dirs: "" image-ref: "" version: "" - helm-overrides-file: "" \ No newline at end of file + helm-overrides-files: "" + cosign: + image: "ghcr.io/my-project/my-image:latest" + keyless: false + keyless-config: + fulcio_url: "https://fulcio.sigstore.dev" + rekor_url: "https://rekor.sigstore.dev" + keyed-config: + key: "sample-key" + cosign-version: "v0.1.0" + docker-metadata: + images: ["my-org/my-image","image2"] + extra_tags: ["latest","tag2"] + title: "sample" + licenses: "" + vendor: "abc" + debug: true + docker-metadata-version: "" + ssm-buildkite-plugin: + ssm-buildkite-version: "v1.0.4" + parameters: + COSIGN_KEY_SECRET: "test-secret" + COSIGN_PASSWORD: "passwd" + GITHUB_TOKEN: "token" + docker-build: + dockerfile: "Dockerfile" + context: "." + secret-file: "id=mysecret,src=secret-file" + tags: + - "my-org/my-image:latest" + labels: + - "org.opencontainers.image.source=$BUILDKITE_REPO" + build-args: + - "FOO=bar" + - "BAZ=qux" + push: false + +# --overrides plugins.trivy.skip-files="x.txt,y.txt" --overrides plugins.cosign.keyless=false \ No newline at end of file diff --git a/generator/common-pipeline.go b/generator/common-pipeline.go index 57cdd55..f8470bd 100755 --- a/generator/common-pipeline.go +++ b/generator/common-pipeline.go @@ -2,45 +2,25 @@ package generator import ( "io" - "strings" + "os" "text/template" ) -// Generator keeps the state of the generator -// where enabled plugin with the respective config is kept -type Generator struct { - TrivyPluginEnabled bool - TPConfig TrivyPluginConfig -} - -// TrivyPluginConfig stores the various configurations for trivy plugin -type TrivyPluginConfig struct { - ExitCode *int `mapstructure:"exit-code"` - Timeout *string `mapstructure:"timeout"` - Severity *string `mapstructure:"severity"` - IgnoreUnfixed *bool `mapstructure:"ignore-unfixed"` - SecurityChecks *string `mapstructure:"security-checks"` - SkipFiles *string `mapstructure:"skip-files"` - SkipDirs *string `mapstructure:"skip-dirs"` - ImageRef *string `mapstructure:"image-ref"` - TrivyVersion *string `mapstructure:"version"` - HelmOverridesFile *string `mapstructure:"helm-overrides-file"` -} - -// GenerateTrivyStep takes trivy plugin version and shell plugin version -// and an io.Writer to generate trivy step configuration. The trivy step is -// written to the provided io.Writer. +// GenerateBuildSteps takes a Generator object, an io.Writer, and a templateFilePath +// to generate build step configuration. The build step is written to the provided io.Writer. // It returns error in case write to the io.Writer errors out. -func GenerateTrivyStep(g Generator, w io.Writer, templateFolderPath string) error { - funcMap := template.FuncMap{ - "join": func(arr []string) string { - return strings.Join(arr, ",") - }, +func GenerateBuildSteps(g Generator, w io.Writer, templateFilePath string) error { + file, err := os.ReadFile(templateFilePath) + if err != nil { + return err } - tpl, err := template.New("").Funcs(funcMap).ParseGlob(templateFolderPath) + // Parse the template contents + tmpl, err := template.New("tmpl").Parse(string(file)) if err != nil { return err } - return tpl.ExecuteTemplate(w, "trivy-step.tmpl", g) + + // Use the template.Execute() function to apply the data object to the parsed template + return tmpl.Execute(w, g) } diff --git a/generator/common-pipeline_test.go b/generator/common-pipeline_test.go index 4a1b112..d954417 100644 --- a/generator/common-pipeline_test.go +++ b/generator/common-pipeline_test.go @@ -37,8 +37,8 @@ steps: skip-files: "cosign.key" ` cases := []testCase{ - {"success", tpc, "../templates/*", false, "", expected}, - {"wrong_template_path", tpc, "templates/*", true, "template: pattern matches no files", ""}, + {"success", tpc, "../templates/plugins-step.tmpl", false, "", expected}, + {"wrong_template_path", tpc, "../templates/xyz.tmpl", true, "no such file or directory", ""}, } g := Generator{ @@ -51,7 +51,200 @@ steps: tc.name, func(t *testing.T) { var sb strings.Builder - err := GenerateTrivyStep(g, &sb, tc.templatePath) + err := GenerateBuildSteps(g, &sb, tc.templatePath) + if tc.hasError { + if !strings.Contains(err.Error(), tc.errMsg) { + t.Fatalf("Error %s does not contain %s\n", err.Error(), tc.errMsg) + } + } else { + if strings.TrimSpace(tc.expVal) != strings.TrimSpace(sb.String()) { + t.Fatalf("Not equal: \n"+ + "expected: %s\n"+ + "actual : %s\n", strings.TrimSpace(tc.expVal), strings.TrimSpace(sb.String())) + } + } + }, + ) + } +} + +type dockerTestCase struct { + name string + dmpc DockerMetadataPluginConfig + templatePath string + hasError bool + errMsg string + expVal string +} + +func TestGenerateDockerMetadataStep(t *testing.T) { + images := []string{"test_image"} + title := "test_title" + vendor := "test_vendor" + + dmpc := DockerMetadataPluginConfig{ + Images: images, + Title: title, + Vendor: vendor, + } + expected := ` +steps: + - command: ls + plugins: + - equinixmetal-buildkite/docker-metadata#: + images: + - "test_image" + title: "test_title" + vendor: "test_vendor" +` + cases := []dockerTestCase{ + {"success", dmpc, "../templates/plugins-step.tmpl", false, "", expected}, + } + + g := Generator{ + DockerMetadataPluginEnabled: true, + DockerMetadataConfig: dmpc, + } + + for _, tc := range cases { + t.Run( + tc.name, + func(t *testing.T) { + var sb strings.Builder + err := GenerateBuildSteps(g, &sb, tc.templatePath) + if tc.hasError { + if !strings.Contains(err.Error(), tc.errMsg) { + t.Fatalf("Error %s does not contain %s\n", err.Error(), tc.errMsg) + } + } else { + if strings.TrimSpace(tc.expVal) != strings.TrimSpace(sb.String()) { + t.Fatalf("Not equal: \n"+ + "expected: %s\n"+ + "actual : %s\n", strings.TrimSpace(tc.expVal), strings.TrimSpace(sb.String())) + } + } + }, + ) + } +} + +type cosignTestCase struct { + name string + cosignConf CosignPluginConfig + templatePath string + hasError bool + errMsg string + expVal string +} + +func TestCosignStep(t *testing.T) { + + image := "ghcr.io/my-project/my-image:latest" + keyless := false + key := "sample-key" + + cosignConfig := CosignPluginConfig{ + Image: image, + Keyless: keyless, + KeyedConfig: KeyedConfig{Key: key}, + } + + CosignKeySecret := "test-secret" + CosignPasswd := "passwd" + ssm := SSMPluginConfig{ + Parameter: Parameter{CosignKeySecret: CosignKeySecret, CosignPassword: CosignPasswd}, + } + expected := ` +steps: + - label: ":docker: get cosign key" + key: "getkey" + command: | + #!/bin/bash + echo "\$COSIGN_KEY_SECRET" > ${COSIGN_KEY_PATH} + plugins: + - ssh://git@github.com/equinixmetal/ssm-buildkite-plugin#: + parameters: + COSIGN_KEY_SECRET : test-secret + COSIGN_PASSWORD : passwd + - equinixmetal-buildkite/cosign#: + image: ghcr.io/my-project/my-image:latest + keyless : false + keyed-config: + key: sample-key +` + cases := []cosignTestCase{ + {"success", cosignConfig, "../templates/plugins-step.tmpl", false, "", expected}, + } + + g := Generator{ + CosignPluginEnabled: true, + SSMPluginEnabled: true, + CosignConfig: cosignConfig, + SSMConfig: ssm, + } + + for _, tc := range cases { + t.Run( + tc.name, + func(t *testing.T) { + var sb strings.Builder + err := GenerateBuildSteps(g, &sb, tc.templatePath) + if tc.hasError { + if !strings.Contains(err.Error(), tc.errMsg) { + t.Fatalf("Error %s does not contain %s\n", err.Error(), tc.errMsg) + } + } else { + if strings.TrimSpace(tc.expVal) != strings.TrimSpace(sb.String()) { + t.Fatalf("Not equal: \n"+ + "expected: %s\n"+ + "actual : %s\n", strings.TrimSpace(tc.expVal), strings.TrimSpace(sb.String())) + } + } + }, + ) + } +} + +type dockerBuildTestCase struct { + name string + dmpc DockerBuildConfig + templatePath string + hasError bool + errMsg string + expVal string +} + +func TestGenerateDockerBuildStep(t *testing.T) { + dockerfile := "Dockerfile" + secretFile := "id=mysecret,src=secret-file" + + dbc := DockerBuildConfig{ + Dockerfile: dockerfile, + SecretFile: secretFile, + } + expected := ` +steps: + - command: ls + plugins: + - equinixmetal-buildkite/docker-build#: + dockerfile: Dockerfile + secret-file: id=mysecret,src=secret-file +` + cases := []dockerBuildTestCase{ + {"success", dbc, "../templates/plugins-step.tmpl", false, "", expected}, + } + + g := Generator{ + DockerBuildPluginEnabled: true, + DockerBuildConfig: dbc, + } + + for _, tc := range cases { + t.Run( + tc.name, + func(t *testing.T) { + var sb strings.Builder + err := GenerateBuildSteps(g, &sb, tc.templatePath) if tc.hasError { if !strings.Contains(err.Error(), tc.errMsg) { t.Fatalf("Error %s does not contain %s\n", err.Error(), tc.errMsg) diff --git a/generator/cosign-plugin-config.go b/generator/cosign-plugin-config.go new file mode 100644 index 0000000..11613d0 --- /dev/null +++ b/generator/cosign-plugin-config.go @@ -0,0 +1,21 @@ +package generator + +// CosignPluginConfig stores the various configurations for cosign plugin +type CosignPluginConfig struct { + Image string `mapstructure:"image"` + Keyless bool `mapstructure:"keyless"` + KeylessConfig KeylessConfig `mapstructure:"keyless-config"` + KeyedConfig KeyedConfig `mapstructure:"keyed-config"` + CosignVersion string `mapstructure:"cosign-version"` +} + +// KeylessConfig is used if Keyless is set to true in CosignPluginConfig +type KeylessConfig struct { + FulcioURL string `mapstructure:"fulcio_url"` + RekorURL string `mapstructure:"rekor_url"` +} + +// KeyedConfig is used if Keyless is set to false in CosignPluginConfig +type KeyedConfig struct { + Key string `mapstructure:"key"` +} diff --git a/generator/docker-build-config.go b/generator/docker-build-config.go new file mode 100644 index 0000000..b3bf947 --- /dev/null +++ b/generator/docker-build-config.go @@ -0,0 +1,13 @@ +package generator + +// DockerBuildConfig stores the various configurations for docker build plugin +type DockerBuildConfig struct { + Dockerfile string `mapstructure:"dockerfile"` + Context string `mapstructure:"context"` + SecretFile string `mapstructure:"secret-file"` + Tags []string `mapstructure:"tags"` + Labels []string `mapstructure:"labels"` + BuildArgs []string `mapstructure:"build-args"` + Push bool `mapstructure:"push"` + Version string +} diff --git a/generator/docker-metadata-plugin-config.go b/generator/docker-metadata-plugin-config.go new file mode 100644 index 0000000..261d09a --- /dev/null +++ b/generator/docker-metadata-plugin-config.go @@ -0,0 +1,11 @@ +package generator + +type DockerMetadataPluginConfig struct { + Images []string `mapstructure:"images"` + ExtraTags []string `mapstructure:"extra_tags"` + Title string `mapstructure:"title"` + Licenses string `mapstructure:"licenses"` + Vendor string `mapstructure:"vendor"` + Debug bool `mapstructure:"debug"` + Version string `mapstructure:"docker-metadata-version"` +} diff --git a/generator/generator.go b/generator/generator.go new file mode 100644 index 0000000..f713ad3 --- /dev/null +++ b/generator/generator.go @@ -0,0 +1,16 @@ +package generator + +// Generator keeps the state of the generator +// where enabled plugin with the respective config is kept +type Generator struct { + TrivyPluginEnabled bool + CosignPluginEnabled bool + DockerMetadataPluginEnabled bool + SSMPluginEnabled bool + DockerBuildPluginEnabled bool + TPConfig TrivyPluginConfig + CosignConfig CosignPluginConfig + DockerMetadataConfig DockerMetadataPluginConfig + SSMConfig SSMPluginConfig + DockerBuildConfig DockerBuildConfig +} diff --git a/generator/ssm-plugin-config.go b/generator/ssm-plugin-config.go new file mode 100644 index 0000000..ff14156 --- /dev/null +++ b/generator/ssm-plugin-config.go @@ -0,0 +1,12 @@ +package generator + +type SSMPluginConfig struct { + Parameter Parameter `mapstructure:"parameters"` + Version string `mapstructure:"ssm-buildkite-version"` +} + +type Parameter struct { + CosignKeySecret string `mapstructure:"COSIGN_KEY_SECRET"` + CosignPassword string `mapstructure:"COSIGN_PASSWORD"` + GithubToken string `mapstructure:"GITHUB_TOKEN"` +} diff --git a/generator/trivy-plugin-config.go b/generator/trivy-plugin-config.go new file mode 100644 index 0000000..a66df2c --- /dev/null +++ b/generator/trivy-plugin-config.go @@ -0,0 +1,15 @@ +package generator + +// TrivyPluginConfig stores the various configurations for trivy plugin +type TrivyPluginConfig struct { + ExitCode *int `mapstructure:"exit-code"` + Timeout *string `mapstructure:"timeout"` + Severity *string `mapstructure:"severity"` + IgnoreUnfixed *bool `mapstructure:"ignore-unfixed"` + SecurityChecks *string `mapstructure:"security-checks"` + SkipFiles *string `mapstructure:"skip-files"` + SkipDirs *string `mapstructure:"skip-dirs"` + ImageRef *string `mapstructure:"image-ref"` + TrivyVersion *string `mapstructure:"version"` + HelmOverridesFile *string `mapstructure:"helm-overrides-file"` +} diff --git a/go.mod b/go.mod index d3dd1db..406d8df 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module dynamic-buildkite-template go 1.20 require ( + github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.17.0 ) @@ -10,6 +11,7 @@ require ( require ( github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect @@ -18,8 +20,7 @@ require ( github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.10.0 // indirect github.com/spf13/cast v1.5.1 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect @@ -27,11 +28,5 @@ require ( golang.org/x/sys v0.12.0 // indirect golang.org/x/text v0.13.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect -) - -require ( - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/sirupsen/logrus v1.9.3 - github.com/spf13/pflag v1.0.5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d03d13b..df1f949 100644 --- a/go.sum +++ b/go.sum @@ -48,8 +48,8 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -138,14 +138,12 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= @@ -158,37 +156,27 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= -github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= -github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= -github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -335,8 +323,6 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -348,8 +334,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -495,8 +479,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/main.go b/main.go index e3c8c42..9cb2224 100644 --- a/main.go +++ b/main.go @@ -15,7 +15,7 @@ func init() { // Can be any io.Writer, see below for File example log.SetOutput(os.Stderr) - // Only log the error severity or above. + // Only log the error severity or above. Chnage to log.DebugLevel for debugging log.SetLevel(log.ErrorLevel) } func main() { diff --git a/templates/plugins-step.tmpl b/templates/plugins-step.tmpl new file mode 100644 index 0000000..9fabec2 --- /dev/null +++ b/templates/plugins-step.tmpl @@ -0,0 +1,136 @@ +steps: +{{- if .CosignPluginEnabled }} +{{- if not .CosignConfig.Keyless }} + - label: ":docker: get cosign key" + key: "getkey" + command: | + #!/bin/bash + echo "\$COSIGN_KEY_SECRET" > ${COSIGN_KEY_PATH} + plugins: +{{- end }} +{{- else }} + - command: ls + plugins: +{{- end }} +{{- if .CosignPluginEnabled }} +{{- if not .CosignConfig.Keyless }} + - ssh://git@github.com/equinixmetal/ssm-buildkite-plugin#{{ .SSMConfig.Version }}: + parameters: + COSIGN_KEY_SECRET : {{ .SSMConfig.Parameter.CosignKeySecret}} + COSIGN_PASSWORD : {{ .SSMConfig.Parameter.CosignPassword }} + {{- if .SSMConfig.Parameter.GithubToken}} + GITHUB_TOKEN : {{ .SSMConfig.Parameter.GithubToken }} + {{- end }} +{{- end }} +{{- end}} +{{- if .CosignPluginEnabled }} + - equinixmetal-buildkite/cosign#{{ .CosignConfig.CosignVersion }}: + {{- if .CosignConfig.Image}} + image: {{ .CosignConfig.Image }} + {{- end }} + {{- if not .CosignConfig.Keyless}} + keyless : {{ .CosignConfig.Keyless }} + {{- end }} + {{- if .CosignConfig.Keyless}} + keyless-config: + fulcio-url: {{ .CosignConfig.KeylessConfig.FulcioURL }} + rekor-url: {{ .CosignConfig.KeylessConfig.RekorURL }} + {{- end }} + {{- if not .CosignConfig.Keyless}} + keyed-config: + key: {{ .CosignConfig.KeyedConfig.Key }} + {{- end }} + {{- if .CosignConfig.CosignVersion}} + cosign-version: {{ .CosignConfig.CosignVersion }} + {{- end }} +{{- end}} +{{- if .TrivyPluginEnabled }} + - equinixmetal-buildkite/trivy#{{ .TPConfig.TrivyVersion }}: + {{- if .TPConfig.ExitCode}} + exit-code: {{ .TPConfig.ExitCode }} + {{- end }} + {{- if .TPConfig.Timeout}} + timeout : "{{ .TPConfig.Timeout }}" + {{- end }} + {{- if .TPConfig.Severity}} + severity: "{{ .TPConfig.Severity }}" + {{- end }} + {{- if .TPConfig.IgnoreUnfixed}} + ignore-unfixed: {{ .TPConfig.IgnoreUnfixed }} + {{- end }} + {{- if .TPConfig.SecurityChecks}} + security-checks: "{{ .TPConfig.SecurityChecks }}" + {{- end }} + {{- if .TPConfig.SkipFiles}} + skip-files: "{{ .TPConfig.SkipFiles }}" + {{- end }} + {{- if .TPConfig.SkipDirs}} + skip-dirs: "{{ .TPConfig.SkipDirs }}" + {{- end }} + {{- if .TPConfig.ImageRef}} + image-ref: "{{ .TPConfig.ImageRef }}" + {{- end }} + {{- if .TPConfig.HelmOverridesFile}} + helm-overrides-file: "{{ .TPConfig.HelmOverridesFile }}" + {{- end }} +{{- end}} +{{- if .DockerMetadataPluginEnabled }} + - equinixmetal-buildkite/docker-metadata#{{ .DockerMetadataConfig.Version }}: + {{- if .DockerMetadataConfig.Images }} + images: + {{- range .DockerMetadataConfig.Images }} + - "{{ . }}" + {{- end }} + {{- end}} + {{- if .DockerMetadataConfig.ExtraTags }} + extra_tags: + {{- range .DockerMetadataConfig.ExtraTags }} + - "{{ . }}" + {{- end}} + {{- end}} + {{- if .DockerMetadataConfig.Title }} + title: "{{ .DockerMetadataConfig.Title }}" + {{- end}} + {{- if .DockerMetadataConfig.Licenses }} + licenses: "{{ .DockerMetadataConfig.Licenses }}" + {{- end}} + {{- if .DockerMetadataConfig.Vendor }} + vendor: "{{ .DockerMetadataConfig.Vendor }}" + {{- end}} + {{- if .DockerMetadataConfig.Debug }} + debug: "{{ .DockerMetadataConfig.Debug }}" + {{- end}} +{{- end}} +{{- if .DockerBuildPluginEnabled }} + - equinixmetal-buildkite/docker-build#{{ .DockerBuildConfig.Version }}: + {{- if .DockerBuildConfig.Dockerfile}} + dockerfile: {{ .DockerBuildConfig.Dockerfile }} + {{- end }} + {{- if .DockerBuildConfig.Context}} + context : {{ .DockerBuildConfig.Context }} + {{- end }} + {{- if .DockerBuildConfig.SecretFile}} + secret-file: {{ .DockerBuildConfig.SecretFile }} + {{- end }} + {{- if .DockerBuildConfig.Tags}} + tags: + {{- range .DockerBuildConfig.Tags }} + - {{ . }} + {{- end }} + {{- end }} + {{- if .DockerBuildConfig.Labels}} + labels: + {{- range .DockerBuildConfig.Labels }} + - {{ . }} + {{- end }} + {{- end }} + {{- if .DockerBuildConfig.BuildArgs}} + build-args: + {{- range .DockerBuildConfig.BuildArgs }} + - {{ . }} + {{- end }} + {{- end }} + {{- if .DockerBuildConfig.Push}} + push: {{ .DockerBuildConfig.Push }} + {{- end }} +{{- end}} \ No newline at end of file diff --git a/templates/trivy-step.tmpl b/templates/trivy-step.tmpl deleted file mode 100644 index c9156c7..0000000 --- a/templates/trivy-step.tmpl +++ /dev/null @@ -1,33 +0,0 @@ -steps: - - command: ls - plugins: -{{- if .TrivyPluginEnabled }} - - equinixmetal-buildkite/trivy#{{ .TPConfig.TrivyVersion }}: - {{- if .TPConfig.ExitCode}} - exit-code: {{ .TPConfig.ExitCode }} - {{- end }} - {{- if .TPConfig.Timeout}} - timeout : "{{ .TPConfig.Timeout }}" - {{- end }} - {{- if .TPConfig.Severity}} - severity: "{{ .TPConfig.Severity }}" - {{- end }} - {{- if .TPConfig.IgnoreUnfixed}} - ignore-unfixed: {{ .TPConfig.IgnoreUnfixed }} - {{- end }} - {{- if .TPConfig.SecurityChecks}} - security-checks: "{{ .TPConfig.SecurityChecks }}" - {{- end }} - {{- if .TPConfig.SkipFiles}} - skip-files: "{{ .TPConfig.SkipFiles }}" - {{- end }} - {{- if .TPConfig.SkipDirs}} - skip-dirs: "{{ .TPConfig.SkipDirs }}" - {{- end }} - {{- if .TPConfig.ImageRef}} - image-ref: "{{ .TPConfig.ImageRef }}" - {{- end }} - {{- if .TPConfig.HelmOverridesFile}} - helm-overrides-file: "{{ .TPConfig.HelmOverridesFile }}" - {{- end }} -{{- end}} diff --git a/util/constants.go b/util/constants.go new file mode 100644 index 0000000..d356e24 --- /dev/null +++ b/util/constants.go @@ -0,0 +1,5 @@ +package util + +const ( + TemplateFilePath string = "templates/plugins-step.tmpl" +)