Skip to content

feat(ci): add tag-triggered tarball release for ghost-drift#45

Merged
nahiyankhan merged 4 commits intomainfrom
feat/tarball-release
Apr 21, 2026
Merged

feat(ci): add tag-triggered tarball release for ghost-drift#45
nahiyankhan merged 4 commits intomainfrom
feat/tarball-release

Conversation

@nahiyankhan
Copy link
Copy Markdown
Collaborator

Summary

Distribution channel for `ghost-drift` while npm publishing is blocked on the org-side package-name bootstrap. Adds a tag-triggered workflow that packs the package and attaches the `.tgz` to a GitHub Release.

Consumer install

npm install https://github.com/block/ghost/releases/download/ghost-drift%400.1.1/ghost-drift-0.1.1.tgz

Works with npm, pnpm, yarn. `ghost-drift` binary installs to `node_modules/.bin` exactly as it would from npm. Library imports (`import { parseFingerprint } from "ghost-drift"`) work normally.

How to cut a release

After merge:

git tag ghost-drift@0.1.1
git push origin ghost-drift@0.1.1

That triggers `.github/workflows/release-tarball.yml`, which:

  1. Builds `ghost-drift`
  2. Runs `pnpm --filter ghost-drift pack`
  3. Creates a GitHub Release at `ghost-drift@0.1.1` with auto-generated notes
  4. Attaches `ghost-drift-0.1.1.tgz` to the release

Can also trigger manually via `workflow_dispatch` if needed.

Not changed

  • npm publishing workflow (`.github/workflows/release.yml`) left in place; once the org unblocks creation of `ghost-drift` on npm, it takes over and this tarball channel can be deprecated.
  • Changesets flow stays the same — version bumps land in `packages/ghost-drift/package.json` via Version Packages PRs.

Test plan

🤖 Generated with Claude Code

While npm publishing is blocked on org-side package-name bootstrap, ship ghost-drift as a .tgz attached to a GitHub Release. Consumers install via npm install <release-url>, which works for any tarball URL and doesn't require an npm account or custom registry config.

- .github/workflows/release-tarball.yml — runs on pushing a tag matching 'ghost-drift@*' (or workflow_dispatch), builds + pnpm packs the package, creates a GitHub Release with the .tgz attached and auto-generated notes.
- packages/ghost-drift/README.md — Install section rewritten to point at the GitHub Release URL pattern, with a note that it'll move to npm once registration is sorted.

To cut a release:

  git tag ghost-drift@0.1.1
  git push origin ghost-drift@0.1.1

Triggers the workflow, which lands a release at
https://github.com/block/ghost/releases/tag/ghost-drift%400.1.1 with
packages/ghost-drift/ghost-drift-0.1.1.tgz attached.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread .github/workflows/release-tarball.yml Fixed
Comment thread .github/workflows/release-tarball.yml Fixed
Comment thread .github/workflows/release-tarball.yml Fixed
nahiyankhan and others added 3 commits April 21, 2026 09:54
Addresses zizmor cache-poisoning alert (#5). The actions/cache store backing 'cache: pnpm' is shared across the repo — any workflow run on any branch can write to it — so in a publishing workflow a poisoned cache entry could be baked into the shipped tarball without anyone noticing.

For a tag-triggered release workflow that runs maybe once a week, the ~30s install-from-scratch cost isn't worth the supply-chain risk. Dropped 'cache: pnpm' and left a comment explaining why so nobody re-adds it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three scanner alerts were still open on PR #45:

- zizmor/cache-poisoning (#5): pnpm/action-setup maintains its own cache store even without 'cache: pnpm' on setup-node. Switched to corepack enable instead, which reads the 'packageManager' field from root package.json and has no cache state.
- semgrep/run-shell-injection (#6, line 57/60): '${{ github.event_name }}' and '${{ inputs.version }}' were interpolated directly into a run: script. inputs.* is attacker-controlled via workflow_dispatch. Moved both to env: and referenced as '$EVENT_NAME' / '$INPUT_VERSION' so they're passed as environment variables instead of being substituted into shell syntax.
- semgrep/run-shell-injection (#7, line 68/69): same fix for '${{ steps.tag.outputs.tag }}' in the gh release create step — now passed via TAG env var.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Zizmor flags any GitHub-official setup action in a publishing workflow — even without caching enabled — on the logic that the action is cache-capable and a future edit could re-enable caching without catching the change.

ubuntu-latest ships Node 20 and corepack preinstalled. Our engines.node is >=18, so we can skip actions/setup-node entirely and rely on the runner default. Corepack then picks up the pnpm version from the root package.json 'packageManager' field, so pnpm version pinning is preserved.

One less action pinned, one less cache vector, zizmor clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nahiyankhan nahiyankhan merged commit 87c179f into main Apr 21, 2026
6 checks passed
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.

2 participants