diff --git a/.github/badges/ghcr-downloads.json b/.github/badges/ghcr-downloads.json deleted file mode 100644 index 4a51303f..00000000 --- a/.github/badges/ghcr-downloads.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "schemaVersion": 1, - "label": "GHCR pulls", - "message": "0", - "color": "blue", - "cacheSeconds": 3600 -} diff --git a/.github/workflows/badge-ghcr-downloads.yml b/.github/workflows/badge-ghcr-downloads.yml deleted file mode 100644 index 17527227..00000000 --- a/.github/workflows/badge-ghcr-downloads.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: "Badge: GHCR downloads" - -on: - schedule: - # Update periodically (GitHub schedules may be delayed) - - cron: '17 * * * *' - workflow_dispatch: {} - -permissions: - contents: write - packages: read - -concurrency: - group: ghcr-downloads-badge - cancel-in-progress: false - -jobs: - update: - runs-on: ubuntu-latest - steps: - - name: Checkout (main) - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - ref: main - - - name: Set up Node - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - with: - node-version: 24.13.1 - - - name: Update GHCR downloads badge - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GHCR_OWNER: ${{ github.repository_owner }} - GHCR_PACKAGE: charon - BADGE_OUTPUT: .github/badges/ghcr-downloads.json - run: node scripts/update-ghcr-downloads-badge.mjs - - - name: Commit and push (if changed) - shell: bash - run: | - set -euo pipefail - - if git diff --quiet; then - echo "No changes." - exit 0 - fi - - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - - git add .github/badges/ghcr-downloads.json - git commit -m "chore(badges): update GHCR downloads [skip ci]" - git push origin HEAD:main diff --git a/.github/workflows/e2e-tests-split.yml.backup b/.github/workflows/e2e-tests-split.yml.backup deleted file mode 100644 index a655fe80..00000000 --- a/.github/workflows/e2e-tests-split.yml.backup +++ /dev/null @@ -1,1170 +0,0 @@ -# E2E Tests Workflow (Reorganized: Security Isolation + Parallel Sharding) -# -# Architecture: 15 Total Jobs -# - 3 Security Enforcement Jobs (1 shard per browser, serial execution, 30min timeout) -# - 12 Non-Security Jobs (4 shards per browser, parallel execution, 20min timeout) -# -# Problem Solved: Cross-shard contamination from security middleware state changes -# Solution: Isolate security enforcement tests in dedicated jobs with Cerberus enabled, -# run all other tests with Cerberus OFF to prevent ACL/rate limit interference -# -# See docs/implementation/E2E_TEST_REORGANIZATION_IMPLEMENTATION.md for full details - -name: 'E2E Tests (Split - Security + Sharded)' - -on: - workflow_run: - workflows: ["Docker Build, Publish & Test"] - types: [completed] - branches: [main, development, 'feature/**', 'hotfix/**'] - pull_request: - branches: [main, development, 'feature/**', 'hotfix/**'] - paths: - - 'frontend/**' - - 'backend/**' - - 'tests/**' - - 'playwright.config.js' - - '.github/workflows/e2e-tests-split.yml' - workflow_dispatch: - inputs: - browser: - description: 'Browser to test' - required: false - default: 'all' - type: choice - options: - - chromium - - firefox - - webkit - - all - test_category: - description: 'Test category' - required: false - default: 'all' - type: choice - options: - - all - - security - - non-security - -env: - NODE_VERSION: '20' - GO_VERSION: '1.25.6' - GOTOOLCHAIN: auto - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository_owner }}/charon - PLAYWRIGHT_COVERAGE: ${{ vars.PLAYWRIGHT_COVERAGE || '0' }} - DEBUG: 'charon:*,charon-test:*' - PLAYWRIGHT_DEBUG: '1' - CI_LOG_LEVEL: 'verbose' - -concurrency: - group: e2e-split-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - # Build application once, share across all browser jobs - build: - name: Build Application - runs-on: ubuntu-latest - outputs: - image_digest: ${{ steps.build-image.outputs.digest }} - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - - name: Set up Go - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6 - with: - go-version: ${{ env.GO_VERSION }} - cache: true - cache-dependency-path: backend/go.sum - - - name: Set up Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Cache npm dependencies - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 - with: - path: ~/.npm - key: npm-${{ hashFiles('package-lock.json') }} - restore-keys: npm- - - - name: Install dependencies - run: npm ci - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - - - name: Build Docker image - id: build-image - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6 - with: - context: . - file: ./Dockerfile - push: false - load: true - tags: charon:e2e-test - cache-from: type=gha - cache-to: type=gha,mode=max - - - name: Save Docker image - run: docker save charon:e2e-test -o charon-e2e-image.tar - - - name: Upload Docker image artifact - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: docker-image - path: charon-e2e-image.tar - retention-days: 1 - - # ================================================================================== - # SECURITY ENFORCEMENT TESTS (3 jobs: 1 per browser, serial execution) - # ================================================================================== - # These tests enable Cerberus middleware and verify security enforcement - # Run serially to avoid cross-test contamination from global state changes - # ================================================================================== - - e2e-chromium-security: - name: E2E Chromium (Security Enforcement) - runs-on: ubuntu-latest - needs: build - if: | - (github.event_name != 'workflow_dispatch') || - (github.event.inputs.browser == 'chromium' || github.event.inputs.browser == 'all') && - (github.event.inputs.test_category == 'security' || github.event.inputs.test_category == 'all') - timeout-minutes: 30 - env: - CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }} - CHARON_EMERGENCY_SERVER_ENABLED: "true" - CHARON_SECURITY_TESTS_ENABLED: "true" # Cerberus ON for enforcement tests - CHARON_E2E_IMAGE_TAG: charon:e2e-test - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - - name: Set up Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Download Docker image - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - name: docker-image - - - name: Validate Emergency Token Configuration - run: | - echo "๐Ÿ” Validating emergency token configuration..." - if [ -z "$CHARON_EMERGENCY_TOKEN" ]; then - echo "::error title=Missing Secret::CHARON_EMERGENCY_TOKEN secret not configured" - exit 1 - fi - TOKEN_LENGTH=${#CHARON_EMERGENCY_TOKEN} - if [ $TOKEN_LENGTH -lt 64 ]; then - echo "::error title=Invalid Token Length::CHARON_EMERGENCY_TOKEN must be at least 64 characters" - exit 1 - fi - MASKED_TOKEN="${CHARON_EMERGENCY_TOKEN:0:8}...${CHARON_EMERGENCY_TOKEN: -4}" - echo "::notice::Emergency token validated (length: $TOKEN_LENGTH, preview: $MASKED_TOKEN)" - env: - CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }} - - - name: Load Docker image - run: | - docker load -i charon-e2e-image.tar - docker images | grep charon - - - name: Generate ephemeral encryption key - run: echo "CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32)" >> $GITHUB_ENV - - - name: Start test environment (Security Tests Profile) - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml --profile security-tests up -d - echo "โœ… Container started for Chromium security enforcement tests" - - - name: Wait for service health - run: | - echo "โณ Waiting for Charon to be healthy..." - MAX_ATTEMPTS=30 - ATTEMPT=0 - while [[ ${ATTEMPT} -lt ${MAX_ATTEMPTS} ]]; do - ATTEMPT=$((ATTEMPT + 1)) - echo "Attempt ${ATTEMPT}/${MAX_ATTEMPTS}..." - if curl -sf http://127.0.0.1:8080/api/v1/health > /dev/null 2>&1; then - echo "โœ… Charon is healthy!" - curl -s http://127.0.0.1:8080/api/v1/health | jq . - exit 0 - fi - sleep 2 - done - echo "โŒ Health check failed" - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs - exit 1 - - - name: Install dependencies - run: npm ci - - - name: Install Playwright Chromium - run: | - echo "๐Ÿ“ฆ Installing Chromium..." - npx playwright install --with-deps chromium - EXIT_CODE=$? - echo "โœ… Install command completed (exit code: $EXIT_CODE)" - exit $EXIT_CODE - - - name: Run Chromium Security Enforcement Tests - run: | - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "Chromium Security Enforcement Tests" - echo "Cerberus: ENABLED" - echo "Execution: SERIAL (no sharding)" - echo "Start Time: $(date -u +'%Y-%m-%dT%H:%M:%SZ')" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - - SHARD_START=$(date +%s) - echo "SHARD_START=$SHARD_START" >> $GITHUB_ENV - - npx playwright test \ - --project=chromium \ - tests/security-enforcement/ - - SHARD_END=$(date +%s) - echo "SHARD_END=$SHARD_END" >> $GITHUB_ENV - SHARD_DURATION=$((SHARD_END - SHARD_START)) - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "Chromium Security Complete | Duration: ${SHARD_DURATION}s" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - env: - PLAYWRIGHT_BASE_URL: http://127.0.0.1:8080 - CI: true - - - name: Upload HTML report (Chromium Security) - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: playwright-report-chromium-security - path: playwright-report/ - retention-days: 14 - - - name: Upload Chromium Security coverage (if enabled) - if: always() && env.PLAYWRIGHT_COVERAGE == '1' - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: e2e-coverage-chromium-security - path: coverage/e2e/ - retention-days: 7 - - - name: Upload test traces on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: traces-chromium-security - path: test-results/**/*.zip - retention-days: 7 - - - name: Collect Docker logs on failure - if: failure() - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs > docker-logs-chromium-security.txt 2>&1 - - - name: Upload Docker logs on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: docker-logs-chromium-security - path: docker-logs-chromium-security.txt - retention-days: 7 - - - name: Cleanup - if: always() - run: docker compose -f .docker/compose/docker-compose.playwright-ci.yml down -v 2>/dev/null || true - - e2e-firefox-security: - name: E2E Firefox (Security Enforcement) - runs-on: ubuntu-latest - needs: build - if: | - (github.event_name != 'workflow_dispatch') || - (github.event.inputs.browser == 'firefox' || github.event.inputs.browser == 'all') && - (github.event.inputs.test_category == 'security' || github.event.inputs.test_category == 'all') - timeout-minutes: 30 - env: - CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }} - CHARON_EMERGENCY_SERVER_ENABLED: "true" - CHARON_SECURITY_TESTS_ENABLED: "true" # Cerberus ON for enforcement tests - CHARON_E2E_IMAGE_TAG: charon:e2e-test - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - - name: Set up Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Download Docker image - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - name: docker-image - - - name: Validate Emergency Token Configuration - run: | - echo "๐Ÿ” Validating emergency token configuration..." - if [ -z "$CHARON_EMERGENCY_TOKEN" ]; then - echo "::error title=Missing Secret::CHARON_EMERGENCY_TOKEN secret not configured" - exit 1 - fi - TOKEN_LENGTH=${#CHARON_EMERGENCY_TOKEN} - if [ $TOKEN_LENGTH -lt 64 ]; then - echo "::error title=Invalid Token Length::CHARON_EMERGENCY_TOKEN must be at least 64 characters" - exit 1 - fi - MASKED_TOKEN="${CHARON_EMERGENCY_TOKEN:0:8}...${CHARON_EMERGENCY_TOKEN: -4}" - echo "::notice::Emergency token validated (length: $TOKEN_LENGTH, preview: $MASKED_TOKEN)" - env: - CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }} - - - name: Load Docker image - run: | - docker load -i charon-e2e-image.tar - docker images | grep charon - - - name: Generate ephemeral encryption key - run: echo "CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32)" >> $GITHUB_ENV - - - name: Start test environment (Security Tests Profile) - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml --profile security-tests up -d - echo "โœ… Container started for Firefox security enforcement tests" - - - name: Wait for service health - run: | - echo "โณ Waiting for Charon to be healthy..." - MAX_ATTEMPTS=30 - ATTEMPT=0 - while [[ ${ATTEMPT} -lt ${MAX_ATTEMPTS} ]]; do - ATTEMPT=$((ATTEMPT + 1)) - echo "Attempt ${ATTEMPT}/${MAX_ATTEMPTS}..." - if curl -sf http://127.0.0.1:8080/api/v1/health > /dev/null 2>&1; then - echo "โœ… Charon is healthy!" - curl -s http://127.0.0.1:8080/api/v1/health | jq . - exit 0 - fi - sleep 2 - done - echo "โŒ Health check failed" - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs - exit 1 - - - name: Install dependencies - run: npm ci - - - name: Install Playwright Chromium (required by security-tests dependency) - run: | - echo "๐Ÿ“ฆ Installing Chromium (required by security-tests dependency)..." - npx playwright install --with-deps chromium - EXIT_CODE=$? - echo "โœ… Install command completed (exit code: $EXIT_CODE)" - exit $EXIT_CODE - - - name: Install Playwright Firefox - run: | - echo "๐Ÿ“ฆ Installing Firefox..." - npx playwright install --with-deps firefox - EXIT_CODE=$? - echo "โœ… Install command completed (exit code: $EXIT_CODE)" - exit $EXIT_CODE - - - name: Run Firefox Security Enforcement Tests - run: | - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "Firefox Security Enforcement Tests" - echo "Cerberus: ENABLED" - echo "Execution: SERIAL (no sharding)" - echo "Start Time: $(date -u +'%Y-%m-%dT%H:%M:%SZ')" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - - SHARD_START=$(date +%s) - echo "SHARD_START=$SHARD_START" >> $GITHUB_ENV - - npx playwright test \ - --project=firefox \ - tests/security-enforcement/ - - SHARD_END=$(date +%s) - echo "SHARD_END=$SHARD_END" >> $GITHUB_ENV - SHARD_DURATION=$((SHARD_END - SHARD_START)) - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "Firefox Security Complete | Duration: ${SHARD_DURATION}s" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - env: - PLAYWRIGHT_BASE_URL: http://127.0.0.1:8080 - CI: true - - - name: Upload HTML report (Firefox Security) - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: playwright-report-firefox-security - path: playwright-report/ - retention-days: 14 - - - name: Upload Firefox Security coverage (if enabled) - if: always() && env.PLAYWRIGHT_COVERAGE == '1' - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: e2e-coverage-firefox-security - path: coverage/e2e/ - retention-days: 7 - - - name: Upload test traces on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: traces-firefox-security - path: test-results/**/*.zip - retention-days: 7 - - - name: Collect Docker logs on failure - if: failure() - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs > docker-logs-firefox-security.txt 2>&1 - - - name: Upload Docker logs on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: docker-logs-firefox-security - path: docker-logs-firefox-security.txt - retention-days: 7 - - - name: Cleanup - if: always() - run: docker compose -f .docker/compose/docker-compose.playwright-ci.yml down -v 2>/dev/null || true - - e2e-webkit-security: - name: E2E WebKit (Security Enforcement) - runs-on: ubuntu-latest - needs: build - if: | - (github.event_name != 'workflow_dispatch') || - (github.event.inputs.browser == 'webkit' || github.event.inputs.browser == 'all') && - (github.event.inputs.test_category == 'security' || github.event.inputs.test_category == 'all') - timeout-minutes: 30 - env: - CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }} - CHARON_EMERGENCY_SERVER_ENABLED: "true" - CHARON_SECURITY_TESTS_ENABLED: "true" # Cerberus ON for enforcement tests - CHARON_E2E_IMAGE_TAG: charon:e2e-test - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - - name: Set up Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Download Docker image - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - name: docker-image - - - name: Validate Emergency Token Configuration - run: | - echo "๐Ÿ” Validating emergency token configuration..." - if [ -z "$CHARON_EMERGENCY_TOKEN" ]; then - echo "::error title=Missing Secret::CHARON_EMERGENCY_TOKEN secret not configured" - exit 1 - fi - TOKEN_LENGTH=${#CHARON_EMERGENCY_TOKEN} - if [ $TOKEN_LENGTH -lt 64 ]; then - echo "::error title=Invalid Token Length::CHARON_EMERGENCY_TOKEN must be at least 64 characters" - exit 1 - fi - MASKED_TOKEN="${CHARON_EMERGENCY_TOKEN:0:8}...${CHARON_EMERGENCY_TOKEN: -4}" - echo "::notice::Emergency token validated (length: $TOKEN_LENGTH, preview: $MASKED_TOKEN)" - env: - CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }} - - - name: Load Docker image - run: | - docker load -i charon-e2e-image.tar - docker images | grep charon - - - name: Generate ephemeral encryption key - run: echo "CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32)" >> $GITHUB_ENV - - - name: Start test environment (Security Tests Profile) - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml --profile security-tests up -d - echo "โœ… Container started for WebKit security enforcement tests" - - - name: Wait for service health - run: | - echo "โณ Waiting for Charon to be healthy..." - MAX_ATTEMPTS=30 - ATTEMPT=0 - while [[ ${ATTEMPT} -lt ${MAX_ATTEMPTS} ]]; do - ATTEMPT=$((ATTEMPT + 1)) - echo "Attempt ${ATTEMPT}/${MAX_ATTEMPTS}..." - if curl -sf http://127.0.0.1:8080/api/v1/health > /dev/null 2>&1; then - echo "โœ… Charon is healthy!" - curl -s http://127.0.0.1:8080/api/v1/health | jq . - exit 0 - fi - sleep 2 - done - echo "โŒ Health check failed" - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs - exit 1 - - - name: Install dependencies - run: npm ci - - - name: Install Playwright Chromium (required by security-tests dependency) - run: | - echo "๐Ÿ“ฆ Installing Chromium (required by security-tests dependency)..." - npx playwright install --with-deps chromium - EXIT_CODE=$? - echo "โœ… Install command completed (exit code: $EXIT_CODE)" - exit $EXIT_CODE - - - name: Install Playwright WebKit - run: | - echo "๐Ÿ“ฆ Installing WebKit..." - npx playwright install --with-deps webkit - EXIT_CODE=$? - echo "โœ… Install command completed (exit code: $EXIT_CODE)" - exit $EXIT_CODE - - - name: Run WebKit Security Enforcement Tests - run: | - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "WebKit Security Enforcement Tests" - echo "Cerberus: ENABLED" - echo "Execution: SERIAL (no sharding)" - echo "Start Time: $(date -u +'%Y-%m-%dT%H:%M:%SZ')" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - - SHARD_START=$(date +%s) - echo "SHARD_START=$SHARD_START" >> $GITHUB_ENV - - npx playwright test \ - --project=webkit \ - tests/security-enforcement/ - - SHARD_END=$(date +%s) - echo "SHARD_END=$SHARD_END" >> $GITHUB_ENV - SHARD_DURATION=$((SHARD_END - SHARD_START)) - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "WebKit Security Complete | Duration: ${SHARD_DURATION}s" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - env: - PLAYWRIGHT_BASE_URL: http://127.0.0.1:8080 - CI: true - - - name: Upload HTML report (WebKit Security) - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: playwright-report-webkit-security - path: playwright-report/ - retention-days: 14 - - - name: Upload WebKit Security coverage (if enabled) - if: always() && env.PLAYWRIGHT_COVERAGE == '1' - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: e2e-coverage-webkit-security - path: coverage/e2e/ - retention-days: 7 - - - name: Upload test traces on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: traces-webkit-security - path: test-results/**/*.zip - retention-days: 7 - - - name: Collect Docker logs on failure - if: failure() - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs > docker-logs-webkit-security.txt 2>&1 - - - name: Upload Docker logs on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: docker-logs-webkit-security - path: docker-logs-webkit-security.txt - retention-days: 7 - - - name: Cleanup - if: always() - run: docker compose -f .docker/compose/docker-compose.playwright-ci.yml down -v 2>/dev/null || true - - # ================================================================================== - # NON-SECURITY TESTS (12 jobs: 4 shards ร— 3 browsers, parallel execution) - # ==================================================================================================== - # These tests run with Cerberus DISABLED to prevent ACL/rate limit interference - # Sharded for performance: 4 shards per browser for faster execution - # ================================================================================== - - e2e-chromium: - name: E2E Chromium (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) - runs-on: ubuntu-latest - needs: build - if: | - (github.event_name != 'workflow_dispatch') || - (github.event.inputs.browser == 'chromium' || github.event.inputs.browser == 'all') && - (github.event.inputs.test_category == 'non-security' || github.event.inputs.test_category == 'all') - timeout-minutes: 20 - env: - CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }} - CHARON_EMERGENCY_SERVER_ENABLED: "true" - CHARON_SECURITY_TESTS_ENABLED: "false" # Cerberus OFF for non-security tests - CHARON_E2E_IMAGE_TAG: charon:e2e-test - strategy: - fail-fast: false - matrix: - shard: [1, 2, 3, 4] - total-shards: [4] - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - - name: Set up Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Download Docker image - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - name: docker-image - - - name: Load Docker image - run: | - docker load -i charon-e2e-image.tar - docker images | grep charon - - - name: Generate ephemeral encryption key - run: echo "CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32)" >> $GITHUB_ENV - - - name: Start test environment (Non-Security Profile) - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml up -d - echo "โœ… Container started for Chromium non-security tests (Cerberus OFF)" - - - name: Wait for service health - run: | - echo "โณ Waiting for Charon to be healthy..." - MAX_ATTEMPTS=30 - ATTEMPT=0 - while [[ ${ATTEMPT} -lt ${MAX_ATTEMPTS} ]]; do - ATTEMPT=$((ATTEMPT + 1)) - echo "Attempt ${ATTEMPT}/${MAX_ATTEMPTS}..." - if curl -sf http://127.0.0.1:8080/api/v1/health > /dev/null 2>&1; then - echo "โœ… Charon is healthy!" - curl -s http://127.0.0.1:8080/api/v1/health | jq . - exit 0 - fi - sleep 2 - done - echo "โŒ Health check failed" - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs - exit 1 - - - name: Install dependencies - run: npm ci - - - name: Install Playwright Chromium - run: | - echo "๐Ÿ“ฆ Installing Chromium..." - npx playwright install --with-deps chromium - EXIT_CODE=$? - echo "โœ… Install command completed (exit code: $EXIT_CODE)" - exit $EXIT_CODE - - - name: Run Chromium Non-Security Tests (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) - run: | - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "Chromium Non-Security Tests - Shard ${{ matrix.shard }}/${{ matrix.total-shards }}" - echo "Cerberus: DISABLED" - echo "Execution: PARALLEL (sharded)" - echo "Start Time: $(date -u +'%Y-%m-%dT%H:%M:%SZ')" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - - SHARD_START=$(date +%s) - echo "SHARD_START=$SHARD_START" >> $GITHUB_ENV - - npx playwright test \ - --project=chromium \ - --shard=${{ matrix.shard }}/${{ matrix.total-shards }} \ - tests/core \ - tests/dns-provider-crud.spec.ts \ - tests/dns-provider-types.spec.ts \ - tests/emergency-server \ - tests/integration \ - tests/manual-dns-provider.spec.ts \ - tests/monitoring \ - tests/security \ - tests/settings \ - tests/tasks - - SHARD_END=$(date +%s) - echo "SHARD_END=$SHARD_END" >> $GITHUB_ENV - SHARD_DURATION=$((SHARD_END - SHARD_START)) - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "Chromium Shard ${{ matrix.shard }} Complete | Duration: ${SHARD_DURATION}s" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - env: - PLAYWRIGHT_BASE_URL: http://127.0.0.1:8080 - CI: true - TEST_WORKER_INDEX: ${{ matrix.shard }} - - - name: Upload HTML report (Chromium shard ${{ matrix.shard }}) - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: playwright-report-chromium-shard-${{ matrix.shard }} - path: playwright-report/ - retention-days: 14 - - - name: Upload Chromium coverage (if enabled) - if: always() && env.PLAYWRIGHT_COVERAGE == '1' - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: e2e-coverage-chromium-shard-${{ matrix.shard }} - path: coverage/e2e/ - retention-days: 7 - - - name: Upload test traces on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: traces-chromium-shard-${{ matrix.shard }} - path: test-results/**/*.zip - retention-days: 7 - - - name: Collect Docker logs on failure - if: failure() - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs > docker-logs-chromium-shard-${{ matrix.shard }}.txt 2>&1 - - - name: Upload Docker logs on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: docker-logs-chromium-shard-${{ matrix.shard }} - path: docker-logs-chromium-shard-${{ matrix.shard }}.txt - retention-days: 7 - - - name: Cleanup - if: always() - run: docker compose -f .docker/compose/docker-compose.playwright-ci.yml down -v 2>/dev/null || true - - e2e-firefox: - name: E2E Firefox (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) - runs-on: ubuntu-latest - needs: build - if: | - (github.event_name != 'workflow_dispatch') || - (github.event.inputs.browser == 'firefox' || github.event.inputs.browser == 'all') && - (github.event.inputs.test_category == 'non-security' || github.event.inputs.test_category == 'all') - timeout-minutes: 20 - env: - CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }} - CHARON_EMERGENCY_SERVER_ENABLED: "true" - CHARON_SECURITY_TESTS_ENABLED: "false" # Cerberus OFF for non-security tests - CHARON_E2E_IMAGE_TAG: charon:e2e-test - strategy: - fail-fast: false - matrix: - shard: [1, 2, 3, 4] - total-shards: [4] - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - - name: Set up Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Download Docker image - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - name: docker-image - - - name: Load Docker image - run: | - docker load -i charon-e2e-image.tar - docker images | grep charon - - - name: Generate ephemeral encryption key - run: echo "CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32)" >> $GITHUB_ENV - - - name: Start test environment (Non-Security Profile) - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml up -d - echo "โœ… Container started for Firefox non-security tests (Cerberus OFF)" - - - name: Wait for service health - run: | - echo "โณ Waiting for Charon to be healthy..." - MAX_ATTEMPTS=30 - ATTEMPT=0 - while [[ ${ATTEMPT} -lt ${MAX_ATTEMPTS} ]]; do - ATTEMPT=$((ATTEMPT + 1)) - echo "Attempt ${ATTEMPT}/${MAX_ATTEMPTS}..." - if curl -sf http://127.0.0.1:8080/api/v1/health > /dev/null 2>&1; then - echo "โœ… Charon is healthy!" - curl -s http://127.0.0.1:8080/api/v1/health | jq . - exit 0 - fi - sleep 2 - done - echo "โŒ Health check failed" - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs - exit 1 - - - name: Install dependencies - run: npm ci - - - name: Install Playwright Firefox - run: | - echo "๐Ÿ“ฆ Installing Firefox..." - npx playwright install --with-deps firefox - EXIT_CODE=$? - echo "โœ… Install command completed (exit code: $EXIT_CODE)" - exit $EXIT_CODE - - - name: Run Firefox Non-Security Tests (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) - run: | - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "Firefox Non-Security Tests - Shard ${{ matrix.shard }}/${{ matrix.total-shards }}" - echo "Cerberus: DISABLED" - echo "Execution: PARALLEL (sharded)" - echo "Start Time: $(date -u +'%Y-%m-%dT%H:%M:%SZ')" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - - SHARD_START=$(date +%s) - echo "SHARD_START=$SHARD_START" >> $GITHUB_ENV - - npx playwright test \ - --project=firefox \ - --shard=${{ matrix.shard }}/${{ matrix.total-shards }} \ - tests/core \ - tests/dns-provider-crud.spec.ts \ - tests/dns-provider-types.spec.ts \ - tests/emergency-server \ - tests/integration \ - tests/manual-dns-provider.spec.ts \ - tests/monitoring \ - tests/security \ - tests/settings \ - tests/tasks - - SHARD_END=$(date +%s) - echo "SHARD_END=$SHARD_END" >> $GITHUB_ENV - SHARD_DURATION=$((SHARD_END - SHARD_START)) - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "Firefox Shard ${{ matrix.shard }} Complete | Duration: ${SHARD_DURATION}s" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - env: - PLAYWRIGHT_BASE_URL: http://127.0.0.1:8080 - CI: true - TEST_WORKER_INDEX: ${{ matrix.shard }} - - - name: Upload HTML report (Firefox shard ${{ matrix.shard }}) - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: playwright-report-firefox-shard-${{ matrix.shard }} - path: playwright-report/ - retention-days: 14 - - - name: Upload Firefox coverage (if enabled) - if: always() && env.PLAYWRIGHT_COVERAGE == '1' - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: e2e-coverage-firefox-shard-${{ matrix.shard }} - path: coverage/e2e/ - retention-days: 7 - - - name: Upload test traces on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: traces-firefox-shard-${{ matrix.shard }} - path: test-results/**/*.zip - retention-days: 7 - - - name: Collect Docker logs on failure - if: failure() - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs > docker-logs-firefox-shard-${{ matrix.shard }}.txt 2>&1 - - - name: Upload Docker logs on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: docker-logs-firefox-shard-${{ matrix.shard }} - path: docker-logs-firefox-shard-${{ matrix.shard }}.txt - retention-days: 7 - - - name: Cleanup - if: always() - run: docker compose -f .docker/compose/docker-compose.playwright-ci.yml down -v 2>/dev/null || true - - e2e-webkit: - name: E2E WebKit (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) - runs-on: ubuntu-latest - needs: build - if: | - (github.event_name != 'workflow_dispatch') || - (github.event.inputs.browser == 'webkit' || github.event.inputs.browser == 'all') && - (github.event.inputs.test_category == 'non-security' || github.event.inputs.test_category == 'all') - timeout-minutes: 20 - env: - CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }} - CHARON_EMERGENCY_SERVER_ENABLED: "true" - CHARON_SECURITY_TESTS_ENABLED: "false" # Cerberus OFF for non-security tests - CHARON_E2E_IMAGE_TAG: charon:e2e-test - strategy: - fail-fast: false - matrix: - shard: [1, 2, 3, 4] - total-shards: [4] - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - - name: Set up Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Download Docker image - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - name: docker-image - - - name: Load Docker image - run: | - docker load -i charon-e2e-image.tar - docker images | grep charon - - - name: Generate ephemeral encryption key - run: echo "CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32)" >> $GITHUB_ENV - - - name: Start test environment (Non-Security Profile) - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml up -d - echo "โœ… Container started for WebKit non-security tests (Cerberus OFF)" - - - name: Wait for service health - run: | - echo "โณ Waiting for Charon to be healthy..." - MAX_ATTEMPTS=30 - ATTEMPT=0 - while [[ ${ATTEMPT} -lt ${MAX_ATTEMPTS} ]]; do - ATTEMPT=$((ATTEMPT + 1)) - echo "Attempt ${ATTEMPT}/${MAX_ATTEMPTS}..." - if curl -sf http://127.0.0.1:8080/api/v1/health > /dev/null 2>&1; then - echo "โœ… Charon is healthy!" - curl -s http://127.0.0.1:8080/api/v1/health | jq . - exit 0 - fi - sleep 2 - done - echo "โŒ Health check failed" - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs - exit 1 - - - name: Install dependencies - run: npm ci - - - name: Install Playwright WebKit - run: | - echo "๐Ÿ“ฆ Installing WebKit..." - npx playwright install --with-deps webkit - EXIT_CODE=$? - echo "โœ… Install command completed (exit code: $EXIT_CODE)" - exit $EXIT_CODE - - - name: Run WebKit Non-Security Tests (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) - run: | - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "WebKit Non-Security Tests - Shard ${{ matrix.shard }}/${{ matrix.total-shards }}" - echo "Cerberus: DISABLED" - echo "Execution: PARALLEL (sharded)" - echo "Start Time: $(date -u +'%Y-%m-%dT%H:%M:%SZ')" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - - SHARD_START=$(date +%s) - echo "SHARD_START=$SHARD_START" >> $GITHUB_ENV - - npx playwright test \ - --project=webkit \ - --shard=${{ matrix.shard }}/${{ matrix.total-shards }} \ - tests/core \ - tests/dns-provider-crud.spec.ts \ - tests/dns-provider-types.spec.ts \ - tests/emergency-server \ - tests/integration \ - tests/manual-dns-provider.spec.ts \ - tests/monitoring \ - tests/security \ - tests/settings \ - tests/tasks - - SHARD_END=$(date +%s) - echo "SHARD_END=$SHARD_END" >> $GITHUB_ENV - SHARD_DURATION=$((SHARD_END - SHARD_START)) - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "WebKit Shard ${{ matrix.shard }} Complete | Duration: ${SHARD_DURATION}s" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - env: - PLAYWRIGHT_BASE_URL: http://127.0.0.1:8080 - CI: true - TEST_WORKER_INDEX: ${{ matrix.shard }} - - - name: Upload HTML report (WebKit shard ${{ matrix.shard }}) - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: playwright-report-webkit-shard-${{ matrix.shard }} - path: playwright-report/ - retention-days: 14 - - - name: Upload WebKit coverage (if enabled) - if: always() && env.PLAYWRIGHT_COVERAGE == '1' - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: e2e-coverage-webkit-shard-${{ matrix.shard }} - path: coverage/e2e/ - retention-days: 7 - - - name: Upload test traces on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: traces-webkit-shard-${{ matrix.shard }} - path: test-results/**/*.zip - retention-days: 7 - - - name: Collect Docker logs on failure - if: failure() - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs > docker-logs-webkit-shard-${{ matrix.shard }}.txt 2>&1 - - - name: Upload Docker logs on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: docker-logs-webkit-shard-${{ matrix.shard }} - path: docker-logs-webkit-shard-${{ matrix.shard }}.txt - retention-days: 7 - - - name: Cleanup - if: always() - run: docker compose -f .docker/compose/docker-compose.playwright-ci.yml down -v 2>/dev/null || true - - # Test summary job - test-summary: - name: E2E Test Summary - runs-on: ubuntu-latest - needs: [e2e-chromium-security, e2e-firefox-security, e2e-webkit-security, e2e-chromium, e2e-firefox, e2e-webkit] - if: always() - - steps: - - name: Generate job summary - run: | - echo "## ๐Ÿ“Š E2E Test Results (Split: Security + Sharded)" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Architecture: 15 Total Jobs" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "#### Security Enforcement (3 jobs)" >> $GITHUB_STEP_SUMMARY - echo "| Browser | Status | Shards | Timeout | Cerberus |" >> $GITHUB_STEP_SUMMARY - echo "|---------|--------|--------|---------|----------|" >> $GITHUB_STEP_SUMMARY - echo "| Chromium | ${{ needs.e2e-chromium-security.result }} | 1 | 30min | ON |" >> $GITHUB_STEP_SUMMARY - echo "| Firefox | ${{ needs.e2e-firefox-security.result }} | 1 | 30min | ON |" >> $GITHUB_STEP_SUMMARY - echo "| WebKit | ${{ needs.e2e-webkit-security.result }} | 1 | 30min | ON |" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "#### Non-Security Tests (12 jobs)" >> $GITHUB_STEP_SUMMARY - echo "| Browser | Status | Shards | Timeout | Cerberus |" >> $GITHUB_STEP_SUMMARY - echo "|---------|--------|--------|---------|----------|" >> $GITHUB_STEP_SUMMARY - echo "| Chromium | ${{ needs.e2e-chromium.result }} | 4 | 20min | OFF |" >> $GITHUB_STEP_SUMMARY - echo "| Firefox | ${{ needs.e2e-firefox.result }} | 4 | 20min | OFF |" >> $GITHUB_STEP_SUMMARY - echo "| WebKit | ${{ needs.e2e-webkit.result }} | 4 | 20min | OFF |" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Benefits" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "- โœ… **Isolation:** Security tests run independently without ACL/rate limit interference" >> $GITHUB_STEP_SUMMARY - echo "- โœ… **Performance:** Non-security tests sharded 4-way for faster execution" >> $GITHUB_STEP_SUMMARY - echo "- โœ… **Reliability:** Cerberus OFF by default prevents cross-shard contamination" >> $GITHUB_STEP_SUMMARY - echo "- โœ… **Clarity:** Separate artifacts for security vs non-security test results" >> $GITHUB_STEP_SUMMARY - - # Final status check - e2e-results: - name: E2E Test Results (Final) - runs-on: ubuntu-latest - needs: [e2e-chromium-security, e2e-firefox-security, e2e-webkit-security, e2e-chromium, e2e-firefox, e2e-webkit] - if: always() - - steps: - - name: Check test results - run: | - CHROMIUM_SEC="${{ needs.e2e-chromium-security.result }}" - FIREFOX_SEC="${{ needs.e2e-firefox-security.result }}" - WEBKIT_SEC="${{ needs.e2e-webkit-security.result }}" - CHROMIUM="${{ needs.e2e-chromium.result }}" - FIREFOX="${{ needs.e2e-firefox.result }}" - WEBKIT="${{ needs.e2e-webkit.result }}" - - echo "Security Enforcement Results:" - echo " Chromium Security: $CHROMIUM_SEC" - echo " Firefox Security: $FIREFOX_SEC" - echo " WebKit Security: $WEBKIT_SEC" - echo "" - echo "Non-Security Results:" - echo " Chromium: $CHROMIUM" - echo " Firefox: $FIREFOX" - echo " WebKit: $WEBKIT" - - # Allow skipped jobs (workflow_dispatch with specific browser/category) - if [[ "$CHROMIUM_SEC" == "skipped" ]]; then CHROMIUM_SEC="success"; fi - if [[ "$FIREFOX_SEC" == "skipped" ]]; then FIREFOX_SEC="success"; fi - if [[ "$WEBKIT_SEC" == "skipped" ]]; then WEBKIT_SEC="success"; fi - if [[ "$CHROMIUM" == "skipped" ]]; then CHROMIUM="success"; fi - if [[ "$FIREFOX" == "skipped" ]]; then FIREFOX="success"; fi - if [[ "$WEBKIT" == "skipped" ]]; then WEBKIT="success"; fi - - if [[ "$CHROMIUM_SEC" == "success" && "$FIREFOX_SEC" == "success" && "$WEBKIT_SEC" == "success" && \ - "$CHROMIUM" == "success" && "$FIREFOX" == "success" && "$WEBKIT" == "success" ]]; then - echo "โœ… All browser tests passed or were skipped" - exit 0 - else - echo "โŒ One or more browser tests failed" - exit 1 - fi diff --git a/.github/workflows/e2e-tests.yml.backup b/.github/workflows/e2e-tests.yml.backup deleted file mode 100644 index 8e7cdd4c..00000000 --- a/.github/workflows/e2e-tests.yml.backup +++ /dev/null @@ -1,632 +0,0 @@ -# E2E Tests Workflow -# Runs Playwright E2E tests with sharding for faster execution -# and collects frontend code coverage via @bgotink/playwright-coverage -# -# Test Execution Architecture: -# - Parallel Sharding: Tests split across 4 shards for speed -# - Per-Shard HTML Reports: Each shard generates its own HTML report -# - No Merging Needed: Smaller reports are easier to debug -# - Trace Collection: Failure traces captured for debugging -# -# Coverage Architecture: -# - Backend: Docker container at localhost:8080 (API) -# - Frontend: Vite dev server at localhost:3000 (serves source files) -# - Tests hit Vite, which proxies API calls to Docker -# - V8 coverage maps directly to source files for accurate reporting -# - Coverage disabled by default (requires PLAYWRIGHT_COVERAGE=1) -# -# Triggers: -# - Pull requests to main/develop (with path filters) -# - Push to main branch -# - Manual dispatch with browser selection -# -# Jobs: -# 1. build: Build Docker image and upload as artifact -# 2. e2e-tests: Run tests in parallel shards, upload per-shard HTML reports -# 3. test-summary: Generate summary with links to shard reports -# 4. comment-results: Post test results as PR comment -# 5. upload-coverage: Merge and upload E2E coverage to Codecov (if enabled) -# 6. e2e-results: Status check to block merge on failure - -name: E2E Tests - -on: - pull_request: - branches: - - main - - development - - 'feature/**' - paths: - - 'frontend/**' - - 'backend/**' - - 'tests/**' - - 'playwright.config.js' - - '.github/workflows/e2e-tests.yml' - - workflow_dispatch: - inputs: - browser: - description: 'Browser to test' - required: false - default: 'chromium' - type: choice - options: - - chromium - - firefox - - webkit - - all - -env: - NODE_VERSION: '20' - GO_VERSION: '1.25.6' - GOTOOLCHAIN: auto - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository_owner }}/charon - PLAYWRIGHT_COVERAGE: ${{ vars.PLAYWRIGHT_COVERAGE || '0' }} - # Enhanced debugging environment variables - DEBUG: 'charon:*,charon-test:*' - PLAYWRIGHT_DEBUG: '1' - CI_LOG_LEVEL: 'verbose' - -concurrency: - group: e2e-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - # Build application once, share across test shards - build: - name: Build Application - runs-on: ubuntu-latest - outputs: - image_digest: ${{ steps.build-image.outputs.digest }} - steps: - - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 - - - name: Set up Go - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6 - with: - go-version: ${{ env.GO_VERSION }} - cache: true - cache-dependency-path: backend/go.sum - - - name: Set up Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Cache npm dependencies - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 - with: - path: ~/.npm - key: npm-${{ hashFiles('package-lock.json') }} - restore-keys: npm- - - - name: Install dependencies - run: npm ci - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - - - name: Build Docker image - id: build-image - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6 - with: - context: . - file: ./Dockerfile - push: false - load: true - tags: charon:e2e-test - cache-from: type=gha - cache-to: type=gha,mode=max - - - name: Save Docker image - run: docker save charon:e2e-test -o charon-e2e-image.tar - - - name: Upload Docker image artifact - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: docker-image - path: charon-e2e-image.tar - retention-days: 1 - - # Run tests in parallel shards - e2e-tests: - name: E2E ${{ matrix.browser }} (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) - runs-on: ubuntu-latest - needs: build - timeout-minutes: 30 - env: - # Required for security teardown (emergency reset fallback when ACL blocks API) - CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }} - # Enable security-focused endpoints and test gating - CHARON_EMERGENCY_SERVER_ENABLED: "true" - CHARON_SECURITY_TESTS_ENABLED: "true" - CHARON_E2E_IMAGE_TAG: charon:e2e-test - strategy: - fail-fast: false - matrix: - shard: [1, 2, 3, 4] - total-shards: [4] - browser: [chromium, firefox, webkit] - - steps: - - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 - - - name: Set up Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Download Docker image - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - name: docker-image - - - name: Validate Emergency Token Configuration - run: | - echo "๐Ÿ” Validating emergency token configuration..." - - if [ -z "$CHARON_EMERGENCY_TOKEN" ]; then - echo "::error title=Missing Secret::CHARON_EMERGENCY_TOKEN secret not configured in repository settings" - echo "::error::Navigate to: Repository Settings โ†’ Secrets and Variables โ†’ Actions" - echo "::error::Create secret: CHARON_EMERGENCY_TOKEN" - echo "::error::Generate value with: openssl rand -hex 32" - echo "::error::See docs/github-setup.md for detailed instructions" - exit 1 - fi - - TOKEN_LENGTH=${#CHARON_EMERGENCY_TOKEN} - if [ $TOKEN_LENGTH -lt 64 ]; then - echo "::error title=Invalid Token Length::CHARON_EMERGENCY_TOKEN must be at least 64 characters (current: $TOKEN_LENGTH)" - echo "::error::Generate new token with: openssl rand -hex 32" - exit 1 - fi - - # Mask token in output (show first 8 chars only) - MASKED_TOKEN="${CHARON_EMERGENCY_TOKEN:0:8}...${CHARON_EMERGENCY_TOKEN: -4}" - echo "::notice::Emergency token validated (length: $TOKEN_LENGTH, preview: $MASKED_TOKEN)" - env: - CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }} - - - name: Load Docker image - run: | - docker load -i charon-e2e-image.tar - docker images | grep charon - - - name: Generate ephemeral encryption key - run: | - # Generate a unique, ephemeral encryption key for this CI run - # Key is 32 bytes, base64-encoded as required by CHARON_ENCRYPTION_KEY - echo "CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32)" >> $GITHUB_ENV - echo "โœ… Generated ephemeral encryption key for E2E tests" - - - name: Start test environment - run: | - # Use docker-compose.playwright-ci.yml for CI (no .env file, uses GitHub Secrets) - # Note: Using pre-built image loaded from artifact - no rebuild needed - docker compose -f .docker/compose/docker-compose.playwright-ci.yml --profile security-tests up -d - echo "โœ… Container started via docker-compose.playwright-ci.yml" - - - name: Wait for service health - run: | - echo "โณ Waiting for Charon to be healthy..." - MAX_ATTEMPTS=30 - ATTEMPT=0 - - while [[ ${ATTEMPT} -lt ${MAX_ATTEMPTS} ]]; do - ATTEMPT=$((ATTEMPT + 1)) - echo "Attempt ${ATTEMPT}/${MAX_ATTEMPTS}..." - - if curl -sf http://localhost:8080/api/v1/health > /dev/null 2>&1; then - echo "โœ… Charon is healthy!" - curl -s http://localhost:8080/api/v1/health | jq . - exit 0 - fi - - sleep 2 - done - - echo "โŒ Health check failed" - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs - exit 1 - - - name: Install dependencies - run: npm ci - - - name: Clean Playwright browser cache - run: rm -rf ~/.cache/ms-playwright - - - - name: Cache Playwright browsers - id: playwright-cache - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 - with: - path: ~/.cache/ms-playwright - # Use exact match only - no restore-keys fallback - # This ensures we don't restore stale browsers when Playwright version changes - key: playwright-${{ matrix.browser }}-${{ hashFiles('package-lock.json') }} - - - name: Install & verify Playwright browsers - run: | - npx playwright install --with-deps --force - - set -euo pipefail - - echo "๐ŸŽฏ Playwright CLI version" - npx playwright --version || true - - echo "๐Ÿ” Showing Playwright cache root (if present)" - ls -la ~/.cache/ms-playwright || true - - echo "๐Ÿ“ฅ Install or verify browser: ${{ matrix.browser }}" - - # Install when cache miss, otherwise verify the expected executables exist - if [[ "${{ steps.playwright-cache.outputs.cache-hit }}" != "true" ]]; then - echo "๐Ÿ“ฅ Cache miss - downloading ${{ matrix.browser }} browser..." - npx playwright install --with-deps ${{ matrix.browser }} - else - echo "โœ… Cache hit - verifying ${{ matrix.browser }} browser files..." - fi - - # Look for the browser-specific headless shell executable(s) - case "${{ matrix.browser }}" in - chromium) - EXPECTED_PATTERN="chrome-headless-shell*" - ;; - firefox) - EXPECTED_PATTERN="firefox*" - ;; - webkit) - EXPECTED_PATTERN="webkit*" - ;; - *) - EXPECTED_PATTERN="*" - ;; - esac - - echo "Searching for expected files (pattern=$EXPECTED_PATTERN)..." - find ~/.cache/ms-playwright -maxdepth 4 -type f -name "$EXPECTED_PATTERN" -print || true - - # Attempt to derive the exact executable path Playwright will use - echo "Attempting to resolve Playwright's executable path via Node API (best-effort)" - node -e "try{ const pw = require('playwright'); const b = pw['${{ matrix.browser }}']; console.log('exePath:', b.executablePath ? b.executablePath() : 'n/a'); }catch(e){ console.error('node-check-failed', e.message); process.exit(0); }" || true - - # If the expected binary is missing, force reinstall - MISSING_COUNT=$(find ~/.cache/ms-playwright -maxdepth 4 -type f -name "$EXPECTED_PATTERN" | wc -l || true) - if [[ "$MISSING_COUNT" -lt 1 ]]; then - echo "โš ๏ธ Expected Playwright browser executable not found (count=$MISSING_COUNT). Forcing reinstall..." - npx playwright install --with-deps ${{ matrix.browser }} --force - fi - - echo "Post-install: show cache contents (top 5 lines)" - find ~/.cache/ms-playwright -maxdepth 3 -printf '%p\n' | head -40 || true - - # Final sanity check: try a headless launch via a tiny Node script (browser-specific args, retry without args) - echo "๐Ÿ” Verifying browser can be launched (headless)" - node -e "(async()=>{ try{ const pw=require('playwright'); const name='${{ matrix.browser }}'; const browser = pw[name]; const argsMap = { chromium: ['--no-sandbox'], firefox: ['--no-sandbox'], webkit: [] }; const args = argsMap[name] || []; - // First attempt: launch with recommended args for this browser - try { - console.log('attempt-launch', name, 'args', JSON.stringify(args)); - const b = await browser.launch({ headless: true, args }); - await b.close(); - console.log('launch-ok', 'argsUsed', JSON.stringify(args)); - process.exit(0); - } catch (err) { - console.warn('launch-with-args-failed', err && err.message); - if (args.length) { - // Retry without args (some browsers reject unknown flags) - console.log('retrying-without-args'); - const b2 = await browser.launch({ headless: true }); - await b2.close(); - console.log('launch-ok-no-args'); - process.exit(0); - } - throw err; - } - } catch (e) { console.error('launch-failed', e && e.message); process.exit(2); } })()" || (echo 'โŒ Browser launch verification failed' && exit 1) - - echo "โœ… Playwright ${{ matrix.browser }} ready and verified" - - - name: Run E2E tests (Shard ${{ matrix.shard }}/${{ matrix.total-shards }}) - run: | - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "E2E Test Shard ${{ matrix.shard }}/${{ matrix.total-shards }}" - echo "Browser: ${{ matrix.browser }}" - echo "Start Time: $(date -u +'%Y-%m-%dT%H:%M:%SZ')" - echo "" - echo "Reporter: HTML (per-shard reports)" - echo "Output: playwright-report/ directory" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - - # Capture start time for performance budget tracking - SHARD_START=$(date +%s) - echo "SHARD_START=$SHARD_START" >> $GITHUB_ENV - - npx playwright test \ - --project=${{ matrix.browser }} \ - --shard=${{ matrix.shard }}/${{ matrix.total-shards }} - - # Capture end time for performance budget tracking - SHARD_END=$(date +%s) - echo "SHARD_END=$SHARD_END" >> $GITHUB_ENV - - SHARD_DURATION=$((SHARD_END - SHARD_START)) - - echo "" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - echo "Shard ${{ matrix.shard }} Complete | Duration: ${SHARD_DURATION}s" - echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" - env: - # Test directly against Docker container (no coverage) - PLAYWRIGHT_BASE_URL: http://localhost:8080 - CI: true - TEST_WORKER_INDEX: ${{ matrix.shard }} - - - name: Verify shard performance budget - if: always() - run: | - # Calculate shard execution time - SHARD_DURATION=$((SHARD_END - SHARD_START)) - MAX_DURATION=900 # 15 minutes - - echo "๐Ÿ“Š Performance Budget Check" - echo " Shard Duration: ${SHARD_DURATION}s" - echo " Budget Limit: ${MAX_DURATION}s" - echo " Utilization: $((SHARD_DURATION * 100 / MAX_DURATION))%" - - # Fail if shard exceeded performance budget - if [[ $SHARD_DURATION -gt $MAX_DURATION ]]; then - echo "::error::Shard exceeded performance budget: ${SHARD_DURATION}s > ${MAX_DURATION}s" - echo "::error::This likely indicates feature flag polling regression or API bottleneck" - echo "::error::Review test logs and consider optimizing wait helpers or API calls" - exit 1 - fi - - echo "โœ… Shard completed within budget: ${SHARD_DURATION}s" - - - name: Upload HTML report (per-shard) - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: playwright-report-${{ matrix.browser }}-shard-${{ matrix.shard }} - path: playwright-report/ - retention-days: 14 - - - name: Upload test traces on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: traces-${{ matrix.browser }}-shard-${{ matrix.shard }} - path: test-results/**/*.zip - retention-days: 7 - - - name: Collect Docker logs on failure - if: failure() - run: | - echo "๐Ÿ“‹ Container logs:" - docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs > docker-logs-${{ matrix.browser }}-shard-${{ matrix.shard }}.txt 2>&1 - - - name: Upload Docker logs on failure - if: failure() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: docker-logs-${{ matrix.browser }}-shard-${{ matrix.shard }} - path: docker-logs-${{ matrix.browser }}-shard-${{ matrix.shard }}.txt - retention-days: 7 - - - name: Cleanup - if: always() - run: | - docker compose -f .docker/compose/docker-compose.playwright-ci.yml down -v 2>/dev/null || true - - # Summarize test results from all shards (no merging needed) - test-summary: - name: E2E Test Summary - runs-on: ubuntu-latest - needs: e2e-tests - if: always() - - steps: - - name: Generate job summary with per-shard links - run: | - echo "## ๐Ÿ“Š E2E Test Results" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Per-Shard HTML Reports" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "Each shard generates its own HTML report for easier debugging:" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Browser | Shards | HTML Reports | Traces (on failure) |" >> $GITHUB_STEP_SUMMARY - echo "|---------|--------|--------------|---------------------|" >> $GITHUB_STEP_SUMMARY - echo "| Chromium | 1-4 | \`playwright-report-chromium-shard-{1..4}\` | \`traces-chromium-shard-{1..4}\` |" >> $GITHUB_STEP_SUMMARY - echo "| Firefox | 1-4 | \`playwright-report-firefox-shard-{1..4}\` | \`traces-firefox-shard-{1..4}\` |" >> $GITHUB_STEP_SUMMARY - echo "| WebKit | 1-4 | \`playwright-report-webkit-shard-{1..4}\` | \`traces-webkit-shard-{1..4}\` |" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### How to View Reports" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "1. Download the shard HTML report artifact (zip file)" >> $GITHUB_STEP_SUMMARY - echo "2. Extract and open \`index.html\` in your browser" >> $GITHUB_STEP_SUMMARY - echo "3. Or run: \`npx playwright show-report path/to/extracted-folder\`" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Debugging Tips" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "- **Failed tests?** Download the shard report that failed. Each shard has a focused subset of tests." >> $GITHUB_STEP_SUMMARY - echo "- **Traces**: Available in trace artifacts (only on failure)" >> $GITHUB_STEP_SUMMARY - echo "- **Docker Logs**: Backend errors available in docker-logs-shard-N artifacts" >> $GITHUB_STEP_SUMMARY - echo "- **Local repro**: \`npx playwright test --grep=\"test name\"\`" >> $GITHUB_STEP_SUMMARY - - # Comment on PR with results - comment-results: - name: Comment Test Results - runs-on: ubuntu-latest - needs: [e2e-tests, test-summary] - if: github.event_name == 'pull_request' && always() - permissions: - pull-requests: write - - steps: - - name: Determine test status - id: status - run: | - if [[ "${{ needs.e2e-tests.result }}" == "success" ]]; then - echo "emoji=โœ…" >> $GITHUB_OUTPUT - echo "status=PASSED" >> $GITHUB_OUTPUT - echo "message=All E2E tests passed!" >> $GITHUB_OUTPUT - elif [[ "${{ needs.e2e-tests.result }}" == "failure" ]]; then - echo "emoji=โŒ" >> $GITHUB_OUTPUT - echo "status=FAILED" >> $GITHUB_OUTPUT - echo "message=Some E2E tests failed. Check artifacts for per-shard reports." >> $GITHUB_OUTPUT - else - echo "emoji=โš ๏ธ" >> $GITHUB_OUTPUT - echo "status=UNKNOWN" >> $GITHUB_OUTPUT - echo "message=E2E tests did not complete successfully." >> $GITHUB_OUTPUT - fi - - - name: Comment on PR - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const emoji = '${{ steps.status.outputs.emoji }}'; - const status = '${{ steps.status.outputs.status }}'; - const message = '${{ steps.status.outputs.message }}'; - const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; - - const body = `## ${emoji} E2E Test Results: ${status} - - ${message} - - | Metric | Result | - |--------|--------| - | Browsers | Chromium, Firefox, WebKit | - | Shards per Browser | 4 | - | Total Jobs | 12 | - | Status | ${status} | - - **Per-Shard HTML Reports** (easier to debug): - - \`playwright-report-{browser}-shard-{1..4}\` (12 total artifacts) - - Trace artifacts: \`traces-{browser}-shard-{N}\` - - [๐Ÿ“Š View workflow run & download reports](${runUrl}) - - --- - ๐Ÿค– This comment was automatically generated by the E2E Tests workflow.`; - - // Find existing comment - const { data: comments } = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - }); - - const botComment = comments.find(comment => - comment.user.type === 'Bot' && - comment.body.includes('E2E Test Results') - ); - - if (botComment) { - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: botComment.id, - body: body - }); - } else { - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - body: body - }); - } - - # Upload merged E2E coverage to Codecov - upload-coverage: - name: Upload E2E Coverage - runs-on: ubuntu-latest - needs: e2e-tests - # Coverage is only produced when PLAYWRIGHT_COVERAGE=1 (requires Vite dev server) - if: vars.PLAYWRIGHT_COVERAGE == '1' - - - steps: - - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 - - - name: Set up Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - - - name: Download all coverage artifacts - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - pattern: e2e-coverage-* - path: all-coverage - merge-multiple: false - - - name: Merge LCOV coverage files - run: | - # Install lcov for merging - sudo apt-get update && sudo apt-get install -y lcov - - # Create merged coverage directory - mkdir -p coverage/e2e-merged - - # Find all lcov.info files and merge them - LCOV_FILES=$(find all-coverage -name "lcov.info" -type f) - - if [[ -n "$LCOV_FILES" ]]; then - # Build merge command - MERGE_ARGS="" - for file in $LCOV_FILES; do - MERGE_ARGS="$MERGE_ARGS -a $file" - done - - lcov $MERGE_ARGS -o coverage/e2e-merged/lcov.info - echo "โœ… Merged $(echo "$LCOV_FILES" | wc -w) coverage files" - else - echo "โš ๏ธ No coverage files found to merge" - exit 0 - fi - - - name: Upload E2E coverage to Codecov - uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: ./coverage/e2e-merged/lcov.info - flags: e2e - name: e2e-coverage - fail_ci_if_error: false - - - name: Upload merged coverage artifact - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: e2e-coverage-merged - path: coverage/e2e-merged/ - retention-days: 30 - - # Final status check - blocks merge if tests fail - e2e-results: - name: E2E Test Results - runs-on: ubuntu-latest - needs: e2e-tests - if: always() - - steps: - - name: Check test results - run: | - if [[ "${{ needs.e2e-tests.result }}" == "success" ]]; then - echo "โœ… All E2E tests passed" - exit 0 - elif [[ "${{ needs.e2e-tests.result }}" == "skipped" ]]; then - echo "โญ๏ธ E2E tests were skipped" - exit 0 - else - echo "โŒ E2E tests failed or were cancelled" - echo "Result: ${{ needs.e2e-tests.result }}" - exit 1 - fi diff --git a/README.md b/README.md index 234c900a..209aa084 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@

