Skip to content
Merged
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
20 changes: 10 additions & 10 deletions .asf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,11 @@ github:
restrict_force_push: true

environments:
# 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.
# These environments are the deployment boundaries around signing secrets
# and npm OIDC. Release publication adds human review; scheduled npm
# Nightly relies on exact ref admission instead. Naming an environment here
# replaces its settings wholesale, so keep every protection rule in this
# declarative authority.
release:
required_reviewers:
- id: M4n5ter
Expand All @@ -99,17 +101,15 @@ github:
policies:
- name: "v*-incubating-rc*"
type: tag
npm-release:
required_reviewers:
- id: M4n5ter
type: User
npm-publication:
required_reviewers: []
wait_timer: 0
prevent_self_review: true
prevent_self_review: false
deployment_branch_policy:
protected_branches: false
policies:
- name: "v*"
type: tag
- name: main
type: branch
product-release:
required_reviewers:
- id: M4n5ter
Expand Down
6 changes: 3 additions & 3 deletions .github/ASF_NPM_RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ registry side effects.

After both source-release votes approve the candidate, the product Release
workflow creates `v<version>` at that approved commit. The npm Stage workflow
then builds and validates one tarball from that final tag, submits those exact
bytes to npm staging through the protected `npm-release` Environment and OIDC,
and records the stage identity. Human approval with npm 2FA makes the package
then builds and validates one tarball from that final tag in jobs without OIDC. The OIDC job runs
only reviewed `main` publisher code, submits those exact bytes through the main-restricted
`npm-publication` Environment, and records both product-source and publisher identities. Human approval with npm 2FA makes the package
public; Finalize verifies the registry bytes, integrity, signature, provenance,
and dist-tag.

Expand Down
12 changes: 7 additions & 5 deletions .github/DESKTOP_NIGHTLY.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,19 @@

Desktop Nightly is an ephemeral developer snapshot, not an Apache release. It builds the current `main` commit every day so contributors can try recent Desktop changes and report problems without waiting for an ASF source-release vote.

The workflow gives each snapshot an immutable version such as `0.2.0-dev.20260829.42`. The download page records its exact source commit. A packaged Nightly accepts updates only from `https://nightlies.apache.org/maka/desktop/`, accepts only newer `dev` versions, and verifies that downloaded bytes were attested by `.github/workflows/desktop-nightly.yml` on `main`. A formal Desktop build continues to use the GitHub Release feed and the formal product-release attestation identity.
The npm publication workflow gives each snapshot an immutable version such as `0.2.0-dev.42.20260829`. The run number is the sole ordering authority. After that exact npm version is public, it triggers Desktop Nightly with a version-only artifact; the authenticated workflow event supplies the exact source commit and upstream run. A packaged Nightly accepts updates only from `https://nightlies.apache.org/maka/desktop/`, advances only to a higher run number, and verifies that downloaded bytes were attested by `.github/workflows/desktop-nightly.yml` on `main`. A formal Desktop build continues to use the GitHub Release feed and the formal product-release attestation identity.

Nightly currently uses the same application identity as the formal Desktop. Installing it replaces the existing Maka installation rather than creating a second side-by-side app. Its user data remains in the same location. Testers who need the formal build should reinstall that build before returning to the formal channel.

## One-time setup

1. Ask Apache Infra to allow `apache/maka` to publish GitHub Actions output to `nightlies.apache.org`, provide the SSH `known_hosts` entry through an authenticated channel, and confirm whether retention is service-managed or requires a separate project cleanup job. Do not enable scheduled publication until that retention owner is explicit.
2. Create a GitHub Environment named `nightly` that permits only `main`. Store `NIGHTLIES_RSYNC_PATH`, `NIGHTLIES_RSYNC_HOST`, `NIGHTLIES_RSYNC_PORT`, `NIGHTLIES_RSYNC_USER`, `NIGHTLIES_RSYNC_KEY`, and the Infra-verified `NIGHTLIES_RSYNC_KNOWN_HOSTS` value as Environment secrets. Configure its macOS signing and notarization secrets: `CSC_LINK`, `CSC_KEY_PASSWORD`, `APPLE_API_KEY`, `APPLE_API_KEY_ID`, and `APPLE_API_ISSUER`. Do not expose these secrets to repository-wide or pull-request workflows.
3. Merge the Nightly workflow while it is disabled. After Infra publishing and the Environment secrets are ready, set the repository variable `DESKTOP_NIGHTLY_ENABLED` to `true` and run `Desktop Nightly` manually once.
4. Verify the download page, `latest-mac.yml`, and `latest.yml` under `https://nightlies.apache.org/maka/desktop/`, install both platform artifacts on clean machines, and confirm one automatic update before sharing the channel with testers.
3. Configure npm Trusted Publishing for `apache/maka` and `.github/workflows/npm-publication.yml`, restricted to the `npm-publication` Environment and with both `npm publish` and `npm stage publish` allowed. Do not create or store a long-lived npm token.
4. After npm Trusted Publishing is ready, set `NPM_NIGHTLY_ENABLED` to `true`, run `npm publication` from `main` with `channel=nightly`, and verify the exact npm version and `nightly` dist-tag. This does not depend on Desktop Infra.
5. After Infra publishing and the `nightly` Environment secrets are ready, set `DESKTOP_NIGHTLY_ENABLED` to `true` and start a fresh npm Nightly. Confirm that its successful run triggers `Desktop Nightly`.
6. Verify the download page, `latest-mac.yml`, and `latest.yml` under `https://nightlies.apache.org/maka/desktop/`, install both platform artifacts on clean machines, and confirm one automatic update before sharing the channel with testers.

The scheduled run starts at 18:17 UTC. It audits the shipped dependency closure, builds and verifies macOS arm64 and Windows x64 artifacts, issues and locally verifies Sigstore provenance, appends a new immutable version directory, and advances the mutable update metadata last. A failure before publication leaves both existing platform feeds untouched. Each platform feed file is replaced independently after its complete payload exists, so an interrupted feed transfer may temporarily leave macOS and Windows on different valid Nightly versions. Do not rerun a failed workflow attempt in place; start a fresh manual run so it receives a new version. Historical payload cleanup is separate from publication, targets the Nightlies retention policy, and must never rewrite a published version or delete one referenced by a feed. Apache Nightlies storage is temporary; it must not be used as a formal release archive.
The npm schedule starts at 18:17 UTC. Before changing the npm tag, the workflow requires its run number to exceed the current `nightly` version. Desktop applies the same check against both remote feed files before uploading anything. It then appends a new immutable Desktop version directory and advances the mutable update metadata last. Each platform feed file is replaced independently after its complete payload exists, so an interrupted feed transfer may temporarily leave macOS and Windows on different valid Nightly versions. Do not rerun a failed workflow attempt in place; start a fresh npm Nightly so it receives a new version. Historical payload cleanup is separate from publication, targets the Nightlies retention policy, and must never rewrite a published version or delete one referenced by a feed. Apache Nightlies storage is temporary; it must not be used as a formal release archive.

Remote Runtime Host setup still follows the package identity embedded in the repository manifests. A Nightly does not publish a matching npm package, so clean remote setup is outside this channel until that dependency has its own reviewed snapshot distribution contract.
Remote Runtime Host setup uses the exact `maka-agent@<nightly-version>` package embedded in the Desktop manifest. The npm package is verified before Desktop artifacts become visible, so clean remote setup never depends on an unpublished Runtime Host version.
17 changes: 11 additions & 6 deletions .github/RELEASE_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,12 @@ 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,
`product-release` accepts only `main`, and each requires a reviewer other than the triggering user.
- the `release` Environment accepts only its declared source-candidate tag pattern and requires a
reviewer other than the triggering user;
- `npm-publication` and `product-release` accept only `main`; `product-release` requires a reviewer
other than the triggering user. `npm-publication` has no GitHub
approval gate because scheduled Nightly publication is automatic; formal npm publication still
requires human 2FA approval after staging.

These controls close the check-to-upload and check-to-stage windows. Finalize uses GitHub Actions
OIDC rather than a stored signing key to attest every convenience artifact. Keep the Release in
Expand All @@ -83,8 +87,8 @@ bytes and expected filename are not covered by that protected workflow identity.
5. Confirm `release-identity`, both Desktop matrix entries, `cli-macos-arm64`, 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
reference in its notes, is not marked as a GitHub prerelease or 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, and their required checksums.
7. Inspect the CLI ZIP. It must contain `bin/maka`, `RELEASE.json`, `DISCLAIMER-WIP`, `LICENSE`, `NOTICE`,
Expand All @@ -111,7 +115,8 @@ then rerun. If only the tag exists, the retry creates the missing Draft.
Follow [the npm release runbook](../docs/cli-npm-release.md) against the exact product tag and Draft:

1. Record the successful **Release** workflow run ID and attempt that built the Draft assets. Run
**Stage CLI npm release** from `v<version>` and record its successful run ID and attempt.
**npm publication** with `channel=formal` from `main` 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 product release** from `main`. Its first job verifies the public package
bytes, provenance, signature, and release dist-tag.
Expand All @@ -122,7 +127,7 @@ Keep the GitHub Release in Draft throughout this sequence. The final workflow jo
has passed. It verifies the live Draft digests against the immutable publication record from the
exact successful Release run, creates Sigstore provenance and an offline
`Maka-<version>-attestation.sigstore.json` bundle, then publishes the convenience Release and makes a
stable release Latest in the same GitHub operation; prereleases remain non-Latest. Do not publish or
stable release Latest in the same GitHub operation. Do not publish or
change the Latest designation manually. A failed or rejected npm candidate requires a new product
version; never publish the Draft to work around npm state.

Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/cli-package-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ on:
pull_request:
paths:
- '.github/workflows/cli-package-validation.yml'
- '.github/workflows/npm-publication.yml'
- '.github/workflows/runtime-host-peer-admission.yml'
- 'deny.toml'
- 'native/runtime-host-peer/**'
Expand Down Expand Up @@ -48,6 +49,11 @@ on:
required: false
type: string
default: ''
package_version:
description: Exact Product Nightly version; empty builds the checked-in formal version
required: false
type: string
default: ''
outputs:
release_candidate_artifact_id:
description: Immutable artifact produced by the build job
Expand Down Expand Up @@ -165,6 +171,7 @@ jobs:
merge-multiple: true
- name: Build the release tarball once
env:
MAKA_CLI_NIGHTLY_VERSION: ${{ inputs.package_version }}
MAKA_RUNTIME_HOST_PEER_PREBUILDS: ${{ runner.temp }}/runtime-host-peer-prebuilds
run: npm run release:cli:pack
- name: Upload the immutable release candidate
Expand Down
65 changes: 49 additions & 16 deletions .github/workflows/desktop-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
name: Desktop Nightly

