Commit Graph

18 Commits

Author SHA1 Message Date
ethernet
14b1e7220b feat(release): derive canaries from stable build identity 2026-09-21 22:02:46 -04:00
ethernet
b37acb8389 feat(release): dynamic R2-owned channels and preview retirement (rounds 1-2)
Checkpoint before round-3 reduction (two-tier retirement derived from
product identity). Includes:

- R2 channel protocol (release_channels.py, channel-protocol.ts): records,
  builds, manifests, retired channels with pinned destinationHead and
  receiverProtocol; fail-closed readers in both languages
- One shared native manifest/feed writer (scripts/bundles/channel_artifacts.py)
- Scoped/disposable R2 publication, fork isolation before credential
  access, canary bootstrap verification of its own promoted outputs
- Channel source CLI: typed SourceTarget, source-channel resolution,
  retirement downgrade refusal
- Desktop channel resolver/strategy, install-stamp/build-stamp receiver
  ownership (stable-owned S/T candidates), single-flight updater operation
- Cross-package retirement machinery (receiver/host/preservation/
  compatibility/connections/dialog/discovery, backup_migration strict
  snapshots with retained-link inventory, empty-dir preservation,
  connection-collision resolution, URL-credential rejection)
- Native install harness (tests/install/channel-retirement-*) and
  install-e2e retirement jobs
- checkout-source.test.ts transport shim now covers build_opener().open
  (was silently hitting the real network in CI)

Removed secondary certification protocol (channel_qualification.py) per
approved round-2 plan. All focused suites green at checkpoint; native
cross-package journeys unverified (to be deleted in round 3).
2026-09-14 10:26:36 -04:00
ethernet
bf75bc2516 feat(ci): require desktop chat after bundle and install builds
Share the real composer, provider-witness and completed-reply check across
post-build bundle smoke and desktop-bearing install/update checkpoints.
Keep native automatic-relaunch proof separate from post-update chat.

Download receipt-bound artifacts without release credentials and install
DMG, ZIP, MSIX and universal MSIXBUNDLE on each native architecture.
Split Windows assembly from feed publication; publish tested bytes only.
Bind candidate smoke results into the manifest used by stable promotion.

Verify historical/source provenance without assuming a version IPC commit,
strip CI identity from source build children, and use the actual Electron
PID rather than Playwright's Windows launcher wrapper.

Validation: real Linux Electron chat and sequential OLD/NEW source smoke
with preserved history; 145 targeted Python tests and 14 JS tests passed;
TypeScript, shell/PowerShell parsing and workflow checks passed.
Native macOS/Windows deployment and historical upgrades need Actions proof.
2026-09-13 19:57:38 -04:00
ethernet
690316c589 Give release Python sole ownership of App Installer descriptors 2026-09-12 19:00:39 -04:00
ethernet
c4e2d937f7 fix(desktop): isolate canary and commit package identities
Canary and commit builds must not replace stable or share its desktop
state. Package names alone are insufficient because Electron reads the
product name before main initializes its paths. Pin nonstable userData
before the first lookup, and keep the packaged identity independent of
runtime build variables.

Keep release artifact filenames unchanged. Qualify payload CLI names,
route each nonstable MSIX alias to its own entrypoint, and copy the
immutable desktop provenance into the embedded Python checkout. Only
stable releases can use the official Store identity.

Targeted validation: 75 JavaScript tests passed, 2 platform skips;
15 Python tests passed with file retries disabled. Native Windows SDK
manifest proof is tracked separately. Full app install, signing and macOS
launch validation are not claimed.
2026-09-11 19:59:38 -04:00
ethernet
063cf4428a feat(release): build and stage admitted commits without channels
Keep commit admission on the trusted workflow checkout and reject mixed
release inputs before loading repository code. Stage every built product
under its commit with receipt-bound summary links, never channel writes.

Build both Windows universal bundles through the existing SDK scripts.
Keep Store calendar versions separate from sideload app versions so zero-
major app versions remain packageable. Reject invalid arguments before
modifying bundles. Bind desktop and Termux versions to the source commit,
and record Termux cache provenance without labeling commits as tags.

Verification: 77 Python tests and 36 JS tests passed. Real makeappx packed
and unpacked disposable per-arch and universal packages. Seven official
workflow-expression checks, actionlint, syntax, lint and prose passed.
No signing, installed-app update, Android build, or remote dispatch ran.
2026-09-10 05:42:18 -04:00
ethernet
d36562ac9f fix(release): provision Windows bundle tools on cache misses 2026-09-08 14:32:30 -04:00
ethernet
67e5572ed1 fix(signing): share the verified runtime resolver for MSIX bundles
The envelope signer selected a cached .NET ZIP as DOTNET_ROOT. Its local
cache walker included archive and state files beside the extracted runtime.
The payload signer already filters these entries correctly.

Reuse the payload signer's runtime and dlib resolvers. Remove both duplicate
cache walkers and cover archive/state siblings in the shared resolver tests.

The actual bundle script failed before this change and passed afterward
with the same published packages and real Azure signing. The 4.9 GB bundle
passed native signature verification. All 34 focused tests pass. Remote
publication still needs a release run containing this fix.
2026-09-08 04:20:20 -04:00
ethernet
b0ab0162b0 feat(release): gate stable promotion through the full release pipeline
Run the entire CI workflow before Docker build and tests. Require Nix,
native payload smoke tests, install/update E2E and signed-package upgrade
acceptance before publishing. Keep Desktop Playwright E2E deferred.

Archive tested Docker images and signed bundle candidates with provenance
and hashes. Publishers consume those exact artifacts without rebuilding.
Advance stable channels only after all required publications succeed.
Keep canaries on their separate path and reject direct stable-builder
publication that bypasses the gate.

Move shared release transport, manifests and gates to Python. Keep native
Electron adapters in JS and share feed/MIME facts as JSON. Replace the
R2/feed JS implementation and move its protocol tests to Python.

Verified targeted Python and JS tests, real loopback transport and CLI
execution, temporary Git admission, workflow graph lint, and typechecks.
No live stable release was run. Native signing, package upgrades and real
registry/Store promotion still need their release-run receipts. Separate
services cannot promote atomically. A promotion failure keeps the run red.
2026-09-07 14:40:10 -04:00
ethernet
92686159d1 fix(pm): integrate audited runtime and lifecycle repairs
Prepare dependency generations before selecting them. Keep shipped tool
bytes separate from writable additions, and store facts beside their entries.
Validate proposed plugin sets before config publication. Restore the previous
config if the facts write fails.

Consolidate duplicate updater, backup, setup, and voice helpers. Repair
launcher selection, dependency consumers, download ownership, update feeds,
and native Windows process and file handling.

Verification: 206 changed/prior-failing Python files reported 4630 passed,
one failed, and 330 skipped. Fix the remaining Hindsight fixture boundary.
The final targeted rerun reported 234 passed and two skipped. The store
review regression batch reported 83 passed and one skipped. Desktop
TypeScript checks, 56 selected Electron tests, 24 release tests, and the
removed-import/compatibility guards passed.

This is an integration checkpoint, not full audit acceptance. The complete
Python suite has not run on this fixed tree. Crash-atomic plugin publication,
generation cleanup, receipt correlation, and packaged lifecycle acceptance
remain open in docs/pm-audit-status.md.
2026-09-05 22:36:48 -04:00
ethernet
c9e1592622 fix(ci): restore acs timestamp on the msixbundle dlib sign + retry
The previous fix split the bundle sign into two passes (dlib sign with no
/tr, then a separate `signtool timestamp` against digicert). That was
wrong for MSIX: signtool silently exits 3 on an untimestamped
.msixbundle (appx signatures require a timestamp), and the ATS dlib
cannot parse a third-party timestamp server's response at all.

Restore the original single sign call with
`/tr http://timestamp.acs.microsoft.com /td SHA256` — the only
timestamp server the dlib can speak (electron-builder's default, and
what the build legs' .msix sign uses) — and wrap it in a 3-attempt
retry so acs's intermittent flakiness never fails the bundle (signtool
replaces the signature on re-sign, so a retry is safe).

Verified: node --check, 215 signing/r2/appinstaller tests pass; skill
reference corrected (MSIX bundle sign requires the acs timestamp;
digicert -> "no content extracted", no /tr -> silent exit 3).
2026-09-02 01:07:01 -04:00
ethernet
d8fa6c2463 fix(ci): sign the msixbundle envelope in two passes — dlib sign, then public RFC3161 timestamp
The publish-win32-updater job died at the bundle-envelope sign with
signtool exit 3 and "@url:`http://timestamp.digicert.com`: no content
extracted". Passing /tr on the SAME signtool call as /dlib hands the
timestamp URL to the Azure Trusted Signing dlib (`@url:` form), which
cannot extract a token from a third-party RFC3161 server.

Split it like the repo's own batch-sign-binaries.mjs (the pattern the
build legs use, and which the batch-sign tests pin):
1. `signtool sign /fd SHA256 /dlib <dlib> /dmdf meta bundle` — NO /tr.
2. `signtool timestamp /tr http://timestamp.digicert.com /td SHA256
   bundle` — NO dlib; signtool does the RFC3161 exchange itself (probed:
   digicert returns Status: Granted for a plain timestamp query).
3. `signtool verify /pa`.

The timestamp pass also retries (3 attempts) so a flaky server never
forces a re-sign of the ~2.7GB bundle.

Verified: node --check, 215 signing/r2/appinstaller tests pass.
2026-09-01 23:14:59 -04:00
ethernet
a9793b3ea6 refactor(release): rename the nightly release channel to canary
The fast-moving desktop prerelease channel is now "canary" everywhere:
the tag shape (vX.Y.Z-canary.<ts>), the electron-updater/R2 feed dirs
(canary.yml / releases/<os>/canary/), the update-channel consts and CLI
choices, the MSIX build-number derivation, the App Installer channel
paths, and the Windows Store flight var (MS_STORE_CANARY_FLIGHT_ID).

Also renames the scheduled workflow to canary-release.yml and the
release test file to test_release_canary.py, and flips the CLI flags
(--canary / --prune-canaries / prune-canaries subcommand).

Unrelated "nightly" mentions are untouched: Brave's own browser channel
(browser_connect), cron scheduling prose (README, i18n, cron/browser/
kanban docs, zh-Hans), upstream skill docs (comfyui/unsloth/torchtitan),
evals fixtures, Node's node-nightly prereleases, and cron job names in
gateway tests.

Note: MS_STORE_NIGHTLY_FLIGHT_ID was renamed to MS_STORE_CANARY_FLIGHT_ID
in the workflow — the matching repo/org variable on GitHub must be
renamed in repo settings for the Store flight ring to keep working.
2026-09-01 22:15:17 -04:00
ethernet
65d0f03e52 ci(desktop): re-enable the Windows Store submission with nightly flights
Flip publish-win32-store back on (was a dummy skip), restore the store
variant build in build-win32, and wire the MSStore CLI submission:

- stable tags → production submission: msstore submission delete (clear
  any pending, tolerant) then msstore publish <Store-*.msixbundle> -id.
- nightly tags → package flight ring: msstore flights submission delete
  then msstore publish -f <flightId> -id. delete-then-replace so the
  newest nightly always wins the single-slot submission queue (chosen
  over skip-if-pending: always ship the newest, at the cost of cert
  churn).
- Gate: runs for stable when MS_STORE_PRODUCT_ID is set; runs for
  nightly only when MS_STORE_NIGHTLY_FLIGHT_ID is ALSO set, so the
  flight ring stays off until the flight exists in Partner Center.
- The r2 staging loop archives the per-arch Store-*.msix again (and the
  assembled universal bundle is archived by the store job).

Credentials (release-signing environment): MS_STORE_TENANT_ID,
MS_STORE_SELLER_ID, MS_STORE_CLIENT_ID, MS_STORE_CLIENT_SECRET
(secrets); MS_STORE_PRODUCT_ID, MS_STORE_NIGHTLY_FLIGHT_ID (vars).

