From b77db2625e4b5ec0a1ea4eef3b5ce78737caf472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20B=C3=A4rlocher?= Date: Fri, 7 Aug 2026 19:49:05 +0200 Subject: [PATCH] feat(ci): run this repository's own workflows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every workflow here was `workflow_call`-only, so nothing verified this repository itself: the sole check on a PR came from a `pull_request:` trigger grafted onto the `ai-claude-review.yml` reusable. Mirror the layout of sbaerlocher/.github instead — dedicated self-CI workflows that invoke the local reusables through a `./` path, so the workflows consumers depend on are exercised before they ship. self-merge.yml closes a rollout gap rather than adding convenience. Tagging was manual, the newest tag was 2026-06-18, and all seven consumer repositories pin exactly that tag — so anything merged after that date sat on main unreachable. The tag now follows the day's latest merge, forward-only and serialised on a single concurrency group. Moving the trigger out of ai-claude-review.yml does not affect the claude-code-action workflow-validation guard. That guard compares every workflow file participating in a run against the default branch, not just the triggering one, so a PR touching the reusable still has its review skipped. Reporting that skip as a skip rather than a green pass is a separate change. yamllint stays off in the lint job for now — `ai-claude-review.yml` holds a 515-char `--allowedTools` line that exceeds the 500-char limit in templates/.yamllint.yml. The list is comma-separated and cannot be folded, since YAML block folding inserts a space after each newline and would corrupt the tool names. Signed-off-by: Simon Bärlocher --- .github/workflows/ai-claude-review.yml | 10 ++-- .github/workflows/self-merge.yml | 55 ++++++++++++++++++++ .github/workflows/self-pull-request.yml | 58 ++++++++++++++++++++++ .github/workflows/self-weekly-security.yml | 30 +++++++++++ CHANGELOG.md | 23 +++++++++ 5 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/self-merge.yml create mode 100644 .github/workflows/self-pull-request.yml create mode 100644 .github/workflows/self-weekly-security.yml diff --git a/.github/workflows/ai-claude-review.yml b/.github/workflows/ai-claude-review.yml index 1dce350..802f331 100644 --- a/.github/workflows/ai-claude-review.yml +++ b/.github/workflows/ai-claude-review.yml @@ -2,8 +2,6 @@ name: AI - Code Review on: - pull_request: - types: [opened, synchronize, ready_for_review, reopened] workflow_call: inputs: cancel-in-progress: @@ -27,16 +25,14 @@ on: secrets: CLAUDE_CODE_OAUTH_TOKEN: required: true - # Note: for pull_request trigger, secrets.CLAUDE_CODE_OAUTH_TOKEN resolves - # directly from the repo's secrets context — no caller needed. permissions: contents: read concurrency: - # Dual-trigger workflow: `inputs.*` is undefined on `pull_request:` and - # only populated under `workflow_call:`. Expressions below fall back to - # the original hardcoded behaviour when inputs are missing. + # `github.event.pull_request.number` is the caller's event context, so it is + # set whenever the calling workflow runs on `pull_request`; `github.run_id` + # keeps the group unique for any other calling event. group: >- claude-review-${{ github.event.pull_request.number || github.run_id }}${{ inputs.concurrency-suffix && format('-{0}', inputs.concurrency-suffix) || '' diff --git a/.github/workflows/self-merge.yml b/.github/workflows/self-merge.yml new file mode 100644 index 0000000..ff9e7a2 --- /dev/null +++ b/.github/workflows/self-merge.yml @@ -0,0 +1,55 @@ +--- +name: Merge to Main + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: write # Tag-Push + +# The tag move is read-modify-write on a single ref, so two runs must never +# overlap. Queue them instead of cancelling: a cancelled run would skip the +# tag move for a commit that is already on main. +concurrency: + group: date-tag + cancel-in-progress: false + +jobs: + date-tag: + name: Move Date Tag + # A dispatch from another branch would otherwise force the day's tag onto + # that branch, and consumer repos pin these tags. + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: true + + - name: Move date tag to this commit + run: | + set -euo pipefail + TAG=$(date -u +%Y-%m-%d) + # The tag tracks the day's latest merge, not its first. Skipping when + # the tag already existed left every merge after the first one + # unreachable by any tag until the next day's first merge. + git fetch origin --tags --quiet + # Only ever move the tag forward. Runs are serialised, but a queued + # run still checks out its own commit, so without this an older one + # finishing last would drag the tag backwards. + if OLD=$(git rev-parse -q --verify "refs/tags/$TAG^{commit}"); then + if [ "$OLD" = "$(git rev-parse HEAD)" ]; then + echo "Tag $TAG already points at HEAD, nothing to do." + exit 0 + fi + if ! git merge-base --is-ancestor "$OLD" HEAD; then + echo "Tag $TAG points at $OLD, which is not an ancestor of HEAD — leaving it alone." + exit 0 + fi + fi + git tag -f "$TAG" + git push -f origin "refs/tags/$TAG" + echo "Tag $TAG now points at $(git rev-parse --short HEAD)." diff --git a/.github/workflows/self-pull-request.yml b/.github/workflows/self-pull-request.yml new file mode 100644 index 0000000..809a3dd --- /dev/null +++ b/.github/workflows/self-pull-request.yml @@ -0,0 +1,58 @@ +--- +name: Pull Request + +on: + pull_request: + branches: [main] + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + contents: read + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + # This repository ships workflows and configuration rather than application + # code, so the gate is lint plus code scanning. Each job calls this repo's own + # reusable via a local `./` path: the workflows consumers depend on are the + # same ones exercised here, and a break shows up before it reaches them. + lint: + name: Lint + permissions: + contents: read + pull-requests: write + uses: ./.github/workflows/ci-lint.yml + with: + enable_actionlint: true + # The embedded `run:` scripts in these workflows are only checked when + # shellcheck runs alongside actionlint. + enable_shellcheck: true + # Off for now: `ai-claude-review.yml` carries a 515-char `--allowedTools` + # line that trips the 500-char limit in templates/.yamllint.yml. The list + # is comma-separated and cannot be folded — YAML block folding inserts a + # space after each newline, which would corrupt the tool names. Enable + # once that line is restructured or the template's limit is revisited. + enable_yamllint: false + + review: + name: Code Review + permissions: + contents: read + pull-requests: write + issues: read + id-token: write + uses: ./.github/workflows/ai-claude-review.yml + secrets: + CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + code-scan: + name: Code Analysis + permissions: + contents: read + security-events: write + actions: read + uses: ./.github/workflows/security-code.yml + with: + languages: '["actions"]' diff --git a/.github/workflows/self-weekly-security.yml b/.github/workflows/self-weekly-security.yml new file mode 100644 index 0000000..f2fb29f --- /dev/null +++ b/.github/workflows/self-weekly-security.yml @@ -0,0 +1,30 @@ +--- +name: Weekly Security + +on: + schedule: + - cron: '0 2 * * 1' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + +jobs: + config: + name: Config Security + permissions: + contents: read + security-events: write + actions: read + uses: ./.github/workflows/security-config.yml + + secrets: + name: Secret Scanning + permissions: + contents: read + actions: read + uses: ./.github/workflows/security-secrets.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 61e7a53..18a55c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,29 @@ This is a rolling release - changes are deployed continuously to `main`. ## 2026-08-07 +### Added + +- **self-pull-request.yml**, **self-merge.yml**, **self-weekly-security.yml**: + This repository now runs its own CI, mirroring `sbaerlocher/.github`. Until + now every workflow here was `workflow_call`-only and nothing verified the + repository itself. Each new workflow calls this repo's own reusables through + a local `./` path, so the workflows consumers depend on are exercised before + they ship. +- **self-merge.yml**: Moves the `YYYY-MM-DD` date tag to the newest commit on + `main`, forward-only and serialised via `concurrency: date-tag`. Tagging was + manual before; the newest tag was `2026-06-18`, which is exactly what the + consumer repositories pin — so fixes merged after that date never reached + them without a hand-cut tag. + +### Changed + +- **ai-claude-review.yml**: Dropped the `pull_request:` trigger; the workflow is + now `workflow_call`-only like every other reusable here, and + `self-pull-request.yml` invokes it. Note that this does not change the + `claude-code-action` workflow-validation guard: it checks every workflow file + taking part in a run against the default branch, so a PR modifying this file + still has its review skipped regardless of where the trigger lives. + ### Fixed - **workflows/security-code.yml**: Caller inputs (`paths-ignore`,