on:
schedule:
- cron: '17 18 * * *'
workflow_dispatch:
workflow_run:
workflows:
- npm publication
types:
- completed

permissions:
actions: read
contents: read

concurrency:
Expand All @@ -31,36 +34,51 @@ concurrency:

jobs:
identity:
if: vars.DESKTOP_NIGHTLY_ENABLED == 'true'
if: >-
vars.DESKTOP_NIGHTLY_ENABLED == 'true' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.display_title == 'npm nightly publication'
runs-on: ubuntu-24.04
timeout-minutes: 10
outputs:
source_commit: ${{ steps.identity.outputs.source_commit }}
source_commit: ${{ github.event.workflow_run.head_sha }}
version: ${{ steps.identity.outputs.version }}
steps:
- name: Reject in-place workflow reruns
if: github.run_attempt != 1
run: |
echo "Desktop Nightly retries require a fresh workflow dispatch" >&2
echo "Desktop Nightly retries require a fresh npm Nightly dispatch" >&2
exit 1

- name: Check out the scheduled main commit
- name: Check out the published Nightly source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
ref: ${{ github.event.workflow_run.head_sha }}
persist-credentials: false

- name: Require the Apache main branch
- name: Require the successful Apache npm Nightly run
env:
UPSTREAM_REPOSITORY: ${{ github.event.workflow_run.head_repository.full_name }}
run: |
test "$GITHUB_REPOSITORY" = apache/maka
test "$GITHUB_REF" = refs/heads/main
test "$UPSTREAM_REPOSITORY" = apache/maka

- name: Resolve the immutable Nightly identity
- name: Download the published Nightly version
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: product-nightly-version
path: ${{ runner.temp }}/product-nightly-version
github-token: ${{ github.token }}
repository: ${{ github.repository }}
run-id: ${{ github.event.workflow_run.id }}

- name: Bind Desktop to the exact npm Nightly version
id: identity
env:
GITHUB_SHA: ${{ github.sha }}
GITHUB_RUN_NUMBER: ${{ github.run_number }}
run: node scripts/desktop-nightly.mjs identity
VERSION_PATH: ${{ runner.temp }}/product-nightly-version/version.txt
run: |
node scripts/product-nightly.mjs inspect-version "$VERSION_PATH" "$GITHUB_OUTPUT"

desktop:
needs: identity
Expand All @@ -84,7 +102,7 @@ jobs:
- name: Reject in-place workflow reruns
if: github.run_attempt != 1
run: |
echo "Desktop Nightly retries require a fresh workflow dispatch" >&2
echo "Desktop Nightly retries require a fresh npm Nightly dispatch" >&2
exit 1

- name: Check out the exact Nightly source
Expand Down Expand Up @@ -200,7 +218,7 @@ jobs:
- name: Reject in-place workflow reruns
if: github.run_attempt != 1
run: |
echo "Desktop Nightly retries require a fresh workflow dispatch" >&2
echo "Desktop Nightly retries require a fresh npm Nightly dispatch" >&2
exit 1

- name: Check out the Nightly publisher
Expand Down Expand Up @@ -297,6 +315,21 @@ jobs:
echo "RSYNC_RSH=ssh -i $ssh_directory/key -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=$ssh_directory/known_hosts -p $NIGHTLIES_RSYNC_PORT"
} >> "$GITHUB_ENV"

- name: Require the Desktop Nightly feed to advance
env:
NIGHTLY_VERSION: ${{ needs.identity.outputs.version }}
run: |
mkdir -p .nightly-current-feed
rsync -rlptDz --protect-args \
--include='/latest-mac.yml' \
--include='/latest.yml' \
--exclude='*' \
"$NIGHTLIES_RSYNC_TARGET/" \
.nightly-current-feed/
node scripts/desktop-nightly.mjs assert-feed-advance \
.nightly-current-feed \
"$NIGHTLY_VERSION"

- name: Publish immutable Nightly payloads
run: rsync -rlptDvz --protect-args .nightly-publish/versions/ "$NIGHTLIES_RSYNC_TARGET/versions/"

Expand Down
Loading
Loading