Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Keeps the hash-pinned action refs current. Every `uses:` in this repo is pinned
# to a commit (see .github/zizmor.yml), which is only maintainable if something
# proposes the bumps — that is this file's whole job. Without it the pins rot.
version: 2
updates:
# For the github-actions ecosystem, `/` means ".github/workflows" plus an
# action.yml in the repo root — it is not a normal directory path. This repo has
# no composite actions, so one entry covers it. `examples/` is not scanned, but
# the only ref in there is a reusable workflow at `@main`, which is deliberately
# unpinned (see .github/zizmor.yml).
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
# Wait a week before proposing a release. Auto-bumping a commit hash means
# trusting whatever was published; most compromised or yanked releases are
# found within days, so the delay costs nothing and skips that window.
cooldown:
default-days: 7
groups:
# One PR for all action bumps rather than one per action.
actions:
patterns: ["*"]
2 changes: 1 addition & 1 deletion .github/workflows/claude-docs-drift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ jobs:

- name: Generate relay token
id: app-token
uses: actions/create-github-app-token@v3
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }}
private-key: ${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }}
Expand Down
11 changes: 6 additions & 5 deletions .github/workflows/claude-pr-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ name: Triage PR with Claude
# triage_instructions: |
# <your repo's category meanings + high/medium/low risk rules, and
# optionally a reviewer-action policy — see the example caller>
# secrets: inherit
# secrets:
# ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
#
# Notes:
# * `triage_instructions` is the per-repo rubric: what each category means for
Expand All @@ -48,8 +49,8 @@ name: Triage PR with Claude
# `gh label list`. It can't write files or post comments, and the workflow
# never runs the PR's code (checkout only). Only two secrets are ever
# referenced — ANTHROPIC_API_KEY and the permissions-scoped GITHUB_TOKEN —
# and GitHub injects a secret into a step only where it's explicitly used, so
# `secrets: inherit` doesn't widen the blast radius.
# and callers pass the first one explicitly (see the usage block above), so
# nothing else in the caller's secret store is reachable from here.
# * Fork PRs are skipped (they don't get secrets). Maintainers can still run a
# fork PR through `workflow_dispatch` after a sanity look.

Expand Down Expand Up @@ -117,7 +118,7 @@ jobs:
group: claude-triage-${{ github.repository }}-${{ inputs.pr_number != '' && inputs.pr_number || github.event.pull_request.number }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
with:
fetch-depth: 1
persist-credentials: false
Expand Down Expand Up @@ -160,7 +161,7 @@ jobs:

- name: Triage PR
id: triage
uses: anthropics/claude-code-action@fefa07e9c665b7320f08c3b525980457f22f58aa # v1.0.111
uses: anthropics/claude-code-action@d40ddef4c030e508327d6e35a9c45f3368482c50 # v1.0.195
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
# Use the runner-injected GITHUB_TOKEN instead of letting the action mint
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/clickhouse-benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,18 @@ jobs:

- name: Mint token for the benchmarks repo
id: app-token
uses: actions/create-github-app-token@v3
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }}
private-key: ${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }}
owner: ${{ steps.bench.outputs.owner }}
repositories: ${{ steps.bench.outputs.name }}
# Without these the token carries every permission the app holds on the
# benchmarks repo. All it does is dispatch one workflow there:
# `actions: write` to dispatch, `contents: read` to resolve the ref.
permission-actions: write
permission-contents: read

- name: Trigger the StressHouse dispatch workflow
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/cross-repo-bug-relay.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,15 @@ jobs:

- name: Generate token for central repo
id: app-token
uses: actions/create-github-app-token@v3
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }}
private-key: ${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }}
owner: ${{ steps.parse.outputs.owner }}
repositories: ${{ steps.parse.outputs.name }}
# Without this the token carries every permission the app holds on the
# central repo. The only call it makes is one `gh issue create`.
permission-issues: write

- name: Relay
run: |
Expand Down
75 changes: 75 additions & 0 deletions .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: zizmor

# Static analysis of this repo's GitHub Actions definitions.
#
# Everything here is a reusable workflow that other repos call, so a mistake in
# one of these files becomes a mistake in every caller. These workflows also run
# an AI agent over untrusted PR content with an app token, which puts them in the
# trust boundary rather than in build glue. zizmor catches the classes that
# matter: expression interpolation into `run:` blocks, over-broad app tokens and
# `permissions:` grants, and unreviewed action refs.
#
# The gate fails on ANY finding zizmor reports. Accepted risks are listed in
# .github/zizmor.yml with a reason, so an exception is a reviewable diff rather
# than a warning nobody reads. If this job fails, either fix the workflow or add
# the exception there.

