Files
Charon/docs/implementation/WORKFLOW_REVIEW_2026-01-26.md
GitHub Actions ac803fd411 fix(ci): add CHARON_EMERGENCY_TOKEN to E2E test workflows
Add missing emergency token environment variable to all E2E test workflows to
fix security teardown failures in CI. Without this token, the emergency reset
endpoint returns 501 "not configured", causing test teardown to fail and
leaving ACL enabled, which blocks 83 subsequent tests.

Changes:

Add CHARON_EMERGENCY_TOKEN to docker-build.yml test-image job
Add CHARON_EMERGENCY_TOKEN to e2e-tests.yml e2e-tests job
Add CHARON_EMERGENCY_TOKEN to playwright.yml playwright job
Verified:

Docker build strategy already optimal (build once, push to both GHCR + Docker Hub)
Testing strategy correct (test once by digest, validates both registries)
All workflows now have environment parity with local development setup
Requires GitHub repository secret:

Name: CHARON_EMERGENCY_TOKEN
Value: 64-char hex token (e.g., from openssl rand -hex 32)
Related:

Emergency endpoint rate limiting removal (proper fix)
Local emergency token configuration (.env, docker-compose.local.yml)
Security test suite teardown mechanism
Refs #550
2026-01-26 20:03:30 +00:00

182 lines
5.7 KiB
Markdown

# Workflow Review - Emergency Token & Docker Registry Strategy
**Date**: January 26, 2026
**Status**: ✅ Critical fixes applied
**PR**: #550 (Docker Debian Trixie migration)
## Critical Issue Fixed ❌→✅
### Problem
All E2E test workflows were missing `CHARON_EMERGENCY_TOKEN` environment variable, causing security teardown failures identical to the local issue we just resolved.
**Impact**:
- Security teardown would fail with 501 "not configured" error
- Caused cascading test failures (83 tests blocked by ACL)
- CI/CD pipeline would report false failures
### Solution Applied
Added `CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }}` to environment variables in:
1. **`.github/workflows/docker-build.yml`** → `test-image` job
2. **`.github/workflows/e2e-tests.yml`** → `e2e-tests` job
3. **`.github/workflows/playwright.yml`** → `playwright` job
**Before**:
```yaml
jobs:
test-image:
name: Test Docker Image
runs-on: ubuntu-latest
steps: ...
```
**After**:
```yaml
jobs:
test-image:
name: Test Docker Image
runs-on: ubuntu-latest
env:
# Required for security teardown in integration tests
CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }}
steps: ...
```
---
## Docker Registry Strategy Review ✅
### Current Setup (Optimal)
**`docker-build.yml`** implements the recommended "build once, push twice" strategy:
```yaml
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }} # Contains both GHCR + Docker Hub tags
- name: Sign GHCR Image
run: cosign sign --yes ${{ env.GHCR_REGISTRY }}/...@${{ digest }}
- name: Sign Docker Hub Image
run: cosign sign --yes ${{ env.DOCKERHUB_REGISTRY }}/...@${{ digest }}
```
**Verification**:
✅ Single multi-arch build
✅ Same digest pushed to both registries
✅ Both images signed with Cosign
✅ SBOM generated and attached
✅ No duplicate builds or testing
### Why This Is Correct
- **Immutable artifact**: One build = one digest = one set of binaries
- **Efficient**: No rebuilding or re-testing needed
- **Supply chain security**: Same SBOM and signatures for both registries
- **Cost-effective**: Minimal CI/CD minutes
---
## Testing Strategy Review ✅
### Current Approach
Tests are run **once** against the built image (by digest), not separately per registry:
```yaml
test-image:
steps:
- name: Pull Docker image
run: docker pull ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}
- name: Run Integration Test
run: ./scripts/integration-test.sh
```
**Why This Is Correct**:
- If the image digest is identical across registries (which it is), testing once validates both
- Registry-specific concerns (access, visibility) are tested by push/pull operations themselves
- E2E tests focus on **application functionality**, not registry operations
---
## Recommendations for GitHub Secrets
### Required Repository Secrets
Add these to **Settings → Secrets and variables → Actions → Repository secrets**:
| Secret Name | Purpose | How to Generate | Status |
|------------|---------|-----------------|--------|
| `CHARON_EMERGENCY_TOKEN` | Security teardown in E2E tests | `openssl rand -hex 32` | ⚠️ **Missing** |
| `CHARON_CI_ENCRYPTION_KEY` | Database encryption in tests | `openssl rand -base64 32` | ✅ Exists |
| `DOCKERHUB_USERNAME` | Docker Hub authentication | Your Docker Hub username | ✅ Exists |
| `DOCKERHUB_TOKEN` | Docker Hub push access | Create at hub.docker.com/settings/security | ✅ Exists |
| `CODECOV_TOKEN` | Coverage upload | From codecov.io project settings | ✅ Exists |
### Action Required ⚠️
```bash
# Generate emergency token for CI (same format as local .env)
openssl rand -hex 32
# Add as CHARON_EMERGENCY_TOKEN in GitHub repo secrets
# Navigate to: https://github.com/Wikid82/Charon/settings/secrets/actions/new
```
---
## Smoke Test Command (Optional Enhancement)
To add explicit registry verification, consider this optional enhancement to `docker-build.yml`:
```yaml
- name: Verify Both Registries (Optional Smoke Test)
if: github.event_name != 'pull_request'
run: |
# Pull from GHCR
docker pull ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
GHCR_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ...)
# Pull from Docker Hub
docker pull ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
DOCKERHUB_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ...)
# Compare digests
if [[ "$GHCR_DIGEST" != "$DOCKERHUB_DIGEST" ]]; then
echo "❌ Digest mismatch between registries!"
exit 1
fi
# Verify signatures exist
cosign verify $GHCR_DIGEST
cosign verify $DOCKERHUB_DIGEST
```
**Recommendation**: This is **optional** and adds ~30 seconds to CI. Only add if you've experienced registry sync issues in the past.
---
## Summary
### ✅ What Was Fixed
1. **Critical**: Added `CHARON_EMERGENCY_TOKEN` to all E2E workflow environments
2. **Verified**: Docker build/push strategy is optimal (no changes needed)
3. **Confirmed**: Test strategy is correct (no duplicate testing needed)
### ⚠️ Action Required
- Add `CHARON_EMERGENCY_TOKEN` secret to GitHub repository (generate with `openssl rand -hex 32`)
### ✅ Already Optimal
- Docker multi-registry push strategy
- Image signing and SBOM generation
- Test execution approach
---
## Files Modified
- `.github/workflows/docker-build.yml`
- `.github/workflows/e2e-tests.yml`
- `.github/workflows/playwright.yml`
## Related
- Issue: Security teardown failures in CI
- Fix: Backend emergency endpoint rate limit removal (PR #550)
- Docs: `.env` setup for local development