From 02f30b2a5d1adbcfd66d2d742fab8ebb9c925747 Mon Sep 17 00:00:00 2001 From: Fede Barcelona Date: Wed, 5 Nov 2025 12:29:49 +0100 Subject: [PATCH 1/3] feat(vulnerability-policy): add admission control stage --- .../client/v2/vulnerability_policy_model.go | 4 ++- ...urce_sysdig_secure_vulnerability_policy.go | 27 ++++++++++++++++++- ...sysdig_secure_vulnerability_policy_test.go | 10 ++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/sysdig/internal/client/v2/vulnerability_policy_model.go b/sysdig/internal/client/v2/vulnerability_policy_model.go index dffbaa38..20b30ad6 100644 --- a/sysdig/internal/client/v2/vulnerability_policy_model.go +++ b/sysdig/internal/client/v2/vulnerability_policy_model.go @@ -19,5 +19,7 @@ type Stage struct { } type Configuration struct { - Scope string `json:"scope"` + Scope string `json:"scope"` + Behaviour string `json:"behaviour,omitempty"` + UnknownImageAction string `json:"unknownImageAction,omitempty"` } diff --git a/sysdig/resource_sysdig_secure_vulnerability_policy.go b/sysdig/resource_sysdig_secure_vulnerability_policy.go index af2d7f4d..0916fce7 100644 --- a/sysdig/resource_sysdig_secure_vulnerability_policy.go +++ b/sysdig/resource_sysdig_secure_vulnerability_policy.go @@ -67,6 +67,7 @@ func resourceSysdigSecureVulnerabilityPolicy() *schema.Resource { "pipeline", "registry", "runtime", + "admission_control", }, false)), }, "configuration": { @@ -79,6 +80,18 @@ func resourceSysdigSecureVulnerabilityPolicy() *schema.Resource { Required: true, Description: "Scope expression for this stage", }, + "failure_action": { + Type: schema.TypeString, + Optional: true, + Description: "Required for `admission_control` stage only. Policy Failure Action. What should happen if the policy fails (aka: there's a rule vioation)", + ValidateFunc: validation.StringInSlice([]string{"reject", "warn"}, false), + }, + "unknown_image_action": { + Type: schema.TypeString, + Optional: true, + Description: "Required for `admission_control` stage only. Unknown Image Action. What should happen if the image is unknown.", + ValidateFunc: validation.StringInSlice([]string{"reject", "rejectAndScan", "warn"}, false), + }, }, }, }, @@ -193,6 +206,14 @@ func vulnerabilityPolicyStagesToMap(policyStages []v2.Stage) []map[string]any { newConfig := map[string]any{ "scope": stageconfig.Scope, } + + if stageconfig.Behaviour != "" { + newConfig["failure_action"] = stageconfig.Behaviour + } + + if stageconfig.UnknownImageAction != "" { + newConfig["unknown_image_action"] = stageconfig.UnknownImageAction + } configsMap = append(configsMap, newConfig) } @@ -297,7 +318,11 @@ func vulnerabilityPolicyConfigsFromSet(set *schema.Set) []v2.Configuration { for _, raw := range set.List() { rawMap := raw.(map[string]any) - out = append(out, v2.Configuration{Scope: rawMap["scope"].(string)}) + out = append(out, v2.Configuration{ + Scope: rawMap["scope"].(string), + Behaviour: rawMap["failure_action"].(string), + UnknownImageAction: rawMap["unknown_image_action"].(string), + }) } return out diff --git a/sysdig/resource_sysdig_secure_vulnerability_policy_test.go b/sysdig/resource_sysdig_secure_vulnerability_policy_test.go index 2fbad888..817f1c87 100644 --- a/sysdig/resource_sysdig_secure_vulnerability_policy_test.go +++ b/sysdig/resource_sysdig_secure_vulnerability_policy_test.go @@ -34,7 +34,7 @@ func TestAccVulnerabilityPolicy(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("sysdig_secure_vulnerability_policy.sample", "bundles.#", "2"), resource.TestCheckResourceAttr("sysdig_secure_vulnerability_policy.sample", "bundles.0", "1"), - resource.TestCheckResourceAttr("sysdig_secure_vulnerability_policy.sample", "stages.#", "3"), + resource.TestCheckResourceAttr("sysdig_secure_vulnerability_policy.sample", "stages.#", "4"), ), }, { @@ -90,6 +90,14 @@ resource "sysdig_secure_vulnerability_policy" "sample" { scope = "agent.tag.cluster = \"my-cluster\"" } } + stages { + name = "admission_control" + configuration { + scope = "agent.tag.cluster = \"my-cluster\"" + failure_action = "reject" + unknown_image_action = "rejectAndScan" + } + } } `, suffix, suffix, suffix) } From b711e8aff17631b40440da454ff6c75939f58f60 Mon Sep 17 00:00:00 2001 From: Fede Barcelona Date: Wed, 5 Nov 2025 12:35:46 +0100 Subject: [PATCH 2/3] docs(vulnerability-policy): add admission control stage documentation --- website/docs/r/secure_vulnerability_policy.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/website/docs/r/secure_vulnerability_policy.md b/website/docs/r/secure_vulnerability_policy.md index 52c7a27f..4b096e3e 100644 --- a/website/docs/r/secure_vulnerability_policy.md +++ b/website/docs/r/secure_vulnerability_policy.md @@ -26,6 +26,15 @@ resource "sysdig_secure_vulnerability_policy" "vulnerability_policy_example" { scope = "container.image != ''" } } + + stages { + name = "admission_control" + configuration { + scope = "kubernetes.cluster.name = 'my-cluster'" + failure_action = "reject" + unknown_image_action = "rejectAndScan" + } + } } ``` @@ -38,12 +47,14 @@ resource "sysdig_secure_vulnerability_policy" "vulnerability_policy_example" { ### Stages block -* `name` - (Required) Must be one of `pipeline`, `registry`, or `runtime`. +* `name` - (Required) Must be one of `pipeline`, `registry`, `runtime`, or `admission_control`. * `configuration` - (Optional) Configuration block for the stage. If no configuration is provided, it will apply to any workload in this stage. ### Configuration block * `scope` - (Required) Scope expression defining the stage applicability. +* `failure_action` - (Optional) Required for `admission_control` stage only. Policy Failure Action. What should happen if the policy fails (aka: there's a rule vioation). Must be one of `reject` or `warn`. +* `unknown_image_action` - (Optional) Required for `admission_control` stage only. Unknown Image Action. What should happen if the image is unknown. Must be one of `reject`, `rejectAndScan`, or `warn`. ## Attributes Reference From 0541fc6e5bd22eaf71ac3c9a365f0c15c0b2e8db Mon Sep 17 00:00:00 2001 From: Fede Barcelona Date: Fri, 21 Nov 2025 13:47:23 +0100 Subject: [PATCH 3/3] fix(resource): handle optional stage attributes in vulnerability policy --- .envrc | 6 +++++ .envrc.template | 12 ---------- .gitignore | 4 ++-- ...urce_sysdig_secure_vulnerability_policy.go | 22 ++++++++++++++----- ...sysdig_secure_vulnerability_policy_test.go | 2 +- 5 files changed, 26 insertions(+), 20 deletions(-) create mode 100644 .envrc delete mode 100644 .envrc.template diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..bacbcba8 --- /dev/null +++ b/.envrc @@ -0,0 +1,6 @@ +export TF_ACC=true +export TF_LOG=DEBUG +dotenv_if_exists .env # You can create a .env file with your env vars for this project. You can also use .secrets if you are using act. See the line below. +dotenv_if_exists .secrets # Used by [act](https://nektosact.com/) to load secrets into the pipelines +strict_env +env_vars_required SYSDIG_SECURE_API_TOKEN SYSDIG_MONITOR_API_TOKEN diff --git a/.envrc.template b/.envrc.template deleted file mode 100644 index 1de08332..00000000 --- a/.envrc.template +++ /dev/null @@ -1,12 +0,0 @@ -# export SYSDIG_SECURE_URL=https://secure.sysdig.com - -# credentials -export SYSDIG_SECURE_API_TOKEN= -export SYSDIG_MONITOR_API_TOKEN= - - -# whether to run local acc test -export TF_ACC=false - -# terraform log level -export TF_LOG=DEBUG \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1605ac60..05a01209 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ *.dll *.exe .DS_Store -.envrc .env +.secrets .direnv/ example.tf terraform.tfplan @@ -54,4 +54,4 @@ oanc # Local test folder local-terraform-test/ dist/ -.secrets + diff --git a/sysdig/resource_sysdig_secure_vulnerability_policy.go b/sysdig/resource_sysdig_secure_vulnerability_policy.go index 0916fce7..6144ed98 100644 --- a/sysdig/resource_sysdig_secure_vulnerability_policy.go +++ b/sysdig/resource_sysdig_secure_vulnerability_policy.go @@ -56,6 +56,10 @@ func resourceSysdigSecureVulnerabilityPolicy() *schema.Resource { "stages": { Type: schema.TypeSet, Optional: true, + Set: func(a any) int { + in := a.(map[string]any) + return schema.HashString(in["name"]) + }, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { @@ -318,11 +322,19 @@ func vulnerabilityPolicyConfigsFromSet(set *schema.Set) []v2.Configuration { for _, raw := range set.List() { rawMap := raw.(map[string]any) - out = append(out, v2.Configuration{ - Scope: rawMap["scope"].(string), - Behaviour: rawMap["failure_action"].(string), - UnknownImageAction: rawMap["unknown_image_action"].(string), - }) + config := v2.Configuration{ + Scope: rawMap["scope"].(string), + } + + if raw, ok := rawMap["failure_action"]; ok { + config.Behaviour = raw.(string) + } + + if raw, ok := rawMap["unknown_image_action"]; ok { + config.UnknownImageAction = raw.(string) + } + + out = append(out, config) } return out diff --git a/sysdig/resource_sysdig_secure_vulnerability_policy_test.go b/sysdig/resource_sysdig_secure_vulnerability_policy_test.go index 817f1c87..42734aef 100644 --- a/sysdig/resource_sysdig_secure_vulnerability_policy_test.go +++ b/sysdig/resource_sysdig_secure_vulnerability_policy_test.go @@ -93,7 +93,7 @@ resource "sysdig_secure_vulnerability_policy" "sample" { stages { name = "admission_control" configuration { - scope = "agent.tag.cluster = \"my-cluster\"" + scope = "not kubernetes.namespace.name in (\"sysdig\", \"sysdig-agent\")" failure_action = "reject" unknown_image_action = "rejectAndScan" }