Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions .github/AZURE_RELAY_REGRESSION_TEST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Azure Relay Tests - Regression Test Documentation

## The Bug

**Issue**: Azure relay tests failed with authentication error even when OIDC credentials were configured.

**Root Cause**: GitHub Actions secrets are **not accessible** in workflow `if:` conditional expressions. They always evaluate to empty strings in that context.

## Reproduction of the Bug

### Original Code (Broken)
```yaml
# In .github/workflows/azure-relay-tests.yml (commit f26dc90)

- name: Azure Login (OIDC)
if: ${{ secrets.AZURE_CLIENT_ID != '' }} # ❌ Always FALSE
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Azure Login (Legacy)
if: ${{ secrets.AZURE_CLIENT_ID == '' && secrets.AZURE_CREDENTIALS != '' }} # ❌ Only checks AZURE_CREDENTIALS
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
```

### What Happened
1. Even when `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and `AZURE_SUBSCRIPTION_ID` secrets were configured
2. The condition `if: ${{ secrets.AZURE_CLIENT_ID != '' }}` **always evaluated to false**
3. OIDC login step was always skipped
4. Legacy login step always ran (checking only AZURE_CREDENTIALS)
5. Login failed with: "Not all values are present. Ensure 'client-id' and 'tenant-id' are supplied"

### Why It Failed
GitHub Actions **does not expose secret values** in the `if:` conditional context. Per GitHub's security model:
- Secrets can be used in `with:` parameters (e.g., `client-id: ${{ secrets.AZURE_CLIENT_ID }}`)
- Secrets can be used in `run:` shell scripts (e.g., `echo "${{ secrets.AZURE_CLIENT_ID }}"`)
- Secrets **cannot** be accessed in `if:` expressions - they're always empty

## The Fix

### Fixed Code (Working)
```yaml
# Step 1: Add auth_type output to check-credentials job
check-credentials:
outputs:
has_credentials: ${{ steps.check.outputs.has_credentials }}
auth_type: ${{ steps.check.outputs.auth_type }} # NEW
steps:
- name: Check if Azure credentials are configured
id: check
run: |
# Secrets ARE accessible in shell scripts
if [ -n "${{ secrets.AZURE_CLIENT_ID }}" ] && [ -n "${{ secrets.AZURE_TENANT_ID }}" ] && [ -n "${{ secrets.AZURE_SUBSCRIPTION_ID }}" ]; then
echo "has_credentials=true" >> $GITHUB_OUTPUT
echo "auth_type=oidc" >> $GITHUB_OUTPUT # NEW
elif [ -n "${{ secrets.AZURE_CREDENTIALS }}" ]; then
echo "has_credentials=true" >> $GITHUB_OUTPUT
echo "auth_type=legacy" >> $GITHUB_OUTPUT # NEW
else
echo "has_credentials=false" >> $GITHUB_OUTPUT
echo "auth_type=none" >> $GITHUB_OUTPUT # NEW
fi

