Skip to content

ci: zero-trust GitHub Actions CI/CD template - #1

Open
VibeCodingLabs wants to merge 1 commit into
mainfrom
ci/secure-cicd-template
Open

ci: zero-trust GitHub Actions CI/CD template#1
VibeCodingLabs wants to merge 1 commit into
mainfrom
ci/secure-cicd-template

Conversation

@VibeCodingLabs

Copy link
Copy Markdown
Owner

What

Adds a complete zero-trust CI/CD stack for tailscale-guard:

File Role
.github/workflows/ci.yml Caller — delegates to reusable workflows, enforces required-checks gate.
.github/workflows/_build.yml Reusable: lint (ruff + golangci-lint), typecheck (mypy), matrix tests (3 OS × 3 Py × 2 Go), coverage.
.github/workflows/_security.yml Reusable: CodeQL (extended+quality), gitleaks, Trivy fs, Syft SBOM (signed attestation), actionlint, zizmor.
.github/workflows/deploy.yml OIDC to AWS/GCP/Azure + Tailscale Workload Identity Federation — no long-lived secrets.
.github/workflows/release.yml Tag-triggered: GHCR push, cosign keyless signing, SLSA provenance, GitHub Release.
.github/workflows/scheduled-security.yml Nightly deep security sweep on main.
.github/actions/setup-toolchain/ Composite action for Python+Go install with caching.
.github/dependabot.yml Weekly grouped updates for actions/pip/go/docker.
.github/CODEOWNERS, SECURITY.md, PR + issue templates Governance.

Zero-trust defaults

  • permissions: read-all at workflow root; every job opts in to the narrowest write scope it needs.
  • GITHUB_TOKEN read-only (matches the repo-level setting you should flip under Settings → Actions → General).
  • Third-party actions pinned to commit SHA with a # vX.Y.Z trailing comment; first-party actions/* and github/codeql-action/* on major tag (dependabot-managed).
  • persist-credentials: false on every actions/checkout — nothing written to .git/config.
  • step-security/harden-runner on every job (egress-policy: audit); the deploy job has an explicit allowed-endpoints list you can flip to block once stable.
  • OIDC everywhere — AWS STS AssumeRoleWithWebIdentity, GCP Workload Identity Federation, Azure federated credential, and Tailscale Workload Identity Federation (no OAuth client secret needed).
  • Signed releases — cosign keyless via Sigstore + SLSA v1 provenance attestation published to the registry.
  • Concurrency — PR runs cancel on push; deploy runs never cancel in-flight.

Required one-time setup

See .github/workflows/README.md for the complete runbook. Key steps:

  1. Settings → Actions → General: flip workflow permissions to read-only, disable Actions-authored PRs.
  2. Settings → Environments: create staging and production (required reviewers on prod).
  3. Branch protection on main: require Required checks, signed commits, linear history, code owners.
  4. Cloud OIDC: uncomment the stanza you use in deploy.yml and set the repo Variables.
  5. Tailscale WIF: create a federated identity in the admin console bound to this repo's environment subject; set TS_OAUTH_CLIENT_ID + TS_AUDIENCE secrets and TS_DEPLOY_TARGET variable.
  6. Optional: add CODECOV_TOKEN secret if private.

Validation

  • actionlint 1.7.7 — passes with zero findings across all 6 workflows.
  • python -m yaml parse — OK on all YAML files.

Threat-model coverage

OWASP Top 10 CI/CD · SLSA v1.0 build L3 · NIST SSDF (SP 800-218) · MITRE ATT&CK T1195 (supply-chain compromise) · CWE-829 (inclusion from untrusted source).

- Read-only default permissions (per-job opt-in writes)
- Reusable _build.yml (OS x Python x Go matrix) and _security.yml
- OIDC-only deploy.yml (AWS/GCP/Azure stanzas + Tailscale WIF)
- Release pipeline: GHCR push, cosign keyless signing, SLSA provenance
- Nightly scheduled security sweep
- CodeQL extended+quality, gitleaks, Trivy fs, Syft SBOM, actionlint, zizmor
- step-security/harden-runner on every job, egress audit enabled
- All third-party actions pinned to immutable commit SHAs
- Dependabot weekly grouped updates (actions/pip/go/docker)
- CODEOWNERS, SECURITY.md, PR template, issue templates
- persist-credentials: false on every checkout

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4c8be2d8e5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/ci.yml
Comment on lines +53 to +57
permissions:
contents: read
security-events: write # upload SARIF to code scanning
actions: read
packages: read

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Grant attestation permissions for CI security runs

The security caller job here does not grant id-token: write or attestations: write, but _security.yml includes an SBOM attestation step (actions/attest-sbom) for non-PR events. In reusable workflows, called jobs cannot elevate token scopes beyond what the caller grants, so CI runs on push/tags will hit permission errors in the SBOM job and fail the required-check gate.

Useful? React with 👍 / 👎.

Comment on lines +44 to +47
preflight:
name: Preflight
uses: ./.github/workflows/_build.yml
permissions:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate the requested ref in deploy preflight

For workflow_dispatch, the workflow accepts a ref to deploy, but preflight only calls _build.yml with defaults and does not test that requested ref. The deploy job later checks out inputs.ref, so a manually dispatched run can deploy a commit/tag that was never validated by preflight in that same run.

Useful? React with 👍 / 👎.

persist-credentials: false
- name: actionlint
run: |
bash <(curl -fsSL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.7.7

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pin actionlint installer to an immutable source

This step executes a script fetched from .../main/... at runtime, which is a mutable branch head. That breaks reproducibility and creates a supply-chain risk because upstream changes can alter CI behavior without any change in this repository. Use a pinned tag/commit URL (or a pinned action) and verify integrity.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant