Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
name: publish

on:
release:
types: [published]

permissions:
contents: read
id-token: write
attestations: write
artifact-metadata: write

jobs:
check:
name: check npm package versions
if: github.event.release.prerelease == false
runs-on: ubuntu-latest
outputs:
should_publish: ${{ steps.appdmg_publish_status.outputs.exists == '0' && steps.cli_publish_status.outputs.exists == '0' }}

steps:
- name: checkout
uses: actions/checkout@v6

- name: setup node 24
uses: actions/setup-node@v6
with:
node-version: 24
registry-url: https://registry.npmjs.org

- name: check appdmg npm package version
id: appdmg_publish_status
uses: tehpsalmist/npm-publish-status-action@01cb25946b194a7a5468f22c8e74db04c283f121

- name: prepare cli package metadata
run: |
cp package.json package.appdmg.json
cp packages/cli/package.json package.json

- name: check cli npm package version
id: cli_publish_status
uses: tehpsalmist/npm-publish-status-action@01cb25946b194a7a5468f22c8e74db04c283f121

publish:
name: publish to npmjs
needs: check
if: needs.check.outputs.should_publish == 'true'
runs-on: ubuntu-latest

steps:
- name: checkout
uses: actions/checkout@v6

- name: setup node 24
uses: actions/setup-node@v6
with:
node-version: 24
registry-url: https://registry.npmjs.org
cache: npm

- name: install appdmg dependencies
run: npm ci

- name: install cli dependencies
run: npm ci --prefix packages/cli

- name: pack appdmg package
id: pack_appdmg
run: |
mkdir -p dist/appdmg
npm pack --json --pack-destination dist/appdmg > dist/appdmg/pack.json
tarball="$(find dist/appdmg -maxdepth 1 -name '*.tgz' -print -quit)"
test -n "$tarball"
echo "tarball=$tarball" >> "$GITHUB_OUTPUT"

- name: pack cli package
id: pack_cli
run: |
mkdir -p dist/cli
(
cd packages/cli
npm pack --json --pack-destination ../../dist/cli > ../../dist/cli/pack.json
)
tarball="$(find dist/cli -maxdepth 1 -name '*.tgz' -print -quit)"
test -n "$tarball"
echo "tarball=$tarball" >> "$GITHUB_OUTPUT"

- name: attest npm package artifacts
uses: actions/attest@v4
with:
subject-path: dist/**/*.tgz

- name: publish appdmg package
run: npm publish "$TARBALL" --provenance --access public
env:
TARBALL: ${{ steps.pack_appdmg.outputs.tarball }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: publish cli package
run: npm publish "$TARBALL" --provenance --access public
env:
TARBALL: ${{ steps.pack_cli.outputs.tarball }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
4 changes: 4 additions & 0 deletions docs/node24-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ Before publishing the final CLI to npm, verify that each scoped helper package
is available from npm at the intended version and that a clean install of
`@appdmg/cli` resolves only npm-published artifacts.

The npm release process is documented in
[npm-publishing.md](npm-publishing.md). Packages must be published from GitHub
Actions with provenance and package artifact attestations.

## Test coverage

The rewrite is backed by AVA tests.
Expand Down
69 changes: 69 additions & 0 deletions docs/npm-publishing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# npm publishing with provenance

All `@appdmg/*` packages are published from GitHub Actions. Local npm publish
is not part of the release process.

## Required npm package settings

Prefer npm Trusted Publishing for every package. Configure the npm package
Trusted Publisher as GitHub Actions with these values:

| Package | GitHub repository | Workflow filename | Environment |
| --- | --- | --- | --- |
| `@appdmg/bplist-creator` | `appdmg/bplist-creator` | `publish.yml` | blank |
| `@appdmg/tn1150` | `appdmg/tn1150` | `publish.yml` | blank |
| `@appdmg/macos-alias` | `appdmg/macos-alias` | `publish.yml` | blank |
| `@appdmg/ds-store` | `appdmg/ds-store` | `publish.yml` | blank |
| `@appdmg/appdmg` | `appdmg/appdmg-cli` | `publish.yml` | blank |
| `@appdmg/cli` | `appdmg/appdmg-cli` | `publish.yml` | blank |

The repositories and packages must stay public for npm provenance to be
generated and shown by npm.

If npm cannot configure Trusted Publishing before a first package publish, add
a granular `NPM_TOKEN` repository secret with publish permission and 2FA bypass.
The workflows still publish from GitHub Actions with `npm publish --provenance
--access public`, so the package gets npm provenance. Remove the token path once
Trusted Publishing works.

## What the workflows attest

Each publish workflow:

- runs on a GitHub-hosted runner with `id-token: write`;
- ignores GitHub prereleases so prerelease tags cannot publish the npm `latest`
dist-tag by accident;
- checks whether the exact package version already exists on npm with
`tehpsalmist/npm-publish-status-action` pinned to
`01cb25946b194a7a5468f22c8e74db04c283f121`;
- installs with Node.js 24;
- installs dependencies with `npm ci`;
- creates the exact npm package tarball with `npm pack`;
- creates a GitHub artifact attestation for that `.tgz`;
- publishes the same `.tgz` to npm with provenance enabled.

If the exact package version is already published, the publish path exits
without running the package, attestation, or npm publish steps. Build, test,
audit, and runtime dependency checks remain in the normal build/CI workflows.

The appdmg CLI repository publishes two packages from one workflow. It publishes
`@appdmg/appdmg` first, then `@appdmg/cli`. If either package version is already
published, the workflow exits without publishing either package.

## Release order

Publish packages bottom-up:

1. `@appdmg/bplist-creator`
2. `@appdmg/tn1150`
3. `@appdmg/macos-alias`
4. `@appdmg/ds-store`
5. `@appdmg/appdmg` and `@appdmg/cli`

After publishing, verify from a clean project:

```sh
npm install @appdmg/cli
npm audit signatures
npx appdmg-cli --version
```