Skip to content

Feature request: opt-in reusable workflow to rebuild and commit generated files on Dependabot PRs #70

Open

Description

@brunoborges

Problem

JavaScript actions such as actions/setup-java commit generated dist/ bundles. Dependabot updates npm manifests and lockfiles but does not rebuild those bundles. The shared check-dist.yml workflow rebuilds and detects the mismatch, then uploads the expected output as an artifact, but a follow-up contribution is still needed to commit the rebuilt files before the PR can pass.

This affects multiple consumers of this repository. Examples include the failing dist checks on actions/setup-node#1639 and actions/setup-python#1364.

Proposal

Add a separate, opt-in reusable workflow that rebuilds generated files and commits them back to eligible Dependabot PR branches. Keep the existing check-dist.yml workflow read-only and unchanged so it continues to provide independent source-to-bundle validation.

The reusable workflow should require a caller-supplied personal access token (PAT) for pushing the generated commit. A push using GITHUB_TOKEN does not automatically trigger the normal pull_request workflows on the updated commit. Requiring a PAT avoids leaving required checks unrun on that commit.

Suggested interface

Input or secret Requirement Purpose
install-command input Optional; default npm ci --ignore-scripts Allow the caller to supply a custom dependency installation command.
build-command input Optional; default npm run build Allow the caller to supply a custom build command.
node-version input Optional; follow the existing shared workflow convention Select the build runtime.
dist-path input Optional; default dist Restrict which generated files may be committed.
token secret Required PAT Push the generated commit and allow normal PR checks to run. Scope it to the target repository with Contents read/write permission.

Dependency installation should default to npm ci --ignore-scripts, consistent with the existing check-dist workflow, while allowing an independent install-command override such as pnpm install --frozen-lockfile or yarn install --immutable. Callers using another package manager must ensure that tool is available in the build job. Both installation and build commands must come from the trusted caller workflow configuration, not PR titles, comments, or other untrusted event fields, and must run only in the unprivileged build job without access to the PAT.

Expected behavior

  1. Validate that the target is an open Dependabot PR with a branch in the caller repository, and capture its exact head SHA.
  2. Check out that SHA and execute install-command, followed by build-command, in a job without the PAT or repository-write credentials. An installation failure must stop the build and prevent publication.
  3. Transfer only the allowed generated output to a separate publishing job on a fresh runner. That job must not execute PR code, dependency tooling, or either caller-provided command.
  4. Validate artifact paths and file types, reject unsafe output, and stage only the configured generated directory, including additions and deletions.
  5. Verify that the PR still points to the original head SHA before publishing. Never force-push over newer work.
  6. If generated output is unchanged, finish without a commit. Otherwise commit the generated files and push with the required PAT, triggering normal PR checks.

The workflow should also handle concurrent updates and prevent rebuild loops. Its commit-message policy should preserve Dependabot's ability to refresh/rebase updates where supported.

Credential setup and documentation

Document the supported caller trigger and exactly where the PAT must be configured. Dependabot-triggered workflows have special secret restrictions; an implementation must not assume that ordinary Actions secrets are available, or that pull_request_target bypasses those restrictions. Missing credentials should fail clearly before attempting publication.

Separating build and publication into different jobs is essential: exposing the PAT only in a later step of the same job does not isolate it from code executed during the build.

Secret naming convention

Recommend DEPENDABOT_BUILD_TOKEN as the caller-side secret name, while keeping the reusable workflow's required workflow_call secret named token. Callers explicitly map their chosen secret to token; a separate secret-name input or implicit secret lookup is unnecessary. Avoid secrets: inherit, which would pass unrelated secrets as well.

For the proposed Dependabot-triggered pull_request caller below, configure the PAT as a Dependabot secret in the caller repository (or an organization Dependabot secret granted to that repository), rather than assuming an Actions secret is available. The reusable workflow must use the passed token only in the isolated publishing job, not for checkout, installation, or building in the build job.

Illustrative caller workflow

The filename and reference below are placeholders for the proposed reusable workflow, not an existing published API. Replace <reviewed-commit-sha> with the reviewed full commit SHA after the workflow is implemented. The trigger/secret behavior and security boundaries must be validated before shipping this example as production guidance.

# .github/workflows/dependabot-rebuild.yml in the caller repository
name: Rebuild Dependabot updates

on:
  pull_request:
    types: [opened, reopened, synchronize]
    paths:
      - 'package.json'
      - 'package-lock.json'

permissions:
  contents: read
  pull-requests: read

concurrency:
  group: dependabot-rebuild-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  rebuild:
    if: >-
      github.actor == 'dependabot[bot]' &&
      github.event.pull_request.user.login == 'dependabot[bot]' &&
      github.event.pull_request.head.repo.full_name == github.repository
    uses: actions/reusable-workflows/.github/workflows/dependabot-rebuild.yml@<reviewed-commit-sha>
    with:
      node-version: '24.x'
      dist-path: 'dist'
      # Optional: these are the proposed defaults and can be omitted.
      install-command: 'npm ci --ignore-scripts'
      build-command: 'npm run build'
    secrets:
      token: ${{ secrets.DEPENDABOT_BUILD_TOKEN }}

The actor check intentionally skips the rebuild job on the PAT-generated synchronize event; the repository's normal PR validation workflows should still run. The reusable workflow must independently validate the target and retain its no-op and stale-head protections. The caller workflow and command configuration must be trusted; checking a bot identity alone is not a substitute for that trust boundary.

To use a differently named secret, change only the explicit mapping:

    secrets:
      token: ${{ secrets.MY_REBUILD_PAT }}

To customize installation and building, override the inputs independently, for example:

    with:
      install-command: 'npm ci --ignore-scripts --include=dev'
      build-command: 'npm run build:action'

The custom script must exist in the caller project. If switching package managers, ensure the tool is provisioned in the isolated build job and adjust the caller's manifest/lockfile path filters accordingly.

Acceptance criteria

  • The workflow is reusable and opt-in; existing check-dist behavior is unaffected.
  • Omitting install-command executes npm ci --ignore-scripts; providing it executes the caller's custom installation command instead.
  • Omitting build-command executes npm run build; providing it executes the caller's custom command instead.
  • A PAT is required for publication and is unavailable to the build job.
  • Only allowed generated files are committed; no-op builds produce no commit.
  • Stale runs cannot overwrite newer branch updates.
  • Normal PR checks run on the generated commit.
  • Usage documentation covers permissions, secret setup, supported triggers, both custom command inputs, and availability requirements for alternative package managers.

Related long-term improvement

Dependabot-native generation before opening or updating a PR is requested in dependabot/dependabot-core#14549. This proposal is an Actions-based interim solution that could be shared across setup actions instead of each repository maintaining its own rebuild-and-push automation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions