Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b43f58e
feat(release): unify Desktop and CLI product releases
Astro-Han Aug 18, 2026
cd030b6
fix(release): bind npm to the product release
Astro-Han Aug 18, 2026
032c2e1
refactor(release): consolidate CLI packaging policy
Astro-Han Aug 18, 2026
7f3594f
fix(release): define exact draft recovery
Astro-Han Aug 18, 2026
c34585f
fix(release): prune non-macOS native artifacts
Astro-Han Aug 18, 2026
76dcec3
fix(release): pass the product tag into staging
Astro-Han Aug 18, 2026
ce9edee
fix(release): carry the incubator disclaimer in CLI ZIPs
Astro-Han Aug 18, 2026
18591b4
fix(release): order workspace builds by build dependencies
Astro-Han Aug 18, 2026
0190b71
fix(release): close product authority races
Astro-Han Aug 18, 2026
c1a163e
docs(release): describe artifact validation precisely
Astro-Han Aug 18, 2026
fe396b2
docs(cli): keep managed setup on the maka command
Astro-Han Aug 19, 2026
5849288
fix(release): close artifact integrity gaps
Astro-Han Aug 19, 2026
b67176e
fix(release): hash finalized desktop installers
Astro-Han Aug 19, 2026
b37e01b
fix(release): bind npm staging to product tags
Astro-Han Aug 19, 2026
e4cb2ca
fix(release): recover draft assets without replacement
Astro-Han Aug 19, 2026
d0838eb
docs(release): dispatch npm staging from product tags
Astro-Han Aug 19, 2026
ed7fa2b
fix(release): parse npm provenance attestation bundles
Astro-Han Aug 19, 2026
551a170
docs(release): require immutable product identity
Astro-Han Aug 19, 2026
1ff0c1d
fix(release): validate the live product identity locally
Astro-Han Aug 19, 2026
9669a45
docs(release): close manual validation gaps
Astro-Han Aug 19, 2026
9ffea1a
fix(ci): build before validating release contracts
Astro-Han Aug 20, 2026
a3f4ea7
fix(release): bind products to ASF source authority
M4n5ter Aug 21, 2026
8df5188
fix(release): enforce distributable product artifacts
M4n5ter Aug 21, 2026
7d6b89d
fix(release): unify product update and version authority
M4n5ter Aug 21, 2026
fc3822c
fix(release): align publication channel authority
M4n5ter Aug 21, 2026
bfd06fa
fix(release): enforce draft publication authority
M4n5ter Aug 21, 2026
be7cea7
test(release): trim redundant contract coverage
M4n5ter Aug 21, 2026
0eb1450
fix(release): harden standalone macOS CLI
Astro-Han Aug 21, 2026
cf88e54
fix(release): enforce exact product release authority
Astro-Han Aug 21, 2026
5d77994
test(release): run macOS launcher contract through bash
Astro-Han Aug 21, 2026
d75a461
fix(release): align published metadata with Apache authority
M4n5ter Aug 21, 2026
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
42 changes: 32 additions & 10 deletions .asf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,42 @@ github:
contexts:
- test

rulesets:
- name: Immutable release tags
type: tag
branches:
includes:
- "v*"
excludes: []
restrict_deletion: true
restrict_force_push: true

environments:
# release holds the Apple notarization and code signing credentials used by
# .github/workflows/release-desktop.yml. That workflow's own branch guard
# sits inside the file it is meant to protect, so this policy is the only
# boundary GitHub enforces from outside the workflow.
#
# Naming an environment here replaces its settings wholesale, so restate
# its full configuration when adding one. npm-release carries a required
# reviewer and a branch policy that live only on GitHub.
# These environments are the external human gates around signing secrets
# and npm OIDC. Naming an environment here replaces its settings wholesale,
# so keep every protection rule in this declarative authority.
release:
required_reviewers:
- id: M4n5ter
type: User
wait_timer: 0
prevent_self_review: true
deployment_branch_policy:
protected_branches: false
policies:
- name: "v*-incubating-rc*"
type: tag
npm-release:
required_reviewers:
- id: M4n5ter
type: User
wait_timer: 0
prevent_self_review: true
deployment_branch_policy:
protected_branches: false
policies:
- name: main
type: branch
- name: "v*"
type: tag

notifications:
commits: commits@maka.apache.org
Expand Down
147 changes: 119 additions & 28 deletions .github/RELEASE_CHECKLIST.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,141 @@
# Desktop release checklist
# Product release checklist

