Skip to content

feat: add contributor CI workflow for fork-friendly testing#192

Open
abtreece wants to merge 9 commits into
fullstaq-ruby:mainfrom
abtreece:feat/contributor-ci
Open

feat: add contributor CI workflow for fork-friendly testing#192
abtreece wants to merge 9 commits into
fullstaq-ruby:mainfrom
abtreece:feat/contributor-ci

Conversation

@abtreece
Copy link
Copy Markdown
Collaborator

Summary

Adds a credentialless CI workflow that runs on contributor forks and PRs, enabling third-party contributors to validate their changes without access to project infrastructure.

  • Contributor CI workflow (ci-cd-contributor): Builds Ruby packages for two representative distributions (Ubuntu 24.04 and EL 9) with applicable variants and runs smoke tests. No cloud credentials or special setup needed.
  • ok-to-test label gate: Maintainers can add the ok-to-test label to trigger the full CI pipeline (all distros, test publishing) against a PR. A label guard workflow automatically removes the label when new commits are pushed, requiring re-review before re-triggering.
  • Main workflow restriction: The main CI/CD workflow now checks github.repository to avoid running on forks.
  • Variant exclusion support: Contributor workflow respects variant_exclusions from config.yml (e.g., skips malloctrim for Ruby >= 3.3).
  • Test script fixes: createrepocreaterepo_c in RPM test prep, added adduser package for DEB tests.
  • Documentation: Updated CONTRIBUTING.md with fork CI and local build/test instructions.

Closes #54

Test plan

  • Verify contributor CI workflow runs on a fork push (no secrets required)
  • Verify ok-to-test label triggers full pipeline on PR
  • Verify label guard removes ok-to-test on new push to PR
  • Verify main CI workflow does not run on fork repositories
  • Verify generated YAML matches ERB template output (./internal-scripts/generate-ci-cd-yaml.rb)
  • Verify malloctrim variant is excluded for Ruby >= 3.3 in contributor workflow

Add a credentialless CI workflow that runs on contributor forks and PRs,
enabling third-party contributors to validate their changes without
access to project infrastructure.

- Contributor CI workflow (ci-cd-contributor) builds Ruby packages for
  two representative distributions (Ubuntu 24.04 and EL 9) with
  applicable variants and runs smoke tests
- ok-to-test label gate lets maintainers trigger the full CI pipeline;
  a label guard workflow removes the label on new pushes, requiring
  re-review before re-triggering
- Main CI/CD workflow restricted to upstream repository only
- Respects variant_exclusions from config.yml (skips malloctrim for
  Ruby >= 3.3)
- Test script fixes: createrepo -> createrepo_c, added adduser package
- Updated CONTRIBUTING.md with fork CI and local build/test docs
@abtreece abtreece force-pushed the feat/contributor-ci branch from b39e09f to c5c0ec4 Compare April 25, 2026 04:35
noahssarcastic
noahssarcastic previously approved these changes May 17, 2026
Copy link
Copy Markdown
Collaborator

@noahssarcastic noahssarcastic left a comment

Choose a reason for hiding this comment

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

Looks good, reviewed with respect to pull_request and pull_request_target and all actions are safe from "pwn request" PR's. Added a couple of nitpick type things, we may want to call out the use of pull_request and pull_request_target and other guard-rails in comment to ensure they are not accidentally removed or modified.

Comment thread lib/ci_workflow_support.rb Outdated
Comment thread lib/ci_workflow_support.rb Outdated
Comment thread .github/workflows/ci-cd-label-guard.yml
Copy link
Copy Markdown
Member

@FooBarWidget FooBarWidget left a comment

Choose a reason for hiding this comment

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

Nice work so far.

Comment thread .github/workflows/ci-cd-contributor.yml.erb Outdated
Comment thread .github/workflows/ci-cd-contributor.yml.erb Outdated
Comment thread .github/workflows/ci-cd-contributor.yml.erb Outdated
Comment thread .github/workflows/ci-cd-contributor.yml.erb
Comment thread .github/workflows/ci-cd-contributor.yml.erb Outdated
Comment thread .github/workflows/ci-cd-contributor.yml.erb
Comment on lines +56 to +57
with:
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.ref }}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't we need to do this on all jobs?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch — yes. check_workflow_uptodate had a bare actions/checkout@v4 with no ref: override, so under pull_request_target it was validating the base branch's generated YAML and silently passing regardless of what the PR changed.

Added the same ref: override AND the ok-to-test label gate used by determine_necessary_jobs, so the check now actually validates PR-head contents and only runs after a maintainer has labeled the PR (69f5211).

Audited the rest of ci-cd-main.yml.erbcheck_workflow_uptodate was the only other job using actions/checkout directly; everything else uses workflow_call and inherits behavior from the called workflows.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

everything else uses workflow_call and inherits behavior from the called workflows.

Then don't we need to update those workflows too?

abtreece added 8 commits May 22, 2026 12:52
Deduplicates the distribution entry mapping between `distributions` and
`contributor_distributions`, and fixes a memoization break where
`return [] if names.nil?` exited the method without assigning the
`||= begin` block.
Previously relied on `ruby_package_versions.first`, which in turn
depended on the order of `minor_version_packages` and
`tiny_version_packages` in `config.yml`. Use `max_by` with
`Gem::Version` so the result is deterministic regardless of config
ordering.

Considered sorting the full `ruby_package_versions` list (the broader
fix Noah suggested), but that interleaves minor/tiny entries and
produces a ~9000-line rendered-YAML diff with no functional change to
which version is "latest". Targeting `latest_ruby_package_version`
directly addresses the robustness concern with minimal blast radius.
The previous guard `event_name == 'pull_request' || repository != upstream`
fired for both fork PRs AND same-repo PRs, causing the contributor
workflow to run alongside ci-cd-main on internal branches and
duplicating every build.

Tighten the condition so the workflow only runs when either (a) it's
executing in a fork's own repo, or (b) it's executing in upstream for
a PR whose head is in a fork.
Prevents stuck runners from lingering at the default 360-minute timeout.
build_packages (60m) and test_packages (30m) already had explicit
timeouts; this adds 10m for lint and 30m for build_images.
Splits the contributor workflow's previously-monolithic build_images
and build_packages jobs into per-distro matrix jobs, and extracts
distro-agnostic packages (rbenv, common) into a separate
build_common_packages job that runs in parallel.

Also sets retention-days: 1 on all contributor artifacts -- they're
purely job-to-job intermediate state and don't need the default
90-day retention.
Pins all third-party action references in the workflows introduced by
this PR to commit SHAs, with a trailing tag comment for readability.
Mitigates supply-chain risk from mutable tag re-pointing in workflows
that run untrusted contributor code.

Also adds .github/dependabot.yml so the github-actions ecosystem
tracks SHA updates automatically.

Scope: ci-cd-contributor.yml.erb and ci-cd-label-guard.yml. Pinning
the pre-existing workflows (main, prepare, build-packages-N,
publish-test-*) is out of scope here and can land separately.
…R head

Under pull_request_target the bare actions/checkout@v4 was checking
out the base branch, so the "is the generated YAML up-to-date with
the ERB?" check silently passed regardless of what the PR changed,
making the check meaningless for fork PRs.

Add the same ref: override and ok-to-test label gate used by
determine_necessary_jobs so the check actually validates PR-head
contents, and only runs after a maintainer has labeled the PR.
…flow headers

Adds a short header comment to ci-cd-main, ci-cd-contributor, and
ci-cd-label-guard describing how the three files combine to form the
fork-PR security boundary. A future change to any single file (e.g.,
flipping pull_request_target to pull_request, removing the label
gate, renaming the ok-to-test label) silently breaks the model
otherwise.
@abtreece
Copy link
Copy Markdown
Collaborator Author

Pushed 8 commits addressing the inline feedback. Summary:

  • 1aaef3c — extract build_distribution_entries helper + fix memoization break (Noah:83)
  • 67b807c — make latest_ruby_package_version independent of YAML order via max_by (Noah:279)
  • f2897ce — skip contributor workflow for same-repo PRs (FBW)
  • 8a02f8b — add timeout-minutes to lint (10m) and build_images (30m) (FBW)
  • 00efae4 — parallelize contributor builds via matrix jobs; split off build_common_packages; retention-days: 1 on artifacts (FBW)
  • f6d6050 — pin action SHAs in contributor + label-guard workflows; add .github/dependabot.yml (FBW)
  • 69f5211 — gate check_workflow_uptodate with ok-to-test and check out PR head (FBW)
  • ddc3670 — document the pull_request / pull_request_target / label-guard security invariant in workflow headers (Noah)

Heads-up on CI: the new triggers (pull_request_target on ci-cd-main, label-guard, contributor workflow) don't exist on upstream/main yet, so they can't fire from this PR's synchronize event. The contributor workflow does run in my fork via push, exercising the matrix-parallelized pipeline for real. Full activation of the security model happens at merge.

Ready for re-review.

@FooBarWidget
Copy link
Copy Markdown
Member

All right, there's just one open comment left.

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.

Allow third-party pull requests to use the CI system

3 participants