Repository: jfrog/terraform-provider-xray (go)

Issue:
Patterns do not work with release bundles V2 indexing configuration
**Describe the bug**
Found while testing the feature https://github.com/jfrog/terraform-provider-xray/issues/220 https://github.com/jfrog/terraform-provider-xray/pull/222

Adding all release bundles (`*/**`) to the indexing configuration does not work.
For builds (https://registry.terraform.io/providers/jfrog/xray/latest/docs/resources/binary_manager_builds) it does.
Error:
```
   │ Error: Provider produced inconsistent result after apply
   │ 
   │ When applying changes to
   │ xray_binary_manager_release_bundles_v2.xray_myproj_indexed_resources_release_bundles_v2,
   │ provider "provider[\"registry.terraform.io/jfrog/xray\"]" produced an
   │ unexpected new value: .indexed_release_bundle_v2: planned set element
   │ cty.StringVal("*/**") does not correlate with any element in actual.
   │ 
   │ This is a bug in the provider, which should be reported in the provider's
   │ own issue tracker.
```

![image](https://github.com/user-attachments/assets/39c8fd80-91e2-49e1-a96f-9138690d0274)


**Requirements for and issue**
- [x] A fully functioning terraform snippet that can be copy&pasted (no outside files or ENV vars unless that's part of the issue)
```
 "xray_binary_manager_builds": {
  "xray_myproj_indexed_resources_builds": {
	"//": {
	  "metadata": {
		"path": "myproj/xray_myproj_indexed_resources_builds",
		"uniqueId": "xray_myproj_indexed_resources_builds"
	  }
	},
	"id": "default",
	"indexed_builds": [
	  "*/**"
	],
	"project_key": "myproj"
  }
},
"xray_binary_manager_release_bundles_v2": {
  "xray_myproj_indexed_resources_release_bundles_v2": {
	"//": {
	  "metadata": {
		"path": "myproj/xray_myproj_indexed_resources_release_bundles_v2",
		"uniqueId": "xray_myproj_indexed_resources_release_bundles_v2"
	  }
	},
	"id": "default",
	"indexed_release_bundle_v2": [
	  "*/**"
	],
	"project_key": "myproj"
  }
}
```

- [x] Your version of Artifactory and Xray (you can `curl` Artifactory version at `$host/artifactory/api/system/version` and Xray version at 
`$host/xray/api/v1/system/version`
```
{"version" : "7.92.1", "revision" : "79201900"}
{"xray_version":"3.101.5","xray_revision":"17f5a9d"}
```

- [x] Your version of terraform
```
Terraform v1.9.3
on linux_amd64

cdktf --version
0.20.8
```
**Expected behavior**
Pattern support for release bundles V2 indexing configuration must be possible

**Additional context**
Import did not recognize patterns as well - it imported an existing release bundle which was not selected


Pull request description:
Add attribute validation to Bulds and Release Bundle V2 indexed resources
Close #226

Also update docs to reflect the limitation

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ee2b738e..ab2dbaf1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 2.9.1 (August 7 30, 2024). Tested on Artifactory 7.90.6 and Xray 3.101.5 with Terraform 1.9.4 and OpenTofu 1.8.1
+
+IMPROVEMENTS:
+
+* resource/xray_binary_manager_release_bundles_v2: Add `indexed_release_bundle_v2` attribute validation to prevent the use of Ant-style pattern.
+* resource/xray_binary_manager_build: Add `indexed_builds` attribute validation to prevent the use of Ant-style pattern.
+
+PR: [#227](https://github.com/jfrog/terraform-provider-xray/pull/227)
+
+Issue: [#226](https://github.com/jfrog/terraform-provider-xray/issues/226)
+
 ## 2.9.0 (July 30, 2024). Tested on Artifactory 7.90.5 and Xray 3.101.5 with Terraform 1.9.3 and OpenTofu 1.8.0
 
 FEATURES:
diff --git a/docs/resources/binary_manager_builds.md b/docs/resources/binary_manager_builds.md
index 5aab1590..627954d7 100644
--- a/docs/resources/binary_manager_builds.md
+++ b/docs/resources/binary_manager_builds.md
@@ -27,6 +27,8 @@ resource "xray_binary_manager_builds" "my-indexed-builds" {
 - `id` (String) ID of the binary manager, e.g. 'default'
 - `indexed_builds` (Set of String) Builds to be indexed.
 
+~>Currently does not support Ant-style path patterns (`*`, `**`, or `?`) due to API limitation.
+
 ### Optional
 
 - `project_key` (String) For Xray version 3.21.2 and above with Projects, a Project Admin with Index Resources privilege can maintain the indexed and not indexed repositories in a given binary manger using this resource in the scope of a project.
diff --git a/docs/resources/binary_manager_release_bundles_v2.md b/docs/resources/binary_manager_release_bundles_v2.md
index 2db24462..5d97897a 100644
--- a/docs/resources/binary_manager_release_bundles_v2.md
+++ b/docs/resources/binary_manager_release_bundles_v2.md
@@ -27,6 +27,8 @@ resource "xray_binary_manager_release_bundles_v2" "my-indexed-release-bundles" {
 - `id` (String) ID of the binary manager, e.g. 'default'
 - `indexed_release_bundle_v2` (Set of String) Release Bundles V2 to be indexed.
 
+~>Currently does not support Ant-style path patterns (`*`, `**`, or `?`) due to API limitation.
+
 ### Optional
 
 - `project_key` (String) For Xray version 3.21.2 and above with Projects, a Project Admin with Index Resources privilege can maintain the indexed and not indexed repositories in a given binary manger using this resource in the scope of a project.
diff --git a/docs/resources/custom_issue.md b/docs/resources/custom_issue.md
index 99bad675..7539318c 100644
--- a/docs/resources/custom_issue.md
+++ b/docs/resources/custom_issue.md
@@ -49,17 +49,20 @@ resource "xray_custom_issue" "my-issue-1" {
 
 ### Required
 
-- `component` (Block Set, Min: 1) Component of custom issue (see [below for nested schema](#nestedblock--component))
-- `cve` (Block Set, Min: 1) CVE of the custom issue (see [below for nested schema](#nestedblock--cve))
 - `description` (String) Description of custom issue
 - `name` (String) Name of the custom issue. It must not begin with 'xray' (case insensitive)
 - `package_type` (String) Package Type of custom issue. Valid values are: alpine, bower, cargo, composer, conan, conda, cran, debian, docker, generic, go, gradle, huggingface, ivy, maven, npm, nuget, oci, pypi, rpm, rubygems, sbt, terraformbe
 - `provider_name` (String) Provider of custom issue. It must not be 'jfrog' (case insensitive)
 - `severity` (String) Severity of custom issue. Valid values: Critical, High, Medium, Low, Information
-- `source` (Block Set, Min: 1) List of sources (see [below for nested schema](#nestedblock--source))
 - `summary` (String) Summary of custom issue
 - `type` (String) Type of custom issue. Valid values: other, performance, security, versions
 
+### Optional
+
+- `component` (Block Set) Component of custom issue (see [below for nested schema](#nestedblock--component))
+- `cve` (Block Set) CVE of the custom issue (see [below for nested schema](#nestedblock--cve))
+- `source` (Block Set) List of sources (see [below for nested schema](#nestedblock--source))
+
 ### Read-Only
 
 - `id` (String) The ID of this resource.
@@ -73,7 +76,7 @@ Required:
 
 Optional:
 
-- `fixed_versions` (Set of String) List of the fixed versions
+- `fixed_versions` (Set of String) List of fixed versions
 - `vulnerable_ranges` (Block Set) List of the vulnerable ranges (see [below for nested schema](#nestedblock--component--vulnerable_ranges))
 - `vulnerable_versions` (Set of String) List of vulnerable versions
 
@@ -82,7 +85,7 @@ Optional:
 
 Optional:
 
-- `fixed_versions` (Set of String) List of the fixed versions
+- `fixed_versions` (Set of String) List of fixed versions
 - `vulnerable_versions` (Set of String) List of vulnerable versions
 
 
diff --git a/docs/resources/watch.md b/docs/resources/watch.md
index 0133f25d..80442077 100644
--- a/docs/resources/watch.md
+++ b/docs/resources/watch.md
@@ -358,20 +358,16 @@ resource "xray_watch" "project" {
 
 ### Required
 
-- `assigned_policy` (Block Set, Min: 1) Nested argument describing policies that will be applied. Defined below. (see [below for nested schema](#nestedblock--assigned_policy))
-- `name` (String) Name of the watch (must be unique)
-- `watch_resource` (Block Set, Min: 1) Nested argument describing the resources to be watched. Defined below. (see [below for nested schema](#nestedblock--watch_resource))
+- `name` (String) Name of the watch
 
 ### Optional
 
 - `active` (Boolean) Whether or not the watch is active
+- `assigned_policy` (Block Set) Nested argument describing policies that will be applied. Defined below. (see [below for nested schema](#nestedblock--assigned_policy))
 - `description` (String) Description of the watch
 - `project_key` (String) Project key for assigning this resource to. Must be 2 - 10 lowercase alphanumeric and hyphen characters. Support repository and build watch resource types. When specifying individual repository or build they must be already assigned to the project. Build must be added as indexed resources.
 - `watch_recipients` (Set of String) A list of email addressed that will get emailed when a violation is triggered.
-
-### Read-Only
-
-- `id` (String) The ID of this resource.
+- `watch_resource` (Block Set) (see [below for nested schema](#nestedblock--watch_resource))
 
 <a id="nestedblock--assigned_policy"></a>
 ### Nested Schema for `assigned_policy`
diff --git a/pkg/xray/resource/resource_xray_binary_manager_builds.go b/pkg/xray/resource/resource_xray_binary_manager_builds.go
index a09c8ce2..4ee25938 100644
--- a/pkg/xray/resource/resource_xray_binary_manager_builds.go
+++ b/pkg/xray/resource/resource_xray_binary_manager_builds.go
@@ -2,8 +2,10 @@ package xray
 
 import (
 	"context"
+	"regexp"
 	"strings"
 
+	"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
 	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
 	"github.com/hashicorp/terraform-plugin-framework/diag"
 	"github.com/hashicorp/terraform-plugin-framework/path"
@@ -102,7 +104,12 @@ func (r *BinaryManagerBuildsResource) Schema(ctx context.Context, req resource.S
 			"indexed_builds": schema.SetAttribute{
 				ElementType: types.StringType,
 				Required:    true,
-				Description: "Builds to be indexed.",
+				Validators: []validator.Set{
+					setvalidator.ValueStringsAre(
+						validatorfw_string.RegexNotMatches(regexp.MustCompile(`[\*|\*\*|\?]+`), "cannot contain Ant-style patterns ('*', '**', or '?')"),
+					),
+				},
+				Description: "Builds to be indexed.\n\n~>Currently does not support Ant-style path patterns (`*`, `**`, or `?`) due to API limitation.",
 			},
 			"non_indexed_builds": schema.SetAttribute{
 				ElementType: types.StringType,
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 a45ce259..b20fcca8 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
@@ -2,8 +2,10 @@ package xray
 
 import (
 	"context"
+	"regexp"
 	"strings"
 
+	"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
 	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
 	"github.com/hashicorp/terraform-plugin-framework/diag"
 	"github.com/hashicorp/terraform-plugin-framework/path"
@@ -103,7 +105,12 @@ func (r *BinaryManagerReleaseBundlesV2Resource) Schema(ctx context.Context, req
 			"indexed_release_bundle_v2": schema.SetAttribute{
 				ElementType: types.StringType,
 				Required:    true,
-				Description: "Release Bundles V2 to be indexed.",
+				Validators: []validator.Set{
+					setvalidator.ValueStringsAre(
+						validatorfw_string.RegexNotMatches(regexp.MustCompile(`[\*|\*\*|\?]+`), "cannot contain Ant-style patterns ('*', '**', or '?')"),
+					),
+				},
+				MarkdownDescription: "Release Bundles V2 to be indexed.\n\n~>Currently does not support Ant-style path patterns (`*`, `**`, or `?`) due to API limitation.",
 			},
 			"non_indexed_release_bundle_v2": schema.SetAttribute{
 				ElementType: types.StringType,
@@ -111,7 +118,7 @@ func (r *BinaryManagerReleaseBundlesV2Resource) Schema(ctx context.Context, req
 				Description: "Non-indexed Release Bundles V2 for output.",
 			},
 		},
-		Description: "Provides an Xray Binary Manager Release Bundles V2 Indexing configuration resource. See [Indexing Xray Resources](https://jfrog.com/help/r/jfrog-security-documentation/add-or-remove-resources-from-indexing) " +
+		MarkdownDescription: "Provides an Xray Binary Manager Release Bundles V2 Indexing configuration resource. See [Indexing Xray Resources](https://jfrog.com/help/r/jfrog-security-documentation/add-or-remove-resources-from-indexing) " +
 			"and [REST API](https://jfrog.com/help/r/xray-rest-apis/add-release-bundles-v2-indexing-configuration) for more details.",
 	}
 }


Test patch:
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 afa43198..eb25860c 100644
--- a/pkg/xray/resource/resource_xray_binary_manager_builds_test.go
+++ b/pkg/xray/resource/resource_xray_binary_manager_builds_test.go
@@ -2,6 +2,7 @@ package xray_test
 
 import (
 	"fmt"
+	"regexp"
 	"testing"
 	"time"
 
@@ -267,3 +268,40 @@ func TestAccBinaryManagerBuilds_project_full(t *testing.T) {
 		},
 	})
 }
+
+func TestAccBinaryManagerBuilds_invalid_patterns(t *testing.T) {
+	invalidPatterns := []string{"*", "**", "?"}
+
+	for _, invalidPattern := range invalidPatterns {
+		t.Run(invalidPattern, func(t *testing.T) {
+			_, _, resourceName := testutil.MkNames("test-bin-mgr-builds", "xray_binary_manager_builds")
+
+			const template = `
+				resource "xray_binary_manager_builds" "{{ .name }}" {
+					id = "default"
+					indexed_builds = ["{{ .pattern }}"]
+				}
+			`
+
+			testData := map[string]string{
+				"name":    resourceName,
+				"pattern": invalidPattern,
+			}
+
+			config := util.ExecuteTemplate("TestAccBinaryManagerBuilds_invalid_patterns", template, testData)
+
+			resource.Test(t, resource.TestCase{
+				PreCheck: func() {
+					acctest.PreCheck(t)
+				},
+				ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories,
+				Steps: []resource.TestStep{
+					{
+						Config:      config,
+						ExpectError: regexp.MustCompile(`.*cannot contain Ant-style patterns.*`),
+					},
+				},
+			})
+		})
+	}
+}
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 25f4a93b..9788d69c 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
@@ -3,6 +3,7 @@ package xray_test
 import (
 	"fmt"
 	"os"
+	"regexp"
 	"testing"
 
 	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
@@ -433,3 +434,40 @@ func TestAccBinaryManagerReleaseBundlesV2_project_full(t *testing.T) {
 		},
 	})
 }
+
+func TestAccBinaryManagerReleaseBundlesV2_invalid_patterns(t *testing.T) {
+	invalidPatterns := []string{"*", "**", "?"}
+
+	for _, invalidPattern := range invalidPatterns {
+		t.Run(invalidPattern, func(t *testing.T) {
+			_, _, resourceName := testutil.MkNames("test-bin-mgr-release-bundles-v2", "xray_binary_manager_release_bundles_v2")
+
+			const template = `
+				resource "xray_binary_manager_release_bundles_v2" "{{ .name }}" {
+					id = "default"
+					indexed_release_bundle_v2 = ["{{ .pattern }}"]
+				}
+			`
+
+			testData := map[string]string{
+				"name":    resourceName,
+				"pattern": invalidPattern,
+			}
+
+			config := util.ExecuteTemplate("TestAccBinaryManagerReleaseBundlesV2_invalid_patterns", template, testData)
+
+			resource.Test(t, resource.TestCase{
+				PreCheck: func() {
+					acctest.PreCheck(t)
+				},
+				ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories,
+				Steps: []resource.TestStep{
+					{
+						Config:      config,
+						ExpectError: regexp.MustCompile(`.*cannot contain Ant-style\n.*patterns.*`),
+					},
+				},
+			})
+		})
+	}
+}