Verified: yaml parses + needs graph resolves, store variant build
restored, bash branch harness (nightly→flight / stable→production)
executes the right msstore invocations, 215 js tests pass.
2026-09-01 21:30:23 -04:00
ethernet
f437776030 ci(desktop): disable the Windows Store submission path for now
App installer feeds are the update path; the MSStore flow is parked.
publish-win32-store is now a dummy skip (ubuntu notice step, kept in the
dependency graph so nothing downstream changes), and build-win32 no
longer builds the store variant (--variant=store removed). The r2
staging loop's Store-* archive branch and the store-bundle script stay
in the tree, documented, for re-enable.

Verified: yaml parses, needs graph resolves, no --variant=store remains
in the build step.
2026-09-01 18:13:47 -04:00
ethernet
5f3f9f3e72 ci(desktop): split release pipeline per-OS; gate MSIX work on windows only
The msixbundle + finalize jobs were both gated on the entire 6-leg build
matrix, so macos + linux legs blocked the win32 App Installer feed and
everything else downstream.

Restructure desktop-bundled-release.yml into per-OS jobs:

- build-win32 (x64 + arm64) — the only active builder legs; builds the
  bundled + Store variants, audits arch, uploads *.msix, stages to R2.
- build-darwin / build-linux — dummy skips for now (no macOS updater arm;
  linux unshipped). Matrix kept so downstream jobs stay green; re-enable
  by restoring the build body + runners.
- publish-win32-updater (was msixbundle) — needs build-win32 only; stages
  the App Installer feed (.appinstaller + universal .msixbundle).
- publish-win32-store (NEW, parallel) — bundles the two Store-*.msix into
  one universal Store .msixbundle and submits it to the Windows Store via
  the MSStore CLI (microsoft/microsoft-store-apppublisher@v1.4). Stable
  tags only; gated on MS_STORE_PRODUCT_ID var so it stays skipped until
  the release-signing environment is configured. The store bundle is left
  unsigned on purpose — Partner Center re-signs on ingestion.
- publish-darwin-updater (was finalize) — dummy skip; no mac feed to
  publish until the darwin electron-updater arm returns.

Shared plumbing: resolveWinSdkTools moves into msix-shared.mjs (single
resolver for both bundle jobs, kills the dead candidates var); new
bundle-store-msixbundle.mjs bundles the store per-arch packages and
prints the bundle path on stdout for the workflow.

Verified: node --check all scripts, yaml parses + needs graph resolves,
107 r2-release tests pass.
2026-09-01 15:53:55 -04:00
ethernet
029099b249 fix msix bundle signging with better timestamp sig 2026-09-01 10:32:12 -04:00
ethernet
47f4ab3a17 feat(desktop): bundle, publish, and update the desktop app as MSIX
Wire the desktop app onto the pm store for real distribution:
- MSIX bundle: electron-builder config, appx assets, manifest, copilot
  key + deep-link routing, App Installer + Windows Store variant
  (sign only the msix; inner binaries covered by the package block map)
- Rust CLI shim (apps/desktop/shim) — bundled builds run from the store
  python + shim, never the venv; payload symlinks relativized so the
  relocatable venv survives relocation
- Cloudflare R2 release pipeline: publish binaries + update feeds,
  nightly channels/tags, stamp-first version resolution
- Update system: gate, uninstall steward, boot bootstrap, release
  channels, update receipts
- install.ps1 reduced to a 361-line stage-protocol bootstrapper (heavy
  deps are pm's job); darwin updater + update-channel mirror ripped
- doctor: main's re-landed TCC anchor kept, termux branches removed

Rebuilt from ethie/pm onto the pm-store stack. 22 hot files hand-merged;
uv.lock + package-lock.json keep main's newer dep tree; test_engines
reads the pm/lock.json pin; lazy_deps.py deleted (all 222 importers
migrated to pm in the foundation commit).
2026-08-31 18:00:48 -04:00