diff --git a/.github/workflows/validate-policy-id.yaml b/.github/workflows/validate-policy-id.yaml new file mode 100644 index 00000000..796c1035 --- /dev/null +++ b/.github/workflows/validate-policy-id.yaml @@ -0,0 +1,194 @@ +name: Confirm Policy Definition has Unique ID and does not conflict with Built-In Policies + +on: + pull_request: + branches: + - main + +jobs: + # ------------------------------------------------------------- + # Using GitHub's API + # ------------------------------------------------------------- + # Event `pull_request`: Returns all changed pull request files. + # -------------------------------------------------------------- + validate-built-in-policy-id: + name: Validate Policy Definition Unique ID + runs-on: ubuntu-latest + permissions: + pull-requests: read + steps: + - uses: actions/checkout@v3 + + - name: Get changed files + id: changed_files + uses: tj-actions/changed-files@v37 + with: + separator: "§" # we need a character which isn't used within a file name or path + + - name: Validate Policy Definition Unique ID & Check for Built-In Policy Conflicts + if: ${{ steps.changed_files.outputs.any_changed }} == 'true' + env: + GH_SEARCH_TOKEN: ${{ secrets.GH_SEARCH_TOKEN }} + shell: bash + run: > + echo 'Step 1: Checking if azurepolicy.json file exists...' + + filesString="${{ steps.changed_files.outputs.all_changed_files }}" + + echo " Info: found changed files - $filesString" + + IFS='§' read -ra files <<< "$filesString" + + echo " Info: changed files converted to array, ready to check each file..." + + for file in "${files[@]}"; do + echo " Checking file name: ${file}" + if echo "$file" | grep -q 'azurepolicy.json'; then + policyFile=$file + echo " Success: azurepolicy.json file found... policyFile <-- $file" + break + fi + done + + if [ ! -f "$policyFile" ]; then + echo "" + echo "" + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo ' | |' + echo ' | - VALIDATION FAILED - |' + echo ' | File NOT FOUND: azurepolicy.json |' + echo ' | |' + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo "" + echo "" + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo ' | |' + echo ' | - NEXT STEPS - |' + echo ' | Please make sure your main Policy Definition file is included, |' + echo ' | and the file is named azurepolicy.json. |' + echo ' | |' + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo "" + echo "" + exit 1 + fi + + echo "Step 2: Attempting to return policy name from $policyFile" + + policyName=$(jq -r '.name' "${policyFile}") + + echo " Success: name field found in azurepolicy.json... policyName <-- ${policyName}" + + if [ -z "$policyName" ]; then + echo "" + echo "" + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo ' | |' + echo ' | - VALIDATION FAILED - |' + echo ' | Policy Name not found in azurepolicy.json file |' + echo ' | |' + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo "" + echo "" + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo ' | |' + echo ' | - NEXT STEPS - |' + echo ' | Please make sure a name is present in azurepolicy.json |' + echo ' | Please make sure the name is a valid GUID |' + echo ' | |' + echo ' | What is a GUID? https://www.rfc-editor.org/rfc/rfc4122 |' + echo ' | Make a new GUID in PowerShell: https://aka.ms/new-guid |' + echo ' | |' + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo "" + echo "" + exit 1 + elif [[ ! $policyName =~ ^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ ]]; then + echo "" + echo "" + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo ' | |' + echo ' | - VALIDATION FAILED - |' + echo ' | Policy name is not a valid GUID |' + echo ' | |' + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo "" + echo "" + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo ' | |' + echo ' | - NEXT STEPS - |' + echo ' | Please change the policy name to a unique GUID |' + echo ' | |' + echo ' | What is a GUID? https://www.rfc-editor.org/rfc/rfc4122 |' + echo ' | Make a new GUID in PowerShell: https://aka.ms/new-guid |' + echo ' | |' + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo "" + echo "" + exit 1 + else + echo " Success: Policy Name $policyName exists and is a valid GUID." + echo 'Step 3: Sending request to GitHub API to search for Policy Name in Azure Policy Repo...' + + response=$(curl -s \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: token $GH_SEARCH_TOKEN" \ + "https://api.github.com/search/code?q=$policyName+in:file+language:json+repo:Azure/azure-policy") + + if [ -z "$response" ]; then + echo ' Error: API Response - No response from GitHub API.' + exit 1 + else + echo ' Success: Response from GitHub API received.' + fi + + if [ "$(echo $response | jq '.message')" = '"Bad credentials"' ]; then + echo ' Error: API Response - Bad credentials. Please check the GH_SEARCH_TOKEN secret.' + echo ' Next Steps: This one is on us, please open an issue if you see this error.' + exit 1 + elif [ "$(echo $response | jq '.message')" = '"Requires authentication"' ]; then + echo ' Error: API Response - API requires authentication. Please make sure we are passing the Authorization Header.' + echo ' Next Steps: This one is on us, please open an issue if you see this error.' + exit 1 + elif [ -z "$(echo $response | jq '.total_count')" ]; then + echo ' Error: API Response - Something went wrong... No total_count found in response body.' + echo ' Next Steps: This one is on us, please open an issue if you see this error.' + exit 1 + fi + if [ "$(echo $response | jq '.total_count')" == 0 ]; then + echo ' Success: GUID not found in Built-In Azure Policy Repo.' + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo ' | |' + echo ' | - VALIDATION SUCCESS - |' + echo ' | Policy name is a valid GUID |' + echo ' | and does not match existing built-in Policy Definition |' + echo ' | |' + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + exit 0 + else + echo "" + echo "" + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo ' | |' + echo ' | - VALIDATION FAILED - |' + echo ' | Policy name exists in the Built-In Azure Policy Repo |' + echo ' | |' + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo "" + echo " Built-in Policy URL: $(echo $response | jq -r '.items[0].html_url')" + echo "" + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo ' | |' + echo ' | - NEXT STEPS - |' + echo ' | Please change the policy name to a unique GUID |' + echo ' | Please do not submit only slightly altered built-in policies |' + echo ' | |' + echo ' | What is a GUID? https://www.rfc-editor.org/rfc/rfc4122 |' + echo ' | Make a new GUID in PowerShell: https://aka.ms/new-guid |' + echo ' | |' + echo ' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////' + echo "" + echo "" + exit 1 + fi + fi \ No newline at end of file