From a715b4f2d4adcdb7a161b55f415730d8e3579c7b Mon Sep 17 00:00:00 2001 From: romwol-witt <152502283+romwol-witt@users.noreply.github.com> Date: Fri, 5 Apr 2024 17:36:06 +0200 Subject: [PATCH] Add new flags to toggle deletion of orphan images, setting parent project and dtrack project name by k8s pod annotation (#563) * feat: add new flags to toggle deletion of orphan projects, setting parent project and dtrack project name by k8s annotation feat: add two new flags to toggle deletion of orphan projects and setting parent project by k8s annotation feat: add new flags to toggle deletion of orphan projects, setting parent project and dtrack project name by k8s annotation readme readme readme readme readme readme readme release test release test chore: release 2.0.0 release test chore: release 2.0.1 release test chore: release 2.0.2 release test release test chore: release 2.0.4 release test chore: release 2.0.5 release test chore: release 2.0.6 cleanup test stuff * for loop bug fixed * Renamed config Key "DeleteOrphanProjects" to "DeleteOrphanImages" --------- Co-authored-by: mondeg --- README.md | 52 ++++++++++ internal/config.go | 88 +++++++++-------- internal/processor/processor.go | 10 +- internal/target/dtrack/dtrack_target.go | 124 ++++++++++++++++++++---- main.go | 3 + 5 files changed, 215 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 630f4a53..14d244a1 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ All parameters are cli-flags. The flags can be configured as args or as environm | `namespace-label-selector` | `false` | `""` | Kubernetes Label-Selector for namespaces. | | `fallback-image-pull-secret` | `false` | `""` | Kubernetes Pull-Secret Name to load as a fallback when all others fail (must be in the same namespace as the sbom-operator) | | `registry-proxy` | `false` | `[]` | Proxy-Registry-Hosts to use. Flag can be used multiple times. Value-Mapping e.g. `docker.io=ghcr.io` | +| `delete-orphan-images` | `false` | `true` | Delete orphan images automatically | ### Example Helm-Config @@ -122,12 +123,63 @@ not present in the cluster anymore are removed from the configured targets (exce | `dtrack-ca-cert-file` | `false` | `""` | CA-Certificate filepath when using mTLS to connect to dtrack | | `dtrack-client-cert-file` | `true` when `dtrack-ca-cert-file` is provided | `""` | Client-Certificate filepath when using mTLS to connect to dtrack | | `dtrack-client-key-file` | `true` when `dtrack-ca-cert-file` is provided | `""` | Client-Key filepath when using mTLS to connect to dtrack | +| `dtrack-parent-project-annotation-key` | `false` | `""` | Kubernetes pod annotation key to set parent project automatically, e.g. "my.pod.annotation" | +| `dtrack-project-name-annotation-key` | `false` | `""` | Kubernetes pod annotation key to set custom dtrack project name automatically, e.g. "my.pod.annotation" | | `kubernetes-cluster-id` | `false` | `"default"` | Kubernetes Cluster ID (to be used in Dependency-Track or Job-Images) | Each image in the cluster is created as project with the full-image name (registry and image-path without tag) and the image-tag as project-version. When there's no image-tag, but a digest, the digest is used as project-version. The `autoCreate` option of DT is used. You have to set the `--format` flag to `cyclonedx` with this target. +--- +#### Custom dtrack project name: + +The key at kubernetes has to be suffixed with the container name the project is for. e.g. `my.project.name/my-nginx`. +> [!IMPORTANT] +> The suffix regarding container name must not be added to the config value and must not include `/`. e.g. `my.project.name` + +The value for a custom project name in dtrack by annotation at the specific Pod is written in the format of `project:version` or just `project` where version defaults to `latest`. E.g. `MyParentProject` or `MyParentProject:1.0` + +--- + +#### Setting parent project at Dependency Track automatically: + +The key at kubernetes has to be suffixed with the container name the parent project is for. e.g. `my.parent.project/my-nginx`. +The value for the parent project annotation at the specific Pod is written in the format of `project:version` or just `project` where version defaults to `latest`. E.g. `MyParentProject` or `MyParentProject:1.0` + +> [!IMPORTANT] +> The suffix regarding container name must not be added to the config value and must not include `/`. e.g. `my.parent.project` + +--- + +#### Example Pod Annotation: +```yaml +apiVersion: v1 +kind: Pod +metadata: + annotations: + my.parent.project/my-nginx: MyParentProject + my.project.name/my-nginx: MyNginxProject:1.0 + my.parent.project/my-sidecar: MyOtherParentProject + my.project.name/my-sidecar: MySidecarProject:1.0.1 +spec: + containers: + - image: nginx:latest + name: my-nginx + ... + - image: some-other-image:latest + name: my-sidecar + ... +... +``` +--- + +#### sbom-operator config: +```bash +--dtrack-parent-project-annotation-key=my.parent.project +--dtrack-project-name-annotation-key=my.project.name +``` +--- ### Git diff --git a/internal/config.go b/internal/config.go index 092246a7..6da4ce05 100644 --- a/internal/config.go +++ b/internal/config.go @@ -1,40 +1,43 @@ package internal type Config struct { - Cron string `yaml:"cron" env:"SBOM_CRON" flag:"cron"` - Format string `yaml:"format" env:"SBOM_FORMAT" flag:"format"` - Targets []string `yaml:"targets" env:"SBOM_TARGETS" flag:"targets"` - IgnoreAnnotations bool `yaml:"ignoreAnnotations" env:"SBOM_IGNORE_ANNOTATIONS" flag:"ignore-annotations"` - GitWorkingTree string `yaml:"gitWorkingTree" env:"SBOM_GIT_WORKINGTREE" flag:"git-workingtree"` - GitRepository string `yaml:"gitRepository" env:"SBOM_GIT_REPOSITORY" flag:"git-repository"` - GitBranch string `yaml:"gitBranch" env:"SBOM_GIT_BRANCH" flag:"git-branch"` - GitPath string `yaml:"gitPath" env:"SBOM_GIT_PATH" flag:"git-path"` - GitAccessToken string `yaml:"gitAccessToken" env:"SBOM_GIT_ACCESS_TOKEN" flag:"git-access-token"` - GitUserName string `yaml:"gitUserName" env:"SBOM_GIT_USERNAME" flag:"git-username"` - GitPassword string `yaml:"gitPassword" env:"SBOM_GIT_PASSWORD" flag:"git-password"` - GitAuthorName string `yaml:"gitAuthorName" env:"SBOM_GIT_AUTHOR_NAME" flag:"git-author-name"` - GitAuthorEmail string `yaml:"gitAuthorEmail" env:"SBOM_GIT_AUTHOR_EMAIL" flag:"git-author-email"` - GitHubAppId string `yaml:"githubAppId" env:"SBOM_GITHUB_APP_ID" flag:"github-app-id"` - GitHubAppInstallationId string `yaml:"githubAppInstallationId" env:"SBOM_GITHUB_APP_INSTALLATION_ID" flag:"github-app-installation-id"` - GitHubPrivateKey string `yaml:"githubAppPrivateKey" env:"SBOM_GITHUB_APP_PRIVATE_KEY"` - PodLabelSelector string `yaml:"podLabelSelector" env:"SBOM_POD_LABEL_SELECTOR" flag:"pod-label-selector"` - NamespaceLabelSelector string `yaml:"namespaceLabelSelector" env:"SBOM_NAMESPACE_LABEL_SELECTOR" flag:"namespace-label-selector"` - DtrackBaseUrl string `yaml:"dtrackBaseUrl" env:"SBOM_DTRACK_BASE_URL" flag:"dtrack-base-url"` - DtrackApiKey string `yaml:"dtrackApiKey" env:"SBOM_DTRACK_API_KEY" flag:"dtrack-api-key"` - DtrackLabelTagMatcher string `yaml:"dtrackLabelTagMatcher" env:"SBOM_DTRACK_LABEL_TAG_MATCHER" flag:"dtrack-label-tag-matcher"` - DtrackCaCertFile string `yaml:"dtrackCaCertFile" env:"SBOM_DTRACK_CA_CERT_FILE" flag:"dtrack-ca-cert-file"` - DtrackClientCertFile string `yaml:"dtrackClientCertFile" env:"SBOM_DTRACK_CLIENT_CERT_FILE" flag:"dtrack-client-cert-file"` - DtrackClientKeyFile string `yaml:"dtrackClientKeyFile" env:"SBOM_DTRACK_CLIENT_KEY_FILE" flag:"dtrack-client-key-file"` - KubernetesClusterId string `yaml:"kubernetesClusterId" env:"SBOM_KUBERNETES_CLUSTER_ID" flag:"kubernetes-cluster-id"` - JobImage string `yaml:"jobImage" env:"SBOM_JOB_IMAGE" flag:"job-image"` - JobImagePullSecret string `yaml:"jobImagePullSecret" env:"SBOM_JOB_IMAGE_PULL_SECRET" flag:"job-image-pull-secret"` - JobTimeout int64 `yaml:"jobTimeout" env:"SBOM_JOB_TIMEOUT" flag:"job-timeout"` - OciRegistry string `yaml:"ociRegistry" env:"SBOM_OCI_REGISTRY" flag:"oci-registry"` - OciUser string `yaml:"ociUser" env:"SBOM_OCI_USER" flag:"oci-user"` - OciToken string `yaml:"ociToken" env:"SBOM_OCI_TOKEN" flag:"oci-token"` - FallbackPullSecret string `yaml:"fallbackPullSecret" env:"SBOM_FALLBACK_PULL_SECRET" flag:"fallback-pull-secret"` - RegistryProxies []string `yaml:"registryProxy" env:"SBOM_REGISTRY_PROXY" flag:"registry-proxy"` - Verbosity string `env:"SBOM_VERBOSITY" flag:"verbosity"` + Cron string `yaml:"cron" env:"SBOM_CRON" flag:"cron"` + Format string `yaml:"format" env:"SBOM_FORMAT" flag:"format"` + Targets []string `yaml:"targets" env:"SBOM_TARGETS" flag:"targets"` + IgnoreAnnotations bool `yaml:"ignoreAnnotations" env:"SBOM_IGNORE_ANNOTATIONS" flag:"ignore-annotations"` + GitWorkingTree string `yaml:"gitWorkingTree" env:"SBOM_GIT_WORKINGTREE" flag:"git-workingtree"` + GitRepository string `yaml:"gitRepository" env:"SBOM_GIT_REPOSITORY" flag:"git-repository"` + GitBranch string `yaml:"gitBranch" env:"SBOM_GIT_BRANCH" flag:"git-branch"` + GitPath string `yaml:"gitPath" env:"SBOM_GIT_PATH" flag:"git-path"` + GitAccessToken string `yaml:"gitAccessToken" env:"SBOM_GIT_ACCESS_TOKEN" flag:"git-access-token"` + GitUserName string `yaml:"gitUserName" env:"SBOM_GIT_USERNAME" flag:"git-username"` + GitPassword string `yaml:"gitPassword" env:"SBOM_GIT_PASSWORD" flag:"git-password"` + GitAuthorName string `yaml:"gitAuthorName" env:"SBOM_GIT_AUTHOR_NAME" flag:"git-author-name"` + GitAuthorEmail string `yaml:"gitAuthorEmail" env:"SBOM_GIT_AUTHOR_EMAIL" flag:"git-author-email"` + GitHubAppId string `yaml:"githubAppId" env:"SBOM_GITHUB_APP_ID" flag:"github-app-id"` + GitHubAppInstallationId string `yaml:"githubAppInstallationId" env:"SBOM_GITHUB_APP_INSTALLATION_ID" flag:"github-app-installation-id"` + GitHubPrivateKey string `yaml:"githubAppPrivateKey" env:"SBOM_GITHUB_APP_PRIVATE_KEY"` + PodLabelSelector string `yaml:"podLabelSelector" env:"SBOM_POD_LABEL_SELECTOR" flag:"pod-label-selector"` + NamespaceLabelSelector string `yaml:"namespaceLabelSelector" env:"SBOM_NAMESPACE_LABEL_SELECTOR" flag:"namespace-label-selector"` + DeleteOrphanImages bool `yaml:"deleteOrphanImages" env:"SBOM_DELETRE_ORPHAN_IMAGES" flag:"delete-orphan-images"` + DtrackBaseUrl string `yaml:"dtrackBaseUrl" env:"SBOM_DTRACK_BASE_URL" flag:"dtrack-base-url"` + DtrackApiKey string `yaml:"dtrackApiKey" env:"SBOM_DTRACK_API_KEY" flag:"dtrack-api-key"` + DtrackLabelTagMatcher string `yaml:"dtrackLabelTagMatcher" env:"SBOM_DTRACK_LABEL_TAG_MATCHER" flag:"dtrack-label-tag-matcher"` + DtrackCaCertFile string `yaml:"dtrackCaCertFile" env:"SBOM_DTRACK_CA_CERT_FILE" flag:"dtrack-ca-cert-file"` + DtrackClientCertFile string `yaml:"dtrackClientCertFile" env:"SBOM_DTRACK_CLIENT_CERT_FILE" flag:"dtrack-client-cert-file"` + DtrackClientKeyFile string `yaml:"dtrackClientKeyFile" env:"SBOM_DTRACK_CLIENT_KEY_FILE" flag:"dtrack-client-key-file"` + DtrackParentProjectAnnotationKey string `yaml:"dtrackParentProjectAnnotationKey" env:"SBOM_DTRACK_PARENT_PROJECT_ANNOTATION_KEY" flag:"dtrack-parent-project-annotation-key"` + DtrackProjectNameAnnotationKey string `yaml:"dtrackProjectNameAnnotationKey" env:"SBOM_DTRACK_PROJECT_NAME_ANNOTATION_KEY" flag:"dtrack-project-name-annotation-key"` + KubernetesClusterId string `yaml:"kubernetesClusterId" env:"SBOM_KUBERNETES_CLUSTER_ID" flag:"kubernetes-cluster-id"` + JobImage string `yaml:"jobImage" env:"SBOM_JOB_IMAGE" flag:"job-image"` + JobImagePullSecret string `yaml:"jobImagePullSecret" env:"SBOM_JOB_IMAGE_PULL_SECRET" flag:"job-image-pull-secret"` + JobTimeout int64 `yaml:"jobTimeout" env:"SBOM_JOB_TIMEOUT" flag:"job-timeout"` + OciRegistry string `yaml:"ociRegistry" env:"SBOM_OCI_REGISTRY" flag:"oci-registry"` + OciUser string `yaml:"ociUser" env:"SBOM_OCI_USER" flag:"oci-user"` + OciToken string `yaml:"ociToken" env:"SBOM_OCI_TOKEN" flag:"oci-token"` + FallbackPullSecret string `yaml:"fallbackPullSecret" env:"SBOM_FALLBACK_PULL_SECRET" flag:"fallback-pull-secret"` + RegistryProxies []string `yaml:"registryProxy" env:"SBOM_REGISTRY_PROXY" flag:"registry-proxy"` + Verbosity string `env:"SBOM_VERBOSITY" flag:"verbosity"` } var ( @@ -55,15 +58,18 @@ var ( ConfigKeyGitHubAppInstallationId = "github-app-installation-id" ConfigKeyPodLabelSelector = "pod-label-selector" ConfigKeyNamespaceLabelSelector = "namespace-label-selector" + ConfigKeyDeleteOrphanImages = "delete-orphan-images" ConfigKeyDependencyTrackBaseUrl = "dtrack-base-url" /* #nosec */ - ConfigKeyDependencyTrackApiKey = "dtrack-api-key" - ConfigKeyDependencyTrackLabelTagMatcher = "dtrack-label-tag-matcher" - ConfigKeyDependencyTrackCaCertFile = "dtrack-ca-cert-file" - ConfigKeyDependencyTrackClientCertFile = "dtrack-client-cert-file" - ConfigKeyDependencyTrackClientKeyFile = "dtrack-client-key-file" - ConfigKeyKubernetesClusterId = "kubernetes-cluster-id" - ConfigKeyJobImage = "job-image" + ConfigKeyDependencyTrackApiKey = "dtrack-api-key" + ConfigKeyDependencyTrackLabelTagMatcher = "dtrack-label-tag-matcher" + ConfigKeyDependencyTrackCaCertFile = "dtrack-ca-cert-file" + ConfigKeyDependencyTrackClientCertFile = "dtrack-client-cert-file" + ConfigKeyDependencyTrackClientKeyFile = "dtrack-client-key-file" + ConfigKeyDependencyTrackDtrackParentProjectAnnotationKey = "dtrack-parent-project-annotation-key" + ConfigKeyDependencyTrackDtrackProjectNameAnnotationKey = "dtrack-project-name-annotation-key" + ConfigKeyKubernetesClusterId = "kubernetes-cluster-id" + ConfigKeyJobImage = "job-image" /* #nosec */ ConfigKeyJobImagePullSecret = "job-image-pull-secret" ConfigKeyJobTimeout = "job-timeout" diff --git a/internal/processor/processor.go b/internal/processor/processor.go index b296697e..44be8226 100644 --- a/internal/processor/processor.go +++ b/internal/processor/processor.go @@ -135,11 +135,13 @@ func initTargets(k8s *kubernetes.KubeClient) []target.Target { baseUrl := internal.OperatorConfig.DtrackBaseUrl apiKey := internal.OperatorConfig.DtrackApiKey podLabelTagMatcher := internal.OperatorConfig.DtrackLabelTagMatcher + parentProjectAnnotationKey := internal.OperatorConfig.DtrackParentProjectAnnotationKey + projectNameAnnotationKey := internal.OperatorConfig.DtrackProjectNameAnnotationKey caCertFile := internal.OperatorConfig.DtrackCaCertFile clientCertFile := internal.OperatorConfig.DtrackClientCertFile clientKeyFile := internal.OperatorConfig.DtrackClientKeyFile k8sClusterId := internal.OperatorConfig.KubernetesClusterId - t := dtrack.NewDependencyTrackTarget(baseUrl, apiKey, podLabelTagMatcher, caCertFile, clientCertFile, clientKeyFile, k8sClusterId) + t := dtrack.NewDependencyTrackTarget(baseUrl, apiKey, podLabelTagMatcher, caCertFile, clientCertFile, clientKeyFile, k8sClusterId, parentProjectAnnotationKey, projectNameAnnotationKey) err = t.ValidateConfig() targets = append(targets, t) } else if ta == "oci" { @@ -195,7 +197,7 @@ func (p *Processor) executeSyftScans(pods []libk8s.PodInfo, allImages []*liboci. } } - if len(removableImages) > 0 { + if len(removableImages) > 0 && internal.OperatorConfig.DeleteOrphanImages { t.Remove(removableImages) } } @@ -302,7 +304,9 @@ func (p *Processor) cleanupImagesIfNeeded(removedContainers []*libk8s.ContainerI if len(images) > 0 { for _, t := range p.Targets { - t.Remove(images) + if internal.OperatorConfig.DeleteOrphanImages { + t.Remove(images) + } } } } diff --git a/internal/target/dtrack/dtrack_target.go b/internal/target/dtrack/dtrack_target.go index ead9ced8..9244af8b 100644 --- a/internal/target/dtrack/dtrack_target.go +++ b/internal/target/dtrack/dtrack_target.go @@ -20,14 +20,16 @@ import ( type DependencyTrackTarget struct { clientOptions []dtrack.ClientOption - baseUrl string - apiKey string - podLabelTagMatcher string - caCertFile string - clientCertFile string - clientKeyFile string - k8sClusterId string - imageProjectMap map[string]uuid.UUID + baseUrl string + apiKey string + podLabelTagMatcher string + parentProjectAnnotationKey string + projectNameAnnotationKey string + caCertFile string + clientCertFile string + clientKeyFile string + k8sClusterId string + imageProjectMap map[string]uuid.UUID } const ( @@ -37,15 +39,17 @@ const ( podNamespaceTagKey = "namespace" ) -func NewDependencyTrackTarget(baseUrl, apiKey, podLabelTagMatcher, caCertFile, clientCertFile, clientKeyFile, k8sClusterId string) *DependencyTrackTarget { +func NewDependencyTrackTarget(baseUrl, apiKey, podLabelTagMatcher, caCertFile, clientCertFile, clientKeyFile, k8sClusterId string, parentProjectAnnotationKey string, projectNameAnnotationKey string) *DependencyTrackTarget { return &DependencyTrackTarget{ - baseUrl: baseUrl, - apiKey: apiKey, - podLabelTagMatcher: podLabelTagMatcher, - caCertFile: caCertFile, - clientCertFile: clientCertFile, - clientKeyFile: clientKeyFile, - k8sClusterId: k8sClusterId, + baseUrl: baseUrl, + apiKey: apiKey, + podLabelTagMatcher: podLabelTagMatcher, + caCertFile: caCertFile, + clientCertFile: clientCertFile, + clientKeyFile: clientKeyFile, + k8sClusterId: k8sClusterId, + parentProjectAnnotationKey: parentProjectAnnotationKey, + projectNameAnnotationKey: projectNameAnnotationKey, } } @@ -90,7 +94,40 @@ func (g *DependencyTrackTarget) Initialize() error { } func (g *DependencyTrackTarget) ProcessSbom(ctx *target.TargetContext) error { - projectName, version := getRepoWithVersion(ctx.Image) + projectName := "" + version := "" + + logrus.Debugf("%v", g) + // Set custom project name by kubernetes annotation? + if g.projectNameAnnotationKey != "" { + logrus.Debugf(`Try to set project name by configured annotationkey "%s"`, g.projectNameAnnotationKey) + for podAnnotationKey, podAnnotationValue := range ctx.Pod.Annotations { + if strings.HasPrefix(podAnnotationKey, g.projectNameAnnotationKey) { + if podAnnotationValue != "" { + // determine container name from annotation key + containerName := getContainerNameFromAnnotationKey(podAnnotationKey, "/") + if containerName != "" { + logrus.Debugf(`ContainerName found: "%s"`, containerName) + // correct container? + if containerName == ctx.Container.Name { + projectName, version = getNameAndVersionFromString(podAnnotationValue, ":") + logrus.Infof(`Custom project name found at annotation "%s" for container "%s": "%s:%s"`, podAnnotationKey, containerName, projectName, version) + break + } + } else { + logrus.Errorf(`Containername could not be determined from annotation "%s". Skip setting project name.`, podAnnotationKey) + } + } else { + logrus.Errorf(`Empty value for custom project name annotation "%s". Skip setting custom project name.`, podAnnotationKey) + } + } + } + } + + // If projectNameAnnotationKey is not set or could not be parsed correctly, use image instead + if projectName == "" || version == "" { + projectName, version = getRepoWithVersion(ctx.Image) + } if ctx.Sbom == "" { logrus.Infof("Empty SBOM - skip image (image=%s)", ctx.Image.ImageID) @@ -154,9 +191,41 @@ func (g *DependencyTrackTarget) ProcessSbom(ctx *target.TargetContext) error { } } + if g.parentProjectAnnotationKey != "" { + logrus.Debugf("Try to set parent project by configured annotationkey %s", g.parentProjectAnnotationKey) + for podAnnotationKey, podAnnotationValue := range ctx.Pod.Annotations { + logrus.Debugf("AnnotationKey %s starts with %s?", podAnnotationKey, g.parentProjectAnnotationKey) + if strings.HasPrefix(podAnnotationKey, g.parentProjectAnnotationKey) { + // determine container name from annotation key + containerName := getContainerNameFromAnnotationKey(podAnnotationKey, "/") + if containerName != "" { + if podAnnotationValue != "" { + // correct container found? + if containerName == ctx.Container.Name { + parentProjectName, parentProjectVersion := getNameAndVersionFromString(podAnnotationValue, ":") + logrus.Debugf("Try to find parent project by name from annotation \"%s\", for container %s, parentProjectName \"%s\" and parentProjectVersion \"%s\"", podAnnotationKey, containerName, parentProjectName, parentProjectVersion) + parentProject, err := client.Project.Lookup(context.Background(), parentProjectName, parentProjectVersion) + if err != nil { + logrus.WithError(err).Errorf(`Could not find parent project "%s"`, parentProjectName) + } else { + logrus.Infof(`Found parent project with name "%s:%s" and UUID "%s" for container "%s": %+v\n`, parentProjectName, parentProjectVersion, parentProject.UUID, containerName, parentProject) + project.ParentRef = &dtrack.ParentRef{UUID: parentProject.UUID} + } + break + } + } else { + logrus.Errorf(`Empty value for parent project annotation "%s". Skip setting parent project.`, podAnnotationKey) + } + } else { + logrus.Errorf(`Containername could not be determined from annotation "%s". Skip setting parent project.`, podAnnotationKey) + } + } + } + } + _, err = client.Project.Update(context.Background(), project) if err != nil { - logrus.WithError(err).Errorf("Could not update project tags") + logrus.WithError(err).Errorf("Could not update project") } if g.imageProjectMap == nil { @@ -291,6 +360,25 @@ func (g *DependencyTrackTarget) Remove(images []*libk8s.RegistryImage) { } } +func getNameAndVersionFromString(input string, delimiter string) (string, string) { + parts := strings.Split(input, delimiter) + name := parts[0] + version := "latest" + if len(parts) == 2 { + version = parts[1] + } + return name, version +} + +func getContainerNameFromAnnotationKey(annotationKey string, delimiter string) string { + parts := strings.Split(annotationKey, delimiter) + containerName := "" + if len(parts) == 2 { + containerName = parts[1] + } + return containerName +} + func containsTag(tags []dtrack.Tag, tagString string) bool { for _, tag := range tags { if tag.Name == tagString || strings.Index(tag.Name, tagString) == 0 { diff --git a/main.go b/main.go index 3373ee56..3cc68597 100644 --- a/main.go +++ b/main.go @@ -75,9 +75,12 @@ func newRootCmd() *cobra.Command { rootCmd.PersistentFlags().String(internal.ConfigKeyGitHubAppInstallationId, "", "GitHub App Installation ID (for authentication).") rootCmd.PersistentFlags().String(internal.ConfigKeyPodLabelSelector, "", "Kubernetes Label-Selector for pods.") rootCmd.PersistentFlags().String(internal.ConfigKeyNamespaceLabelSelector, "", "Kubernetes Label-Selector for namespaces.") + rootCmd.PersistentFlags().Bool(internal.ConfigKeyDeleteOrphanImages, true, "Set to false to disable automatic removal of orphan images") rootCmd.PersistentFlags().String(internal.ConfigKeyDependencyTrackBaseUrl, "", "Dependency-Track base URL, e.g. 'https://dtrack.example.com'") rootCmd.PersistentFlags().String(internal.ConfigKeyDependencyTrackApiKey, "", "Dependency-Track API key") rootCmd.PersistentFlags().String(internal.ConfigKeyDependencyTrackLabelTagMatcher, "", "Dependency-Track Pod-Label-Tag matcher regex") + rootCmd.PersistentFlags().String(internal.ConfigKeyDependencyTrackDtrackParentProjectAnnotationKey, "", "Dependency-Track: kubernetes annotation-key for setting parent project") + rootCmd.PersistentFlags().String(internal.ConfigKeyDependencyTrackDtrackProjectNameAnnotationKey, "", "Dependency-Track: kubernetes annotation-key for setting custom project name") rootCmd.PersistentFlags().String(internal.ConfigKeyKubernetesClusterId, "default", "Kubernetes Cluster ID") rootCmd.PersistentFlags().String(internal.ConfigKeyJobImage, "", "Custom Job-Image") rootCmd.PersistentFlags().String(internal.ConfigKeyJobImagePullSecret, "", "Custom Job-Image-Pull-Secret")