on:
# Deliberately unfiltered on pull requests, unlike the push trigger below. A
# run that `paths` skips reports no status at all, so this job could never be a
# required check: every pull request that left the workflows alone would wait
# for a status that never arrives. The audit takes about ten seconds, so it is
# cheaper to run it every time than to keep a filter and a skip shim in sync.
pull_request:
push:
branches: [main]
paths:
- ".github/workflows/**"
- ".github/actions/**"
- ".github/zizmor.yml"
# zizmor audits the Dependabot config too (cooldown windows, ecosystems),
# so a change to it has to re-run the gate.
- ".github/dependabot.yml"
- "examples/**"
workflow_dispatch:

permissions: {}

jobs:
zizmor:
name: Audit Actions setup
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
with:
persist-credentials: false

- name: Run zizmor
# `pipx` is preinstalled on the GitHub-hosted Ubuntu images, so there is
# no setup action to trust here.
#
# The version is pinned: with a fail-on-anything gate, an unpinned
# zizmor would let a new release add audits that break unrelated PRs.
# Bump it deliberately, and fix or record whatever the new version finds
# in the same PR.
#
# The examples are matched as files, not as a directory: zizmor collects
# directories by convention and only looks in `.github`. They are audited
# because client repos copy them, so a permissions or interpolation
# mistake there propagates. The glob keeps new examples covered without
# anyone remembering to add them.
#
# Default `regular` persona. `--persona=pedantic` also reports style
# findings (missing concurrency limits, uncommented `permissions:`) that
# are not security properties and would make the gate noisy.
#
# GH_TOKEN enables the online audits, which check action refs against
# GitHub advisories and confirm the refs still exist. Those need the API,
# and they are the reason a workflow-touching PR can start failing for a
# newly published advisory — that is the intent.
run: pipx run zizmor==1.29.0 --no-progress .github/ examples/*.yml
env:
GH_TOKEN: ${{ github.token }}
24 changes: 24 additions & 0 deletions .github/zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# zizmor configuration — https://docs.zizmor.sh/configuration/
#
# The CI gate (.github/workflows/zizmor.yml) fails on ANY finding zizmor still
# reports. So this file is the complete list of accepted risks in this repo's
# Actions setup, and each entry must say why. Fix the workflow first; add an
# entry here only when the finding is wrong or the risk is understood and taken.
#
# There is no `unpinned-uses` policy block on purpose: zizmor's default blanket
# policy already requires a full commit hash, and every `uses:` in this repo is
# pinned that way. .github/dependabot.yml proposes the bumps weekly so the pins
# stay current — the two files are a pair, and dropping either one leaves you
# with refs that are stale or unpinned.

rules:
unpinned-uses:
ignore:
# Callers are told to reference these reusable workflows at `@main` — that
# is the point of publishing them here, and pinning callers to a commit
# would mean every client repo needs a bump for every fix. The example
# callers are audited anyway so that a `run:` block or permissions mistake
# in one cannot be copied into seven repos unnoticed. Add a line here when
# you add an example caller.
- caller-claude-pr-triage.yml
- caller-claude-docs-drift.yml
17 changes: 15 additions & 2 deletions examples/caller-claude-pr-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# `.claude/skills/triage-pr/SKILL.md`).
#
# Requirements in the caller repo:
# * Secret `ANTHROPIC_API_KEY`, reachable via `secrets: inherit`.
# * Secret `ANTHROPIC_API_KEY`, passed through explicitly (see the bottom).
# * Labels using the `triage:*` and `risk:*` prefixes will be created/applied.

name: Triage PR with Claude
Expand All @@ -23,6 +23,15 @@ on:

jobs:
triage:
# Required, not optional. A called workflow can only narrow the permissions
# its caller grants, never widen them — so if you leave this out, the job
# runs on your repo's default token and triage fails to apply labels or post
# its comment whenever that default is read-only. These three are exactly
# what claude-pr-triage.yml declares; do not add to them.
permissions:
contents: read
pull-requests: write # labels + the sticky results comment
issues: read # lets Claude read an issue the PR links to
uses: ClickHouse/integrations-shared-workflows/.github/workflows/claude-pr-triage.yml@main
with:
# pull_request runs read the PR from the event; only workflow_dispatch
Expand Down Expand Up @@ -74,4 +83,8 @@ jobs:
- low — AI review only; eligible for auto-merge per repo policy.
- medium — at least one human reviewer.
- high — PR body must include an architectural description before review.
secrets: inherit
# Passed explicitly rather than with `secrets: inherit`. This is the only
# secret the reusable workflow declares, so naming it keeps the rest of this
# repo's secret store out of reach of a workflow in another repository.
secrets:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}