Skip to content

Workflow node-version pins can drift from engines.node without detection #333

Description

@lamemustafa

Split out of #331, where four review rounds showed the check cannot be done correctly by regex.

What is unguarded

Every workflow pins node-version: 24.20.0 and package.json declares engines.node: ">=24.20.0". Nothing enforces that they agree. A workflow could pin a different major, pin a version below the declared minimum, or lose its pin entirely and fall back to the runner default, and no check would notice.

Why #331 stopped trying

tests/repo/node-runtime-types-alignment.test.ts attempted this by scanning the YAML with regexes. Review found four ways it passed while broken, each surfacing only after the previous was fixed:

  1. Lexical version comparison — "24.9.0" >= "24.20.0" is true, and "26.10.0" >= "26.4.1" is false. Wrong in both directions.
  2. An aggregate count across files stayed positive when one file lost its pin.
  3. A per-file count stayed positive when one of release.yml's two setup-node steps lost its pin.
  4. A commented-out pin — # node-version: 24.20.0 — satisfies every regex while GitHub ignores it.

Each fix was correct and produced the next hole. The pattern is not sloppiness: associating a pin with its step requires knowing which with: block belongs to which step, which is YAML semantics, and this repo has a record of what happens when it hand-rolls a parser for a grammar it does not own (#197, six rounds).

The guard now asserts only that the resolved @types/node major matches engines.node, read from the lockfile. That covers the risk the dependabot ignore rule exists for, and cannot be fooled by comments, ranges, or indentation.

What a real fix needs

A YAML parse, so each actions/setup-node step is checked for its own active with.node-version. That means a parser dependency, which is ask-first here, and the trade should be stated rather than assumed: one small YAML dependency against a class of drift nothing currently detects.

Worth noting the exposure is modest — all seven workflows carry correct pins today, and a wrong pin would likely surface as a CI failure rather than silently. The reason to fix it is that "likely" is doing real work in that sentence.

Not blocking

Recorded so the gap is known rather than forgotten. #331 is deliberately narrower than the problem.

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions