Skip to content

Release pipeline is broken: auto-tag versions diverge from package.json (0.0.x vs 1.0.1) and tag pushes never trigger publish #26

Description

@dmchaledev

Summary

The release automation (auto-tag.yml + publish.yml) has three compounding defects that together mean tagged releases are not being published, and if they ever are, they will publish the wrong (lower) version number. This is distinct from every open issue/PR — those all touch src/ logic; this is purely about the CI/release machinery, which only auto-tag.yml / publish.yml cover and no in-flight work modifies.

Evidence (current state)

$ git ls-remote --tags origin
... refs/tags/v0.0.2 ... refs/tags/v0.0.10   # newest tag = v0.0.10 on HEAD of main
$ node -p "require('./package.json').version"
1.0.1

So the repo simultaneously claims 1.0.1 in package.json (and the README npm-version badge advertises the 1.x line) while the auto-tagger keeps emitting v0.0.x tags. The two never reconcile.

Three concrete defects

1. Automated publishing never fires — GITHUB_TOKEN tag pushes can't trigger publish.yml

.github/workflows/auto-tag.yml creates and pushes the version tag using the default GITHUB_TOKEN:

- uses: actions/checkout@v4
  with:
    token: ${{ secrets.GITHUB_TOKEN }}
...
git tag "v$NEW_VERSION"
git push origin "v$NEW_VERSION"

.github/workflows/publish.yml is meant to fire on that tag:

on:
  push:
    tags:
      - 'v*'

But per GitHub's documented behavior, events triggered by GITHUB_TOKEN (other than workflow_dispatch/repository_dispatch) do not start new workflow runs — this is the recursion guard. So a tag pushed by auto-tag.yml will not trigger publish.yml. Result: tags v0.0.2v0.0.10 exist, but none of them were auto-published to npm. The only way publish.yml runs today is a manual workflow_dispatch.

Ref: GitHub Actions docs, "Triggering a workflow from a workflow" — "events triggered by the GITHUB_TOKEN … will not create a new workflow run."

2. Version source-of-truth split — package.json 1.0.1 is permanently ignored

auto-tag.yml computes the next version solely from the highest existing git tag, only falling back to package.json when no tags exist:

LATEST=$(git tag -l 'v*' --sort=-version:refname | head -1)   # -> v0.0.10
if [ -z "$LATEST" ]; then
  LATEST="v$(node -p "require('./package.json').version")"     # only when NO tags exist
fi
CURRENT="${LATEST#v}"                                          # 0.0.10
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
NEW_VERSION="$MAJOR.$MINOR.$((PATCH + 1))"                     # 0.0.11

Because a v0.0.x tag already exists, the manual chore: bump to v1.0.1 (commit 8e4ee6e) is silently ignored and the next tag will be v0.0.11, not something in the 1.x line. The declared package version and the auto-tag stream have permanently diverged.

3. If publish does run, it ships a version below what users already have

publish.yml overwrites the package version from the tag before publishing:

TAG_VERSION="${GITHUB_REF#refs/tags/v}"          # 0.0.11
npm version "$TAG_VERSION" --no-git-tag-version  # package.json -> 0.0.11
npm publish --provenance --access public

If 1.0.1 is the version currently on npm (as the badge implies), a manual dispatch of publish.yml on v0.0.11 would publish 0.0.11 and move npm's latest dist-tag backward, so npm install @hailbytes/sbom-diff would start resolving to a lower version than 1.0.1. For a security tool that's a real supply-chain footgun, not just cosmetics.

Bonus: publish.yml has no quality gate

publish.yml runs npm run build then npm publish with no typecheck, test, or lint step. The auto-tag.yml test gate doesn't protect the workflow_dispatch publish path, so a manual publish can ship code that doesn't even compile-check or pass tests.

Proposed fixes

These involve a couple of policy decisions, so flagging as an issue rather than a unilateral PR. Recommended direction:

  1. Make package.json the single source of truth for the version. Drop the "derive next version from highest git tag" logic. Either:

    • tag directly from package.json (v$(node -p "require('./package.json').version")) and let a human own the bump (e.g. via npm version), or
    • if you want auto-increment, increment from package.json (npm version patch) and commit the bump back, so the file and the tags never diverge.
      This immediately resolves the 0.0.x vs 1.0.1 split and prevents the downgrade in defect fix: add engines field, remove placeholder workflow #3.
  2. Fix the publish trigger. Pick one:

    • (simplest) Move the build+publish steps into the auto-tag.yml job itself, right after the tag is created — no cross-workflow trigger needed.
    • Push the tag with a PAT / fine-grained token (or a GitHub App token) instead of GITHUB_TOKEN, so the push: tags event actually fires publish.yml.
    • Have auto-tag.yml explicitly invoke publish via workflow_dispatch / repository_dispatch (those are allowed from GITHUB_TOKEN).
  3. Add a quality gate to publish.yml before npm publish:

    - run: npm ci
    - run: npm run typecheck
    - run: npm test
    - run: npm run build

    So no path to npm skips type-check + tests.

  4. Reconcile the existing tags once a direction is chosen (e.g. cut a proper v1.0.x/v1.1.0 tag so the tag stream lines up with the published 1.x line, and stop emitting 0.0.x).

Why this is high-leverage

  • It's the difference between "releases publish correctly" and "releases silently don't publish, or publish a downgrade." For a package whose whole pitch is supply-chain integrity, a release pipeline that ships the wrong version (or nothing) undermines trust in the artifact itself.
  • It's orthogonal to all open PRs/issues (which touch diff.ts / parser.ts / reporter.ts / cli.ts), so it won't conflict with anything in flight.
  • The changes are confined to the two workflow files plus a one-time tag cleanup.

Happy to open a focused PR implementing whichever of the option (1)/(2) directions you prefer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions