Repository: radius-project/radius

Issue:
Use dedicated ACR for Test User-Defined Bicep Types
We currently are re-using the biceptypes.azurecr.io registry for test user-defined types used in functional tests. The approach to fix this was discussed with the team and the following steps were outlined: 

1. Create a new registry testuserdefinedbiceptypes.azurecr.io so all engineers have access to it and can move test udt bicep types to the new registry and update workflows accordingly.
2. Update validatebicep.yaml to pull index.json from npx registry for udts & create temp directory where test uct bicep types are pushed. This will help `validate bicep` step run successfully in PRs without requiring manual push to the new acr.

[AB#15719](https://dev.azure.com/azure-octo/e61041b4-555f-47ae-95b2-4f8ab480ea57/_workitems/edit/15719)

Discussion:

Solution patch:
diff --git a/.github/workflows/functional-test-noncloud.yaml b/.github/workflows/functional-test-noncloud.yaml
index 915cdab29..6a392b197 100644
--- a/.github/workflows/functional-test-noncloud.yaml
+++ b/.github/workflows/functional-test-noncloud.yaml
@@ -426,7 +426,7 @@ jobs:
         run: |
           export PATH=$GITHUB_WORKSPACE/bin:$PATH
           which rad || { echo "cannot find rad"; exit 1; }
-          rad bicep publish-extension -f ./test/functional-portable/dynamicrp/noncloud/resources/testdata/usertypealpha.yaml --target br:${{ env.LOCAL_REGISTRY_SERVER }}:${{ env.LOCAL_REGISTRY_PORT }}/testresources:${{ env.REL_VERSION == 'edge' && 'latest' || env.REL_VERSION }} --force
+          rad bicep publish-extension -f ./test/functional-portable/dynamicrp/noncloud/resources/testdata/testresourcetypes.yaml --target br:${{ env.LOCAL_REGISTRY_SERVER }}:${{ env.LOCAL_REGISTRY_PORT }}/testresources:${{ env.REL_VERSION == 'edge' && 'latest' || env.REL_VERSION }} --force
 
       - name: Generate test bicepconfig.json
         run: |
diff --git a/.github/workflows/long-running-azure.yaml b/.github/workflows/long-running-azure.yaml
index 112f0ef0b..da5be2fcc 100644
--- a/.github/workflows/long-running-azure.yaml
+++ b/.github/workflows/long-running-azure.yaml
@@ -70,8 +70,8 @@ env:
   CONTAINER_REGISTRY: ghcr.io/radius-project/dev
   # Container registry for storing Bicep recipe artifacts
   BICEP_RECIPE_REGISTRY: ghcr.io/radius-project/dev
-  # bicep-types ACR url for uploading UDT Bicep types
-  BICEP_TYPES_REGISTRY: 'biceptypes.azurecr.io'
+  # ACR url for uploading test UDT Bicep types
+  TEST_BICEP_TYPES_REGISTRY: 'testuserdefinedbiceptypes.azurecr.io'
   # The radius functional test timeout
   FUNCTIONALTEST_TIMEOUT: 60m
   # The Azure Location to store test resources
@@ -321,7 +321,7 @@ jobs:
           which rad || { echo "cannot find rad"; exit 1; }
           rad bicep download
           rad version
-          rad bicep publish-extension -f ./test/functional-portable/dynamicrp/noncloud/resources/testdata/usertypealpha.yaml --target br:${{ env.BICEP_TYPES_REGISTRY }}/testresources:latest --force
+          rad bicep publish-extension -f ./test/functional-portable/dynamicrp/noncloud/resources/testdata/testresourcetypes.yaml --target br:${{ env.TEST_BICEP_TYPES_REGISTRY}}/testresources:latest --force
       - name: Login to Azure
         uses: azure/login@v2
         with:
diff --git a/.github/workflows/validate-bicep.yaml b/.github/workflows/validate-bicep.yaml
index 1bffa9c35..563878cc2 100644
--- a/.github/workflows/validate-bicep.yaml
+++ b/.github/workflows/validate-bicep.yaml
@@ -44,6 +44,20 @@ jobs:
     name: Validate Bicep Code
     runs-on: ubuntu-latest
     steps:
+      - name: Setup Node.js
+        uses: actions/setup-node@v4
+        with:
+          node-version: '18'
+
+      - name: Verify npx installation
+        run: |
+          if ! command -v npx &> /dev/null; then
+            echo "npx not found, installing..."
+            npm install -g npx
+          else
+            echo "npx is already installed"
+          fi
+
       - name: Setup and verify bicep CLI
         run: |
           curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64
@@ -53,17 +67,32 @@ jobs:
       - name: Check out repo
         uses: actions/checkout@v4
       - name: Create a temporary file system 
-        run:
+        run: |
           mkdir tmp-radius-bicep-extension
+          mkdir tmp-testresources-bicep-extension
       - name: Publish bicep types 
         run: | 
-          bicep publish-extension ./hack/bicep-types-radius/generated/index.json --target ./tmp-radius-bicep-extension/radius.tgz 
+          bicep publish-extension ./hack/bicep-types-radius/generated/index.json --target ./tmp-radius-bicep-extension/radius.tgz --force
+      - name: Generate testresources extension index
+        run: |
+          npx @radius-project/manifest-to-bicep-extension@alpha generate ./test/functional-portable/dynamicrp/noncloud/resources/testdata/testresourcetypes.yaml ./tmp-testresources-bicep-extension
+      - name: Publish testresources extension
+        run: |
+          bicep publish-extension ./tmp-testresources-bicep-extension/index.json --target ./tmp-testresources-bicep-extension/testresources.tgz --force
       - name: Install jq
         run: sudo apt-get install -y jq
       - name: Modify bicepconfig.json
         run: |
-          # Add credential preference to the bicepconfig.json file
-          jq '.extensions.radius = "./tmp-radius-bicep-extension/radius.tgz"' bicepconfig.json > tmp.json && mv tmp.json bicepconfig.json
+          # Update bicepconfig.json with paths for extensions
+          WORKDIR="${{ github.workspace }}"
+          jq \
+            --arg rad "$WORKDIR/tmp-radius-bicep-extension/radius.tgz" \
+            --arg test "$WORKDIR/tmp-testresources-bicep-extension/testresources.tgz" \
+            '.extensions.radius = $rad | .extensions.testresources = $test' \
+            bicepconfig.json > tmp.json && mv tmp.json bicepconfig.json
+
+           # Copy to the dynamicrp resources test directory so the .bicep files there can find it
+           cp -f bicepconfig.json ./test/functional-portable/dynamicrp/noncloud/resources/bicepconfig.json
       - name: Print updated bicepconfig.json
         run: cat bicepconfig.json
       - name: Verify Bicep files



Test patch:
diff --git a/test/functional-portable/dynamicrp/noncloud/resources/bicepconfig.json b/test/functional-portable/dynamicrp/noncloud/resources/bicepconfig.json
index 2062a0515..b07ca1725 100644
--- a/test/functional-portable/dynamicrp/noncloud/resources/bicepconfig.json
+++ b/test/functional-portable/dynamicrp/noncloud/resources/bicepconfig.json
@@ -5,6 +5,6 @@
 	"extensions": {
 		"radius": "br:biceptypes.azurecr.io/radius:latest",
 		"aws": "br:biceptypes.azurecr.io/aws:latest",
-		"testresources": "br:biceptypes.azurecr.io/testresources:latest"
+		"testresources": "br:testuserdefinedbiceptypes.azurecr.io/testresources:latest"
 	}
 }
\ No newline at end of file
diff --git a/test/functional-portable/dynamicrp/noncloud/resources/dynamicrp_test.go b/test/functional-portable/dynamicrp/noncloud/resources/dynamicrp_test.go
index 5cf146b25..4257eaca3 100644
--- a/test/functional-portable/dynamicrp/noncloud/resources/dynamicrp_test.go
+++ b/test/functional-portable/dynamicrp/noncloud/resources/dynamicrp_test.go
@@ -48,7 +48,7 @@ func Test_DynamicRP_Recipe(t *testing.T) {
 	name := "usertypealpha-recipe-app"
 	appNamespace := "default-usertypealpha-recipe"
 	resourceTypeName := "Test.Resources/userTypeAlpha"
-	filepath := "testdata/usertypealpha.yaml"
+	filepath := "testdata/testresourcetypes.yaml"
 	options := rp.NewRPTestOptions(t)
 	cli := radcli.NewCLI(t, options.ConfigFilePath)
 
@@ -115,7 +115,7 @@ func Test_Postgres_EnvScoped_ExistingResource(t *testing.T) {
 	appNamespace := "dynamicrp-postgres-existing-app"
 	appName := "dynamicrp-postgres-existing"
 	resourceTypeName := "Test.Resources/postgres"
-	filepath := "testdata/usertypealpha.yaml"
+	filepath := "testdata/testresourcetypes.yaml"
 	options := rp.NewRPTestOptions(t)
 	cli := radcli.NewCLI(t, options.ConfigFilePath)
 	test := rp.NewRPTest(t, name, []rp.TestStep{
@@ -210,7 +210,7 @@ func Test_DynamicRP_ExternalResource(t *testing.T) {
 	expectedEnvValue := `{"app1.sample.properties":"property1=value1\nproperty2=value2","app2.sample.properties":"property3=value3\nproperty4=value4"}`
 	resourceTypeName := "Test.Resources/externalResource"
 	containerName := "externalresourcecntr"
-	filepath := "testdata/usertypealpha.yaml"
+	filepath := "testdata/testresourcetypes.yaml"
 	options := rp.NewRPTestOptions(t)
 	cli := radcli.NewCLI(t, options.ConfigFilePath)
 
diff --git a/test/functional-portable/dynamicrp/noncloud/resources/testdata/usertypealpha.yaml b/test/functional-portable/dynamicrp/noncloud/resources/testdata/testresourcetypes.yaml
similarity index 100%
rename from test/functional-portable/dynamicrp/noncloud/resources/testdata/usertypealpha.yaml
rename to test/functional-portable/dynamicrp/noncloud/resources/testdata/testresourcetypes.yaml