Skip to content

Make action execution hermetic and reproducible #18

Closed

Description

@vitormattos

Goal

Make the reusable actions execute the exact dependency graph that was reviewed and tested.

Current gap

The composite actions run npm install --ignore-scripts at execution time and the repository currently has no committed package-lock.json. Direct dependencies are exact, but transitive resolution can still change between CI validation and consumer execution.

Target

Prefer a runtime artifact that does not resolve package dependencies dynamically.

Evaluate in this order:

  1. commit a lockfile and use npm ci --ignore-scripts everywhere;
  2. build and verify deterministic dist/ output;
  3. if practical, make the reusable action execute prebuilt/bundled JavaScript so consumers do not install development dependencies at runtime.

Quality requirements

  • Dependabot updates the lockfile;
  • REUSE metadata covers generated dependency metadata appropriately;
  • CI fails when package.json and lockfile diverge;
  • CI verifies committed/bundled output matches source;
  • consumers remain pinned to immutable action SHAs;
  • no package lifecycle scripts run during action execution.

Note

This is a hardening follow-up and should not block the first v0.1.0 release mechanism.

Activity

  1. vitormattos commented on Sep 20, 2026

    @vitormattos
    MemberAuthor

    Architecture review confirmed that both reusable composite actions and the TypeScript/Vitest CI currently resolve dependencies with npm install --ignore-scripts and there is no committed package-lock.json.

    The next implementation should first generate and review a real lockfile from the current dependency graph, then migrate CI and action runtime installation to npm ci --ignore-scripts. A later step can evaluate prebuilt/bundled JavaScript to eliminate dependency resolution in consumer runs entirely.

    I did not commit a synthetic lockfile: lockfile generation must come from npm and be reproducible.

  2. vitormattos commented on Sep 20, 2026

    @vitormattos
    MemberAuthor

    Implemented and validated in #26.

    The reusable governance Actions no longer resolve npm dependencies or build TypeScript at consumer runtime. They now execute the reviewed TypeScript source directly with Node 24, and the source was adjusted to use syntax supported by Node's TypeScript stripping mode.

    CI now smoke-tests the exact runtime path before installing development dependencies, while Vitest and TypeScript build/typecheck coverage remain in CI. The merged main commit passed TypeScript, Vitest, CodeQL, actionlint, zizmor and REUSE.

    This removes the mutable runtime dependency graph described in this issue, which is stronger than only switching from npm install to npm ci.

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