feat(logging): write un-redacted log files in DEBUG builds (#295) #39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Integration tests | |
| on: | |
| push: | |
| branches: [main] | |
| paths-ignore: | |
| - 'docs/**' | |
| - '**/*.md' | |
| - '.github/ISSUE_TEMPLATE/**' | |
| # pull_request_target (not pull_request) is intentional: | |
| # - `pull_request` runs in the context of the PR head (untrusted fork code) | |
| # while holding id-token:write + Azure OIDC access — a secret-exposure risk. | |
| # - `pull_request_target` runs in the context of the BASE branch; the | |
| # checked-out ref below is pinned to github.event.pull_request.base.sha so | |
| # fork-PR code is NEVER executed by this workflow. | |
| # - Fork PRs are gated by the maintainer-only `integration` label; that label | |
| # plus the base-SHA checkout is the only fork gate. The `integration` | |
| # environment has no required reviewers, so push-to-main runs execute | |
| # unattended and still access environment-scoped Azure secrets/vars. | |
| pull_request_target: | |
| types: [labeled] | |
| workflow_dispatch: | |
| permissions: | |
| id-token: write | |
| contents: read | |
| concurrency: | |
| group: integration-tests | |
| cancel-in-progress: false | |
| jobs: | |
| integration: | |
| if: ${{ github.event_name != 'pull_request_target' || contains(github.event.pull_request.labels.*.name, 'integration') }} | |
| runs-on: macos-15 | |
| environment: integration | |
| timeout-minutes: 45 | |
| env: | |
| HOMEBREW_NO_ENV_HINTS: "1" | |
| steps: | |
| # SECURITY: always check out the BASE ref, never the PR head. | |
| # On pull_request_target the default ref IS the base, but we pin | |
| # explicitly to guard against future event-schema changes. | |
| - uses: actions/checkout@v6.0.3 | |
| with: | |
| ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.base.sha || github.sha }} | |
| - uses: azure/login@v3.0.0 | |
| with: | |
| client-id: ${{ secrets.AZURE_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_TENANT_ID }} | |
| subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} | |
| - name: Verify Azure login | |
| run: az account show -o none | |
| - name: Resume Fabric capacity | |
| run: | | |
| set -euo pipefail | |
| CAPACITY_ID="${{ vars.OFEM_TEST_CAPACITY_ID }}" | |
| # Wait for the capacity to leave any transitional state, up to 5 min | |
| for _ in {1..30}; do | |
| STATE=$(az resource show --ids "$CAPACITY_ID" --query 'properties.state' -o tsv 2>/dev/null || echo "Unknown") | |
| echo "Pre-resume state: $STATE" | |
| case "$STATE" in | |
| Active) echo "Already Active, skipping resume"; exit 0 ;; | |
| Paused) break ;; | |
| *) sleep 10 ;; | |
| esac | |
| done | |
| # Issue resume, but tolerate transient BadRequest | |
| for attempt in {1..6}; do | |
| if az resource invoke-action --ids "$CAPACITY_ID" --action resume; then | |
| break | |
| fi | |
| echo "Resume attempt $attempt failed (likely transient), waiting 15s..." | |
| sleep 15 | |
| done | |
| # Poll until Active, then sleep 120s for data-plane warm-up (max ~7 min) | |
| for _ in {1..30}; do | |
| STATE=$(az resource show --ids "$CAPACITY_ID" --query 'properties.state' -o tsv) | |
| echo "Post-resume state: $STATE" | |
| if [[ "$STATE" == "Active" ]]; then | |
| echo "Capacity is Active; sleeping 120s for Fabric data-plane to settle..." | |
| sleep 120 | |
| exit 0 | |
| fi | |
| sleep 10 | |
| done | |
| echo "Capacity did not reach Active state within 5 minutes" >&2 | |
| exit 1 | |
| - name: Mint bearer tokens | |
| run: | | |
| set -euo pipefail | |
| FABRIC_TOKEN=$(az account get-access-token --resource https://analysis.windows.net/powerbi/api --query accessToken -o tsv) | |
| echo "::add-mask::$FABRIC_TOKEN" | |
| echo "OFEM_TOKEN_FABRIC=$FABRIC_TOKEN" >> "$GITHUB_ENV" | |
| ONELAKE_TOKEN=$(az account get-access-token --resource https://storage.azure.com --query accessToken -o tsv) | |
| echo "::add-mask::$ONELAKE_TOKEN" | |
| echo "OFEM_TOKEN_ONELAKE=$ONELAKE_TOKEN" >> "$GITHUB_ENV" | |
| - name: Seed warehouse table | |
| env: | |
| OFEM_TEST_WH_SERVER: ${{ vars.OFEM_TEST_WH_SERVER }} | |
| OFEM_TEST_WH_DATABASE: ${{ vars.OFEM_TEST_WH_DATABASE }} | |
| OFEM_TEST_WH_TABLE: ${{ vars.OFEM_TEST_WH_TABLE }} | |
| run: | | |
| set -euo pipefail | |
| # Remove unused pre-installed taps to silence the untrusted-taps warning. | |
| brew untap aws/tap azure/bicep 2>/dev/null || true | |
| brew list sqlcmd &>/dev/null || brew install sqlcmd | |
| # Reference the Homebrew-managed binary directly: a pre-existing | |
| # mssql-tools symlink can shadow it in PATH on the runner. | |
| SQLCMD="$(brew --prefix sqlcmd)/bin/sqlcmd" | |
| # Retry loop: warehouse SQL endpoint may need time to warm up after capacity resume | |
| for attempt in 1 2 3 4 5; do | |
| if "$SQLCMD" -S "$OFEM_TEST_WH_SERVER" -d "$OFEM_TEST_WH_DATABASE" \ | |
| --authentication-method ActiveDirectoryAzCli \ | |
| -v table="$OFEM_TEST_WH_TABLE" -i scripts/prep_warehouse.sql -b; then | |
| exit 0 | |
| fi | |
| echo "prep attempt $attempt failed, waiting 20s..."; sleep 20 | |
| done | |
| echo "warehouse prep failed after retries" >&2; exit 1 | |
| - name: Run integration tests | |
| env: | |
| OFEM_TEST_WORKSPACE_ID: ${{ vars.OFEM_TEST_WORKSPACE_ID }} | |
| OFEM_TEST_LAKEHOUSE_ID: ${{ vars.OFEM_TEST_LAKEHOUSE_ID }} | |
| OFEM_TEST_WAREHOUSE_ID: ${{ vars.OFEM_TEST_WAREHOUSE_ID }} | |
| run: make test-integration | |
| - name: Re-authenticate for capacity suspend | |
| if: always() | |
| uses: azure/login@v3.0.0 | |
| with: | |
| client-id: ${{ secrets.AZURE_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_TENANT_ID }} | |
| subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} | |
| - name: Suspend Fabric capacity | |
| if: always() | |
| run: | | |
| set -euo pipefail | |
| CAPACITY_ID="${{ vars.OFEM_TEST_CAPACITY_ID }}" | |
| # Wait for the capacity to leave any transitional state, up to 5 min | |
| for _ in {1..30}; do | |
| STATE=$(az resource show --ids "$CAPACITY_ID" --query 'properties.state' -o tsv 2>/dev/null || echo "Unknown") | |
| echo "Pre-suspend state: $STATE" | |
| case "$STATE" in | |
| Paused) echo "Already Paused, skipping suspend"; exit 0 ;; | |
| Active) break ;; | |
| *) sleep 10 ;; | |
| esac | |
| done | |
| # Issue suspend, but tolerate transient BadRequest | |
| for attempt in {1..6}; do | |
| if az resource invoke-action --ids "$CAPACITY_ID" --action suspend; then | |
| break | |
| fi | |
| echo "Suspend attempt $attempt failed (likely transient), waiting 15s..." | |
| sleep 15 | |
| done | |
| # Poll until Paused, max 5 min | |
| for _ in {1..30}; do | |
| STATE=$(az resource show --ids "$CAPACITY_ID" --query 'properties.state' -o tsv) | |
| echo "Post-suspend state: $STATE" | |
| [[ "$STATE" == "Paused" ]] && exit 0 | |
| sleep 10 | |
| done | |
| echo "Capacity did not reach Paused state within 5 minutes" >&2 | |
| exit 1 |