Skip to content

Harden reusable workflows and introduce v1 versioning#88

Merged
mtfishman merged 3 commits intomainfrom
mf/integration-test-fork-skip
May 1, 2026
Merged

Harden reusable workflows and introduce v1 versioning#88
mtfishman merged 3 commits intomainfrom
mf/integration-test-fork-skip

Conversation

@mtfishman
Copy link
Copy Markdown
Member

@mtfishman mtfishman commented Apr 30, 2026

Summary

Restructures the IntegrationTest, IntegrationTestRequest, and FormatCheck reusable workflows to reduce GitHub Actions trust-boundary risk, and introduces a versioning convention so callers can pin to @v1 instead of @main.

IntegrationTest

  • Matrix expansion and the aggregation gate move into the reusable. Input changes from pkg: (scalar) to pkgs: (JSON array).
  • URL-based entries are probed anonymously with git ls-remote before secrets are used. Public URLs and registered package names run normally. Private URL entries are skipped on fork pull_request events, where secrets are not in scope.
  • Skipped private URL legs upload marker artifacts. The aggregate IntegrationTest gate inspects those markers and fails when every downstream leg skipped on a fork PR, with a /integrationtest <url> instruction.
  • The caller-level pull_request_target: trigger is no longer needed for migrated repositories; callers should use pull_request:.

IntegrationTestRequest

  • Comment-body parsing moves from direct shell interpolation to an env: mapping.
  • The requested package is JSON-encoded into the new pkgs array input.
  • On a successful manual run, the workflow posts a passing IntegrationTest check run for the PR head SHA, allowing a maintainer-triggered private integration test to clear the gate.

FormatCheck

  • FormatCheck.yml is now the read-only parse phase. It runs on pull_request, checks out PR code without secrets, runs the formatter, uploads the diff and PR metadata as an artifact, and reports the branch-protection check.
  • FormatCheckComment.yml is the trusted comment phase. It runs after the parse workflow via workflow_run, downloads the artifact, and posts or updates the format-suggestion comment without checking out PR code.
  • Branch protection should require the parse-phase check (Format Check / Check Formatting); the comment workflow exists only to update the PR comment.

Hygiene Across The Rest Of The Reusables

  • Direct ${{ inputs.* }} shell interpolations were moved to env: mappings in the reusable workflows.
  • Explicit per-job permissions: blocks were added where they were missing.
  • Mutable @latest action references in this repository were removed.

Versioning

  • The README documents the vMAJOR.MINOR.PATCH release tag plus mutable vMAJOR tag convention.
  • .scripts/release.sh creates release tags locally and rewrites internal @main references in the tagged commit to a fixed SHA so tagged releases are snapshot-stable.

Breaking Change

The IntegrationTest reusable input changes from pkg: to pkgs:. Per-repo callers need to update to the new JSON-array form.

Test Plan

  • Open a canary PR against a public-matrix repo, pointing callers at this PR's head SHA. Verify the public downstream matrix runs and the aggregate IntegrationTest check passes.
  • Open a canary PR against a Tennis-using repo. Verify internal PRs can run private URL integration tests and fork PRs require /integrationtest.
  • Verify FormatCheck runs from pull_request without secrets and that FormatCheckComment posts or updates the formatting comment once the comment workflow exists on the target repository's default branch.
  • Run .scripts/release.sh v1.0.0 locally after merge and confirm it creates the expected v1.0.0 and v1 tags without pushing.

mtfishman and others added 2 commits April 30, 2026 14:50
Restructures the IntegrationTest, IntegrationTestRequest, and
FormatCheck reusable workflows to address security risks discussed
in https://discourse.julialang.org/t/reviewing-github-actions-workflows-tokens/136400,
and introduces a versioning convention so callers can pin to `@v1`
instead of `@main`.

IntegrationTest.yml: matrix expansion and aggregation gate move
inside the reusable; the input changes from a scalar `pkg` to a
JSON-array `pkgs`. A pre-leg step probes URL-based matrix entries
anonymously and skips them on fork PRs that lack authentication
(closing the pattern where PR-controlled Julia ran with
`INTEGRATIONTEST_PAT` in scope under `pull_request_target`). The
aggregate `IntegrationTest` check fails on fork-PR matrices that
all-skip on private deps, with a `/integrationtest <pkg>` hint.

IntegrationTestRequest.yml: comment-body parsing moves from shell
interpolation to an `env:` mapping; on a successful manual
`/integrationtest` run, posts a passing `IntegrationTest` check via
the GitHub Checks API so the run can clear the gate above.

FormatCheck.yml + new FormatCheckPostback.yml: split into a parse
phase (runs on `pull_request:`, no secrets, uploads diff artifact)
and a postback phase (runs on `workflow_run:`, in the trusted base
context, downloads artifact, posts/updates the format-suggestion
comment). Branch protection should require the parse phase's check.

Tests, Documentation, CompatHelper, LiterateCheck, Registrator,
FormatPullRequest: `${{ inputs.* }}` interpolations into shell
`run:` blocks moved to `env:` mappings, and explicit per-job
`permissions:` blocks added.

`julia-actions/julia-buildpkg@latest` pinned to `@v1` in
IntegrationTest.yml.

New `.scripts/release.sh` tags `vX.Y.Z` (annotated, immutable) and
maintains a `vX` mutable major tag, rewriting internal `@main`
references in the released commit so the tagged release is fully
snapshot-stable.

README: new top-level Versioning section; FormatCheck section
rewritten to document the parse + postback split.

Breaking change: the IntegrationTest workflow's input shape changes
from `pkg:` (scalar) to `pkgs:` (JSON array). Per-repo callers will
need to update to the new form and to `@v1` pinning; that work is
staged as a follow-up sweep across the ecosystem repos.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mtfishman mtfishman force-pushed the mf/integration-test-fork-skip branch 2 times, most recently from 42c1e17 to 92acc71 Compare April 30, 2026 20:14
@mtfishman mtfishman force-pushed the mf/integration-test-fork-skip branch from 92acc71 to dc36f8c Compare April 30, 2026 20:24
@mtfishman mtfishman merged commit e591939 into main May 1, 2026
1 check passed
@mtfishman mtfishman deleted the mf/integration-test-fork-skip branch May 1, 2026 00:53
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