|
| 1 | +# GitHub Actions Workflow Audit |
| 2 | + |
| 3 | +## Inventory |
| 4 | +| Workflow | Triggers | Jobs | Cache (actions/cache) | Explicit permissions | |
| 5 | +| --- | --- | ---: | :---: | :---: | |
| 6 | +| actionlint.yml | push, pull_request, workflow_dispatch | 1 | No | Yes | |
| 7 | +| agents-ci.yml | push, pull_request, workflow_dispatch | 7 | No | No | |
| 8 | +| backend-ci.yml | push, pull_request | 6 | Yes | No | |
| 9 | +| code-quality.yml | pull_request, workflow_dispatch | 1 | No | No | |
| 10 | +| codeql.yml | push, pull_request, schedule | 1 | No | No | |
| 11 | +| dependency-review.yml | pull_request | 1 | No | No | |
| 12 | +| deploy.yml | push, workflow_dispatch | 7 | No | No | |
| 13 | +| docs-validation.yml | pull_request, push | 6 | No | No | |
| 14 | +| docs.yml | push, pull_request, workflow_dispatch | 3 | No | Yes | |
| 15 | +| emoji-validation.yml | pull_request, push | 1 | No | No | |
| 16 | +| frontend-ci.yml | push, pull_request | 8 | No | No | |
| 17 | +| incident-response.yml | workflow_dispatch | 5 | No | No | |
| 18 | +| infrastructure-ci.yml | push, pull_request | 7 | No | No | |
| 19 | +| lint.yml | pull_request, push | 1 | No | No | |
| 20 | +| meta-architecture-check.yml | pull_request, push, workflow_dispatch | 2 | No | No | |
| 21 | +| migrations.yml | pull_request, push | 5 | No | No | |
| 22 | +| pr-review.yml | issue_comment | 1 | No | Yes | |
| 23 | +| python_ci.yml | push, pull_request, workflow_dispatch | 5 | No | No | |
| 24 | +| release.yml | push, workflow_dispatch | 7 | No | Yes | |
| 25 | +| requirements_index.yml | push, pull_request, workflow_dispatch | 1 | No | Yes | |
| 26 | +| requirements_validate_traceability.yml | pull_request, push, workflow_dispatch | 1 | No | No | |
| 27 | +| security-scan.yml | push, pull_request, schedule | 11 | No | No | |
| 28 | +| sync-docs.yml | schedule, workflow_dispatch | 2 | No | No | |
| 29 | +| test-pyramid.yml | push, pull_request, schedule | 3 | No | No | |
| 30 | +| validate-guides.yml | pull_request, push, workflow_dispatch | 5 | No | No | |
| 31 | + |
| 32 | +## Quick findings |
| 33 | +- Total workflows: 25. |
| 34 | +- Workflows with `workflow_dispatch`: 13/25. |
| 35 | +- Missing `workflow_dispatch`: backend-ci.yml, codeql.yml, dependency-review.yml, docs-validation.yml, emoji-validation.yml, frontend-ci.yml, infrastructure-ci.yml, lint.yml, migrations.yml, pr-review.yml, security-scan.yml, test-pyramid.yml |
| 36 | +- Missing `push` trigger: code-quality.yml, dependency-review.yml, incident-response.yml, pr-review.yml, sync-docs.yml |
| 37 | +- Missing `pull_request` trigger: deploy.yml, incident-response.yml, pr-review.yml, release.yml, sync-docs.yml |
| 38 | +- Lacking explicit top-level `permissions`: agents-ci.yml, backend-ci.yml, code-quality.yml, codeql.yml, dependency-review.yml, deploy.yml, docs-validation.yml, emoji-validation.yml, frontend-ci.yml, incident-response.yml, infrastructure-ci.yml, lint.yml, meta-architecture-check.yml, migrations.yml, python_ci.yml, requirements_validate_traceability.yml, security-scan.yml, sync-docs.yml, test-pyramid.yml, validate-guides.yml |
| 39 | +- Workflows without `actions/cache`: actionlint.yml, agents-ci.yml, code-quality.yml, codeql.yml, dependency-review.yml, deploy.yml, docs-validation.yml, docs.yml, emoji-validation.yml, frontend-ci.yml, incident-response.yml, infrastructure-ci.yml, lint.yml, meta-architecture-check.yml, migrations.yml, pr-review.yml, python_ci.yml, release.yml, requirements_index.yml, requirements_validate_traceability.yml, security-scan.yml, sync-docs.yml, test-pyramid.yml, validate-guides.yml |
| 40 | + |
| 41 | +## Recommendations |
| 42 | +- Add `workflow_dispatch` to workflows that currently only run on PR/push to enable manual runs during incidents or hotfix validation. |
| 43 | +- Define explicit, least-privilege `permissions` blocks to avoid default write scopes (e.g., contents: read, pull-requests: write only where needed). |
| 44 | +- Introduce dependency caching where missing (pip, npm, etc.) to speed up jobs; most workflows reinstall dependencies from scratch. |
| 45 | +- Expand test matrices for Python/Node where appropriate (e.g., backend/agents run single Python 3.11, frontend fixed to Node 18). |
| 46 | +- Consider a lightweight security gate (e.g., Semgrep or Trivy) on push to main/develop to complement existing CodeQL and security scans. |
| 47 | +- Add concurrency keys to long-running workflows (deploy, incident-response) to prevent overlapping runs per ref/environment. |
| 48 | + |
| 49 | +## Per-workflow issues and gaps |
| 50 | +- **actionlint.yml**: Uses explicit permissions and manual trigger is present, but there is no caching and the Docker action is not pinned to a digest. |
| 51 | +- **agents-ci.yml**: Lacks an explicit permissions block, requires `CODECOV_TOKEN` to run coverage uploads, and the Bandit step ignores findings by design (`|| true`). |
| 52 | +- **backend-ci.yml**: Missing `workflow_dispatch`; no permissions block; database service uses default MySQL root credentials and exposes 3306. |
| 53 | +- **code-quality.yml**: Only runs on `pull_request` and `workflow_dispatch` is absent; no explicit permissions; no dependency caching. |
| 54 | +- **codeql.yml**: Lacks `workflow_dispatch`; permissions not explicitly narrowed for code scanning upload; no cache for Python setup. |
| 55 | +- **dependency-review.yml**: Only trigger is `pull_request`; no manual trigger; permissions block present but default read/write not narrowed to minimal contents/read. |
| 56 | +- **deploy.yml**: Does not run on `pull_request`; no permissions block; re-runs full test suite without caching, slowing deployments. |
| 57 | +- **docs-validation.yml**: Missing `workflow_dispatch` and explicit permissions; no caching for Python or Sphinx deps. |
| 58 | +- **docs.yml**: Triggers are complete and permissions are explicit, but there is no dependency cache and no concurrency control for doc publishes. |
| 59 | +- **emoji-validation.yml**: Missing manual trigger; no permissions block; re-installs dependencies every run. |
| 60 | +- **frontend-ci.yml**: Missing `workflow_dispatch`; no permissions block; npm/node dependencies are not cached and only Node 18 is covered. |
| 61 | +- **incident-response.yml**: Manual-only trigger with no `push`/`pull_request`; lacking permissions block and dependency caching. |
| 62 | +- **infrastructure-ci.yml**: Missing `workflow_dispatch` and permissions block; Terraform steps lack a backend/cache and may need environment protection. |
| 63 | +- **lint.yml**: Missing `workflow_dispatch` and permissions block; no caching for lint dependencies. |
| 64 | +- **meta-architecture-check.yml**: Triggers present, but no permissions block and no dependency caching. |
| 65 | +- **migrations.yml**: Missing `workflow_dispatch`; no permissions block; seeds data with inline secrets (`testpass`) and exposes MySQL port 3306. |
| 66 | +- **pr-review.yml**: Triggered only by `issue_comment` with no `push`/`pull_request`; permissions are constrained but there is no validation to limit to PR comments; no caching. |
| 67 | +- **python_ci.yml**: Triggers present but lacks permissions block; no cache for Python dependencies and no concurrency control. |
| 68 | +- **release.yml**: No `pull_request` trigger; permissions rely on defaults; reuses build artifacts without checksum verification. |
| 69 | +- **requirements_index.yml**: Triggers present and permissions explicit, but there is no cache and the Python job runs only on a single version. |
| 70 | +- **requirements_validate_traceability.yml**: Triggers present but no permissions block; no dependency caching. |
| 71 | +- **security-scan.yml**: Missing `workflow_dispatch` and permissions block; no caching and uses broad third-party actions without digests. |
| 72 | +- **sync-docs.yml**: Missing `push`/`pull_request` triggers; no permissions block; relies on PAT/SSH secrets without validation and lacks caching. |
| 73 | +- **test-pyramid.yml**: Missing `workflow_dispatch`; no permissions block; Python jobs reuse `pip install` without cache and matrix lacks latest versions. |
| 74 | +- **validate-guides.yml**: Triggers are complete, but permissions are not explicit and there is no dependency caching. |
0 commit comments