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
5.7 KiB
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:
.github/workflows/docker-build.yml→test-imagejob.github/workflows/e2e-tests.yml→e2e-testsjob.github/workflows/playwright.yml→playwrightjob
Before:
jobs:
test-image:
name: Test Docker Image
runs-on: ubuntu-latest
steps: ...
After:
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:
- 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:
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 ⚠️
# 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:
- 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
- Critical: Added
CHARON_EMERGENCY_TOKENto all E2E workflow environments - Verified: Docker build/push strategy is optimal (no changes needed)
- Confirmed: Test strategy is correct (no duplicate testing needed)
⚠️ Action Required
- Add
CHARON_EMERGENCY_TOKENsecret to GitHub repository (generate withopenssl 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:
.envsetup for local development