The `Release desktop` workflow is the single release entry point. It packages, verifies, and creates one draft GitHub Release carrying the Apple Silicon macOS and Windows x64 builds; it never publishes the release. The macOS build is signed, notarized, and stapled. The Windows build is unsigned.
The `Release` workflow is Maka's convenience-artifact release entry point. Desktop, CLI/TUI, and
bundled Git source materials are built from the exact IPMC-approved ASF source candidate commit.
They share that source commit, the root product version, one convenience tag, one GitHub Release,
one Draft decision, and one release gate. The workflow creates no Draft until every required
artifact job succeeds.

Phase 1 requires:

- signed and notarized Apple Silicon macOS Desktop artifacts;
- the unsigned Windows x64 Desktop installer and ZIP;
- the signed, notarized, relocatable Apple Silicon CLI/TUI ZIP;
- bundled Git source materials;
- checksums generated after each artifact reaches its final form.

The first product release also requires the exact `maka-agent@<version>` npm package. The product
tag and Draft must exist before npm staging, but the Draft must remain unpublished until npm is
public, Finalize has verified it, and Desktop acceptance has exercised remote Runtime Host setup.

## One-time repository setup

Create a GitHub Environment named `release`. Add required reviewers if the repository needs a release approval gate, then configure these environment secrets:
Create a protected GitHub Environment named `release`, require the appropriate reviewers, and
configure:

- `CSC_LINK`: base64-encoded Developer ID Application `.p12`;
- `CSC_KEY_PASSWORD`: password for that `.p12`;
- `APPLE_API_KEY`: raw contents of an App Store Connect API `.p8` key;
- `APPLE_API_KEY_ID`: App Store Connect API key ID;
- `APPLE_API_ISSUER`: App Store Connect API issuer ID.

Windows needs no secrets while the build is unsigned: electron-builder skips signing when no certificate is configured. Adding an Authenticode certificate later means configuring it in `apps/desktop/electron-builder.config.mjs`, and nothing else: electron-builder derives the publisher name that authenticates updates from the certificate itself.
The checked-in release configuration pins Maka's Apple Team ID to `FABM2QUA8Q`. Confirm every
replacement `CSC_LINK` belongs to that team before changing credentials; changing the pinned Team
ID requires its own reviewed product-release change.

Windows remains unsigned until an Authenticode policy and certificate are added. Release secrets
must never be exposed to fork or ordinary pull-request jobs.

Before the first product release, confirm the checked-in `.asf.yaml` has reconciled the live repository:

- the `Immutable release tags` ruleset blocks updates, force-pushes, and deletions of `v*` tags;
- the `release` and `npm-release` Environments accept only their declared tag patterns and require a reviewer other than the triggering user;
- enable immutable releases so assets and the associated tag cannot change after publication.

These controls close the check-to-upload and check-to-stage windows. Keep the Release in Draft while assets and acceptance are incomplete; publishing early must make subsequent mutation fail closed.

## Create the complete Draft

