From 192920e6bdda8304b0436223566f9cf5fd64f94e Mon Sep 17 00:00:00 2001 From: Louis Varin Date: Thu, 3 Sep 2026 23:51:24 +0000 Subject: [PATCH] ci: add zizmor lint workflow for public repositories Add the ruleset-required zizmor workflow that enforces the public-repository action-pinning policy: it checks out the repository a targeted pull request was opened against and runs zizmor with the policy inlined in the workflow, mirroring the org-wide lint workflow. The standalone .github/zizmor.yml is removed now that the policy lives in the workflow. Ticket: INF-3420 Session-Id: 217d73a9-ac3c-466a-9cd9-112324f86e76 Task-Id: bfb9a42e-a4b1-49e6-a6e5-6f8d9d3d3051 --- .github/workflows/lint-gha.yaml | 205 ++++++++++++++++++++++++++++++++ .github/zizmor.yml | 136 --------------------- 2 files changed, 205 insertions(+), 136 deletions(-) create mode 100644 .github/workflows/lint-gha.yaml delete mode 100644 .github/zizmor.yml diff --git a/.github/workflows/lint-gha.yaml b/.github/workflows/lint-gha.yaml new file mode 100644 index 0000000000..3fc2a02abc --- /dev/null +++ b/.github/workflows/lint-gha.yaml @@ -0,0 +1,205 @@ +name: Lint GitHub Actions Files + +# This workflow is required to pass org-wide for public repositories +# via a GitHub organization ruleset "required_workflows" rule. GitHub +# runs it against pull requests opened in the repositories the ruleset +# targets, checking out and scanning THAT repository's workflows, not +# BitGoJS's own. +# +# Required workflows only support these events; see +# https://docs.github.com/en/enterprise-cloud@latest/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets#require-workflows-to-pass-before-merging +on: + pull_request: + merge_group: + +permissions: + contents: read + +jobs: + zizmor: + name: Run Zizmor + runs-on: ${{ vars.BUILD_SYSTEM_MEDIUM_RUNNER || 'ubuntu-latest' }} + timeout-minutes: 10 + permissions: + contents: read + steps: + # Checks out the CALLING repo (the one the PR was opened against), + # not BitGoJS -- this is standard ruleset-required-workflow + # behavior: github.repository/actions/checkout resolve to the + # target repo's PR head, exactly as if this workflow were defined + # directly in that repo. + - name: Checkout target repository + uses: actions/checkout@v7 + + # zizmor's default config discovery only looks in the repo it's + # scanning (the one just checked out above), and the target + # repo's own policy, if any, is not ours. The policy is therefore + # inlined here and written to a file that --config points at. + # + # Policy: + # - GitHub-owned (actions/*, github/*) and the docker/* and + # aws-actions/* orgs are exempt from hash-pinning -- + # ref-pinning (a tag or branch) is enough; hash-pinning them + # adds SHA-churn maintenance with no security benefit. + # - The grandfathered lists came from a 2026-09-03 scan of + # every non-archived public repository in the BitGo org for + # uses: references not pinned to a full-length commit SHA + # (INF-3420). Both lists are shrink-only: remove an entry + # once every public-repository workflow that references it + # pins it to a commit SHA -- do not add new entries. + # - Everything else defaults to hash-pin ("*": hash-pin), so + # new third-party actions must be pinned to a commit SHA + # from day one. + - name: Write zizmor policy + env: + ENABLE_ALL_GHA_LINT_CHECKS: ${{ vars.ENABLE_ALL_GHA_LINT_CHECKS }} + run: | + policy="${GITHUB_WORKSPACE}/.zizmor-ci-policy.yml" + if [ "$ENABLE_ALL_GHA_LINT_CHECKS" = 'true' ]; then + disabled_dest=/dev/null + else + disabled_dest="$policy" + fi + echo "rules:" > "$policy" + cat >> "$disabled_dest" <<'DISABLED' + adhoc-packages: + disable: true + anonymous-definition: + disable: true + archived-uses: + disable: true + artipacked: + disable: true + bot-conditions: + disable: true + cache-poisoning: + disable: true + concurrency-limits: + disable: true + dangerous-triggers: + disable: true + dependabot-cooldown: + disable: true + dependabot-execution: + disable: true + excessive-permissions: + disable: true + forbidden-uses: + disable: true + github-app: + disable: true + github-env: + disable: true + hardcoded-container-credentials: + disable: true + impostor-commit: + disable: true + insecure-commands: + disable: true + insecure-url-scheme: + disable: true + known-vulnerable-actions: + disable: true + misfeature: + disable: true + obfuscation: + disable: true + overprovisioned-secrets: + disable: true + ref-confusion: + disable: true + ref-version-mismatch: + disable: true + secrets-inherit: + disable: true + secrets-outside-env: + disable: true + self-hosted-runner: + disable: true + self-repository: + disable: true + stale-action-refs: + disable: true + superfluous-actions: + disable: true + template-injection: + disable: true + typosquat-uses: + disable: true + undocumented-permissions: + disable: true + unpinned-images: + disable: true + unpinned-tools: + disable: true + unredacted-secrets: + disable: true + unsound-condition: + disable: true + unsound-contains: + disable: true + unsound-ternary: + disable: true + use-trusted-publishing: + disable: true + DISABLED + cat >> "$policy" <<'PINNING' + unpinned-uses: + config: + policies: + # Trusted orgs -- ref-pinning (a tag or branch) is + # enough. Mirrors the org-level policy: GitHub-owned + # (actions/*, github/*) and the docker/* and + # aws-actions/* orgs. + "actions/*": ref-pin + "github/*": ref-pin + "docker/*": ref-pin + "aws-actions/*": ref-pin + + # Grandfathered internal (BitGo-owned) actions and + # reusable workflows still referenced by a floating + # tag/branch by at least one public repository as of + # the INF-3420 scan. + "BitGo/gha-renovate-bot/*": ref-pin + "BitGo/install-github-release-binary/*": ref-pin + "BitGo/semantic-release-github-actions/*": ref-pin + + # Grandfathered external third-party actions still + # referenced by a floating tag/branch by at least one + # public repository as of the INF-3420 scan. + "actions-rs/toolchain": ref-pin + "azure/setup-helm": ref-pin + "codecov/codecov-action": ref-pin + "dtolnay/rust-toolchain": ref-pin + "helm/chart-releaser-action": ref-pin + "ilammy/msvc-dev-cmd": ref-pin + "ludeeus/action-shellcheck": ref-pin + "peter-evans/create-pull-request": ref-pin + "xresloader/upload-to-github-release": ref-pin + + # Everything else: every other action (including new + # third-party actions, subpaths of grandfathered + # third-party repos, and internal actions in repos + # not listed above) must be pinned to a full commit + # SHA. + "*": hash-pin + PINNING + + - name: Run zizmor + uses: zizmorcore/zizmor-action@70fb788f84895a7701f5643d103d587e460b5c99 # v0.6.3 + with: + config: .zizmor-ci-policy.yml + # Online audits (e.g. ref-confusion) call the GitHub API to + # inspect OTHER repos referenced by uses: clauses. The default + # github.token is only scoped to the checked-out repo, so + # those lookups fail fatally for any repo the token cannot + # read. unpinned-uses (the only audit this policy relies on) + # is fully offline-capable. + online-audits: "false" + # Advanced Security (SARIF + code scanning upload) needs a + # paid feature target repos may not have; use plain + # annotations so this works uniformly across every repository + # the ruleset targets. + advanced-security: "false" + annotations: "true" + fail-on-no-inputs: "false" diff --git a/.github/zizmor.yml b/.github/zizmor.yml deleted file mode 100644 index 12443a82fe..0000000000 --- a/.github/zizmor.yml +++ /dev/null @@ -1,136 +0,0 @@ -# Zizmor policy for BitGo's public repositories (INF-3420). -# -# The org-level action-pinning required workflow cannot run against -# public repositories: GitHub does not allow required workflows from a -# private repository to run in public ones. This is its -# public-repository counterpart, stored in a public repository so that -# enforcement for public repositories can reference it. -# -# Every zizmor audit except unpinned-uses is disabled: this policy -# enforces third-party action pinning and nothing else. -# -# The grandfathered lists came from a 2026-09-03 scan of every -# non-archived public repository in the BitGo org for `uses:` -# references not pinned to a full-length commit SHA (INF-3420). Both -# lists are shrink-only: remove an entry once every public-repository -# workflow that references it pins it to a commit SHA -- do not add -# new entries. -rules: - adhoc-packages: - disable: true - anonymous-definition: - disable: true - archived-uses: - disable: true - artipacked: - disable: true - bot-conditions: - disable: true - cache-poisoning: - disable: true - concurrency-limits: - disable: true - dangerous-triggers: - disable: true - dependabot-cooldown: - disable: true - dependabot-execution: - disable: true - excessive-permissions: - disable: true - forbidden-uses: - disable: true - github-app: - disable: true - github-env: - disable: true - hardcoded-container-credentials: - disable: true - impostor-commit: - disable: true - insecure-commands: - disable: true - insecure-url-scheme: - disable: true - known-vulnerable-actions: - disable: true - misfeature: - disable: true - obfuscation: - disable: true - overprovisioned-secrets: - disable: true - ref-confusion: - disable: true - ref-version-mismatch: - disable: true - secrets-inherit: - disable: true - secrets-outside-env: - disable: true - self-hosted-runner: - disable: true - self-repository: - disable: true - stale-action-refs: - disable: true - superfluous-actions: - disable: true - template-injection: - disable: true - typosquat-uses: - disable: true - undocumented-permissions: - disable: true - unpinned-images: - disable: true - unpinned-tools: - disable: true - unredacted-secrets: - disable: true - unsound-condition: - disable: true - unsound-contains: - disable: true - unsound-ternary: - disable: true - use-trusted-publishing: - disable: true - unpinned-uses: - config: - policies: - # Trusted orgs -- ref-pinning (a tag or branch) is enough. - # Mirrors the org-level policy: GitHub-owned (actions/*, - # github/*) and the docker/* and aws-actions/* orgs. These orgs - # are trusted enough that hash-pinning them adds SHA-churn - # maintenance with no security benefit. - "actions/*": ref-pin - "github/*": ref-pin - "docker/*": ref-pin - "aws-actions/*": ref-pin - - # Grandfathered internal (BitGo-owned) actions and reusable - # workflows still referenced by a floating tag/branch by at - # least one public repository as of the INF-3420 scan. - "BitGo/gha-renovate-bot/*": ref-pin - "BitGo/install-github-release-binary/*": ref-pin - "BitGo/semantic-release-github-actions/*": ref-pin - - # Grandfathered external third-party actions still referenced by - # a floating tag/branch by at least one public repository as of - # the INF-3420 scan. - "actions-rs/toolchain": ref-pin - "azure/setup-helm": ref-pin - "codecov/codecov-action": ref-pin - "dtolnay/rust-toolchain": ref-pin - "helm/chart-releaser-action": ref-pin - "ilammy/msvc-dev-cmd": ref-pin - "ludeeus/action-shellcheck": ref-pin - "peter-evans/create-pull-request": ref-pin - "xresloader/upload-to-github-release": ref-pin - - # Everything else: every other action (including new third-party - # actions, subpaths of grandfathered third-party repos, and - # internal actions in repos not listed above) must be pinned to - # a full commit SHA. - "*": hash-pin