64 lines
3.8 KiB
Markdown
64 lines
3.8 KiB
Markdown
# Repository Security Settings
|
|
|
|
After creating workflow files, repository security settings should be configured. These are not optional — they are the security foundation that makes the CI pipeline trustworthy.
|
|
|
|
The project's GitHub URL can be determined from its git remote (e.g., `git remote -v`). For a project hosted at `https://github.com/{owner}/{repo}`, the relevant settings links are:
|
|
|
|
- Branch protection: `https://github.com/{owner}/{repo}/settings/branches`
|
|
- Actions permissions: `https://github.com/{owner}/{repo}/settings/actions`
|
|
- Secrets: `https://github.com/{owner}/{repo}/settings/secrets/actions`
|
|
- Environments: `https://github.com/{owner}/{repo}/settings/environments`
|
|
|
|
These links allow direct navigation to the appropriate settings page.
|
|
|
|
## Branch Protection Rules
|
|
|
|
Configure a branch protection rule for `main` (or the default branch):
|
|
|
|
1. **Require a pull request before merging** — prevents direct pushes to main
|
|
2. **Require approvals** (at least 1) — no self-merging without review
|
|
3. **Dismiss stale pull request approvals when new commits are pushed** — prevents approving then sneaking in changes
|
|
4. **Require status checks to pass before merging** — add all CI workflow job names as required checks (e.g., `Test (Go 1.24)`, `Test (Go stable)`, `Lint`)
|
|
5. **Require branches to be up to date before merging** — prevents merging stale PRs that haven't been tested against latest main
|
|
6. **Do not allow bypassing the above settings** — applies rules to admins too
|
|
|
|
## Workflow Permissions
|
|
|
|
Set the default `GITHUB_TOKEN` to **read-only** at the repository level:
|
|
|
|
1. Go to **Actions permissions** (link above)
|
|
2. Workflow permissions MUST follow least privilege. Under **Workflow permissions**, select **"Read repository contents and packages permissions"**
|
|
3. Uncheck **"Allow GitHub Actions to create and approve pull requests"** (unless auto-merge is needed — then check it only for that purpose)
|
|
|
|
This means workflows start with no write access by default. Each workflow that needs elevated permissions must explicitly declare them in its `permissions:` block. This is defense-in-depth: if a workflow is compromised, it cannot write to the repository unless explicitly granted.
|
|
|
|
## Fork Pull Request Restrictions
|
|
|
|
For public/open-source repositories:
|
|
|
|
1. In **Actions permissions** (link above), set **"Fork pull request workflows from outside collaborators"** to **"Require approval for all outside collaborators"**
|
|
2. This prevents untrusted forks from running workflows that consume your Actions minutes or access secrets
|
|
3. NEVER use `pull_request_target` with untrusted code — it runs with write access to the base repo
|
|
|
|
## Secrets and Environments
|
|
|
|
- Never put secrets in workflow files — use **Secrets** settings (link above)
|
|
- For release workflows, create a **"release" environment** with required reviewers in **Environments** (link above) to add a manual approval gate before publishing
|
|
- Rotate `CODECOV_TOKEN` and other third-party tokens periodically
|
|
|
|
## Permissions Cheat Sheet
|
|
|
|
The security implications of every permission used are documented below:
|
|
|
|
| Permission | Workflows that need it | Risk |
|
|
| --- | --- | --- |
|
|
| `contents: read` | All workflows | **Low** — read-only, default safe |
|
|
| `contents: write` | Release, auto-merge | **High** — can modify repo contents, create releases |
|
|
| `packages: write` | Docker | **High** — can push container images to GHCR |
|
|
| `pull-requests: write` | Auto-merge | **High** — can merge PRs, approve changes |
|
|
| `attestations: write` | Docker | **Medium** — can create provenance/SBOM attestations |
|
|
| `id-token: write` | Docker | **Medium** — OIDC token for signing attestations |
|
|
| `security-events: write` | Security/SAST, Docker | **Medium** — can upload SARIF to Security tab |
|
|
|
|
Always prefer the narrowest permission scope. If a workflow only needs `contents: read`, do not grant `contents: write`.
|