1. Confirm the podling and Incubator PMC votes have both passed for one immutable source candidate.
Record both result URLs and independently verify its signed annotated
`v<version>-incubating-rc<rc>` tag.
2. Confirm that tag resolves to a commit on `main`, required CI is green for that exact commit, and
root `package.json` contains a product version that has never been released.
3. Confirm `apps/desktop/package.json` and `packages/cli/package.json` exactly match the root
version, and the CLI manifest exposes only the `maka` command.
4. Dispatch `Release` from the exact approved candidate tag and supply the same tag as
`source_reference_tag`. A rerun must use that same tag; never select current `main` instead.
5. Confirm `release-identity`, both Desktop matrix entries, `cli-macos-arm64`, `source`, and
`publish` pass. A skipped or failed required job must prevent Draft creation.
6. Confirm one Draft named `v<version>` targets the approved source SHA, identifies the ASF source
reference in its notes, is marked as a GitHub prerelease exactly when the product version is a
prerelease, is not marked Latest while it remains a Draft, and contains exactly the manifest
reported by `node scripts/product-release-artifacts.mjs list`. The manifest covers both Desktop
platforms and update metadata, the standalone CLI/TUI, bundled source, and their required checksums.
7. Inspect the CLI ZIP. It must contain `bin/maka`, `RELEASE.json`, `DISCLAIMER-WIP`, `LICENSE`, `NOTICE`,
`THIRD_PARTY_NOTICES.txt`, the pinned Node license, and no `bin/maka-agent`.
8. Confirm `RELEASE.json` records the Draft's product version and source SHA, Apple Team ID
`FABM2QUA8Q`, the official Node
URL/archive/digest, npm version, workspace and production dependency closures, dependency
patches, Mach-O inventory, and `developer-id-notarized` signing state. Its final Node
entitlements must retain the required hardened-runtime capabilities and omit
`com.apple.security.get-task-allow`, as required by Apple's
[notarization guidance](https://developer.apple.com/documentation/security/resolving-common-notarization-issues).
9. Extract the bundled Git source-materials archive. Confirm `SOURCE_MANIFEST.json`, `README.txt`,
all manifest archives, and the expected Dugite native release are present.

If the publish job created the product tag or Draft but failed before every asset was uploaded,
rerun `Release` from the same approved ASF source candidate tag with the same
`source_reference_tag` input. Existing Draft assets must exactly
match the newly verified bytes; the retry keeps matching assets and uploads only missing ones. If an
asset conflicts or is unexpected, inspect and remove it manually while the Release is still a Draft,
then rerun. If only the tag exists, the retry creates the missing Draft.

## Publish and verify the npm channel

Follow [the npm release runbook](../docs/cli-npm-release.md) against the exact product tag and Draft:

1. Run **Stage CLI npm release** from `v<version>` and record its successful run ID and attempt.
2. Inspect the staged tarball and provenance, then approve that exact stage with npm 2FA.
3. Run **Finalize CLI npm channel** from `main` and confirm it verifies the public package bytes,
provenance, signature, and release dist-tag.
4. Install the exact public version on each release platform and complete the npm acceptance steps.

## Create the draft
Keep the GitHub Release in Draft throughout this sequence. A failed or rejected npm candidate
requires a new product version; never publish the Draft to work around npm state.

1. Confirm the intended commit is on `main`, CI is green, `apps/desktop/package.json` contains a version that has never been released, and the exact `maka-agent` version in `packages/cli/package.json` is public on npm.
2. In GitHub Actions, run `Release desktop` against `main`.
3. Confirm every workflow step passes on both platforms and a draft release named `v<version>` exists.
4. Confirm the draft records the intended commit SHA and contains the macOS DMG, ZIP, `latest-mac.yml`, the Windows `.exe`, ZIP, `latest.yml`, the bundled Git source-materials archive, and matching `.sha256` files.
5. Extract the bundled Git source-materials archive. Confirm `SOURCE_MANIFEST.json` and `README.txt` are present, every manifest archive is present, and the manifest pins the expected Dugite native release.
6. Confirm the packaged applications contain `licenses/git/LICENSE.txt`, `NOTICE.txt`, and `SOURCE_OFFER.txt`.
When every npm and cross-machine acceptance check has passed, publish the Draft. Mark a stable
release as Latest at that final publication boundary; prereleases must remain non-Latest.

## Acceptance on another Apple Silicon Mac

Download the DMG and its `.sha256` file through the GitHub UI. This download path applies the real browser quarantine metadata that CI intentionally does not simulate.
Download the DMG, CLI ZIP, and their checksum files through a browser from the Draft. Do not move
artifacts directly from the workflow runner; the browser path supplies the real quarantine
boundary.

1. From the download directory, run `shasum -a 256 -c Maka-<version>-mac-arm64.dmg.sha256`.
2. Open the DMG in Finder, drag Maka to Applications, and launch it from Finder.
3. Confirm macOS opens Maka without an unidentified-developer or damaged-app warning.
4. Run `spctl --assess --type execute --verbose=4 /Applications/Maka.app` and confirm it is accepted with a Developer ID origin.
5. Configure a model connection, send one basic prompt, and run one representative file-tool task.
6. Install `ripgrep` with `brew install ripgrep`, then confirm a task using `Grep` works.
7. Confirm the known limitation is accurate: Computer Use is not included.
1. Run `shasum -a 256 -c` for the DMG and CLI ZIP.
2. Install and launch the Desktop app from Finder. Confirm there is no unidentified-developer or
damaged-app warning.
3. Run `spctl --assess --type execute --verbose=4 /Applications/Maka.app` and confirm a Developer
ID origin.
4. Extract the CLI ZIP without clearing quarantine. Run `bin/maka --version` and `bin/maka --help`.
Keep the Mac online for this first Gatekeeper assessment: the notarized ZIP cannot carry a
stapled ticket, so macOS may retrieve it from Apple.
5. Create an external link, for example `ln -s "$PWD/bin/maka" /tmp/maka-release-acceptance`, and
confirm the linked command reports the same version and help output.
6. Start `bin/maka` with no arguments and confirm the TUI renders, accepts input, and exits cleanly.
7. Exercise one non-interactive `bin/maka run`, one deterministic `bin/maka eval run`, and one streaming
tool-call path against the packaged artifact.
8. Configure a Desktop model connection, send one prompt, and run one representative file-tool
task. Confirm the documented Computer Use limitation remains accurate.
9. Add a clean remote Runtime Host from the packaged Desktop app. Confirm setup installs the exact
public `maka-agent@<version>` package and the remote session completes one model turn.

## Acceptance on a Windows x64 machine

Download the `.exe` installer and its `.sha256` file through the GitHub UI. The build is unsigned, so this pass is about confirming the expected warnings and that the app still runs.
Download the installer, Windows Desktop ZIP, and both checksum files through a browser from the same Draft.

1. From the download directory, run `Get-FileHash Maka-<version>-win-x64.exe -Algorithm SHA256` in PowerShell and confirm the hash matches the `.sha256` file.
2. Run the installer. Confirm SmartScreen shows the expected unrecognized-publisher warning, and that continuing through **More info → Run anyway** completes the install.
3. Launch Maka from the Start menu.
4. Configure a model connection, send one basic prompt, and run one representative file-tool task.
5. Install `ripgrep` with `winget install BurntSushi.ripgrep.MSVC`, restart Maka so the new `PATH` applies, then confirm a task using `Grep` works.
6. Run one terminal task and confirm the shell integration works against the packaged `node-pty`.
7. Confirm the known limitation is accurate: Computer Use is not included.
1. Verify both SHA-256 checksums in PowerShell.
2. Expand the ZIP and launch its Maka executable once to confirm the portable artifact starts.
3. Run the installer and confirm the expected unsigned-publisher SmartScreen flow.
4. Launch Maka from the Start menu, configure a model connection, send one prompt, and run one representative file-tool task.
5. Run one terminal task and confirm packaged `node-pty` behavior.
6. Confirm the documented Computer Use limitation remains accurate.
7. Add a clean remote Runtime Host from the packaged Desktop app. Confirm setup installs the exact
public `maka-agent@<version>` package and the remote session completes one model turn.

Publish the draft only after all checks pass on both platforms. If acceptance fails, keep the draft unpublished, fix the issue, increment the desktop version, and run the workflow again; do not replace an existing release identity.
Immediately before publication, reverify that the approved ASF candidate tag and convenience
`v<version>` tag still resolve to the same recorded commit. Publish only after npm Finalize and both
independent-machine acceptance passes. If any required artifact, npm step, or
acceptance step fails, keep the Draft unpublished, fix the issue, increment the root product
version, and run the full workflow again. Never replace an existing release identity.
10 changes: 7 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
run: node --test --test-concurrency=1 scripts/protocol-epoch-check.test.mjs

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
if: steps.plan.outputs.code == 'true' || steps.plan.outputs.astryx_surface == 'true' || steps.plan.outputs.asf_source == 'true' || steps.plan.outputs.cli_package == 'true'
if: steps.plan.outputs.code == 'true' || steps.plan.outputs.astryx_surface == 'true' || steps.plan.outputs.asf_source == 'true' || steps.plan.outputs.cli_package == 'true' || steps.plan.outputs.release_contract == 'true'
with:
node-version: '24'
cache: npm
Expand Down Expand Up @@ -100,7 +100,7 @@ jobs:
fi

- name: Install dependencies
if: steps.plan.outputs.code == 'true' || steps.plan.outputs.cli_package == 'true'
if: steps.plan.outputs.code == 'true' || steps.plan.outputs.cli_package == 'true' || steps.plan.outputs.release_contract == 'true'
run: npm ci

- name: Lint
Expand All @@ -112,9 +112,13 @@ jobs:
run: npm run format:check

- name: Build
if: steps.plan.outputs.code == 'true'
if: steps.plan.outputs.code == 'true' || steps.plan.outputs.cli_package == 'true' || steps.plan.outputs.release_contract == 'true'
run: npm run build

- name: Release contracts
if: steps.plan.outputs.release_contract == 'true'
run: npm run check:release

- name: Typecheck
if: steps.plan.outputs.code == 'true'
run: npm run typecheck
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/cli-package-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ name: CLI package validation

on:
workflow_call:
inputs:
source_commit:
description: Exact product release commit to build; defaults to the triggering commit
required: false
type: string
default: ''
outputs:
release_candidate_artifact_id:
description: Immutable artifact produced by the build job
Expand All @@ -24,6 +30,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.source_commit || github.sha }}
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
Expand Down Expand Up @@ -77,6 +84,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.source_commit || github.sha }}
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
Expand Down Expand Up @@ -105,6 +113,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.source_commit || github.sha }}
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
Expand Down
Loading