diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a7b7fe..ff19944 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,11 @@ jobs: contents: read checks: write steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -40,6 +45,11 @@ jobs: contents: read security-events: write steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -57,6 +67,11 @@ jobs: actions: read security-events: write steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -76,6 +91,11 @@ jobs: contents: read pull-requests: write steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -93,6 +113,11 @@ jobs: permissions: contents: read steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -109,6 +134,11 @@ jobs: permissions: contents: read steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false diff --git a/README.md b/README.md index 4187361..fa86d16 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,111 @@ steps: The action will fail the job if `terramate generate` produces uncommitted output, ensuring generated files are always in sync with the source of truth. +## Consuming repo CI setup + +Public and private repos use different subsets of these actions. The key differences are `harden-runner` (sends egress telemetry to StepSecurity — omit on private repos) and `scorecard` (requires public visibility to produce meaningful scores). + +### Public repo + +```yaml +name: CI +on: + push: + branches: [main] + pull_request: + schedule: + - cron: '0 6 * * 1' +permissions: + contents: read +jobs: + actionlint: + runs-on: ubuntu-latest + permissions: { contents: read, checks: write } + steps: + - uses: step-security/harden-runner@ + with: { egress-policy: audit } + - uses: actions/checkout@ + with: { persist-credentials: false } + - uses: sparkgeo/github-actions/.github/actions/github-actionlint@ + + zizmor: + runs-on: ubuntu-latest + permissions: { contents: read, security-events: write } + steps: + - uses: step-security/harden-runner@ + with: { egress-policy: audit } + - uses: actions/checkout@ + with: { persist-credentials: false } + - uses: sparkgeo/github-actions/.github/actions/zizmor@ + + scorecard: # public repos only — checks degrade on private repos + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + permissions: { contents: read, actions: read, security-events: write } + steps: + - uses: step-security/harden-runner@ + with: { egress-policy: audit } + - uses: actions/checkout@ + with: { persist-credentials: false } + - uses: sparkgeo/github-actions/.github/actions/scorecard@ + + dependency-review: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + permissions: { contents: read, pull-requests: write } + steps: + - uses: step-security/harden-runner@ + with: { egress-policy: audit } + - uses: actions/checkout@ + with: { persist-credentials: false } + - uses: sparkgeo/github-actions/.github/actions/dependency-review@ +``` + +### Private repo + +Same structure — drop `harden-runner` from every job and drop the `scorecard` job entirely: + +```yaml +name: CI +on: + push: + branches: [main] + pull_request: +permissions: + contents: read +jobs: + actionlint: + runs-on: ubuntu-latest + permissions: { contents: read, checks: write } + steps: + # harden-runner omitted — sends egress telemetry to StepSecurity (third party) + - uses: actions/checkout@ + with: { persist-credentials: false } + - uses: sparkgeo/github-actions/.github/actions/github-actionlint@ + + zizmor: + runs-on: ubuntu-latest + permissions: { contents: read, security-events: write } + # security-events: write requires GitHub Advanced Security on private repos + steps: + - uses: actions/checkout@ + with: { persist-credentials: false } + - uses: sparkgeo/github-actions/.github/actions/zizmor@ + + # scorecard omitted — most checks require public repo visibility + + dependency-review: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + permissions: { contents: read, pull-requests: write } + steps: + - uses: actions/checkout@ + with: { persist-credentials: false } + - uses: sparkgeo/github-actions/.github/actions/dependency-review@ +``` + +See [docs/approved-actions.md](docs/approved-actions.md) for full data handling and telemetry details. + ## Security This repo is part of the Sparkgeo GitHub Actions security programme. The pillars are: diff --git a/docs/approved-actions.md b/docs/approved-actions.md index a2f35a1..9cdd21e 100644 --- a/docs/approved-actions.md +++ b/docs/approved-actions.md @@ -25,6 +25,41 @@ This is enforced at: **Org Settings → Actions → General → Allow selected a | `zizmorcore/zizmor-action` | zizmorcore | `5f14fd08` (v0.5.6) | `zizmor` | Zizmor static security analysis; uploads SARIF | 2026-05-21 | | `opentofu/setup-opentofu` | OpenTofu | `847eaa4a` (v2.0.1) | `terramate-opentofu-setup` | Install OpenTofu CLI | 2026-05-21 | | `terramate-io/terramate-action` | Terramate | `c5a13758` (v3.0.0) | `terramate-opentofu-setup` | Install Terramate CLI | 2026-05-21 | +| `step-security/harden-runner` | StepSecurity | `9af89fc7` (v2.19.4) | `ci.yml` (all jobs) | Runner egress monitor — audits outbound network calls; baseline for enforce mode | 2026-06-01 | + +## Data handling and third-party telemetry + +### step-security/harden-runner + +`harden-runner` sends network egress telemetry to StepSecurity's platform (app.stepsecurity.io). This is the mechanism that powers the dashboard — it is not a side effect. + +**Data sent to StepSecurity:** +- Repository name and organisation +- Workflow run ID, job name, step name +- Outbound connection metadata: destination hostname/IP, port, process name, timestamp + +**Data NOT sent:** secrets, environment variables, source code, file contents. + +**Implications by repo visibility:** + +| Repo type | Risk | Recommendation | +|---|---|---| +| Public | Low — repo name/structure already public | Acceptable; use `egress-policy: audit` to build endpoint allowlist | +| Private | Medium — org name + CI topology exposed to StepSecurity | Review [StepSecurity privacy policy](https://www.stepsecurity.io/privacy) and data processing terms before adopting; if org policy prohibits third-party CI telemetry, omit this action | + +There is no mode that suppresses telemetry while keeping the dashboard — if data leaving GitHub is unacceptable, remove `harden-runner` entirely and enforce egress via network-level controls instead. + +### Decision: private repo usage + +For private repos, the recommendation is to **omit `harden-runner` entirely** from consuming workflows. There is no configuration option that suppresses telemetry while keeping monitoring — the two are inseparable. + +Alternatives for private repos that need egress control: + +- **GitHub Enterprise Cloud (GHEC) Actions network configurations** — network-layer egress control; data stays within GitHub/Azure infrastructure; requires a GHEC subscription (approximately $21/user/month). +- **Self-hosted runners with firewall rules** — egress data stays in your own infrastructure; trades StepSecurity dependency for additional ops overhead managing the runner fleet. +- **StepSecurity Enterprise (self-hosted backend)** — licensed product where the runner agent connects to your own server rather than app.stepsecurity.io; eliminates third-party data sharing but requires procuring and operating the backend. + +For static pre-run security analysis on private repos, **zizmor + actionlint** (already included in this repo) provide workflow security coverage without any outbound egress, and should be considered sufficient for the static analysis layer. ## Security review criteria @@ -54,7 +89,7 @@ Before approving a new action, verify all of the following: "github_owned_allowed": true, "verified_allowed": false, "patterns_allowed": [ - "ossf/*", "reviewdog/*", "zizmorcore/*", "opentofu/*", "terramate-io/*", + "ossf/*", "reviewdog/*", "zizmorcore/*", "opentofu/*", "terramate-io/*", "step-security/*", "/*" ] } @@ -74,6 +109,7 @@ reviewdog/* zizmorcore/* opentofu/* terramate-io/* +step-security/* ``` GitHub-owned actions (`actions/*`, `github/*`) are covered by `github_owned_allowed: true` and do not need explicit patterns.