Project Status: Active โ€“ The project is being actively developed. Docker Pulls - GHCR Pulls Release
Code Coverage diff --git a/docs/AGENT_SKILLS_MIGRATION.md b/docs/plans/archive/AGENT_SKILLS_MIGRATION.md similarity index 100% rename from docs/AGENT_SKILLS_MIGRATION.md rename to docs/plans/archive/AGENT_SKILLS_MIGRATION.md diff --git a/docs/plans/CI_REMEDIATION_MASTER_PLAN.md b/docs/plans/archive/CI_REMEDIATION_MASTER_PLAN.md similarity index 100% rename from docs/plans/CI_REMEDIATION_MASTER_PLAN.md rename to docs/plans/archive/CI_REMEDIATION_MASTER_PLAN.md diff --git a/docs/plans/CI_SECRET_DIAGNOSIS.md b/docs/plans/archive/CI_SECRET_DIAGNOSIS.md similarity index 100% rename from docs/plans/CI_SECRET_DIAGNOSIS.md rename to docs/plans/archive/CI_SECRET_DIAGNOSIS.md diff --git a/docs/plans/CI_TEST_FAILURES_DETAILED_REMEDIATION.md b/docs/plans/archive/CI_TEST_FAILURES_DETAILED_REMEDIATION.md similarity index 100% rename from docs/plans/CI_TEST_FAILURES_DETAILED_REMEDIATION.md rename to docs/plans/archive/CI_TEST_FAILURES_DETAILED_REMEDIATION.md diff --git a/docs/plans/CI_TEST_FAILURES_REMEDIATION.md b/docs/plans/archive/CI_TEST_FAILURES_REMEDIATION.md similarity index 100% rename from docs/plans/CI_TEST_FAILURES_REMEDIATION.md rename to docs/plans/archive/CI_TEST_FAILURES_REMEDIATION.md diff --git a/docs/plans/GO_126_TEST_FAILURES_ANALYSIS.md b/docs/plans/archive/GO_126_TEST_FAILURES_ANALYSIS.md similarity index 100% rename from docs/plans/GO_126_TEST_FAILURES_ANALYSIS.md rename to docs/plans/archive/GO_126_TEST_FAILURES_ANALYSIS.md diff --git a/docs/plans/MIGRATION_UPDATE_SUMMARY.md b/docs/plans/archive/MIGRATION_UPDATE_SUMMARY.md similarity index 100% rename from docs/plans/MIGRATION_UPDATE_SUMMARY.md rename to docs/plans/archive/MIGRATION_UPDATE_SUMMARY.md diff --git a/.github/workflows/PHASE1_IMPLEMENTATION.md b/docs/plans/archive/PHASE1_IMPLEMENTATION.md similarity index 100% rename from .github/workflows/PHASE1_IMPLEMENTATION.md rename to docs/plans/archive/PHASE1_IMPLEMENTATION.md diff --git a/docs/plans/PHASE5_E2E_REMEDIATION.md b/docs/plans/archive/PHASE5_E2E_REMEDIATION.md similarity index 100% rename from docs/plans/PHASE5_E2E_REMEDIATION.md rename to docs/plans/archive/PHASE5_E2E_REMEDIATION.md diff --git a/docs/plans/PHASE_2_3_REMEDIATION_PLAN.md b/docs/plans/archive/PHASE_2_3_REMEDIATION_PLAN.md similarity index 100% rename from docs/plans/PHASE_2_3_REMEDIATION_PLAN.md rename to docs/plans/archive/PHASE_2_3_REMEDIATION_PLAN.md diff --git a/docs/plans/PHASE_3_SECURITY_TESTING_PLAN.md b/docs/plans/archive/PHASE_3_SECURITY_TESTING_PLAN.md similarity index 100% rename from docs/plans/PHASE_3_SECURITY_TESTING_PLAN.md rename to docs/plans/archive/PHASE_3_SECURITY_TESTING_PLAN.md diff --git a/docs/plans/PHASE_4_UAT_INTEGRATION_PLAN.md b/docs/plans/archive/PHASE_4_UAT_INTEGRATION_PLAN.md similarity index 100% rename from docs/plans/PHASE_4_UAT_INTEGRATION_PLAN.md rename to docs/plans/archive/PHASE_4_UAT_INTEGRATION_PLAN.md diff --git a/docs/plans/SECURITY_COVERAGE_QA_PLAN.md b/docs/plans/archive/SECURITY_COVERAGE_QA_PLAN.md similarity index 100% rename from docs/plans/SECURITY_COVERAGE_QA_PLAN.md rename to docs/plans/archive/SECURITY_COVERAGE_QA_PLAN.md diff --git a/docs/SUPPLY_CHAIN_SECURITY_FIXES.md b/docs/plans/archive/SUPPLY_CHAIN_SECURITY_FIXES.md similarity index 100% rename from docs/SUPPLY_CHAIN_SECURITY_FIXES.md rename to docs/plans/archive/SUPPLY_CHAIN_SECURITY_FIXES.md diff --git a/docs/SUPPLY_CHAIN_VULNERABILITY_GUIDE.md b/docs/plans/archive/SUPPLY_CHAIN_VULNERABILITY_GUIDE.md similarity index 100% rename from docs/SUPPLY_CHAIN_VULNERABILITY_GUIDE.md rename to docs/plans/archive/SUPPLY_CHAIN_VULNERABILITY_GUIDE.md diff --git a/docs/plans/TEST_ISOLATION_FINDINGS.md b/docs/plans/archive/TEST_ISOLATION_FINDINGS.md similarity index 100% rename from docs/plans/TEST_ISOLATION_FINDINGS.md rename to docs/plans/archive/TEST_ISOLATION_FINDINGS.md diff --git a/docs/plans/agent-skills-migration-spec.md b/docs/plans/archive/agent-skills-migration-spec.md similarity index 100% rename from docs/plans/agent-skills-migration-spec.md rename to docs/plans/archive/agent-skills-migration-spec.md diff --git a/docs/plans/alpine_migration_spec.md b/docs/plans/archive/alpine_migration_spec.md similarity index 100% rename from docs/plans/alpine_migration_spec.md rename to docs/plans/archive/alpine_migration_spec.md diff --git a/docs/plans/archive_supply_chain_pr_implementation.md b/docs/plans/archive/archive_supply_chain_pr_implementation.md similarity index 100% rename from docs/plans/archive_supply_chain_pr_implementation.md rename to docs/plans/archive/archive_supply_chain_pr_implementation.md diff --git a/docs/plans/auto_versioning_remediation.md b/docs/plans/archive/auto_versioning_remediation.md similarity index 100% rename from docs/plans/auto_versioning_remediation.md rename to docs/plans/archive/auto_versioning_remediation.md diff --git a/docs/plans/backend_coverage_fix_plan.md b/docs/plans/archive/backend_coverage_fix_plan.md similarity index 100% rename from docs/plans/backend_coverage_fix_plan.md rename to docs/plans/archive/backend_coverage_fix_plan.md diff --git a/docs/plans/backend_coverage_investigation_spec.md b/docs/plans/archive/backend_coverage_investigation_spec.md similarity index 100% rename from docs/plans/backend_coverage_investigation_spec.md rename to docs/plans/archive/backend_coverage_investigation_spec.md diff --git a/docs/beta_release_draft_pr.md b/docs/plans/archive/beta_release_draft_pr.md similarity index 100% rename from docs/beta_release_draft_pr.md rename to docs/plans/archive/beta_release_draft_pr.md diff --git a/docs/beta_release_draft_pr_body_snapshot.md b/docs/plans/archive/beta_release_draft_pr_body_snapshot.md similarity index 100% rename from docs/beta_release_draft_pr_body_snapshot.md rename to docs/plans/archive/beta_release_draft_pr_body_snapshot.md diff --git a/docs/beta_release_pr_body.md b/docs/plans/archive/beta_release_pr_body.md similarity index 100% rename from docs/beta_release_pr_body.md rename to docs/plans/archive/beta_release_pr_body.md diff --git a/docs/plans/break_glass_protocol_redesign.md b/docs/plans/archive/break_glass_protocol_redesign.md similarity index 100% rename from docs/plans/break_glass_protocol_redesign.md rename to docs/plans/archive/break_glass_protocol_redesign.md diff --git a/docs/plans/browser_alignment_triage.md b/docs/plans/archive/browser_alignment_triage.md similarity index 100% rename from docs/plans/browser_alignment_triage.md rename to docs/plans/archive/browser_alignment_triage.md diff --git a/docs/plans/bulk-apply-security-headers-plan.md b/docs/plans/archive/bulk-apply-security-headers-plan.md similarity index 100% rename from docs/plans/bulk-apply-security-headers-plan.md rename to docs/plans/archive/bulk-apply-security-headers-plan.md diff --git a/docs/plans/c-ares_remediation_plan.md b/docs/plans/archive/c-ares_remediation_plan.md similarity index 100% rename from docs/plans/c-ares_remediation_plan.md rename to docs/plans/archive/c-ares_remediation_plan.md diff --git a/docs/plans/caddy_bouncer_field_remediation.md b/docs/plans/archive/caddy_bouncer_field_remediation.md similarity index 100% rename from docs/plans/caddy_bouncer_field_remediation.md rename to docs/plans/archive/caddy_bouncer_field_remediation.md diff --git a/docs/plans/caddy_config_architecture_investigation.md b/docs/plans/archive/caddy_config_architecture_investigation.md similarity index 100% rename from docs/plans/caddy_config_architecture_investigation.md rename to docs/plans/archive/caddy_config_architecture_investigation.md diff --git a/docs/plans/caddy_import_backend_analysis.md b/docs/plans/archive/caddy_import_backend_analysis.md similarity index 100% rename from docs/plans/caddy_import_backend_analysis.md rename to docs/plans/archive/caddy_import_backend_analysis.md diff --git a/docs/plans/caddy_import_debug_spec.md b/docs/plans/archive/caddy_import_debug_spec.md similarity index 100% rename from docs/plans/caddy_import_debug_spec.md rename to docs/plans/archive/caddy_import_debug_spec.md diff --git a/docs/plans/caddy_import_firefox_assessment.md b/docs/plans/archive/caddy_import_firefox_assessment.md similarity index 100% rename from docs/plans/caddy_import_firefox_assessment.md rename to docs/plans/archive/caddy_import_firefox_assessment.md diff --git a/docs/plans/caddy_import_firefox_fix_spec.md b/docs/plans/archive/caddy_import_firefox_fix_spec.md similarity index 100% rename from docs/plans/caddy_import_firefox_fix_spec.md rename to docs/plans/archive/caddy_import_firefox_fix_spec.md diff --git a/docs/plans/caddy_import_fixes_spec.md b/docs/plans/archive/caddy_import_fixes_spec.md similarity index 100% rename from docs/plans/caddy_import_fixes_spec.md rename to docs/plans/archive/caddy_import_fixes_spec.md diff --git a/docs/plans/caddy_import_frontend_analysis.md b/docs/plans/archive/caddy_import_frontend_analysis.md similarity index 100% rename from docs/plans/caddy_import_frontend_analysis.md rename to docs/plans/archive/caddy_import_frontend_analysis.md diff --git a/docs/plans/caddy_upgrade_plan.md b/docs/plans/archive/caddy_upgrade_plan.md similarity index 100% rename from docs/plans/caddy_upgrade_plan.md rename to docs/plans/archive/caddy_upgrade_plan.md diff --git a/docs/plans/cerberus_integration_testing_plan.md b/docs/plans/archive/cerberus_integration_testing_plan.md similarity index 100% rename from docs/plans/cerberus_integration_testing_plan.md rename to docs/plans/archive/cerberus_integration_testing_plan.md diff --git a/docs/plans/cerberus_remediation_plan.md b/docs/plans/archive/cerberus_remediation_plan.md similarity index 100% rename from docs/plans/cerberus_remediation_plan.md rename to docs/plans/archive/cerberus_remediation_plan.md diff --git a/docs/plans/cerberus_uiux_testing_plan.md b/docs/plans/archive/cerberus_uiux_testing_plan.md similarity index 100% rename from docs/plans/cerberus_uiux_testing_plan.md rename to docs/plans/archive/cerberus_uiux_testing_plan.md diff --git a/docs/plans/archive/chores.md b/docs/plans/archive/chores.md new file mode 100644 index 00000000..069c60e0 --- /dev/null +++ b/docs/plans/archive/chores.md @@ -0,0 +1,60 @@ +# Chores and To-Dos for Charon + +## To-Do + +- in the add Proxy Host card, the ACL and Security Headers drop downs don't let me select anything. + - Add e2e tests for Proxy Host add/edit cards to trace and fix this bug ๐Ÿ› + +- Turn Vite back on for Playwright coverage annalysis. + +- Extensive e2e testing and triage for all save functions. Users have reported 404 errors when trying to save certain configurations. Need to ensure all save functions work as expected. + +- Extensive e2e testing and triage for all import functions. Some users have reported unable to import caddyfiles and crowdsec configs. Need to ensure all import functions work as expected. Ref issue #585 + +- Extensive e2e testing and triage for Uptime Monitoring. There is a bug that I just cant place my finger on. Proxi Hosts I added after a certain update a while ago only come back as UP if I manually refresh the card. All others still operate as expected. Need to ensure Uptime Monitoring works as expected. + +- Notifications should have a "single source of truth" for configuration. Currently, there are two places to configure notifications: the standard notification settings and the security notifications settings. This is redundant and can lead to confusion. Need to consolidate notification settings into a single area and ensure all notifications work as expected. Security notifications need move to the standard notification area. Its redundant to have two places to setup notifications. Need tests to sniff out bugs. Security notifications report a 404 error and users state the discord and gotify messages don't send. Need to ensure Security Notifications work as expected. Ref issue #623 + +- Admin users are regular users with admin privlages. To prevent confusion, ad min user should be listed in the user managment page. Currently there are two places to manage users: the standard user management page and the admin account page. This is redundant and can lead to confusion. Need to consolidate user management into a single area and ensure all user management functions work as expected. The user account should create cutome privlage tiers that can be assigned to users. The user management page should list all users, including the admin user, and allow for role assignment and permission management. Need to ensure User Management works as expected. + +- The job failed due to several Docker errors: + + - Error response from daemon: manifest unknown + The job is trying to pull a Docker image (likely wikid82/charon:sha-75b26c1) that doesn't exist or wasn't built/pushed correctly. + - Error response from daemon: No such container: test-container + The workflow attempts to access a container that was never created because the image pull failed. + - Error response from daemon: network charon-test-net not found + It tries to remove or use a Docker network that was never created due to the earlier failures. + - Ref `docker_build_and_test.yml` workflow. + + +- Page by Page e2e tests: + - Dashboard + - Proxy Hosts + - Remote Servers + - Domains + - Certificates + - DNS + - DNS Providers + - Plugins + - Uptime **HIGH** + - Security + - Dashboard + - CrowdSec + - Access Control Lists + - Rate Limiting + - WAF + - Security Headers + - Encryption + - Settings + - System + - Notifications **CRITICAL** **USER REQUESTED** + - Email (SMTP) + - Admin Account + - Account Managment + - Tasks + - Import + - Caddyfile **CRITICAL** **USER REQUESTED** + - CrowdSec **CRITICAL** **USER REQUESTED** + - Backups + - Logs **MEDIUM** diff --git a/docs/plans/ci_artifact_handover.md b/docs/plans/archive/ci_artifact_handover.md similarity index 100% rename from docs/plans/ci_artifact_handover.md rename to docs/plans/archive/ci_artifact_handover.md diff --git a/docs/plans/ci_codecov_backend_failure_remediation.md b/docs/plans/archive/ci_codecov_backend_failure_remediation.md similarity index 100% rename from docs/plans/ci_codecov_backend_failure_remediation.md rename to docs/plans/archive/ci_codecov_backend_failure_remediation.md diff --git a/docs/plans/ci_failure_fix.md b/docs/plans/archive/ci_failure_fix.md similarity index 100% rename from docs/plans/ci_failure_fix.md rename to docs/plans/archive/ci_failure_fix.md diff --git a/docs/plans/ci_failure_remediation_plan.md b/docs/plans/archive/ci_failure_remediation_plan.md similarity index 100% rename from docs/plans/ci_failure_remediation_plan.md rename to docs/plans/archive/ci_failure_remediation_plan.md diff --git a/docs/plans/ci_hang_remediation.md b/docs/plans/archive/ci_hang_remediation.md similarity index 100% rename from docs/plans/ci_hang_remediation.md rename to docs/plans/archive/ci_hang_remediation.md diff --git a/docs/plans/ci_image_ref_fix_spec.md b/docs/plans/archive/ci_image_ref_fix_spec.md similarity index 100% rename from docs/plans/ci_image_ref_fix_spec.md rename to docs/plans/archive/ci_image_ref_fix_spec.md diff --git a/docs/plans/ci_optimization_spec.md b/docs/plans/archive/ci_optimization_spec.md similarity index 100% rename from docs/plans/ci_optimization_spec.md rename to docs/plans/archive/ci_optimization_spec.md diff --git a/docs/plans/ci_pipeline_fix_spec.md b/docs/plans/archive/ci_pipeline_fix_spec.md similarity index 100% rename from docs/plans/ci_pipeline_fix_spec.md rename to docs/plans/archive/ci_pipeline_fix_spec.md diff --git a/docs/plans/ci_ref_debug_fix_spec.md b/docs/plans/archive/ci_ref_debug_fix_spec.md similarity index 100% rename from docs/plans/ci_ref_debug_fix_spec.md rename to docs/plans/archive/ci_ref_debug_fix_spec.md diff --git a/docs/plans/ci_remediation_spec.md b/docs/plans/archive/ci_remediation_spec.md similarity index 100% rename from docs/plans/ci_remediation_spec.md rename to docs/plans/archive/ci_remediation_spec.md diff --git a/docs/plans/ci_sequencing_spec.md b/docs/plans/archive/ci_sequencing_spec.md similarity index 100% rename from docs/plans/ci_sequencing_spec.md rename to docs/plans/archive/ci_sequencing_spec.md diff --git a/docs/plans/ci_tag_hardening_spec.md b/docs/plans/archive/ci_tag_hardening_spec.md similarity index 100% rename from docs/plans/ci_tag_hardening_spec.md rename to docs/plans/archive/ci_tag_hardening_spec.md diff --git a/docs/plans/ci_test_cleanup_spec.md b/docs/plans/archive/ci_test_cleanup_spec.md similarity index 100% rename from docs/plans/ci_test_cleanup_spec.md rename to docs/plans/archive/ci_test_cleanup_spec.md diff --git a/docs/plans/cleanup_temp_files.md b/docs/plans/archive/cleanup_temp_files.md similarity index 100% rename from docs/plans/cleanup_temp_files.md rename to docs/plans/archive/cleanup_temp_files.md diff --git a/docs/plans/codecov-acceptinvite-patch-coverage.md b/docs/plans/archive/codecov-acceptinvite-patch-coverage.md similarity index 100% rename from docs/plans/codecov-acceptinvite-patch-coverage.md rename to docs/plans/archive/codecov-acceptinvite-patch-coverage.md diff --git a/docs/plans/codecov_config_analysis.md b/docs/plans/archive/codecov_config_analysis.md similarity index 100% rename from docs/plans/codecov_config_analysis.md rename to docs/plans/archive/codecov_config_analysis.md diff --git a/docs/plans/archive/codecove_patch_report.md b/docs/plans/archive/codecove_patch_report.md new file mode 100644 index 00000000..07adab43 --- /dev/null +++ b/docs/plans/archive/codecove_patch_report.md @@ -0,0 +1,9 @@ +Codecov Report + +โŒ Patch coverage is 87.35632% with 11 lines in your changes missing coverage. Please review. +Files with missing lines Patch % Lines +...ackend/internal/api/handlers/proxy_host_handler.go 70.00% 3 Missing โš ๏ธ +backend/internal/crowdsec/hub_sync.go 80.00% 3 Missing โš ๏ธ +backend/internal/api/handlers/crowdsec_handler.go 60.00% 2 Missing โš ๏ธ +backend/internal/services/backup_service.go 33.33% 2 Missing โš ๏ธ +backend/internal/crowdsec/hub_cache.go 50.00% 1 Missing โš ๏ธ diff --git a/docs/plans/codeql-local-hygiene.md b/docs/plans/archive/codeql-local-hygiene.md similarity index 100% rename from docs/plans/codeql-local-hygiene.md rename to docs/plans/archive/codeql-local-hygiene.md diff --git a/docs/plans/comprehensive_modal_fix_spec.md b/docs/plans/archive/comprehensive_modal_fix_spec.md similarity index 100% rename from docs/plans/comprehensive_modal_fix_spec.md rename to docs/plans/archive/comprehensive_modal_fix_spec.md diff --git a/docs/plans/container-hardening-fix.md b/docs/plans/archive/container-hardening-fix.md similarity index 100% rename from docs/plans/container-hardening-fix.md rename to docs/plans/archive/container-hardening-fix.md diff --git a/docs/plans/crowdsec_api_spec_backup_2026-02-04.md b/docs/plans/archive/crowdsec_api_spec_backup_2026-02-04.md similarity index 100% rename from docs/plans/crowdsec_api_spec_backup_2026-02-04.md rename to docs/plans/archive/crowdsec_api_spec_backup_2026-02-04.md diff --git a/docs/plans/crowdsec_bouncer_auto_registration.md b/docs/plans/archive/crowdsec_bouncer_auto_registration.md similarity index 100% rename from docs/plans/crowdsec_bouncer_auto_registration.md rename to docs/plans/archive/crowdsec_bouncer_auto_registration.md diff --git a/docs/plans/crowdsec_bouncer_research_plan.md b/docs/plans/archive/crowdsec_bouncer_research_plan.md similarity index 100% rename from docs/plans/crowdsec_bouncer_research_plan.md rename to docs/plans/archive/crowdsec_bouncer_research_plan.md diff --git a/docs/plans/crowdsec_enrollment_debug_spec.md b/docs/plans/archive/crowdsec_enrollment_debug_spec.md similarity index 100% rename from docs/plans/crowdsec_enrollment_debug_spec.md rename to docs/plans/archive/crowdsec_enrollment_debug_spec.md diff --git a/docs/plans/crowdsec_full_implementation.md b/docs/plans/archive/crowdsec_full_implementation.md similarity index 100% rename from docs/plans/crowdsec_full_implementation.md rename to docs/plans/archive/crowdsec_full_implementation.md diff --git a/docs/plans/crowdsec_hotfix_plan.md b/docs/plans/archive/crowdsec_hotfix_plan.md similarity index 100% rename from docs/plans/crowdsec_hotfix_plan.md rename to docs/plans/archive/crowdsec_hotfix_plan.md diff --git a/docs/plans/crowdsec_lapi_auth_fix.md b/docs/plans/archive/crowdsec_lapi_auth_fix.md similarity index 100% rename from docs/plans/crowdsec_lapi_auth_fix.md rename to docs/plans/archive/crowdsec_lapi_auth_fix.md diff --git a/docs/plans/crowdsec_lapi_error_diagnostic.md b/docs/plans/archive/crowdsec_lapi_error_diagnostic.md similarity index 100% rename from docs/plans/crowdsec_lapi_error_diagnostic.md rename to docs/plans/archive/crowdsec_lapi_error_diagnostic.md diff --git a/docs/plans/crowdsec_lapi_integration_test_spec.md b/docs/plans/archive/crowdsec_lapi_integration_test_spec.md similarity index 100% rename from docs/plans/crowdsec_lapi_integration_test_spec.md rename to docs/plans/archive/crowdsec_lapi_integration_test_spec.md diff --git a/docs/plans/crowdsec_nonroot_fix_spec.md b/docs/plans/archive/crowdsec_nonroot_fix_spec.md similarity index 100% rename from docs/plans/crowdsec_nonroot_fix_spec.md rename to docs/plans/archive/crowdsec_nonroot_fix_spec.md diff --git a/docs/plans/crowdsec_reconciliation_failure.md b/docs/plans/archive/crowdsec_reconciliation_failure.md similarity index 100% rename from docs/plans/crowdsec_reconciliation_failure.md rename to docs/plans/archive/crowdsec_reconciliation_failure.md diff --git a/docs/plans/crowdsec_source_build.md b/docs/plans/archive/crowdsec_source_build.md similarity index 100% rename from docs/plans/crowdsec_source_build.md rename to docs/plans/archive/crowdsec_source_build.md diff --git a/docs/plans/crowdsec_startup_fix.md b/docs/plans/archive/crowdsec_startup_fix.md similarity index 100% rename from docs/plans/crowdsec_startup_fix.md rename to docs/plans/archive/crowdsec_startup_fix.md diff --git a/docs/plans/crowdsec_testing_plan.md b/docs/plans/archive/crowdsec_testing_plan.md similarity index 100% rename from docs/plans/crowdsec_testing_plan.md rename to docs/plans/archive/crowdsec_testing_plan.md diff --git a/docs/plans/crowdsec_toggle_fix_plan.md b/docs/plans/archive/crowdsec_toggle_fix_plan.md similarity index 100% rename from docs/plans/crowdsec_toggle_fix_plan.md rename to docs/plans/archive/crowdsec_toggle_fix_plan.md diff --git a/docs/plans/current_spec.docker-cicd-backup.md b/docs/plans/archive/current_spec.docker-cicd-backup.md similarity index 100% rename from docs/plans/current_spec.docker-cicd-backup.md rename to docs/plans/archive/current_spec.docker-cicd-backup.md diff --git a/docs/plans/current_spec.md.backup b/docs/plans/archive/current_spec.md.backup similarity index 100% rename from docs/plans/current_spec.md.backup rename to docs/plans/archive/current_spec.md.backup diff --git a/docs/plans/custom_dns_plugin_spec.md b/docs/plans/archive/custom_dns_plugin_spec.md similarity index 100% rename from docs/plans/custom_dns_plugin_spec.md rename to docs/plans/archive/custom_dns_plugin_spec.md diff --git a/docs/plans/db_corruption_guardrails_spec.md b/docs/plans/archive/db_corruption_guardrails_spec.md similarity index 100% rename from docs/plans/db_corruption_guardrails_spec.md rename to docs/plans/archive/db_corruption_guardrails_spec.md diff --git a/docs/plans/debian_migration_spec.md b/docs/plans/archive/debian_migration_spec.md similarity index 100% rename from docs/plans/debian_migration_spec.md rename to docs/plans/archive/debian_migration_spec.md diff --git a/docs/plans/archive/design.md b/docs/plans/archive/design.md new file mode 100644 index 00000000..55d45510 --- /dev/null +++ b/docs/plans/archive/design.md @@ -0,0 +1,108 @@ +## Design - Playwright Triage and Remediation Plan + +Source: [docs/plans/current_spec.md](docs/plans/current_spec.md) + +## Architecture Overview + +This plan stabilizes the Playwright harness before addressing product defects. +It defines a failure taxonomy to separate code fixes from test fixes, structures +test subsets into Tier 0-4 suites for staged execution, and documents modal +dropdown remediation patterns and notification template resolution behavior. + +## Failure Taxonomy + +Classification axes: + +- Source of truth + - Code fix: product behavior is incorrect or missing. + - Test fix: test is stale, mislocated, or asserts non-existent behavior. +- Failure mode + - Deterministic: reproducible with the same steps. + - Infra or harness: run ends early, context closed, baseURL or auth mismatch. + +Triage rule: Address harness failures before product or test changes. + +## Test Subset Architecture (Tier 0-4) + +Tier 0: Harness stability +- tests/global-setup.ts +- tests/auth.setup.ts +- tests/utils/wait-helpers.spec.ts + +Tier 1: ProxyHostForm focus +- tests/core/proxy-hosts.spec.ts +- tests/proxy-host-dropdown-fix.spec.ts +- tests/modal-dropdown-triage.spec.ts + +Tier 2: Uptime focus +- tests/monitoring/uptime-monitoring.spec.ts + +Tier 3: Notifications focus +- tests/settings/notifications.spec.ts + +Tier 4: Narrow regression sampling +- tests/settings/account-settings.spec.ts +- tests/tasks/backups-create.spec.ts + +Execution notes: +- Use a single browser (firefox) during triage. +- Run workers=1 for suites that share state or are ordering sensitive. + +## Harness Stability Prerequisites + +- Base URL alignment: auth cookie domain and browser baseURL must match. +- Setup and teardown sequencing must not close contexts still in use. +- Global setup must avoid emergency resets during active runs. +- E2E container must be rebuilt when app or Docker inputs change. + +## Modal Dropdown Fix Patterns (Radix Select Portal Strategy) + +Pattern goals: +- Avoid native select elements inside pointer-events-none modal layers. +- Render dropdown content via portal to escape modal stacking context. +- Ensure the trigger and content use consistent z-index and focus styles. + +Radix Select strategy: +- Use Radix Select for modal dropdowns. +- Configure portal rendering for dropdown content. +- Validate pointer and keyboard interaction paths (open, navigate, select). + +## Notification Template Resolution Flow + +Behavioral flow: +1. UI selects provider defaults and template (minimal or detailed). +2. Backend resolves template with provider-specific requirements. +3. Preview and test send use the same resolution and validation logic. +4. Discord and Slack defaults must include required content fields. + +Validation outcomes: +- Discord payload contains content or embeds. +- Slack payload contains text. +- Preview payload matches test send payload for the same inputs. + +## Domain/DNS Suite Stabilization + +Approach: + +- Use authenticated fixtures for domain and DNS provider workflows. +- Seed domain and DNS provider data via API before UI assertions. +- Add API readiness waits for list and mutation endpoints before UI interaction. +- Use dialog waits for DNS provider form and deletion confirmation flows. + +## Traceability + +- Requirements: [docs/plans/requirements.md](docs/plans/requirements.md) +- Tasks: [docs/plans/tasks.md](docs/plans/tasks.md) + +## Execution Outcomes + +- Harness stability fixes completed, resolving context closure failures. +- ProxyHostForm and Uptime validation confirmed using Radix Select. +- Notifications templates aligned with fallback defaults for provider requirements. +- Role gating bug fix applied for the Backups empty state. +- 135 Playwright tests passing across 5 tiers. + +## Remaining Phases + +- Phase 6: Documentation and hygiene review. +- Phase 7: Validation and coverage gates. diff --git a/docs/plans/dns_challenge_backend_research.md b/docs/plans/archive/dns_challenge_backend_research.md similarity index 100% rename from docs/plans/dns_challenge_backend_research.md rename to docs/plans/archive/dns_challenge_backend_research.md diff --git a/docs/plans/dns_challenge_frontend_research.md b/docs/plans/archive/dns_challenge_frontend_research.md similarity index 100% rename from docs/plans/dns_challenge_frontend_research.md rename to docs/plans/archive/dns_challenge_frontend_research.md diff --git a/docs/plans/dns_challenge_future_features.md b/docs/plans/archive/dns_challenge_future_features.md similarity index 100% rename from docs/plans/dns_challenge_future_features.md rename to docs/plans/archive/dns_challenge_future_features.md diff --git a/docs/plans/dns_future_features_implementation.md b/docs/plans/archive/dns_future_features_implementation.md similarity index 100% rename from docs/plans/dns_future_features_implementation.md rename to docs/plans/archive/dns_future_features_implementation.md diff --git a/docs/plans/docker_compose_ci_fix.md b/docs/plans/archive/docker_compose_ci_fix.md similarity index 100% rename from docs/plans/docker_compose_ci_fix.md rename to docs/plans/archive/docker_compose_ci_fix.md diff --git a/docs/plans/docker_compose_ci_fix_summary.md b/docs/plans/archive/docker_compose_ci_fix_summary.md similarity index 100% rename from docs/plans/docker_compose_ci_fix_summary.md rename to docs/plans/archive/docker_compose_ci_fix_summary.md diff --git a/docs/plans/docker_socket_trace.md b/docs/plans/archive/docker_socket_trace.md similarity index 100% rename from docs/plans/docker_socket_trace.md rename to docs/plans/archive/docker_socket_trace.md diff --git a/docs/plans/docker_tag_sanitization.md b/docs/plans/archive/docker_tag_sanitization.md similarity index 100% rename from docs/plans/docker_tag_sanitization.md rename to docs/plans/archive/docker_tag_sanitization.md diff --git a/docs/plans/docs_to_issues_workflow.md b/docs/plans/archive/docs_to_issues_workflow.md similarity index 100% rename from docs/plans/docs_to_issues_workflow.md rename to docs/plans/archive/docs_to_issues_workflow.md diff --git a/docs/plans/docs_workflow_update.md b/docs/plans/archive/docs_workflow_update.md similarity index 100% rename from docs/plans/docs_workflow_update.md rename to docs/plans/archive/docs_workflow_update.md diff --git a/docs/plans/dod_remediation_spec.md b/docs/plans/archive/dod_remediation_spec.md similarity index 100% rename from docs/plans/dod_remediation_spec.md rename to docs/plans/archive/dod_remediation_spec.md diff --git a/docs/plans/e2e-remediation-v4.md b/docs/plans/archive/e2e-remediation-v4.md similarity index 100% rename from docs/plans/e2e-remediation-v4.md rename to docs/plans/archive/e2e-remediation-v4.md diff --git a/docs/plans/e2e-remediation-v5.md b/docs/plans/archive/e2e-remediation-v5.md similarity index 100% rename from docs/plans/e2e-remediation-v5.md rename to docs/plans/archive/e2e-remediation-v5.md diff --git a/docs/plans/e2e-test-fix-spec.md b/docs/plans/archive/e2e-test-fix-spec.md similarity index 100% rename from docs/plans/e2e-test-fix-spec.md rename to docs/plans/archive/e2e-test-fix-spec.md diff --git a/docs/plans/e2e-test-triage-plan.md b/docs/plans/archive/e2e-test-triage-plan.md similarity index 100% rename from docs/plans/e2e-test-triage-plan.md rename to docs/plans/archive/e2e-test-triage-plan.md diff --git a/docs/plans/e2e-test-triage-quick-start.md b/docs/plans/archive/e2e-test-triage-quick-start.md similarity index 100% rename from docs/plans/e2e-test-triage-quick-start.md rename to docs/plans/archive/e2e-test-triage-quick-start.md diff --git a/docs/plans/e2e_ci_failure_diagnosis.md b/docs/plans/archive/e2e_ci_failure_diagnosis.md similarity index 100% rename from docs/plans/e2e_ci_failure_diagnosis.md rename to docs/plans/archive/e2e_ci_failure_diagnosis.md diff --git a/docs/plans/e2e_emergency_token_fix.md b/docs/plans/archive/e2e_emergency_token_fix.md similarity index 100% rename from docs/plans/e2e_emergency_token_fix.md rename to docs/plans/archive/e2e_emergency_token_fix.md diff --git a/docs/plans/e2e_failure_investigation.md b/docs/plans/archive/e2e_failure_investigation.md similarity index 100% rename from docs/plans/e2e_failure_investigation.md rename to docs/plans/archive/e2e_failure_investigation.md diff --git a/docs/plans/e2e_remediation_spec.md b/docs/plans/archive/e2e_remediation_spec.md similarity index 100% rename from docs/plans/e2e_remediation_spec.md rename to docs/plans/archive/e2e_remediation_spec.md diff --git a/docs/plans/e2e_test_failures.md b/docs/plans/archive/e2e_test_failures.md similarity index 100% rename from docs/plans/e2e_test_failures.md rename to docs/plans/archive/e2e_test_failures.md diff --git a/docs/plans/e2e_test_fix_v2.md b/docs/plans/archive/e2e_test_fix_v2.md similarity index 100% rename from docs/plans/e2e_test_fix_v2.md rename to docs/plans/archive/e2e_test_fix_v2.md diff --git a/docs/plans/fix_e2e_failures.md b/docs/plans/archive/fix_e2e_failures.md similarity index 100% rename from docs/plans/fix_e2e_failures.md rename to docs/plans/archive/fix_e2e_failures.md diff --git a/docs/plans/fix_generateconfig_tests.md b/docs/plans/archive/fix_generateconfig_tests.md similarity index 100% rename from docs/plans/fix_generateconfig_tests.md rename to docs/plans/archive/fix_generateconfig_tests.md diff --git a/docs/plans/fix_workflow_concurrency.md b/docs/plans/archive/fix_workflow_concurrency.md similarity index 100% rename from docs/plans/fix_workflow_concurrency.md rename to docs/plans/archive/fix_workflow_concurrency.md diff --git a/docs/plans/frontend_coverage_boost.md b/docs/plans/archive/frontend_coverage_boost.md similarity index 100% rename from docs/plans/frontend_coverage_boost.md rename to docs/plans/archive/frontend_coverage_boost.md diff --git a/docs/plans/frontend_coverage_test_plan.md b/docs/plans/archive/frontend_coverage_test_plan.md similarity index 100% rename from docs/plans/frontend_coverage_test_plan.md rename to docs/plans/archive/frontend_coverage_test_plan.md diff --git a/docs/plans/geolite2_checksum_fix_spec.md b/docs/plans/archive/geolite2_checksum_fix_spec.md similarity index 100% rename from docs/plans/geolite2_checksum_fix_spec.md rename to docs/plans/archive/geolite2_checksum_fix_spec.md diff --git a/docs/plans/go_version_management_strategy.md b/docs/plans/archive/go_version_management_strategy.md similarity index 100% rename from docs/plans/go_version_management_strategy.md rename to docs/plans/archive/go_version_management_strategy.md diff --git a/docs/plans/gorm_security_remediation_plan.md b/docs/plans/archive/gorm_security_remediation_plan.md similarity index 100% rename from docs/plans/gorm_security_remediation_plan.md rename to docs/plans/archive/gorm_security_remediation_plan.md diff --git a/docs/plans/gorm_security_scanner_spec.md b/docs/plans/archive/gorm_security_scanner_spec.md similarity index 100% rename from docs/plans/gorm_security_scanner_spec.md rename to docs/plans/archive/gorm_security_scanner_spec.md diff --git a/docs/plans/handler_test_optimization.md b/docs/plans/archive/handler_test_optimization.md similarity index 100% rename from docs/plans/handler_test_optimization.md rename to docs/plans/archive/handler_test_optimization.md diff --git a/docs/plans/history_rewrite.md b/docs/plans/archive/history_rewrite.md similarity index 100% rename from docs/plans/history_rewrite.md rename to docs/plans/archive/history_rewrite.md diff --git a/docs/plans/import_cert_dashboard_spec.md b/docs/plans/archive/import_cert_dashboard_spec.md similarity index 100% rename from docs/plans/import_cert_dashboard_spec.md rename to docs/plans/archive/import_cert_dashboard_spec.md diff --git a/docs/plans/instruction_compliance_spec.md b/docs/plans/archive/instruction_compliance_spec.md similarity index 100% rename from docs/plans/instruction_compliance_spec.md rename to docs/plans/archive/instruction_compliance_spec.md diff --git a/docs/plans/issue-365-additional-security.md b/docs/plans/archive/issue-365-additional-security.md similarity index 100% rename from docs/plans/issue-365-additional-security.md rename to docs/plans/archive/issue-365-additional-security.md diff --git a/docs/plans/issue-365-remaining-work.md b/docs/plans/archive/issue-365-remaining-work.md similarity index 100% rename from docs/plans/issue-365-remaining-work.md rename to docs/plans/archive/issue-365-remaining-work.md diff --git a/docs/plans/lapi_translation_bugs.md b/docs/plans/archive/lapi_translation_bugs.md similarity index 100% rename from docs/plans/lapi_translation_bugs.md rename to docs/plans/archive/lapi_translation_bugs.md diff --git a/docs/plans/lint_remediation_plan_full.md b/docs/plans/archive/lint_remediation_plan_full.md similarity index 100% rename from docs/plans/lint_remediation_plan_full.md rename to docs/plans/archive/lint_remediation_plan_full.md diff --git a/docs/plans/medium_severity_remediation.md b/docs/plans/archive/medium_severity_remediation.md similarity index 100% rename from docs/plans/medium_severity_remediation.md rename to docs/plans/archive/medium_severity_remediation.md diff --git a/docs/plans/merge-resolution-plan.md b/docs/plans/archive/merge-resolution-plan.md similarity index 100% rename from docs/plans/merge-resolution-plan.md rename to docs/plans/archive/merge-resolution-plan.md diff --git a/docs/plans/nightly_branch_implementation.md b/docs/plans/archive/nightly_branch_implementation.md similarity index 100% rename from docs/plans/nightly_branch_implementation.md rename to docs/plans/archive/nightly_branch_implementation.md diff --git a/docs/plans/nightly_workflow_verification_status.md b/docs/plans/archive/nightly_workflow_verification_status.md similarity index 100% rename from docs/plans/nightly_workflow_verification_status.md rename to docs/plans/archive/nightly_workflow_verification_status.md diff --git a/docs/plans/notification_page_trace.md b/docs/plans/archive/notification_page_trace.md similarity index 100% rename from docs/plans/notification_page_trace.md rename to docs/plans/archive/notification_page_trace.md diff --git a/docs/plans/patch-coverage-codecov.md b/docs/plans/archive/patch-coverage-codecov.md similarity index 100% rename from docs/plans/patch-coverage-codecov.md rename to docs/plans/archive/patch-coverage-codecov.md diff --git a/docs/plans/patch_coverage_spec.md b/docs/plans/archive/patch_coverage_spec.md similarity index 100% rename from docs/plans/patch_coverage_spec.md rename to docs/plans/archive/patch_coverage_spec.md diff --git a/docs/plans/phase1-failures-remediation.md b/docs/plans/archive/phase1-failures-remediation.md similarity index 100% rename from docs/plans/phase1-failures-remediation.md rename to docs/plans/archive/phase1-failures-remediation.md diff --git a/docs/plans/phase1-skipped-tests-remediation.md b/docs/plans/archive/phase1-skipped-tests-remediation.md similarity index 100% rename from docs/plans/phase1-skipped-tests-remediation.md rename to docs/plans/archive/phase1-skipped-tests-remediation.md diff --git a/docs/plans/phase2_docker_integration_discovery.md b/docs/plans/archive/phase2_docker_integration_discovery.md similarity index 100% rename from docs/plans/phase2_docker_integration_discovery.md rename to docs/plans/archive/phase2_docker_integration_discovery.md diff --git a/docs/plans/phase2_remediation.md b/docs/plans/archive/phase2_remediation.md similarity index 100% rename from docs/plans/phase2_remediation.md rename to docs/plans/archive/phase2_remediation.md diff --git a/docs/plans/phase2_user_mgmt_discovery.md b/docs/plans/archive/phase2_user_mgmt_discovery.md similarity index 100% rename from docs/plans/phase2_user_mgmt_discovery.md rename to docs/plans/archive/phase2_user_mgmt_discovery.md diff --git a/docs/plans/phase3_blockers_remediation.md b/docs/plans/archive/phase3_blockers_remediation.md similarity index 100% rename from docs/plans/phase3_blockers_remediation.md rename to docs/plans/archive/phase3_blockers_remediation.md diff --git a/docs/plans/phase3_caddy_integration_completion.md b/docs/plans/archive/phase3_caddy_integration_completion.md similarity index 100% rename from docs/plans/phase3_caddy_integration_completion.md rename to docs/plans/archive/phase3_caddy_integration_completion.md diff --git a/docs/plans/phase3_completion_summary.md b/docs/plans/archive/phase3_completion_summary.md similarity index 100% rename from docs/plans/phase3_completion_summary.md rename to docs/plans/archive/phase3_completion_summary.md diff --git a/docs/plans/phase4-settings-plan.md b/docs/plans/archive/phase4-settings-plan.md similarity index 100% rename from docs/plans/phase4-settings-plan.md rename to docs/plans/archive/phase4-settings-plan.md diff --git a/docs/plans/phase4-test-remediation.md b/docs/plans/archive/phase4-test-remediation.md similarity index 100% rename from docs/plans/phase4-test-remediation.md rename to docs/plans/archive/phase4-test-remediation.md diff --git a/docs/plans/phase4_security_toggles_spec.md b/docs/plans/archive/phase4_security_toggles_spec.md similarity index 100% rename from docs/plans/phase4_security_toggles_spec.md rename to docs/plans/archive/phase4_security_toggles_spec.md diff --git a/docs/plans/phase5-implementation.md b/docs/plans/archive/phase5-implementation.md similarity index 100% rename from docs/plans/phase5-implementation.md rename to docs/plans/archive/phase5-implementation.md diff --git a/docs/plans/phase5_custom_plugins_spec.md b/docs/plans/archive/phase5_custom_plugins_spec.md similarity index 100% rename from docs/plans/phase5_custom_plugins_spec.md rename to docs/plans/archive/phase5_custom_plugins_spec.md diff --git a/docs/plans/phase_2_failure_analysis.md b/docs/plans/archive/phase_2_failure_analysis.md similarity index 100% rename from docs/plans/phase_2_failure_analysis.md rename to docs/plans/archive/phase_2_failure_analysis.md diff --git a/docs/plans/phase_2_fix_plan.md b/docs/plans/archive/phase_2_fix_plan.md similarity index 100% rename from docs/plans/phase_2_fix_plan.md rename to docs/plans/archive/phase_2_fix_plan.md diff --git a/docs/plans/phase_2_interruption_analysis.md b/docs/plans/archive/phase_2_interruption_analysis.md similarity index 100% rename from docs/plans/phase_2_interruption_analysis.md rename to docs/plans/archive/phase_2_interruption_analysis.md diff --git a/docs/plans/phase_2_test_organization_audit.md b/docs/plans/archive/phase_2_test_organization_audit.md similarity index 100% rename from docs/plans/phase_2_test_organization_audit.md rename to docs/plans/archive/phase_2_test_organization_audit.md diff --git a/docs/plans/playright_remidiation_2026.02.04.md b/docs/plans/archive/playright_remidiation_2026.02.04.md similarity index 100% rename from docs/plans/playright_remidiation_2026.02.04.md rename to docs/plans/archive/playright_remidiation_2026.02.04.md diff --git a/docs/plans/playwright-coverage-fix.md b/docs/plans/archive/playwright-coverage-fix.md similarity index 100% rename from docs/plans/playwright-coverage-fix.md rename to docs/plans/archive/playwright-coverage-fix.md diff --git a/docs/plans/playwright-coverage-plan.md b/docs/plans/archive/playwright-coverage-plan.md similarity index 100% rename from docs/plans/playwright-coverage-plan.md rename to docs/plans/archive/playwright-coverage-plan.md diff --git a/docs/plans/post_rebuild_diagnostic.md b/docs/plans/archive/post_rebuild_diagnostic.md similarity index 100% rename from docs/plans/post_rebuild_diagnostic.md rename to docs/plans/archive/post_rebuild_diagnostic.md diff --git a/docs/plans/pr-434-docker-analysis.md b/docs/plans/archive/pr-434-docker-analysis.md similarity index 100% rename from docs/plans/pr-434-docker-analysis.md rename to docs/plans/archive/pr-434-docker-analysis.md diff --git a/docs/plans/pr1_blocker_remediation.md b/docs/plans/archive/pr1_blocker_remediation.md similarity index 100% rename from docs/plans/pr1_blocker_remediation.md rename to docs/plans/archive/pr1_blocker_remediation.md diff --git a/docs/plans/pr460_frontend_coverage.md b/docs/plans/archive/pr460_frontend_coverage.md similarity index 100% rename from docs/plans/pr460_frontend_coverage.md rename to docs/plans/archive/pr460_frontend_coverage.md diff --git a/docs/plans/pr583_patch_coverage_spec.md b/docs/plans/archive/pr583_patch_coverage_spec.md similarity index 100% rename from docs/plans/pr583_patch_coverage_spec.md rename to docs/plans/archive/pr583_patch_coverage_spec.md diff --git a/docs/plans/precommit_performance_fix_spec.md b/docs/plans/archive/precommit_performance_fix_spec.md similarity index 100% rename from docs/plans/precommit_performance_fix_spec.md rename to docs/plans/archive/precommit_performance_fix_spec.md diff --git a/docs/plans/prev_spec_archived_dec16.md b/docs/plans/archive/prev_spec_archived_dec16.md similarity index 100% rename from docs/plans/prev_spec_archived_dec16.md rename to docs/plans/archive/prev_spec_archived_dec16.md diff --git a/docs/plans/prev_spec_ci_investigation_dec18.md b/docs/plans/archive/prev_spec_ci_investigation_dec18.md similarity index 100% rename from docs/plans/prev_spec_ci_investigation_dec18.md rename to docs/plans/archive/prev_spec_ci_investigation_dec18.md diff --git a/docs/plans/prev_spec_docker_socket_500_dec23.md b/docs/plans/archive/prev_spec_docker_socket_500_dec23.md similarity index 100% rename from docs/plans/prev_spec_docker_socket_500_dec23.md rename to docs/plans/archive/prev_spec_docker_socket_500_dec23.md diff --git a/docs/plans/prev_spec_i18n_language_selector_dec19.md b/docs/plans/archive/prev_spec_i18n_language_selector_dec19.md similarity index 100% rename from docs/plans/prev_spec_i18n_language_selector_dec19.md rename to docs/plans/archive/prev_spec_i18n_language_selector_dec19.md diff --git a/docs/plans/prev_spec_security_headers_persistence_dec18.md b/docs/plans/archive/prev_spec_security_headers_persistence_dec18.md similarity index 100% rename from docs/plans/prev_spec_security_headers_persistence_dec18.md rename to docs/plans/archive/prev_spec_security_headers_persistence_dec18.md diff --git a/docs/plans/prev_spec_standard_proxy_headers_dec19.md b/docs/plans/archive/prev_spec_standard_proxy_headers_dec19.md similarity index 100% rename from docs/plans/prev_spec_standard_proxy_headers_dec19.md rename to docs/plans/archive/prev_spec_standard_proxy_headers_dec19.md diff --git a/docs/plans/prev_spec_test_coverage_dec24.md b/docs/plans/archive/prev_spec_test_coverage_dec24.md similarity index 100% rename from docs/plans/prev_spec_test_coverage_dec24.md rename to docs/plans/archive/prev_spec_test_coverage_dec24.md diff --git a/docs/plans/prev_spec_uiux_dec16.md b/docs/plans/archive/prev_spec_uiux_dec16.md similarity index 100% rename from docs/plans/prev_spec_uiux_dec16.md rename to docs/plans/archive/prev_spec_uiux_dec16.md diff --git a/docs/plans/prev_spec_websocket_fix_dec16.md b/docs/plans/archive/prev_spec_websocket_fix_dec16.md similarity index 100% rename from docs/plans/prev_spec_websocket_fix_dec16.md rename to docs/plans/archive/prev_spec_websocket_fix_dec16.md diff --git a/docs/plans/prev_spec_xforwarded_port_investigation.md b/docs/plans/archive/prev_spec_xforwarded_port_investigation.md similarity index 100% rename from docs/plans/prev_spec_xforwarded_port_investigation.md rename to docs/plans/archive/prev_spec_xforwarded_port_investigation.md diff --git a/docs/plans/propagation_workflow_update.md b/docs/plans/archive/propagation_workflow_update.md similarity index 100% rename from docs/plans/propagation_workflow_update.md rename to docs/plans/archive/propagation_workflow_update.md diff --git a/docs/plans/qa_remediation.md b/docs/plans/archive/qa_remediation.md similarity index 100% rename from docs/plans/qa_remediation.md rename to docs/plans/archive/qa_remediation.md diff --git a/docs/plans/qa_remediation_full_plan.md b/docs/plans/archive/qa_remediation_full_plan.md similarity index 100% rename from docs/plans/qa_remediation_full_plan.md rename to docs/plans/archive/qa_remediation_full_plan.md diff --git a/docs/plans/rate_limiter_testing_plan.md b/docs/plans/archive/rate_limiter_testing_plan.md similarity index 100% rename from docs/plans/rate_limiter_testing_plan.md rename to docs/plans/archive/rate_limiter_testing_plan.md diff --git a/docs/plans/react-activity-icon-error-plan.md b/docs/plans/archive/react-activity-icon-error-plan.md similarity index 100% rename from docs/plans/react-activity-icon-error-plan.md rename to docs/plans/archive/react-activity-icon-error-plan.md diff --git a/docs/plans/rebase_resolution.md b/docs/plans/archive/rebase_resolution.md similarity index 100% rename from docs/plans/rebase_resolution.md rename to docs/plans/archive/rebase_resolution.md diff --git a/docs/plans/reddit_feedback_spec.md b/docs/plans/archive/reddit_feedback_spec.md similarity index 100% rename from docs/plans/reddit_feedback_spec.md rename to docs/plans/archive/reddit_feedback_spec.md diff --git a/docs/plans/archive/requirements.md b/docs/plans/archive/requirements.md new file mode 100644 index 00000000..ad14d56d --- /dev/null +++ b/docs/plans/archive/requirements.md @@ -0,0 +1,30 @@ +## Requirements - Playwright Triage and Remediation Plan + +Source: [docs/plans/current_spec.md](docs/plans/current_spec.md) + +## EARS Requirements + +1. WHEN Tier 0 through Tier 4 test subsets are executed, THE SYSTEM SHALL complete each tier without early termination or context-closed failures. +2. WHEN the ProxyHostForm modal dropdowns are opened, THE SYSTEM SHALL allow selection changes using pointer input. +3. WHEN the ProxyHostForm modal dropdowns are opened, THE SYSTEM SHALL allow keyboard navigation with visible focus for open, navigate, and select actions. +4. WHEN the Uptime create monitor modal dropdown is opened, THE SYSTEM SHALL allow selecting a monitor type without click failures. +5. WHEN the Uptime create monitor modal dropdown is opened, THE SYSTEM SHALL allow keyboard navigation with visible focus for open, navigate, and select actions. +6. WHEN a Discord provider uses the default minimal template, THE SYSTEM SHALL send a payload that contains content or embeds as required. +7. WHEN a Slack provider uses the default minimal template, THE SYSTEM SHALL send a payload that contains text as required. +8. WHEN provider preview is requested, THE SYSTEM SHALL validate and render the same payload shape as test send for the same provider and template. +9. WHEN the Domains page is loaded, THE SYSTEM SHALL allow creating a domain via the add form and reflect it after the create API completes. +10. WHEN a domain delete action is confirmed, THE SYSTEM SHALL remove the domain after the delete API completes. +11. WHEN the DNS Providers page is loaded, THE SYSTEM SHALL render provider cards for API-seeded providers and load provider types when the add form opens. + +## Execution Outcomes + +- Harness stability fixes completed, resolving context closure failures. +- ProxyHostForm and Uptime validation confirmed using Radix Select. +- Notifications templates aligned with fallback defaults for provider requirements. +- Role gating bug fix applied for the Backups empty state. +- 135 Playwright tests passing across 5 tiers. + +## Remaining Phases + +- Phase 6: Documentation and hygiene review. +- Phase 7: Validation and coverage gates. diff --git a/docs/plans/revert_ci_pipeline.md b/docs/plans/archive/revert_ci_pipeline.md similarity index 100% rename from docs/plans/revert_ci_pipeline.md rename to docs/plans/archive/revert_ci_pipeline.md diff --git a/docs/plans/sample_orchestration_plan.md b/docs/plans/archive/sample_orchestration_plan.md similarity index 100% rename from docs/plans/sample_orchestration_plan.md rename to docs/plans/archive/sample_orchestration_plan.md diff --git a/docs/plans/security_features_spec.md b/docs/plans/archive/security_features_spec.md similarity index 100% rename from docs/plans/security_features_spec.md rename to docs/plans/archive/security_features_spec.md diff --git a/docs/plans/security_headers_apply_preset_analysis.md b/docs/plans/archive/security_headers_apply_preset_analysis.md similarity index 100% rename from docs/plans/security_headers_apply_preset_analysis.md rename to docs/plans/archive/security_headers_apply_preset_analysis.md diff --git a/docs/plans/security_headers_investigation.md b/docs/plans/archive/security_headers_investigation.md similarity index 100% rename from docs/plans/security_headers_investigation.md rename to docs/plans/archive/security_headers_investigation.md diff --git a/docs/plans/security_remediation_plan.md b/docs/plans/archive/security_remediation_plan.md similarity index 100% rename from docs/plans/security_remediation_plan.md rename to docs/plans/archive/security_remediation_plan.md diff --git a/docs/plans/security_suite_remediation.md b/docs/plans/archive/security_suite_remediation.md similarity index 100% rename from docs/plans/security_suite_remediation.md rename to docs/plans/archive/security_suite_remediation.md diff --git a/docs/plans/security_tooling_analysis.md b/docs/plans/archive/security_tooling_analysis.md similarity index 100% rename from docs/plans/security_tooling_analysis.md rename to docs/plans/archive/security_tooling_analysis.md diff --git a/docs/plans/security_vulnerability_remediation.md b/docs/plans/archive/security_vulnerability_remediation.md similarity index 100% rename from docs/plans/security_vulnerability_remediation.md rename to docs/plans/archive/security_vulnerability_remediation.md diff --git a/docs/plans/shard1_fix_plan.md b/docs/plans/archive/shard1_fix_plan.md similarity index 100% rename from docs/plans/shard1_fix_plan.md rename to docs/plans/archive/shard1_fix_plan.md diff --git a/docs/plans/shard1_investigation_summary.md b/docs/plans/archive/shard1_investigation_summary.md similarity index 100% rename from docs/plans/shard1_investigation_summary.md rename to docs/plans/archive/shard1_investigation_summary.md diff --git a/docs/plans/skipped-tests-remediation.md b/docs/plans/archive/skipped-tests-remediation.md similarity index 100% rename from docs/plans/skipped-tests-remediation.md rename to docs/plans/archive/skipped-tests-remediation.md diff --git a/docs/plans/skipped_tests_remediation.md b/docs/plans/archive/skipped_tests_remediation.md similarity index 100% rename from docs/plans/skipped_tests_remediation.md rename to docs/plans/archive/skipped_tests_remediation.md diff --git a/docs/plans/ssl_card_pending_fix.md b/docs/plans/archive/ssl_card_pending_fix.md similarity index 100% rename from docs/plans/ssl_card_pending_fix.md rename to docs/plans/archive/ssl_card_pending_fix.md diff --git a/docs/plans/ssrf-remediation.md b/docs/plans/archive/ssrf-remediation.md similarity index 100% rename from docs/plans/ssrf-remediation.md rename to docs/plans/archive/ssrf-remediation.md diff --git a/docs/plans/ssrf_handler_fix_spec.md b/docs/plans/archive/ssrf_handler_fix_spec.md similarity index 100% rename from docs/plans/ssrf_handler_fix_spec.md rename to docs/plans/archive/ssrf_handler_fix_spec.md diff --git a/docs/plans/ssrf_remediation_spec.md b/docs/plans/archive/ssrf_remediation_spec.md similarity index 100% rename from docs/plans/ssrf_remediation_spec.md rename to docs/plans/archive/ssrf_remediation_spec.md diff --git a/docs/plans/structure.md b/docs/plans/archive/structure.md similarity index 100% rename from docs/plans/structure.md rename to docs/plans/archive/structure.md diff --git a/docs/plans/supply_chain_fix.md b/docs/plans/archive/supply_chain_fix.md similarity index 100% rename from docs/plans/supply_chain_fix.md rename to docs/plans/archive/supply_chain_fix.md diff --git a/docs/plans/supply_chain_manual_grype.md b/docs/plans/archive/supply_chain_manual_grype.md similarity index 100% rename from docs/plans/supply_chain_manual_grype.md rename to docs/plans/archive/supply_chain_manual_grype.md diff --git a/docs/plans/supply_chain_security_implementation.md b/docs/plans/archive/supply_chain_security_implementation.md similarity index 100% rename from docs/plans/supply_chain_security_implementation.md rename to docs/plans/archive/supply_chain_security_implementation.md diff --git a/docs/plans/archive/supply_chain_security_implementation.md.backup b/docs/plans/archive/supply_chain_security_implementation.md.backup new file mode 100644 index 00000000..baf4cb38 --- /dev/null +++ b/docs/plans/archive/supply_chain_security_implementation.md.backup @@ -0,0 +1,1739 @@ +# Supply Chain Security Implementation Plan + +**Version**: 2.0 +**Date**: 2026-01-10 +**Updated**: 2026-01-10 (Supervisor Feedback) +**Target Completion**: Phase 3 (3-4 weeks) +**Assignee**: DevOps Agent + +--- + +## Executive Summary + +Implement a comprehensive supply chain security solution for Charon using **SBOM verification** (Software Bill of Materials), **Cosign** (artifact signing), and **SLSA** (provenance attestation). This plan integrates signing and verification into GitHub Actions workflows, creates production-ready GitHub Skills for local development, adds VS Code tasks for developer workflows, and includes complete key management procedures. + +**Key Goals**: +1. Automate SBOM generation, verification, and vulnerability scanning +2. Sign all Docker images and binaries with Cosign (keyless and local key support) +3. Generate and verify SLSA provenance for all releases +4. Enable local testing via complete, tested GitHub Skills +5. Update Management agent Definition of Done with supply chain verification +6. Establish performance baselines and monitoring +7. Implement fallback mechanisms for service outages + +**Implementation Priority** (Revised): +- **Phase 1**: SBOM Verification (Week 1) - Foundation for supply chain visibility +- **Phase 2**: Cosign Integration (Week 2) - Artifact signing and integrity +- **Phase 3**: SLSA Provenance (Week 3) - Build transparency and attestation + +--- + +## Background + +### Current State +- โœ… SBOM generation exists in `docker-build.yml` (Anchore SBOM action) +- โœ… SBOM attestation exists in `docker-build.yml` (actions/attest-sbom) +- โŒ No SBOM vulnerability scanning or semantic diffing +- โŒ No Cosign signing for artifacts +- โŒ No SLSA provenance generation +- โŒ No verification workflows with PR triggers +- โŒ No local testing skills (complete implementation) +- โŒ No local key management procedures +- โŒ No performance baselines or monitoring +- โŒ No Rekor fallback mechanisms + +### Security Requirements +- **SLSA Level 2+**: Provenance generation with isolated build system +- **Keyless Signing**: Use GitHub OIDC tokens (no long-lived keys in CI) +- **Local Key Management**: Secure procedures for development signing with key-based signing +- **Transparency Logs**: All signatures stored in Rekor with fallback for outages +- **Verification**: Automated verification in CI (including PRs) and pre-deployment +- **Developer Access**: Complete, tested local signing/verification via Skills +- **Vulnerability Scanning**: Automated SBOM scanning with Grype/Trivy +- **Semantic SBOM Diffing**: Use sbom-diff or similar for component analysis +- **Performance Monitoring**: Baseline measurements and continuous tracking +- **Air-Gapped Support**: Local signing without internet connectivity +- **Standardization**: SPDX format for all SBOMs + +--- + +## Architecture Overview + +### Component Stack + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ GitHub Actions (CI/CD) โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ Workflow: docker-build.yml โ”‚ +โ”‚ โ”œโ”€ Build Docker Image โ”‚ +โ”‚ โ”œโ”€ Generate SBOM (SPDX format) [ENHANCED] โ”‚ +โ”‚ โ”œโ”€ Scan SBOM with Grype/Trivy [NEW] โ”‚ +โ”‚ โ”œโ”€ Diff SBOM with baseline [NEW] โ”‚ +โ”‚ โ”œโ”€ Sign with Cosign (keyless OIDC) [NEW] โ”‚ +โ”‚ โ”œโ”€ Generate SLSA Provenance [NEW] โ”‚ +โ”‚ โ””โ”€ Attest SBOM (existing, enhanced) โ”‚ +โ”‚ โ”‚ +โ”‚ Workflow: release-goreleaser.yml โ”‚ +โ”‚ โ”œโ”€ Build Binaries โ”‚ +โ”‚ โ”œโ”€ Sign with GoReleaser hooks [NEW] โ”‚ +โ”‚ โ”œโ”€ Generate SLSA Provenance [NEW] โ”‚ +โ”‚ โ””โ”€ Attach to GitHub Release โ”‚ +โ”‚ โ”‚ +โ”‚ Workflow: supply-chain-verify.yml [NEW] โ”‚ +โ”‚ โ”œโ”€ Trigger: releases, PRs, schedule โ”‚ +โ”‚ โ”œโ”€ Verify Cosign Signatures (with Rekor fallback) โ”‚ +โ”‚ โ”œโ”€ Verify SLSA Provenance โ”‚ +โ”‚ โ”œโ”€ Verify SBOM (semantic diff + vuln scan) โ”‚ +โ”‚ โ””โ”€ Generate verification report โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ GitHub Skills โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ security-verify-sbom [NEW, COMPLETE] โ”‚ +โ”‚ security-sign-cosign [NEW, COMPLETE] โ”‚ +โ”‚ security-slsa-provenance [NEW, COMPLETE] โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ VS Code Tasks โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ Security: Verify SBOM [NEW] โ”‚ +โ”‚ Security: Sign with Cosign [NEW] โ”‚ +โ”‚ Security: Generate SLSA Provenance [NEW] โ”‚ +โ”‚ Security: Full Supply Chain Audit [NEW] โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ Local Key Management โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ โ”œโ”€ Key generation procedures โ”‚ +โ”‚ โ”œโ”€ Secure storage with encryption โ”‚ +โ”‚ โ”œโ”€ Air-gapped signing support โ”‚ +โ”‚ โ””โ”€ Key rotation and backup โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ Performance Monitoring โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ โ”œโ”€ Build time impact tracking โ”‚ +โ”‚ โ”œโ”€ Verification duration metrics โ”‚ +โ”‚ โ””โ”€ Alert thresholds and dashboards โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +--- + +## Phase 1: SBOM Verification (Week 1) + +**Priority**: CRITICAL - Foundation for supply chain visibility +**Status**: New implementation with enhancements + +### 1.1 Workflow Enhancement + +#### File: `.github/workflows/docker-build.yml` + +**Location**: Enhance existing SBOM generation (around line 160) + +**Changes**: +1. Standardize SBOM format to SPDX +2. Add vulnerability scanning with Grype +3. Implement semantic SBOM diffing +4. Add baseline comparison + +```yaml +# Replace existing SBOM generation step with enhanced version + +- name: Generate SBOM (SPDX Format) + if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' + uses: anchore/sbom-action@d94f46e13c6c62f59525ac9a1e147a99dc0b9bf5 # v0.21.0 + with: + image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }} + format: spdx-json + output-file: sbom-spdx.json + upload-artifact: true + upload-release-assets: true + +- name: Scan SBOM for Vulnerabilities + if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' + run: | + # Install Grype + curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin + + # Scan SBOM + echo "Scanning SBOM for vulnerabilities..." + grype sbom:sbom-spdx.json -o json > vuln-results.json + grype sbom:sbom-spdx.json -o table + + # Check for critical/high vulnerabilities + CRITICAL_COUNT=$(jq '[.matches[] | select(.vulnerability.severity == "Critical")] | length' vuln-results.json) + HIGH_COUNT=$(jq '[.matches[] | select(.vulnerability.severity == "High")] | length' vuln-results.json) + + echo "Critical vulnerabilities: ${CRITICAL_COUNT}" + echo "High vulnerabilities: ${HIGH_COUNT}" + + if [[ ${CRITICAL_COUNT} -gt 0 ]]; then + echo "โŒ Critical vulnerabilities found - review required" + # Don't fail build, but warn + echo "::warning::${CRITICAL_COUNT} critical vulnerabilities found in SBOM" + fi + +- name: SBOM Semantic Diff + if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' + continue-on-error: true + run: | + # Install sbom-diff tool + go install github.com/interlynk-io/sbomasm/cmd/sbomasm@latest + + # Download previous SBOM if exists + if gh release view latest --json assets -q '.assets[] | select(.name == "sbom-spdx.json") | .url' > /dev/null 2>&1; then + gh release download latest --pattern "sbom-spdx.json" --output sbom-baseline.json + + echo "Comparing current SBOM with baseline..." + + # Compare component counts + BASELINE_COUNT=$(jq '.packages | length' sbom-baseline.json) + CURRENT_COUNT=$(jq '.packages | length' sbom-spdx.json) + + echo "Baseline packages: ${BASELINE_COUNT}" + echo "Current packages: ${CURRENT_COUNT}" + echo "Delta: $((CURRENT_COUNT - BASELINE_COUNT))" + + # Identify added/removed packages + jq -r '.packages[].name' sbom-baseline.json | sort > baseline-packages.txt + jq -r '.packages[].name' sbom-spdx.json | sort > current-packages.txt + + echo "Removed packages:" + comm -23 baseline-packages.txt current-packages.txt || true + + echo "Added packages:" + comm -13 baseline-packages.txt current-packages.txt || true + else + echo "No baseline SBOM found - this will become the baseline" + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +- name: Attest SBOM + if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' + uses: actions/attest-sbom@210638bd5681be69f5648391e3b0a389d2d08e5b # v3.0.0 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + subject-digest: ${{ steps.build-and-push.outputs.digest }} + sbom-path: sbom-spdx.json + push-to-registry: true +``` + +### 1.2 Workflow Creation: Verification with PR Triggers + +#### File: `.github/workflows/supply-chain-verify.yml` [NEW] + +**Location**: `.github/workflows/supply-chain-verify.yml` + +**Purpose**: Automated verification workflow triggered on releases, PRs, and schedules + +```yaml +name: Supply Chain Verification + +on: + release: + types: [published] + pull_request: # NEW: Add PR trigger + paths: + - '.github/workflows/docker-build.yml' + - '.github/workflows/release-goreleaser.yml' + - 'Dockerfile' + - 'backend/**' + - 'frontend/**' + schedule: + # Run weekly on Mondays at 00:00 UTC + - cron: '0 0 * * 1' + workflow_dispatch: + +permissions: + contents: read + packages: read + id-token: write # NEW: OIDC token for keyless verification + attestations: write # NEW: Create/verify attestations + security-events: write + pull-requests: write # NEW: Comment on PRs + +jobs: + verify-sbom: + name: Verify SBOM + runs-on: ubuntu-latest + if: github.event_name != 'schedule' || github.ref == 'refs/heads/main' + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Install Verification Tools + run: | + # Install Syft + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + + # Install Grype + curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin + + # Install sbom-diff + go install github.com/interlynk-io/sbomasm/cmd/sbomasm@latest + + - name: Determine Image Tag + id: tag + run: | + if [[ "${{ github.event_name }}" == "release" ]]; then + TAG="${{ github.event.release.tag_name }}" + elif [[ "${{ github.event_name }}" == "pull_request" ]]; then + TAG="pr-${{ github.event.pull_request.number }}" + else + TAG="latest" + fi + echo "tag=${TAG}" >> $GITHUB_OUTPUT + + - name: Verify SBOM Completeness + env: + IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }} + run: | + echo "Verifying SBOM for ${IMAGE}..." + + # Generate fresh SBOM + syft ${IMAGE} -o spdx-json > sbom-generated.json + + # Download attested SBOM + gh attestation download ${IMAGE} --digest-alg sha256 \ + --predicate-type https://spdx.dev/Document \ + --output sbom-attested.json || { + echo "โš ๏ธ No attested SBOM found - may be PR build" + exit 0 + } + + # Semantic comparison using sbomasm + GENERATED_COUNT=$(jq '.packages | length' sbom-generated.json) + ATTESTED_COUNT=$(jq '.packages | length' sbom-attested.json) + + echo "Generated SBOM packages: ${GENERATED_COUNT}" + echo "Attested SBOM packages: ${ATTESTED_COUNT}" + + # Allow 5% variance + DIFF=$((GENERATED_COUNT - ATTESTED_COUNT)) + DIFF_ABS=${DIFF#-} + DIFF_PCT=$((100 * DIFF_ABS / GENERATED_COUNT)) + + if [[ ${DIFF_PCT} -gt 5 ]]; then + echo "โŒ SBOM package mismatch exceeds 5%" + exit 1 + fi + + echo "โœ… SBOM verification passed (${DIFF_PCT}% variance)" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Scan for Vulnerabilities + continue-on-error: true + env: + IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }} + run: | + echo "Scanning for vulnerabilities..." + grype ${IMAGE} -o json > vuln-scan.json + grype ${IMAGE} -o table + + CRITICAL=$(jq '[.matches[] | select(.vulnerability.severity == "Critical")] | length' vuln-scan.json) + HIGH=$(jq '[.matches[] | select(.vulnerability.severity == "High")] | length' vuln-scan.json) + + echo "Critical: ${CRITICAL}, High: ${HIGH}" + + if [[ ${CRITICAL} -gt 0 ]]; then + echo "::warning::${CRITICAL} critical vulnerabilities found" + fi + + - name: Comment on PR + if: github.event_name == 'pull_request' + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const fs = require('fs'); + const vulnData = JSON.parse(fs.readFileSync('vuln-scan.json', 'utf8')); + const critical = vulnData.matches.filter(m => m.vulnerability.severity === 'Critical').length; + const high = vulnData.matches.filter(m => m.vulnerability.severity === 'High').length; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `## ๐Ÿ”’ Supply Chain Verification\n\nโœ… SBOM verified\n๐Ÿ“Š Vulnerabilities: ${critical} Critical, ${high} High\n\n[View full report](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})` + }); + + verify-docker-image: + name: Verify Docker Image Supply Chain + runs-on: ubuntu-latest + if: github.event_name == 'release' + needs: verify-sbom + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Install Verification Tools + run: | + # Install Cosign (pinned to commit SHA) + curl -sLO https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64 + echo "4e84f155f98be2c2d3e63dea0e80b0ca5b4d843f5f4b1d3e8c9b7e4e7c0e0e0e cosign-linux-amd64" | sha256sum -c + sudo install cosign-linux-amd64 /usr/local/bin/cosign + rm cosign-linux-amd64 + + # Install SLSA Verifier (pinned to commit SHA) + curl -sLO https://github.com/slsa-framework/slsa-verifier/releases/download/v2.6.0/slsa-verifier-linux-amd64 + echo "7e4c88e0de4b5e3e0e8f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f slsa-verifier-linux-amd64" | sha256sum -c + sudo install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier + rm slsa-verifier-linux-amd64 + + - name: Determine Image Tag + id: tag + run: | + TAG="${{ github.event.release.tag_name }}" + echo "tag=${TAG}" >> $GITHUB_OUTPUT + + - name: Verify Cosign Signature with Rekor Fallback + env: + IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }} + run: | + echo "Verifying Cosign signature for ${IMAGE}..." + + # Try with Rekor + if cosign verify ${IMAGE} \ + --certificate-identity-regexp="https://github.com/${{ github.repository }}" \ + --certificate-oidc-issuer="https://token.actions.githubusercontent.com" 2>&1; then + echo "โœ… Cosign signature verified (with Rekor)" + else + echo "โš ๏ธ Rekor verification failed, trying offline verification..." + + # Fallback: verify without Rekor + if cosign verify ${IMAGE} \ + --certificate-identity-regexp="https://github.com/${{ github.repository }}" \ + --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \ + --insecure-ignore-tlog 2>&1; then + echo "โœ… Cosign signature verified (offline mode)" + echo "::warning::Verified without Rekor - transparency log unavailable" + else + echo "โŒ Signature verification failed" + exit 1 + fi + fi + + - name: Verify SLSA Provenance + env: + IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }} + run: | + echo "Verifying SLSA provenance for ${IMAGE}..." + + # Download provenance + gh attestation download ${IMAGE} --digest-alg sha256 \ + --predicate-type https://slsa.dev/provenance/v1 \ + --output provenance.json + + # Verify provenance + slsa-verifier verify-image ${IMAGE} \ + --provenance-path provenance.json \ + --source-uri github.com/${{ github.repository }} + + echo "โœ… SLSA provenance verified" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create Verification Report + if: always() + run: | + cat << EOF > verification-report.md + # Supply Chain Verification Report + + **Image**: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }} + **Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC") + **Workflow**: ${{ github.workflow }} + **Run**: ${{ github.run_id }} + + ## Results + + - **SBOM Verification**: ${{ needs.verify-sbom.result }} + - **Cosign Signature**: ${{ job.status }} + - **SLSA Provenance**: ${{ job.status }} + + ## Verification Failure Recovery + + If verification failed: + 1. Check workflow logs for detailed error messages + 2. Verify signing steps ran successfully in build workflow + 3. Confirm attestations were pushed to registry + 4. Check Rekor status: https://status.sigstore.dev + 5. For Rekor outages, manual verification may be required + 6. Re-run build if signatures/provenance are missing + EOF + + cat verification-report.md >> $GITHUB_STEP_SUMMARY + + verify-release-artifacts: + name: Verify Release Artifacts + runs-on: ubuntu-latest + if: github.event_name == 'release' + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Install Verification Tools + run: | + # Install Cosign (pinned) + curl -sLO https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64 + sudo install cosign-linux-amd64 /usr/local/bin/cosign + rm cosign-linux-amd64 + + # Install SLSA Verifier (pinned) + curl -sLO https://github.com/slsa-framework/slsa-verifier/releases/download/v2.6.0/slsa-verifier-linux-amd64 + sudo install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier + rm slsa-verifier-linux-amd64 + + - name: Download Release Assets + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + TAG=${{ github.event.release.tag_name }} + gh release download ${TAG} --dir ./release-assets + + - name: Verify Artifact Signatures with Fallback + run: | + echo "Verifying Cosign signatures for release artifacts..." + + for artifact in ./release-assets/*; do + # Skip signature and certificate files + if [[ "$artifact" == *.sig || "$artifact" == *.pem || "$artifact" == *provenance* ]]; then + continue + fi + + if [[ -f "$artifact" ]]; then + echo "Verifying: $(basename $artifact)" + + # Try with Rekor + if cosign verify-blob "$artifact" \ + --signature "${artifact}.sig" \ + --certificate "${artifact}.pem" \ + --certificate-identity-regexp="https://github.com/${{ github.repository }}" \ + --certificate-oidc-issuer="https://token.actions.githubusercontent.com" 2>&1; then + echo "โœ… Verified with Rekor" + else + echo "โš ๏ธ Rekor unavailable, trying offline..." + cosign verify-blob "$artifact" \ + --signature "${artifact}.sig" \ + --certificate "${artifact}.pem" \ + --certificate-identity-regexp="https://github.com/${{ github.repository }}" \ + --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \ + --insecure-ignore-tlog + echo "โœ… Verified offline" + fi + fi + done + + echo "โœ… All artifact signatures verified" + + - name: Verify Release Provenance + run: | + echo "Verifying SLSA provenance for release..." + + if [[ -f "./release-assets/provenance-release.json" ]]; then + slsa-verifier verify-artifact \ + --provenance-path ./release-assets/provenance-release.json \ + --source-uri github.com/${{ github.repository }} + echo "โœ… Release provenance verified" + else + echo "โš ๏ธ No provenance file found" + exit 1 + fi +``` + +### 1.3 GitHub Skill: `security-verify-sbom` (Complete Implementation) + +#### File: `.github/skills/security-verify-sbom.SKILL.md` + +**Location**: `.github/skills/security-verify-sbom.SKILL.md` + +**Content**: Full SKILL.md specification with parameter validation + +```markdown +--- +name: "security-verify-sbom" +version: "1.0.0" +description: "Verify SBOM completeness, scan for vulnerabilities, and perform semantic diff analysis" +author: "Charon Project" +license: "MIT" +tags: ["security", "sbom", "verification", "supply-chain", "vulnerability-scanning"] +compatibility: + os: ["linux", "darwin"] + shells: ["bash"] +requirements: + - name: "syft" + version: ">=1.17.0" + optional: false + install_url: "https://github.com/anchore/syft" + - name: "grype" + version: ">=0.85.0" + optional: false + install_url: "https://github.com/anchore/grype" + - name: "jq" + version: ">=1.6" + optional: false +environment_variables: + - name: "SBOM_FORMAT" + description: "SBOM format (spdx-json, cyclonedx-json)" + default: "spdx-json" + required: false + - name: "VULN_SCAN_ENABLED" + description: "Enable vulnerability scanning" + default: "true" + required: false +parameters: + - name: "target" + type: "string" + description: "Docker image or file path" + required: true + validation: "^[a-zA-Z0-9:/@._-]+$" + - name: "baseline" + type: "string" + description: "Baseline SBOM file path for comparison" + required: false + default: "" + - name: "vuln_scan" + type: "boolean" + description: "Run vulnerability scan" + required: false + default: true +exit_codes: + 0: "Verification successful" + 1: "Verification failed or critical vulnerabilities found" + 2: "Missing dependencies or invalid parameters" +--- + +# Security: Verify SBOM + +Verify Software Bill of Materials (SBOM) completeness, scan for vulnerabilities, and perform semantic diff analysis. + +## Features + +- Generate SBOM in SPDX format (standardized) +- Compare with baseline SBOM (semantic diff) +- Scan for vulnerabilities (Critical/High/Medium/Low) +- Validate SBOM structure and completeness +- Support Docker images and local files +- Air-gapped operation support (skip vulnerability scanning) + +## Usage + +```bash +# Verify Docker image SBOM with vulnerability scan +.github/skills/scripts/skill-runner.sh security-verify-sbom ghcr.io/user/charon:latest + +# Verify with baseline comparison +.github/skills/scripts/skill-runner.sh security-verify-sbom charon:local sbom-baseline.json + +# Verify local image without vulnerability scan (air-gapped) +VULN_SCAN_ENABLED=false .github/skills/scripts/skill-runner.sh security-verify-sbom charon:local + +# Negative test: verify tampered image (should fail) +.github/skills/scripts/skill-runner.sh security-verify-sbom tampered:image +``` + +## Examples + +### Basic Verification +```bash +$ .github/skills/scripts/skill-runner.sh security-verify-sbom charon:test +[INFO] Generating SBOM for charon:test... +[INFO] SBOM contains 247 packages +[INFO] Scanning for vulnerabilities... +[INFO] Found: 0 Critical, 2 High, 15 Medium +โœ… Verification complete +``` + +### With Baseline Comparison +```bash +$ .github/skills/scripts/skill-runner.sh security-verify-sbom charon:latest sbom-baseline.json +[INFO] Generating SBOM for charon:latest... +[INFO] Comparing with baseline... +[INFO] Baseline: 245 packages, Current: 247 packages +[INFO] Added packages: golang.org/x/crypto@v0.30.0, github.com/pkg/errors@v0.9.1 +[INFO] Removed packages: (none) +โœ… Verification complete (0.8% variance) + +### 1.1 Workflow Updates + +#### File: `.github/workflows/docker-build.yml` + +**Location**: After `steps.build-and-push` (line ~145) + +**Changes**: +1. Add Cosign installation step +2. Add Docker image signing step +3. Store signature in Rekor transparency log + +```yaml +# Add after "Build and push Docker image" step + +- name: Install Cosign + if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' + uses: sigstore/cosign-installer@v3.8.1 + with: + cosign-release: 'v2.4.1' + +- name: Sign Docker Image with Cosign + if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' + env: + DIGEST: ${{ steps.build-and-push.outputs.digest }} + TAGS: ${{ steps.meta.outputs.tags }} + run: | + echo "Signing image with Cosign (keyless OIDC)..." + images="" + for tag in ${TAGS}; do + images+="${tag}@${DIGEST} " + done + + # Sign with keyless mode (GitHub OIDC token) + cosign sign --yes ${images} + + echo "โœ… Image signed and uploaded to Rekor transparency log" + echo "Verification command: cosign verify ${REGISTRY}/${IMAGE_NAME}@${DIGEST} \\" + echo " --certificate-identity-regexp='https://github.com/${GITHUB_REPOSITORY}' \\" + echo " --certificate-oidc-issuer='https://token.actions.githubusercontent.com'" +``` + +#### File: `.github/workflows/release-goreleaser.yml` + +**Location**: After `Run GoReleaser` step (line ~60) + +**Changes**: +1. Add Cosign installation +2. Sign all release binaries +3. Upload signatures as release assets + +```yaml +# Add after "Run GoReleaser" step + +- name: Install Cosign + uses: sigstore/cosign-installer@v3.8.1 + with: + cosign-release: 'v2.4.1' + +- name: Sign Release Artifacts with Cosign + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "Signing release artifacts..." + + # Get release tag + TAG=${GITHUB_REF#refs/tags/} + + # Download artifacts from release + gh release download ${TAG} --dir ./release-artifacts + + # Sign each binary + for artifact in ./release-artifacts/*; do + if [[ -f "$artifact" && ! "$artifact" == *.sig && ! "$artifact" == *.pem ]]; then + echo "Signing: $(basename $artifact)" + cosign sign-blob --yes --output-signature="${artifact}.sig" \ + --output-certificate="${artifact}.pem" \ + "$artifact" + fi + done + + # Upload signatures back to release + gh release upload ${TAG} ./release-artifacts/*.sig ./release-artifacts/*.pem --clobber + + echo "โœ… All artifacts signed and signatures uploaded to release" +``` + +### 1.2 GitHub Skill: `security-sign-cosign` + +#### File: `.github/skills/security-sign-cosign.SKILL.md` + +**Location**: `.github/skills/security-sign-cosign.SKILL.md` + +**Content**: Full SKILL.md specification (see appendix A1) + +#### File: `.github/skills/security-sign-cosign-scripts/run.sh` + +**Location**: `.github/skills/security-sign-cosign-scripts/run.sh` + +**Content**: Bash script implementing local Cosign signing (see appendix A2) + +**Key Features**: +- Sign local Docker images +- Sign arbitrary files (binaries, archives) +- Support keyless (OIDC) and key-based signing +- Verify signatures after signing +- Output signature files (.sig, .pem) + +### 1.3 VS Code Task + +#### File: `.vscode/tasks.json` + +**Location**: Add to `tasks` array + +```json +{ + "label": "Security: Sign with Cosign", + "type": "shell", + "command": ".github/skills/scripts/skill-runner.sh security-sign-cosign", + "group": "test", + "problemMatcher": [] +} +``` + +### 1.4 Secrets Configuration + +**No secrets required** for keyless signing (uses GitHub OIDC tokens automatically). + +Optional: For key-based signing (local development): +- `COSIGN_PRIVATE_KEY`: Base64-encoded private key +- `COSIGN_PASSWORD`: Password for private key + +### 1.5 Testing & Validation + +**Acceptance Criteria**: +- [ ] Docker images signed in `docker-build.yml` workflow +- [ ] Release binaries signed in `release-goreleaser.yml` workflow +- [ ] Signatures visible in Rekor transparency log +- [ ] Local skill can sign test images +- [ ] VS Code task executes successfully +- [ ] Signature verification passes via `cosign verify` + +--- + +## Phase 2: SLSA Provenance (Week 2) + +### 2.1 Workflow Updates + +#### File: `.github/workflows/docker-build.yml` + +**Location**: After Cosign signing step + +**Changes**: +1. Generate SLSA provenance using `slsa-github-generator` +2. Attach provenance to image as attestation + +```yaml +- name: Generate SLSA Provenance + if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' + uses: slsa-framework/slsa-github-generator/.github/actions/generator-generic-slsa3@v2.1.0 + with: + base64-subjects: ${{ steps.build-and-push.outputs.digest }} + provenance-name: "provenance.json" + upload-assets: true + +- name: Attest Provenance to Image + if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' + uses: actions/attest-build-provenance@v2.1.0 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + subject-digest: ${{ steps.build-and-push.outputs.digest }} + push-to-registry: true +``` + +#### File: `.github/workflows/release-goreleaser.yml` + +**Location**: After Cosign signing step + +**Changes**: +1. Generate SLSA provenance for all release artifacts +2. Upload provenance as release asset + +```yaml +- name: Generate SLSA Provenance for Release + uses: slsa-framework/slsa-github-generator/.github/actions/generator-generic-slsa3@v2.1.0 + with: + base64-subjects: | + ${{ hashFiles('release-artifacts/*') }} + provenance-name: "provenance-release.json" + upload-assets: true + upload-tag-name: ${{ github.ref_name }} +``` + +### 2.2 GitHub Skill: `security-slsa-provenance` + +#### File: `.github/skills/security-slsa-provenance.SKILL.md` + +**Location**: `.github/skills/security-slsa-provenance.SKILL.md` + +**Content**: Full SKILL.md specification (see appendix B1) + +#### File: `.github/skills/security-slsa-provenance-scripts/run.sh` + +**Location**: `.github/skills/security-slsa-provenance-scripts/run.sh` + +**Content**: Bash script implementing SLSA provenance generation and verification (see appendix B2) + +**Key Features**: +- Generate SLSA provenance for local artifacts +- Verify provenance against policy +- Parse and display provenance metadata +- Check SLSA level compliance + +### 2.3 VS Code Task + +#### File: `.vscode/tasks.json` + +**Location**: Add to `tasks` array + +```json +{ + "label": "Security: Generate SLSA Provenance", + "type": "shell", + "command": ".github/skills/scripts/skill-runner.sh security-slsa-provenance", + "group": "test", + "problemMatcher": [] +} +``` + +### 2.4 Testing & Validation + +**Acceptance Criteria**: +- [ ] SLSA provenance generated for Docker images +- [ ] SLSA provenance generated for release binaries +- [ ] Provenance attestations pushed to registry +- [ ] Provenance files uploaded to GitHub releases +- [ ] Local skill can generate/verify provenance +- [ ] VS Code task executes successfully +- [ ] SLSA level 2+ compliance verified + +--- + +## Phase 3: SBOM Verification (Week 3) + +### 3.1 Workflow Creation + +#### File: `.github/workflows/supply-chain-verify.yml` [NEW] + +**Location**: `.github/workflows/supply-chain-verify.yml` + +**Purpose**: Automated verification workflow triggered on releases and schedules + +```yaml +name: Supply Chain Verification + +on: + release: + types: [published] + schedule: + # Run weekly on Mondays at 00:00 UTC + - cron: '0 0 * * 1' + workflow_dispatch: + +permissions: + contents: read + packages: read + security-events: write + +jobs: + verify-docker-image: + name: Verify Docker Image Supply Chain + runs-on: ubuntu-latest + if: github.event_name != 'schedule' || github.ref == 'refs/heads/main' + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install Verification Tools + run: | + # Install Cosign + curl -sLO https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64 + sudo install cosign-linux-amd64 /usr/local/bin/cosign + rm cosign-linux-amd64 + + # Install SLSA Verifier + curl -sLO https://github.com/slsa-framework/slsa-verifier/releases/download/v2.6.0/slsa-verifier-linux-amd64 + sudo install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier + rm slsa-verifier-linux-amd64 + + # Install Syft (SBOM generation/verification) + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + + - name: Determine Image Tag + id: tag + run: | + if [[ "${{ github.event_name }}" == "release" ]]; then + TAG="${{ github.event.release.tag_name }}" + else + TAG="latest" + fi + echo "tag=${TAG}" >> $GITHUB_OUTPUT + + - name: Verify Cosign Signature + env: + IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }} + run: | + echo "Verifying Cosign signature for ${IMAGE}..." + cosign verify ${IMAGE} \ + --certificate-identity-regexp="https://github.com/${{ github.repository }}" \ + --certificate-oidc-issuer="https://token.actions.githubusercontent.com" + echo "โœ… Cosign signature verified" + + - name: Verify SLSA Provenance + env: + IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }} + run: | + echo "Verifying SLSA provenance for ${IMAGE}..." + + # Download provenance + gh attestation download ${IMAGE} --digest-alg sha256 \ + --predicate-type https://slsa.dev/provenance/v1 \ + --output provenance.json + + # Verify provenance + slsa-verifier verify-image ${IMAGE} \ + --provenance-path provenance.json \ + --source-uri github.com/${{ github.repository }} + + echo "โœ… SLSA provenance verified" + + - name: Verify SBOM Completeness + env: + IMAGE: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }} + run: | + echo "Verifying SBOM for ${IMAGE}..." + + # Generate fresh SBOM + syft ${IMAGE} -o cyclonedx-json > sbom-generated.json + + # Download attested SBOM + gh attestation download ${IMAGE} --digest-alg sha256 \ + --predicate-type https://spdx.dev/Document \ + --output sbom-attested.json + + # Compare component counts + GENERATED_COUNT=$(jq '.components | length' sbom-generated.json) + ATTESTED_COUNT=$(jq '.components | length' sbom-attested.json) + + echo "Generated SBOM components: ${GENERATED_COUNT}" + echo "Attested SBOM components: ${ATTESTED_COUNT}" + + # Allow 5% variance + DIFF=$((GENERATED_COUNT - ATTESTED_COUNT)) + DIFF_PCT=$((100 * DIFF / GENERATED_COUNT)) + + if [[ ${DIFF_PCT#-} -gt 5 ]]; then + echo "โŒ SBOM component mismatch exceeds 5%" + exit 1 + fi + + echo "โœ… SBOM verification passed" + + - name: Create Verification Report + if: always() + run: | + cat << EOF > verification-report.md + # Supply Chain Verification Report + + **Image**: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }} + **Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC") + **Workflow**: ${{ github.workflow }} + **Run**: ${{ github.run_id }} + + ## Results + + - **Cosign Signature**: ${{ job.status }} + - **SLSA Provenance**: ${{ job.status }} + - **SBOM Verification**: ${{ job.status }} + + ## Next Steps + + If any verification failed: + 1. Check workflow logs for detailed error messages + 2. Verify signing steps ran successfully in build workflow + 3. Confirm attestations were pushed to registry + 4. Re-run build if necessary + EOF + + cat verification-report.md >> $GITHUB_STEP_SUMMARY + + verify-release-artifacts: + name: Verify Release Artifacts + runs-on: ubuntu-latest + if: github.event_name == 'release' + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install Verification Tools + run: | + # Install Cosign + curl -sLO https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64 + sudo install cosign-linux-amd64 /usr/local/bin/cosign + rm cosign-linux-amd64 + + # Install SLSA Verifier + curl -sLO https://github.com/slsa-framework/slsa-verifier/releases/download/v2.6.0/slsa-verifier-linux-amd64 + sudo install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier + rm slsa-verifier-linux-amd64 + + - name: Download Release Assets + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + TAG=${{ github.event.release.tag_name }} + gh release download ${TAG} --dir ./release-assets + + - name: Verify Artifact Signatures + run: | + echo "Verifying Cosign signatures for release artifacts..." + + for artifact in ./release-assets/*; do + # Skip signature and certificate files + if [[ "$artifact" == *.sig || "$artifact" == *.pem || "$artifact" == *provenance* ]]; then + continue + fi + + if [[ -f "$artifact" ]]; then + echo "Verifying: $(basename $artifact)" + + # Verify blob signature + cosign verify-blob "$artifact" \ + --signature "${artifact}.sig" \ + --certificate "${artifact}.pem" \ + --certificate-identity-regexp="https://github.com/${{ github.repository }}" \ + --certificate-oidc-issuer="https://token.actions.githubusercontent.com" + fi + done + + echo "โœ… All artifact signatures verified" + + - name: Verify Release Provenance + run: | + echo "Verifying SLSA provenance for release..." + + if [[ -f "./release-assets/provenance-release.json" ]]; then + slsa-verifier verify-artifact \ + --provenance-path ./release-assets/provenance-release.json \ + --source-uri github.com/${{ github.repository }} + echo "โœ… Release provenance verified" + else + echo "โš ๏ธ No provenance file found" + exit 1 + fi +``` + +### 3.2 GitHub Skill: `security-verify-sbom` + +#### File: `.github/skills/security-verify-sbom.SKILL.md` + +**Location**: `.github/skills/security-verify-sbom.SKILL.md` + +**Content**: Full SKILL.md specification (see appendix C1) + +#### File: `.github/skills/security-verify-sbom-scripts/run.sh` + +**Location**: `.github/skills/security-verify-sbom-scripts/run.sh` + +**Content**: Bash script implementing SBOM verification (see appendix C2) + +**Key Features**: +- Generate SBOM from local Docker images +- Compare SBOM against attested version +- Check for known vulnerabilities in SBOM +- Validate SBOM format and completeness +- Report drift between builds + +### 3.3 VS Code Tasks + +#### File: `.vscode/tasks.json` + +**Location**: Add to `tasks` array + +```json +{ + "label": "Security: Verify SBOM", + "type": "shell", + "command": ".github/skills/scripts/skill-runner.sh security-verify-sbom", + "group": "test", + "problemMatcher": [] +}, +{ + "label": "Security: Full Supply Chain Audit", + "type": "shell", + "dependsOn": [ + "Security: Sign with Cosign", + "Security: Generate SLSA Provenance", + "Security: Verify SBOM" + ], + "dependsOrder": "sequence", + "command": "echo 'โœ… Supply chain audit complete'", + "group": "test", + "problemMatcher": [] +} +``` + +### 3.4 Testing & Validation + +**Acceptance Criteria**: +- [ ] Verification workflow runs on releases +- [ ] Verification workflow runs weekly +- [ ] Docker image signatures verified +- [ ] Release artifact signatures verified +- [ ] SLSA provenance verified +- [ ] SBOM completeness verified +- [ ] Local skill can verify SBOM +- [ ] VS Code tasks execute successfully +- [ ] Full audit task chains all verifications + +--- + +## Management Agent Definition of Done Updates + +### File: `.github/agents/Managment.agent.md` + +**Location**: Section `## DEFINITION OF DONE ##` (line 70) + +**Changes**: Add supply chain verification as mandatory step + +```markdown +## DEFINITION OF DONE ## + +The task is not complete until ALL of the following pass with zero issues: + +1. **Coverage Tests (MANDATORY - Verify Explicitly)**: + - **Backend**: Ensure `Backend_Dev` ran VS Code task "Test: Backend with Coverage" or `scripts/go-test-coverage.sh` + - **Frontend**: Ensure `Frontend_Dev` ran VS Code task "Test: Frontend with Coverage" or `scripts/frontend-test-coverage.sh` + - **Why**: These are in manual stage of pre-commit for performance. Subagents MUST run them via VS Code tasks or scripts. + - Minimum coverage: 85% for both backend and frontend. + - All tests must pass with zero failures. + +2. **Type Safety (Frontend)**: + - Ensure `Frontend_Dev` ran VS Code task "Lint: TypeScript Check" or `npm run type-check` + - **Why**: This check is in manual stage of pre-commit for performance. Subagents MUST run it explicitly. + +3. **Pre-commit Hooks**: Ensure `QA_Security` ran `pre-commit run --all-files` (fast hooks only; coverage was verified in step 1) + +4. **Security Scans**: Ensure `QA_Security` ran CodeQL and Trivy with zero Critical or High severity issues + +5. **Supply Chain Security (NEW - MANDATORY for releases)**: [NEW] + - **Docker Images**: Ensure DevOps signed images with Cosign and generated SLSA provenance + - **Release Artifacts**: Ensure DevOps signed all binaries and attached SLSA provenance + - **SBOM Verification**: Ensure DevOps verified SBOM completeness + - **Verification**: Run VS Code task "Security: Full Supply Chain Audit" to verify all attestations + - **Why**: Supply chain attacks are a critical threat. All artifacts must be cryptographically signed and provenance-verified. + - **When**: Required for all releases, recommended for development builds + +6. **Linting**: All language-specific linters must pass + +**Your Role**: You delegate implementation to subagents, but YOU are responsible for verifying they completed the Definition of Done. Do not accept "DONE" from a subagent until you have confirmed they ran coverage tests, type checks, security scans, **and supply chain verification** explicitly. + +**Critical Note**: Leaving this unfinished prevents commit, push, and leaves users open to security concerns. All issues must be fixed regardless of whether they are unrelated to the original task. This rule must never be skipped. It is non-negotiable anytime any bit of code is added or changed. +``` + +--- + +## File Changes Summary + +### Files to Create (10 new files) + +1. `.github/skills/security-sign-cosign.SKILL.md` +2. `.github/skills/security-sign-cosign-scripts/run.sh` +3. `.github/skills/security-slsa-provenance.SKILL.md` +4. `.github/skills/security-slsa-provenance-scripts/run.sh` +5. `.github/skills/security-verify-sbom.SKILL.md` +6. `.github/skills/security-verify-sbom-scripts/run.sh` +7. `.github/workflows/supply-chain-verify.yml` +8. `docs/plans/supply_chain_security_implementation.md` (this file) +9. `docs/reports/supply_chain_verification_report_template.md` +10. `.github/skills/examples/supply-chain-example.sh` + +### Files to Modify (3 existing files) + +1. `.github/workflows/docker-build.yml` + - Add Cosign installation step (after line 145) + - Add Cosign signing step (after build-and-push) + - Add SLSA provenance generation (after signing) + +2. `.github/workflows/release-goreleaser.yml` + - Add Cosign installation step (after line 60) + - Add artifact signing step (after GoReleaser) + - Add SLSA provenance generation (after signing) + +3. `.vscode/tasks.json` + - Add 4 new tasks (lines to append to tasks array) + +4. `.github/agents/Managment.agent.md` + - Update Definition of Done section (line 70) + +--- + +## Secret Requirements + +### GitHub Secrets (Repository Level) + +**None required** for keyless signing. The following are **optional** for advanced scenarios: + +1. `COSIGN_PRIVATE_KEY` (Optional) + - **Purpose**: Key-based signing for non-CI environments + - **Format**: Base64-encoded private key + - **Generation**: `cosign generate-key-pair` + - **Usage**: Local development, air-gapped signing + +2. `COSIGN_PASSWORD` (Optional) + - **Purpose**: Password for private key + - **Format**: String + - **Usage**: Decrypt COSIGN_PRIVATE_KEY + +### GitHub Permissions (Workflow Level) + +Required permissions for workflows: + +```yaml +permissions: + contents: write # Upload signatures to releases + packages: write # Push attestations to registry + id-token: write # OIDC token for keyless signing + attestations: write # Create attestations + security-events: write # Upload verification results +``` + +### Environment Variables (CI/CD) + +Default values work for standard setup: + +- `COSIGN_EXPERIMENTAL=1` (Enable keyless signing) +- `COSIGN_YES=true` (Non-interactive mode) +- `SLSA_LEVEL=2` (Minimum SLSA level) + +--- + +## Verification & Testing Plan + +### Phase 1 Testing (Cosign) + +**Test Case 1.1**: Docker Image Signing +```bash +# Trigger workflow +git tag -a v1.0.0-rc1 -m "Test release" +git push origin v1.0.0-rc1 + +# Verify signature +cosign verify ghcr.io/$USER/charon:v1.0.0-rc1 \ + --certificate-identity-regexp="https://github.com/$USER/charon" \ + --certificate-oidc-issuer="https://token.actions.githubusercontent.com" +``` + +**Test Case 1.2**: Local Signing via Skill +```bash +# Build local image +docker build -t charon:test . + +# Sign with skill +.github/skills/scripts/skill-runner.sh security-sign-cosign docker charon:test + +# Verify signature +cosign verify charon:test --key cosign.pub +``` + +**Test Case 1.3**: VS Code Task +```bash +# Open Command Palette (Ctrl+Shift+P) +# Type: "Tasks: Run Task" +# Select: "Security: Sign with Cosign" +# Verify output shows successful signing +``` + +### Phase 2 Testing (SLSA) + +**Test Case 2.1**: SLSA Provenance Generation +```bash +# Check release assets +gh release view v1.0.0-rc1 --json assets + +# Download provenance +gh attestation download ghcr.io/$USER/charon:v1.0.0-rc1 \ + --predicate-type https://slsa.dev/provenance/v1 + +# Verify provenance +slsa-verifier verify-image ghcr.io/$USER/charon:v1.0.0-rc1 \ + --source-uri github.com/$USER/charon +``` + +**Test Case 2.2**: Local Provenance via Skill +```bash +# Generate provenance for local artifact +.github/skills/scripts/skill-runner.sh security-slsa-provenance generate charon-binary + +# Verify provenance +.github/skills/scripts/skill-runner.sh security-slsa-provenance verify charon-binary +``` + +### Phase 3 Testing (SBOM) + +**Test Case 3.1**: SBOM Verification Workflow +```bash +# Trigger verification workflow +gh workflow run supply-chain-verify.yml + +# Check results +gh run list --workflow=supply-chain-verify.yml --limit 1 +``` + +**Test Case 3.2**: Local SBOM Verification via Skill +```bash +# Verify SBOM +.github/skills/scripts/skill-runner.sh security-verify-sbom ghcr.io/$USER/charon:latest + +# Check output for component counts and vulnerabilities +``` + +**Test Case 3.3**: Full Supply Chain Audit Task +```bash +# Run complete audit via VS Code +# Tasks: Run Task -> Security: Full Supply Chain Audit +# Verify all three sub-tasks complete successfully +``` + +### Integration Testing + +**End-to-End Test**: Release Pipeline +1. Create feature branch +2. Make code change +3. Create PR +4. Merge to main +5. Create release tag +6. Verify workflow builds and signs artifacts +7. Run verification workflow +8. Download release assets +9. Verify all signatures and attestations locally + +**Success Criteria**: +- All workflows complete without errors +- Signatures verify successfully +- Provenance matches expected source +- SBOM contains all dependencies +- Rekor transparency log contains entries + +--- + +## Rollout Strategy + +### Development Environment (Week 1) +- Deploy Phase 1 (Cosign) to development branch +- Test with beta releases +- Validate skill execution locally +- Gather developer feedback + +### Staging Environment (Week 2) +- Deploy Phase 2 (SLSA) to development branch +- Test full signing pipeline +- Validate provenance generation +- Performance testing + +### Production Environment (Week 3) +- Deploy Phase 3 (SBOM verification) to main branch +- Enable verification workflow +- Monitor for issues +- Update documentation + +### Rollback Plan +If critical issues arise: +1. Disable verification workflow (comment out triggers) +2. Remove signing steps from build workflows (make optional with flag) +3. Maintain SBOM generation (already exists, low risk) +4. Document issues and plan remediation + +--- + +## Monitoring & Alerts + +### Metrics to Track + +1. **Signing Success Rate**: Percentage of successful Cosign signings +2. **Provenance Generation Rate**: Percentage of builds with SLSA provenance +3. **Verification Failure Rate**: Failed verification attempts +4. **Rekor Log Entries**: Transparency log entries created +5. **SBOM Drift**: Variance between builds + +### Alerting Rules + +1. **Critical**: Signing failure in production release +2. **High**: Verification failure in scheduled check +3. **Medium**: SBOM drift exceeds 10% +4. **Low**: Skill execution failures + +### Dashboards + +Create GitHub insights dashboard: +- Total artifacts signed (weekly) +- Verification workflow runs (success/failure) +- SLSA level compliance +- Skill usage statistics + +--- + +## Documentation Requirements + +### User-Facing Documentation + +1. **README.md Updates** + - Add supply chain security section + - Link to verification instructions + - Show verification commands + +2. **SECURITY.md Updates** + - Document signing process + - Add verification procedures + - List transparency log URLs + +3. **Developer Guide** (new file: `docs/development/supply-chain-security.md`) + - How to sign artifacts locally + - How to verify signatures + - Troubleshooting guide + +### Internal Documentation + +1. **Runbook**: `docs/runbooks/supply-chain-incident-response.md` + - Signature verification failures + - Provenance mismatches + - SBOM vulnerabilities + +2. **Architecture Decision Records** + - Why Cosign over other tools + - Keyless vs key-based signing + - SLSA level rationale + +--- + +## Dependencies & Prerequisites + +### Tool Versions + +| Tool | Minimum Version | Installation | +|------|----------------|--------------| +| Cosign | v2.4.1 | `go install github.com/sigstore/cosign/v2/cmd/cosign@latest` | +| SLSA Verifier | v2.6.0 | `go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest` | +| Syft | v1.17.0 | `curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh \| sh` | +| GitHub CLI | v2.62.0 | `brew install gh` or [GitHub CLI](https://cli.github.com/) | + +### GitHub Actions + +| Action | Version | Purpose | +|--------|---------|---------| +| sigstore/cosign-installer | v3.8.1 | Install Cosign in workflows | +| slsa-framework/slsa-github-generator | v2.1.0 | Generate SLSA provenance | +| actions/attest-build-provenance | v2.1.0 | Attest provenance to registry | +| actions/attest-sbom | v3.0.0 | Attest SBOM (existing) | +| anchore/sbom-action | v0.21.0 | Generate SBOM (existing) | + +### External Services + +- **Rekor Transparency Log**: `https://rekor.sigstore.dev` +- **Fulcio Certificate Authority**: `https://fulcio.sigstore.dev` +- **GitHub Packages**: `ghcr.io` (for attestations) + +--- + +## Risk Assessment + +### High Risks + +1. **Key Compromise**: Signing keys leaked + - **Mitigation**: Use keyless signing (OIDC tokens) + - **Detection**: Monitor Rekor logs for unauthorized signatures + +2. **Workflow Compromise**: Attacker modifies CI/CD + - **Mitigation**: Branch protection rules, required reviews + - **Detection**: Audit logs, signature mismatches + +3. **Supply Chain Attack**: Compromised dependency + - **Mitigation**: SBOM verification, vulnerability scanning + - **Detection**: Trivy/Grype scans, GitHub security advisories + +### Medium Risks + +1. **Verification Failures**: False positives blocking releases + - **Mitigation**: Comprehensive testing, retry logic + - **Fallback**: Manual verification procedures + +2. **Performance Impact**: Signing adds latency to builds + - **Mitigation**: Parallel execution, caching + - **Monitoring**: Track build times + +### Low Risks + +1. **Tool Updates**: Breaking changes in Cosign/SLSA + - **Mitigation**: Pin versions, test updates + - **Monitoring**: Renovate bot, release notes + +--- + +## Success Metrics + +### Quantitative Goals + +- **100%** of Docker images signed within 4 weeks +- **100%** of release binaries signed within 4 weeks +- **โ‰ฅ95%** verification success rate +- **<5%** SBOM drift between builds +- **<30s** added to build time for signing +- **<10** false positive verification failures per month + +### Qualitative Goals + +- Developers can verify signatures locally +- Security team has visibility into supply chain +- Compliance requirements met (SOC2, SLSA) +- Zero supply chain incidents post-implementation + +--- + +## Appendices + +### Appendix A: Cosign Skill Implementation + +#### A1: SKILL.md Specification + +```markdown +--- +name: "security-sign-cosign" +version: "1.0.0" +description: "Sign Docker images and artifacts with Cosign (Sigstore)" +author: "Charon Project" +license: "MIT" +tags: ["security", "signing", "cosign", "supply-chain"] +compatibility: + os: ["linux", "darwin"] + shells: ["bash"] +requirements: + - name: "cosign" + version: ">=2.4.0" + optional: false +environment_variables: + - name: "COSIGN_EXPERIMENTAL" + description: "Enable keyless signing" + default: "1" + required: false +parameters: + - name: "type" + type: "string" + description: "Artifact type (docker, file)" + default: "docker" + required: false + - name: "target" + type: "string" + description: "Image tag or file path" + required: true +--- + +# Security: Sign with Cosign + +Sign Docker images and files using Cosign for supply chain security. + +## Usage + +```bash +# Sign Docker image +.github/skills/scripts/skill-runner.sh security-sign-cosign docker charon:local + +# Sign file +.github/skills/scripts/skill-runner.sh security-sign-cosign file ./dist/charon-binary +``` +``` + +#### A2: Execution Script Skeleton + +```bash +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/../scripts/_logging_helpers.sh" + +TYPE="${1:-docker}" +TARGET="${2:-}" + +if [[ -z "${TARGET}" ]]; then + log_error "Usage: security-sign-cosign " + exit 1 +fi + +case "${TYPE}" in + docker) + log_step "COSIGN" "Signing Docker image: ${TARGET}" + cosign sign --yes "${TARGET}" + ;; + file) + log_step "COSIGN" "Signing file: ${TARGET}" + cosign sign-blob --yes --output-signature="${TARGET}.sig" \ + --output-certificate="${TARGET}.pem" "${TARGET}" + ;; + *) + log_error "Invalid type: ${TYPE}" + exit 1 + ;; +esac + +log_success "Signature created and stored in Rekor" +``` + +### Appendix B: SLSA Provenance Skill Implementation + +#### B1: SKILL.md Specification + +```markdown +--- +name: "security-slsa-provenance" +version: "1.0.0" +description: "Generate and verify SLSA provenance attestations" +author: "Charon Project" +license: "MIT" +tags: ["security", "slsa", "provenance", "supply-chain"] +--- + +# Security: SLSA Provenance + +Generate and verify SLSA provenance for build artifacts. + +## Usage + +```bash +# Generate provenance +.github/skills/scripts/skill-runner.sh security-slsa-provenance generate charon-binary + +# Verify provenance +.github/skills/scripts/skill-runner.sh security-slsa-provenance verify charon-binary +``` +``` + +### Appendix C: SBOM Verification Skill Implementation + +#### C1: SKILL.md Specification + +```markdown +--- +name: "security-verify-sbom" +version: "1.0.0" +description: "Verify SBOM completeness and check for vulnerabilities" +author: "Charon Project" +license: "MIT" +tags: ["security", "sbom", "verification", "supply-chain"] +--- + +# Security: Verify SBOM + +Verify Software Bill of Materials (SBOM) for Docker images and releases. + +## Usage + +```bash +# Verify Docker image SBOM +.github/skills/scripts/skill-runner.sh security-verify-sbom ghcr.io/user/charon:latest + +# Verify local image +.github/skills/scripts/skill-runner.sh security-verify-sbom charon:local +``` +``` + +--- + +## Conclusion + +This implementation plan provides a comprehensive, phased approach to integrating supply chain security into Charon. By following this plan, the DevOps agent will: + +1. **Sign all artifacts** with Cosign for tamper detection +2. **Generate SLSA provenance** for build transparency +3. **Verify SBOMs** for dependency tracking +4. **Enable local testing** via GitHub Skills +5. **Update processes** to include verification in DoD + +**Estimated Effort**: 3-4 weeks (1 week per phase + testing) +**Complexity**: Medium (existing infrastructure, well-documented tools) +**Risk**: Low (non-breaking, incremental rollout) + +**Ready for delegation to DevOps agent.** diff --git a/docs/tasks.md b/docs/plans/archive/tasks.md similarity index 100% rename from docs/tasks.md rename to docs/plans/archive/tasks.md diff --git a/docs/plans/test-coverage-remediation-plan.md b/docs/plans/archive/test-coverage-remediation-plan.md similarity index 100% rename from docs/plans/test-coverage-remediation-plan.md rename to docs/plans/archive/test-coverage-remediation-plan.md diff --git a/docs/plans/test-optimization.md b/docs/plans/archive/test-optimization.md similarity index 100% rename from docs/plans/test-optimization.md rename to docs/plans/archive/test-optimization.md diff --git a/docs/plans/test_coverage_plan_100_percent.md b/docs/plans/archive/test_coverage_plan_100_percent.md similarity index 100% rename from docs/plans/test_coverage_plan_100_percent.md rename to docs/plans/archive/test_coverage_plan_100_percent.md diff --git a/docs/plans/test_coverage_plan_sqlite_corruption.md b/docs/plans/archive/test_coverage_plan_sqlite_corruption.md similarity index 100% rename from docs/plans/test_coverage_plan_sqlite_corruption.md rename to docs/plans/archive/test_coverage_plan_sqlite_corruption.md diff --git a/docs/plans/ui_ux_bugfixes_spec.md b/docs/plans/archive/ui_ux_bugfixes_spec.md similarity index 100% rename from docs/plans/ui_ux_bugfixes_spec.md rename to docs/plans/archive/ui_ux_bugfixes_spec.md diff --git a/docs/plans/uptime_monitoring_diagnosis.md b/docs/plans/archive/uptime_monitoring_diagnosis.md similarity index 100% rename from docs/plans/uptime_monitoring_diagnosis.md rename to docs/plans/archive/uptime_monitoring_diagnosis.md diff --git a/docs/plans/url_test_security_fixes.md b/docs/plans/archive/url_test_security_fixes.md similarity index 100% rename from docs/plans/url_test_security_fixes.md rename to docs/plans/archive/url_test_security_fixes.md diff --git a/docs/plans/url_testing_codeql_fix.md b/docs/plans/archive/url_testing_codeql_fix.md similarity index 100% rename from docs/plans/url_testing_codeql_fix.md rename to docs/plans/archive/url_testing_codeql_fix.md diff --git a/docs/plans/user_handler_coverage_fix.md b/docs/plans/archive/user_handler_coverage_fix.md similarity index 100% rename from docs/plans/user_handler_coverage_fix.md rename to docs/plans/archive/user_handler_coverage_fix.md diff --git a/docs/plans/waf_integration_fix.md b/docs/plans/archive/waf_integration_fix.md similarity index 100% rename from docs/plans/waf_integration_fix.md rename to docs/plans/archive/waf_integration_fix.md diff --git a/docs/plans/waf_testing_plan.md b/docs/plans/archive/waf_testing_plan.md similarity index 100% rename from docs/plans/waf_testing_plan.md rename to docs/plans/archive/waf_testing_plan.md diff --git a/docs/plans/workflow_modularization_spec.md b/docs/plans/archive/workflow_modularization_spec.md similarity index 100% rename from docs/plans/workflow_modularization_spec.md rename to docs/plans/archive/workflow_modularization_spec.md diff --git a/docs/reports/404_fix_qa_report.md b/docs/reports/archive/404_fix_qa_report.md similarity index 100% rename from docs/reports/404_fix_qa_report.md rename to docs/reports/archive/404_fix_qa_report.md diff --git a/docs/reports/ACL_DROPDOWN_BUG_FIX.md b/docs/reports/archive/ACL_DROPDOWN_BUG_FIX.md similarity index 100% rename from docs/reports/ACL_DROPDOWN_BUG_FIX.md rename to docs/reports/archive/ACL_DROPDOWN_BUG_FIX.md diff --git a/docs/reports/CI_TEST_FIXES_SUMMARY.md b/docs/reports/archive/CI_TEST_FIXES_SUMMARY.md similarity index 100% rename from docs/reports/CI_TEST_FIXES_SUMMARY.md rename to docs/reports/archive/CI_TEST_FIXES_SUMMARY.md diff --git a/docs/reports/DIALOG_FIX_INVESTIGATION.md b/docs/reports/archive/DIALOG_FIX_INVESTIGATION.md similarity index 100% rename from docs/reports/DIALOG_FIX_INVESTIGATION.md rename to docs/reports/archive/DIALOG_FIX_INVESTIGATION.md diff --git a/docs/reports/DNS_BUTTON_FIX_COMPLETE.md b/docs/reports/archive/DNS_BUTTON_FIX_COMPLETE.md similarity index 100% rename from docs/reports/DNS_BUTTON_FIX_COMPLETE.md rename to docs/reports/archive/DNS_BUTTON_FIX_COMPLETE.md diff --git a/docs/reports/E2E_BASELINE_FRESH_2026-02-12.md b/docs/reports/archive/E2E_BASELINE_FRESH_2026-02-12.md similarity index 100% rename from docs/reports/E2E_BASELINE_FRESH_2026-02-12.md rename to docs/reports/archive/E2E_BASELINE_FRESH_2026-02-12.md diff --git a/docs/reports/E2E_BASELINE_REPORT_2026-02-12.md b/docs/reports/archive/E2E_BASELINE_REPORT_2026-02-12.md similarity index 100% rename from docs/reports/E2E_BASELINE_REPORT_2026-02-12.md rename to docs/reports/archive/E2E_BASELINE_REPORT_2026-02-12.md diff --git a/docs/reports/E2E_BLOCKER_RESOLUTION.md b/docs/reports/archive/E2E_BLOCKER_RESOLUTION.md similarity index 100% rename from docs/reports/E2E_BLOCKER_RESOLUTION.md rename to docs/reports/archive/E2E_BLOCKER_RESOLUTION.md diff --git a/docs/reports/E2E_REMEDIATION_CHECKLIST.md b/docs/reports/archive/E2E_REMEDIATION_CHECKLIST.md similarity index 100% rename from docs/reports/E2E_REMEDIATION_CHECKLIST.md rename to docs/reports/archive/E2E_REMEDIATION_CHECKLIST.md diff --git a/docs/reports/E2E_SKIP_REMOVAL_CHECKPOINT.md b/docs/reports/archive/E2E_SKIP_REMOVAL_CHECKPOINT.md similarity index 100% rename from docs/reports/E2E_SKIP_REMOVAL_CHECKPOINT.md rename to docs/reports/archive/E2E_SKIP_REMOVAL_CHECKPOINT.md diff --git a/docs/reports/E2E_SKIP_REMOVAL_SUMMARY.md b/docs/reports/archive/E2E_SKIP_REMOVAL_SUMMARY.md similarity index 100% rename from docs/reports/E2E_SKIP_REMOVAL_SUMMARY.md rename to docs/reports/archive/E2E_SKIP_REMOVAL_SUMMARY.md diff --git a/docs/reports/E2E_TEST_FIX_SUMMARY.md b/docs/reports/archive/E2E_TEST_FIX_SUMMARY.md similarity index 100% rename from docs/reports/E2E_TEST_FIX_SUMMARY.md rename to docs/reports/archive/E2E_TEST_FIX_SUMMARY.md diff --git a/docs/reports/E2E_TEST_QUICK_GUIDE.md b/docs/reports/archive/E2E_TEST_QUICK_GUIDE.md similarity index 100% rename from docs/reports/E2E_TEST_QUICK_GUIDE.md rename to docs/reports/archive/E2E_TEST_QUICK_GUIDE.md diff --git a/docs/reports/FINAL_VERIFICATION_SSRF_REMEDIATION.md b/docs/reports/archive/FINAL_VERIFICATION_SSRF_REMEDIATION.md similarity index 100% rename from docs/reports/FINAL_VERIFICATION_SSRF_REMEDIATION.md rename to docs/reports/archive/FINAL_VERIFICATION_SSRF_REMEDIATION.md diff --git a/docs/reports/HOTFIX_CROWDSEC_INTEGRATION_ISSUES.md b/docs/reports/archive/HOTFIX_CROWDSEC_INTEGRATION_ISSUES.md similarity index 100% rename from docs/reports/HOTFIX_CROWDSEC_INTEGRATION_ISSUES.md rename to docs/reports/archive/HOTFIX_CROWDSEC_INTEGRATION_ISSUES.md diff --git a/docs/reports/HTTP_HEADER_SCAN.md b/docs/reports/archive/HTTP_HEADER_SCAN.md similarity index 100% rename from docs/reports/HTTP_HEADER_SCAN.md rename to docs/reports/archive/HTTP_HEADER_SCAN.md diff --git a/docs/reports/PHASE1_VALIDATION_EXECUTIVE_SUMMARY.md b/docs/reports/archive/PHASE1_VALIDATION_EXECUTIVE_SUMMARY.md similarity index 100% rename from docs/reports/PHASE1_VALIDATION_EXECUTIVE_SUMMARY.md rename to docs/reports/archive/PHASE1_VALIDATION_EXECUTIVE_SUMMARY.md diff --git a/docs/reports/PHASE_2_DOCUMENTATION_INDEX.md b/docs/reports/archive/PHASE_2_DOCUMENTATION_INDEX.md similarity index 100% rename from docs/reports/PHASE_2_DOCUMENTATION_INDEX.md rename to docs/reports/archive/PHASE_2_DOCUMENTATION_INDEX.md diff --git a/docs/reports/PHASE_2_EXECUTIVE_BRIEF.md b/docs/reports/archive/PHASE_2_EXECUTIVE_BRIEF.md similarity index 100% rename from docs/reports/PHASE_2_EXECUTIVE_BRIEF.md rename to docs/reports/archive/PHASE_2_EXECUTIVE_BRIEF.md diff --git a/docs/reports/PHASE_2_FINAL_APPROVAL.md b/docs/reports/archive/PHASE_2_FINAL_APPROVAL.md similarity index 100% rename from docs/reports/PHASE_2_FINAL_APPROVAL.md rename to docs/reports/archive/PHASE_2_FINAL_APPROVAL.md diff --git a/docs/reports/PHASE_2_FINAL_REPORT.md b/docs/reports/archive/PHASE_2_FINAL_REPORT.md similarity index 100% rename from docs/reports/PHASE_2_FINAL_REPORT.md rename to docs/reports/archive/PHASE_2_FINAL_REPORT.md diff --git a/docs/reports/PHASE_2_VERIFICATION_COMPLETE.md b/docs/reports/archive/PHASE_2_VERIFICATION_COMPLETE.md similarity index 100% rename from docs/reports/PHASE_2_VERIFICATION_COMPLETE.md rename to docs/reports/archive/PHASE_2_VERIFICATION_COMPLETE.md diff --git a/docs/reports/PHASE_2_VERIFICATION_EXECUTION.md b/docs/reports/archive/PHASE_2_VERIFICATION_EXECUTION.md similarity index 100% rename from docs/reports/PHASE_2_VERIFICATION_EXECUTION.md rename to docs/reports/archive/PHASE_2_VERIFICATION_EXECUTION.md diff --git a/docs/reports/PHASE_3_1_AUTH_FIX_REPORT.md b/docs/reports/archive/PHASE_3_1_AUTH_FIX_REPORT.md similarity index 100% rename from docs/reports/PHASE_3_1_AUTH_FIX_REPORT.md rename to docs/reports/archive/PHASE_3_1_AUTH_FIX_REPORT.md diff --git a/docs/reports/PHASE_3_EXECUTION_COMPLETE.md b/docs/reports/archive/PHASE_3_EXECUTION_COMPLETE.md similarity index 100% rename from docs/reports/PHASE_3_EXECUTION_COMPLETE.md rename to docs/reports/archive/PHASE_3_EXECUTION_COMPLETE.md diff --git a/docs/reports/PHASE_3_FINAL_VALIDATION_REPORT.md b/docs/reports/archive/PHASE_3_FINAL_VALIDATION_REPORT.md similarity index 100% rename from docs/reports/PHASE_3_FINAL_VALIDATION_REPORT.md rename to docs/reports/archive/PHASE_3_FINAL_VALIDATION_REPORT.md diff --git a/docs/reports/PHASE_3_VALIDATION_REPORT.md b/docs/reports/archive/PHASE_3_VALIDATION_REPORT.md similarity index 100% rename from docs/reports/PHASE_3_VALIDATION_REPORT.md rename to docs/reports/archive/PHASE_3_VALIDATION_REPORT.md diff --git a/docs/reports/RELEASE_DECISION.md b/docs/reports/archive/RELEASE_DECISION.md similarity index 100% rename from docs/reports/RELEASE_DECISION.md rename to docs/reports/archive/RELEASE_DECISION.md diff --git a/docs/reports/SPRINT1_GO_DECISION.md b/docs/reports/archive/SPRINT1_GO_DECISION.md similarity index 100% rename from docs/reports/SPRINT1_GO_DECISION.md rename to docs/reports/archive/SPRINT1_GO_DECISION.md diff --git a/docs/reports/SSRF_DOCUMENTATION_UPDATE_SUMMARY.md b/docs/reports/archive/SSRF_DOCUMENTATION_UPDATE_SUMMARY.md similarity index 100% rename from docs/reports/SSRF_DOCUMENTATION_UPDATE_SUMMARY.md rename to docs/reports/archive/SSRF_DOCUMENTATION_UPDATE_SUMMARY.md diff --git a/docs/reports/TEST_VERIFICATION_SUMMARY.md b/docs/reports/archive/TEST_VERIFICATION_SUMMARY.md similarity index 100% rename from docs/reports/TEST_VERIFICATION_SUMMARY.md rename to docs/reports/archive/TEST_VERIFICATION_SUMMARY.md diff --git a/docs/reports/audit_logging_qa_report.md b/docs/reports/archive/audit_logging_qa_report.md similarity index 100% rename from docs/reports/audit_logging_qa_report.md rename to docs/reports/archive/audit_logging_qa_report.md diff --git a/docs/reports/backend_coverage_verification.md b/docs/reports/archive/backend_coverage_verification.md similarity index 100% rename from docs/reports/backend_coverage_verification.md rename to docs/reports/archive/backend_coverage_verification.md diff --git a/docs/reports/backend_ip_fix_qa.md b/docs/reports/archive/backend_ip_fix_qa.md similarity index 100% rename from docs/reports/backend_ip_fix_qa.md rename to docs/reports/archive/backend_ip_fix_qa.md diff --git a/docs/reports/break_glass_protocol_qa_report.md b/docs/reports/archive/break_glass_protocol_qa_report.md similarity index 100% rename from docs/reports/break_glass_protocol_qa_report.md rename to docs/reports/archive/break_glass_protocol_qa_report.md diff --git a/docs/reports/browser_alignment_diagnostic.md b/docs/reports/archive/browser_alignment_diagnostic.md similarity index 100% rename from docs/reports/browser_alignment_diagnostic.md rename to docs/reports/archive/browser_alignment_diagnostic.md diff --git a/docs/reports/caddy_import_final_test_results.md b/docs/reports/archive/caddy_import_final_test_results.md similarity index 100% rename from docs/reports/caddy_import_final_test_results.md rename to docs/reports/archive/caddy_import_final_test_results.md diff --git a/docs/reports/caddy_import_full_test_results.md b/docs/reports/archive/caddy_import_full_test_results.md similarity index 100% rename from docs/reports/caddy_import_full_test_results.md rename to docs/reports/archive/caddy_import_full_test_results.md diff --git a/docs/reports/caddy_import_poc_results.md b/docs/reports/archive/caddy_import_poc_results.md similarity index 100% rename from docs/reports/caddy_import_poc_results.md rename to docs/reports/archive/caddy_import_poc_results.md diff --git a/docs/reports/caddy_import_test_execution_summary.md b/docs/reports/archive/caddy_import_test_execution_summary.md similarity index 100% rename from docs/reports/caddy_import_test_execution_summary.md rename to docs/reports/archive/caddy_import_test_execution_summary.md diff --git a/docs/reports/cerberus_live_logs_qa_report.md b/docs/reports/archive/cerberus_live_logs_qa_report.md similarity index 100% rename from docs/reports/cerberus_live_logs_qa_report.md rename to docs/reports/archive/cerberus_live_logs_qa_report.md diff --git a/docs/reports/cerberus_tc2_fix_implementation_report.md b/docs/reports/archive/cerberus_tc2_fix_implementation_report.md similarity index 100% rename from docs/reports/cerberus_tc2_fix_implementation_report.md rename to docs/reports/archive/cerberus_tc2_fix_implementation_report.md diff --git a/docs/reports/ci_failure_diagnosis.md b/docs/reports/archive/ci_failure_diagnosis.md similarity index 100% rename from docs/reports/ci_failure_diagnosis.md rename to docs/reports/archive/ci_failure_diagnosis.md diff --git a/docs/reports/ci_pipeline_audit.md b/docs/reports/archive/ci_pipeline_audit.md similarity index 100% rename from docs/reports/ci_pipeline_audit.md rename to docs/reports/archive/ci_pipeline_audit.md diff --git a/docs/reports/ci_remediation_qa_report.md b/docs/reports/archive/ci_remediation_qa_report.md similarity index 100% rename from docs/reports/ci_remediation_qa_report.md rename to docs/reports/archive/ci_remediation_qa_report.md diff --git a/docs/reports/ci_sequencing_audit.md b/docs/reports/archive/ci_sequencing_audit.md similarity index 100% rename from docs/reports/ci_sequencing_audit.md rename to docs/reports/archive/ci_sequencing_audit.md diff --git a/docs/reports/ci_workflow_analysis.md b/docs/reports/archive/ci_workflow_analysis.md similarity index 100% rename from docs/reports/ci_workflow_analysis.md rename to docs/reports/archive/ci_workflow_analysis.md diff --git a/docs/reports/codeql_pr718_origin_map.md b/docs/reports/archive/codeql_pr718_origin_map.md similarity index 100% rename from docs/reports/codeql_pr718_origin_map.md rename to docs/reports/archive/codeql_pr718_origin_map.md diff --git a/docs/reports/compliance_qa_report.md b/docs/reports/archive/compliance_qa_report.md similarity index 100% rename from docs/reports/compliance_qa_report.md rename to docs/reports/archive/compliance_qa_report.md diff --git a/docs/reports/coverage_gap_analysis.md b/docs/reports/archive/coverage_gap_analysis.md similarity index 100% rename from docs/reports/coverage_gap_analysis.md rename to docs/reports/archive/coverage_gap_analysis.md diff --git a/docs/reports/coverage_verification.md b/docs/reports/archive/coverage_verification.md similarity index 100% rename from docs/reports/coverage_verification.md rename to docs/reports/archive/coverage_verification.md diff --git a/docs/reports/crowdsec-preset-fix-summary.md b/docs/reports/archive/crowdsec-preset-fix-summary.md similarity index 100% rename from docs/reports/crowdsec-preset-fix-summary.md rename to docs/reports/archive/crowdsec-preset-fix-summary.md diff --git a/docs/reports/crowdsec-preset-pull-apply-debug.md b/docs/reports/archive/crowdsec-preset-pull-apply-debug.md similarity index 100% rename from docs/reports/crowdsec-preset-pull-apply-debug.md rename to docs/reports/archive/crowdsec-preset-pull-apply-debug.md diff --git a/docs/reports/crowdsec_app_level_config.md b/docs/reports/archive/crowdsec_app_level_config.md similarity index 100% rename from docs/reports/crowdsec_app_level_config.md rename to docs/reports/archive/crowdsec_app_level_config.md diff --git a/docs/reports/crowdsec_bouncer_field_investigation.md b/docs/reports/archive/crowdsec_bouncer_field_investigation.md similarity index 100% rename from docs/reports/crowdsec_bouncer_field_investigation.md rename to docs/reports/archive/crowdsec_bouncer_field_investigation.md diff --git a/docs/reports/crowdsec_final_validation.md b/docs/reports/archive/crowdsec_final_validation.md similarity index 100% rename from docs/reports/crowdsec_final_validation.md rename to docs/reports/archive/crowdsec_final_validation.md diff --git a/docs/reports/crowdsec_final_validation_20251215.md b/docs/reports/archive/crowdsec_final_validation_20251215.md similarity index 100% rename from docs/reports/crowdsec_final_validation_20251215.md rename to docs/reports/archive/crowdsec_final_validation_20251215.md diff --git a/docs/reports/crowdsec_fix_deployment.md b/docs/reports/archive/crowdsec_fix_deployment.md similarity index 100% rename from docs/reports/crowdsec_fix_deployment.md rename to docs/reports/archive/crowdsec_fix_deployment.md diff --git a/docs/reports/crowdsec_integration_summary.md b/docs/reports/archive/crowdsec_integration_summary.md similarity index 100% rename from docs/reports/crowdsec_integration_summary.md rename to docs/reports/archive/crowdsec_integration_summary.md diff --git a/docs/reports/crowdsec_migration_qa_report.md b/docs/reports/archive/crowdsec_migration_qa_report.md similarity index 100% rename from docs/reports/crowdsec_migration_qa_report.md rename to docs/reports/archive/crowdsec_migration_qa_report.md diff --git a/docs/reports/crowdsec_production_ready_20251215_205500.md b/docs/reports/archive/crowdsec_production_ready_20251215_205500.md similarity index 100% rename from docs/reports/crowdsec_production_ready_20251215_205500.md rename to docs/reports/archive/crowdsec_production_ready_20251215_205500.md diff --git a/docs/reports/crowdsec_trusted_proxies_fix.md b/docs/reports/archive/crowdsec_trusted_proxies_fix.md similarity index 100% rename from docs/reports/crowdsec_trusted_proxies_fix.md rename to docs/reports/archive/crowdsec_trusted_proxies_fix.md diff --git a/docs/reports/crowdsec_validation_final.md b/docs/reports/archive/crowdsec_validation_final.md similarity index 100% rename from docs/reports/crowdsec_validation_final.md rename to docs/reports/archive/crowdsec_validation_final.md diff --git a/docs/reports/definition_of_done_report.md b/docs/reports/archive/definition_of_done_report.md similarity index 100% rename from docs/reports/definition_of_done_report.md rename to docs/reports/archive/definition_of_done_report.md diff --git a/docs/reports/design.md b/docs/reports/archive/design.md similarity index 100% rename from docs/reports/design.md rename to docs/reports/archive/design.md diff --git a/docs/reports/documentation_updates_geolite2_fix.md b/docs/reports/archive/documentation_updates_geolite2_fix.md similarity index 100% rename from docs/reports/documentation_updates_geolite2_fix.md rename to docs/reports/archive/documentation_updates_geolite2_fix.md diff --git a/docs/reports/e2e_fail_skip_ledger_2026-02-13.md b/docs/reports/archive/e2e_fail_skip_ledger_2026-02-13.md similarity index 100% rename from docs/reports/e2e_fail_skip_ledger_2026-02-13.md rename to docs/reports/archive/e2e_fail_skip_ledger_2026-02-13.md diff --git a/docs/reports/e2e_final_validation.md b/docs/reports/archive/e2e_final_validation.md similarity index 100% rename from docs/reports/e2e_final_validation.md rename to docs/reports/archive/e2e_final_validation.md diff --git a/docs/reports/e2e_fix_v2_qa_report.md b/docs/reports/archive/e2e_fix_v2_qa_report.md similarity index 100% rename from docs/reports/e2e_fix_v2_qa_report.md rename to docs/reports/archive/e2e_fix_v2_qa_report.md diff --git a/docs/reports/e2e_fix_v2_summary.md b/docs/reports/archive/e2e_fix_v2_summary.md similarity index 100% rename from docs/reports/e2e_fix_v2_summary.md rename to docs/reports/archive/e2e_fix_v2_summary.md diff --git a/docs/reports/e2e_shard3_analysis.md b/docs/reports/archive/e2e_shard3_analysis.md similarity index 100% rename from docs/reports/e2e_shard3_analysis.md rename to docs/reports/archive/e2e_shard3_analysis.md diff --git a/docs/reports/e2e_skip_registry_2026-02-13.md b/docs/reports/archive/e2e_skip_registry_2026-02-13.md similarity index 100% rename from docs/reports/e2e_skip_registry_2026-02-13.md rename to docs/reports/archive/e2e_skip_registry_2026-02-13.md diff --git a/docs/reports/e2e_triage_report.md b/docs/reports/archive/e2e_triage_report.md similarity index 100% rename from docs/reports/e2e_triage_report.md rename to docs/reports/archive/e2e_triage_report.md diff --git a/docs/reports/e2e_validation_report.md b/docs/reports/archive/e2e_validation_report.md similarity index 100% rename from docs/reports/e2e_validation_report.md rename to docs/reports/archive/e2e_validation_report.md diff --git a/docs/reports/gh_actions_diagnostic.md b/docs/reports/archive/gh_actions_diagnostic.md similarity index 100% rename from docs/reports/gh_actions_diagnostic.md rename to docs/reports/archive/gh_actions_diagnostic.md diff --git a/docs/reports/gorm_scanner_qa_report.md b/docs/reports/archive/gorm_scanner_qa_report.md similarity index 100% rename from docs/reports/gorm_scanner_qa_report.md rename to docs/reports/archive/gorm_scanner_qa_report.md diff --git a/docs/reports/implementation_notes.md b/docs/reports/archive/implementation_notes.md similarity index 100% rename from docs/reports/implementation_notes.md rename to docs/reports/archive/implementation_notes.md diff --git a/docs/reports/key_rotation_qa_report.md b/docs/reports/archive/key_rotation_qa_report.md similarity index 100% rename from docs/reports/key_rotation_qa_report.md rename to docs/reports/archive/key_rotation_qa_report.md diff --git a/docs/reports/lint_remediation_checkpoint.md b/docs/reports/archive/lint_remediation_checkpoint.md similarity index 100% rename from docs/reports/lint_remediation_checkpoint.md rename to docs/reports/archive/lint_remediation_checkpoint.md diff --git a/docs/reports/multi_credential_qa_report.md b/docs/reports/archive/multi_credential_qa_report.md similarity index 100% rename from docs/reports/multi_credential_qa_report.md rename to docs/reports/archive/multi_credential_qa_report.md diff --git a/docs/reports/nebula_upgrade_analysis.md b/docs/reports/archive/nebula_upgrade_analysis.md similarity index 100% rename from docs/reports/nebula_upgrade_analysis.md rename to docs/reports/archive/nebula_upgrade_analysis.md diff --git a/docs/reports/archive/performance_diagnostics.md b/docs/reports/archive/performance_diagnostics.md new file mode 100644 index 00000000..f8f8f85f --- /dev/null +++ b/docs/reports/archive/performance_diagnostics.md @@ -0,0 +1,659 @@ +# VS Code Remote SSH Performance Diagnostics Report + +**Date:** January 12, 2026 +**System:** srv599055 (Remote SSH Server) +**VS Code Version:** Insiders-7c62052af606ba507cbb8ee90b0c22957bb175e7 +**Uptime:** 2 days, 4 hours, 52 minutes + +--- + +## Executive Summary + +VS Code is experiencing performance degradation on the remote SSH server due to **multiple concurrent resource-intensive processes**, particularly language servers and excessive workspace artifacts. The system has adequate resources (16GB RAM, 4 CPUs), but the combination of TypeScript servers, Go language servers (gopls), Python language servers (Pylance), ESLint, and Docker containers are consuming significant memory and CPU. + +**Note:** Caddy (reverse proxy manager) is a **core component of the Charon project** and its 110MB RAM usage is expected and healthy. It is not a performance issue. + +**Critical Issues Identified:** + +1. โš ๏ธ **Duplicate TypeScript Servers** - Two TypeScript servers running simultaneously (742MB) +2. โš ๏ธ **Zombie Vite Process** - Stopped Vite dev server holding 11GB virtual memory +3. โš ๏ธ **Excessive Workspace Files** - 64,090 files causing slow indexing +4. โš ๏ธ **110+ Test Artifacts** - Coverage files and reports cluttering workspace root +5. โš ๏ธ **436MB+ CodeQL Databases** - Multiple databases not properly cleaned up +6. โš ๏ธ **Large VS Code Server** - 2.9GB installation directory + +--- + +## 1. System Resource Analysis + +### 1.1 CPU Usage + +``` +Load Average: 0.09 (1m), 0.60 (5m), 1.38 (15m) +%Cpu(s): 4.5 us, 4.5 sy, 0.0 ni, 90.9 id, 0.0 wa + +Top CPU Consumers: +- VS Code ExtensionHost: 5.7% (941MB RAM) +- TypeScript Server: 2.7% (580MB RAM) +- Tailscaled: 2.3% (56MB RAM) +- VS Code FileWatcher: 2.0% (133MB RAM) + +Expected Services Running Normally: +- Caddy (Reverse Proxy Manager): 2.0% CPU, 110MB RAM - Core Charon component +``` + +**Analysis:** CPU usage is acceptable with ~90% idle time. The 15-minute load average of 1.38 on a 4-CPU system (35% average load) is manageable but indicates sustained activity. Caddy's resource usage is typical and healthy for a reverse proxy handling the project's routing. + +### 1.2 Memory Usage + +``` +Total: 15.6GB +Used: 5.6GB (35%) +Free: 2.3GB (15%) +Buff/Cache: 8.1GB (50%) +Available: 10GB (64%) +Swap: 0B (DISABLED) +``` + +**Top Memory Consumers:** + +| Process | Memory | % of Total | Description | +|---------|--------|-----------|-------------| +| VS Code ExtensionHost | 941MB | 5.7% | Main extension runtime | +| TypeScript Server (main) | 580MB | 3.5% | Full semantic analysis | +| Pylance (Python) | 521MB | 3.1% | Python language server | +| gopls (Go) | 265MB | 1.6% | Go language server | +| ESLint Server | 231MB | 1.4% | JavaScript/TypeScript linting | +| TypeScript Server (partial) | 162MB | 0.9% | Partial semantic mode | +| Charon Container | 210MB | 1.3% | Main Docker container | +| Docker containers (total) | ~1.5GB | 9.6% | All running containers | + +**Combined VS Code Processes:** ~3.2GB (20% of total RAM) + +**Critical Finding:** No swap space configured. When memory pressure increases, the system cannot page out inactive memory, potentially causing OOM conditions. + +### 1.3 Disk Usage + +``` +Filesystem: /dev/sda1 +Total: 193GB +Used: 64GB (33%) +Available: 130GB (67%) +``` + +**Analysis:** Disk space is adequate. No immediate concerns. + +### 1.4 Disk I/O + +``` +Average CPU: %user=6.31, %system=3.77, %iowait=0.28, %idle=88.65 +Disk /dev/sda: +- Read: 50.43 r/s, 535.77 kB/s +- Write: 13.08 w/s, 793.04 kB/s +- Await: 0.27ms (read), 0.83ms (write) +- %util: 1.30% +``` + +**Analysis:** Disk I/O is healthy with minimal wait times. Not a bottleneck. + +--- + +## 2. VS Code Process Analysis + +### 2.1 Active Language Servers + +``` +Total VS Code Related Processes: 30+ + +Language Servers: +1. TypeScript Server (Full Semantic): 580MB, 2.7% CPU +2. TypeScript Server (Partial Semantic): 162MB, 0.1% CPU +3. Pylance (Python): 521MB, 0.7% CPU +4. gopls (Go): 265MB + 125MB telemetry, 0.6% CPU +5. ESLint Server: 231MB, 0.8% CPU +6. JSON Language Server: 66MB, 0% CPU +7. Markdown Language Server: 67MB, 0% CPU +8. YAML Language Server: 89MB, 0% CPU +9. GitHub Actions Language Server: 68MB, 0% CPU + +Extension Host: 941MB, 5.7% CPU +File Watcher: 133MB, 2.0% CPU +``` + +**Critical Finding:** **TWO TypeScript servers are running simultaneously** (full semantic + partial semantic), consuming 742MB combined. This is a major contributor to performance issues. + +### 2.2 Problematic Processes + +``` +Zombie Processes: +- PID 2271208: [wget] + +Stopped Processes (Signal: SIGTSTP): +- PID 2438000: bash terminal (pts/3) +- PID 2438021: sh -c vite (pts/3) +- PID 2438022: node vite (11GB VSZ, stopped) +- PID 2438034: esbuild (stopped) +``` + +**Critical Finding:** A **stopped Vite development server** with 11GB virtual memory allocation is holding resources. This appears to be from a previous `npm run dev` session that was suspended (Ctrl+Z) but never resumed or killed. + +--- + +## 3. Docker Container Analysis + +### 3.1 Running Containers + +``` +Total Containers: 11 +Total Memory Usage: ~1.6GB +Total CPU Usage: ~3% + +Top Consumers: +- mealie: 276MB (26.95% of 1GB limit), 0.20% CPU +- tautulli: 215MB (42.10% of 512MB limit), 0.14% CPU +- charon: 210MB (1.31% of 15.6GB limit), 1.51% CPU - Core Charon application container +- seerr: 206MB (20.12% of 1GB limit), 0.06% CPU +``` + +**Analysis:** Docker containers are well-behaved and within limits. The Charon container (210MB) is the main application container and its resource usage is expected and healthy. Collectively, containers are consuming ~10% of system RAM, which is acceptable for a multi-service development environment. Not a primary performance concern. + +--- + +## 4. Workspace Analysis + +### 4.1 File Count and Structure + +``` +Total Files: 64,090 +Total Size: ~1.1GB + +Largest Directories: +- frontend/: 366MB (node_modules heavy) +- backend/: 218MB (test artifacts heavy) +- codeql-db-js/: 215MB (should be in build artifacts) +- codeql-db-javascript/: 121MB (duplicate database) +- codeql-db-go/: 63MB +- node_modules/ (root): 42MB +- my-codeql-db/: 37MB (another duplicate) +``` + +**Critical Findings:** + +- **436MB of CodeQL databases** in workspace root (should be in `.gitignore` or `codeql-agent-results/`) +- **64,090 files** is excessive for IDE indexing, causing slow file searches and symbol lookups +- **110 test artifacts** in backend/ directory (`.cover`, `.html`, `.txt` files) +- Multiple duplicate CodeQL databases (`codeql-db-js`, `codeql-db-javascript`, `my-codeql-db`) + +### 4.2 Large Files + +``` +No files larger than 100MB detected. +``` + +**Analysis:** No individual large files causing issues. The problem is volume, not size. + +### 4.3 Test Artifacts in Workspace Root + +``` +Test Artifacts Count: 110 files + +Located in: +- /projects/Charon/backend/*.cover (50+ files) +- /projects/Charon/backend/*.txt (30+ files) +- /projects/Charon/backend/*.html (20+ files) +- /projects/Charon/*.sarif (3 files) +- /projects/Charon/*.txt (5+ files) +``` + +**Critical Finding:** These files violate the repository structure guidelines (`.github/instructions/structure.instructions.md`) which mandate: + +- Test outputs should go to `test-results/` or be gitignored +- Implementation docs should be in `docs/implementation/` +- Temp config files should not be committed at root + +--- + +## 5. VS Code Server Installation + +``` +VS Code Server Size: 2.9GB +Location: ~/.vscode-server-insiders/ +``` + +**Analysis:** The installation is quite large, likely due to: + +- Multiple extensions installed +- Extension caches +- Logs not being cleaned +- Multiple server versions retained + +--- + +## 6. Network Latency (SSH) + +``` +SSH Connection Test: Failed to complete (interactive prompt) +Load Average History: 0.09 (1m) โ†’ 0.60 (5m) โ†’ 1.38 (15m) +``` + +**Analysis:** + +- SSH connection test couldn't complete automatically due to host key verification +- Decreasing load average (1.38 โ†’ 0.60 โ†’ 0.09) indicates the system is recovering from previous load spikes +- VS Code Remote SSH is stable (connected since Jan 11, 16:44) + +--- + +## 7. Root Cause Analysis + +### Primary Bottlenecks (Ranked by Impact) + +**Note on Caddy:** The Caddy process (110MB RAM, 2.0% CPU) is an **expected core service** of the Charon project, serving as the reverse proxy manager. Its resource usage is typical and healthy for a production reverse proxy. It is **not** a performance issue. + +#### ๐Ÿ”ด **Critical (Immediate Action Required)** + +1. **Duplicate TypeScript Servers (Impact: High)** + - Two TypeScript servers running simultaneously (742MB combined) + - Cause: Likely misconfiguration or extension conflict + - Impact: ~5% of total RAM, significant CPU usage, duplicate work + +2. **Stopped Vite Process Holding 11GB Virtual Memory (Impact: High)** + - PID 2438022: Suspended Vite dev server + - Cause: User likely pressed Ctrl+Z instead of Ctrl+C + - Impact: Resource leak, memory fragmentation, wasted allocation + +3. **110 Test Artifacts in Workspace (Impact: High)** + - 110 coverage/test files in backend/ and root directories + - Cause: Tests not configured to output to `test-results/` + - Impact: Slow file indexing, search performance degradation, workspace clutter + +4. **Excessive Workspace File Count - 64,090 Files (Impact: High)** + - Cause: `node_modules/`, CodeQL databases, test artifacts not properly excluded + - Impact: Slow symbol search, file watchers overwhelmed, memory pressure + +#### ๐ŸŸก **Important (Address Soon)** + +1. **436MB of CodeQL Databases in Workspace Root (Impact: Medium)** + - `codeql-db-*` and `my-codeql-db` directories not gitignored + - Cause: CodeQL scans not cleaning up after completion + - Impact: Wasted disk space, unnecessary file watching + +2. **No Swap Space Configured (Impact: Medium)** + - 0B swap available + - Cause: Server configuration choice + - Impact: Risk of OOM kills under memory pressure + +3. **Large VS Code Server - 2.9GB (Impact: Medium)** + - Likely due to multiple extension versions and caches + - Impact: Disk space, slower extension loading + +4. **1 Zombie Process (Impact: Low)** + - PID 2271208: [wget] defunct + - Cause: Parent process didn't properly wait() on child + - Impact: Minor - consumes PID entry only + +#### ๐ŸŸข **Optimization (Nice to Have)** + +1. **11 Docker Containers Running (Impact: Low)** + - Consuming ~1.6GB RAM collectively + - Impact: Background load, acceptable for workstation use + +2. **Multiple Language Servers Active (Impact: Low)** + - Expected behavior for multi-language workspace + - Impact: Necessary for functionality + +--- + +## 8. Recommended Actions + +### ๐Ÿšจ **Immediate Actions (Do Now)** + +#### 1. Kill Stopped/Zombie Processes + +```bash +# Kill zombie wget process +kill -9 2271208 + +# Kill stopped Vite processes +kill -9 2438000 2438021 2438022 2438034 +``` + +**Expected Impact:** Free up ~130MB RAM, eliminate resource leak + +#### 2. Clean Up Test Artifacts + +```bash +# Move test artifacts to proper location +cd /projects/Charon +mkdir -p test-results/backend-coverage +mv backend/*.cover backend/*.html backend/*.txt test-results/backend-coverage/ 2>/dev/null + +# Clean up root-level test artifacts +rm -f *.sarif trivy-*.txt coverage.txt +``` + +**Expected Impact:** Reduce file count by 110+, improve indexing speed by ~15-20% + +#### 3. Remove Duplicate CodeQL Databases + +```bash +# Remove CodeQL databases from workspace root +cd /projects/Charon +rm -rf codeql-db-go codeql-db-javascript codeql-db-js my-codeql-db + +# Add to .gitignore if not already present +echo "codeql-db-*/" >> .gitignore +echo "my-codeql-db/" >> .gitignore +``` + +**Expected Impact:** Free 436MB disk, reduce file count by ~15,000, improve indexing speed + +#### 4. Update .gitignore to Prevent Future Artifacts + +```bash +cat >> /projects/Charon/.gitignore << 'EOF' + +# Test artifacts (should go in test-results/) +**/*.cover +**/*.sarif +**/coverage*.txt +**/trivy-*.txt + +# CodeQL databases +codeql-db-*/ +codeql-agent-results/ +my-codeql-db/ +EOF +``` + +#### 5. Restart TypeScript Language Server + +**In VS Code:** + +1. Press `Ctrl+Shift+P` +2. Type: "TypeScript: Restart TS Server" +3. Press Enter + +**Expected Impact:** Reduce TypeScript memory usage by ~300MB, eliminate duplicate server + +--- + +### ๐Ÿ“‹ **Short-Term Actions (This Week)** + +#### 6. Configure Test Output Directory + +**backend/Makefile or test scripts:** + +```makefile +# Update test targets to output to test-results/ +test: + mkdir -p ../test-results/backend-coverage + go test ./... -coverprofile=../test-results/backend-coverage/coverage.out + go tool cover -html=../test-results/backend-coverage/coverage.out -o ../test-results/backend-coverage/coverage.html +``` + +#### 7. Optimize VS Code Settings for Large Workspace + +**Add to `.vscode/settings.json`:** + +```json +{ + "files.watcherExclude": { + "**/node_modules/**": true, + "**/codeql-db-*/**": true, + "**/test-results/**": true, + "**/.venv/**": true, + "**/backend/vendor/**": true + }, + "search.exclude": { + "**/node_modules": true, + "**/codeql-db-*": true, + "**/test-results": true, + "**/.venv": true, + "**/backend/vendor": true + }, + "files.exclude": { + "**/node_modules": false, + "**/codeql-db-*": true, + "**/.venv": true + }, + "typescript.tsserver.maxTsServerMemory": 4096, + "typescript.disableAutomaticTypeAcquisition": true, + "eslint.workingDirectories": [ + { "directory": "./frontend", "changeProcessCWD": true } + ] +} +``` + +#### 8. Clean Up VS Code Server Cache + +```bash +# Clean VS Code extension cache +rm -rf ~/.vscode-server-insiders/data/logs/* +rm -rf ~/.vscode-server-insiders/extensions/*/node_modules/.cache + +# Clean TypeScript cache +rm -rf ~/.cache/typescript/* +``` + +**Expected Impact:** Free ~500MB-1GB, faster extension loading + +#### 9. Configure Workspace File Limits + +**Add to `.vscode/settings.json`:** + +```json +{ + "files.maxMemoryForLargeFilesMB": 4096, + "typescript.preferences.autoImportFileExcludePatterns": [ + "**/node_modules/*", + "**/.venv/*", + "**/vendor/*" + ] +} +``` + +--- + +### ๐Ÿ”ง **Long-Term Solutions (This Month)** + +#### 10. Enable Swap Space (Recommended) + +```bash +# Create 8GB swap file +sudo fallocate -l 8G /swapfile +sudo chmod 600 /swapfile +sudo mkswap /swapfile +sudo swapon /swapfile + +# Make permanent +echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab + +# Set swappiness (how aggressive to use swap) +echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf +sudo sysctl -p +``` + +**Expected Impact:** Prevent OOM conditions during memory pressure + +#### 11. Implement Automated Cleanup Script + +**Create `.github/scripts/cleanup-artifacts.sh`:** + +```bash +#!/bin/bash +# Automated cleanup of test artifacts and temporary files + +set -e + +WORKSPACE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$WORKSPACE_ROOT" + +echo "๐Ÿงน Cleaning test artifacts..." +mkdir -p test-results/backend-coverage +find backend -maxdepth 1 \( -name "*.cover" -o -name "*.html" -o -name "*_test.txt" \) \ + -exec mv {} test-results/backend-coverage/ \; 2>/dev/null || true + +echo "๐Ÿ—‘๏ธ Removing CodeQL databases..." +rm -rf codeql-db-* my-codeql-db + +echo "๐Ÿ“Š Workspace stats:" +echo " Total files: $(find . -type f | wc -l)" +echo " Workspace size: $(du -sh . | cut -f1)" + +echo "โœ… Cleanup complete!" +``` + +**Run weekly via cron or manually:** + +```bash +chmod +x .github/scripts/cleanup-artifacts.sh +./.github/scripts/cleanup-artifacts.sh +``` + +#### 12. Split Large Workspaces + +Consider creating separate VS Code workspaces for frontend and backend: + +- `Charon-Backend.code-workspace` (backend/, tools/, docs/) +- `Charon-Frontend.code-workspace` (frontend/, docs/) + +**Benefits:** + +- Reduced memory per workspace +- Faster language server initialization +- More focused development environment + +#### 13. Upgrade System Resources (If Budget Allows) + +If performance issues persist: + +- **RAM:** Upgrade to 32GB (current: 16GB) +- **CPU:** Upgrade to 6-8 cores (current: 4 cores) +- **Storage:** Add NVMe SSD for project directories + +--- + +## 9. Expected Performance Improvements + +### After Immediate Actions (5-10 minutes work) + +| Metric | Before | After | Improvement | +|--------|--------|-------|-------------| +| VS Code Memory | 3.2GB | 2.7GB | -15% | +| Workspace Files | 64,090 | ~48,000 | -25% | +| File Indexing Speed | Slow | Medium | +30% | +| Symbol Search Speed | Slow | Medium | +40% | +| Disk Usage | 64GB | 63.5GB | +0.5GB free | + +### After Short-Term Actions (1-2 hours work) + +| Metric | Before | After | Improvement | +|--------|--------|-------|-------------| +| VS Code Memory | 3.2GB | 2.2GB | -31% | +| File Watcher Load | High | Low | -50% | +| Extension Load Time | Slow | Fast | +60% | +| TypeScript Responsiveness | Laggy | Responsive | +80% | + +### After Long-Term Solutions (Ongoing) + +| Metric | Before | After | Improvement | +|--------|--------|-------|-------------| +| OOM Risk | Medium | Low | -80% | +| Workspace Maintainability | Poor | Good | +100% | +| Overall Responsiveness | Laggy | Snappy | +150% | + +--- + +## 10. Monitoring and Prevention + +### Daily Health Checks + +```bash +# Quick system health check +echo "=== System Health ===" +uptime +free -h +docker stats --no-stream +ps aux --sort=-%mem | head -5 + +# Quick workspace check +echo "=== Workspace Health ===" +echo "Files: $(find /projects/Charon -type f | wc -l)" +echo "Size: $(du -sh /projects/Charon)" +echo "Test artifacts: $(find /projects/Charon/backend -maxdepth 1 -name "*.cover" | wc -l)" +``` + +### Warning Signs to Watch For + +- โœ‹ Memory usage > 80% (12.5GB+) +- โœ‹ Load average > 3.0 (sustained) +- โœ‹ VS Code processes > 4GB combined +- โœ‹ Workspace file count > 70,000 +- โœ‹ Test artifacts > 50 files +- โœ‹ Disk usage > 85% + +### Automated Monitoring + +Set up a daily cron job: + +```bash +# Add to crontab +0 9 * * * /projects/Charon/.github/scripts/cleanup-artifacts.sh +``` + +--- + +## 11. Conclusion + +The VS Code performance issues are **primarily caused by resource accumulation** rather than resource exhaustion: + +- **Duplicate TypeScript servers** consuming 742MB (critical) +- **Stopped Vite process** holding 11GB virtual memory (critical) +- **64,090+ files** overwhelming file watchers (high impact) +- **110+ test artifacts** causing slow indexing (high impact) +- **436MB of CodeQL databases** unnecessarily watched (medium impact) + +**Note:** Caddy (110MB) and Docker containers (~1.6GB) are **expected services** for the Charon project and not contributing to performance issues. Their resource usage is healthy and typical for a reverse proxy manager and application containers. + +**Quick Wins:** Execute immediate actions (15 minutes) to achieve **15-40% performance improvement** by eliminating duplicate processes and cleaning workspace clutter. + +**Sustainable Solution:** Implement all short-term and long-term actions to achieve **150%+ overall performance improvement** and prevent future degradation through proper configuration and automated cleanup. + +--- + +## 12. Action Checklist + +### Immediate (Today) โœ… + +- [ ] Kill zombie and stopped processes +- [ ] Clean up 110+ test artifacts from workspace root +- [ ] Remove 436MB of CodeQL databases +- [ ] Update .gitignore +- [ ] Restart TypeScript language server + +### Short-Term (This Week) ๐Ÿ“‹ + +- [ ] Configure test output directory +- [ ] Optimize VS Code workspace settings +- [ ] Clean VS Code server cache +- [ ] Configure file watcher exclusions + +### Long-Term (This Month) ๐Ÿ”ง + +- [ ] Enable 8GB swap space +- [ ] Implement automated cleanup script +- [ ] Consider workspace splitting +- [ ] Set up daily monitoring + +### Verify Improvements โœ… + +- [ ] Measure file indexing time (search for random symbol) +- [ ] Check VS Code memory usage: `ps aux | grep vscode` +- [ ] Verify file count: `find /projects/Charon -type f | wc -l` +- [ ] Test TypeScript autocomplete responsiveness + +--- + +**Report Generated:** January 12, 2026, 04:08 UTC +**Next Review:** After implementing immediate actions (within 24 hours) diff --git a/docs/reports/phase1_analysis.md b/docs/reports/archive/phase1_analysis.md similarity index 100% rename from docs/reports/phase1_analysis.md rename to docs/reports/archive/phase1_analysis.md diff --git a/docs/reports/phase1_complete.md b/docs/reports/archive/phase1_complete.md similarity index 100% rename from docs/reports/phase1_complete.md rename to docs/reports/archive/phase1_complete.md diff --git a/docs/reports/phase1_diagnostics.md b/docs/reports/archive/phase1_diagnostics.md similarity index 100% rename from docs/reports/phase1_diagnostics.md rename to docs/reports/archive/phase1_diagnostics.md diff --git a/docs/reports/phase1_final_report.md b/docs/reports/archive/phase1_final_report.md similarity index 100% rename from docs/reports/phase1_final_report.md rename to docs/reports/archive/phase1_final_report.md diff --git a/docs/reports/phase1_validation.md b/docs/reports/archive/phase1_validation.md similarity index 100% rename from docs/reports/phase1_validation.md rename to docs/reports/archive/phase1_validation.md diff --git a/docs/reports/phase1_validation_checklist.md b/docs/reports/archive/phase1_validation_checklist.md similarity index 100% rename from docs/reports/phase1_validation_checklist.md rename to docs/reports/archive/phase1_validation_checklist.md diff --git a/docs/reports/phase2_checkpoint_report.md b/docs/reports/archive/phase2_checkpoint_report.md similarity index 100% rename from docs/reports/phase2_checkpoint_report.md rename to docs/reports/archive/phase2_checkpoint_report.md diff --git a/docs/reports/phase2_complete.md b/docs/reports/archive/phase2_complete.md similarity index 100% rename from docs/reports/phase2_complete.md rename to docs/reports/archive/phase2_complete.md diff --git a/docs/reports/phase2_failure_triage.md b/docs/reports/archive/phase2_failure_triage.md similarity index 100% rename from docs/reports/phase2_failure_triage.md rename to docs/reports/archive/phase2_failure_triage.md diff --git a/docs/reports/phase3_3_completion_report.md b/docs/reports/archive/phase3_3_completion_report.md similarity index 100% rename from docs/reports/phase3_3_completion_report.md rename to docs/reports/archive/phase3_3_completion_report.md diff --git a/docs/reports/phase3_3_findings.md b/docs/reports/archive/phase3_3_findings.md similarity index 100% rename from docs/reports/phase3_3_findings.md rename to docs/reports/archive/phase3_3_findings.md diff --git a/docs/reports/phase3_4_validation_report.md b/docs/reports/archive/phase3_4_validation_report.md similarity index 100% rename from docs/reports/phase3_4_validation_report.md rename to docs/reports/archive/phase3_4_validation_report.md diff --git a/docs/reports/phase3_coverage_gap_analysis.md b/docs/reports/archive/phase3_coverage_gap_analysis.md similarity index 100% rename from docs/reports/phase3_coverage_gap_analysis.md rename to docs/reports/archive/phase3_coverage_gap_analysis.md diff --git a/docs/reports/phase4_dns_autodetection_qa_report.md b/docs/reports/archive/phase4_dns_autodetection_qa_report.md similarity index 100% rename from docs/reports/phase4_dns_autodetection_qa_report.md rename to docs/reports/archive/phase4_dns_autodetection_qa_report.md diff --git a/docs/reports/phase5_qa_report_20260120.md b/docs/reports/archive/phase5_qa_report_20260120.md similarity index 100% rename from docs/reports/phase5_qa_report_20260120.md rename to docs/reports/archive/phase5_qa_report_20260120.md diff --git a/docs/reports/pr1_backend_impl_status.md b/docs/reports/archive/pr1_backend_impl_status.md similarity index 100% rename from docs/reports/pr1_backend_impl_status.md rename to docs/reports/archive/pr1_backend_impl_status.md diff --git a/docs/reports/pr1_frontend_impl_status.md b/docs/reports/archive/pr1_frontend_impl_status.md similarity index 100% rename from docs/reports/pr1_frontend_impl_status.md rename to docs/reports/archive/pr1_frontend_impl_status.md diff --git a/docs/reports/pr1_supervisor_review.md b/docs/reports/archive/pr1_supervisor_review.md similarity index 100% rename from docs/reports/pr1_supervisor_review.md rename to docs/reports/archive/pr1_supervisor_review.md diff --git a/docs/reports/pr2_impl_status.md b/docs/reports/archive/pr2_impl_status.md similarity index 100% rename from docs/reports/pr2_impl_status.md rename to docs/reports/archive/pr2_impl_status.md diff --git a/docs/reports/pr2_supervisor_review.md b/docs/reports/archive/pr2_supervisor_review.md similarity index 100% rename from docs/reports/pr2_supervisor_review.md rename to docs/reports/archive/pr2_supervisor_review.md diff --git a/docs/reports/pr3_hygiene_scanner_hardening_2026-02-18.md b/docs/reports/archive/pr3_hygiene_scanner_hardening_2026-02-18.md similarity index 100% rename from docs/reports/pr3_hygiene_scanner_hardening_2026-02-18.md rename to docs/reports/archive/pr3_hygiene_scanner_hardening_2026-02-18.md diff --git a/docs/reports/pr460_qa_report.md b/docs/reports/archive/pr460_qa_report.md similarity index 100% rename from docs/reports/pr460_qa_report.md rename to docs/reports/archive/pr460_qa_report.md diff --git a/docs/reports/pr718_open_alerts_baseline.json b/docs/reports/archive/pr718_open_alerts_baseline.json similarity index 100% rename from docs/reports/pr718_open_alerts_baseline.json rename to docs/reports/archive/pr718_open_alerts_baseline.json diff --git a/docs/reports/pr718_open_alerts_freshness_20260218T135045Z.json b/docs/reports/archive/pr718_open_alerts_freshness_20260218T135045Z.json similarity index 100% rename from docs/reports/pr718_open_alerts_freshness_20260218T135045Z.json rename to docs/reports/archive/pr718_open_alerts_freshness_20260218T135045Z.json diff --git a/docs/reports/pr718_open_alerts_freshness_20260218T135045Z.md b/docs/reports/archive/pr718_open_alerts_freshness_20260218T135045Z.md similarity index 100% rename from docs/reports/pr718_open_alerts_freshness_20260218T135045Z.md rename to docs/reports/archive/pr718_open_alerts_freshness_20260218T135045Z.md diff --git a/docs/reports/pr718_open_alerts_freshness_20260218T163443Z.json b/docs/reports/archive/pr718_open_alerts_freshness_20260218T163443Z.json similarity index 100% rename from docs/reports/pr718_open_alerts_freshness_20260218T163443Z.json rename to docs/reports/archive/pr718_open_alerts_freshness_20260218T163443Z.json diff --git a/docs/reports/pr718_open_alerts_freshness_20260218T163443Z.md b/docs/reports/archive/pr718_open_alerts_freshness_20260218T163443Z.md similarity index 100% rename from docs/reports/pr718_open_alerts_freshness_20260218T163443Z.md rename to docs/reports/archive/pr718_open_alerts_freshness_20260218T163443Z.md diff --git a/docs/reports/pr718_open_alerts_freshness_20260218T163456Z.json b/docs/reports/archive/pr718_open_alerts_freshness_20260218T163456Z.json similarity index 100% rename from docs/reports/pr718_open_alerts_freshness_20260218T163456Z.json rename to docs/reports/archive/pr718_open_alerts_freshness_20260218T163456Z.json diff --git a/docs/reports/pr718_open_alerts_freshness_20260218T163456Z.md b/docs/reports/archive/pr718_open_alerts_freshness_20260218T163456Z.md similarity index 100% rename from docs/reports/pr718_open_alerts_freshness_20260218T163456Z.md rename to docs/reports/archive/pr718_open_alerts_freshness_20260218T163456Z.md diff --git a/docs/reports/pr718_open_alerts_freshness_20260218T163528Z.json b/docs/reports/archive/pr718_open_alerts_freshness_20260218T163528Z.json similarity index 100% rename from docs/reports/pr718_open_alerts_freshness_20260218T163528Z.json rename to docs/reports/archive/pr718_open_alerts_freshness_20260218T163528Z.json diff --git a/docs/reports/pr718_open_alerts_freshness_20260218T163528Z.md b/docs/reports/archive/pr718_open_alerts_freshness_20260218T163528Z.md similarity index 100% rename from docs/reports/pr718_open_alerts_freshness_20260218T163528Z.md rename to docs/reports/archive/pr718_open_alerts_freshness_20260218T163528Z.md diff --git a/docs/reports/pr718_open_alerts_freshness_20260218T163918Z.json b/docs/reports/archive/pr718_open_alerts_freshness_20260218T163918Z.json similarity index 100% rename from docs/reports/pr718_open_alerts_freshness_20260218T163918Z.json rename to docs/reports/archive/pr718_open_alerts_freshness_20260218T163918Z.json diff --git a/docs/reports/pr718_open_alerts_freshness_20260218T163918Z.md b/docs/reports/archive/pr718_open_alerts_freshness_20260218T163918Z.md similarity index 100% rename from docs/reports/pr718_open_alerts_freshness_20260218T163918Z.md rename to docs/reports/archive/pr718_open_alerts_freshness_20260218T163918Z.md diff --git a/docs/reports/pr718_remediation_progress_closure_2026-02-18.md b/docs/reports/archive/pr718_remediation_progress_closure_2026-02-18.md similarity index 100% rename from docs/reports/pr718_remediation_progress_closure_2026-02-18.md rename to docs/reports/archive/pr718_remediation_progress_closure_2026-02-18.md diff --git a/docs/reports/pr_461_remediation_complete.md b/docs/reports/archive/pr_461_remediation_complete.md similarity index 100% rename from docs/reports/pr_461_remediation_complete.md rename to docs/reports/archive/pr_461_remediation_complete.md diff --git a/docs/reports/pr_461_vulnerability_comment.md b/docs/reports/archive/pr_461_vulnerability_comment.md similarity index 100% rename from docs/reports/pr_461_vulnerability_comment.md rename to docs/reports/archive/pr_461_vulnerability_comment.md diff --git a/docs/reports/precommit_blockers.md b/docs/reports/archive/precommit_blockers.md similarity index 100% rename from docs/reports/precommit_blockers.md rename to docs/reports/archive/precommit_blockers.md diff --git a/docs/reports/precommit_fix_verification.md b/docs/reports/archive/precommit_fix_verification.md similarity index 100% rename from docs/reports/precommit_fix_verification.md rename to docs/reports/archive/precommit_fix_verification.md diff --git a/docs/reports/precommit_performance_diagnosis.md b/docs/reports/archive/precommit_performance_diagnosis.md similarity index 100% rename from docs/reports/precommit_performance_diagnosis.md rename to docs/reports/archive/precommit_performance_diagnosis.md diff --git a/docs/reports/qa_agent_skills_migration.md b/docs/reports/archive/qa_agent_skills_migration.md similarity index 100% rename from docs/reports/qa_agent_skills_migration.md rename to docs/reports/archive/qa_agent_skills_migration.md diff --git a/docs/reports/qa_codeql_ci_alignment.md b/docs/reports/archive/qa_codeql_ci_alignment.md similarity index 100% rename from docs/reports/qa_codeql_ci_alignment.md rename to docs/reports/archive/qa_codeql_ci_alignment.md diff --git a/docs/reports/qa_coverage_validation_report.md b/docs/reports/archive/qa_coverage_validation_report.md similarity index 100% rename from docs/reports/qa_coverage_validation_report.md rename to docs/reports/archive/qa_coverage_validation_report.md diff --git a/docs/reports/qa_crowdsec_frontend_coverage_report.md b/docs/reports/archive/qa_crowdsec_frontend_coverage_report.md similarity index 100% rename from docs/reports/qa_crowdsec_frontend_coverage_report.md rename to docs/reports/archive/qa_crowdsec_frontend_coverage_report.md diff --git a/docs/reports/qa_crowdsec_implementation.md b/docs/reports/archive/qa_crowdsec_implementation.md similarity index 100% rename from docs/reports/qa_crowdsec_implementation.md rename to docs/reports/archive/qa_crowdsec_implementation.md diff --git a/docs/reports/qa_crowdsec_lapi_auth_fix.md b/docs/reports/archive/qa_crowdsec_lapi_auth_fix.md similarity index 100% rename from docs/reports/qa_crowdsec_lapi_auth_fix.md rename to docs/reports/archive/qa_crowdsec_lapi_auth_fix.md diff --git a/docs/reports/qa_crowdsec_lapi_availability_fix.md b/docs/reports/archive/qa_crowdsec_lapi_availability_fix.md similarity index 100% rename from docs/reports/qa_crowdsec_lapi_availability_fix.md rename to docs/reports/archive/qa_crowdsec_lapi_availability_fix.md diff --git a/docs/reports/qa_crowdsec_startup_test_failure.md b/docs/reports/archive/qa_crowdsec_startup_test_failure.md similarity index 100% rename from docs/reports/qa_crowdsec_startup_test_failure.md rename to docs/reports/archive/qa_crowdsec_startup_test_failure.md diff --git a/docs/reports/qa_crowdsec_toggle_fix_summary.md b/docs/reports/archive/qa_crowdsec_toggle_fix_summary.md similarity index 100% rename from docs/reports/qa_crowdsec_toggle_fix_summary.md rename to docs/reports/archive/qa_crowdsec_toggle_fix_summary.md diff --git a/docs/reports/qa_cwe918_ssrf_triage.md b/docs/reports/archive/qa_cwe918_ssrf_triage.md similarity index 100% rename from docs/reports/qa_cwe918_ssrf_triage.md rename to docs/reports/archive/qa_cwe918_ssrf_triage.md diff --git a/docs/reports/qa_debian_trixie_migration_2026-01-18.md b/docs/reports/archive/qa_debian_trixie_migration_2026-01-18.md similarity index 100% rename from docs/reports/qa_debian_trixie_migration_2026-01-18.md rename to docs/reports/archive/qa_debian_trixie_migration_2026-01-18.md diff --git a/docs/reports/qa_docker_only_build_fix_report.md b/docs/reports/archive/qa_docker_only_build_fix_report.md similarity index 100% rename from docs/reports/qa_docker_only_build_fix_report.md rename to docs/reports/archive/qa_docker_only_build_fix_report.md diff --git a/docs/reports/qa_docs_to_issues_workflow_fix.md b/docs/reports/archive/qa_docs_to_issues_workflow_fix.md similarity index 100% rename from docs/reports/qa_docs_to_issues_workflow_fix.md rename to docs/reports/archive/qa_docs_to_issues_workflow_fix.md diff --git a/docs/reports/qa_e2e_test_fixes_report.md b/docs/reports/archive/qa_e2e_test_fixes_report.md similarity index 100% rename from docs/reports/qa_e2e_test_fixes_report.md rename to docs/reports/archive/qa_e2e_test_fixes_report.md diff --git a/docs/reports/qa_final_audit.md b/docs/reports/archive/qa_final_audit.md similarity index 100% rename from docs/reports/qa_final_audit.md rename to docs/reports/archive/qa_final_audit.md diff --git a/docs/reports/qa_final_crowdsec_validation.md b/docs/reports/archive/qa_final_crowdsec_validation.md similarity index 100% rename from docs/reports/qa_final_crowdsec_validation.md rename to docs/reports/archive/qa_final_crowdsec_validation.md diff --git a/docs/reports/qa_final_validation_sprint1.md b/docs/reports/archive/qa_final_validation_sprint1.md similarity index 100% rename from docs/reports/qa_final_validation_sprint1.md rename to docs/reports/archive/qa_final_validation_sprint1.md diff --git a/docs/reports/qa_geolite2_checksum_fix.md b/docs/reports/archive/qa_geolite2_checksum_fix.md similarity index 100% rename from docs/reports/qa_geolite2_checksum_fix.md rename to docs/reports/archive/qa_geolite2_checksum_fix.md diff --git a/docs/reports/qa_i18n_report.md b/docs/reports/archive/qa_i18n_report.md similarity index 100% rename from docs/reports/qa_i18n_report.md rename to docs/reports/archive/qa_i18n_report.md diff --git a/docs/reports/qa_phase0_e2e_infrastructure.md b/docs/reports/archive/qa_phase0_e2e_infrastructure.md similarity index 100% rename from docs/reports/qa_phase0_e2e_infrastructure.md rename to docs/reports/archive/qa_phase0_e2e_infrastructure.md diff --git a/docs/reports/qa_phase2_testdata_auth_fix_20250123.md b/docs/reports/archive/qa_phase2_testdata_auth_fix_20250123.md similarity index 100% rename from docs/reports/qa_phase2_testdata_auth_fix_20250123.md rename to docs/reports/archive/qa_phase2_testdata_auth_fix_20250123.md diff --git a/docs/reports/qa_phase3_caddy_import_firefox_fix.md b/docs/reports/archive/qa_phase3_caddy_import_firefox_fix.md similarity index 100% rename from docs/reports/qa_phase3_caddy_import_firefox_fix.md rename to docs/reports/archive/qa_phase3_caddy_import_firefox_fix.md diff --git a/docs/reports/qa_phase5_testdata_auth_20260124.md b/docs/reports/archive/qa_phase5_testdata_auth_20260124.md similarity index 100% rename from docs/reports/qa_phase5_testdata_auth_20260124.md rename to docs/reports/archive/qa_phase5_testdata_auth_20260124.md diff --git a/docs/reports/qa_race_and_test_failures_2025-12-12.md b/docs/reports/archive/qa_race_and_test_failures_2025-12-12.md similarity index 100% rename from docs/reports/qa_race_and_test_failures_2025-12-12.md rename to docs/reports/archive/qa_race_and_test_failures_2025-12-12.md diff --git a/docs/reports/qa_report_acl_uuid_validation.md b/docs/reports/archive/qa_report_acl_uuid_validation.md similarity index 100% rename from docs/reports/qa_report_acl_uuid_validation.md rename to docs/reports/archive/qa_report_acl_uuid_validation.md diff --git a/docs/reports/qa_report_bulk_apply_headers.md b/docs/reports/archive/qa_report_bulk_apply_headers.md similarity index 100% rename from docs/reports/qa_report_bulk_apply_headers.md rename to docs/reports/archive/qa_report_bulk_apply_headers.md diff --git a/docs/reports/qa_report_capi_fix.md b/docs/reports/archive/qa_report_capi_fix.md similarity index 100% rename from docs/reports/qa_report_capi_fix.md rename to docs/reports/archive/qa_report_capi_fix.md diff --git a/docs/reports/qa_report_ci_fixes.md b/docs/reports/archive/qa_report_ci_fixes.md similarity index 100% rename from docs/reports/qa_report_ci_fixes.md rename to docs/reports/archive/qa_report_ci_fixes.md diff --git a/docs/reports/qa_report_crowdsec_architecture.md b/docs/reports/archive/qa_report_crowdsec_architecture.md similarity index 100% rename from docs/reports/qa_report_crowdsec_architecture.md rename to docs/reports/archive/qa_report_crowdsec_architecture.md diff --git a/docs/reports/qa_report_crowdsec_markdownlint_20251212.md b/docs/reports/archive/qa_report_crowdsec_markdownlint_20251212.md similarity index 100% rename from docs/reports/qa_report_crowdsec_markdownlint_20251212.md rename to docs/reports/archive/qa_report_crowdsec_markdownlint_20251212.md diff --git a/docs/reports/qa_report_crowdsec_startup_fix.md b/docs/reports/archive/qa_report_crowdsec_startup_fix.md similarity index 100% rename from docs/reports/qa_report_crowdsec_startup_fix.md rename to docs/reports/archive/qa_report_crowdsec_startup_fix.md diff --git a/docs/reports/qa_report_crowdsec_verification.md b/docs/reports/archive/qa_report_crowdsec_verification.md similarity index 100% rename from docs/reports/qa_report_crowdsec_verification.md rename to docs/reports/archive/qa_report_crowdsec_verification.md diff --git a/docs/reports/qa_report_dns_provider_e2e_fixes.md b/docs/reports/archive/qa_report_dns_provider_e2e_fixes.md similarity index 100% rename from docs/reports/qa_report_dns_provider_e2e_fixes.md rename to docs/reports/archive/qa_report_dns_provider_e2e_fixes.md diff --git a/docs/reports/qa_report_docker_tag_fix_pr421.md b/docs/reports/archive/qa_report_docker_tag_fix_pr421.md similarity index 100% rename from docs/reports/qa_report_docker_tag_fix_pr421.md rename to docs/reports/archive/qa_report_docker_tag_fix_pr421.md diff --git a/docs/reports/qa_report_dod_verification.md b/docs/reports/archive/qa_report_dod_verification.md similarity index 100% rename from docs/reports/qa_report_dod_verification.md rename to docs/reports/archive/qa_report_dod_verification.md diff --git a/docs/reports/qa_report_dual_registry_publishing_2026-01-25.md b/docs/reports/archive/qa_report_dual_registry_publishing_2026-01-25.md similarity index 100% rename from docs/reports/qa_report_dual_registry_publishing_2026-01-25.md rename to docs/reports/archive/qa_report_dual_registry_publishing_2026-01-25.md diff --git a/docs/reports/qa_report_final.md b/docs/reports/archive/qa_report_final.md similarity index 100% rename from docs/reports/qa_report_final.md rename to docs/reports/archive/qa_report_final.md diff --git a/docs/reports/qa_report_geoip_v2.md b/docs/reports/archive/qa_report_geoip_v2.md similarity index 100% rename from docs/reports/qa_report_geoip_v2.md rename to docs/reports/archive/qa_report_geoip_v2.md diff --git a/docs/reports/qa_report_grype_sbom_2026-01-10.md b/docs/reports/archive/qa_report_grype_sbom_2026-01-10.md similarity index 100% rename from docs/reports/qa_report_grype_sbom_2026-01-10.md rename to docs/reports/archive/qa_report_grype_sbom_2026-01-10.md diff --git a/docs/reports/qa_report_i18n.md b/docs/reports/archive/qa_report_i18n.md similarity index 100% rename from docs/reports/qa_report_i18n.md rename to docs/reports/archive/qa_report_i18n.md diff --git a/docs/reports/qa_report_issue20_security_headers.md b/docs/reports/archive/qa_report_issue20_security_headers.md similarity index 100% rename from docs/reports/qa_report_issue20_security_headers.md rename to docs/reports/archive/qa_report_issue20_security_headers.md diff --git a/docs/reports/qa_report_issue365.md b/docs/reports/archive/qa_report_issue365.md similarity index 100% rename from docs/reports/qa_report_issue365.md rename to docs/reports/archive/qa_report_issue365.md diff --git a/docs/reports/qa_report_old_20260116_023158.md b/docs/reports/archive/qa_report_old_20260116_023158.md similarity index 100% rename from docs/reports/qa_report_old_20260116_023158.md rename to docs/reports/archive/qa_report_old_20260116_023158.md diff --git a/docs/reports/qa_report_phase2.md b/docs/reports/archive/qa_report_phase2.md similarity index 100% rename from docs/reports/qa_report_phase2.md rename to docs/reports/archive/qa_report_phase2.md diff --git a/docs/reports/qa_report_phase3.md b/docs/reports/archive/qa_report_phase3.md similarity index 100% rename from docs/reports/qa_report_phase3.md rename to docs/reports/archive/qa_report_phase3.md diff --git a/docs/reports/qa_report_phase3_remediation.md b/docs/reports/archive/qa_report_phase3_remediation.md similarity index 100% rename from docs/reports/qa_report_phase3_remediation.md rename to docs/reports/archive/qa_report_phase3_remediation.md diff --git a/docs/reports/qa_report_pr1.md b/docs/reports/archive/qa_report_pr1.md similarity index 100% rename from docs/reports/qa_report_pr1.md rename to docs/reports/archive/qa_report_pr1.md diff --git a/docs/reports/qa_report_pr583.md b/docs/reports/archive/qa_report_pr583.md similarity index 100% rename from docs/reports/qa_report_pr583.md rename to docs/reports/archive/qa_report_pr583.md diff --git a/docs/reports/qa_report_proxy_host_update_fix.md b/docs/reports/archive/qa_report_proxy_host_update_fix.md similarity index 100% rename from docs/reports/qa_report_proxy_host_update_fix.md rename to docs/reports/archive/qa_report_proxy_host_update_fix.md diff --git a/docs/reports/qa_report_rate_limiting_20251212.md b/docs/reports/archive/qa_report_rate_limiting_20251212.md similarity index 100% rename from docs/reports/qa_report_rate_limiting_20251212.md rename to docs/reports/archive/qa_report_rate_limiting_20251212.md diff --git a/docs/reports/qa_report_sidebar_ui.md b/docs/reports/archive/qa_report_sidebar_ui.md similarity index 100% rename from docs/reports/qa_report_sidebar_ui.md rename to docs/reports/archive/qa_report_sidebar_ui.md diff --git a/docs/reports/qa_report_ssrf_fix.md b/docs/reports/archive/qa_report_ssrf_fix.md similarity index 100% rename from docs/reports/qa_report_ssrf_fix.md rename to docs/reports/archive/qa_report_ssrf_fix.md diff --git a/docs/reports/qa_report_standard_proxy_headers.md b/docs/reports/archive/qa_report_standard_proxy_headers.md similarity index 100% rename from docs/reports/qa_report_standard_proxy_headers.md rename to docs/reports/archive/qa_report_standard_proxy_headers.md diff --git a/docs/reports/qa_report_staticcheck_old.md b/docs/reports/archive/qa_report_staticcheck_old.md similarity index 100% rename from docs/reports/qa_report_staticcheck_old.md rename to docs/reports/archive/qa_report_staticcheck_old.md diff --git a/docs/reports/qa_report_validator_fix_20260128.md b/docs/reports/archive/qa_report_validator_fix_20260128.md similarity index 100% rename from docs/reports/qa_report_validator_fix_20260128.md rename to docs/reports/archive/qa_report_validator_fix_20260128.md diff --git a/docs/reports/qa_report_waf_integration_fix_2026-01-25.md b/docs/reports/archive/qa_report_waf_integration_fix_2026-01-25.md similarity index 100% rename from docs/reports/qa_report_waf_integration_fix_2026-01-25.md rename to docs/reports/archive/qa_report_waf_integration_fix_2026-01-25.md diff --git a/docs/reports/qa_report_workflow_orchestration.md b/docs/reports/archive/qa_report_workflow_orchestration.md similarity index 100% rename from docs/reports/qa_report_workflow_orchestration.md rename to docs/reports/archive/qa_report_workflow_orchestration.md diff --git a/docs/reports/qa_security_headers_fix_2025-12-18.md b/docs/reports/archive/qa_security_headers_fix_2025-12-18.md similarity index 100% rename from docs/reports/qa_security_headers_fix_2025-12-18.md rename to docs/reports/archive/qa_security_headers_fix_2025-12-18.md diff --git a/docs/reports/qa_security_weekly_workflow.md b/docs/reports/archive/qa_security_weekly_workflow.md similarity index 100% rename from docs/reports/qa_security_weekly_workflow.md rename to docs/reports/archive/qa_security_weekly_workflow.md diff --git a/docs/reports/qa_ssrf_remediation_final.md b/docs/reports/archive/qa_ssrf_remediation_final.md similarity index 100% rename from docs/reports/qa_ssrf_remediation_final.md rename to docs/reports/archive/qa_ssrf_remediation_final.md diff --git a/docs/reports/qa_ssrf_remediation_report.md b/docs/reports/archive/qa_ssrf_remediation_report.md similarity index 100% rename from docs/reports/qa_ssrf_remediation_report.md rename to docs/reports/archive/qa_ssrf_remediation_report.md diff --git a/docs/reports/qa_summary_sidebar_ui.md b/docs/reports/archive/qa_summary_sidebar_ui.md similarity index 100% rename from docs/reports/qa_summary_sidebar_ui.md rename to docs/reports/archive/qa_summary_sidebar_ui.md diff --git a/docs/reports/qa_supply_chain_security.md b/docs/reports/archive/qa_supply_chain_security.md similarity index 100% rename from docs/reports/qa_supply_chain_security.md rename to docs/reports/archive/qa_supply_chain_security.md diff --git a/docs/reports/qa_test_coverage_audit.md b/docs/reports/archive/qa_test_coverage_audit.md similarity index 100% rename from docs/reports/qa_test_coverage_audit.md rename to docs/reports/archive/qa_test_coverage_audit.md diff --git a/docs/reports/qa_uiux_testing_report.md b/docs/reports/archive/qa_uiux_testing_report.md similarity index 100% rename from docs/reports/qa_uiux_testing_report.md rename to docs/reports/archive/qa_uiux_testing_report.md diff --git a/docs/reports/rate_limit_fix_summary.md b/docs/reports/archive/rate_limit_fix_summary.md similarity index 100% rename from docs/reports/rate_limit_fix_summary.md rename to docs/reports/archive/rate_limit_fix_summary.md diff --git a/docs/reports/rate_limit_test_status.md b/docs/reports/archive/rate_limit_test_status.md similarity index 100% rename from docs/reports/rate_limit_test_status.md rename to docs/reports/archive/rate_limit_test_status.md diff --git a/docs/reports/requirements.md b/docs/reports/archive/requirements.md similarity index 100% rename from docs/reports/requirements.md rename to docs/reports/archive/requirements.md diff --git a/docs/reports/security-module-testing-qa-audit.md b/docs/reports/archive/security-module-testing-qa-audit.md similarity index 100% rename from docs/reports/security-module-testing-qa-audit.md rename to docs/reports/archive/security-module-testing-qa-audit.md diff --git a/docs/reports/security_headers_bug_fix_summary.md b/docs/reports/archive/security_headers_bug_fix_summary.md similarity index 100% rename from docs/reports/security_headers_bug_fix_summary.md rename to docs/reports/archive/security_headers_bug_fix_summary.md diff --git a/docs/reports/security_headers_trace.md b/docs/reports/archive/security_headers_trace.md similarity index 100% rename from docs/reports/security_headers_trace.md rename to docs/reports/archive/security_headers_trace.md diff --git a/docs/reports/security_scan_summary.md b/docs/reports/archive/security_scan_summary.md similarity index 100% rename from docs/reports/security_scan_summary.md rename to docs/reports/archive/security_scan_summary.md diff --git a/docs/reports/shard1_fix_qa_report.md b/docs/reports/archive/shard1_fix_qa_report.md similarity index 100% rename from docs/reports/shard1_fix_qa_report.md rename to docs/reports/archive/shard1_fix_qa_report.md diff --git a/docs/reports/shard_isolation_fix.md b/docs/reports/archive/shard_isolation_fix.md similarity index 100% rename from docs/reports/shard_isolation_fix.md rename to docs/reports/archive/shard_isolation_fix.md diff --git a/docs/reports/supervisor_review.md b/docs/reports/archive/supervisor_review.md similarity index 100% rename from docs/reports/supervisor_review.md rename to docs/reports/archive/supervisor_review.md diff --git a/docs/reports/supervisor_review_dod.md b/docs/reports/archive/supervisor_review_dod.md similarity index 100% rename from docs/reports/supervisor_review_dod.md rename to docs/reports/archive/supervisor_review_dod.md diff --git a/docs/reports/tasks.md b/docs/reports/archive/tasks.md similarity index 100% rename from docs/reports/tasks.md rename to docs/reports/archive/tasks.md diff --git a/docs/reports/unused_code_audit.md b/docs/reports/archive/unused_code_audit.md similarity index 100% rename from docs/reports/unused_code_audit.md rename to docs/reports/archive/unused_code_audit.md