diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 89d8e745e2..7d401751d2 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -296,13 +296,19 @@ jobs: # Bounded retry — Release Please may still be creating the release EXISTING="" + FOUND=0 for i in $(seq 1 6); do if EXISTING=$(gh release view "$TAG" --json body -q '.body // ""' 2>/dev/null); then + FOUND=1 break fi echo "Release '$TAG' not available yet (attempt $i/6), retrying in 10s..." sleep 10 done + if [ "$FOUND" -ne 1 ]; then + echo "::error::GitHub release '$TAG' not available after 6 attempts" + exit 1 + fi IMAGES=$(cat <<'BLOCK' diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 0115af7b46..03beccd22f 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -72,7 +72,7 @@ jobs: # MkDocs output is already at _site/docs/ from the build step - name: Upload Pages artifact - uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3 + uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 with: path: _site diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000000..426fe13db1 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,32 @@ +name: Workflow Security + +on: + push: + branches: [main] + paths: + - ".github/workflows/**" + pull_request: + branches: [main] + paths: + - ".github/workflows/**" + workflow_dispatch: + +permissions: {} + +jobs: + zizmor: + name: zizmor + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + actions: read + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 + with: + advanced-security: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} diff --git a/CLAUDE.md b/CLAUDE.md index 84bfee3127..326e1a20a3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -179,6 +179,7 @@ src/ai_company/ - **Secret scanning**: gitleaks workflow on push/PR + weekly schedule - **Dependency review**: license allow-list (permissive only), PR comment summaries - **Coverage**: Codecov integration (replaces artifact-only uploads) +- **Workflow security**: `.github/workflows/zizmor.yml` — zizmor static analysis of GitHub Actions workflows on push to main and PRs (triggers only when workflow files change), SARIF upload to Security tab on push events only (fork PRs lack `security-events: write`) - **Release**: `.github/workflows/release.yml` — Release Please (Google) auto-creates a release PR on every push to main. Merging the release PR creates a git tag (`vX.Y.Z`) + GitHub Release with changelog. Tag push triggers the Docker workflow to build version-tagged images. Uses `RELEASE_PLEASE_TOKEN` secret (PAT/GitHub App token) so tag creation triggers downstream workflows (GITHUB_TOKEN cannot). Config in `.github/release-please-config.json` and `.github/.release-please-manifest.json`. ## Dependencies diff --git a/DESIGN_SPEC.md b/DESIGN_SPEC.md index bc9263d1e3..b615a69a01 100644 --- a/DESIGN_SPEC.md +++ b/DESIGN_SPEC.md @@ -3262,7 +3262,8 @@ synthorg/ │ │ ├── dependency-review.yml # License allow-list on PRs │ │ ├── release.yml # Release Please (automated versioning + GitHub Releases) │ │ ├── secret-scan.yml # Gitleaks on push/PR + weekly -│ │ └── pages.yml # Build Astro + MkDocs → deploy GitHub Pages +│ │ ├── pages.yml # Build Astro + MkDocs → deploy GitHub Pages +│ │ └── zizmor.yml # Workflow security analysis (zizmor) │ ├── actions/ │ │ └── setup-python-uv/ # Composite action: Python + uv install │ ├── dependabot.yml # uv + github-actions + docker updates