# Step 2: Use auth_type output in conditionals (not secrets)
- name: Azure Login (OIDC)
if: ${{ needs.check-credentials.outputs.auth_type == 'oidc' }} # ✅ Works!
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Azure Login (Legacy)
if: ${{ needs.check-credentials.outputs.auth_type == 'legacy' }} # ✅ Works!
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
```

## Regression Test

The automated regression test is in `.github/workflows/test-workflow-logic.yml`.

### Test Cases

1. **Verify auth_type output exists**
- Ensures the fix is in place
- Checks that `auth_type:` is declared in job outputs

2. **Verify all auth_type branches are set**
- Confirms `auth_type=oidc` for OIDC credentials
- Confirms `auth_type=legacy` for legacy credentials
- Confirms `auth_type=none` for no credentials

3. **Verify no direct secret checks (the bug)**
- Fails if it finds `if: ${{ secrets.AZURE_CLIENT_ID` in Azure Login steps
- This is the regression test - it would fail on the original broken code

4. **Verify correct auth_type usage**
- Confirms Azure Login (OIDC) checks `auth_type == 'oidc'`
- Confirms Azure Login (Legacy) checks `auth_type == 'legacy'`

### Running the Test Locally

```bash
# Run the validation checks
cd .github/workflows
bash -c '
# Test that would FAIL on original broken code
if grep -A 5 "name: Azure Login" azure-relay-tests.yml | grep -q "if:.*secrets\.AZURE_CLIENT_ID"; then
echo "❌ REGRESSION: Found the bug - direct secret check in conditional"
exit 1
fi

# Test that would PASS on fixed code
if grep -A 5 "name: Azure Login (OIDC)" azure-relay-tests.yml | grep -q "auth_type == .oidc."; then
echo "✅ PASS: Using auth_type output (the fix)"
fi
'
```

### Manual Verification

You can also verify the fix works by checking the workflow run logs:

**Before fix (run 21325698059)**:
```
Azure Login (OIDC): Skipped
Azure Login (Legacy): Running
Error: Not all values are present. Ensure 'client-id' and 'tenant-id' are supplied.
```

**After fix**:
```
check-credentials:
✓ Azure OIDC credentials are configured
has_credentials=true
auth_type=oidc

deploy-infrastructure:
Azure Login (OIDC): Running (auth_type == 'oidc') ✓
Azure Login (Legacy): Skipped (auth_type != 'legacy') ✓
Login successful ✓
```

## Impact

This fix is critical for:
- ✅ OIDC authentication to work when configured
- ✅ Scheduled Azure relay tests to run successfully
- ✅ P2P relay functionality validation in Azure
- ✅ Proper credential detection and selection

## References

- **Original failure**: https://github.com/plures/pluresdb/actions/runs/21325698059
- **GitHub Actions secrets documentation**: https://docs.github.com/en/actions/security-guides/encrypted-secrets#using-encrypted-secrets-in-a-workflow
- **Fix commit**: dfa61db
16 changes: 10 additions & 6 deletions .github/workflows/azure-relay-tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Azure Relay Tests

Check warning on line 1 in .github/workflows/azure-relay-tests.yml

View workflow job for this annotation

GitHub Actions / copilot

1:1 [document-start] missing document start "---"

on:

Check warning on line 3 in .github/workflows/azure-relay-tests.yml

View workflow job for this annotation

GitHub Actions / copilot

3:1 [truthy] truthy value should be one of [false, true]
# Run on manual trigger
Expand All @@ -25,7 +25,7 @@

# Run on schedule (weekly for test environment)
schedule:
- cron: '0 2 * * 0' # Every Sunday at 2 AM UTC

Check warning on line 28 in .github/workflows/azure-relay-tests.yml

View workflow job for this annotation

GitHub Actions / copilot

28:25 [comments] too few spaces before comment: expected 2

permissions:
id-token: write # Required for OIDC authentication with Azure
Expand All @@ -41,20 +41,24 @@
runs-on: ubuntu-latest
outputs:
has_credentials: ${{ steps.check.outputs.has_credentials }}
auth_type: ${{ steps.check.outputs.auth_type }}
steps:
- name: Check if Azure credentials are configured
id: check
run: |
# Check for OIDC credentials (recommended)
if [ -n "${{ secrets.AZURE_CLIENT_ID }}" ] && [ -n "${{ secrets.AZURE_TENANT_ID }}" ] && [ -n "${{ secrets.AZURE_SUBSCRIPTION_ID }}" ]; then
echo "has_credentials=true" >> $GITHUB_OUTPUT
echo "auth_type=oidc" >> $GITHUB_OUTPUT
echo "✓ Azure OIDC credentials are configured"
# Fallback: Check for legacy AZURE_CREDENTIALS secret
elif [ -n "${{ secrets.AZURE_CREDENTIALS }}" ]; then
echo "has_credentials=true" >> $GITHUB_OUTPUT
echo "auth_type=legacy" >> $GITHUB_OUTPUT
echo "⚠️ Using legacy AZURE_CREDENTIALS secret (consider migrating to OIDC)"
else
echo "has_credentials=false" >> $GITHUB_OUTPUT
echo "auth_type=none" >> $GITHUB_OUTPUT
echo "⚠️ Azure credentials are not configured"
echo "This workflow requires Azure OIDC credentials to be set."
echo "See azure/docs/SECRETS.md for configuration instructions."
Expand All @@ -79,15 +83,15 @@
uses: actions/checkout@v4

- name: Azure Login (OIDC)
if: ${{ secrets.AZURE_CLIENT_ID != '' }}
if: ${{ needs.check-credentials.outputs.auth_type == 'oidc' }}
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Azure Login (Legacy)
if: ${{ secrets.AZURE_CLIENT_ID == '' && secrets.AZURE_CREDENTIALS != '' }}
if: ${{ needs.check-credentials.outputs.auth_type == 'legacy' }}
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
Expand Down Expand Up @@ -168,15 +172,15 @@
deno-version: v2.x

- name: Azure Login (OIDC)
if: ${{ secrets.AZURE_CLIENT_ID != '' }}
if: ${{ needs.check-credentials.outputs.auth_type == 'oidc' }}
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Azure Login (Legacy)
if: ${{ secrets.AZURE_CLIENT_ID == '' && secrets.AZURE_CREDENTIALS != '' }}
if: ${{ needs.check-credentials.outputs.auth_type == 'legacy' }}
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
Expand Down Expand Up @@ -254,15 +258,15 @@
uses: actions/checkout@v4

- name: Azure Login (OIDC)
if: ${{ secrets.AZURE_CLIENT_ID != '' }}
if: ${{ needs.check-credentials.outputs.auth_type == 'oidc' }}
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Azure Login (Legacy)
if: ${{ secrets.AZURE_CLIENT_ID == '' && secrets.AZURE_CREDENTIALS != '' }}
if: ${{ needs.check-credentials.outputs.auth_type == 'legacy' }}
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
Expand Down
86 changes: 86 additions & 0 deletions .github/workflows/test-workflow-logic.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Test Workflow Logic

Check warning on line 1 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

1:1 [document-start] missing document start "---"

# This workflow validates that the Azure relay tests workflow
# correctly detects authentication types without accessing secrets
# in conditional expressions (which doesn't work in GitHub Actions)

on:

Check warning on line 7 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

7:1 [truthy] truthy value should be one of [false, true]
pull_request:
paths:
- '.github/workflows/azure-relay-tests.yml'
- '.github/workflows/test-workflow-logic.yml'

jobs:
validate-auth-detection:
name: Validate Auth Type Detection Logic
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

Check failure on line 20 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

20:1 [trailing-spaces] trailing spaces
- name: Verify auth_type output exists
run: |
# Check that the check-credentials job outputs auth_type
if ! grep -q "auth_type:" .github/workflows/azure-relay-tests.yml; then

Check failure on line 24 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

24:81 [line-length] line too long (81 > 80 characters)
echo "❌ FAIL: auth_type output not found in check-credentials job"
exit 1
fi
echo "✅ PASS: auth_type output exists"

Check failure on line 29 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

29:1 [trailing-spaces] trailing spaces
- name: Verify auth_type is set in all branches
run: |
# Check that all conditional branches set auth_type
if ! grep -q 'echo "auth_type=oidc"' .github/workflows/azure-relay-tests.yml; then

Check failure on line 33 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

33:81 [line-length] line too long (92 > 80 characters)
echo "❌ FAIL: OIDC auth_type not set"
exit 1
fi
if ! grep -q 'echo "auth_type=legacy"' .github/workflows/azure-relay-tests.yml; then

Check failure on line 37 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

37:81 [line-length] line too long (94 > 80 characters)
echo "❌ FAIL: Legacy auth_type not set"
exit 1
fi
if ! grep -q 'echo "auth_type=none"' .github/workflows/azure-relay-tests.yml; then

Check failure on line 41 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

41:81 [line-length] line too long (92 > 80 characters)
echo "❌ FAIL: None auth_type not set"
exit 1
fi
echo "✅ PASS: All auth_type values are set"

Check failure on line 46 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

46:1 [trailing-spaces] trailing spaces
- name: Verify no direct secret checks in conditionals
run: |
# Verify that Azure Login steps don't check secrets directly
# The pattern "if: ${{ secrets." followed by login steps indicates the bug

Check failure on line 50 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

50:81 [line-length] line too long (84 > 80 characters)

Check failure on line 51 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

51:1 [trailing-spaces] trailing spaces
# Extract Azure Login sections and check their conditionals
if grep -A 5 "name: Azure Login" .github/workflows/azure-relay-tests.yml | grep -q 'if:.*secrets\.AZURE_CLIENT_ID'; then

Check failure on line 53 in .github/workflows/test-workflow-logic.yml

View workflow job for this annotation

GitHub Actions / copilot

53:81 [line-length] line too long (130 > 80 characters)
echo "❌ FAIL: Found direct secret check in Azure Login conditional"
echo "This is the bug we're fixing - secrets are not accessible in if conditionals"
exit 1
fi
echo "✅ PASS: No direct secret checks in Azure Login conditionals"

- name: Verify correct auth_type usage
run: |
# Verify that Azure Login steps use auth_type output
if ! grep -A 5 "name: Azure Login (OIDC)" .github/workflows/azure-relay-tests.yml | grep -q "auth_type == 'oidc'"; then
echo "❌ FAIL: OIDC login doesn't check auth_type"
exit 1
fi
if ! grep -A 5 "name: Azure Login (Legacy)" .github/workflows/azure-relay-tests.yml | grep -q "auth_type == 'legacy'"; then
echo "❌ FAIL: Legacy login doesn't check auth_type"
exit 1
fi
echo "✅ PASS: Azure Login steps correctly use auth_type"

- name: Summary
run: |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ All workflow logic validation checks passed"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "The Azure relay tests workflow correctly:"
echo " ✓ Detects auth type in shell context (where secrets work)"
echo " ✓ Uses job outputs for conditionals (not direct secret checks)"
echo " ✓ Sets auth_type for all code paths (oidc/legacy/none)"
echo " ✓ Uses auth_type in Azure Login conditionals"
echo ""
echo "This prevents the bug where secrets.AZURE_CLIENT_ID != ''"
echo "always evaluates to false in GitHub Actions if conditionals."