ci: route Playwright reports through private Azure Storage container

Replaces the public `/playwright-reports/*` static-website uploads and all GitHub Actions artifact uploads for Playwright traces/videos/blob-reports with uploads to a new private container `playwright-reports` on the same storage account. PR comments now link to an Azure Portal blob-properties deep link (requires AAD sign-in) instead of the previously anonymous static-site URL.

Fixes MSRC finding: Playwright traces captured on test failure embed Authorization: Bearer headers, and the existing publish path made them anonymously downloadable. The new private container is RBAC-gated (Storage Blob Data Reader/Contributor at container scope) and the storage account already has anonymous blob access and shared-key access disabled.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Sung-Hyun Kang
2026-06-10 14:16:46 -05:00
parent 4f9a987d28
commit b288ed7374
+63 -51
View File
@@ -299,13 +299,19 @@ jobs:
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --list run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --list
- name: Run test shard ${{ matrix['shardIndex'] }} of ${{ matrix['shardTotal']}} - name: Run test shard ${{ matrix['shardIndex'] }} of ${{ matrix['shardTotal']}}
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --workers=3 run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --workers=3
- name: Upload blob report to GitHub Actions Artifacts - name: Upload shard blob-report to Azure Storage
if: ${{ !cancelled() }} if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4 env:
with: KEY: ${{ github.run_id }}-${{ github.run_attempt }}
name: blob-report-${{ matrix.shardIndex }} SHARD: ${{ matrix.shardIndex }}
path: blob-report run: |
retention-days: 1 az storage blob upload-batch \
--account-name ${{ secrets.PREVIEW_STORAGE_ACCOUNT_NAME }} \
--auth-mode login \
-d playwright-reports \
-s blob-report \
--destination-path "${KEY}/shards/shard-${SHARD}" \
--overwrite true
merge-playwright-reports: merge-playwright-reports:
name: "Merge Playwright Reports" name: "Merge Playwright Reports"
@@ -325,29 +331,64 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci
- name: Download blob reports from GitHub Actions Artifacts - name: "Az CLI login"
uses: actions/download-artifact@v4 uses: Azure/login@v2
with: with:
path: all-blob-reports client-id: ${{ secrets.AZURE_CLIENT_ID }}
pattern: blob-report-* tenant-id: ${{ secrets.AZURE_TENANT_ID }}
merge-multiple: true subscription-id: ${{ secrets.PREVIEW_SUBSCRIPTION_ID }}
- name: Download all shard reports from Azure Storage
env:
KEY: ${{ github.run_id }}-${{ github.run_attempt }}
run: |
mkdir -p all-blob-reports
az storage blob download-batch \
--account-name ${{ secrets.PREVIEW_STORAGE_ACCOUNT_NAME }} \
--auth-mode login \
-s playwright-reports \
--pattern "${KEY}/shards/*" \
-d ./all-blob-reports
- name: Merge into HTML Report - name: Merge into HTML Report
run: npx playwright merge-reports --reporter html ./all-blob-reports run: npx playwright merge-reports --reporter html ./all-blob-reports
- name: Upload HTML report - name: Bundle merged report into a single zip
uses: actions/upload-artifact@v4 run: |
with: cd playwright-report
name: html-report--attempt-${{ github.run_attempt }} zip -r ../report.zip .
path: playwright-report cd ..
retention-days: 14
- name: Upload report.zip to Azure Storage
env:
KEY: ${{ github.run_id }}-${{ github.run_attempt }}
run: |
az storage blob upload \
--account-name ${{ secrets.PREVIEW_STORAGE_ACCOUNT_NAME }} \
--auth-mode login \
-c playwright-reports \
-n "${KEY}/report.zip" \
-f report.zip \
--overwrite
- name: Clean up shard intermediates from Azure Storage
if: ${{ always() }}
env:
KEY: ${{ github.run_id }}-${{ github.run_attempt }}
run: |
az storage blob delete-batch \
--account-name ${{ secrets.PREVIEW_STORAGE_ACCOUNT_NAME }} \
--auth-mode login \
-s playwright-reports \
--pattern "${KEY}/shards/*"
- name: Comment Playwright results on PR - name: Comment Playwright results on PR
if: ${{ !cancelled() && github.event_name == 'pull_request' }} if: ${{ !cancelled() && github.event_name == 'pull_request' }}
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR: ${{ github.event.pull_request.number }} PR: ${{ github.event.pull_request.number }}
REPORT_URL: https://dataexplorerpreview.z5.web.core.windows.net/playwright-reports/${{ github.run_id }}-${{ github.run_attempt }}/index.html SA_ID: /subscriptions/${{ secrets.PREVIEW_SUBSCRIPTION_ID }}/resourceGroups/dataexplorer-preview/providers/Microsoft.Storage/storageAccounts/dataexplorerpreview
KEY: ${{ github.run_id }}-${{ github.run_attempt }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: | run: |
PLAYWRIGHT_JSON_OUTPUT_NAME=results.json npx playwright merge-reports --reporter json ./all-blob-reports PLAYWRIGHT_JSON_OUTPUT_NAME=results.json npx playwright merge-reports --reporter json ./all-blob-reports
@@ -355,6 +396,9 @@ jobs:
BROKEN=$(gh api "repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}/jobs" \ BROKEN=$(gh api "repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}/jobs" \
--jq '[.jobs[] | select(.name | startswith("Run Playwright Tests")) | select(.conclusion == "failure")] | length') --jq '[.jobs[] | select(.name | startswith("Run Playwright Tests")) | select(.conclusion == "failure")] | length')
if [ "$FAILED" -gt 0 ] || [ "$BROKEN" -gt 0 ]; then ICON="❌ failed"; else ICON="✅ passed"; fi if [ "$FAILED" -gt 0 ] || [ "$BROKEN" -gt 0 ]; then ICON="❌ failed"; else ICON="✅ passed"; fi
SA_ENC=$(printf '%s' "$SA_ID" | jq -sRr @uri)
BLOB_PATH_ENC=$(printf 'playwright-reports/%s/report.zip' "$KEY" | jq -sRr @uri)
REPORT_URL="https://portal.azure.com/#view/Microsoft_Azure_Storage/BlobPropertiesBladeV2/storageAccountId/${SA_ENC}/path/${BLOB_PATH_ENC}"
NOTE="" NOTE=""
[ "$BROKEN" -gt 0 ] && NOTE=" [ "$BROKEN" -gt 0 ] && NOTE="
@@ -365,38 +409,6 @@ jobs:
| :---: | :---: | :---: | :---: | | :---: | :---: | :---: | :---: |
| $PASSED | $FAILED | $FLAKY | ${DURATION}s | | $PASSED | $FAILED | $FLAKY | ${DURATION}s |
📊 [Open full report]($REPORT_URL) · [Workflow run]($RUN_URL)$NOTE" 📁 [Download report.zip]($REPORT_URL) (Azure sign-in required → click **Download** → unzip → open \`index.html\`) · [Workflow run]($RUN_URL)$NOTE"
publish-playwright-report:
name: "Publish Playwright Report to Blob"
if: ${{ !cancelled() }}
needs: [merge-playwright-reports]
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Download HTML report artifact
uses: actions/download-artifact@v4
with:
name: html-report--attempt-${{ github.run_attempt }}
path: playwright-report
- name: "Az CLI login"
uses: Azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.PREVIEW_SUBSCRIPTION_ID }}
- name: Upload Playwright report to blob storage
env:
KEY: ${{ github.run_id }}-${{ github.run_attempt }}
BASE: https://dataexplorerpreview.z5.web.core.windows.net
run: |
az storage blob upload-batch -d '$web' -s playwright-report \
--destination-path "playwright-reports/${KEY}" \
--account-name ${{ secrets.PREVIEW_STORAGE_ACCOUNT_NAME }} \
--auth-mode login --overwrite true
echo "📊 [Open Playwright report](${BASE}/playwright-reports/${KEY}/index.html)" >> $GITHUB_STEP_SUMMARY