From 732dbd5ce67d56d9cc243c0cbd77eea69943797c Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 12 Sep 2024 10:18:01 -0700 Subject: [PATCH 01/11] Upgrade Golang to 1.22.7 --- .github/workflows/acceptance-tests.yml | 2 +- .github/workflows/release.yml | 2 +- go.mod | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 019cd7db..967d4f85 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -149,7 +149,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: 1.21 + go-version: '1.22.7' - name: Install Terraform CLI uses: hashicorp/setup-terraform@v3 if: ${{ matrix.cli == 'terraform' }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d8bb220a..6f388555 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,7 +29,7 @@ jobs: name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.21 + go-version: '1.22.7' - name: Import GPG key id: import_gpg diff --git a/go.mod b/go.mod index 0ca52e8f..a2c30f91 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/jfrog/terraform-provider-xray // if you need to do local dev, literally just uncomment the line below // replace github.com/jfrog/terraform-provider-shared => ../terraform-provider-shared -go 1.21.5 +go 1.22.7 require ( github.com/go-resty/resty/v2 v2.14.0 From 3bf24e2f3960372af5fa1f95b1be10e8183c14f9 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 12 Sep 2024 11:21:47 -0700 Subject: [PATCH 02/11] Use correct plan check for migration acceptance tests --- .../resource/resource_xray_license_policy_test.go | 11 +++++++---- .../resource_xray_operational_risk_policy_test.go | 11 +++++++---- .../resource/resource_xray_security_policy_test.go | 11 +++++++---- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/pkg/xray/resource/resource_xray_license_policy_test.go b/pkg/xray/resource/resource_xray_license_policy_test.go index c70804d9..d621202c 100644 --- a/pkg/xray/resource/resource_xray_license_policy_test.go +++ b/pkg/xray/resource/resource_xray_license_policy_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/jfrog/terraform-provider-shared/testutil" "github.com/jfrog/terraform-provider-shared/util" "github.com/jfrog/terraform-provider-shared/util/sdk" @@ -97,11 +98,13 @@ func TestAccLicensePolicy_UpgradeFromSDKv2(t *testing.T) { ), }, { + Config: config, ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, - ResourceName: fqrn, - ImportState: true, - ImportStateId: testData["policy_name"], - ImportStateVerify: true, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, }, }, }) diff --git a/pkg/xray/resource/resource_xray_operational_risk_policy_test.go b/pkg/xray/resource/resource_xray_operational_risk_policy_test.go index 3cc09d39..c3d47abf 100644 --- a/pkg/xray/resource/resource_xray_operational_risk_policy_test.go +++ b/pkg/xray/resource/resource_xray_operational_risk_policy_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/jfrog/terraform-provider-shared/testutil" "github.com/jfrog/terraform-provider-shared/util" "github.com/jfrog/terraform-provider-shared/util/sdk" @@ -84,11 +85,13 @@ func TestAccOperationalRiskPolicy_UpgradeFromSDKv2(t *testing.T) { ), }, { + Config: config, ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, - ResourceName: fqrn, - ImportState: true, - ImportStateId: testData["policy_name"], - ImportStateVerify: true, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, }, }, }) diff --git a/pkg/xray/resource/resource_xray_security_policy_test.go b/pkg/xray/resource/resource_xray_security_policy_test.go index 5a61d761..d7b14730 100644 --- a/pkg/xray/resource/resource_xray_security_policy_test.go +++ b/pkg/xray/resource/resource_xray_security_policy_test.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/jfrog/terraform-provider-shared/testutil" "github.com/jfrog/terraform-provider-shared/util" "github.com/jfrog/terraform-provider-shared/util/sdk" @@ -101,11 +102,13 @@ func TestAccSecurityPolicy_UpgradeFromSDKv2(t *testing.T) { ), }, { + Config: config, ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, - ResourceName: fqrn, - ImportState: true, - ImportStateId: testData["policy_name"], - ImportStateVerify: true, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, }, }, }) From 05881337e27a63c1af5cae96dffc123e58e34afe Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 12 Sep 2024 11:22:41 -0700 Subject: [PATCH 03/11] Moved common schema attributes to shared package --- pkg/xray/resource/policies.go | 44 ++++++++++++ .../resource/resource_xray_security_policy.go | 67 ------------------- 2 files changed, 44 insertions(+), 67 deletions(-) diff --git a/pkg/xray/resource/policies.go b/pkg/xray/resource/policies.go index b7e82400..346b79c5 100644 --- a/pkg/xray/resource/policies.go +++ b/pkg/xray/resource/policies.go @@ -14,6 +14,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/jfrog/terraform-provider-shared/util" @@ -401,6 +403,48 @@ var commonActionsAttrs = map[string]schema.Attribute{ }, } +var policySchemaAttrs = lo.Assign( + projectKeySchemaAttrs(false, ""), + map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + }, + "name": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Description: "Name of the policy (must be unique)", + }, + "description": schema.StringAttribute{ + Optional: true, + Description: "More verbose description of the policy", + }, + "type": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf("security", "license", "operational_risk"), + }, + Description: "Type of the policy", + }, + "author": schema.StringAttribute{ + Computed: true, + Description: "User, who created the policy", + }, + "created": schema.StringAttribute{ + Computed: true, + Description: "Creation timestamp", + }, + "modified": schema.StringAttribute{ + Computed: true, + Description: "Modification timestamp", + }, + }, +) + var policyBlocks = func(criteriaAttrs map[string]schema.Attribute, criteriaBlocks map[string]schema.Block, actionsAttrs map[string]schema.Attribute, actionsBlocks map[string]schema.Block) map[string]schema.Block { return map[string]schema.Block{ "rule": schema.SetNestedBlock{ diff --git a/pkg/xray/resource/resource_xray_security_policy.go b/pkg/xray/resource/resource_xray_security_policy.go index df87d9a0..f4b880ea 100644 --- a/pkg/xray/resource/resource_xray_security_policy.go +++ b/pkg/xray/resource/resource_xray_security_policy.go @@ -2,7 +2,6 @@ package xray import ( "context" - "fmt" "regexp" "github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator" @@ -16,14 +15,10 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/jfrog/terraform-provider-shared/util" - validatorfw_string "github.com/jfrog/terraform-provider-shared/validator/fw/string" - "github.com/samber/lo" ) var _ resource.Resource = &SecurityPolicyResource{} @@ -284,68 +279,6 @@ var securityRuleSetElementType = types.ObjectType{ AttrTypes: securityRuleAttrTypes, } -var projectKeySchemaAttrs = func(isForceNew bool, additionalDescription string) map[string]schema.Attribute { - description := fmt.Sprintf("Project key for assigning this resource to. Must be 2 - 10 lowercase alphanumeric and hyphen characters. %s", additionalDescription) - planModifiers := []planmodifier.String{} - - if isForceNew { - planModifiers = append(planModifiers, stringplanmodifier.RequiresReplace()) - } - - return map[string]schema.Attribute{ - "project_key": schema.StringAttribute{ - Optional: true, - Validators: []validator.String{ - validatorfw_string.ProjectKey(), - }, - PlanModifiers: planModifiers, - Description: description, - }, - } -} - -var policySchemaAttrs = lo.Assign( - projectKeySchemaAttrs(false, ""), - map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - }, - "name": schema.StringAttribute{ - Required: true, - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - Description: "Name of the policy (must be unique)", - }, - "description": schema.StringAttribute{ - Optional: true, - Description: "More verbose description of the policy", - }, - "type": schema.StringAttribute{ - Required: true, - Validators: []validator.String{ - stringvalidator.OneOf("security", "license", "operational_risk"), - }, - Description: "Type of the policy", - }, - "author": schema.StringAttribute{ - Computed: true, - Description: "User, who created the policy", - }, - "created": schema.StringAttribute{ - Computed: true, - Description: "Creation timestamp", - }, - "modified": schema.StringAttribute{ - Computed: true, - Description: "Modification timestamp", - }, - }, -) - var securityPolicyCriteriaBlocks = map[string]schema.Block{ "cvss_range": schema.ListNestedBlock{ NestedObject: schema.NestedBlockObject{ From 870b539e0e5d070eb55038cdb47edbc1f566ac2c Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 12 Sep 2024 12:14:47 -0700 Subject: [PATCH 04/11] Fix provider version not being set correctly --- .goreleaser.yml | 2 +- GNUmakefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 56174f87..950d67e3 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -16,7 +16,7 @@ builds: flags: - -trimpath ldflags: - - '-s -w -X github.com/jfrog/terraform-provider-xray/pkg/xray.Version={{.Version}}' + - '-s -w -X github.com/jfrog/terraform-provider-xray/pkg/xray/provider.Version={{.Version}}' goos: - freebsd - windows diff --git a/GNUmakefile b/GNUmakefile index 96879a10..33c0a269 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -54,7 +54,7 @@ attach: acceptance: fmt export TF_ACC=true && \ - go test -cover -coverprofile=coverage.txt -ldflags="-X '${PKG_VERSION_PATH}.Version=${NEXT_VERSION}-test'" -v -p 1 -parallel 20 -timeout 35m ./pkg/... + go test -cover -coverprofile=coverage.txt -ldflags="-X '${PKG_VERSION_PATH}/provider.Version=${NEXT_VERSION}-test'" -v -p 1 -parallel 20 -timeout 35m ./pkg/... # To generate coverage.txt run `make acceptance` first coverage: From a92ab130439469fa977dd8b5e6cc28872fe5bbaa Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 12 Sep 2024 12:15:12 -0700 Subject: [PATCH 05/11] Migrate xray_vulnerabilities_report to Plugin Framework --- pkg/xray/provider/framework.go | 1 + pkg/xray/provider/sdkv2.go | 1 - pkg/xray/resource/reports.go | 1069 +++++++++++++---- .../resource/resource_xray_report_test.go | 59 + .../resource_xray_vulnerabilities_report.go | 441 +++++-- pkg/xray/resource/util.go | 74 +- 6 files changed, 1305 insertions(+), 340 deletions(-) diff --git a/pkg/xray/provider/framework.go b/pkg/xray/provider/framework.go index e37f6c05..2e897b04 100644 --- a/pkg/xray/provider/framework.go +++ b/pkg/xray/provider/framework.go @@ -185,6 +185,7 @@ func (p *XrayProvider) Resources(ctx context.Context) []func() resource.Resource xray_resource.NewRepositoryConfigResource, xray_resource.NewSecurityPolicyResource, xray_resource.NewSettingsResource, + xray_resource.NewVulnerabilitiesReportResource, xray_resource.NewWatchResource, xray_resource.NewWebhookResource, xray_resource.NewWorkersCountResource, diff --git a/pkg/xray/provider/sdkv2.go b/pkg/xray/provider/sdkv2.go index 51a67f56..ed19b0ff 100644 --- a/pkg/xray/provider/sdkv2.go +++ b/pkg/xray/provider/sdkv2.go @@ -54,7 +54,6 @@ func SdkV2() *schema.Provider { ResourcesMap: sdk.AddTelemetry( productId, map[string]*schema.Resource{ - "xray_vulnerabilities_report": xray.ResourceXrayVulnerabilitiesReport(), "xray_licenses_report": xray.ResourceXrayLicensesReport(), "xray_violations_report": xray.ResourceXrayViolationsReport(), "xray_operational_risks_report": xray.ResourceXrayOperationalRisksReport(), diff --git a/pkg/xray/resource/reports.go b/pkg/xray/resource/reports.go index 96bd3a8a..b083a944 100644 --- a/pkg/xray/resource/reports.go +++ b/pkg/xray/resource/reports.go @@ -5,63 +5,474 @@ import ( "fmt" "net/http" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + sdkv2_diag "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + sdkv2_schema "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/jfrog/terraform-provider-shared/util" + utilfw "github.com/jfrog/terraform-provider-shared/util/fw" "github.com/jfrog/terraform-provider-shared/util/sdk" - "github.com/jfrog/terraform-provider-shared/validator" + sdkv2_validator "github.com/jfrog/terraform-provider-shared/validator" + "github.com/samber/lo" "golang.org/x/exp/slices" ) -var getReportSchema = func(filtersSchema map[string]*schema.Schema) map[string]*schema.Schema { +const ( + ReportsEndpoint = "xray/api/v1/reports/{reportType}" + ReportEndpoint = "xray/api/v1/reports/{reportId}" +) + +type ReportResource struct { + ProviderData util.ProviderMetadata + TypeName string +} + +type ReportResourceModel struct { + ID types.String `tfsdk:"id"` + ReportID types.Int64 `tfsdk:"report_id"` + Name types.String `tfsdk:"name"` + ProjectKey types.String `tfsdk:"project_key"` + Resources types.Set `tfsdk:"resources"` + Filters types.Set `tfsdk:"filters"` +} + +func (m ReportResourceModel) toAPIModel( + ctx context.Context, + apiModel *ReportAPIModel, + toFiltersAPIModel func(ctx context.Context, filtersElems []attr.Value) (*FiltersAPIModel, diag.Diagnostics), +) diag.Diagnostics { + diags := diag.Diagnostics{} + + var resources *ResourcesAPIModel + + if len(m.Resources.Elements()) > 0 { + attrs := m.Resources.Elements()[0].(types.Object).Attributes() + + var repositories *[]RepositoryAPIModel + if v, ok := attrs["repository"]; ok { + if len(v.(types.Set).Elements()) > 0 { + rs := lo.Map( + v.(types.Set).Elements(), + func(elem attr.Value, _ int) RepositoryAPIModel { + attrs := elem.(types.Object).Attributes() + + var includePathPatterns []string + d := attrs["include_path_patterns"].(types.Set).ElementsAs(ctx, &includePathPatterns, false) + if d.HasError() { + diags.Append(d...) + } + + var excludePathPatterns []string + d = attrs["exclude_path_patterns"].(types.Set).ElementsAs(ctx, &excludePathPatterns, false) + if d.HasError() { + diags.Append(d...) + } + + return RepositoryAPIModel{ + Name: attrs["name"].(types.String).ValueString(), + IncludePathPatterns: includePathPatterns, + ExcludePathPatterns: excludePathPatterns, + } + }, + ) + + repositories = &rs + } + } + + var builds *BuildsAPIModel + if v, ok := attrs["builds"]; ok { + if len(v.(types.Set).Elements()) > 0 { + attrs := v.(types.Set).Elements()[0].(types.Object).Attributes() + + var names []string + d := attrs["names"].(types.Set).ElementsAs(ctx, &names, false) + if d.HasError() { + diags.Append(d...) + } + + var includePatterns []string + d = attrs["include_patterns"].(types.Set).ElementsAs(ctx, &includePatterns, false) + if d.HasError() { + diags.Append(d...) + } + + var excludePatterns []string + d = attrs["exclude_patterns"].(types.Set).ElementsAs(ctx, &excludePatterns, false) + if d.HasError() { + diags.Append(d...) + } + + builds = &BuildsAPIModel{ + Names: names, + IncludePatterns: includePatterns, + ExcludePatterns: excludePatterns, + NumberOfLatestVersions: attrs["number_of_latest_versions"].(types.Int64).ValueInt64(), + } + } + } + + var releaseBundles *ReleaseBundlesAPIModel + if v, ok := attrs["release_bundles"]; ok { + if len(v.(types.Set).Elements()) > 0 { + attrs := v.(types.Set).Elements()[0].(types.Object).Attributes() + + var names []string + d := attrs["names"].(types.Set).ElementsAs(ctx, &names, false) + if d.HasError() { + diags.Append(d...) + } + + var includePatterns []string + d = attrs["include_patterns"].(types.Set).ElementsAs(ctx, &includePatterns, false) + if d.HasError() { + diags.Append(d...) + } + + var excludePatterns []string + d = attrs["exclude_patterns"].(types.Set).ElementsAs(ctx, &excludePatterns, false) + if d.HasError() { + diags.Append(d...) + } + + releaseBundles = &ReleaseBundlesAPIModel{ + Names: names, + IncludePatterns: includePatterns, + ExcludePatterns: excludePatterns, + NumberOfLatestVersions: attrs["number_of_latest_versions"].(types.Int64).ValueInt64(), + } + } + } + + var projects *ProjectsAPIModel + if v, ok := attrs["projects"]; ok { + if len(v.(types.Set).Elements()) > 0 { + attrs := v.(types.Set).Elements()[0].(types.Object).Attributes() + + var names []string + d := attrs["names"].(types.Set).ElementsAs(ctx, &names, false) + if d.HasError() { + diags.Append(d...) + } + + var includeKeyPatterns []string + d = attrs["include_key_patterns"].(types.Set).ElementsAs(ctx, &includeKeyPatterns, false) + if d.HasError() { + diags.Append(d...) + } + + projects = &ProjectsAPIModel{ + Names: names, + IncludeKeyPatterns: includeKeyPatterns, + NumberOfLatestVersions: attrs["number_of_latest_versions"].(types.Int64).ValueInt64(), + } + } + } + + resources = &ResourcesAPIModel{ + Repositories: repositories, + Builds: builds, + ReleaseBundles: releaseBundles, + Projects: projects, + } + } + + filters, ds := toFiltersAPIModel(ctx, m.Filters.Elements()) + if ds.HasError() { + diags.Append(ds...) + } + + *apiModel = ReportAPIModel{ + Name: m.Name.ValueString(), + Resources: resources, + Filters: filters, + } + + return diags +} + +var reportsSchemaAttrs = lo.Assign( + projectKeySchemaAttrs(false, ""), + map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "report_id": schema.Int64Attribute{ + Computed: true, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.UseStateForUnknown(), + }, + Description: "Report ID", + }, + "name": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Description: "Name of the report.", + }, + }, +) + +var reportsBlocks = func(filtersAttrs map[string]schema.Attribute, filtersBlocks map[string]schema.Block) map[string]schema.Block { + return map[string]schema.Block{ + "resources": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Blocks: map[string]schema.Block{ + "repository": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + Description: "Repository name.", + }, + "include_path_patterns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Description: "Include path patterns.", + }, + "exclude_path_patterns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Description: "Exclude path patterns.", + }, + }, + }, + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("builds"), + path.MatchRelative().AtParent().AtName("release_bundles"), + path.MatchRelative().AtParent().AtName("projects"), + ), + }, + Description: "The list of repositories for the report. Only one type of resource can be set per report.", + }, + "builds": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "names": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Description: "The list of build names. Only one of 'names' or '*_patterns' can be set.", + }, + "include_patterns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Description: "The list of include patterns. Only one of 'names' or '*_patterns' can be set.", + }, + "exclude_patterns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Description: "The list of exclude patterns. Only one of 'names' or '*_patterns' can be set.", + }, + "number_of_latest_versions": schema.Int64Attribute{ + Optional: true, + Computed: true, + Default: int64default.StaticInt64(1), + Validators: []validator.Int64{ + int64validator.AtLeast(1), + }, + Description: "The number of latest build versions to include to the report.", + }, + }, + }, + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("repository"), + path.MatchRelative().AtParent().AtName("release_bundles"), + path.MatchRelative().AtParent().AtName("projects"), + ), + }, + Description: "The builds to include into the report. Only one type of resource can be set per report.", + }, + "release_bundles": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "names": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Description: "The list of release bundles names.", + }, + "include_patterns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Description: "The list of include patterns", + }, + "exclude_patterns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Description: "The list of exclude patterns", + }, + "number_of_latest_versions": schema.Int64Attribute{ + Optional: true, + Computed: true, + Default: int64default.StaticInt64(1), + Validators: []validator.Int64{ + int64validator.AtLeast(0), + }, + Description: "The number of latest release bundle versions to include to the report.", + }, + }, + }, + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("repository"), + path.MatchRelative().AtParent().AtName("builds"), + path.MatchRelative().AtParent().AtName("projects"), + ), + }, + Description: "The release bundles to include into the report. Only one type of resource can be set per report.", + }, + "projects": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "names": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Description: "The list of project names.", + }, + "include_key_patterns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Description: "The list of include patterns", + }, + "number_of_latest_versions": schema.Int64Attribute{ + Optional: true, + Computed: true, + Default: int64default.StaticInt64(1), + Validators: []validator.Int64{ + int64validator.AtLeast(0), + }, + Description: "The number of latest release bundle versions to include to the report.", + }, + }, + }, + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("repository"), + path.MatchRelative().AtParent().AtName("builds"), + path.MatchRelative().AtParent().AtName("release_bundles"), + ), + }, + Description: "The projects to include into the report. Only one type of resource can be set per report.", + }, + }, + }, + Validators: []validator.Set{ + setvalidator.IsRequired(), + setvalidator.SizeAtMost(1), + }, + Description: "The list of resources to include into the report.", + }, + "filters": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: filtersAttrs, + Blocks: filtersBlocks, + }, + Validators: []validator.Set{ + setvalidator.IsRequired(), + setvalidator.SizeAtMost(1), + }, + Description: "Advanced filters.", + }, + } +} + +var getReportSchema = func(filtersSchema map[string]*sdkv2_schema.Schema) map[string]*sdkv2_schema.Schema { return sdk.MergeMaps( getProjectKeySchema(false, ""), - map[string]*schema.Schema{ + map[string]*sdkv2_schema.Schema{ "report_id": { - Type: schema.TypeInt, + Type: sdkv2_schema.TypeInt, Optional: true, Computed: true, Description: "Report ID", }, "name": { - Type: schema.TypeString, + Type: sdkv2_schema.TypeString, Required: true, ForceNew: true, - ValidateDiagFunc: validator.StringIsNotEmpty, + ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, Description: "Name of the report.", }, "resources": { - Type: schema.TypeSet, + Type: sdkv2_schema.TypeSet, Required: true, MaxItems: 1, Description: "The list of resources to include into the report.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ + Elem: &sdkv2_schema.Resource{ + Schema: map[string]*sdkv2_schema.Schema{ "repository": { - Type: schema.TypeSet, + Type: sdkv2_schema.TypeSet, Optional: true, MinItems: 1, Description: "The list of repositories for the report. Only one type of resource can be set per report.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ + Elem: &sdkv2_schema.Resource{ + Schema: map[string]*sdkv2_schema.Schema{ "name": { - Type: schema.TypeString, + Type: sdkv2_schema.TypeString, Required: true, - ValidateDiagFunc: validator.StringIsNotEmpty, + ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, Description: "Repository name.", }, "include_path_patterns": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "Include path patterns.", }, "exclude_path_patterns": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "Exclude path patterns.", }, @@ -69,35 +480,35 @@ var getReportSchema = func(filtersSchema map[string]*schema.Schema) map[string]* }, }, "builds": { - Type: schema.TypeSet, + Type: sdkv2_schema.TypeSet, Optional: true, MaxItems: 1, Description: "The builds to include into the report. Only one type of resource can be set per report.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ + Elem: &sdkv2_schema.Resource{ + Schema: map[string]*sdkv2_schema.Schema{ "names": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "The list of build names. Only one of 'names' or '*_patterns' can be set.", }, "include_patterns": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "The list of include patterns. Only one of 'names' or '*_patterns' can be set.", }, "exclude_patterns": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "The list of exclude patterns. Only one of 'names' or '*_patterns' can be set.", }, "number_of_latest_versions": { - Type: schema.TypeInt, + Type: sdkv2_schema.TypeInt, Optional: true, Default: 1, ValidateFunc: validation.IntAtLeast(1), @@ -107,35 +518,35 @@ var getReportSchema = func(filtersSchema map[string]*schema.Schema) map[string]* }, }, "release_bundles": { - Type: schema.TypeSet, + Type: sdkv2_schema.TypeSet, Optional: true, MaxItems: 1, Description: "The release bundles to include into the report. Only one type of resource can be set per report.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ + Elem: &sdkv2_schema.Resource{ + Schema: map[string]*sdkv2_schema.Schema{ "names": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "The list of release bundles names.", }, "include_patterns": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "The list of include patterns", }, "exclude_patterns": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "The list of exclude patterns", }, "number_of_latest_versions": { - Type: schema.TypeInt, + Type: sdkv2_schema.TypeInt, Optional: true, Default: 1, ValidateFunc: validation.IntAtLeast(0), @@ -145,28 +556,28 @@ var getReportSchema = func(filtersSchema map[string]*schema.Schema) map[string]* }, }, "projects": { - Type: schema.TypeSet, + Type: sdkv2_schema.TypeSet, Optional: true, MaxItems: 1, Description: "The projects to include into the report. Only one type of resource can be set per report.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ + Elem: &sdkv2_schema.Resource{ + Schema: map[string]*sdkv2_schema.Schema{ "names": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "The list of project names.", }, "include_key_patterns": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "The list of include patterns.", }, "number_of_latest_versions": { - Type: schema.TypeInt, + Type: sdkv2_schema.TypeInt, Optional: true, Default: 1, ValidateFunc: validation.IntAtLeast(0), @@ -179,10 +590,10 @@ var getReportSchema = func(filtersSchema map[string]*schema.Schema) map[string]* }, }, "filters": { - Type: schema.TypeSet, + Type: sdkv2_schema.TypeSet, Required: true, Description: "Advanced filters.", - Elem: &schema.Resource{ + Elem: &sdkv2_schema.Resource{ Schema: filtersSchema, }, }, @@ -190,162 +601,348 @@ var getReportSchema = func(filtersSchema map[string]*schema.Schema) map[string]* ) } -type Report struct { - ReportId int `json:"report_id,omitempty"` - Name string `json:"name"` - ProjectKey string `json:"-"` - Resources *Resources `json:"resources,omitempty"` - Filters *Filters `json:"filters"` +type ReportAPIModel struct { + ReportId int64 `json:"report_id,omitempty"` + Name string `json:"name"` + ProjectKey string `json:"-"` + Resources *ResourcesAPIModel `json:"resources,omitempty"` + Filters *FiltersAPIModel `json:"filters"` } -type Resources struct { - Repositories *[]Repository `json:"repositories,omitempty"` - Builds *Builds `json:"builds,omitempty"` - ReleaseBundles *ReleaseBundles `json:"release_bundles,omitempty"` - Projects *Projects `json:"projects,omitempty"` +type ResourcesAPIModel struct { + Repositories *[]RepositoryAPIModel `json:"repositories,omitempty"` + Builds *BuildsAPIModel `json:"builds,omitempty"` + ReleaseBundles *ReleaseBundlesAPIModel `json:"release_bundles,omitempty"` + Projects *ProjectsAPIModel `json:"projects,omitempty"` } -type Repository struct { +type RepositoryAPIModel struct { Name string `json:"name,omitempty"` IncludePathPatterns []string `json:"include_path_patterns,omitempty"` ExcludePathPatterns []string `json:"exclude_path_patterns,omitempty"` } -type Builds struct { +type BuildsAPIModel struct { Names []string `json:"names,omitempty"` IncludePatterns []string `json:"include_patterns,omitempty"` ExcludePatterns []string `json:"exclude_patterns,omitempty"` - NumberOfLatestVersions int `json:"number_of_latest_versions,omitempty"` + NumberOfLatestVersions int64 `json:"number_of_latest_versions,omitempty"` } -type ReleaseBundles struct { +type ReleaseBundlesAPIModel struct { Names []string `json:"names,omitempty"` IncludePatterns []string `json:"include_patterns,omitempty"` ExcludePatterns []string `json:"exclude_patterns,omitempty"` - NumberOfLatestVersions int `json:"number_of_latest_versions,omitempty"` + NumberOfLatestVersions int64 `json:"number_of_latest_versions,omitempty"` } -type Projects struct { +type ProjectsAPIModel struct { Names []string `json:"names,omitempty"` IncludeKeyPatterns []string `json:"include_key_patterns,omitempty"` - NumberOfLatestVersions int `json:"number_of_latest_versions,omitempty"` -} - -type Filters struct { - VulnerableComponent string `json:"vulnerable_component,omitempty"` // Vulnerability report filter - ImpactedArtifact string `json:"impacted_artifact,omitempty"` - HasRemediation bool `json:"has_remediation,omitempty"` - Cve string `json:"cve,omitempty"` - IssueId string `json:"issue_id,omitempty"` - CvssScore *CvssScore `json:"cvss_score,omitempty"` - Published *StartAndEndDate `json:"published,omitempty"` - Unknown bool `json:"unknown"` // Licenses report filter - Unrecognized bool `json:"unrecognized"` - LicenseNames []string `json:"license_names,omitempty"` - LicensePatterns []string `json:"license_patterns"` - Type string `json:"type,omitempty"` // Violations report filter - WatchNames []string `json:"watch_names,omitempty"` - WatchPatterns []string `json:"watch_patterns,omitempty"` - PolicyNames []string `json:"policy_names,omitempty"` - Updated *StartAndEndDate `json:"updated"` - SecurityFilters *SecurityFilter `json:"security_filters"` - LicenseFilters *LicenseFilter `json:"license_filters"` - Risks []string `json:"risks,omitempty"` // Operational risks filter - ScanDate *StartAndEndDate `json:"scan_date,omitempty"` // Common attributes - Component string `json:"component,omitempty"` - Artifact string `json:"artifact,omitempty"` - Severities []string `json:"severities,omitempty"` -} - -type CvssScore struct { + NumberOfLatestVersions int64 `json:"number_of_latest_versions,omitempty"` +} + +type FiltersAPIModel struct { + VulnerableComponent string `json:"vulnerable_component,omitempty"` // Vulnerability report filter + ImpactedArtifact string `json:"impacted_artifact,omitempty"` + HasRemediation bool `json:"has_remediation,omitempty"` + CVE string `json:"cve,omitempty"` + IssueId string `json:"issue_id,omitempty"` + CVSSScore *CVSSScoreAPIModel `json:"cvss_score,omitempty"` + Published *StartAndEndDateAPIModel `json:"published,omitempty"` + Unknown bool `json:"unknown"` // Licenses report filter + Unrecognized bool `json:"unrecognized"` + LicenseNames []string `json:"license_names,omitempty"` + LicensePatterns []string `json:"license_patterns,omitempty"` + Type string `json:"type,omitempty"` // Violations report filter + WatchNames []string `json:"watch_names,omitempty"` + WatchPatterns []string `json:"watch_patterns,omitempty"` + PolicyNames []string `json:"policy_names,omitempty"` + Updated *StartAndEndDateAPIModel `json:"updated"` + SecurityFilters *SecurityFilterAPIModel `json:"security_filters,omitempty"` + LicenseFilters *LicenseFilterAPIModel `json:"license_filters,omitempty"` + Risks []string `json:"risks,omitempty"` // Operational risks filter + ScanDate *StartAndEndDateAPIModel `json:"scan_date,omitempty"` // Common attributes + Component string `json:"component,omitempty"` + Artifact string `json:"artifact,omitempty"` + Severities []string `json:"severities,omitempty"` +} + +type CVSSScoreAPIModel struct { MinScore float64 `json:"min_score,omitempty"` MaxScore float64 `json:"max_score,omitempty"` } -type StartAndEndDate struct { +type StartAndEndDateAPIModel struct { Start string `json:"start,omitempty"` End string `json:"end,omitempty"` } -type SecurityFilter struct { - Cve string `json:"cve,omitempty"` - IssueId string `json:"issue_id,omitempty"` - CvssScore *CvssScore `json:"cvss_score,omitempty"` - SummaryContains string `json:"summary_contains"` - HasRemediation bool `json:"has_remediation,omitempty"` - Published *StartAndEndDate `json:"published,omitempty"` +type SecurityFilterAPIModel struct { + Cve string `json:"cve,omitempty"` + IssueId string `json:"issue_id,omitempty"` + CVSSScore *CVSSScoreAPIModel `json:"cvss_score,omitempty"` + SummaryContains string `json:"summary_contains"` + HasRemediation bool `json:"has_remediation,omitempty"` + Published *StartAndEndDateAPIModel `json:"published,omitempty"` } -type LicenseFilter struct { +type LicenseFilterAPIModel struct { Unknown bool `json:"unknown"` Unrecognized bool `json:"unrecognized"` LicenseNames []string `json:"license_names,omitempty"` - LicensePatterns []string `json:"license_patterns"` + LicensePatterns []string `json:"license_patterns,omitempty"` } -func unpackReport(d *schema.ResourceData, reportType string) *Report { - report := Report{} +func unpackReport(d *sdkv2_schema.ResourceData, reportType string) *ReportAPIModel { + report := ReportAPIModel{} if v, ok := d.GetOk("project_key"); ok { report.ProjectKey = v.(string) } report.Name = d.Get("name").(string) - report.Resources = unpackResources(d.Get("resources").(*schema.Set)) + report.Resources = unpackResources(d.Get("resources").(*sdkv2_schema.Set)) if reportType == "vulnerabilities" { - report.Filters = unpackVulnerabilitiesFilters(d.Get("filters").(*schema.Set)) + report.Filters = unpackVulnerabilitiesFilters(d.Get("filters").(*sdkv2_schema.Set)) } if reportType == "licenses" { - report.Filters = unpackLicensesFilters(d.Get("filters").(*schema.Set)) + report.Filters = unpackLicensesFilters(d.Get("filters").(*sdkv2_schema.Set)) } if reportType == "violations" { - report.Filters = unpackViolationsFilters(d.Get("filters").(*schema.Set)) + report.Filters = unpackViolationsFilters(d.Get("filters").(*sdkv2_schema.Set)) } if reportType == "operationalRisks" { - report.Filters = unpackOperationalRisksFilters(d.Get("filters").(*schema.Set)) + report.Filters = unpackOperationalRisksFilters(d.Get("filters").(*sdkv2_schema.Set)) } return &report } -func unpackResources(configured *schema.Set) *Resources { - var resources Resources +func (r *ReportResource) Create( + ctx context.Context, + reportType string, + toAPIModel func(context.Context, ReportResourceModel, *ReportAPIModel) diag.Diagnostics, + req resource.CreateRequest, + resp *resource.CreateResponse, +) { + go util.SendUsageResourceCreate(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName) + + var plan ReportResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + request, err := getRestyRequest(r.ProviderData.Client, plan.ProjectKey.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "failed to get Resty client", + err.Error(), + ) + return + } + + var report ReportAPIModel + resp.Diagnostics.Append(toAPIModel(ctx, plan, &report)...) + if resp.Diagnostics.HasError() { + return + } + + response, err := request. + SetPathParam("reportType", reportType). + SetBody(report). + SetResult(&report). + Post(ReportsEndpoint) + + if err != nil { + utilfw.UnableToCreateResourceError(resp, err.Error()) + return + } + + if response.IsError() { + utilfw.UnableToCreateResourceError(resp, response.String()) + return + } + + plan.ID = types.StringValue(fmt.Sprintf("%d", report.ReportId)) + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *ReportResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + go util.SendUsageResourceRead(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName) + + var state ReportResourceModel + + // Read Terraform state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + request, err := getRestyRequest(r.ProviderData.Client, state.ProjectKey.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "failed to get Resty client", + err.Error(), + ) + return + } + + response, err := request. + SetPathParam("reportId", state.ID.ValueString()). + Get(ReportEndpoint) + + if err != nil { + utilfw.UnableToRefreshResourceError(resp, err.Error()) + return + } + + if response.StatusCode() == http.StatusNotFound { + resp.State.RemoveResource(ctx) + return + } + + if response.IsError() { + utilfw.UnableToRefreshResourceError(resp, response.String()) + return + } + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *ReportResource) Update( + ctx context.Context, + reportType string, + toAPIModel func(context.Context, ReportResourceModel, *ReportAPIModel) diag.Diagnostics, + req resource.UpdateRequest, + resp *resource.UpdateResponse, +) { + go util.SendUsageResourceUpdate(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName) + + var plan ReportResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + request, err := getRestyRequest(r.ProviderData.Client, plan.ProjectKey.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "failed to get Resty client", + err.Error(), + ) + return + } + + var report ReportAPIModel + resp.Diagnostics.Append(toAPIModel(ctx, plan, &report)...) + if resp.Diagnostics.HasError() { + return + } + + response, err := request. + SetPathParam("reportType", reportType). + SetBody(report). + SetResult(&report). + Post(ReportsEndpoint) + + if err != nil { + utilfw.UnableToUpdateResourceError(resp, err.Error()) + return + } + + if response.IsError() { + utilfw.UnableToUpdateResourceError(resp, response.String()) + return + } + + plan.ID = types.StringValue(fmt.Sprintf("%d", report.ReportId)) + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *ReportResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + go util.SendUsageResourceDelete(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName) + + var state ReportResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + request, err := getRestyRequest(r.ProviderData.Client, state.ProjectKey.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "failed to get Resty client", + err.Error(), + ) + return + } + + response, err := request. + SetPathParam("reportId", state.ID.ValueString()). + Delete(ReportEndpoint) + + if err != nil { + utilfw.UnableToDeleteResourceError(resp, err.Error()) + return + } + + if response.IsError() { + utilfw.UnableToDeleteResourceError(resp, response.String()) + return + } + + // If the logic reaches here, it implicitly succeeded and will remove + // the resource from state if there are no other errors. +} + +func unpackResources(configured *sdkv2_schema.Set) *ResourcesAPIModel { + var resources ResourcesAPIModel m := configured.List()[0].(map[string]interface{}) if m["repository"] != nil { - resources.Repositories = unpackRepository(m["repository"].(*schema.Set)) + resources.Repositories = unpackRepository(m["repository"].(*sdkv2_schema.Set)) } if m["builds"] != nil { - resources.Builds = unpackBuilds(m["builds"].(*schema.Set)) + resources.Builds = unpackBuilds(m["builds"].(*sdkv2_schema.Set)) } if m["release_bundles"] != nil { - resources.ReleaseBundles = unpackReleaseBundles(m["release_bundles"].(*schema.Set)) + resources.ReleaseBundles = unpackReleaseBundles(m["release_bundles"].(*sdkv2_schema.Set)) } if m["release_bundles"] != nil { - resources.Projects = unpackProjects(m["projects"].(*schema.Set)) + resources.Projects = unpackProjects(m["projects"].(*sdkv2_schema.Set)) } return &resources } -func unpackRepository(d *schema.Set) *[]Repository { +func unpackRepository(d *sdkv2_schema.Set) *[]RepositoryAPIModel { repos := d.List() if len(d.List()) > 0 { - var repositories []Repository + var repositories []RepositoryAPIModel for _, raw := range repos { f := raw.(map[string]interface{}) - repository := Repository{ + repository := RepositoryAPIModel{ Name: f["name"].(string), - IncludePathPatterns: sdk.CastToStringArr(f["include_path_patterns"].(*schema.Set).List()), - ExcludePathPatterns: sdk.CastToStringArr(f["exclude_path_patterns"].(*schema.Set).List()), + IncludePathPatterns: sdk.CastToStringArr(f["include_path_patterns"].(*sdkv2_schema.Set).List()), + ExcludePathPatterns: sdk.CastToStringArr(f["exclude_path_patterns"].(*sdkv2_schema.Set).List()), } repositories = append(repositories, repository) } @@ -355,15 +952,15 @@ func unpackRepository(d *schema.Set) *[]Repository { return nil } -func unpackBuilds(d *schema.Set) *Builds { +func unpackBuilds(d *sdkv2_schema.Set) *BuildsAPIModel { if len(d.List()) > 0 { - var builds Builds + var builds BuildsAPIModel f := d.List()[0].(map[string]interface{}) - builds = Builds{ - Names: sdk.CastToStringArr(f["names"].(*schema.Set).List()), - IncludePatterns: sdk.CastToStringArr(f["include_patterns"].(*schema.Set).List()), - ExcludePatterns: sdk.CastToStringArr(f["exclude_patterns"].(*schema.Set).List()), - NumberOfLatestVersions: f["number_of_latest_versions"].(int), + builds = BuildsAPIModel{ + Names: sdk.CastToStringArr(f["names"].(*sdkv2_schema.Set).List()), + IncludePatterns: sdk.CastToStringArr(f["include_patterns"].(*sdkv2_schema.Set).List()), + ExcludePatterns: sdk.CastToStringArr(f["exclude_patterns"].(*sdkv2_schema.Set).List()), + NumberOfLatestVersions: f["number_of_latest_versions"].(int64), } return &builds } @@ -371,15 +968,15 @@ func unpackBuilds(d *schema.Set) *Builds { return nil } -func unpackReleaseBundles(d *schema.Set) *ReleaseBundles { +func unpackReleaseBundles(d *sdkv2_schema.Set) *ReleaseBundlesAPIModel { if len(d.List()) > 0 { - var releaseBundles ReleaseBundles + var releaseBundles ReleaseBundlesAPIModel f := d.List()[0].(map[string]interface{}) - releaseBundles = ReleaseBundles{ - Names: sdk.CastToStringArr(f["names"].(*schema.Set).List()), - IncludePatterns: sdk.CastToStringArr(f["include_patterns"].(*schema.Set).List()), - ExcludePatterns: sdk.CastToStringArr(f["exclude_patterns"].(*schema.Set).List()), - NumberOfLatestVersions: f["number_of_latest_versions"].(int), + releaseBundles = ReleaseBundlesAPIModel{ + Names: sdk.CastToStringArr(f["names"].(*sdkv2_schema.Set).List()), + IncludePatterns: sdk.CastToStringArr(f["include_patterns"].(*sdkv2_schema.Set).List()), + ExcludePatterns: sdk.CastToStringArr(f["exclude_patterns"].(*sdkv2_schema.Set).List()), + NumberOfLatestVersions: f["number_of_latest_versions"].(int64), } return &releaseBundles } @@ -387,14 +984,14 @@ func unpackReleaseBundles(d *schema.Set) *ReleaseBundles { return nil } -func unpackProjects(d *schema.Set) *Projects { +func unpackProjects(d *sdkv2_schema.Set) *ProjectsAPIModel { if len(d.List()) > 0 { - var projects Projects + var projects ProjectsAPIModel f := d.List()[0].(map[string]interface{}) - projects = Projects{ - Names: sdk.CastToStringArr(f["names"].(*schema.Set).List()), - IncludeKeyPatterns: sdk.CastToStringArr(f["include_key_patterns"].(*schema.Set).List()), - NumberOfLatestVersions: f["number_of_latest_versions"].(int), + projects = ProjectsAPIModel{ + Names: sdk.CastToStringArr(f["names"].(*sdkv2_schema.Set).List()), + IncludeKeyPatterns: sdk.CastToStringArr(f["include_key_patterns"].(*sdkv2_schema.Set).List()), + NumberOfLatestVersions: f["number_of_latest_versions"].(int64), } return &projects } @@ -402,8 +999,8 @@ func unpackProjects(d *schema.Set) *Projects { return nil } -func unpackVulnerabilitiesFilters(filter *schema.Set) *Filters { - var filters Filters +func unpackVulnerabilitiesFilters(filter *sdkv2_schema.Set) *FiltersAPIModel { + var filters FiltersAPIModel m := filter.List()[0].(map[string]interface{}) if m["vulnerable_component"] != nil { @@ -417,32 +1014,32 @@ func unpackVulnerabilitiesFilters(filter *schema.Set) *Filters { filters.HasRemediation = m["has_remediation"].(bool) if m["cve"] != nil { - filters.Cve = m["cve"].(string) + filters.CVE = m["cve"].(string) } if m["issue_id"] != nil { filters.IssueId = m["issue_id"].(string) } - filters.Severities = sdk.CastToStringArr(m["severities"].(*schema.Set).List()) + filters.Severities = sdk.CastToStringArr(m["severities"].(*sdkv2_schema.Set).List()) if m["cvss_score"] != nil { - filters.CvssScore = unpackCvssScore(m["cvss_score"].(*schema.Set)) + filters.CVSSScore = unpackCvssScore(m["cvss_score"].(*sdkv2_schema.Set)) } if m["published"] != nil { - filters.Published = unpackStartAndEndDate(m["published"].(*schema.Set)) + filters.Published = unpackStartAndEndDate(m["published"].(*sdkv2_schema.Set)) } if m["scan_date"] != nil { - filters.ScanDate = unpackStartAndEndDate(m["scan_date"].(*schema.Set)) + filters.ScanDate = unpackStartAndEndDate(m["scan_date"].(*sdkv2_schema.Set)) } return &filters } -func unpackLicensesFilters(filter *schema.Set) *Filters { - var filters Filters +func unpackLicensesFilters(filter *sdkv2_schema.Set) *FiltersAPIModel { + var filters FiltersAPIModel m := filter.List()[0].(map[string]interface{}) if m["component"] != nil { @@ -456,18 +1053,18 @@ func unpackLicensesFilters(filter *schema.Set) *Filters { filters.Unknown = m["unknown"].(bool) filters.Unrecognized = m["unrecognized"].(bool) - filters.LicenseNames = sdk.CastToStringArr(m["license_names"].(*schema.Set).List()) - filters.LicensePatterns = sdk.CastToStringArr(m["license_patterns"].(*schema.Set).List()) + filters.LicenseNames = sdk.CastToStringArr(m["license_names"].(*sdkv2_schema.Set).List()) + filters.LicensePatterns = sdk.CastToStringArr(m["license_patterns"].(*sdkv2_schema.Set).List()) if m["scan_date"] != nil { - filters.ScanDate = unpackStartAndEndDate(m["scan_date"].(*schema.Set)) + filters.ScanDate = unpackStartAndEndDate(m["scan_date"].(*sdkv2_schema.Set)) } return &filters } -func unpackViolationsSecurityFilters(filter *schema.Set) *SecurityFilter { - var securityFilter SecurityFilter +func unpackViolationsSecurityFilters(filter *sdkv2_schema.Set) *SecurityFilterAPIModel { + var securityFilter SecurityFilterAPIModel m := filter.List()[0].(map[string]interface{}) if m["cve"] != nil { @@ -479,7 +1076,7 @@ func unpackViolationsSecurityFilters(filter *schema.Set) *SecurityFilter { } if m["cvss_score"] != nil { - securityFilter.CvssScore = unpackCvssScore(m["cvss_score"].(*schema.Set)) + securityFilter.CVSSScore = unpackCvssScore(m["cvss_score"].(*sdkv2_schema.Set)) } if m["summary_contains"] != nil { @@ -489,14 +1086,14 @@ func unpackViolationsSecurityFilters(filter *schema.Set) *SecurityFilter { securityFilter.HasRemediation = m["has_remediation"].(bool) if m["updated"] != nil { - securityFilter.Published = unpackStartAndEndDate(m["published"].(*schema.Set)) + securityFilter.Published = unpackStartAndEndDate(m["published"].(*sdkv2_schema.Set)) } return &securityFilter } -func unpackViolationsFilters(filter *schema.Set) *Filters { - var filters Filters +func unpackViolationsFilters(filter *sdkv2_schema.Set) *FiltersAPIModel { + var filters FiltersAPIModel m := filter.List()[0].(map[string]interface{}) if len(m) > 0 { @@ -505,8 +1102,8 @@ func unpackViolationsFilters(filter *schema.Set) *Filters { filters.Type = m["type"].(string) } - filters.WatchNames = sdk.CastToStringArr(m["watch_names"].(*schema.Set).List()) - filters.WatchPatterns = sdk.CastToStringArr(m["watch_patterns"].(*schema.Set).List()) + filters.WatchNames = sdk.CastToStringArr(m["watch_names"].(*sdkv2_schema.Set).List()) + filters.WatchPatterns = sdk.CastToStringArr(m["watch_patterns"].(*sdkv2_schema.Set).List()) if m["component"] != nil { filters.Component = m["component"].(string) @@ -516,19 +1113,19 @@ func unpackViolationsFilters(filter *schema.Set) *Filters { filters.Artifact = m["artifact"].(string) } - filters.PolicyNames = sdk.CastToStringArr(m["policy_names"].(*schema.Set).List()) - filters.Severities = sdk.CastToStringArr(m["severities"].(*schema.Set).List()) + filters.PolicyNames = sdk.CastToStringArr(m["policy_names"].(*sdkv2_schema.Set).List()) + filters.Severities = sdk.CastToStringArr(m["severities"].(*sdkv2_schema.Set).List()) - if m["updated"].(*schema.Set).Len() > 0 { - filters.Updated = unpackStartAndEndDate(m["updated"].(*schema.Set)) + if m["updated"].(*sdkv2_schema.Set).Len() > 0 { + filters.Updated = unpackStartAndEndDate(m["updated"].(*sdkv2_schema.Set)) } - if m["security_filters"].(*schema.Set).Len() > 0 { - filters.SecurityFilters = unpackViolationsSecurityFilters(m["security_filters"].(*schema.Set)) + if m["security_filters"].(*sdkv2_schema.Set).Len() > 0 { + filters.SecurityFilters = unpackViolationsSecurityFilters(m["security_filters"].(*sdkv2_schema.Set)) } - if m["license_filters"].(*schema.Set).Len() > 0 { - filters.LicenseFilters = unpackViolationsLicensesFilters(m["license_filters"].(*schema.Set)) + if m["license_filters"].(*sdkv2_schema.Set).Len() > 0 { + filters.LicenseFilters = unpackViolationsLicensesFilters(m["license_filters"].(*sdkv2_schema.Set)) } return &filters @@ -536,21 +1133,21 @@ func unpackViolationsFilters(filter *schema.Set) *Filters { return nil } -func unpackViolationsLicensesFilters(filter *schema.Set) *LicenseFilter { - var filters LicenseFilter +func unpackViolationsLicensesFilters(filter *sdkv2_schema.Set) *LicenseFilterAPIModel { + var filters LicenseFilterAPIModel m := filter.List()[0].(map[string]interface{}) filters.Unknown = m["unknown"].(bool) filters.Unrecognized = m["unrecognized"].(bool) - filters.LicenseNames = sdk.CastToStringArr(m["license_names"].(*schema.Set).List()) - filters.LicensePatterns = sdk.CastToStringArr(m["license_patterns"].(*schema.Set).List()) + filters.LicenseNames = sdk.CastToStringArr(m["license_names"].(*sdkv2_schema.Set).List()) + filters.LicensePatterns = sdk.CastToStringArr(m["license_patterns"].(*sdkv2_schema.Set).List()) return &filters } -func unpackOperationalRisksFilters(filter *schema.Set) *Filters { - var filters Filters +func unpackOperationalRisksFilters(filter *sdkv2_schema.Set) *FiltersAPIModel { + var filters FiltersAPIModel m := filter.List()[0].(map[string]interface{}) if m["component"] != nil { @@ -560,21 +1157,21 @@ func unpackOperationalRisksFilters(filter *schema.Set) *Filters { filters.Artifact = m["artifact"].(string) } - filters.Risks = sdk.CastToStringArr(m["risks"].(*schema.Set).List()) + filters.Risks = sdk.CastToStringArr(m["risks"].(*sdkv2_schema.Set).List()) if m["scan_date"] != nil { - filters.ScanDate = unpackStartAndEndDate(m["scan_date"].(*schema.Set)) + filters.ScanDate = unpackStartAndEndDate(m["scan_date"].(*sdkv2_schema.Set)) } return &filters } -func unpackCvssScore(d *schema.Set) *CvssScore { - var cvssScore CvssScore +func unpackCvssScore(d *sdkv2_schema.Set) *CVSSScoreAPIModel { + var cvssScore CVSSScoreAPIModel if len(d.List()) > 0 { f := d.List()[0].(map[string]interface{}) - cvssScore = CvssScore{ + cvssScore = CVSSScoreAPIModel{ MinScore: f["min_score"].(float64), MaxScore: f["max_score"].(float64), } @@ -584,12 +1181,12 @@ func unpackCvssScore(d *schema.Set) *CvssScore { return nil } -func unpackStartAndEndDate(d *schema.Set) *StartAndEndDate { - var dates StartAndEndDate +func unpackStartAndEndDate(d *sdkv2_schema.Set) *StartAndEndDateAPIModel { + var dates StartAndEndDateAPIModel if len(d.List()) > 0 { f := d.List()[0].(map[string]interface{}) - dates = StartAndEndDate{ + dates = StartAndEndDateAPIModel{ Start: f["start"].(string), End: f["end"].(string), } @@ -599,29 +1196,29 @@ func unpackStartAndEndDate(d *schema.Set) *StartAndEndDate { return nil } -func resourceXrayVulnerabilitiesReportCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func resourceXrayVulnerabilitiesReportCreate(ctx context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { return createReport("vulnerabilities", d, m) } -func resourceXrayLicensesReportCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func resourceXrayLicensesReportCreate(ctx context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { return createReport("licenses", d, m) } -func resourceXrayViolationsReportCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func resourceXrayViolationsReportCreate(ctx context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { return createReport("violations", d, m) } -func resourceXrayOperationalRisksReportCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func resourceXrayOperationalRisksReportCreate(ctx context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { return createReport("operationalRisks", d, m) } -func resourceXrayReportRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - report := Report{} +func resourceXrayReportRead(ctx context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { + report := ReportAPIModel{} projectKey := d.Get("project_key").(string) req, err := getRestyRequest(m.(util.ProviderMetadata).Client, projectKey) if err != nil { - return diag.FromErr(err) + return sdkv2_diag.FromErr(err) } resp, err := req. @@ -629,34 +1226,34 @@ func resourceXrayReportRead(ctx context.Context, d *schema.ResourceData, m inter SetPathParam("reportId", d.Id()). Get("xray/api/v1/reports/{reportId}") if err != nil { - return diag.FromErr(err) + return sdkv2_diag.FromErr(err) } if resp.StatusCode() == http.StatusNotFound { d.SetId("") - return diag.Errorf("report (%s) not found, removing from state", d.Id()) + return sdkv2_diag.Errorf("report (%s) not found, removing from state", d.Id()) } if resp.IsError() { - return diag.Errorf("%s", resp.String()) + return sdkv2_diag.Errorf("%s", resp.String()) } return nil } -func resourceXrayReportDelete(_ context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func resourceXrayReportDelete(_ context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { projectKey := d.Get("project_key").(string) req, err := getRestyRequest(m.(util.ProviderMetadata).Client, projectKey) if err != nil { - return diag.FromErr(err) + return sdkv2_diag.FromErr(err) } resp, err := req. SetPathParam("reportId", d.Id()). Delete("xray/api/v1/reports/{reportId}") if err != nil { - return diag.FromErr(err) + return sdkv2_diag.FromErr(err) } if resp.IsError() { - return diag.Errorf("%s", resp.String()) + return sdkv2_diag.Errorf("%s", resp.String()) } d.SetId("") @@ -664,11 +1261,11 @@ func resourceXrayReportDelete(_ context.Context, d *schema.ResourceData, m inter return nil } -func createReport(reportType string, d *schema.ResourceData, m interface{}) diag.Diagnostics { +func createReport(reportType string, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { report := unpackReport(d, reportType) req, err := getRestyRequest(m.(util.ProviderMetadata).Client, report.ProjectKey) if err != nil { - return diag.FromErr(err) + return sdkv2_diag.FromErr(err) } resp, err := req. @@ -677,10 +1274,10 @@ func createReport(reportType string, d *schema.ResourceData, m interface{}) diag SetPathParam("reportType", reportType). Post("xray/api/v1/reports/{reportType}") if err != nil { - return diag.FromErr(err) + return sdkv2_diag.FromErr(err) } if resp.IsError() { - return diag.Errorf("%s", resp.String()) + return sdkv2_diag.Errorf("%s", resp.String()) } d.SetId(fmt.Sprintf("%d", report.ReportId)) @@ -688,8 +1285,8 @@ func createReport(reportType string, d *schema.ResourceData, m interface{}) diag return nil } -func reportResourceDiff(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - reportResources := diff.Get("resources").(*schema.Set).List() +func reportResourceDiff(_ context.Context, diff *sdkv2_schema.ResourceDiff, v interface{}) error { + reportResources := diff.Get("resources").(*sdkv2_schema.Set).List() if len(reportResources) == 0 { return nil } @@ -700,18 +1297,18 @@ func reportResourceDiff(_ context.Context, diff *schema.ResourceDiff, v interfac var resourceCounter int - if r["repository"].(*schema.Set).Len() > 0 { + if r["repository"].(*sdkv2_schema.Set).Len() > 0 { resourceCounter += 1 } - if r["builds"].(*schema.Set).Len() > 0 { + if r["builds"].(*sdkv2_schema.Set).Len() > 0 { resourceCounter += 1 } - if r["release_bundles"].(*schema.Set).Len() > 0 { + if r["release_bundles"].(*sdkv2_schema.Set).Len() > 0 { resourceCounter += 1 } - if r["projects"].(*schema.Set).Len() > 0 { + if r["projects"].(*sdkv2_schema.Set).Len() > 0 { resourceCounter += 1 } @@ -720,7 +1317,7 @@ func reportResourceDiff(_ context.Context, diff *schema.ResourceDiff, v interfac } } // Verify filter fields - reportFilters := diff.Get("filters").(*schema.Set).List() + reportFilters := diff.Get("filters").(*sdkv2_schema.Set).List() for _, reportFilter := range reportFilters { r := reportFilter.(map[string]interface{}) @@ -729,11 +1326,11 @@ func reportResourceDiff(_ context.Context, diff *schema.ResourceDiff, v interfac } // Check violations filter var watchCounter int - if r["watch_names"] != nil && r["watch_names"].(*schema.Set).Len() > 0 { + if r["watch_names"] != nil && r["watch_names"].(*sdkv2_schema.Set).Len() > 0 { watchCounter += 1 } - if r["watch_patterns"] != nil && r["watch_patterns"].(*schema.Set).Len() > 0 { + if r["watch_patterns"] != nil && r["watch_patterns"].(*sdkv2_schema.Set).Len() > 0 { watchCounter += 1 } @@ -755,11 +1352,11 @@ func reportResourceDiff(_ context.Context, diff *schema.ResourceDiff, v interfac } var severitiesFilterCounter int - if r["severities"] != nil && r["severities"].(*schema.Set).Len() > 0 { + if r["severities"] != nil && r["severities"].(*sdkv2_schema.Set).Len() > 0 { severitiesFilterCounter += 1 } - if r["cvss_score"] != nil && r["cvss_score"].(*schema.Set).Len() > 0 { + if r["cvss_score"] != nil && r["cvss_score"].(*sdkv2_schema.Set).Len() > 0 { severitiesFilterCounter += 1 } @@ -769,12 +1366,12 @@ func reportResourceDiff(_ context.Context, diff *schema.ResourceDiff, v interfac // Check license filter in violations report var nestedLicenseFilterCounter int - if r["license_filters"] != nil && r["license_filters"].(*schema.Set).Len() > 0 { - m := r["license_filters"].(*schema.Set).List()[0].(map[string]interface{}) - if m["license_names"] != nil && m["license_names"].(*schema.Set).Len() > 0 { + if r["license_filters"] != nil && r["license_filters"].(*sdkv2_schema.Set).Len() > 0 { + m := r["license_filters"].(*sdkv2_schema.Set).List()[0].(map[string]interface{}) + if m["license_names"] != nil && m["license_names"].(*sdkv2_schema.Set).Len() > 0 { nestedLicenseFilterCounter += 1 } - if m["license_patterns"] != nil && m["license_patterns"].(*schema.Set).Len() > 0 { + if m["license_patterns"] != nil && m["license_patterns"].(*sdkv2_schema.Set).Len() > 0 { nestedLicenseFilterCounter += 1 } } @@ -785,11 +1382,11 @@ func reportResourceDiff(_ context.Context, diff *schema.ResourceDiff, v interfac // Check license filter in license report var licenseFilterCounter int - if r["license_names"] != nil && r["license_names"].(*schema.Set).Len() > 0 { + if r["license_names"] != nil && r["license_names"].(*sdkv2_schema.Set).Len() > 0 { licenseFilterCounter += 1 } - if r["license_patterns"] != nil && r["license_patterns"].(*schema.Set).Len() > 0 { + if r["license_patterns"] != nil && r["license_patterns"].(*sdkv2_schema.Set).Len() > 0 { licenseFilterCounter += 1 } @@ -798,8 +1395,8 @@ func reportResourceDiff(_ context.Context, diff *schema.ResourceDiff, v interfac } // Verify severities in Vulnerabilities and Violations filters - if r["severities"] != nil && r["severities"].(*schema.Set).Len() > 0 { - for _, severity := range r["severities"].(*schema.Set).List() { + if r["severities"] != nil && r["severities"].(*sdkv2_schema.Set).Len() > 0 { + for _, severity := range r["severities"].(*sdkv2_schema.Set).List() { if !slices.Contains([]string{"Low", "Medium", "High", "Critical"}, severity.(string)) { return fmt.Errorf("'severity' attribute value must be one or several of 'Low', 'Medium', 'High', 'Critical'") } @@ -807,8 +1404,8 @@ func reportResourceDiff(_ context.Context, diff *schema.ResourceDiff, v interfac } // Verify risks in Operational Risks filter - if r["risks"] != nil && r["risks"].(*schema.Set).Len() > 0 { - for _, severity := range r["risks"].(*schema.Set).List() { + if r["risks"] != nil && r["risks"].(*sdkv2_schema.Set).Len() > 0 { + for _, severity := range r["risks"].(*sdkv2_schema.Set).List() { if !slices.Contains([]string{"None", "Low", "Medium", "High"}, severity.(string)) { return fmt.Errorf("'risks' attribute value must be one or several of 'None', 'Low', 'Medium', 'High'") } diff --git a/pkg/xray/resource/resource_xray_report_test.go b/pkg/xray/resource/resource_xray_report_test.go index c8c7ea36..37f1abc9 100644 --- a/pkg/xray/resource/resource_xray_report_test.go +++ b/pkg/xray/resource/resource_xray_report_test.go @@ -332,6 +332,19 @@ func TestAccReport_Vulnerabilities(t *testing.T) { } } +func TestAccReport_Vulnerabilities_UpgradeFromSDKv2(t *testing.T) { + terraformReportName := "terraform-vulnerabilities-report" + terraformResourceName := "xray_vulnerabilities_report" + + for _, reportResource := range resourcesList { + resourceNameInReport := reportResource["name"].(string) + t.Run(resourceNameInReport, func(t *testing.T) { + resource.Test(mkFilterTestCase_UpgradeFromSDKv2(t, reportResource, vulnerabilitiesFilterFields, terraformReportName, + terraformResourceName)) + }) + } +} + func TestAccReport_BadResource(t *testing.T) { terraformReportName := "terraform-licenses-report" terraformResourceName := "xray_licenses_report" @@ -483,6 +496,52 @@ func mkFilterTestCase(t *testing.T, resourceFields map[string]interface{}, filte } } +func mkFilterTestCase_UpgradeFromSDKv2(t *testing.T, resourceFields map[string]interface{}, filterFields map[string]interface{}, + reportName string, resourceName string) (*testing.T, resource.TestCase) { + _, fqrn, name := testutil.MkNames(reportName, resourceName) + + allFields := sdk.MergeMaps(filterFields, resourceFields) + allFieldsHcl := sdk.FmtMapToHcl(allFields) + const remoteRepoFull = ` + resource "%s" "%s" { +%s + } + ` + extraChecks := testutil.MapToTestChecks(fqrn, resourceFields) + defaultChecks := testutil.MapToTestChecks(fqrn, allFields) + + checks := append(defaultChecks, extraChecks...) + config := fmt.Sprintf(remoteRepoFull, resourceName, name, allFieldsHcl) + + return t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckReport), // how to get ID? + Steps: []resource.TestStep{ + { + Config: config, + ExternalProviders: map[string]resource.ExternalProvider{ + "xray": { + Source: "jfrog/xray", + VersionConstraint: "2.11.0", + }, + }, + Check: resource.ComposeTestCheckFunc(checks...), + }, + { + Config: config, + ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + PlanOnly: true, + ConfigPlanChecks: testutil.ConfigPlanChecks(""), + // ConfigPlanChecks: resource.ConfigPlanChecks{ + // PreApply: []plancheck.PlanCheck{ + // plancheck.ExpectEmptyPlan(), + // }, + // }, + }, + }, + } +} + func mkFilterNegativeTestCase(t *testing.T, resourceFields map[string]interface{}, filterFields map[string]interface{}, reportName string, resourceName string, expectedErrorMessage string) (*testing.T, resource.TestCase) { _, _, name := testutil.MkNames(reportName, resourceName) diff --git a/pkg/xray/resource/resource_xray_vulnerabilities_report.go b/pkg/xray/resource/resource_xray_vulnerabilities_report.go index a046b0cd..5f4683f3 100644 --- a/pkg/xray/resource/resource_xray_vulnerabilities_report.go +++ b/pkg/xray/resource/resource_xray_vulnerabilities_report.go @@ -1,132 +1,379 @@ package xray import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "github.com/jfrog/terraform-provider-shared/validator" + "context" + + "github.com/hashicorp/terraform-plugin-framework-validators/float64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/jfrog/terraform-provider-shared/util" ) -func ResourceXrayVulnerabilitiesReport() *schema.Resource { - var vulnerabilitiesFilterSchema = map[string]*schema.Schema{ - "vulnerable_component": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "Filter by component name, you can use (*) at the beginning or end of a substring as a wildcard.", +var _ resource.Resource = &VulnerabilitiesReportResource{} + +func NewVulnerabilitiesReportResource() resource.Resource { + return &VulnerabilitiesReportResource{ + ReportResource: ReportResource{ + TypeName: "xray_vulnerabilities_report", }, - "impacted_artifact": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "Filter by artifact name, you can use (*) at the eginning or end of a substring as a wildcard.", + } +} + +type VulnerabilitiesReportResource struct { + ReportResource +} + +func (r *VulnerabilitiesReportResource) toFiltersAPIModel(ctx context.Context, filtersElems []attr.Value) (*FiltersAPIModel, diag.Diagnostics) { + diags := diag.Diagnostics{} + + var filters *FiltersAPIModel + if len(filtersElems) > 0 { + attrs := filtersElems[0].(types.Object).Attributes() + + var cvssScore *CVSSScoreAPIModel + cvssScoreElems := attrs["cvss_score"].(types.Set).Elements() + if len(cvssScoreElems) > 0 { + attrs := cvssScoreElems[0].(types.Object).Attributes() + + cvssScore = &CVSSScoreAPIModel{ + MinScore: attrs["min_score"].(types.Float64).ValueFloat64(), + MaxScore: attrs["max_score"].(types.Float64).ValueFloat64(), + } + } + + var severities []string + d := attrs["severities"].(types.Set).ElementsAs(ctx, &severities, false) + if d.HasError() { + diags.Append(d...) + } + + filters = &FiltersAPIModel{ + VulnerableComponent: attrs["vulnerable_component"].(types.String).ValueString(), + ImpactedArtifact: attrs["impacted_artifact"].(types.String).ValueString(), + HasRemediation: attrs["has_remediation"].(types.Bool).ValueBool(), + CVE: attrs["cve"].(types.String).ValueString(), + IssueId: attrs["issue_id"].(types.String).ValueString(), + Severities: severities, + CVSSScore: cvssScore, + } + } + + return filters, diags +} + +func (r VulnerabilitiesReportResource) toAPIModel(ctx context.Context, plan ReportResourceModel, report *ReportAPIModel) diag.Diagnostics { + return plan.toAPIModel(ctx, report, r.toFiltersAPIModel) +} + +func (r *VulnerabilitiesReportResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = r.TypeName +} + +var vulnerabilitiesFiltersAttrs = map[string]schema.Attribute{ + "vulnerable_component": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "has_remediation": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Whether the issue has a fix or not.", // UI has an option 'All', when the field is empty. Not clear how to make it work with bool. + Description: "Filter by component name, you can use (*) at the beginning or end of a substring as a wildcard.", + }, + "impacted_artifact": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "cve": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "CVE.", + Description: "Filter by artifact name, you can use (*) at the eginning or end of a substring as a wildcard.", + }, + "has_remediation": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + Description: "Whether the issue has a fix or not.", + }, + "cve": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + stringvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("issue_id"), + ), }, - "issue_id": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "Issue ID.", + Description: "CVE.", + }, + "issue_id": schema.StringAttribute{ + Optional: true, + Computed: true, + Default: stringdefault.StaticString(""), // backward compatibility with SDKv2 version + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + stringvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("cve"), + ), }, - "severities": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Optional: true, - Description: "Severity levels. Allowed values: 'Low', 'Medium', 'High', 'Critical'", + Description: "Issue ID.", + }, + "severities": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.ValueStringsAre( + stringvalidator.OneOf("Low", "Medium", "High", "Critical"), + ), + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("cvss_score"), + ), }, - "cvss_score": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "CVSS score.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "min_score": { - Type: schema.TypeFloat, - Optional: true, - ValidateFunc: validation.FloatBetween(0, 10), - Description: "Minimum CVSS score.", + Description: "Severity levels. Allowed values: 'Low', 'Medium', 'High', 'Critical'", + }, +} + +var vulnerabilitiesFiltersBlocks = map[string]schema.Block{ + "cvss_score": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "min_score": schema.Float64Attribute{ + Optional: true, + Validators: []validator.Float64{ + float64validator.Between(0, 10), }, - "max_score": { - Type: schema.TypeFloat, - Optional: true, - ValidateFunc: validation.FloatBetween(0, 10), - Description: "Maximum CVSS score.", + Description: "Minimum CVSS score.", + }, + "max_score": schema.Float64Attribute{ + Optional: true, + Validators: []validator.Float64{ + float64validator.Between(0, 10), }, + Description: "Maximum CVSS score.", }, }, }, - "published": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "start": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), - Description: "Published from date.", + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("severities"), + ), + }, + Description: "CVSS score.", + }, + "published": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "start": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + IsRFC3339Time(), }, - "end": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), - Description: "Published to date.", + Description: "Published from date.", + }, + "end": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + IsRFC3339Time(), }, + Description: "Published to date.", }, }, }, - "scan_date": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "start": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), - Description: "Scanned from date.", + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), + }, + }, + "scan_date": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "start": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + IsRFC3339Time(), }, - "end": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), - Description: "Scanned to date.", + Description: "Scanned from date.", + }, + "end": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + IsRFC3339Time(), }, + Description: "Scanned to date.", }, }, }, - } + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), + }, + }, +} - return &schema.Resource{ - SchemaVersion: 1, - CreateContext: resourceXrayVulnerabilitiesReportCreate, - ReadContext: resourceXrayReportRead, - UpdateContext: resourceXrayVulnerabilitiesReportCreate, - DeleteContext: resourceXrayReportDelete, +func (r *VulnerabilitiesReportResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Version: 1, + Attributes: reportsSchemaAttrs, + Blocks: reportsBlocks(vulnerabilitiesFiltersAttrs, vulnerabilitiesFiltersBlocks), Description: "Creates Xray Vulnerabilities report. The Vulnerabilities report provides information about " + "vulnerabilities in your artifacts, builds, and release bundles. In addition to the information provided in " + "the JFrog Platform on each of these entities, the report gives you a wider range of information such as " + "vulnerabilities in multiple repositories, builds and release bundles. Criteria such as vulnerable component," + " CVE, cvss score, and severity are available in the report.", + } +} - CustomizeDiff: reportResourceDiff, - - Schema: getReportSchema(vulnerabilitiesFilterSchema), +func (r *VulnerabilitiesReportResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return } + r.ProviderData = req.ProviderData.(util.ProviderMetadata) +} + +func (r *VulnerabilitiesReportResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + r.ReportResource.Create(ctx, "vulnerabilities", r.toAPIModel, req, resp) +} + +func (r *VulnerabilitiesReportResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + r.ReportResource.Read(ctx, req, resp) } + +func (r *VulnerabilitiesReportResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + r.ReportResource.Update(ctx, "vulnerabilities", r.toAPIModel, req, resp) +} + +func (r *VulnerabilitiesReportResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + r.ReportResource.Delete(ctx, req, resp) +} + +// +// func ResourceXrayVulnerabilitiesReport() *sdkv2_schema.Resource { +// var vulnerabilitiesFilterSchema = map[string]*sdkv2_schema.Schema{ +// "vulnerable_component": { +// Type: sdkv2_schema.TypeString, +// Optional: true, +// ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, +// Description: "Filter by component name, you can use (*) at the beginning or end of a substring as a wildcard.", +// }, +// "impacted_artifact": { +// Type: sdkv2_schema.TypeString, +// Optional: true, +// ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, +// Description: "Filter by artifact name, you can use (*) at the eginning or end of a substring as a wildcard.", +// }, +// "has_remediation": { +// Type: sdkv2_schema.TypeBool, +// Optional: true, +// Default: false, +// Description: "Whether the issue has a fix or not.", // UI has an option 'All', when the field is empty. Not clear how to make it work with bool. +// }, +// "cve": { +// Type: sdkv2_schema.TypeString, +// Optional: true, +// ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, +// Description: "CVE.", +// }, +// "issue_id": { +// Type: sdkv2_schema.TypeString, +// Optional: true, +// ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, +// Description: "Issue ID.", +// }, +// "severities": { +// Type: sdkv2_schema.TypeSet, +// Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, +// Set: sdkv2_schema.HashString, +// Optional: true, +// Description: "Severity levels. Allowed values: 'Low', 'Medium', 'High', 'Critical'", +// }, +// "cvss_score": { +// Type: sdkv2_schema.TypeSet, +// Optional: true, +// MaxItems: 1, +// Description: "CVSS score.", +// Elem: &sdkv2_schema.Resource{ +// Schema: map[string]*sdkv2_schema.Schema{ +// "min_score": { +// Type: sdkv2_schema.TypeFloat, +// Optional: true, +// ValidateFunc: validation.FloatBetween(0, 10), +// Description: "Minimum CVSS score.", +// }, +// "max_score": { +// Type: sdkv2_schema.TypeFloat, +// Optional: true, +// ValidateFunc: validation.FloatBetween(0, 10), +// Description: "Maximum CVSS score.", +// }, +// }, +// }, +// }, +// "published": { +// Type: sdkv2_schema.TypeSet, +// Optional: true, +// MaxItems: 1, +// Description: "", +// Elem: &sdkv2_schema.Resource{ +// Schema: map[string]*sdkv2_schema.Schema{ +// "start": { +// Type: sdkv2_schema.TypeString, +// Optional: true, +// ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), +// Description: "Published from date.", +// }, +// "end": { +// Type: sdkv2_schema.TypeString, +// Optional: true, +// ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), +// Description: "Published to date.", +// }, +// }, +// }, +// }, +// "scan_date": { +// Type: sdkv2_schema.TypeSet, +// Optional: true, +// MaxItems: 1, +// Description: "", +// Elem: &sdkv2_schema.Resource{ +// Schema: map[string]*sdkv2_schema.Schema{ +// "start": { +// Type: sdkv2_schema.TypeString, +// Optional: true, +// ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), +// Description: "Scanned from date.", +// }, +// "end": { +// Type: sdkv2_schema.TypeString, +// Optional: true, +// ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), +// Description: "Scanned to date.", +// }, +// }, +// }, +// }, +// } +// +// return &sdkv2_schema.Resource{ +// SchemaVersion: 1, +// CreateContext: resourceXrayVulnerabilitiesReportCreate, +// ReadContext: resourceXrayReportRead, +// UpdateContext: resourceXrayVulnerabilitiesReportCreate, +// DeleteContext: resourceXrayReportDelete, +// Description: "Creates Xray Vulnerabilities report. The Vulnerabilities report provides information about " + +// "vulnerabilities in your artifacts, builds, and release bundles. In addition to the information provided in " + +// "the JFrog Platform on each of these entities, the report gives you a wider range of information such as " + +// "vulnerabilities in multiple repositories, builds and release bundles. Criteria such as vulnerable component," + +// " CVE, cvss score, and severity are available in the report.", +// +// CustomizeDiff: reportResourceDiff, +// +// Schema: getReportSchema(vulnerabilitiesFilterSchema), +// } +// } diff --git a/pkg/xray/resource/util.go b/pkg/xray/resource/util.go index 211b7b29..eaa19a01 100644 --- a/pkg/xray/resource/util.go +++ b/pkg/xray/resource/util.go @@ -1,11 +1,18 @@ package xray import ( + "context" "fmt" + "time" "github.com/go-resty/resty/v2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/jfrog/terraform-provider-shared/validator" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + sdkv2_schema "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + sdkv2_validator "github.com/jfrog/terraform-provider-shared/validator" + validatorfw_string "github.com/jfrog/terraform-provider-shared/validator/fw/string" ) func getRestyRequest(client *resty.Client, projectKey string) (*resty.Request, error) { @@ -21,16 +28,71 @@ func getRestyRequest(client *resty.Client, projectKey string) (*resty.Request, e return req, nil } -var getProjectKeySchema = func(isForceNew bool, additionalDescription string) map[string]*schema.Schema { +var getProjectKeySchema = func(isForceNew bool, additionalDescription string) map[string]*sdkv2_schema.Schema { description := fmt.Sprintf("Project key for assigning this resource to. Must be 2 - 10 lowercase alphanumeric and hyphen characters. %s", additionalDescription) - return map[string]*schema.Schema{ + return map[string]*sdkv2_schema.Schema{ "project_key": { - Type: schema.TypeString, + Type: sdkv2_schema.TypeString, Optional: true, ForceNew: isForceNew, - ValidateDiagFunc: validator.ProjectKey, + ValidateDiagFunc: sdkv2_validator.ProjectKey, Description: description, }, } } + +var projectKeySchemaAttrs = func(isForceNew bool, additionalDescription string) map[string]schema.Attribute { + description := fmt.Sprintf("Project key for assigning this resource to. Must be 2 - 10 lowercase alphanumeric and hyphen characters. %s", additionalDescription) + planModifiers := []planmodifier.String{} + + if isForceNew { + planModifiers = append(planModifiers, stringplanmodifier.RequiresReplace()) + } + + return map[string]schema.Attribute{ + "project_key": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + validatorfw_string.ProjectKey(), + }, + PlanModifiers: planModifiers, + Description: description, + }, + } +} + +type IsRFC3339TimeValidator struct{} + +// Description returns a plain text description of the validator's behavior, suitable for a practitioner to understand its impact. +func (v IsRFC3339TimeValidator) Description(ctx context.Context) string { + return "string must be a valid RFC3339 date" +} + +// MarkdownDescription returns a markdown formatted description of the validator's behavior, suitable for a practitioner to understand its impact. +func (v IsRFC3339TimeValidator) MarkdownDescription(ctx context.Context) string { + return "string must be a valid RFC3339 date" +} + +// Validate runs the main validation logic of the validator, reading configuration data out of `req` and updating `resp` with diagnostics. +func (v IsRFC3339TimeValidator) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) { + // If the value is unknown or null, there is nothing to validate. + if req.ConfigValue.IsUnknown() || req.ConfigValue.IsNull() { + return + } + + timeString := req.ConfigValue.ValueString() + + if _, err := time.Parse(time.RFC3339, timeString); err != nil { + resp.Diagnostics.AddAttributeError( + req.Path, + "Invalid Time Format", + fmt.Sprintf("Value must be a valid RFC3339 date, got: %s: %+v", timeString, err), + ) + return + } +} + +func IsRFC3339Time() IsRFC3339TimeValidator { + return IsRFC3339TimeValidator{} +} From c63ebdeda2049888d2af2cec353171dffe6feec5 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 12 Sep 2024 13:50:03 -0700 Subject: [PATCH 06/11] Migrate xray_licenses_report to Plugin Framework --- pkg/xray/provider/framework.go | 1 + pkg/xray/provider/sdkv2.go | 1 - pkg/xray/resource/reports.go | 1 + .../resource/resource_xray_licenses_report.go | 242 ++++++++++++++++-- .../resource/resource_xray_report_test.go | 18 +- 5 files changed, 237 insertions(+), 26 deletions(-) diff --git a/pkg/xray/provider/framework.go b/pkg/xray/provider/framework.go index 2e897b04..302d1d5b 100644 --- a/pkg/xray/provider/framework.go +++ b/pkg/xray/provider/framework.go @@ -181,6 +181,7 @@ func (p *XrayProvider) Resources(ctx context.Context) []func() resource.Resource xray_resource.NewCustomIssueResource, xray_resource.NewIgnoreRuleResource, xray_resource.NewLicensePolicyResource, + xray_resource.NewLicensesReportResource, xray_resource.NewOperationalRiskPolicyResource, xray_resource.NewRepositoryConfigResource, xray_resource.NewSecurityPolicyResource, diff --git a/pkg/xray/provider/sdkv2.go b/pkg/xray/provider/sdkv2.go index ed19b0ff..5ae81bd6 100644 --- a/pkg/xray/provider/sdkv2.go +++ b/pkg/xray/provider/sdkv2.go @@ -54,7 +54,6 @@ func SdkV2() *schema.Provider { ResourcesMap: sdk.AddTelemetry( productId, map[string]*schema.Resource{ - "xray_licenses_report": xray.ResourceXrayLicensesReport(), "xray_violations_report": xray.ResourceXrayViolationsReport(), "xray_operational_risks_report": xray.ResourceXrayOperationalRisksReport(), }, diff --git a/pkg/xray/resource/reports.go b/pkg/xray/resource/reports.go index b083a944..3209c36d 100644 --- a/pkg/xray/resource/reports.go +++ b/pkg/xray/resource/reports.go @@ -772,6 +772,7 @@ func (r *ReportResource) Create( } plan.ID = types.StringValue(fmt.Sprintf("%d", report.ReportId)) + plan.ReportID = types.Int64Null() // Save data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) diff --git a/pkg/xray/resource/resource_xray_licenses_report.go b/pkg/xray/resource/resource_xray_licenses_report.go index f5e37ca4..b4d738ec 100644 --- a/pkg/xray/resource/resource_xray_licenses_report.go +++ b/pkg/xray/resource/resource_xray_licenses_report.go @@ -1,66 +1,264 @@ package xray import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "context" + + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + sdkv2_schema "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "github.com/jfrog/terraform-provider-shared/validator" + "github.com/jfrog/terraform-provider-shared/util" + sdkv2_validator "github.com/jfrog/terraform-provider-shared/validator" ) -func ResourceXrayLicensesReport() *schema.Resource { - var licensesFilterSchema = map[string]*schema.Schema{ +var _ resource.Resource = &LicensesReportResource{} + +func NewLicensesReportResource() resource.Resource { + return &LicensesReportResource{ + ReportResource: ReportResource{ + TypeName: "xray_licenses_report", + }, + } +} + +type LicensesReportResource struct { + ReportResource +} + +func (r *LicensesReportResource) toFiltersAPIModel(ctx context.Context, filtersElems []attr.Value) (*FiltersAPIModel, diag.Diagnostics) { + diags := diag.Diagnostics{} + + var filters *FiltersAPIModel + if len(filtersElems) > 0 { + attrs := filtersElems[0].(types.Object).Attributes() + + var scanDate *StartAndEndDateAPIModel + scanDateElems := attrs["scan_date"].(types.Set).Elements() + if len(scanDateElems) > 0 { + attrs := scanDateElems[0].(types.Object).Attributes() + + scanDate = &StartAndEndDateAPIModel{ + Start: attrs["start"].(types.String).ValueString(), + End: attrs["end"].(types.String).ValueString(), + } + } + + var licenseNames []string + d := attrs["license_names"].(types.Set).ElementsAs(ctx, &licenseNames, false) + if d.HasError() { + diags.Append(d...) + } + + var licensePatterns []string + d = attrs["license_patterns"].(types.Set).ElementsAs(ctx, &licensePatterns, false) + if d.HasError() { + diags.Append(d...) + } + + filters = &FiltersAPIModel{ + Component: attrs["component"].(types.String).ValueString(), + Artifact: attrs["artifact"].(types.String).ValueString(), + Unknown: attrs["unknown"].(types.Bool).ValueBool(), + Unrecognized: attrs["unrecognized"].(types.Bool).ValueBool(), + LicenseNames: licenseNames, + LicensePatterns: licensePatterns, + ScanDate: scanDate, + } + } + + return filters, diags +} + +func (r LicensesReportResource) toAPIModel(ctx context.Context, plan ReportResourceModel, report *ReportAPIModel) diag.Diagnostics { + return plan.toAPIModel(ctx, report, r.toFiltersAPIModel) +} + +func (r *LicensesReportResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = r.TypeName +} + +var licensesFiltersAttrs = map[string]schema.Attribute{ + "component": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + Description: "Artifact's component.", + }, + "artifact": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + Description: "Artifact name.", + }, + "unknown": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + Description: "Unknown displays the components that Xray could not discover any licenses for.", + }, + "unrecognized": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + Description: "Unrecognized displays the components that Xray found licenses for, but these licenses are not Xray recognized licenses.", + }, + "license_names": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("license_patterns"), + ), + }, + Description: "Filter licenses by names. Only one of 'license_names' or 'license_patterns' can be set.", + }, + "license_patterns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("license_names"), + ), + }, + Description: "Filter licenses by patterns. Only one of 'license_names' or 'license_patterns' can be set.", + }, +} + +var licensesFiltersBlocks = map[string]schema.Block{ + "scan_date": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "start": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + IsRFC3339Time(), + }, + Description: "Scanned start date.", + }, + "end": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + IsRFC3339Time(), + }, + Description: "Scanned end date.", + }, + }, + }, + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), + }, + }, +} + +func (r *LicensesReportResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Version: 1, + Attributes: reportsSchemaAttrs, + Blocks: reportsBlocks(licensesFiltersAttrs, licensesFiltersBlocks), + Description: "Creates Xray License Due Diligence report. The License Due Diligence report provides you with a " + + "list of components and artifacts and their relevant licenses. This enables you to review and verify that " + + "the components and artifacts comply with the license requirements. This report provides due diligence " + + "license related information on each component for a selected scope. Due diligence license information " + + "includes information such as unknown licenses and unrecognized licenses found in your components.", + } +} + +func (r *LicensesReportResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + r.ProviderData = req.ProviderData.(util.ProviderMetadata) +} + +func (r *LicensesReportResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + r.ReportResource.Create(ctx, "licenses", r.toAPIModel, req, resp) +} + +func (r *LicensesReportResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + r.ReportResource.Read(ctx, req, resp) +} + +func (r *LicensesReportResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + r.ReportResource.Update(ctx, "licenses", r.toAPIModel, req, resp) +} + +func (r *LicensesReportResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + r.ReportResource.Delete(ctx, req, resp) +} + +func ResourceXrayLicensesReport() *sdkv2_schema.Resource { + var licensesFilterSchema = map[string]*sdkv2_schema.Schema{ "component": { - Type: schema.TypeString, + Type: sdkv2_schema.TypeString, Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, + ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, Description: "Artifact's component.", }, "artifact": { - Type: schema.TypeString, + Type: sdkv2_schema.TypeString, Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, + ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, Description: "Artifact name.", }, "unknown": { - Type: schema.TypeBool, + Type: sdkv2_schema.TypeBool, Optional: true, Default: false, Description: "Unknown displays the components that Xray could not discover any licenses for.", }, "unrecognized": { - Type: schema.TypeBool, + Type: sdkv2_schema.TypeBool, Optional: true, Default: false, Description: "Unrecognized displays the components that Xray found licenses for, but these licenses are not Xray recognized licenses.", }, "license_names": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "Filter licenses by names. Only one of 'license_names' or 'license_patterns' can be set.", }, "license_patterns": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + Type: sdkv2_schema.TypeSet, + Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, + Set: sdkv2_schema.HashString, Optional: true, Description: "Filter licenses by patterns. Only one of 'license_names' or 'license_patterns' can be set.", }, "scan_date": { - Type: schema.TypeSet, + Type: sdkv2_schema.TypeSet, Optional: true, MaxItems: 1, Description: "", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ + Elem: &sdkv2_schema.Resource{ + Schema: map[string]*sdkv2_schema.Schema{ "start": { - Type: schema.TypeString, + Type: sdkv2_schema.TypeString, Optional: true, ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), Description: "Scan start date.", }, "end": { - Type: schema.TypeString, + Type: sdkv2_schema.TypeString, Optional: true, ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), Description: "Scan end date.", @@ -70,7 +268,7 @@ func ResourceXrayLicensesReport() *schema.Resource { }, } - return &schema.Resource{ + return &sdkv2_schema.Resource{ SchemaVersion: 1, CreateContext: resourceXrayLicensesReportCreate, ReadContext: resourceXrayReportRead, diff --git a/pkg/xray/resource/resource_xray_report_test.go b/pkg/xray/resource/resource_xray_report_test.go index 37f1abc9..784780af 100644 --- a/pkg/xray/resource/resource_xray_report_test.go +++ b/pkg/xray/resource/resource_xray_report_test.go @@ -281,6 +281,19 @@ func TestAccReport_Licenses(t *testing.T) { } } +func TestAccReport_Licenses_UpgradeFromSDKv2(t *testing.T) { + terraformReportName := "terraform-licenses-report" + terraformResourceName := "xray_licenses_report" + + for _, reportResource := range resourcesList { + resourceNameInReport := reportResource["name"].(string) + t.Run(resourceNameInReport, func(t *testing.T) { + resource.Test(mkFilterTestCase_UpgradeFromSDKv2(t, reportResource, licenseFilterFields, terraformReportName, + terraformResourceName)) + }) + } +} + func TestAccReport_OperationalRisks(t *testing.T) { terraformReportName := "terraform-operational-risks-report" terraformResourceName := "xray_operational_risks_report" @@ -362,7 +375,7 @@ func TestAccReport_BadResource(t *testing.T) { func TestAccReport_BadLicenseFilter(t *testing.T) { terraformReportName := "terraform-licenses-report" terraformResourceName := "xray_licenses_report" - expectedErrorMessage := "Only one of" + expectedErrorMessage := "(?s).*Invalid Attribute Combination.*license_patterns.*cannot be specified when.*license_names.*is specified.*" var filterFieldsConflict = map[string]interface{}{ "filters": map[string]interface{}{ @@ -434,7 +447,7 @@ func TestAccReport_BadViolationsFilter(t *testing.T) { func TestAccReport_BadVulnerabilitiesFilter(t *testing.T) { terraformReportName := "terraform-vulnerabilities-report" terraformResourceName := "xray_vulnerabilities_report" - expectedErrorMessage := "Only one of" + expectedErrorMessage := "(?s).*Invalid Attribute Combination.*severities.*cannot be specified when.*cvss_score.*is specified.*" var filterFieldsConflict = map[string]interface{}{ "filters": map[string]interface{}{ @@ -442,7 +455,6 @@ func TestAccReport_BadVulnerabilitiesFilter(t *testing.T) { "impacted_artifact": "impacted-artifact", "has_remediation": false, "cve": "CVE-1234-1234", - "issue_id": "XRAY-1234", "severities": []interface{}{"High", "Medium"}, // conflicts with cvss_score "cvss_score": map[string]interface{}{ "min_score": 6.3, From d6486482496b4aadad180c5cdfe374516d745b89 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 12 Sep 2024 14:51:15 -0700 Subject: [PATCH 07/11] Migrate xray_violations_report to Plugin Framework --- pkg/xray/provider/framework.go | 1 + pkg/xray/provider/sdkv2.go | 1 - pkg/xray/resource/reports.go | 42 ++ .../resource/resource_xray_licenses_report.go | 85 --- .../resource/resource_xray_report_test.go | 21 +- .../resource_xray_violations_report.go | 497 +++++++++++++----- 6 files changed, 412 insertions(+), 235 deletions(-) diff --git a/pkg/xray/provider/framework.go b/pkg/xray/provider/framework.go index 302d1d5b..51669e23 100644 --- a/pkg/xray/provider/framework.go +++ b/pkg/xray/provider/framework.go @@ -186,6 +186,7 @@ func (p *XrayProvider) Resources(ctx context.Context) []func() resource.Resource xray_resource.NewRepositoryConfigResource, xray_resource.NewSecurityPolicyResource, xray_resource.NewSettingsResource, + xray_resource.NewViolationsReportResource, xray_resource.NewVulnerabilitiesReportResource, xray_resource.NewWatchResource, xray_resource.NewWebhookResource, diff --git a/pkg/xray/provider/sdkv2.go b/pkg/xray/provider/sdkv2.go index 5ae81bd6..83942bf5 100644 --- a/pkg/xray/provider/sdkv2.go +++ b/pkg/xray/provider/sdkv2.go @@ -54,7 +54,6 @@ func SdkV2() *schema.Provider { ResourcesMap: sdk.AddTelemetry( productId, map[string]*schema.Resource{ - "xray_violations_report": xray.ResourceXrayViolationsReport(), "xray_operational_risks_report": xray.ResourceXrayOperationalRisksReport(), }, ), diff --git a/pkg/xray/resource/reports.go b/pkg/xray/resource/reports.go index 3209c36d..1f2018fd 100644 --- a/pkg/xray/resource/reports.go +++ b/pkg/xray/resource/reports.go @@ -283,6 +283,12 @@ var reportsBlocks = func(filtersAttrs map[string]schema.Attribute, filtersBlocks Optional: true, Computed: true, Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("include_patterns"), + path.MatchRelative().AtParent().AtName("exclude_patterns"), + ), + }, Description: "The list of build names. Only one of 'names' or '*_patterns' can be set.", }, "include_patterns": schema.SetAttribute{ @@ -290,6 +296,11 @@ var reportsBlocks = func(filtersAttrs map[string]schema.Attribute, filtersBlocks Optional: true, Computed: true, Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("names"), + ), + }, Description: "The list of include patterns. Only one of 'names' or '*_patterns' can be set.", }, "exclude_patterns": schema.SetAttribute{ @@ -297,6 +308,11 @@ var reportsBlocks = func(filtersAttrs map[string]schema.Attribute, filtersBlocks Optional: true, Computed: true, Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("names"), + ), + }, Description: "The list of exclude patterns. Only one of 'names' or '*_patterns' can be set.", }, "number_of_latest_versions": schema.Int64Attribute{ @@ -328,6 +344,12 @@ var reportsBlocks = func(filtersAttrs map[string]schema.Attribute, filtersBlocks Optional: true, Computed: true, Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("include_patterns"), + path.MatchRelative().AtParent().AtName("exclude_patterns"), + ), + }, Description: "The list of release bundles names.", }, "include_patterns": schema.SetAttribute{ @@ -335,6 +357,11 @@ var reportsBlocks = func(filtersAttrs map[string]schema.Attribute, filtersBlocks Optional: true, Computed: true, Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("names"), + ), + }, Description: "The list of include patterns", }, "exclude_patterns": schema.SetAttribute{ @@ -342,6 +369,11 @@ var reportsBlocks = func(filtersAttrs map[string]schema.Attribute, filtersBlocks Optional: true, Computed: true, Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("names"), + ), + }, Description: "The list of exclude patterns", }, "number_of_latest_versions": schema.Int64Attribute{ @@ -373,6 +405,11 @@ var reportsBlocks = func(filtersAttrs map[string]schema.Attribute, filtersBlocks Optional: true, Computed: true, Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("include_key_patterns"), + ), + }, Description: "The list of project names.", }, "include_key_patterns": schema.SetAttribute{ @@ -380,6 +417,11 @@ var reportsBlocks = func(filtersAttrs map[string]schema.Attribute, filtersBlocks Optional: true, Computed: true, Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("names"), + ), + }, Description: "The list of include patterns", }, "number_of_latest_versions": schema.Int64Attribute{ diff --git a/pkg/xray/resource/resource_xray_licenses_report.go b/pkg/xray/resource/resource_xray_licenses_report.go index b4d738ec..10bc40a8 100644 --- a/pkg/xray/resource/resource_xray_licenses_report.go +++ b/pkg/xray/resource/resource_xray_licenses_report.go @@ -14,10 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" - sdkv2_schema "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/jfrog/terraform-provider-shared/util" - sdkv2_validator "github.com/jfrog/terraform-provider-shared/validator" ) var _ resource.Resource = &LicensesReportResource{} @@ -203,85 +200,3 @@ func (r *LicensesReportResource) Update(ctx context.Context, req resource.Update func (r *LicensesReportResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { r.ReportResource.Delete(ctx, req, resp) } - -func ResourceXrayLicensesReport() *sdkv2_schema.Resource { - var licensesFilterSchema = map[string]*sdkv2_schema.Schema{ - "component": { - Type: sdkv2_schema.TypeString, - Optional: true, - ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, - Description: "Artifact's component.", - }, - "artifact": { - Type: sdkv2_schema.TypeString, - Optional: true, - ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, - Description: "Artifact name.", - }, - "unknown": { - Type: sdkv2_schema.TypeBool, - Optional: true, - Default: false, - Description: "Unknown displays the components that Xray could not discover any licenses for.", - }, - "unrecognized": { - Type: sdkv2_schema.TypeBool, - Optional: true, - Default: false, - Description: "Unrecognized displays the components that Xray found licenses for, but these licenses are not Xray recognized licenses.", - }, - "license_names": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "Filter licenses by names. Only one of 'license_names' or 'license_patterns' can be set.", - }, - "license_patterns": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "Filter licenses by patterns. Only one of 'license_names' or 'license_patterns' can be set.", - }, - "scan_date": { - Type: sdkv2_schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "", - Elem: &sdkv2_schema.Resource{ - Schema: map[string]*sdkv2_schema.Schema{ - "start": { - Type: sdkv2_schema.TypeString, - Optional: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), - Description: "Scan start date.", - }, - "end": { - Type: sdkv2_schema.TypeString, - Optional: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), - Description: "Scan end date.", - }, - }, - }, - }, - } - - return &sdkv2_schema.Resource{ - SchemaVersion: 1, - CreateContext: resourceXrayLicensesReportCreate, - ReadContext: resourceXrayReportRead, - UpdateContext: resourceXrayLicensesReportCreate, - DeleteContext: resourceXrayReportDelete, - Description: "Creates Xray License Due Diligence report. The License Due Diligence report provides you with a " + - "list of components and artifacts and their relevant licenses. This enables you to review and verify that " + - "the components and artifacts comply with the license requirements. This report provides due diligence " + - "license related information on each component for a selected scope. Due diligence license information " + - "includes information such as unknown licenses and unrecognized licenses found in your components.", - - CustomizeDiff: reportResourceDiff, - - Schema: getReportSchema(licensesFilterSchema), - } -} diff --git a/pkg/xray/resource/resource_xray_report_test.go b/pkg/xray/resource/resource_xray_report_test.go index 784780af..4ad03152 100644 --- a/pkg/xray/resource/resource_xray_report_test.go +++ b/pkg/xray/resource/resource_xray_report_test.go @@ -244,6 +244,7 @@ var resourcesListNegative = []map[string]interface{}{ "number_of_latest_versions": 2, }, }, + "errorMessage": "(?s).*Invalid Attribute Combination.*names.*cannot be specified when.*include_patterns.*is specified.*", }, { "name": "release_bundles_by_names_and_patterns_should_fail", @@ -255,6 +256,7 @@ var resourcesListNegative = []map[string]interface{}{ "number_of_latest_versions": 2, }, }, + "errorMessage": "(?s).*Invalid Attribute Combination.*names.*cannot be specified when.*include_patterns.*is specified.*", }, { "name": "projects_by_names_and_patterns_should_fail", @@ -265,6 +267,7 @@ var resourcesListNegative = []map[string]interface{}{ "number_of_latest_versions": 2, }, }, + "errorMessage": "(?s).*Invalid Attribute Combination.*names.*cannot be specified when.*include_key_patterns.*is specified.*", }, } @@ -320,6 +323,19 @@ func TestAccReport_Violations(t *testing.T) { } } +func TestAccReport_Violations_UpgradeFromSDKv2(t *testing.T) { + terraformReportName := "terraform-violations-report" + terraformResourceName := "xray_violations_report" + + for _, reportResource := range resourcesList { + resourceNameInReport := reportResource["name"].(string) + t.Run(resourceNameInReport, func(t *testing.T) { + resource.Test(mkFilterTestCase_UpgradeFromSDKv2(t, reportResource, violationsFilterFields[0], terraformReportName, + terraformResourceName)) + }) + } +} + func TestAccViolationsReportFilters(t *testing.T) { terraformReportName := "terraform-violations-report" terraformResourceName := "xray_violations_report" @@ -361,13 +377,12 @@ func TestAccReport_Vulnerabilities_UpgradeFromSDKv2(t *testing.T) { func TestAccReport_BadResource(t *testing.T) { terraformReportName := "terraform-licenses-report" terraformResourceName := "xray_licenses_report" - expectedErrorMessage := "Request payload is invalid as cannot" for _, reportResource := range resourcesListNegative { resourceNameInReport := reportResource["name"].(string) t.Run(resourceNameInReport, func(t *testing.T) { resource.Test(mkFilterNegativeTestCase(t, reportResource, licenseFilterFields, terraformReportName, - terraformResourceName, expectedErrorMessage)) + terraformResourceName, reportResource["errorMessage"].(string))) }) } } @@ -403,7 +418,7 @@ func TestAccReport_BadLicenseFilter(t *testing.T) { func TestAccReport_BadViolationsFilter(t *testing.T) { terraformReportName := "terraform-violations-report" terraformResourceName := "xray_violations_report" - expectedErrorMessage := "Only one of" + expectedErrorMessage := "(?s).*Invalid Attribute Combination.*watch_patterns.*cannot be specified when.*watch_names.*is specified.*" var filterFieldsConflict = map[string]interface{}{ "filters": map[string]interface{}{ diff --git a/pkg/xray/resource/resource_xray_violations_report.go b/pkg/xray/resource/resource_xray_violations_report.go index a6271701..03d40952 100644 --- a/pkg/xray/resource/resource_xray_violations_report.go +++ b/pkg/xray/resource/resource_xray_violations_report.go @@ -1,186 +1,391 @@ package xray import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "github.com/jfrog/terraform-provider-shared/validator" + "context" + + "github.com/hashicorp/terraform-plugin-framework-validators/float64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/jfrog/terraform-provider-shared/util" ) -func ResourceXrayViolationsReport() *schema.Resource { - var violationsFilterSchema = map[string]*schema.Schema{ - "type": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringInSlice(true, "security", "license", "operational_risk"), - Description: "Violation type.", +var _ resource.Resource = &ViolationsReportResource{} + +func NewViolationsReportResource() resource.Resource { + return &ViolationsReportResource{ + ReportResource: ReportResource{ + TypeName: "xray_violations_report", + }, + } +} + +type ViolationsReportResource struct { + ReportResource +} + +func (r *ViolationsReportResource) toFiltersAPIModel(ctx context.Context, filtersElems []attr.Value) (*FiltersAPIModel, diag.Diagnostics) { + diags := diag.Diagnostics{} + + var filters *FiltersAPIModel + if len(filtersElems) > 0 { + attrs := filtersElems[0].(types.Object).Attributes() + + var watchNames []string + d := attrs["watch_names"].(types.Set).ElementsAs(ctx, &watchNames, false) + if d.HasError() { + diags.Append(d...) + } + + var watchPatterns []string + d = attrs["watch_patterns"].(types.Set).ElementsAs(ctx, &watchPatterns, false) + if d.HasError() { + diags.Append(d...) + } + + var policyNames []string + d = attrs["policy_names"].(types.Set).ElementsAs(ctx, &policyNames, false) + if d.HasError() { + diags.Append(d...) + } + + var severities []string + d = attrs["severities"].(types.Set).ElementsAs(ctx, &severities, false) + if d.HasError() { + diags.Append(d...) + } + + var updated *StartAndEndDateAPIModel + updatedElems := attrs["updated"].(types.Set).Elements() + if len(updatedElems) > 0 { + attrs := updatedElems[0].(types.Object).Attributes() + + updated = &StartAndEndDateAPIModel{ + Start: attrs["start"].(types.String).ValueString(), + End: attrs["end"].(types.String).ValueString(), + } + } + + var securityFilters *SecurityFilterAPIModel + securityFiltersElems := attrs["security_filters"].(types.Set).Elements() + if len(securityFiltersElems) > 0 { + attrs := securityFiltersElems[0].(types.Object).Attributes() + + var cvssScore *CVSSScoreAPIModel + cvssScoreElems := attrs["cvss_score"].(types.Set).Elements() + if len(cvssScoreElems) > 0 { + attrs := cvssScoreElems[0].(types.Object).Attributes() + + cvssScore = &CVSSScoreAPIModel{ + MinScore: attrs["min_score"].(types.Float64).ValueFloat64(), + MaxScore: attrs["max_score"].(types.Float64).ValueFloat64(), + } + } + + securityFilters = &SecurityFilterAPIModel{ + Cve: attrs["cve"].(types.String).ValueString(), + IssueId: attrs["issue_id"].(types.String).ValueString(), + SummaryContains: attrs["summary_contains"].(types.String).ValueString(), + HasRemediation: attrs["has_remediation"].(types.Bool).ValueBool(), + CVSSScore: cvssScore, + } + } + + var licenseFilters *LicenseFilterAPIModel + licenseFiltersElems := attrs["license_filters"].(types.Set).Elements() + if len(licenseFiltersElems) > 0 { + attrs := licenseFiltersElems[0].(types.Object).Attributes() + + var licenseNames []string + d := attrs["license_names"].(types.Set).ElementsAs(ctx, &licenseNames, false) + if d.HasError() { + diags.Append(d...) + } + + var licensePatterns []string + d = attrs["license_patterns"].(types.Set).ElementsAs(ctx, &licensePatterns, false) + if d.HasError() { + diags.Append(d...) + } + + licenseFilters = &LicenseFilterAPIModel{ + Unknown: attrs["unknown"].(types.Bool).ValueBool(), + Unrecognized: attrs["unrecognized"].(types.Bool).ValueBool(), + LicenseNames: licenseNames, + LicensePatterns: licensePatterns, + } + } + + filters = &FiltersAPIModel{ + Type: attrs["type"].(types.String).ValueString(), + Component: attrs["component"].(types.String).ValueString(), + Artifact: attrs["artifact"].(types.String).ValueString(), + WatchNames: watchNames, + WatchPatterns: watchPatterns, + PolicyNames: policyNames, + Severities: severities, + Updated: updated, + SecurityFilters: securityFilters, + LicenseFilters: licenseFilters, + } + } + + return filters, diags +} + +func (r ViolationsReportResource) toAPIModel(ctx context.Context, plan ReportResourceModel, report *ReportAPIModel) diag.Diagnostics { + return plan.toAPIModel(ctx, report, r.toFiltersAPIModel) +} + +func (r *ViolationsReportResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = r.TypeName +} + +var violationsFiltersAttrs = map[string]schema.Attribute{ + "type": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + stringvalidator.OneOfCaseInsensitive("security", "license", "operational_risk"), }, - "watch_names": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Optional: true, - Description: "Select Xray watch by names. Only one attribute - 'watch_names' or 'watch_patterns' can be set.", + Description: "Violation type.", + }, + "watch_names": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("watch_patterns"), + ), }, - "watch_patterns": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Optional: true, - Description: "Select Xray watch name by patterns. Only one attribute - 'watch_names' or 'watch_patterns' can be set.", + Description: "Select Xray watch by names. Only one attribute - 'watch_names' or 'watch_patterns' can be set.", + }, + "watch_patterns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.ConflictsWith( + path.MatchRelative().AtParent().AtName("watch_names"), + ), }, - "component": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "Filter by component name, you can use (*) at the beginning or end of a substring as a wildcard.", + Description: "Select Xray watch name by patterns. Only one attribute - 'watch_names' or 'watch_patterns' can be set..", + }, + "component": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "artifact": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "Filter by artifact name, you can use (*) at the beginning or end of a substring as a wildcard.", + Description: "Filter by component name, you can use (*) at the beginning or end of a substring as a wildcard.", + }, + "artifact": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "policy_names": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Optional: true, - Description: "Select Xray policies by name.", + Description: "Filter by artifact name, you can use (*) at the beginning or end of a substring as a wildcard.", + }, + "policy_names": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), }, - "severities": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Optional: true, - Description: "Risk/severity levels. Allowed values: 'None', 'Low', 'Medium', 'High'.", + Description: "Select Xray policies by name.", + }, + "severities": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), + setvalidator.ValueStringsAre( + stringvalidator.OneOf("None", "Low", "Medium", "High"), + ), }, - "updated": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "start": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), - Description: "Created from date.", + Description: "Risk/severity levels. Allowed values: 'None', 'Low', 'Medium', 'High'.", + }, +} + +var violationsFiltersBlocks = map[string]schema.Block{ + "updated": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "start": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + IsRFC3339Time(), }, - "end": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), - Description: "Created to date.", + Description: "Created from date.", + }, + "end": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + IsRFC3339Time(), }, + Description: "Created to date.", }, }, }, - "security_filters": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "Security Filters.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "cve": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "CVE.", + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), + }, + }, + "security_filters": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "cve": schema.StringAttribute{ + Optional: true, + Computed: true, + Default: stringdefault.StaticString(""), // backward compatibility with SDKv2 version + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "issue_id": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "Issue ID.", + Description: "CVE.", + }, + "issue_id": schema.StringAttribute{ + Optional: true, + Computed: true, + Default: stringdefault.StaticString(""), // backward compatibility with SDKv2 version + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + Description: "Issue ID.", + }, + "summary_contains": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "cvss_score": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "CVSS score.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "min_score": { - Type: schema.TypeFloat, - Optional: true, - ValidateFunc: validation.FloatBetween(0, 10), - Description: "Minimum CVSS score.", + Description: "Vulnerability Summary.", + }, + "has_remediation": schema.BoolAttribute{ + Optional: true, + Description: "Whether the issue has a fix or not.", + }, + }, + Blocks: map[string]schema.Block{ + "cvss_score": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "min_score": schema.Float64Attribute{ + Optional: true, + Validators: []validator.Float64{ + float64validator.Between(0, 10), }, - "max_score": { - Type: schema.TypeFloat, - Optional: true, - ValidateFunc: validation.FloatBetween(0, 10), - Description: "Maximum CVSS score.", + Description: "Minimum CVSS score.", + }, + "max_score": schema.Float64Attribute{ + Optional: true, + Validators: []validator.Float64{ + float64validator.Between(0, 10), }, + Description: "Maximum CVSS score.", }, }, }, - "summary_contains": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "Vulnerability Summary.", - }, - "has_remediation": { - Type: schema.TypeBool, - Optional: true, - Description: "Whether the issue has a fix or not.", + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), }, + Description: "CVSS score.", }, }, }, - "license_filters": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "Licenses Filters.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unknown": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Unknown displays the components that Xray could not discover any licenses for.", - }, - "unrecognized": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Unrecognized displays the components that Xray found licenses for, but these licenses are not Xray recognized licenses.", - }, - "license_names": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Optional: true, - Description: "Filter licenses by names.", + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), + }, + Description: "Security Filters.", + }, + "license_filters": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "unknown": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + Description: "Unknown displays the components that Xray could not discover any licenses for.", + }, + "unrecognized": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + Description: "Unrecognized displays the components that Xray found licenses for, but these licenses are not Xray recognized licenses.", + }, + "license_names": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), }, - "license_patterns": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Optional: true, - Description: "Filter licenses by patterns.", + Description: "Filter licenses by names.", + }, + "license_patterns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), }, + Description: "Filter licenses by patterns.", }, }, }, - } + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), + }, + Description: "Licenses Filters.", + }, +} - return &schema.Resource{ - SchemaVersion: 1, - CreateContext: resourceXrayViolationsReportCreate, - ReadContext: resourceXrayReportRead, - UpdateContext: resourceXrayViolationsReportCreate, - DeleteContext: resourceXrayReportDelete, +func (r *ViolationsReportResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Version: 1, + Attributes: reportsSchemaAttrs, + Blocks: reportsBlocks(violationsFiltersAttrs, violationsFiltersBlocks), Description: "Creates Xray Violations report. The Violations report provides you with information on security " + "and license violations for each component in the selected scope. Violations information includes " + "information such as type of violation, impacted artifacts, and severity.", + } +} - CustomizeDiff: reportResourceDiff, - - Schema: getReportSchema(violationsFilterSchema), +func (r *ViolationsReportResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return } + r.ProviderData = req.ProviderData.(util.ProviderMetadata) +} + +func (r *ViolationsReportResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + r.ReportResource.Create(ctx, "violations", r.toAPIModel, req, resp) +} + +func (r *ViolationsReportResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + r.ReportResource.Read(ctx, req, resp) +} + +func (r *ViolationsReportResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + r.ReportResource.Update(ctx, "violations", r.toAPIModel, req, resp) +} + +func (r *ViolationsReportResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + r.ReportResource.Delete(ctx, req, resp) } From a82321cd9f138f053b6e7dfa1f31ba4e9cc4694f Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 12 Sep 2024 15:43:10 -0700 Subject: [PATCH 08/11] Migrate xray_operational_risks_report to Plugin Framework Refactor provider code to only Plugin Framework only Remove references to SDKv2 --- go.mod | 5 +- go.sum | 6 - main.go | 46 +- pkg/acctest/test.go | 79 +- .../{provider/framework.go => provider.go} | 23 +- pkg/xray/provider/sdkv2.go | 127 ---- pkg/xray/provider/sdkv2_test.go | 13 - pkg/xray/resource/reports.go | 717 ------------------ ...esource_xray_binary_manager_builds_test.go | 5 - ...y_binary_manager_release_bundle_v2_test.go | 7 - ...resource_xray_binary_manager_repos_test.go | 2 - .../resource_xray_custom_issue_test.go | 2 - .../resource_xray_ignore_rule_test.go | 24 +- .../resource_xray_license_policy_test.go | 30 +- ...ource_xray_operational_risk_policy_test.go | 18 +- .../resource_xray_operational_risks_report.go | 195 +++-- .../resource/resource_xray_report_test.go | 27 +- .../resource_xray_repository_config_test.go | 34 +- .../resource_xray_security_policy_test.go | 81 +- .../resource/resource_xray_settings_test.go | 3 - pkg/xray/resource/resource_xray_watch_test.go | 91 +-- .../resource/resource_xray_webhook_test.go | 3 - .../resource_xray_workers_count_test.go | 1 - pkg/xray/resource/util.go | 16 - 24 files changed, 275 insertions(+), 1280 deletions(-) rename pkg/xray/{provider/framework.go => provider.go} (95%) delete mode 100644 pkg/xray/provider/sdkv2.go delete mode 100644 pkg/xray/provider/sdkv2_test.go diff --git a/go.mod b/go.mod index a2c30f91..26294654 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,6 @@ require ( github.com/hashicorp/terraform-plugin-framework v1.11.0 github.com/hashicorp/terraform-plugin-framework-validators v0.13.0 github.com/hashicorp/terraform-plugin-go v0.23.0 - github.com/hashicorp/terraform-plugin-mux v0.16.0 - github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 github.com/hashicorp/terraform-plugin-testing v1.10.0 github.com/jfrog/terraform-provider-shared v1.25.5 github.com/samber/lo v1.47.0 @@ -55,6 +53,7 @@ require ( github.com/hashicorp/terraform-exec v0.21.0 // indirect github.com/hashicorp/terraform-json v0.22.1 // indirect github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect + github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 // indirect github.com/hashicorp/terraform-registry-address v0.2.3 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect @@ -89,8 +88,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/grpc v1.63.2 // indirect google.golang.org/protobuf v1.34.0 // indirect - gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect - gopkg.in/ldap.v2 v2.5.1 // indirect gopkg.in/yaml.v2 v2.3.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 37480f6e..977419ea 100644 --- a/go.sum +++ b/go.sum @@ -113,8 +113,6 @@ github.com/hashicorp/terraform-plugin-go v0.23.0 h1:AALVuU1gD1kPb48aPQUjug9Ir/12 github.com/hashicorp/terraform-plugin-go v0.23.0/go.mod h1:1E3Cr9h2vMlahWMbsSEcNrOCxovCZhOOIXjFHbjc/lQ= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= -github.com/hashicorp/terraform-plugin-mux v0.16.0 h1:RCzXHGDYwUwwqfYYWJKBFaS3fQsWn/ZECEiW7p2023I= -github.com/hashicorp/terraform-plugin-mux v0.16.0/go.mod h1:PF79mAsPc8CpusXPfEVa4X8PtkB+ngWoiUClMrNZlYo= github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 h1:kJiWGx2kiQVo97Y5IOGR4EMcZ8DtMswHhUuFibsCQQE= github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0/go.mod h1:sl/UoabMc37HA6ICVMmGO+/0wofkVIRxf+BMb/dnoIg= github.com/hashicorp/terraform-plugin-testing v1.10.0 h1:2+tmRNhvnfE4Bs8rB6v58S/VpqzGC6RCh9Y8ujdn+aw= @@ -323,13 +321,9 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4= google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= -gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= 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/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU= -gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go index 9f0c0e89..4836f0c9 100644 --- a/main.go +++ b/main.go @@ -6,11 +6,7 @@ import ( "log" "github.com/hashicorp/terraform-plugin-framework/providerserver" - "github.com/hashicorp/terraform-plugin-go/tfprotov6" - "github.com/hashicorp/terraform-plugin-go/tfprotov6/tf6server" - "github.com/hashicorp/terraform-plugin-mux/tf5to6server" - "github.com/hashicorp/terraform-plugin-mux/tf6muxserver" - "github.com/jfrog/terraform-provider-xray/pkg/xray/provider" + "github.com/jfrog/terraform-provider-xray/pkg/xray" ) // Run the docs generation tool, check its repository for more information on how it works and how docs @@ -18,48 +14,18 @@ import ( //go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs func main() { - ctx := context.Background() - var debug bool flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve") flag.Parse() - upgradedSdkServer, err := tf5to6server.UpgradeServer( - ctx, - provider.SdkV2().GRPCProvider, // Example terraform-plugin-sdk provider - ) - - if err != nil { - log.Fatal(err) + opts := providerserver.ServeOpts{ + Address: "registry.terraform.io/jfrog/xray", + Debug: debug, } - providers := []func() tfprotov6.ProviderServer{ - providerserver.NewProtocol6(provider.Framework()()), // Example terraform-plugin-framework provider - func() tfprotov6.ProviderServer { - return upgradedSdkServer - }, - } - - muxServer, err := tf6muxserver.NewMuxServer(ctx, providers...) - - if err != nil { - log.Fatal(err) - } - - var serveOpts []tf6server.ServeOpt - - if debug { - serveOpts = append(serveOpts, tf6server.WithManagedDebug()) - } - - err = tf6server.Serve( - "registry.terraform.io/jfrog/xray", - muxServer.ProviderServer, - serveOpts..., - ) - + err := providerserver.Serve(context.Background(), xray.NewProvider(), opts) if err != nil { - log.Fatal(err) + log.Fatal(err.Error()) } } diff --git a/pkg/acctest/test.go b/pkg/acctest/test.go index d1dfc623..41b83ba5 100644 --- a/pkg/acctest/test.go +++ b/pkg/acctest/test.go @@ -1,96 +1,36 @@ package acctest import ( - "context" "fmt" "net/http" "strings" - "sync" "testing" "github.com/go-resty/resty/v2" + "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/providerserver" "github.com/hashicorp/terraform-plugin-go/tfprotov6" - "github.com/hashicorp/terraform-plugin-mux/tf5to6server" - "github.com/hashicorp/terraform-plugin-mux/tf6muxserver" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - terraform2 "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/jfrog/terraform-provider-shared/client" "github.com/jfrog/terraform-provider-shared/testutil" - "github.com/jfrog/terraform-provider-shared/util" - "github.com/jfrog/terraform-provider-xray/pkg/xray/provider" + "github.com/jfrog/terraform-provider-xray/pkg/xray" ) // Provider PreCheck(t) must be called before using this provider instance. -var Provider *schema.Provider -var ProviderFactories map[string]func() (*schema.Provider, error) - -// testAccProviderConfigure ensures Provider is only configured once -// -// The PreCheck(t) function is invoked for every test and this prevents -// extraneous reconfiguration to the same values each time. However, this does -// not prevent reconfiguration that may happen should the address of -// Provider be errantly reused in ProviderFactories. -var testAccProviderConfigure sync.Once - -// ProtoV6MuxProviderFactories is used to instantiate both SDK v2 and Framework providers -// during acceptance tests. Use it only if you need to combine resources from SDK v2 and the Framework in the same test. -var ProtoV6MuxProviderFactories map[string]func() (tfprotov6.ProviderServer, error) +var Provider provider.Provider var ProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){ - "xray": providerserver.NewProtocol6WithError(provider.Framework()()), + "xray": providerserver.NewProtocol6WithError(xray.NewProvider()()), } func init() { - Provider = provider.SdkV2() - - ProviderFactories = map[string]func() (*schema.Provider, error){ - "xray": func() (*schema.Provider, error) { return Provider, nil }, - } - - ProtoV6MuxProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){ - "xray": func() (tfprotov6.ProviderServer, error) { - ctx := context.Background() - - upgradedSdkServer, err := tf5to6server.UpgradeServer( - ctx, - provider.SdkV2().GRPCProvider, // terraform-plugin-sdk provider - ) - if err != nil { - return nil, err - } - - providers := []func() tfprotov6.ProviderServer{ - providerserver.NewProtocol6(provider.Framework()()), // terraform-plugin-framework provider - func() tfprotov6.ProviderServer { - return upgradedSdkServer - }, - } + Provider = xray.NewProvider()() - muxServer, err := tf6muxserver.NewMuxServer(ctx, providers...) - - if err != nil { - return nil, err - } - - return muxServer.ProviderServer(), nil - }, + ProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){ + "xray": providerserver.NewProtocol6WithError(Provider), } } -// PreCheck This function should be present in every acceptance test. -func PreCheck(t *testing.T) { - // Since we are outside the scope of the Terraform configuration we must - // call Configure() to properly initialize the provider configuration. - testAccProviderConfigure.Do(func() { - configErr := Provider.Configure(context.Background(), (*terraform2.ResourceConfig)(terraform2.NewResourceConfigRaw(nil))) - if configErr != nil && configErr.HasError() { - t.Fatalf("failed to configure provider %v", configErr) - } - }) -} - type CheckFun func(id string, request *resty.Request) (*resty.Response, error) func VerifyDeleted(id, identifierAttribute string, check CheckFun) func(*terraform.State) error { @@ -104,14 +44,13 @@ func VerifyDeleted(id, identifierAttribute string, check CheckFun) func(*terrafo return fmt.Errorf("provider is not initialized. Please PreCheck() is included in your acceptance test") } - providerMeta := Provider.Meta().(util.ProviderMetadata) - identifier := rs.Primary.ID if identifierAttribute != "" { identifier = rs.Primary.Attributes[identifierAttribute] } - resp, err := check(identifier, providerMeta.Client.R()) + client := Provider.(*xray.XrayProvider).Meta.Client + resp, err := check(identifier, client.R()) if err != nil { return err } diff --git a/pkg/xray/provider/framework.go b/pkg/xray/provider.go similarity index 95% rename from pkg/xray/provider/framework.go rename to pkg/xray/provider.go index 51669e23..c0043fdd 100644 --- a/pkg/xray/provider/framework.go +++ b/pkg/xray/provider.go @@ -1,4 +1,4 @@ -package provider +package xray import ( "context" @@ -18,10 +18,15 @@ import ( xray_resource "github.com/jfrog/terraform-provider-xray/pkg/xray/resource" ) +var Version = "0.0.1" +var productId = "terraform-provider-xray/" + Version + // Ensure the implementation satisfies the provider.Provider interface. var _ provider.Provider = &XrayProvider{} -type XrayProvider struct{} +type XrayProvider struct { + Meta util.ProviderMetadata +} // XrayProviderModel describes the provider data model. type XrayProviderModel struct { @@ -159,17 +164,16 @@ func (p *XrayProvider) Configure(ctx context.Context, req provider.ConfigureRequ featureUsage := fmt.Sprintf("Terraform/%s", req.TerraformVersion) go util.SendUsage(ctx, restyClient.R(), productId, featureUsage) - resp.DataSourceData = util.ProviderMetadata{ + meta := util.ProviderMetadata{ Client: restyClient, ProductId: productId, XrayVersion: version, } - resp.ResourceData = util.ProviderMetadata{ - Client: restyClient, - ProductId: productId, - XrayVersion: version, - } + p.Meta = meta + + resp.DataSourceData = meta + resp.ResourceData = meta } // Resources satisfies the provider.Provider interface for ArtifactoryProvider. @@ -183,6 +187,7 @@ func (p *XrayProvider) Resources(ctx context.Context) []func() resource.Resource xray_resource.NewLicensePolicyResource, xray_resource.NewLicensesReportResource, xray_resource.NewOperationalRiskPolicyResource, + xray_resource.NewOperationalRisksReportResource, xray_resource.NewRepositoryConfigResource, xray_resource.NewSecurityPolicyResource, xray_resource.NewSettingsResource, @@ -201,7 +206,7 @@ func (p *XrayProvider) DataSources(_ context.Context) []func() datasource.DataSo } } -func Framework() func() provider.Provider { +func NewProvider() func() provider.Provider { return func() provider.Provider { return &XrayProvider{} } diff --git a/pkg/xray/provider/sdkv2.go b/pkg/xray/provider/sdkv2.go deleted file mode 100644 index 83942bf5..00000000 --- a/pkg/xray/provider/sdkv2.go +++ /dev/null @@ -1,127 +0,0 @@ -package provider - -import ( - "context" - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "github.com/jfrog/terraform-provider-shared/client" - "github.com/jfrog/terraform-provider-shared/util" - "github.com/jfrog/terraform-provider-shared/util/sdk" - "github.com/jfrog/terraform-provider-shared/validator" - xray "github.com/jfrog/terraform-provider-xray/pkg/xray/resource" -) - -var Version = "0.0.1" -var productId = "terraform-provider-xray/" + Version - -// Provider Xray provider that supports configuration via username+password or a token -// Supported resources are policies and watches -func SdkV2() *schema.Provider { - p := &schema.Provider{ - Schema: map[string]*schema.Schema{ - "url": { - Type: schema.TypeString, - Optional: true, - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"XRAY_URL", "JFROG_URL"}, "http://localhost:8081"), - ValidateFunc: validation.IsURLWithHTTPorHTTPS, - Description: "URL of Xray. This can also be sourced from the `XRAY_URL` or `JFROG_URL` environment variable. Default to 'http://localhost:8081' if not set.", - }, - "access_token": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"XRAY_ACCESS_TOKEN", "JFROG_ACCESS_TOKEN"}, ""), - Description: "This is a bearer token that can be given to you by your admin under `Identity and Access`", - }, - "oidc_provider_name": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "OIDC provider name. See [Configure an OIDC Integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration) for more details.", - }, - "check_license": { - Type: schema.TypeBool, - Optional: true, - Default: true, - Description: "Toggle for pre-flight checking of Artifactory Pro and Enterprise license. Default to `true`.", - Deprecated: "Remove this attribute from your provider configuration as it is no longer used and the attribute will be removed in the next major version of the provider.", - }, - }, - - ResourcesMap: sdk.AddTelemetry( - productId, - map[string]*schema.Resource{ - "xray_operational_risks_report": xray.ResourceXrayOperationalRisksReport(), - }, - ), - } - - p.ConfigureContextFunc = func(ctx context.Context, data *schema.ResourceData) (interface{}, diag.Diagnostics) { - var ds diag.Diagnostics - meta, d := providerConfigure(ctx, data, p.TerraformVersion) - if d != nil { - ds = append(ds, d...) - } - return meta, ds - } - - return p -} - -// Creates the client for artifactory, will use token auth -func providerConfigure(ctx context.Context, d *schema.ResourceData, terraformVersion string) (interface{}, diag.Diagnostics) { - URL, ok := d.GetOk("url") - if URL == nil || URL == "" || !ok { - return nil, diag.Errorf("you must supply a URL") - } - - restyClient, err := client.Build(URL.(string), productId) - if err != nil { - return nil, diag.FromErr(err) - } - - var accessToken string - - if v, ok := d.GetOk("oidc_provider_name"); ok { - oidcAccessToken, err := util.OIDCTokenExchange(ctx, restyClient, v.(string)) - if err != nil { - return nil, diag.FromErr(err) - } - - if oidcAccessToken != "" { - accessToken = oidcAccessToken - } - } - - if v, ok := d.GetOk("access_token"); ok && v != "" { - accessToken = v.(string) - } - - if accessToken == "" { - return nil, diag.Errorf("While configuring the provider, the Access Token was not found in " + - "the JFROG_ACCESS_TOKEN/XRAY_ACCESS_TOKEN environment variable, or provider " + - "configuration block access_token attribute, or from Terraform Cloud Workload Identity token.") - } - - restyClient, err = client.AddAuth(restyClient, "", accessToken) - if err != nil { - return nil, diag.FromErr(err) - } - - xrayVersion, err := util.GetXrayVersion(restyClient) - if err != nil { - return nil, diag.FromErr(err) - } - - featureUsage := fmt.Sprintf("Terraform/%s", terraformVersion) - go util.SendUsage(ctx, restyClient.R(), productId, featureUsage) - - return util.ProviderMetadata{ - Client: restyClient, - XrayVersion: xrayVersion, - }, nil - -} diff --git a/pkg/xray/provider/sdkv2_test.go b/pkg/xray/provider/sdkv2_test.go deleted file mode 100644 index e9292fd7..00000000 --- a/pkg/xray/provider/sdkv2_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package provider_test - -import ( - "testing" - - "github.com/jfrog/terraform-provider-xray/pkg/xray/provider" -) - -func TestProvider(t *testing.T) { - if err := provider.SdkV2().InternalValidate(); err != nil { - t.Fatalf("err: %s", err) - } -} diff --git a/pkg/xray/resource/reports.go b/pkg/xray/resource/reports.go index 1f2018fd..269f2c17 100644 --- a/pkg/xray/resource/reports.go +++ b/pkg/xray/resource/reports.go @@ -20,15 +20,9 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" - sdkv2_diag "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - sdkv2_schema "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/jfrog/terraform-provider-shared/util" utilfw "github.com/jfrog/terraform-provider-shared/util/fw" - "github.com/jfrog/terraform-provider-shared/util/sdk" - sdkv2_validator "github.com/jfrog/terraform-provider-shared/validator" "github.com/samber/lo" - "golang.org/x/exp/slices" ) const ( @@ -467,182 +461,6 @@ var reportsBlocks = func(filtersAttrs map[string]schema.Attribute, filtersBlocks } } -var getReportSchema = func(filtersSchema map[string]*sdkv2_schema.Schema) map[string]*sdkv2_schema.Schema { - return sdk.MergeMaps( - getProjectKeySchema(false, ""), - map[string]*sdkv2_schema.Schema{ - "report_id": { - Type: sdkv2_schema.TypeInt, - Optional: true, - Computed: true, - Description: "Report ID", - }, - "name": { - Type: sdkv2_schema.TypeString, - Required: true, - ForceNew: true, - ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, - Description: "Name of the report.", - }, - "resources": { - Type: sdkv2_schema.TypeSet, - Required: true, - MaxItems: 1, - Description: "The list of resources to include into the report.", - Elem: &sdkv2_schema.Resource{ - Schema: map[string]*sdkv2_schema.Schema{ - "repository": { - Type: sdkv2_schema.TypeSet, - Optional: true, - MinItems: 1, - Description: "The list of repositories for the report. Only one type of resource can be set per report.", - Elem: &sdkv2_schema.Resource{ - Schema: map[string]*sdkv2_schema.Schema{ - "name": { - Type: sdkv2_schema.TypeString, - Required: true, - ValidateDiagFunc: sdkv2_validator.StringIsNotEmpty, - Description: "Repository name.", - }, - "include_path_patterns": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "Include path patterns.", - }, - "exclude_path_patterns": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "Exclude path patterns.", - }, - }, - }, - }, - "builds": { - Type: sdkv2_schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "The builds to include into the report. Only one type of resource can be set per report.", - Elem: &sdkv2_schema.Resource{ - Schema: map[string]*sdkv2_schema.Schema{ - "names": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "The list of build names. Only one of 'names' or '*_patterns' can be set.", - }, - "include_patterns": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "The list of include patterns. Only one of 'names' or '*_patterns' can be set.", - }, - "exclude_patterns": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "The list of exclude patterns. Only one of 'names' or '*_patterns' can be set.", - }, - "number_of_latest_versions": { - Type: sdkv2_schema.TypeInt, - Optional: true, - Default: 1, - ValidateFunc: validation.IntAtLeast(1), - Description: "The number of latest build versions to include to the report.", - }, - }, - }, - }, - "release_bundles": { - Type: sdkv2_schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "The release bundles to include into the report. Only one type of resource can be set per report.", - Elem: &sdkv2_schema.Resource{ - Schema: map[string]*sdkv2_schema.Schema{ - "names": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "The list of release bundles names.", - }, - "include_patterns": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "The list of include patterns", - }, - "exclude_patterns": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "The list of exclude patterns", - }, - "number_of_latest_versions": { - Type: sdkv2_schema.TypeInt, - Optional: true, - Default: 1, - ValidateFunc: validation.IntAtLeast(0), - Description: "The number of latest release bundle versions to include to the report.", - }, - }, - }, - }, - "projects": { - Type: sdkv2_schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "The projects to include into the report. Only one type of resource can be set per report.", - Elem: &sdkv2_schema.Resource{ - Schema: map[string]*sdkv2_schema.Schema{ - "names": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "The list of project names.", - }, - "include_key_patterns": { - Type: sdkv2_schema.TypeSet, - Elem: &sdkv2_schema.Schema{Type: sdkv2_schema.TypeString}, - Set: sdkv2_schema.HashString, - Optional: true, - Description: "The list of include patterns.", - }, - "number_of_latest_versions": { - Type: sdkv2_schema.TypeInt, - Optional: true, - Default: 1, - ValidateFunc: validation.IntAtLeast(0), - Description: "The number of latest release bundle versions to include to the report.", - }, - }, - }, - }, - }, - }, - }, - "filters": { - Type: sdkv2_schema.TypeSet, - Required: true, - Description: "Advanced filters.", - Elem: &sdkv2_schema.Resource{ - Schema: filtersSchema, - }, - }, - }, - ) -} - type ReportAPIModel struct { ReportId int64 `json:"report_id,omitempty"` Name string `json:"name"` @@ -736,35 +554,6 @@ type LicenseFilterAPIModel struct { LicensePatterns []string `json:"license_patterns,omitempty"` } -func unpackReport(d *sdkv2_schema.ResourceData, reportType string) *ReportAPIModel { - report := ReportAPIModel{} - - if v, ok := d.GetOk("project_key"); ok { - report.ProjectKey = v.(string) - } - report.Name = d.Get("name").(string) - - report.Resources = unpackResources(d.Get("resources").(*sdkv2_schema.Set)) - - if reportType == "vulnerabilities" { - report.Filters = unpackVulnerabilitiesFilters(d.Get("filters").(*sdkv2_schema.Set)) - } - - if reportType == "licenses" { - report.Filters = unpackLicensesFilters(d.Get("filters").(*sdkv2_schema.Set)) - } - - if reportType == "violations" { - report.Filters = unpackViolationsFilters(d.Get("filters").(*sdkv2_schema.Set)) - } - - if reportType == "operationalRisks" { - report.Filters = unpackOperationalRisksFilters(d.Get("filters").(*sdkv2_schema.Set)) - } - - return &report -} - func (r *ReportResource) Create( ctx context.Context, reportType string, @@ -951,509 +740,3 @@ func (r *ReportResource) Delete(ctx context.Context, req resource.DeleteRequest, // If the logic reaches here, it implicitly succeeded and will remove // the resource from state if there are no other errors. } - -func unpackResources(configured *sdkv2_schema.Set) *ResourcesAPIModel { - var resources ResourcesAPIModel - m := configured.List()[0].(map[string]interface{}) - - if m["repository"] != nil { - resources.Repositories = unpackRepository(m["repository"].(*sdkv2_schema.Set)) - } - - if m["builds"] != nil { - resources.Builds = unpackBuilds(m["builds"].(*sdkv2_schema.Set)) - } - - if m["release_bundles"] != nil { - resources.ReleaseBundles = unpackReleaseBundles(m["release_bundles"].(*sdkv2_schema.Set)) - } - - if m["release_bundles"] != nil { - resources.Projects = unpackProjects(m["projects"].(*sdkv2_schema.Set)) - } - - return &resources -} - -func unpackRepository(d *sdkv2_schema.Set) *[]RepositoryAPIModel { - repos := d.List() - - if len(d.List()) > 0 { - var repositories []RepositoryAPIModel - for _, raw := range repos { - f := raw.(map[string]interface{}) - repository := RepositoryAPIModel{ - Name: f["name"].(string), - IncludePathPatterns: sdk.CastToStringArr(f["include_path_patterns"].(*sdkv2_schema.Set).List()), - ExcludePathPatterns: sdk.CastToStringArr(f["exclude_path_patterns"].(*sdkv2_schema.Set).List()), - } - repositories = append(repositories, repository) - } - return &repositories - } - - return nil -} - -func unpackBuilds(d *sdkv2_schema.Set) *BuildsAPIModel { - if len(d.List()) > 0 { - var builds BuildsAPIModel - f := d.List()[0].(map[string]interface{}) - builds = BuildsAPIModel{ - Names: sdk.CastToStringArr(f["names"].(*sdkv2_schema.Set).List()), - IncludePatterns: sdk.CastToStringArr(f["include_patterns"].(*sdkv2_schema.Set).List()), - ExcludePatterns: sdk.CastToStringArr(f["exclude_patterns"].(*sdkv2_schema.Set).List()), - NumberOfLatestVersions: f["number_of_latest_versions"].(int64), - } - return &builds - } - - return nil -} - -func unpackReleaseBundles(d *sdkv2_schema.Set) *ReleaseBundlesAPIModel { - if len(d.List()) > 0 { - var releaseBundles ReleaseBundlesAPIModel - f := d.List()[0].(map[string]interface{}) - releaseBundles = ReleaseBundlesAPIModel{ - Names: sdk.CastToStringArr(f["names"].(*sdkv2_schema.Set).List()), - IncludePatterns: sdk.CastToStringArr(f["include_patterns"].(*sdkv2_schema.Set).List()), - ExcludePatterns: sdk.CastToStringArr(f["exclude_patterns"].(*sdkv2_schema.Set).List()), - NumberOfLatestVersions: f["number_of_latest_versions"].(int64), - } - return &releaseBundles - } - - return nil -} - -func unpackProjects(d *sdkv2_schema.Set) *ProjectsAPIModel { - if len(d.List()) > 0 { - var projects ProjectsAPIModel - f := d.List()[0].(map[string]interface{}) - projects = ProjectsAPIModel{ - Names: sdk.CastToStringArr(f["names"].(*sdkv2_schema.Set).List()), - IncludeKeyPatterns: sdk.CastToStringArr(f["include_key_patterns"].(*sdkv2_schema.Set).List()), - NumberOfLatestVersions: f["number_of_latest_versions"].(int64), - } - return &projects - } - - return nil -} - -func unpackVulnerabilitiesFilters(filter *sdkv2_schema.Set) *FiltersAPIModel { - var filters FiltersAPIModel - m := filter.List()[0].(map[string]interface{}) - - if m["vulnerable_component"] != nil { - filters.VulnerableComponent = m["vulnerable_component"].(string) - } - - if m["impacted_artifact"] != nil { - filters.ImpactedArtifact = m["impacted_artifact"].(string) - } - - filters.HasRemediation = m["has_remediation"].(bool) - - if m["cve"] != nil { - filters.CVE = m["cve"].(string) - } - - if m["issue_id"] != nil { - filters.IssueId = m["issue_id"].(string) - } - - filters.Severities = sdk.CastToStringArr(m["severities"].(*sdkv2_schema.Set).List()) - - if m["cvss_score"] != nil { - filters.CVSSScore = unpackCvssScore(m["cvss_score"].(*sdkv2_schema.Set)) - } - - if m["published"] != nil { - filters.Published = unpackStartAndEndDate(m["published"].(*sdkv2_schema.Set)) - } - - if m["scan_date"] != nil { - filters.ScanDate = unpackStartAndEndDate(m["scan_date"].(*sdkv2_schema.Set)) - } - - return &filters -} - -func unpackLicensesFilters(filter *sdkv2_schema.Set) *FiltersAPIModel { - var filters FiltersAPIModel - m := filter.List()[0].(map[string]interface{}) - - if m["component"] != nil { - filters.Component = m["component"].(string) - } - - if m["artifact"] != nil { - filters.Artifact = m["artifact"].(string) - } - - filters.Unknown = m["unknown"].(bool) - filters.Unrecognized = m["unrecognized"].(bool) - - filters.LicenseNames = sdk.CastToStringArr(m["license_names"].(*sdkv2_schema.Set).List()) - filters.LicensePatterns = sdk.CastToStringArr(m["license_patterns"].(*sdkv2_schema.Set).List()) - - if m["scan_date"] != nil { - filters.ScanDate = unpackStartAndEndDate(m["scan_date"].(*sdkv2_schema.Set)) - } - - return &filters -} - -func unpackViolationsSecurityFilters(filter *sdkv2_schema.Set) *SecurityFilterAPIModel { - var securityFilter SecurityFilterAPIModel - m := filter.List()[0].(map[string]interface{}) - - if m["cve"] != nil { - securityFilter.Cve = m["cve"].(string) - } - - if m["issue_id"] != nil { - securityFilter.IssueId = m["issue_id"].(string) - } - - if m["cvss_score"] != nil { - securityFilter.CVSSScore = unpackCvssScore(m["cvss_score"].(*sdkv2_schema.Set)) - } - - if m["summary_contains"] != nil { - securityFilter.IssueId = m["summary_contains"].(string) - } - - securityFilter.HasRemediation = m["has_remediation"].(bool) - - if m["updated"] != nil { - securityFilter.Published = unpackStartAndEndDate(m["published"].(*sdkv2_schema.Set)) - } - - return &securityFilter -} - -func unpackViolationsFilters(filter *sdkv2_schema.Set) *FiltersAPIModel { - var filters FiltersAPIModel - m := filter.List()[0].(map[string]interface{}) - - if len(m) > 0 { - - if m["type"] != nil { - filters.Type = m["type"].(string) - } - - filters.WatchNames = sdk.CastToStringArr(m["watch_names"].(*sdkv2_schema.Set).List()) - filters.WatchPatterns = sdk.CastToStringArr(m["watch_patterns"].(*sdkv2_schema.Set).List()) - - if m["component"] != nil { - filters.Component = m["component"].(string) - } - - if m["artifact"] != nil { - filters.Artifact = m["artifact"].(string) - } - - filters.PolicyNames = sdk.CastToStringArr(m["policy_names"].(*sdkv2_schema.Set).List()) - filters.Severities = sdk.CastToStringArr(m["severities"].(*sdkv2_schema.Set).List()) - - if m["updated"].(*sdkv2_schema.Set).Len() > 0 { - filters.Updated = unpackStartAndEndDate(m["updated"].(*sdkv2_schema.Set)) - } - - if m["security_filters"].(*sdkv2_schema.Set).Len() > 0 { - filters.SecurityFilters = unpackViolationsSecurityFilters(m["security_filters"].(*sdkv2_schema.Set)) - } - - if m["license_filters"].(*sdkv2_schema.Set).Len() > 0 { - filters.LicenseFilters = unpackViolationsLicensesFilters(m["license_filters"].(*sdkv2_schema.Set)) - } - - return &filters - } - return nil -} - -func unpackViolationsLicensesFilters(filter *sdkv2_schema.Set) *LicenseFilterAPIModel { - var filters LicenseFilterAPIModel - m := filter.List()[0].(map[string]interface{}) - - filters.Unknown = m["unknown"].(bool) - filters.Unrecognized = m["unrecognized"].(bool) - - filters.LicenseNames = sdk.CastToStringArr(m["license_names"].(*sdkv2_schema.Set).List()) - filters.LicensePatterns = sdk.CastToStringArr(m["license_patterns"].(*sdkv2_schema.Set).List()) - - return &filters -} - -func unpackOperationalRisksFilters(filter *sdkv2_schema.Set) *FiltersAPIModel { - var filters FiltersAPIModel - m := filter.List()[0].(map[string]interface{}) - - if m["component"] != nil { - filters.Component = m["component"].(string) - } - if m["artifact"] != nil { - filters.Artifact = m["artifact"].(string) - } - - filters.Risks = sdk.CastToStringArr(m["risks"].(*sdkv2_schema.Set).List()) - - if m["scan_date"] != nil { - filters.ScanDate = unpackStartAndEndDate(m["scan_date"].(*sdkv2_schema.Set)) - } - - return &filters -} - -func unpackCvssScore(d *sdkv2_schema.Set) *CVSSScoreAPIModel { - var cvssScore CVSSScoreAPIModel - - if len(d.List()) > 0 { - f := d.List()[0].(map[string]interface{}) - cvssScore = CVSSScoreAPIModel{ - MinScore: f["min_score"].(float64), - MaxScore: f["max_score"].(float64), - } - return &cvssScore - } - - return nil -} - -func unpackStartAndEndDate(d *sdkv2_schema.Set) *StartAndEndDateAPIModel { - var dates StartAndEndDateAPIModel - - if len(d.List()) > 0 { - f := d.List()[0].(map[string]interface{}) - dates = StartAndEndDateAPIModel{ - Start: f["start"].(string), - End: f["end"].(string), - } - return &dates - } - - return nil -} - -func resourceXrayVulnerabilitiesReportCreate(ctx context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { - return createReport("vulnerabilities", d, m) -} - -func resourceXrayLicensesReportCreate(ctx context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { - return createReport("licenses", d, m) -} - -func resourceXrayViolationsReportCreate(ctx context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { - return createReport("violations", d, m) -} - -func resourceXrayOperationalRisksReportCreate(ctx context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { - return createReport("operationalRisks", d, m) -} - -func resourceXrayReportRead(ctx context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { - report := ReportAPIModel{} - - projectKey := d.Get("project_key").(string) - req, err := getRestyRequest(m.(util.ProviderMetadata).Client, projectKey) - if err != nil { - return sdkv2_diag.FromErr(err) - } - - resp, err := req. - SetResult(&report). - SetPathParam("reportId", d.Id()). - Get("xray/api/v1/reports/{reportId}") - if err != nil { - return sdkv2_diag.FromErr(err) - } - if resp.StatusCode() == http.StatusNotFound { - d.SetId("") - return sdkv2_diag.Errorf("report (%s) not found, removing from state", d.Id()) - } - if resp.IsError() { - return sdkv2_diag.Errorf("%s", resp.String()) - } - - return nil -} - -func resourceXrayReportDelete(_ context.Context, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { - projectKey := d.Get("project_key").(string) - req, err := getRestyRequest(m.(util.ProviderMetadata).Client, projectKey) - if err != nil { - return sdkv2_diag.FromErr(err) - } - - resp, err := req. - SetPathParam("reportId", d.Id()). - Delete("xray/api/v1/reports/{reportId}") - if err != nil { - return sdkv2_diag.FromErr(err) - } - if resp.IsError() { - return sdkv2_diag.Errorf("%s", resp.String()) - } - - d.SetId("") - - return nil -} - -func createReport(reportType string, d *sdkv2_schema.ResourceData, m interface{}) sdkv2_diag.Diagnostics { - report := unpackReport(d, reportType) - req, err := getRestyRequest(m.(util.ProviderMetadata).Client, report.ProjectKey) - if err != nil { - return sdkv2_diag.FromErr(err) - } - - resp, err := req. - SetBody(report). - SetResult(&report). - SetPathParam("reportType", reportType). - Post("xray/api/v1/reports/{reportType}") - if err != nil { - return sdkv2_diag.FromErr(err) - } - if resp.IsError() { - return sdkv2_diag.Errorf("%s", resp.String()) - } - - d.SetId(fmt.Sprintf("%d", report.ReportId)) - - return nil -} - -func reportResourceDiff(_ context.Context, diff *sdkv2_schema.ResourceDiff, v interface{}) error { - reportResources := diff.Get("resources").(*sdkv2_schema.Set).List() - if len(reportResources) == 0 { - return nil - } - - // Verify only one resource attribute is set. - for _, reportResource := range reportResources { - r := reportResource.(map[string]interface{}) - - var resourceCounter int - - if r["repository"].(*sdkv2_schema.Set).Len() > 0 { - resourceCounter += 1 - } - - if r["builds"].(*sdkv2_schema.Set).Len() > 0 { - resourceCounter += 1 - } - if r["release_bundles"].(*sdkv2_schema.Set).Len() > 0 { - resourceCounter += 1 - } - - if r["projects"].(*sdkv2_schema.Set).Len() > 0 { - resourceCounter += 1 - } - - if resourceCounter > 1 { - return fmt.Errorf("request payload is invalid as only one resource per report is allowed") - } - } - // Verify filter fields - reportFilters := diff.Get("filters").(*sdkv2_schema.Set).List() - for _, reportFilter := range reportFilters { - r := reportFilter.(map[string]interface{}) - - if len(reportFilters) == 0 { - return nil - } - // Check violations filter - var watchCounter int - if r["watch_names"] != nil && r["watch_names"].(*sdkv2_schema.Set).Len() > 0 { - watchCounter += 1 - } - - if r["watch_patterns"] != nil && r["watch_patterns"].(*sdkv2_schema.Set).Len() > 0 { - watchCounter += 1 - } - - if watchCounter > 1 { - return fmt.Errorf("request payload is invalid. Only one of 'watch_names' or 'watch_patterns' is allowed in the violations filter") - } - // Check vulnerabilities filter - var secFilterCounter int - if r["cve"] != nil && r["cve"] != "" { - secFilterCounter += 1 - } - - if r["issue_id"] != nil && r["issue_id"] != "" { - secFilterCounter += 1 - } - - if secFilterCounter > 1 { - return fmt.Errorf("request payload is invalid. Only one of 'cve' or 'issue_id' is allowed in the vulnerabilities filter") - } - - var severitiesFilterCounter int - if r["severities"] != nil && r["severities"].(*sdkv2_schema.Set).Len() > 0 { - severitiesFilterCounter += 1 - } - - if r["cvss_score"] != nil && r["cvss_score"].(*sdkv2_schema.Set).Len() > 0 { - severitiesFilterCounter += 1 - } - - if severitiesFilterCounter > 1 { - return fmt.Errorf("request payload is invalid. Only one of 'severities' or 'cvss_score' is allowed in the vulnerabilities filter") - } - - // Check license filter in violations report - var nestedLicenseFilterCounter int - if r["license_filters"] != nil && r["license_filters"].(*sdkv2_schema.Set).Len() > 0 { - m := r["license_filters"].(*sdkv2_schema.Set).List()[0].(map[string]interface{}) - if m["license_names"] != nil && m["license_names"].(*sdkv2_schema.Set).Len() > 0 { - nestedLicenseFilterCounter += 1 - } - if m["license_patterns"] != nil && m["license_patterns"].(*sdkv2_schema.Set).Len() > 0 { - nestedLicenseFilterCounter += 1 - } - } - - if nestedLicenseFilterCounter > 1 { - return fmt.Errorf("request payload is invalid. Only one of 'license_names' or 'license_patterns' is allowed in the license filter") - } - - // Check license filter in license report - var licenseFilterCounter int - if r["license_names"] != nil && r["license_names"].(*sdkv2_schema.Set).Len() > 0 { - licenseFilterCounter += 1 - } - - if r["license_patterns"] != nil && r["license_patterns"].(*sdkv2_schema.Set).Len() > 0 { - licenseFilterCounter += 1 - } - - if licenseFilterCounter > 1 { - return fmt.Errorf("request payload is invalid. Only one of 'license_names' or 'license_patterns' is allowed in the license filter") - } - - // Verify severities in Vulnerabilities and Violations filters - if r["severities"] != nil && r["severities"].(*sdkv2_schema.Set).Len() > 0 { - for _, severity := range r["severities"].(*sdkv2_schema.Set).List() { - if !slices.Contains([]string{"Low", "Medium", "High", "Critical"}, severity.(string)) { - return fmt.Errorf("'severity' attribute value must be one or several of 'Low', 'Medium', 'High', 'Critical'") - } - } - } - - // Verify risks in Operational Risks filter - if r["risks"] != nil && r["risks"].(*sdkv2_schema.Set).Len() > 0 { - for _, severity := range r["risks"].(*sdkv2_schema.Set).List() { - if !slices.Contains([]string{"None", "Low", "Medium", "High"}, severity.(string)) { - return fmt.Errorf("'risks' attribute value must be one or several of 'None', 'Low', 'Medium', 'High'") - } - } - } - } - return nil -} diff --git a/pkg/xray/resource/resource_xray_binary_manager_builds_test.go b/pkg/xray/resource/resource_xray_binary_manager_builds_test.go index eb25860c..168f1e38 100644 --- a/pkg/xray/resource/resource_xray_binary_manager_builds_test.go +++ b/pkg/xray/resource/resource_xray_binary_manager_builds_test.go @@ -123,7 +123,6 @@ func TestAccBinaryManagerBuilds_full(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) if err := uploadBuild(t, build1Name, "1", ""); err != nil { t.Fatalf("failed to upload build: %s", err) } @@ -215,7 +214,6 @@ func TestAccBinaryManagerBuilds_project_full(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateProject(t, projectKey) if err := uploadBuild(t, build1Name, "1", projectKey); err != nil { t.Fatalf("failed to upload build: %s", err) @@ -291,9 +289,6 @@ func TestAccBinaryManagerBuilds_invalid_patterns(t *testing.T) { config := util.ExecuteTemplate("TestAccBinaryManagerBuilds_invalid_patterns", template, testData) resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(t) - }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { diff --git a/pkg/xray/resource/resource_xray_binary_manager_release_bundle_v2_test.go b/pkg/xray/resource/resource_xray_binary_manager_release_bundle_v2_test.go index 9788d69c..99368083 100644 --- a/pkg/xray/resource/resource_xray_binary_manager_release_bundle_v2_test.go +++ b/pkg/xray/resource/resource_xray_binary_manager_release_bundle_v2_test.go @@ -247,8 +247,6 @@ func TestAccBinaryManagerReleaseBundlesV2_full(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) - acctest.CreateRepos(t, repoName, "local", "", "maven") path, sha256, err := uploadTestFile(t, repoName) @@ -361,8 +359,6 @@ func TestAccBinaryManagerReleaseBundlesV2_project_full(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) - acctest.CreateRepos(t, repoName, "local", "", "maven") path, sha256, err := uploadTestFile(t, repoName) @@ -457,9 +453,6 @@ func TestAccBinaryManagerReleaseBundlesV2_invalid_patterns(t *testing.T) { config := util.ExecuteTemplate("TestAccBinaryManagerReleaseBundlesV2_invalid_patterns", template, testData) resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(t) - }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { diff --git a/pkg/xray/resource/resource_xray_binary_manager_repos_test.go b/pkg/xray/resource/resource_xray_binary_manager_repos_test.go index 34e7fc69..875bbdd4 100644 --- a/pkg/xray/resource/resource_xray_binary_manager_repos_test.go +++ b/pkg/xray/resource/resource_xray_binary_manager_repos_test.go @@ -88,7 +88,6 @@ func TestAccBinaryManagerRepos_full(t *testing.T) { updatedConfig := util.ExecuteTemplate("TestAccBinaryManagerRepos_full", updateTemplate, updatedTestData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ExternalProviders: map[string]resource.ExternalProvider{ "artifactory": { @@ -282,7 +281,6 @@ func TestAccBinaryManagerRepos_project_full(t *testing.T) { updatedConfig := util.ExecuteTemplate("TestAccBinaryManagerRepos_full", updateTemplate, updatedTestData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ExternalProviders: map[string]resource.ExternalProvider{ "artifactory": { diff --git a/pkg/xray/resource/resource_xray_custom_issue_test.go b/pkg/xray/resource/resource_xray_custom_issue_test.go index 7579eed2..cff573c6 100644 --- a/pkg/xray/resource/resource_xray_custom_issue_test.go +++ b/pkg/xray/resource/resource_xray_custom_issue_test.go @@ -213,7 +213,6 @@ func TestAccCustomIssue_full(t *testing.T) { updatedConfig := util.ExecuteTemplate("TestAccCustomIssue_full", fullTemplate, updatedTestData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckCustomIssue), Steps: []resource.TestStep{ @@ -349,7 +348,6 @@ func TestAccCustomIssue_invalid(t *testing.T) { config := util.ExecuteTemplate("TestAccCustomIssue_invalid", template, testData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { diff --git a/pkg/xray/resource/resource_xray_ignore_rule_test.go b/pkg/xray/resource/resource_xray_ignore_rule_test.go index ff43b8f7..7fff64ca 100644 --- a/pkg/xray/resource/resource_xray_ignore_rule_test.go +++ b/pkg/xray/resource/resource_xray_ignore_rule_test.go @@ -92,7 +92,6 @@ func objectiveTestCase(objective string, t *testing.T) (*testing.T, resource.Tes }) return t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckIgnoreRule), Steps: []resource.TestStep{ @@ -136,7 +135,6 @@ func TestAccIgnoreRule_operational_risk(t *testing.T) { }) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckIgnoreRule), Steps: []resource.TestStep{ @@ -180,7 +178,6 @@ func TestAccIgnoreRule_invalid_operational_risk(t *testing.T) { }) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { @@ -234,8 +231,7 @@ func TestAccIgnoreRule_scopes_policies(t *testing.T) { }) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckIgnoreRule), Steps: []resource.TestStep{ { @@ -318,8 +314,7 @@ func TestAccIgnoreRule_scopes_watches_policies(t *testing.T) { }) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckIgnoreRule), Steps: []resource.TestStep{ { @@ -384,8 +379,7 @@ func TestAccIgnoreRule_scopes_no_expiration_policies(t *testing.T) { }) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckIgnoreRule), Steps: []resource.TestStep{ { @@ -460,8 +454,7 @@ func TestAccIgnoreRule_scopes_no_expiration_watches(t *testing.T) { }) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckIgnoreRule), Steps: []resource.TestStep{ { @@ -501,7 +494,6 @@ func TestAccIgnoreRule_docker_layers(t *testing.T) { }) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckIgnoreRule), Steps: []resource.TestStep{ @@ -547,8 +539,7 @@ func TestAccIgnoreRule_invalid_docker_layers(t *testing.T) { }) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: config, @@ -591,7 +582,6 @@ func sourceTestCase(source string, t *testing.T) (*testing.T, resource.TestCase) }) return t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { @@ -638,7 +628,6 @@ func TestAccIgnoreRule_artifact(t *testing.T) { }) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckIgnoreRule), Steps: []resource.TestStep{ @@ -686,7 +675,6 @@ func TestAccIgnoreRule_invalid_artifact_path(t *testing.T) { }) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { @@ -734,7 +722,6 @@ func TestAccIgnoreRule_with_project_key(t *testing.T) { ) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ExternalProviders: map[string]resource.ExternalProvider{ "project": { @@ -788,7 +775,6 @@ func TestAccIgnoreRule_build_with_project_key(t *testing.T) { ) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ExternalProviders: map[string]resource.ExternalProvider{ "project": { diff --git a/pkg/xray/resource/resource_xray_license_policy_test.go b/pkg/xray/resource/resource_xray_license_policy_test.go index d621202c..e74d3493 100644 --- a/pkg/xray/resource/resource_xray_license_policy_test.go +++ b/pkg/xray/resource/resource_xray_license_policy_test.go @@ -82,7 +82,6 @@ func TestAccLicensePolicy_UpgradeFromSDKv2(t *testing.T) { config := util.ExecuteTemplate(fqrn, template, testData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), Steps: []resource.TestStep{ { @@ -99,7 +98,7 @@ func TestAccLicensePolicy_UpgradeFromSDKv2(t *testing.T) { }, { Config: config, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectEmptyPlan(), @@ -122,9 +121,8 @@ func TestAccLicensePolicy_badLicenseCriteria(t *testing.T) { rangeTo := 5 resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: testAccXrayLicensePolicy_badLicense(resourceName, policyName, policyDesc, ruleName, rangeTo), @@ -146,9 +144,8 @@ func TestAccLicensePolicy_badGracePeriod(t *testing.T) { testData["grace_period_days"] = "5" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, licensePolicyTemplate, testData), @@ -220,14 +217,13 @@ func TestAccLicensePolicy_withProjectKey(t *testing.T) { updatedConfig := util.ExecuteTemplate(fqrn, template, updatedTestData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), ExternalProviders: map[string]resource.ExternalProvider{ "project": { Source: "jfrog/project", }, }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: config, @@ -261,9 +257,8 @@ func TestAccLicensePolicy_createAllowedLic(t *testing.T) { testData["allowedOrBanned"] = "allowed_licenses" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, licensePolicyTemplate, testData), @@ -290,9 +285,8 @@ func TestAccLicensePolicy_createAllowedLicCustom(t *testing.T) { testData["license_1"] = "Custom-License" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, licensePolicyTemplate, testData), @@ -317,9 +311,8 @@ func TestAccLicensePolicy_createBannedLic(t *testing.T) { testData["allowedOrBanned"] = "banned_licenses" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, licensePolicyTemplate, testData), @@ -346,9 +339,8 @@ func TestAccLicensePolicy_createBannedLicCustom(t *testing.T) { testData["license_1"] = "Custom-License" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, licensePolicyTemplate, testData), @@ -374,9 +366,8 @@ func TestAccLicensePolicy_createMultiLicensePermissiveFalse(t *testing.T) { testData["allowedOrBanned"] = "banned_licenses" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, licensePolicyTemplate, testData), @@ -404,9 +395,8 @@ func TestAccLicensePolicy_createBlockFalse(t *testing.T) { testData["allowedOrBanned"] = "banned_licenses" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, licensePolicyTemplate, testData), diff --git a/pkg/xray/resource/resource_xray_operational_risk_policy_test.go b/pkg/xray/resource/resource_xray_operational_risk_policy_test.go index c3d47abf..c69112bb 100644 --- a/pkg/xray/resource/resource_xray_operational_risk_policy_test.go +++ b/pkg/xray/resource/resource_xray_operational_risk_policy_test.go @@ -69,7 +69,6 @@ func TestAccOperationalRiskPolicy_UpgradeFromSDKv2(t *testing.T) { config := util.ExecuteTemplate(fqrn, template, testData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), Steps: []resource.TestStep{ { @@ -86,7 +85,7 @@ func TestAccOperationalRiskPolicy_UpgradeFromSDKv2(t *testing.T) { }, { Config: config, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectEmptyPlan(), @@ -153,14 +152,13 @@ func TestAccOperationalRiskPolicy_withProjectKey(t *testing.T) { updatedConfig := util.ExecuteTemplate(fqrn, template, updatedTestData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), ExternalProviders: map[string]resource.ExternalProvider{ "project": { Source: "jfrog/project", }, }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: config, @@ -218,9 +216,8 @@ func TestAccOperationalRiskPolicy_minRiskCriteria(t *testing.T) { testData["op_risk_min_risk"] = "Medium" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, opertionalRiskPolicyMinRisk, testData), @@ -319,9 +316,8 @@ func TestAccOperationalRiskPolicy_customCriteria(t *testing.T) { }` resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, opertionalRiskPolicyCustomUnset, testData), @@ -402,7 +398,6 @@ func TestAccOperationalRiskPolicy_customCriteria_migration(t *testing.T) { delete(testData, "block_release_bundle_promotion") resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), Steps: []resource.TestStep{ { @@ -425,7 +420,7 @@ func TestAccOperationalRiskPolicy_customCriteria_migration(t *testing.T) { ), }, { - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Config: util.ExecuteTemplate(fqrn, opertionalRiskPolicyCustom, testData), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(fqrn, "rule.0.criteria.0.op_risk_custom.0.use_and_condition", testData["op_risk_custom_use_and_condition"]), @@ -508,9 +503,8 @@ func TestAccOperationalRiskPolicy_criteriaValidation(t *testing.T) { config := util.ExecuteTemplate(fqrn, template, testData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { diff --git a/pkg/xray/resource/resource_xray_operational_risks_report.go b/pkg/xray/resource/resource_xray_operational_risks_report.go index 22349fb7..2ddc9f31 100644 --- a/pkg/xray/resource/resource_xray_operational_risks_report.go +++ b/pkg/xray/resource/resource_xray_operational_risks_report.go @@ -1,72 +1,165 @@ package xray import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "github.com/jfrog/terraform-provider-shared/validator" + "context" + + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/jfrog/terraform-provider-shared/util" ) -func ResourceXrayOperationalRisksReport() *schema.Resource { - var operationalRisksFilterSchema = map[string]*schema.Schema{ - "component": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "Artifact's component.", +var _ resource.Resource = &OperationalRisksReportResource{} + +func NewOperationalRisksReportResource() resource.Resource { + return &OperationalRisksReportResource{ + ReportResource: ReportResource{ + TypeName: "xray_operational_risks_report", }, - "artifact": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validator.StringIsNotEmpty, - Description: "Artifact name.", + } +} + +type OperationalRisksReportResource struct { + ReportResource +} + +func (r *OperationalRisksReportResource) toFiltersAPIModel(ctx context.Context, filtersElems []attr.Value) (*FiltersAPIModel, diag.Diagnostics) { + diags := diag.Diagnostics{} + + var filters *FiltersAPIModel + if len(filtersElems) > 0 { + attrs := filtersElems[0].(types.Object).Attributes() + + var risks []string + d := attrs["risks"].(types.Set).ElementsAs(ctx, &risks, false) + if d.HasError() { + diags.Append(d...) + } + + var scanDate *StartAndEndDateAPIModel + scanDateElems := attrs["scan_date"].(types.Set).Elements() + if len(scanDateElems) > 0 { + attrs := scanDateElems[0].(types.Object).Attributes() + + scanDate = &StartAndEndDateAPIModel{ + Start: attrs["start"].(types.String).ValueString(), + End: attrs["end"].(types.String).ValueString(), + } + } + + filters = &FiltersAPIModel{ + Component: attrs["component"].(types.String).ValueString(), + Artifact: attrs["artifact"].(types.String).ValueString(), + Risks: risks, + ScanDate: scanDate, + } + } + + return filters, diags +} + +func (r OperationalRisksReportResource) toAPIModel(ctx context.Context, plan ReportResourceModel, report *ReportAPIModel) diag.Diagnostics { + return plan.toAPIModel(ctx, report, r.toFiltersAPIModel) +} + +func (r *OperationalRisksReportResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = r.TypeName +} + +var opRisksFiltersAttrs = map[string]schema.Attribute{ + "component": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "risks": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - Optional: true, - Description: "Operational risk level. Allowed values: 'None', 'Low', 'Medium', 'High'.", + Description: "Artifact's component.", + }, + "artifact": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "scan_date": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Description: "", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "start": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), - Description: "Scan start date.", + Description: "Artifact name.", + }, + "risks": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // backward compatibility with SDKv2 version + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), + setvalidator.ValueStringsAre( + stringvalidator.OneOf("None", "Low", "Medium", "High"), + ), + }, + Description: "Operational risk level. Allowed values: 'None', 'Low', 'Medium', 'High'.", + }, +} + +var opRisksFiltersBlocks = map[string]schema.Block{ + "scan_date": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "start": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + IsRFC3339Time(), }, - "end": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: validation.ToDiagFunc(validation.IsRFC3339Time), - Description: "Scan end date.", + Description: "Scan start date.", + }, + "end": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + IsRFC3339Time(), }, + Description: "Scan end date.", }, }, }, - } + Validators: []validator.Set{ + setvalidator.SizeAtMost(1), + }, + }, +} - return &schema.Resource{ - SchemaVersion: 1, - CreateContext: resourceXrayOperationalRisksReportCreate, - ReadContext: resourceXrayReportRead, - UpdateContext: resourceXrayOperationalRisksReportCreate, - DeleteContext: resourceXrayReportDelete, +func (r *OperationalRisksReportResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Version: 1, + Attributes: reportsSchemaAttrs, + Blocks: reportsBlocks(opRisksFiltersAttrs, opRisksFiltersBlocks), Description: "Creates Xray Operational Risks report. The Operational Risk report provides you with additional " + "data on OSS components that will help you gain insights into the risk level of the components in use, " + "such as; EOL, Version Age, Number of New Versions, and so on. For more information, see " + "[Components Operational Risk](https://www.jfrog.com/confluence/display/JFROG/Components+Operational+Risk)", + } +} - CustomizeDiff: reportResourceDiff, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - - Schema: getReportSchema(operationalRisksFilterSchema), +func (r *OperationalRisksReportResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return } + r.ProviderData = req.ProviderData.(util.ProviderMetadata) +} + +func (r *OperationalRisksReportResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + r.ReportResource.Create(ctx, "violations", r.toAPIModel, req, resp) +} + +func (r *OperationalRisksReportResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + r.ReportResource.Read(ctx, req, resp) +} + +func (r *OperationalRisksReportResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + r.ReportResource.Update(ctx, "violations", r.toAPIModel, req, resp) +} + +func (r *OperationalRisksReportResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + r.ReportResource.Delete(ctx, req, resp) } diff --git a/pkg/xray/resource/resource_xray_report_test.go b/pkg/xray/resource/resource_xray_report_test.go index 4ad03152..cbf2680c 100644 --- a/pkg/xray/resource/resource_xray_report_test.go +++ b/pkg/xray/resource/resource_xray_report_test.go @@ -310,6 +310,19 @@ func TestAccReport_OperationalRisks(t *testing.T) { } } +func TestAccReport_OperationalRisks_UpgradeFromSDKv2(t *testing.T) { + terraformReportName := "terraform-operational-risks-report" + terraformResourceName := "xray_operational_risks_report" + + for _, reportResource := range resourcesList { + resourceNameInReport := reportResource["name"].(string) + t.Run(resourceNameInReport, func(t *testing.T) { + resource.Test(mkFilterTestCase_UpgradeFromSDKv2(t, reportResource, opRisksFilterFields, terraformReportName, + terraformResourceName)) + }) + } +} + func TestAccReport_Violations(t *testing.T) { terraformReportName := "terraform-violations-report" terraformResourceName := "xray_violations_report" @@ -511,9 +524,8 @@ func mkFilterTestCase(t *testing.T, resourceFields map[string]interface{}, filte config := fmt.Sprintf(remoteRepoFull, resourceName, name, allFieldsHcl) return t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckReport), // how to get ID? - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: config, @@ -541,7 +553,6 @@ func mkFilterTestCase_UpgradeFromSDKv2(t *testing.T, resourceFields map[string]i config := fmt.Sprintf(remoteRepoFull, resourceName, name, allFieldsHcl) return t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", testCheckReport), // how to get ID? Steps: []resource.TestStep{ { @@ -556,14 +567,9 @@ func mkFilterTestCase_UpgradeFromSDKv2(t *testing.T, resourceFields map[string]i }, { Config: config, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, PlanOnly: true, ConfigPlanChecks: testutil.ConfigPlanChecks(""), - // ConfigPlanChecks: resource.ConfigPlanChecks{ - // PreApply: []plancheck.PlanCheck{ - // plancheck.ExpectEmptyPlan(), - // }, - // }, }, }, } @@ -584,8 +590,7 @@ func mkFilterNegativeTestCase(t *testing.T, resourceFields map[string]interface{ config := fmt.Sprintf(remoteRepoFull, resourceName, name, allFieldsHcl) return t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: config, diff --git a/pkg/xray/resource/resource_xray_repository_config_test.go b/pkg/xray/resource/resource_xray_repository_config_test.go index 92caf9bc..c673fd13 100644 --- a/pkg/xray/resource/resource_xray_repository_config_test.go +++ b/pkg/xray/resource/resource_xray_repository_config_test.go @@ -70,13 +70,8 @@ func TestAccRepositoryConfig_UpgradeFromSDKv2(t *testing.T) { Source: "jfrog/artifactory", }, }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Config: config, - // ConfigPlanChecks is a terraform-plugin-testing feature. - // If acceptance testing is still using terraform-plugin-sdk/v2, - // use `PlanOnly: true` instead. When migrating to - // terraform-plugin-testing, switch to `ConfigPlanChecks` or you - // will likely experience test failures. ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectEmptyPlan(), @@ -104,8 +99,7 @@ func TestAccRepositoryConfig_RepoNoConfig(t *testing.T) { ) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: config, @@ -150,8 +144,7 @@ func TestAccRepositoryConfig_JasDisabled(t *testing.T) { ) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ExternalProviders: map[string]resource.ExternalProvider{ "artifactory": { Source: "jfrog/artifactory", @@ -198,8 +191,7 @@ func TestAccRepositoryConfig_JasDisabled_vulnContextualAnalysis_set(t *testing.T ) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { @@ -246,8 +238,7 @@ func TestAccRepositoryConfig_JasDisabled_exposures_set(t *testing.T) { ) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ExternalProviders: map[string]resource.ExternalProvider{ "artifactory": { Source: "jfrog/artifactory", @@ -310,8 +301,7 @@ func testAccRepositoryConfigRepoConfigCreate_VulnContextualAnalysis(packageType, } resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ExternalProviders: map[string]resource.ExternalProvider{ "artifactory": { Source: "jfrog/artifactory", @@ -491,8 +481,7 @@ func testAccRepositoryConfigRepoConfigCreate(packageType, template, validVersion } resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ExternalProviders: map[string]resource.ExternalProvider{ "artifactory": { Source: "jfrog/artifactory", @@ -530,8 +519,7 @@ func TestAccRepositoryConfig_RepoConfigCreate_InvalidExposures(t *testing.T) { } resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ExternalProviders: map[string]resource.ExternalProvider{ "artifactory": { Source: "jfrog/artifactory", @@ -561,8 +549,7 @@ func TestAccRepositoryConfig_Missing_RetentionInDays(t *testing.T) { } resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ExternalProviders: map[string]resource.ExternalProvider{ "artifactory": { Source: "jfrog/artifactory", @@ -616,8 +603,7 @@ func TestAccRepositoryConfig_RepoPathsUpdate(t *testing.T) { } resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ExternalProviders: map[string]resource.ExternalProvider{ "artifactory": { Source: "jfrog/artifactory", diff --git a/pkg/xray/resource/resource_xray_security_policy_test.go b/pkg/xray/resource/resource_xray_security_policy_test.go index d7b14730..4a8fc950 100644 --- a/pkg/xray/resource/resource_xray_security_policy_test.go +++ b/pkg/xray/resource/resource_xray_security_policy_test.go @@ -86,7 +86,6 @@ func TestAccSecurityPolicy_UpgradeFromSDKv2(t *testing.T) { config := util.ExecuteTemplate(fqrn, template, testData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), Steps: []resource.TestStep{ { @@ -103,7 +102,7 @@ func TestAccSecurityPolicy_UpgradeFromSDKv2(t *testing.T) { }, { Config: config, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectEmptyPlan(), @@ -124,9 +123,8 @@ func TestAccSecurityPolicy_multipleRules(t *testing.T) { testData["rule_name_2"] = fmt.Sprintf("test-security-rule-3-%d", testutil.RandomInt()) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyTwoRules, testData), @@ -189,9 +187,8 @@ func TestAccSecurityPolicy_unknownMinSeveritySecurityPolicy_beforeVersion3602(t } resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { SkipFunc: onOrAfterVersion3602, @@ -212,9 +209,8 @@ func TestAccSecurityPolicy_badTypeInSecurityPolicy(t *testing.T) { resourceName := "policy-" + strconv.Itoa(testutil.RandomInt()) fqrn := "xray_security_policy." + resourceName resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: testAccXraySecurityPolicy_badSecurityType(policyName, policyDesc, ruleName, rangeTo), @@ -234,9 +230,8 @@ func TestAccSecurityPolicy_badSecurityCriteria(t *testing.T) { resourceName := "policy-" + strconv.Itoa(testutil.RandomInt()) fqrn := "xray_security_policy." + resourceName resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: testAccXraySecurityPolicy_badSecurity(policyName, policyDesc, ruleName, allowedLicense), @@ -259,9 +254,8 @@ func TestAccSecurityPolicy_badGracePeriod(t *testing.T) { testData["grace_period_days"] = "5" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyCVSS, testData), @@ -331,14 +325,13 @@ func TestAccSecurityPolicy_withProjectKey(t *testing.T) { updatedConfig := util.ExecuteTemplate(fqrn, template, updatedTestData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), ExternalProviders: map[string]resource.ExternalProvider{ "project": { Source: "jfrog/project", }, }, - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: config, @@ -371,9 +364,8 @@ func TestAccSecurityPolicy_createBlockDownloadTrueCVSS(t *testing.T) { testData["rule_name"] = fmt.Sprintf("test-security-rule-4-%d", testutil.RandomInt()) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyCVSS, testData), @@ -401,9 +393,8 @@ func TestAccSecurityPolicy_createBlockDownloadFalseCVSS(t *testing.T) { testData["block_active"] = "false" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyCVSS, testData), @@ -428,9 +419,8 @@ func TestAccSecurityPolicy_createBlockDownloadTrueMinSeverity(t *testing.T) { testData["rule_name"] = fmt.Sprintf("test-security-rule-6-%d", testutil.RandomInt()) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyMinSeverity, testData), @@ -457,9 +447,8 @@ func TestAccSecurityPolicy_createFixVersionDepMinSeverity(t *testing.T) { testData["fix_version_dependant"] = "true" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyFixVersionDep, testData), @@ -487,9 +476,8 @@ func TestAccSecurityPolicy_createMaliciousPackage(t *testing.T) { testData["fix_version_dependant"] = "false" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyMaliciousPkgFixVersionDep, testData), @@ -516,9 +504,8 @@ func TestAccSecurityPolicy_createMaliciousPackageFail(t *testing.T) { testData["fix_version_dependant"] = "true" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyMaliciousPkgFixVersionDep, testData), @@ -539,9 +526,8 @@ func TestAccSecurityPolicy_createMaliciousPackageCvssMinSeverityFail(t *testing. testData["min_severity"] = "High" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyCVSSMinSeverityMaliciousPkg, testData), @@ -562,9 +548,8 @@ func TestAccSecurityPolicy_createCvssMinSeverityFail(t *testing.T) { testData["min_severity"] = "High" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyCVSSMinSeverityMaliciousPkg, testData), @@ -586,9 +571,8 @@ func TestAccSecurityPolicy_createBlockDownloadFalseMinSeverity(t *testing.T) { testData["block_active"] = "false" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyMinSeverity, testData), @@ -615,9 +599,8 @@ func TestAccSecurityPolicy_createCVSSFloat(t *testing.T) { testData["cvss_to"] = "5.3" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyCVSS, testData), @@ -645,9 +628,8 @@ func TestAccSecurityPolicy_blockMismatchCVSS(t *testing.T) { testData["block_active"] = "false" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyCVSS, testData), @@ -671,9 +653,8 @@ func TestAccSecurityPolicy_noActions(t *testing.T) { testData["CVE_3"] = "XRAY-1234" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyNoActions, testData), @@ -697,9 +678,8 @@ func TestAccSecurityPolicy_vulnerabilityIds(t *testing.T) { testData["CVE_3"] = "XRAY-1234" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyVulnIds, testData), @@ -729,9 +709,8 @@ func TestAccSecurityPolicy_vulnerabilityIdsIncorrectCVEFails(t *testing.T) { testData["CVE_3"] = "XRAY-1234" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyVulnIds, testData), @@ -769,9 +748,8 @@ func TestAccSecurityPolicy_conflictingAttributesFail(t *testing.T) { testData["conflicting_attribute"] = conflictingAttribute resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyVulnIdsConflict, testData), @@ -805,9 +783,8 @@ func TestAccSecurityPolicy_vulnerabilityIdsLimitFail(t *testing.T) { testData["CVEs"] = CVEString resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyVulnIdsLimit, testData), @@ -831,9 +808,8 @@ func TestAccSecurityPolicy_exposures(t *testing.T) { testData["exposures_iac"] = "true" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyExposures, testData), @@ -865,9 +841,8 @@ func TestAccSecurityPolicy_Packages(t *testing.T) { testData["package_version_3"] = "[4.0.0]" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyPackages, testData), @@ -900,9 +875,8 @@ func TestAccSecurityPolicy_PackagesIncorrectVersionRangeFails(t *testing.T) { testData["package_version_3"] = "[3.2.1,]" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyPackages, testData), @@ -928,9 +902,8 @@ func TestAccSecurityPolicy_createPackagesFail(t *testing.T) { testData["fix_version_dependant"] = "true" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "", acctest.CheckPolicy), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, securityPolicyPackagesFixVersionDep, testData), diff --git a/pkg/xray/resource/resource_xray_settings_test.go b/pkg/xray/resource/resource_xray_settings_test.go index e8b7c987..e8f7b0df 100644 --- a/pkg/xray/resource/resource_xray_settings_test.go +++ b/pkg/xray/resource/resource_xray_settings_test.go @@ -91,7 +91,6 @@ func TestAccSettings_basic(t *testing.T) { config := util.ExecuteTemplate(fqrn, tmpl, testData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { @@ -119,7 +118,6 @@ func TestAccSettings_DbSyncTime(t *testing.T) { time := "18:45" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { @@ -135,7 +133,6 @@ func TestAccSettings_DbSyncTime_Invalid(t *testing.T) { var invalidTime = []string{"24:00", "24:55", "", "12:0", "string", "12pm", "9:00"} for _, time := range invalidTime { resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { diff --git a/pkg/xray/resource/resource_xray_watch_test.go b/pkg/xray/resource/resource_xray_watch_test.go index ca4acde8..e2dc47ce 100644 --- a/pkg/xray/resource/resource_xray_watch_test.go +++ b/pkg/xray/resource/resource_xray_watch_test.go @@ -44,7 +44,6 @@ func TestAccWatch_UpgradeFromSDKv2(t *testing.T) { config := util.ExecuteTemplate(fqrn, allReposSinglePolicyWatchTemplate, testData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", testCheckWatch), Steps: []resource.TestStep{ { @@ -58,7 +57,7 @@ func TestAccWatch_UpgradeFromSDKv2(t *testing.T) { Check: verifyXrayWatch(fqrn, testData), }, { - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Config: config, ConfigPlanChecks: testutil.ConfigPlanChecks(""), }, @@ -75,13 +74,12 @@ func TestAccWatch_allReposSinglePolicy(t *testing.T) { testData["policy_name_0"] = fmt.Sprintf("xray-policy-%d", testutil.RandomInt()) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", func(id string, request *resty.Request) (*resty.Response, error) { acctest.CheckPolicyDeleted(testData["policy_name_0"], t, request) resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, allReposSinglePolicyWatchTemplate, testData), @@ -109,13 +107,12 @@ func TestAccWatch_allReposPathAntFilter(t *testing.T) { testData["include_patterns0"] = "**/*.js" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", func(id string, request *resty.Request) (*resty.Response, error) { acctest.CheckPolicyDeleted(testData["policy_name_0"], t, request) resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, allReposPathAntFilterWatchTemplate, testData), @@ -143,13 +140,12 @@ func TestAccWatch_allReposKvFilter(t *testing.T) { testData["kv_filter_value0"] = "test-property-value" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", func(id string, request *resty.Request) (*resty.Response, error) { acctest.CheckPolicyDeleted(testData["policy_name_0"], t, request) resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, allReposKvFilterWatchTemplate, testData), @@ -231,7 +227,6 @@ func TestAccWatch_allReposWithProjectKey(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateProject(t, projectKey) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", func(id string, request *resty.Request) (*resty.Response, error) { @@ -239,7 +234,7 @@ func TestAccWatch_allReposWithProjectKey(t *testing.T) { resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: config, @@ -274,7 +269,6 @@ func TestAccWatch_allReposMultiplePolicies(t *testing.T) { testData["policy_name_2"] = fmt.Sprintf("xray-policy-3%d", testutil.RandomInt()) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", func(id string, request *resty.Request) (*resty.Response, error) { acctest.CheckPolicyDeleted(testData["policy_name_0"], t, request) acctest.CheckPolicyDeleted(testData["policy_name_1"], t, request) @@ -283,7 +277,7 @@ func TestAccWatch_allReposMultiplePolicies(t *testing.T) { return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, allReposMultiplePoliciesWatchTemplate, testData), @@ -335,7 +329,6 @@ func makeSingleRepositoryTestCase(repoType string, t *testing.T) (*testing.T, re return t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateRepos(t, testData["repo0"], repoType, "", "") }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", func(id string, request *resty.Request) (*resty.Response, error) { @@ -345,7 +338,7 @@ func makeSingleRepositoryTestCase(repoType string, t *testing.T) (*testing.T, re return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, singleRepositoryWatchTemplate, testData), @@ -442,7 +435,6 @@ func TestAccWatch_singleRepositoryWithProjectKey(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateProject(t, projectKey) acctest.CreateRepos(t, repoKey, "local", projectKey, "") }, @@ -453,7 +445,7 @@ func TestAccWatch_singleRepositoryWithProjectKey(t *testing.T) { return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: config, @@ -490,7 +482,6 @@ func TestAccWatch_singleRepoMimeTypeFilter(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateRepos(t, testData["repo0"], repoType, "", "") }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", func(id string, request *resty.Request) (*resty.Response, error) { @@ -499,7 +490,7 @@ func TestAccWatch_singleRepoMimeTypeFilter(t *testing.T) { resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, singleRepositoryWatchTemplate, testData), @@ -535,7 +526,6 @@ func TestAccWatch_singleRepoKvFilter(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateRepos(t, testData["repo0"], repoType, "", "") }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", func(id string, request *resty.Request) (*resty.Response, error) { @@ -543,7 +533,7 @@ func TestAccWatch_singleRepoKvFilter(t *testing.T) { acctest.CheckPolicyDeleted(testData["policy_name_0"], t, request) return testCheckWatch(id, request) }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, kvFilters, testData), @@ -577,7 +567,6 @@ func TestAccWatch_repositoryMissingRepoType(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateRepos(t, testData["repo0"], "local", "", "") }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", func(id string, request *resty.Request) (*resty.Response, error) { @@ -587,7 +576,7 @@ func TestAccWatch_repositoryMissingRepoType(t *testing.T) { return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, singleRepositoryInvalidWatchTemplate, testData), @@ -611,7 +600,6 @@ func TestAccWatch_multipleRepositories(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateRepos(t, testData["repo0"], "local", "", "") acctest.CreateRepos(t, testData["repo1"], "local", "", "") }, @@ -622,7 +610,7 @@ func TestAccWatch_multipleRepositories(t *testing.T) { resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, multipleRepositoriesWatchTemplate, testData), @@ -658,7 +646,6 @@ func TestAccWatch_multipleRepositoriesPathAntPatterns(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateRepos(t, testData["repo0"], "local", "", "") acctest.CreateRepos(t, testData["repo1"], "local", "", "") acctest.CreateRepos(t, testData["repo2"], "local", "", "") @@ -671,7 +658,7 @@ func TestAccWatch_multipleRepositoriesPathAntPatterns(t *testing.T) { resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, pathAntPatterns, testData), @@ -715,7 +702,6 @@ func TestAccWatch_PathAntPatternsError(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateRepos(t, testData["repo0"], "local", "", "") acctest.CreateRepos(t, testData["repo1"], "local", "", "") }, @@ -726,7 +712,7 @@ func TestAccWatch_PathAntPatternsError(t *testing.T) { resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, pathAntPatterns, testData), @@ -755,7 +741,6 @@ func TestAccWatch_multipleRepositoriesKvFilter(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateRepos(t, testData["repo0"], "local", "", "") acctest.CreateRepos(t, testData["repo1"], "local", "", "") }, @@ -766,7 +751,7 @@ func TestAccWatch_multipleRepositoriesKvFilter(t *testing.T) { resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, multipleRepositoriesKvFilter, testData), @@ -814,7 +799,6 @@ func TestAccWatch_KvFilterError(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateRepos(t, testData["repo0"], "local", "", "") }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", func(id string, request *resty.Request) (*resty.Response, error) { @@ -823,7 +807,7 @@ func TestAccWatch_KvFilterError(t *testing.T) { resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, kvFilters, testData), @@ -847,11 +831,10 @@ func TestAccWatch_build(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateBuilds(t, builds, "") }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", testCheckWatch), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, buildWatchTemplate, testData), @@ -927,7 +910,6 @@ func TestAccWatch_buildWithProjectKey(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateProject(t, projectKey) acctest.CreateBuilds(t, []string{testData["build_name0"]}, projectKey) }, @@ -936,7 +918,7 @@ func TestAccWatch_buildWithProjectKey(t *testing.T) { resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: config, @@ -1026,7 +1008,6 @@ func TestAccWatch_allBuildsWithProjectKey(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateProject(t, projectKey) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", func(id string, request *resty.Request) (*resty.Response, error) { @@ -1034,7 +1015,7 @@ func TestAccWatch_allBuildsWithProjectKey(t *testing.T) { resp, err := testCheckWatch(id, request) return resp, err }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: config, @@ -1072,11 +1053,10 @@ func TestAccWatch_multipleBuilds(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateBuilds(t, builds, "") }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", testCheckWatch), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, multipleBuildsWatchTemplate, testData), @@ -1103,11 +1083,8 @@ func TestAccWatch_allBuilds(t *testing.T) { testData["watch_type"] = "all-builds" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(t) - }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", testCheckWatch), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, allBuildsWatchTemplate, testData), @@ -1141,11 +1118,8 @@ func TestAccWatch_invalidBuildFilter(t *testing.T) { testData["policy_name_0"] = fmt.Sprintf("xray-policy-%d", testutil.RandomInt()) resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(t) - }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", testCheckWatch), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, invalidBuildsWatchFilterTemplate, testData), @@ -1165,11 +1139,8 @@ func TestAccWatch_allProjects(t *testing.T) { testData["watch_type"] = "all-projects" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(t) - }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", testCheckWatch), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, allProjectsWatchTemplate, testData), @@ -1206,7 +1177,6 @@ func TestAccWatch_singleProject(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - acctest.PreCheck(t) acctest.CreateProject(t, testData["project_key_0"]) acctest.CreateProject(t, testData["project_key_1"]) }, @@ -1218,7 +1188,7 @@ func TestAccWatch_singleProject(t *testing.T) { return testCheckWatch(id, request) }), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, singleProjectWatchTemplate, testData), @@ -1245,11 +1215,8 @@ func TestAccWatch_invalidProjectFilter(t *testing.T) { testData["watch_type"] = "project" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(t) - }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", testCheckWatch), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { @@ -1278,11 +1245,8 @@ func allReleaseBundleTestCase(watchType string, t *testing.T) (*testing.T, resou testData["watch_type"] = watchType return t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(t) - }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", testCheckWatch), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, allReleaseBundlesWatchTemplate, testData), @@ -1317,9 +1281,8 @@ func TestAccWatch_singleReleaseBundle(t *testing.T) { testData["release_bundle_name"] = fmt.Sprintf("test-release-bundle-%d", testutil.RandomInt()) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", testCheckWatch), - ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { Config: util.ExecuteTemplate(fqrn, singleReleaseBundleWatchTemplate, testData), diff --git a/pkg/xray/resource/resource_xray_webhook_test.go b/pkg/xray/resource/resource_xray_webhook_test.go index fd4b5c01..762b6984 100644 --- a/pkg/xray/resource/resource_xray_webhook_test.go +++ b/pkg/xray/resource/resource_xray_webhook_test.go @@ -128,7 +128,6 @@ func TestAccWebhook_full(t *testing.T) { updatedConfig := util.ExecuteTemplate("TestAccWebhook_full", updateTemplate, updatedTestData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, CheckDestroy: acctest.VerifyDeleted(fqrn, "name", testCheckWebhook), Steps: []resource.TestStep{ @@ -189,7 +188,6 @@ func TestAccWebhook_invalid_name(t *testing.T) { config := util.ExecuteTemplate("TestAccWebhook_invalid_name", template, testData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { @@ -216,7 +214,6 @@ func TestAccWebhook_invalid_url(t *testing.T) { config := util.ExecuteTemplate("TestAccWebhook_invalid_name", template, testData) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { diff --git a/pkg/xray/resource/resource_xray_workers_count_test.go b/pkg/xray/resource/resource_xray_workers_count_test.go index 2ee1beda..ca33a8c7 100644 --- a/pkg/xray/resource/resource_xray_workers_count_test.go +++ b/pkg/xray/resource/resource_xray_workers_count_test.go @@ -76,7 +76,6 @@ func TestAccWorkersCount_full(t *testing.T) { updatedConfig := util.ExecuteTemplate("TestAccWorkersCount_full", temp, updatedParams) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, Steps: []resource.TestStep{ { diff --git a/pkg/xray/resource/util.go b/pkg/xray/resource/util.go index eaa19a01..3ac0b329 100644 --- a/pkg/xray/resource/util.go +++ b/pkg/xray/resource/util.go @@ -10,8 +10,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" - sdkv2_schema "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - sdkv2_validator "github.com/jfrog/terraform-provider-shared/validator" validatorfw_string "github.com/jfrog/terraform-provider-shared/validator/fw/string" ) @@ -28,20 +26,6 @@ func getRestyRequest(client *resty.Client, projectKey string) (*resty.Request, e return req, nil } -var getProjectKeySchema = func(isForceNew bool, additionalDescription string) map[string]*sdkv2_schema.Schema { - description := fmt.Sprintf("Project key for assigning this resource to. Must be 2 - 10 lowercase alphanumeric and hyphen characters. %s", additionalDescription) - - return map[string]*sdkv2_schema.Schema{ - "project_key": { - Type: sdkv2_schema.TypeString, - Optional: true, - ForceNew: isForceNew, - ValidateDiagFunc: sdkv2_validator.ProjectKey, - Description: description, - }, - } -} - var projectKeySchemaAttrs = func(isForceNew bool, additionalDescription string) map[string]schema.Attribute { description := fmt.Sprintf("Project key for assigning this resource to. Must be 2 - 10 lowercase alphanumeric and hyphen characters. %s", additionalDescription) planModifiers := []planmodifier.String{} From f606dcfcb6931bbcac8c23355ebb7bb28f6bd014 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 13 Sep 2024 09:15:38 -0700 Subject: [PATCH 09/11] Update CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d50cb6ff..2fa9a629 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ -## 2.11.1 (September 11, 2024). Tested on Artifactory 7.90.9 and Xray 3.104.8 with Terraform 1.9.5 and OpenTofu 1.8.2 +## 2.11.1 (September 16, 2024). Tested on Artifactory 7.90.9 and Xray 3.104.8 with Terraform 1.9.5 and OpenTofu 1.8.2 IMPROVEMENTS: * resource/xray_license_policy, resource/xray_operational_risk_policy, resource/xray_security_policy: Migrate from SDKv2 to Plugin Framework. PR: [#239](https://github.com/jfrog/terraform-provider-xray/pull/239) +* resource/xray_licenses_report, resource/xray_operational_risks_report, resource/xray_violations_report, resource/xray_vulnerabilities_report: Migrate from SDKv2 to Plugin Framework. PR: [#240](https://github.com/jfrog/terraform-provider-xray/pull/240) ## 2.11.0 (August 27, 2024). Tested on Artifactory 7.90.8 and Xray 3.102.5 with Terraform 1.9.5 and OpenTofu 1.8.1 From bf8ae8ced87fa81b9635b1fc6ee421578f1b7b02 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Mon, 16 Sep 2024 14:38:20 -0700 Subject: [PATCH 10/11] Update provider version --- pkg/xray/provider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/xray/provider.go b/pkg/xray/provider.go index c0043fdd..270a137c 100644 --- a/pkg/xray/provider.go +++ b/pkg/xray/provider.go @@ -18,7 +18,7 @@ import ( xray_resource "github.com/jfrog/terraform-provider-xray/pkg/xray/resource" ) -var Version = "0.0.1" +var Version = "2.11.1" var productId = "terraform-provider-xray/" + Version // Ensure the implementation satisfies the provider.Provider interface. From e28176fe46d1a19b81d468f4b077c4e871220fd8 Mon Sep 17 00:00:00 2001 From: JFrog CI Date: Mon, 16 Sep 2024 22:10:16 +0000 Subject: [PATCH 11/11] JFrog Pipelines - Add Artifactory version to CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 792bbf45..bfb06baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.11.1 (September 16, 2024) +## 2.11.1 (September 16, 2024). Tested on Artifactory 7.90.10 and Xray 3.104.11 with Terraform 1.9.5 and OpenTofu 1.8.2 IMPROVEMENTS: