Skip to content

feat(release): centralize and harden artifact publishing#55

Open
francoischalifour wants to merge 1 commit into
mainfrom
fc/release-artifact
Open

feat(release): centralize and harden artifact publishing#55
francoischalifour wants to merge 1 commit into
mainfrom
fc/release-artifact

Conversation

@francoischalifour

Copy link
Copy Markdown
Member

Context

The release pipeline previously distributed release knowledge across TypeScript, shell commands, Make targets, and GitHub Actions workflow YAML. Platform targets, runner selection, artifact names, compiler options, smoke tests, and publication behavior could drift independently.

That created several supply-chain and operational risks:

  • CI could test one artifact and publish another.
  • Public asset names and updater mappings could diverge.
  • Release builds depended on implicit compiler defaults.
  • Important behavioral checks were buried in workflow YAML and difficult to run locally.
  • Partial npm or GitHub publication failures were difficult to recover safely.
  • The release compiler version could accidentally become the minimum Bun version required by npm users.
  • Release binaries were retained for only seven days, despite GitHub’s longer workflow-rerun window.
  • Darwin ARM releases used the deprecated macos-14 runner.
  • npm publishing relied on a long-lived NPM_TOKEN even though the job already supported GitHub Actions OIDC.

This branch makes the release pipeline an explicit, testable contract and ensures the exact bytes that pass verification are the bytes ultimately published.

Proposed solution

Centralize the release contract

Add a typed release manifest as the single source of truth for:

  • Bun compilation targets
  • Supported operating systems and architectures
  • GitHub Actions runners
  • Public GitHub release asset names
  • Updater platform mappings
  • Release metadata and checksum inventory

CI matrices, native compilation, updater resolution, smoke tests, and publication now derive from this manifest. Semantic tests protect public asset names and ensure every supported platform remains represented exactly once.

The Darwin ARM target now uses the supported macos-15 ARM runner instead of deprecated macos-14.

Separate the build toolchain from the runtime contract

Pin Bun 1.3.14 as the reproducible release build toolchain without changing the npm package’s existing runtime contract:

"engines": {
  "bun": ">=1.1.0"
}

The pinned Bun version controls compilation and bundling only. Users installing @altertable/cli do not need the pinned release compiler version; Bun 1.1.0 and newer remain supported.

CI explicitly builds the npm bundle with the pinned toolchain and then smoke-tests those exact bytes under both:

  • the pinned release Bun version
  • Bun 1.1.0, the minimum supported npm runtime

Harden native compilation

Move release compilation into checked-in TypeScript scripts with explicit compiler settings, including:

  • minification
  • bytecode generation
  • unresolved import rejection
  • disabled automatic .env loading
  • disabled automatic bunfig.toml loading
  • explicit target and output paths

The build scripts validate the pinned toolchain and release tag before producing artifacts. Each native binary is smoke-tested on its target runner before it can enter the publication job.

Reuse one canonical verification workflow

Introduce a reusable verification workflow shared by branch CI and release CI.

The canonical gate covers:

  • dependency installation with the frozen lockfile
  • type checking
  • linting and formatting
  • generated OpenAPI drift
  • unit tests and coverage
  • black-box CLI tests
  • dependency and dead-code analysis
  • npm bundle construction and packaging
  • npm bundle smoke testing
  • minimum Bun runtime compatibility

Release jobs check out and verify the exact tagged revision rather than relying on unverified workspace state.

Publish the exact tested artifacts

Native jobs upload only binaries that have already passed their platform smoke tests. The final release job downloads those binaries instead of rebuilding them.

The JavaScript release asset and npm package are also produced from the same bundle bytes. The pipeline then:

  1. Assembles the complete release inventory.
  2. Generates deterministic SHA-256 checksums.
  3. Records artifact-specific build recipes and toolchain metadata.
  4. Verifies the checksums.
  5. Creates GitHub artifact attestations.
  6. Uploads the exact verified assets.
  7. Publishes the npm package.
  8. Publishes the previously draft GitHub release.

This ordering prevents a GitHub release from being presented as complete when npm publication has failed.

Make publication recoverable and retry-safe

Release Please creates a draft GitHub release. It becomes public only after every artifact and npm publication step succeeds.

npm publication is idempotent:

  • If the exact package version is already published, a rerun continues safely.
  • A genuine 404 means publication is still required.
  • Authentication, registry, and network failures remain hard failures rather than being mistaken for an unpublished version.

GitHub asset uploads use replacement semantics, allowing a failed workflow to be rerun without manually deleting partially uploaded assets.

Tested native release binaries are retained for 30 days, matching the workflow recovery window. Disposable diagnostics remain at seven days:

  • release-native binaries: 30 days
  • coverage reports: 7 days
  • ordinary branch compilation artifacts: 7 days

Semantic workflow tests enforce this distinction so release recovery retention cannot accidentally regress.

Replace the npm publishing token with OIDC

Remove NPM_TOKEN from the release workflow and publish through npm trusted publishing using GitHub Actions OIDC.

The npm package now trusts:

  • repository: altertable-ai/altertable-cli
  • workflow: release-please.yml
  • permission: npm publish

The publishing script fails closed unless:

  • GitHub Actions OIDC credentials are present
  • id-token: write is available
  • npm is new enough to support trusted publishing
  • neither NODE_AUTH_TOKEN nor NPM_TOKEN is present

This prevents an accidental fallback to long-lived credentials. npm automatically generates provenance for a successful trusted publication.

The registry migration remains deliberately staged:

  1. Configure the npm trusted publisher before merging.
  2. Publish the first release through OIDC.
  3. Verify that npm provenance references the expected GitHub Actions run.
  4. Configure npm to require 2FA and disallow token publishing.
  5. Delete the unused GitHub NPM_TOKEN secret and revoke the underlying npm token.

Token publishing should not be disabled until the first OIDC release succeeds, preserving a controlled recovery path during the cutover.

Move behavioral logic out of workflow YAML

Reusable build, smoke-test, validation, upload, and publication behavior now lives in checked-in TypeScript scripts.

The workflows retain orchestration-level responsibilities such as:

  • selecting runners
  • declaring permissions
  • connecting job dependencies
  • installing toolchains
  • uploading and downloading artifacts
  • invoking repository scripts

This keeps CI readable while making release behavior locally executable and unit-testable.

Compatibility

This change does not alter the public CLI interface or release asset names.

In particular:

  • Existing updater asset names remain stable.
  • @altertable/cli continues to support Bun >=1.1.0.
  • npm users do not need Bun 1.3.14; that version is only the release compiler pin.
  • Prebuilt native binaries continue to run without Bun installed.
  • Existing development commands remain available.
  • Branch CI and release CI now share the same verification contract.

Define one typed release manifest for platform targets, public artifact names, updater resolution, and CI runners. Move build, smoke, upload, and publication behavior into directly testable repository scripts instead of embedding programs in workflow YAML.

Gate branch and release publication on one reusable canonical verification workflow. Build and execute native artifacts on supported target runners, test the exact npm bytes under the release and minimum Bun runtimes, emit artifact-specific recipes and verified checksums, and attest the same bytes that are published.

Keep GitHub releases draft until npm succeeds, make npm publication idempotent for retries, retain exact release binaries for the full 30-day rerun window, and preserve the independently tested Bun >=1.1.0 runtime contract.

Replace long-lived npm publish credentials with GitHub Actions OIDC trusted publishing. Fail closed when OIDC or the required npm CLI is unavailable, reject token fallback, and document the staged post-release token revocation process.
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.

1 participant