Skip to content

API-55276: Update to FakeController #33625

API-55276: Update to FakeController

API-55276: Update to FakeController #33625

# Validates backend approval requirements for PRs
# Runs on PR updates and review submissions to ensure proper approval from backend-review-group
# or exemption through team-based file ownership
name: Backend Approval
on:
pull_request_review:
types: [submitted, dismissed]
permissions:
id-token: write
contents: read
pull-requests: write
concurrency:
group: backend-approval-${{ github.event.pull_request.number }}
cancel-in-progress: true
env:
AWS_REGION: us-gov-west-1
SSM_BOT_TOKEN_PATH: /devops/VA_VSP_BOT_GITHUB_TOKEN
jobs:
backend-approval-check:
if: ${{ github.actor != 'github-copilot' }}
name: Succeed if backend approval is confirmed
runs-on: ubuntu-latest
permissions: write-all
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Fetch PR data and changed files
id: pr_info
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_NUMBER="${{ github.event.pull_request.number }}"
echo "pr_number=${PR_NUMBER}" >> "$GITHUB_OUTPUT"
# Fetch PR metadata
PR_DATA=$(gh api /repos/${{ github.repository }}/pulls/${PR_NUMBER} --jq '{
author: .user.login,
draft: .draft,
labels: [.labels[].name]
}')
echo "pr_author=$(echo "$PR_DATA" | jq -r '.author')" >> "$GITHUB_OUTPUT"
echo "pr_draft=$(echo "$PR_DATA" | jq -r '.draft')" >> "$GITHUB_OUTPUT"
echo "pr_labels=$(echo "$PR_DATA" | jq -c '.labels')" >> "$GITHUB_OUTPUT"
# Fetch changed files (handles pagination automatically)
CHANGED_FILES=$(gh api "/repos/${{ github.repository }}/pulls/${PR_NUMBER}/files" \
--paginate --jq '.[] | select(.status != "removed") | .filename')
echo "$CHANGED_FILES" > /tmp/changed_files.txt
FILE_COUNT=$(echo "$CHANGED_FILES" | wc -l)
echo "file_count=${FILE_COUNT}" >> "$GITHUB_OUTPUT"
echo "PR #${PR_NUMBER} Analysis"
echo " Author: $(echo "$PR_DATA" | jq -r '.author')"
echo " Draft: $(echo "$PR_DATA" | jq -r '.draft')"
echo " Changed files: ${FILE_COUNT}"
- name: Analyze file ownership against CODEOWNERS
id: file_ownership
run: |
if [[ ! -s /tmp/changed_files.txt ]]; then
echo "all_files_exempt=true" >> "$GITHUB_OUTPUT"
exit 0
fi
CODEOWNERS_FILE=".github/CODEOWNERS"
if [[ ! -f "$CODEOWNERS_FILE" ]]; then
echo "[ERROR] CODEOWNERS file not found"
echo "all_files_exempt=false" >> "$GITHUB_OUTPUT"
exit 0
fi
EXEMPT_TEAM_ARRAY=(
"octo-identity"
"mobile-api-team"
)
all_files_exempt=true
echo "Analyzing Code Owners"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
while IFS= read -r file || [[ -n "$file" ]]; do
[[ -z "$file" ]] && continue
echo "File: $file"
result=$(awk -v f="$file" '
$0 !~ /^#/ && NF > 0 {
p = $1
orig = p
gsub(/\*\*\//, "<!DS!>", p)
gsub(/\*/, "<!S!>", p)
if (p ~ /\/$/) sub(/\/$/, "/<!S!>", p)
else if (p !~ /<!S!>/ && p !~ /<!DS!>/ && p !~ /\./) p = "(" p "$|" p "/<!S!>)"
gsub(/\./, "\\.", p)
gsub(/<!DS!>/, ".*", p)
gsub(/<!S!>/, ".*", p)
if (f ~ "^" p) {
pattern = orig
owners = ""
for (i=2; i<=NF; i++) owners = owners $i " "
}
}
END {
if (pattern && owners) {
print pattern
print owners
exit 0
}
exit 1
}
' "$CODEOWNERS_FILE")
if [[ $? -ne 0 || -z "$result" ]]; then
echo " Pattern matched: (none)"
echo " Code owners: (none)"
echo " Status: [X] REQUIRES APPROVAL"
echo ""
all_files_exempt=false
continue
fi
pattern=$(echo "$result" | head -1)
owners=$(echo "$result" | tail -1)
echo " Pattern matched: \"$pattern\""
echo " Code owners: $owners"
file_is_exempt=false
for team in "${EXEMPT_TEAM_ARRAY[@]}"; do
if echo "$owners" | grep -q "@department-of-veterans-affairs/${team}"; then
echo " Status: [OK] EXEMPT (via team: $team)"
file_is_exempt=true
break
fi
done
if [[ "$file_is_exempt" == "false" ]]; then
echo " Status: [X] REQUIRES APPROVAL"
all_files_exempt=false
fi
echo ""
done < /tmp/changed_files.txt
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [[ "$all_files_exempt" == "true" ]]; then
echo "All files are exempt"
else
echo "Some files require backend approval"
fi
echo "all_files_exempt=${all_files_exempt}" >> "$GITHUB_OUTPUT"
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6
with:
role-to-assume: ${{ vars.AWS_ASSUME_ROLE }}
aws-region: ${{ env.AWS_REGION }}
# VA_VSP_BOT_GITHUB_TOKEN is required to access organization team membership
- name: Retrieve bot token from AWS SSM
uses: marvinpinto/action-inject-ssm-secrets@40db08dfe313758837e611cac1679e3a89b35531 # latest
with:
ssm_parameter: ${{ env.SSM_BOT_TOKEN_PATH }}
env_variable_name: VA_VSP_BOT_GITHUB_TOKEN
- name: Determine approval status
id: approval_status
env:
GITHUB_TOKEN: ${{ env.VA_VSP_BOT_GITHUB_TOKEN }}
PR_NUMBER: ${{ steps.pr_info.outputs.pr_number }}
ALL_FILES_EXEMPT: ${{ steps.file_ownership.outputs.all_files_exempt }}
run: |
exempt=false
exempt_reason=""
backend_approved=false
requires_approval=true
echo "Determining approval requirements"
echo "----------------------------------------"
# Check: Are all files owned by exempt teams?
if [[ "${ALL_FILES_EXEMPT}" == "true" ]]; then
echo "[PASS] Exempt: All files owned by exempt teams"
exempt=true
exempt_reason="file ownership"
requires_approval=false
fi
# If not exempt, verify backend approval
if [[ "${requires_approval}" == "true" ]]; then
echo "Checking for backend-review-group approval..."
# Fetch backend-review-group members
BACKEND_REVIEWERS=$(gh api /orgs/department-of-veterans-affairs/teams/backend-review-group/members --jq '.[].login')
BACKEND_REVIEWERS=$(echo "$BACKEND_REVIEWERS" | tr '\n' '|' | sed 's/|$//')
echo " Backend reviewers: ${BACKEND_REVIEWERS}"
# Get most recent review state per user
REVIEWS_JSON=$(gh api /repos/${{ github.repository }}/pulls/${PR_NUMBER}/reviews --paginate --jq '
.[] | select(.state == "APPROVED") | {login: .user.login, submitted_at: .submitted_at}
' 2>/dev/null || echo "[]")
readarray -t APPROVALS < <(
echo "$REVIEWS_JSON" | jq -s '
sort_by(.submitted_at)
| reverse
| unique_by(.login)
| .[].login
' -r 2>/dev/null || true
)
# Check if any approver is from backend-review-group
for approver in "${APPROVALS[@]}"; do
if echo "$approver" | grep -iqE "^(${BACKEND_REVIEWERS})$"; then
echo "[PASS] Backend approval confirmed by: ${approver}"
backend_approved=true
requires_approval=false
break
fi
done
if [[ "${backend_approved}" == "false" ]]; then
echo "No approval from backend-review-group"
fi
fi
echo "----------------------------------------"
echo "Final Status:"
echo " Exempt: ${exempt}"
[[ "${exempt}" == "true" ]] && echo " Exempt Reason: ${exempt_reason}"
echo " Backend Approved: ${backend_approved}"
echo " Requires Approval: ${requires_approval}"
# Output results for subsequent steps
echo "exempt=${exempt}" >> "$GITHUB_OUTPUT"
echo "exempt_reason=${exempt_reason}" >> "$GITHUB_OUTPUT"
echo "backend_approved=${backend_approved}" >> "$GITHUB_OUTPUT"
echo "requires_approval=${requires_approval}" >> "$GITHUB_OUTPUT"
- name: Update PR labels
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ steps.pr_info.outputs.pr_number }}
EXEMPT: ${{ steps.approval_status.outputs.exempt }}
REQUIRES_APPROVAL: ${{ steps.approval_status.outputs.requires_approval }}
run: |
echo "Updating PR labels..."
# Determine which labels to add/remove based on status
LABELS_TO_ADD=()
LABELS_TO_REMOVE=()
if [[ "${EXEMPT}" == "true" ]]; then
LABELS_TO_ADD+=("exempt-be-review")
LABELS_TO_REMOVE+=("require-backend-approval")
else
LABELS_TO_REMOVE+=("exempt-be-review")
fi
if [[ "${REQUIRES_APPROVAL}" == "true" ]]; then
LABELS_TO_ADD+=("require-backend-approval")
else
LABELS_TO_REMOVE+=("require-backend-approval")
fi
# Apply label changes
for label in "${LABELS_TO_REMOVE[@]}"; do
echo " Removing: ${label}"
gh pr edit "${PR_NUMBER}" --remove-label "${label}" 2>/dev/null || echo " [WARN] Could not remove ${label}"
done
for label in "${LABELS_TO_ADD[@]}"; do
echo " Adding: ${label}"
gh pr edit "${PR_NUMBER}" --add-label "${label}" 2>/dev/null || echo " [WARN] Could not add ${label}"
done
- name: Fail if backend approval required
if: steps.approval_status.outputs.requires_approval == 'true'
run: |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "[FAIL] BACKEND APPROVAL REQUIRED"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "This PR requires approval from the backend-review-group before merging."
echo ""
echo "To get your PR exempt from this requirement, ensure:"
echo " • All changed files are owned exclusively by exempt teams in CODEOWNERS"
echo " • Exempt teams: octo-identity, mobile-api-team"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
exit 1
- name: Confirm approval success
if: steps.approval_status.outputs.requires_approval == 'false'
run: |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "[PASS] APPROVAL CHECK PASSED"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [[ "${{ steps.approval_status.outputs.exempt }}" == "true" ]]; then
echo ""
echo "PR is exempt from backend approval requirement"
echo "Reason: ${{ steps.approval_status.outputs.exempt_reason }}"
else
echo ""
echo "Backend approval has been confirmed"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
exit 0