diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cf1a1aa..aee740a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,21 @@ -## 3.1.6 (Feb 04,2026). Tested on JFrog Platform 11.4.2 (Artifactory 7.133.6, Xray 3.137.16, Catalog 1.31.3) with Terraform 1.14.4 and OpenTofu 1.11.4 +## 3.2.0 (February 24, 2026) -IMPROVEMENTS: +FEATURES: -* resource/xray_repository_config: Add support for gradle,go,ruby,alpine,deb,rpm package types for exposure analysis. PR: [#378](https://github.com/jfrog/terraform-provider-xray/pull/378) +* **New Data Source:** `xray_security_policy` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_artifacts_scan` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_binary_manager_builds` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_binary_manager_release_bundle_v2` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_binary_manager_repos` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_curation_policy` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_custom_curation_condition` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_custom_issue` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_ignore_rule` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_repository_config` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_settings` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_watch` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_webhook` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) +* **New Data Source:** `xray_workers_count` Issue: [#330](https://github.com/jfrog/terraform-provider-xray/issues/330) ## 3.1.5 (Dec 11,2025). Tested on JFrog Platform 11.3.3 (Artifactory 7.125.8, Xray 3.131.25, Catalog 1.28.3) with Terraform 1.14.1 and OpenTofu 1.11.1 diff --git a/pkg/xray/resource/resource_xray_binary_manager_release_bundle_v2.go b/pkg/xray/resource/resource_xray_binary_manager_release_bundle_v2.go index 7747ce62..a5dc5332 100644 --- a/pkg/xray/resource/resource_xray_binary_manager_release_bundle_v2.go +++ b/pkg/xray/resource/resource_xray_binary_manager_release_bundle_v2.go @@ -67,6 +67,22 @@ func stripReleaseBundleV2Prefix(name string) string { return name } +// deduplicateStrings removes duplicate strings from a slice while preserving order. +// This is needed because the same release bundle name can exist in different projects, +// and after stripping the "[repo-type]/" prefix they become duplicates which would +// cause errors when creating a Terraform Set (sets require unique elements). +func deduplicateStrings(input []string) []string { + seen := make(map[string]struct{}, len(input)) + result := make([]string, 0, len(input)) + for _, s := range input { + if _, ok := seen[s]; !ok { + seen[s] = struct{}{} + result = append(result, s) + } + } + return result +} + func (m *BinaryManagerReleaseBundlesV2ResourceModel) fromAPIModel(ctx context.Context, apiModel BinaryManagerReleaseBundlesV2APIModel, preserveIndexed bool) (ds diag.Diagnostics) { m.ID = types.StringValue(apiModel.BinManagerID) @@ -74,24 +90,26 @@ func (m *BinaryManagerReleaseBundlesV2ResourceModel) fromAPIModel(ctx context.Co // This avoids "inconsistent result after apply" errors when API returns // different ordering or timing-delayed results if !preserveIndexed { - // Strip the "[repo-type]/" prefix from each release bundle name + // Strip the "[repo-type]/" prefix from each release bundle name and deduplicate. + // Deduplication is needed because the same release bundle name can exist in + // different projects, and after prefix stripping they become duplicates. strippedIndexed := make([]string, len(apiModel.IndexedReleaseBundlesV2)) for i, name := range apiModel.IndexedReleaseBundlesV2 { strippedIndexed[i] = stripReleaseBundleV2Prefix(name) } - indexedReleaseBundlesV2, d := types.SetValueFrom(ctx, types.StringType, strippedIndexed) + indexedReleaseBundlesV2, d := types.SetValueFrom(ctx, types.StringType, deduplicateStrings(strippedIndexed)) if d != nil { ds.Append(d...) } m.IndexedReleaseBundlesV2 = indexedReleaseBundlesV2 } - // Strip the "[repo-type]/" prefix from each non-indexed release bundle name + // Strip the "[repo-type]/" prefix from each non-indexed release bundle name and deduplicate. strippedNonIndexed := make([]string, len(apiModel.NonIndexedReleaseBundlesV2)) for i, name := range apiModel.NonIndexedReleaseBundlesV2 { strippedNonIndexed[i] = stripReleaseBundleV2Prefix(name) } - nonIndexedBuilds, d := types.SetValueFrom(ctx, types.StringType, strippedNonIndexed) + nonIndexedBuilds, d := types.SetValueFrom(ctx, types.StringType, deduplicateStrings(strippedNonIndexed)) if d != nil { ds.Append(d...) } diff --git a/pkg/xray/resource/resource_xray_binary_manager_repos.go b/pkg/xray/resource/resource_xray_binary_manager_repos.go index 17844658..c8c85ca5 100644 --- a/pkg/xray/resource/resource_xray_binary_manager_repos.go +++ b/pkg/xray/resource/resource_xray_binary_manager_repos.go @@ -85,8 +85,6 @@ var repoSetResourceModelAttributeTypes types.ObjectType = types.ObjectType{ func (m *BinaryManagerReposResourceModel) fromAPIModel(apiModel BinaryManagerReposAPIModel) diag.Diagnostics { diags := diag.Diagnostics{} - m.ID = types.StringValue(apiModel.BinManagerID) - indexedRepos, ds := m.fromRepoAPIModel(apiModel.IndexedRepos) if ds != nil { diags = append(diags, ds...) @@ -299,10 +297,16 @@ func (r *BinaryManagerReposResource) Create(ctx context.Context, req resource.Cr return } - resp.Diagnostics.Append(plan.fromAPIModel(repos)...) - if resp.Diagnostics.HasError() { + // Only update non_indexed_repos from API response. + // Keep indexed_repos from plan to avoid inconsistency between + // planned values and API response (e.g. API may return different + // pkg_type casing or silently drop repos that don't exist). + nonIndexedRepos, ds := plan.fromRepoAPIModel(repos.NonIndexedRepos) + if ds.HasError() { + resp.Diagnostics.Append(ds...) return } + plan.NonIndexedRepos = nonIndexedRepos // Save data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) @@ -408,10 +412,16 @@ func (r *BinaryManagerReposResource) Update(ctx context.Context, req resource.Up return } - resp.Diagnostics.Append(plan.fromAPIModel(repos)...) - if resp.Diagnostics.HasError() { + // Only update non_indexed_repos from API response. + // Keep indexed_repos from plan to avoid inconsistency between + // planned values and API response (e.g. API may return different + // pkg_type casing or silently drop repos that don't exist). + nonIndexedRepos, ds := plan.fromRepoAPIModel(repos.NonIndexedRepos) + if ds.HasError() { + resp.Diagnostics.Append(ds...) return } + plan.NonIndexedRepos = nonIndexedRepos // Save data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) diff --git a/pkg/xray/resource/resource_xray_repository_config.go b/pkg/xray/resource/resource_xray_repository_config.go index e8596f4b..a17e5c3c 100644 --- a/pkg/xray/resource/resource_xray_repository_config.go +++ b/pkg/xray/resource/resource_xray_repository_config.go @@ -79,7 +79,7 @@ func (m RepoConfigResourceModel) toAPIModel(_ context.Context, xrayVersion, pack "secrets_scan": scannerCategoryAttrs["secrets"].(types.Bool).ValueBool(), "applications_scan": scannerCategoryAttrs["applications"].(types.Bool).ValueBool(), } - case "maven", "nuget", "generic", "gradle", "gems", "go", "alpine", "debian", "rpm": + case "maven", "nuget", "generic": exp.ScannersCategory = map[string]bool{ "secrets_scan": scannerCategoryAttrs["secrets"].(types.Bool).ValueBool(), } @@ -237,14 +237,6 @@ var exposuresPackageTypes = func(xrayVersion string) []string { packageTypes = append(packageTypes, "nuget") } - if ok, err := util.CheckVersion(xrayVersion, "3.108.0"); err == nil && ok { - packageTypes = append(packageTypes, "gradle") - } - - if ok, err := util.CheckVersion(xrayVersion, "3.109.0"); err == nil && ok { - packageTypes = append(packageTypes, "go", "gems", "alpine", "debian", "rpm") - } - return packageTypes } @@ -296,7 +288,7 @@ func (m *RepoConfigResourceModel) fromAPIModel(_ context.Context, xrayVersion, p scannersCategoryAttrValues["services"] = types.BoolValue(apiModel.RepoConfig.Exposures.ScannersCategory["services_scan"]) scannersCategoryAttrValues["secrets"] = types.BoolValue(apiModel.RepoConfig.Exposures.ScannersCategory["secrets_scan"]) scannersCategoryAttrValues["applications"] = types.BoolValue(apiModel.RepoConfig.Exposures.ScannersCategory["applications_scan"]) - case "maven", "nuget", "generic", "gradle", "gems", "go", "alpine", "debian", "rpm": + case "maven", "nuget", "generic": scannersCategoryAttrValues["secrets"] = types.BoolValue(apiModel.RepoConfig.Exposures.ScannersCategory["secrets_scan"]) case "npm", "pypi": scannersCategoryAttrValues["secrets"] = types.BoolValue(apiModel.RepoConfig.Exposures.ScannersCategory["secrets_scan"]) diff --git a/pkg/xray/resource/resource_xray_watch.go b/pkg/xray/resource/resource_xray_watch.go index 39a64015..6f2f9db6 100644 --- a/pkg/xray/resource/resource_xray_watch.go +++ b/pkg/xray/resource/resource_xray_watch.go @@ -370,7 +370,7 @@ var packFilterMap = map[string]map[string]interface{}{ }, } -var allTypes = []string{"all-repos", "all-builds", "all-projects","all-releaseBundles", "all-releaseBundlesV2"} +var allTypes = []string{"all-repos", "all-builds", "all-projects"} func (m *WatchResourceModel) fromAPIModel(ctx context.Context, apiModel WatchAPIModel) diag.Diagnostics { diags := diag.Diagnostics{}