Files
Charon/docs/plans/current_spec.md
GitHub Actions 3590553519 chore(ci): comprehensive CI/CD audit fixes per best practices
Implements all 13 fixes identified in the CI/CD audit against
github-actions-ci-cd-best-practices.instructions.md

Critical fixes:

Remove hardcoded encryption key from playwright.yml (security)
Fix artifact filename mismatch in supply-chain-pr.yml (bug)
Pin GoReleaser to ~> v2.5 instead of latest (supply chain)
High priority fixes:

Upgrade CodeQL action from v3 to v4 in supply-chain-pr.yml
Add environment protection for release workflow
Fix shell variable escaping ($$ → $) in release-goreleaser.yml
Medium priority fixes:

Add timeout-minutes to playwright.yml (20 min)
Add explicit permissions to quality-checks.yml
Add timeout-minutes to codecov-upload.yml jobs (15 min)
Fix benchmark.yml permissions (workflow-level read, job-level write)
Low priority fixes:

Add timeout-minutes to docs.yml jobs (10/5 min)
Add permissions block to docker-lint.yml
Add timeout-minutes to renovate.yml (30 min)
2026-01-15 15:25:58 +00:00

755 lines
28 KiB
Markdown

# CI/CD Workflow Audit Report
**Date:** January 15, 2026
**Auditor:** Planning Agent + Supervisor Review
**Repository:** Charon
**Standard:** GitHub Actions CI/CD Best Practices (`.github/instructions/github-actions-ci-cd-best-practices.instructions.md`)
---
## 1. Executive Summary
### Overall Health Score: **78/100** ⭐⭐⭐⭐ (Revised after Supervisor Review)
| Category | Score | Status | Change |
|----------|-------|--------|--------|
| Security | 75/100 | ⚠️ Needs Attention | ↓15 (hardcoded secret found) |
| Performance | 82/100 | ✅ Good | — |
| Structure | 85/100 | ✅ Good | ↓7 (artifact mismatch bug) |
| Testing | 80/100 | ✅ Good | ↓8 (E2E tests may fail silently) |
| Deployment | 85/100 | ✅ Good | — |
**Summary:** The Charon repository demonstrates strong CI/CD practices overall but has **critical issues identified during Supervisor review** that require immediate action:
1. **🔴 CRITICAL:** Hardcoded encryption key in `playwright.yml` (security risk)
2. **🔴 CRITICAL:** Artifact filename mismatch causing supply-chain verification to fail silently
3. **🔴 CRITICAL:** GoReleaser uses `version: latest` (supply chain risk)
4. **🟠 HIGH:** CodeQL action major version inconsistency (v3 vs v4)
5. **🟡 MEDIUM:** Shell variable escaping issues in release workflow
**Note:** The `no-cache: true` setting in `docker-build.yml` is **intentional security hardening** to prevent false-positive vulnerabilities from cached layers—this is NOT a gap.
---
## 2. Per-Workflow Analysis
### 2.1 docker-build.yml (Docker Build, Publish & Test)
**Purpose:** Main build workflow for Docker images with multi-platform support, SBOM generation, and security scanning.
#### Strengths ✅
- **Permissions:** Explicitly defined with least privilege (`contents: read`, `packages: write`, `security-events: write`, `id-token: write`, `attestations: write`)
- **Concurrency:** Properly configured with `cancel-in-progress: true`
- **Action Pinning:** All actions pinned to full SHA (excellent!)
- **SBOM Generation:** Uses `anchore/sbom-action` for supply chain security
- **SBOM Attestation:** Implements `actions/attest-sbom` for verifiable attestations
- **Security Scanning:** Trivy integration with SARIF upload
- **CVE Verification:** Custom checks for CVE-2025-68156 in Caddy and CrowdSec
- **Smart Skip Logic:** Skips builds for chore commits and Renovate bot
- **No-Cache Security:** Intentional `no-cache: true` prevents false-positive vulnerabilities from cached layers ✅
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| LOW | `actions/checkout` uses SHA but label says `v6` | 47 | Update comment to reflect actual pinned version |
| LOW | `continue-on-error: true` on CVE verification | 202, 245 | Consider making CVE checks blocking for security-critical builds |
#### Score: **94/100**
---
### 2.2 playwright.yml (Playwright E2E Tests)
**Purpose:** End-to-end testing using Playwright against PR Docker images.
#### Strengths ✅
- **Workflow Orchestration:** Properly chains from `docker-build.yml` via `workflow_run`
- **Concurrency:** Well-configured cancellation
- **Action Pinning:** All actions pinned to full SHA with version comments
- **Node.js Caching:** Uses `cache: 'npm'` in setup-node
- **Artifact Cleanup:** Proper retention policy (14 days)
- **Health Checks:** Robust health endpoint polling before tests
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| **🔴 CRITICAL** | **Hardcoded encryption key in plaintext** | 31 | **MUST move to GitHub Secrets immediately** |
| MEDIUM | Missing `timeout-minutes` on job | 23 | Add timeout to prevent hung workflows |
| LOW | Permissions not explicitly defined | - | Add explicit `permissions` block for clarity |
| LOW | Test report retention could be shorter | 139 | Consider 7 days for PR artifacts |
> **⚠️ SUPERVISOR FINDING:** Line 31 contains `CHARON_ENCRYPTION_KEY: dGVzdC1lbmNyeXB0aW9uLWtleS1mb3ItY2ktMzJieXQ=` hardcoded in the workflow file. Even if this is a "test" key, hardcoded secrets in YAML files are a security violation and set a bad precedent.
#### Score: **65/100** (↓20 due to hardcoded secret)
---
### 2.3 security-pr.yml (Security Scan for PRs)
**Purpose:** Trivy security scanning on PR Docker images.
#### Strengths ✅
- **Permissions:** Explicitly defined with appropriate scopes
- **Timeout:** Job timeout of 10 minutes configured
- **SARIF Upload:** Results uploaded to GitHub Security tab
- **Binary Extraction:** Extracts and scans the compiled binary specifically
- **Exit Code:** Fails on CRITICAL/HIGH vulnerabilities
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| LOW | Duplicate artifact checking logic | 33-77 | Consider extracting to reusable action |
| LOW | `continue-on-error: true` on SARIF upload | 115 | Should document why this is acceptable |
#### Score: **90/100**
---
### 2.4 supply-chain-pr.yml (Supply Chain Verification for PRs)
**Purpose:** SBOM generation and vulnerability scanning using Syft/Grype for PRs.
#### Strengths ✅
- **Permissions:** Comprehensive and appropriate
- **Concurrency:** Properly configured
- **PR Comments:** Provides detailed security results directly on PR
- **Vulnerability Categorization:** Counts by severity (Critical/High/Medium/Low)
- **Failure Gate:** Fails on critical vulnerabilities
- **Tool Versions:** Pinned Syft and Grype versions in environment variables
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| **🔴 CRITICAL** | **Artifact filename mismatch - looks for `pr-image.tar` but docker-build.yml saves as `charon-pr-image.tar`** | 152 | **Fix filename to match docker-build.yml output** |
| **🟠 HIGH** | **CodeQL action uses v3.28.1 while all other workflows use v4.31.10** | 177 | **Major version gap (v3→v4) - standardize immediately** |
| LOW | Sparse checkout may cause issues with some tools | 46-49 | Document why sparse checkout is sufficient |
> **⚠️ SUPERVISOR FINDING - BUG:** Line 152 expects `pr-image.tar` but `docker-build.yml` line 140 saves as `charon-pr-image.tar`. This mismatch causes supply-chain verification to fail silently for all PRs! The workflow shows "pr-image.tar not found" and exits without actual verification.
>
> **⚠️ SUPERVISOR FINDING - VERSION GAP:** Line 177 uses CodeQL action `v3.28.1` (`b56ba49b26e50535fa1e7f7db0f4f7b45bf65d80d`) while all other workflows use `v4.31.10`. This is a **major version gap** with potential SARIF schema compatibility issues.
#### Score: **70/100** (↓18 due to critical bug and version gap)
---
### 2.5 release-goreleaser.yml (Release with GoReleaser)
**Purpose:** Release automation using GoReleaser for cross-platform builds.
#### Strengths ✅
- **Concurrency:** `cancel-in-progress: false` for releases (correct!)
- **Full Checkout:** `fetch-depth: 0` for release tagging
- **Cross-Compilation:** Zig toolchain for CGO support
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| **🔴 CRITICAL** | `goreleaser-action` uses `version: latest` | 46 | **Pin to specific version for reproducible builds** |
| **🟠 HIGH** | Permissions too broad (`contents: write`, `packages: write`) | 19-20 | Consider using environment protection |
| **🟡 MEDIUM** | **Double `$$` shell escaping issue** | 38 | **Fix: `VERSION=${GITHUB_REF#refs/tags/}` (single `$`)** |
| MEDIUM | `actions/setup-node` pinned to older SHA than others | 32 | Standardize action versions |
> **⚠️ SUPERVISOR FINDING:** Line 38 has `VERSION=$${GITHUB_REF#refs/tags/}` with double `$$`. In GitHub Actions YAML, this is incorrect shell escaping. Should be single `$` for shell variable expansion.
#### Score: **70/100** (↓5 due to additional shell escaping issue)
---
### 2.6 codeql.yml (CodeQL Analysis)
**Purpose:** Static Application Security Testing (SAST) for Go and JavaScript.
#### Strengths ✅
- **Permissions:** Least privilege with job-level override
- **Matrix Strategy:** Tests both Go and JavaScript in parallel
- **Config File:** Uses custom CodeQL config for documented exclusions
- **Schedule:** Weekly scheduled scans
- **Fail on High-Severity:** Blocks merge on critical findings
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| LOW | `fail-fast: false` may slow PR feedback | 34 | Consider `fail-fast: true` for PRs, `false` for scheduled |
| LOW | Forked PR handling could be more elegant | 31 | Document security implications clearly |
#### Score: **95/100**
---
### 2.7 quality-checks.yml (Quality Checks)
**Purpose:** Backend and frontend quality checks including tests, linting, and coverage.
#### Strengths ✅
- **Path-Based Optimization:** Frontend jobs detect if frontend changed
- **Caching:** Go cache and npm cache properly configured
- **Performance Assertions:** Custom perf tests with configurable thresholds
- **Job Separation:** Clear separation between backend and frontend
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| MEDIUM | Permissions not defined | - | Add explicit `permissions: contents: read` |
| LOW | `continue-on-error: true` on golangci-lint | 58 | Consider making lint failures blocking |
| LOW | Duplicate repo health check in both jobs | 28, 73 | Consider extracting to separate job |
#### Score: **85/100**
---
### 2.8 nightly-build.yml (Nightly Build & Package)
**Purpose:** Daily automated builds with comprehensive supply chain verification.
#### Strengths ✅
- **GHA Caching:** Uses `cache-from: type=gha` for Docker builds
- **SBOM Generation:** Both inline SBOM and artifact upload
- **Smoke Tests:** Basic health check against nightly image
- **Artifact Retention:** 30 days for nightly artifacts (appropriate)
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| **HIGH** | Actions pinned to different versions than other workflows | Multiple | **Standardize action versions across all workflows** |
| MEDIUM | Hardcoded Go version `1.23` differs from env var pattern | 113 | Use environment variable like other workflows |
| MEDIUM | Hardcoded Node version `20` differs from other workflows | 118 | Use `24.12.0` for consistency |
| LOW | Health check endpoint differs (`/health` vs `/api/v1/health`) | 95 | Verify correct endpoint |
#### Score: **78/100**
---
### 2.9 benchmark.yml (Go Benchmark)
**Purpose:** Performance regression detection using Go benchmarks.
#### Strengths ✅
- **Path Filtering:** Only runs when backend changes
- **Caching:** Go cache properly configured
- **Benchmark Storage:** Uses `github-action-benchmark` for trend tracking
- **Alert Threshold:** 175% threshold accounts for CI variability
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| MEDIUM | `permissions: contents: write` on all runs | 21 | Restrict to push events only |
| LOW | `fail-on-alert: false` may miss regressions | 37 | Consider `true` for critical paths |
#### Score: **88/100**
---
### 2.10 codecov-upload.yml (Coverage Upload)
**Purpose:** Upload code coverage to Codecov for backend and frontend.
#### Strengths ✅
- **Dedicated Workflow:** Separates coverage upload from test runs
- **Push-Only:** Correctly triggers only on pushes, not PRs
- **Fail on Error:** `fail_ci_if_error: true` ensures reliability
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| LOW | Missing timeout on jobs | - | Add `timeout-minutes: 15` |
| LOW | Missing concurrency group | - | Add for consistency |
#### Score: **85/100**
---
### 2.11 supply-chain-verify.yml (Supply Chain Verification)
**Purpose:** Comprehensive supply chain verification for releases.
#### Strengths ✅
- **Comprehensive Verification:** SBOM validation, vulnerability scanning, Cosign verification
- **PR Comments:** Detailed security summaries on PRs
- **Artifact Upload:** 30-day retention for audit trails
- **Fallback Logic:** Handles Rekor unavailability gracefully
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| MEDIUM | Cosign checksum verification is commented out | 281 | Enable with correct SHA |
| LOW | `continue-on-error: true` on Grype scan | 255 | Document acceptable failure scenarios |
#### Score: **85/100**
---
### 2.12 security-weekly-rebuild.yml (Weekly Security Rebuild)
**Purpose:** Weekly fresh builds to incorporate latest security patches.
#### Strengths ✅
- **No Cache:** Forced fresh builds for security
- **Comprehensive Scanning:** Multiple Trivy output formats
- **Long Retention:** 90 days for weekly scans (audit trail)
- **Package Version Reporting:** Shows installed Alpine packages
#### Issues Found
| Severity | Issue | Line(s) | Recommendation |
|----------|-------|---------|----------------|
| LOW | `continue-on-error: true` on CRITICAL/HIGH scan | 67 | Consider failing workflow on vulnerabilities |
#### Score: **90/100**
---
### 2.13 Minor Workflows Summary
| Workflow | Score | Key Issues |
|----------|-------|------------|
| `docker-lint.yml` | 95/100 | Missing permissions block |
| `renovate.yml` | 90/100 | Consider adding timeout |
| `waf-integration.yml` | 92/100 | Well-structured with good debugging |
| `docs.yml` | 88/100 | Missing timeout on jobs |
| `repo-health.yml` | 90/100 | Good structure and artifact handling |
---
## 3. Categorized Issues (Revised with Supervisor Findings)
### 🔴 CRITICAL (Block Merge - MUST FIX BEFORE ANY MERGE)
| # | Workflow | Issue | Impact | Added By |
|---|----------|-------|--------|----------|
| 1 | `playwright.yml` | **Hardcoded encryption key** (`CHARON_ENCRYPTION_KEY`) in plaintext at line 31 | Secret exposure, security policy violation | 🔍 Supervisor |
| 2 | `supply-chain-pr.yml` | **Artifact filename mismatch** - expects `pr-image.tar` but docker-build saves as `charon-pr-image.tar` | Supply chain verification silently failing for ALL PRs | 🔍 Supervisor |
| 3 | `release-goreleaser.yml` | GoReleaser action uses `version: latest` | Non-reproducible builds, supply chain risk | Planning Agent |
### 🟠 HIGH (Requires Immediate Action)
| # | Workflow | Issue | Impact | Added By |
|---|----------|-------|--------|----------|
| 4 | `supply-chain-pr.yml` | **CodeQL action v3 vs v4** - uses `v3.28.1` while others use `v4.31.10` | Major version gap, SARIF compatibility issues | 🔍 Supervisor (upgraded) |
| 5 | `release-goreleaser.yml` | Broad permissions without environment protection | Security risk for release process | Planning Agent |
| 6 | `nightly-build.yml` | Inconsistent action versions across workflows | Maintenance burden, potential compatibility issues | Planning Agent |
### 🟡 MEDIUM (Requires Discussion)
| # | Workflow | Issue | Impact | Added By |
|---|----------|-------|--------|----------|
| 7 | `release-goreleaser.yml` | **Double `$$` shell escaping** at line 38 | Version injection failure in frontend builds | 🔍 Supervisor |
| 8 | `playwright.yml` | Missing job timeout | Potential hung workflows | Planning Agent |
| 9 | `quality-checks.yml` | Missing explicit permissions | Security best practice violation | Planning Agent |
| 10 | `benchmark.yml` | Write permissions on all events | Unnecessary privilege escalation | Planning Agent |
| 11 | `nightly-build.yml` | Hardcoded language versions | Maintenance burden | Planning Agent |
### 🟢 LOW (Suggestions)
| # | Workflow | Issue | Impact |
|---|----------|-------|--------|
| 12 | Multiple | `continue-on-error: true` without documentation | Unclear failure handling |
| 13 | Multiple | Duplicate reusable logic | Code duplication |
| 14 | Multiple | Artifact retention inconsistencies | Storage optimization |
| 15 | `codecov-upload.yml` | Missing concurrency group | Potential duplicate runs |
### ❌ REMOVED Issues (Supervisor Correction)
| # | Original Issue | Reason for Removal |
|---|----------------|-------------------|
| ~~4~~ | `docker-build.yml` - No Docker layer caching | **Intentional security hardening** - `no-cache: true` prevents false-positive vulnerabilities from cached layers |
---
## 4. Specific Remediation Recommendations
### 4.1 🔴 CRITICAL: Move Hardcoded Encryption Key to GitHub Secrets
**File:** `playwright.yml`
**Line:** 31
```yaml
# ❌ Current (SECURITY VIOLATION)
env:
CHARON_ENV: development
CHARON_DEBUG: "1"
CHARON_ENCRYPTION_KEY: dGVzdC1lbmNyeXB0aW9uLWtleS1mb3ItY2ktMzJieXQ= # HARDCODED!
# ✅ Recommended
env:
CHARON_ENV: development
CHARON_DEBUG: "1"
CHARON_ENCRYPTION_KEY: ${{ secrets.CHARON_CI_ENCRYPTION_KEY }}
```
**Setup Steps:**
1. Go to Repository Settings → Secrets and variables → Actions
2. Create new repository secret: `CHARON_CI_ENCRYPTION_KEY`
3. Set value to a proper test encryption key (32 bytes, base64 encoded)
4. Update workflow to reference the secret
---
### 4.2 🔴 CRITICAL: Fix Artifact Filename Mismatch
**File:** `supply-chain-pr.yml`
**Line:** 152
```yaml
# ❌ Current (BUG - filename mismatch)
- name: Load Docker image
if: steps.check-artifact.outputs.artifact_found == 'true'
id: load-image
run: |
if [[ ! -f "pr-image.tar" ]]; then # WRONG: expects pr-image.tar
echo "❌ pr-image.tar not found in artifact"
ls -la
exit 1
fi
# ✅ Recommended (match docker-build.yml output)
- name: Load Docker image
if: steps.check-artifact.outputs.artifact_found == 'true'
id: load-image
run: |
if [[ ! -f "charon-pr-image.tar" ]]; then # CORRECT: matches docker-build.yml
echo "❌ charon-pr-image.tar not found in artifact"
ls -la
exit 1
fi
echo "🐳 Loading Docker image..."
LOAD_OUTPUT=$(docker load -i charon-pr-image.tar) # CORRECT filename
echo "${LOAD_OUTPUT}"
```
**Root Cause:** `docker-build.yml` line 140 saves: `docker save "${IMAGE_TAG}" -o /tmp/charon-pr-image.tar`
---
### 4.3 🔴 CRITICAL: Pin GoReleaser to Specific Version
**File:** `release-goreleaser.yml`
**Line:** 46
```yaml
# ❌ Current (Insecure)
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6
with:
distribution: goreleaser
version: latest # PROBLEM: Non-reproducible
# ✅ Recommended
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6
with:
distribution: goreleaser
version: '~> v2.5' # Pin to specific major.minor
args: release --clean
```
---
### 4.4 🟠 HIGH: Upgrade CodeQL Action to v4
**File:** `supply-chain-pr.yml`
**Line:** 177
```yaml
# ❌ Current (Version mismatch - v3)
- name: Upload SARIF to GitHub Security
# github/codeql-action v3.28.1
uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d
continue-on-error: true
with:
sarif_file: grype-results.sarif
category: supply-chain-pr
# ✅ Recommended (Match other workflows - v4)
- name: Upload SARIF to GitHub Security
# github/codeql-action v4.31.10
uses: github/codeql-action/upload-sarif@cdefb33c0f6224e58673d9004f47f7cb3e328b89
continue-on-error: true
with:
sarif_file: grype-results.sarif
category: supply-chain-pr
```
---
### 4.5 🟠 HIGH: Add Environment Protection for Releases
**File:** `release-goreleaser.yml`
```yaml
# ✅ Add environment protection
jobs:
goreleaser:
runs-on: ubuntu-latest
environment:
name: release
url: https://github.com/${{ github.repository }}/releases
permissions:
contents: write
packages: write
```
Then configure environment protection rules in GitHub repository settings:
1. Go to Settings → Environments → Create "release"
2. Add required reviewers
3. Restrict to protected branches (tags matching `v*`)
---
### 4.6 🟡 MEDIUM: Fix Shell Variable Escaping
**File:** `release-goreleaser.yml`
**Line:** 38
```yaml
# ❌ Current (Double $$ escaping issue)
- name: Build Frontend
working-directory: frontend
run: |
# Inject version into frontend build from tag (if present)
VERSION=$${GITHUB_REF#refs/tags/} # WRONG: Double $$
echo "VITE_APP_VERSION=$$VERSION" >> $GITHUB_ENV # WRONG: Double $$
npm ci
npm run build
# ✅ Recommended (Single $ for shell variables)
- name: Build Frontend
working-directory: frontend
run: |
# Inject version into frontend build from tag (if present)
VERSION=${GITHUB_REF#refs/tags/} # CORRECT: Single $
echo "VITE_APP_VERSION=${VERSION}" >> $GITHUB_ENV # CORRECT: Single $
npm ci
npm run build
```
**Note:** In GitHub Actions `run:` blocks, shell variables use single `$`. Double `$$` is only needed when you want a literal `$` character in the output.
---
### 4.7 MEDIUM: Add Explicit Permissions to quality-checks.yml
**File:** `quality-checks.yml`
```yaml
name: Quality Checks
on:
push:
branches: [ main, development, 'feature/**' ]
pull_request:
branches: [ main, development ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# ADD: Explicit permissions block
permissions:
contents: read
checks: write # If you want test annotations
env:
GO_VERSION: '1.25.5'
NODE_VERSION: '24.12.0'
```
---
### 4.8 MEDIUM: Standardize Action Versions Across Workflows
Create a shared workflow or use renovate to ensure consistency:
**Recommended Standard Versions (as of audit date):**
| Action | Recommended SHA | Version |
|--------|-----------------|---------|
| `actions/checkout` | `8e8c483db84b4bee98b60c0593521ed34d9990e8` | v6 |
| `actions/setup-go` | `7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5` | v6 |
| `actions/setup-node` | `395ad3262231945c25e8478fd5baf05154b1d79f` | v6 |
| `actions/upload-artifact` | `b7c566a772e6b6bfb58ed0dc250532a479d7789f` | v6.0.0 |
| `actions/download-artifact` | `fa0a91b85d4f404e444e00e005971372dc801d16` | v4.1.8 |
| `docker/build-push-action` | `263435318d21b8e681c14492fe198d362a7d2c83` | v6 |
| `github/codeql-action/*` | `cdefb33c0f6224e58673d9004f47f7cb3e328b89` | **v4.31.10** |
| `aquasecurity/trivy-action` | `b6643a29fecd7f34b3597bc6acb0a98b03d33ff8` | 0.33.1 |
> ⚠️ **Note:** `supply-chain-pr.yml` uses CodeQL v3.28.1 - must upgrade to v4.31.10!
---
### 4.9 LOW: Add Missing Timeouts
Add to all job definitions without explicit timeouts:
```yaml
jobs:
job-name:
runs-on: ubuntu-latest
timeout-minutes: 30 # Adjust based on expected duration
```
Recommended timeouts:
- Build jobs: 30 minutes
- Test jobs: 15 minutes
- Lint jobs: 10 minutes
- Security scan jobs: 15 minutes
- Deploy jobs: 20 minutes
---
## 5. Priority-Ordered Action Items (Revised with Supervisor Findings)
### 🚨 IMMEDIATE (Block All PRs Until Fixed)
| # | Priority | Task | Workflow | Effort |
|---|----------|------|----------|--------|
| 1 | 🔴 CRITICAL | Move hardcoded encryption key to GitHub Secrets | `playwright.yml` | 15 min |
| 2 | 🔴 CRITICAL | Fix artifact filename mismatch (`pr-image.tar``charon-pr-image.tar`) | `supply-chain-pr.yml` | 10 min |
| 3 | 🔴 CRITICAL | Pin GoReleaser to specific version (`~> v2.5`) | `release-goreleaser.yml` | 5 min |
### 🔶 This Sprint (Within 1 Week)
| # | Priority | Task | Workflow | Effort |
|---|----------|------|----------|--------|
| 4 | 🟠 HIGH | Upgrade CodeQL action from v3 to v4 | `supply-chain-pr.yml` | 10 min |
| 5 | 🟠 HIGH | Add environment protection rules for releases | `release-goreleaser.yml` | 30 min |
| 6 | 🟠 HIGH | Standardize action versions in nightly builds | `nightly-build.yml` | 20 min |
### 🟡 Short-Term (Next 2 Sprints)
| # | Priority | Task | Workflow | Effort |
|---|----------|------|----------|--------|
| 7 | 🟡 MEDIUM | Fix shell variable escaping (`$$``$`) | `release-goreleaser.yml` | 5 min |
| 8 | 🟡 MEDIUM | Add explicit permissions block | `quality-checks.yml` | 10 min |
| 9 | 🟡 MEDIUM | Add job timeouts | `playwright.yml`, `codecov-upload.yml`, `docs.yml` | 15 min |
| 10 | 🟡 MEDIUM | Reduce benchmark write permissions to push only | `benchmark.yml` | 5 min |
### 🟢 Long-Term (Backlog)
| # | Priority | Task | Workflow | Effort |
|---|----------|------|----------|--------|
| 11 | 🟢 LOW | Create reusable workflow for artifact downloading | Multiple | 2 hrs |
| 12 | 🟢 LOW | Document all `continue-on-error: true` decisions | Multiple | 1 hr |
| 13 | 🟢 LOW | Standardize artifact retention periods | Multiple | 30 min |
| 14 | 🟢 LOW | Add concurrency group | `codecov-upload.yml` | 5 min |
---
## 6. Compliance Checklist (Updated)
### Security Checklist
- [x] GITHUB_TOKEN permissions explicitly defined with least privilege (most workflows)
- [ ] **⚠️ FAIL: Hardcoded secret in `playwright.yml` line 31** - MUST FIX
- [x] Secrets accessed via `secrets.<NAME>` only (except above violation)
- [x] OIDC used for attestations (`id-token: write`)
- [x] Actions pinned to full SHA (excellent coverage)
- [x] Dependency review / SCA integrated (Grype, Syft)
- [x] SAST (CodeQL) integrated
- [ ] Secret scanning enabled (verify in repo settings)
- [ ] All actions pinned consistently (needs standardization - v3/v4 gap)
### Performance Checklist
- [x] Caching implemented for Go and Node dependencies
- [x] Docker layer caching intentionally disabled for security (`no-cache: true`) ✅
- [x] Matrix strategies used (CodeQL)
- [x] Shallow clones used where appropriate
- [x] Artifacts have retention periods
### Structure Checklist
- [x] Workflows have descriptive names
- [x] Jobs have clear dependencies via `needs`
- [x] Concurrency controls prevent duplicate runs
- [x] `if` conditions used for conditional execution
- [ ] **⚠️ FAIL: Artifact filename mismatch between workflows** - MUST FIX
### Testing Checklist
- [x] Unit tests run on every push/PR
- [x] Integration tests configured (WAF integration)
- [x] E2E tests configured (Playwright)
- [x] Test results uploaded as artifacts
- [ ] **⚠️ WARN: Supply chain verification failing silently due to filename bug**
### Deployment Checklist
- [ ] Environment protection rules configured (needs improvement)
- [ ] Manual approvals for production (needs setup)
- [ ] Rollback strategy documented (partial)
---
## 7. Summary (Revised After Supervisor Review)
The Charon repository demonstrates **solid CI/CD practices** but has **critical issues** discovered during Supervisor review that require immediate attention:
### 🔴 Critical Issues Requiring Immediate Action
| # | Issue | Impact | Workflow |
|---|-------|--------|----------|
| 1 | **Hardcoded encryption key** | Security policy violation, secret exposure risk | `playwright.yml:31` |
| 2 | **Artifact filename mismatch** | Supply chain verification silently failing for ALL PRs | `supply-chain-pr.yml:152` |
| 3 | **GoReleaser `version: latest`** | Non-reproducible builds, supply chain risk | `release-goreleaser.yml:46` |
### 🟠 High Priority Issues
| # | Issue | Impact | Workflow |
|---|-------|--------|----------|
| 4 | **CodeQL v3 vs v4 gap** | Major version mismatch, SARIF compatibility issues | `supply-chain-pr.yml:177` |
| 5 | **Missing environment protection** | No safeguards for production releases | `release-goreleaser.yml` |
### ✅ Strengths Confirmed
- Comprehensive SBOM generation and attestation
- Strong action pinning to SHA (most workflows)
- Proper concurrency controls
- Good test coverage with E2E tests
- Intentional security hardening with `no-cache: true` in Docker builds
### 📊 Revised Health Score
| Category | Original | Revised | Delta |
|----------|----------|---------|-------|
| **Overall** | 87/100 | **78/100** | ↓9 |
| Security | 90/100 | 75/100 | ↓15 |
| Structure | 92/100 | 85/100 | ↓7 |
| Testing | 88/100 | 80/100 | ↓8 |
### Next Steps
1. **IMMEDIATE:** Fix critical issues #1-3 before any new PRs merge
2. **THIS WEEK:** Address high priority issues #4-5
3. **ONGOING:** Work through medium/low priority backlog
---
*Report generated by Planning Agent + Supervisor Review | Last updated: January 15, 2026*
*Supervisor findings marked with 🔍*