Repository navigation
Desktop release packages; a release workflow that keeps signing out of the build - #257
Merged
Merged
Conversation
This was referenced Oct 1, 2026
ymote
force-pushed
the
feat/desktop-kernel-finder
branch
from
October 2, 2026 03:46
387f8f7 to
fc5f8c9
Compare
ymote
force-pushed
the
feat/desktop-packaging-v2
branch
from
October 2, 2026 03:46
fd9ea27 to
3b906d0
Compare
This was referenced Oct 2, 2026
ymote
force-pushed
the
feat/desktop-kernel-finder
branch
from
October 2, 2026 19:58
fc5f8c9 to
5f2db0c
Compare
…t of the build Port of #94 onto the packaged-kernel lookup of the previous commit, with its review findings fixed. desktop/scripts/package.py builds the desktop in Makepad's packaged-resource mode with remapped paths, stages every linked crate's resources, builds the pinned octos kernel with tools/kernel-artifact.py --host and stages it with its receipt (the kernel beside the executable, the receipt with the resources, where crates/kernel looks), and packages it with cargo-packager: macOS .app/.dmg, Windows NSIS, Linux .deb/.AppImage. It needs no secret and always builds unsigned: it strips cargo-packager's signing variables from the build environment. tools/release-scan.py refuses private paths and names inside the packages (new: --dmg-bytes-only, for the Linux release job). A packaged build never looks for an OctoSense checkout: not where it was built, not its working directory, not its executable's ancestors (paths::packaged()), so starting it inside someone else's checkout cannot make it build and run that code. Its theme sheets come from the binary. .github/workflows/release-desktop.yml: - plan resolves what to build. A tag push or a manual run naming a tag checks out that tag (not the branch the run started from), and every job verifies HEAD is the planned commit; the release job verifies it is the tag's commit before attaching. - package (macOS, Windows, Linux) builds and scans unsigned packages with no secrets and uploads them as artifacts. - sign-macos and sign-windows run in the protected `release` environment, only for a tag push or a manual run from main. They download the packages and run codesign/notarytool/signtool only; nothing checks out or builds code there. The kernel's receipt is updated to its signed bytes before the app is sealed. The Windows certificate is used from a file, never imported; the keychain, the .p12 and AuthKey.p8 are deleted in always() steps. Without the secrets they pass the packages through unsigned. - Pull requests get plan and package only: no secrets, no signing. - Every action is pinned to a full commit SHA, and Rust to 1.97.1. tools/ci_local.py lists release-desktop.yml in NOT_LOCAL with its reason, so --check-drift skips it (and fails if the entry goes stale); the desktop job runs the packaging tests. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Windows package job failed on "mDNS .local host name: sen*** (16 chars)" in octosense.exe. It is no machine: matrix-sdk, which Rinx links, names media still in its send queue mxc://send-queue.localhost/... (LOCAL_MXC_SERVER_NAME) and compares server names with it. x86-64 code does that 16 bytes at a time, so the constant's first 16 bytes, "send-queue.local", are a constant of their own, and what follows them is whichever constant the linker put next. In the Windows build that one starts with a non-name byte, so the scanner reads a complete .local name. Linux has the same 16 bytes followed by a letter (no match), and an earlier Windows build had them followed by "uthorized_client". DEPENDENCY_LOCAL_NAMES exempts that exact name, beside the product's own (PRODUCT_LOCAL_NAMES), with a comment saying whose constant it is and why it appears. Every other .local name is still found, including any that merely contains it (my-send-queue.local, send-queue2.local); tests cover both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ymote
force-pushed
the
feat/desktop-packaging-v2
branch
from
October 2, 2026 22:07
72711e3 to
e1bca5a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Installable desktop packages (macOS
.app/.dmg, Windows NSIS, Linux.deb/.AppImage), plus a release workflow that keeps signing out of the build. Replaces #94, with every review finding fixed.Stacked on #256 (the packaged-kernel finder). The base is
feat/desktop-kernel-finder. Merge #256 first, then retarget this PR tomain.Packaging (from #94, updated)
desktop/scripts/package.pyis Desktop release packages (macOS .app/.dmg, Windows NSIS, Linux .deb/.AppImage) and release-desktop workflow #94's script, updated:APPLE_SIGNING_IDENTITY,APPLE_CERTIFICATE, …) from the build's environment, so a stray one never signs.tools/kernel-artifact.py --host's steps (with the same remapped paths) and staged with itsstage.tools/build-desktop.pyis gone.Contents/MacOS/octos-kernel), and its receiptoctos-kernel.jsonships with the resources (Contents/Resources, the Windows install dir,usr/lib/octosense). That is where Desktop: find the packaged octos kernel and refuse one of another revision #256 looks.release.json,Info.plistand entitlements are Desktop release packages (macOS .app/.dmg, Windows NSIS, Linux .deb/.AppImage) and release-desktop workflow #94's.tools/release-scan.pyis Desktop release packages (macOS .app/.dmg, Windows NSIS, Linux .deb/.AppImage) and release-desktop workflow #94's, plus--dmg-bytes-onlyfor the Linux release job. The release job cannot mount a.dmg; its contents were already scanned on macOS, and the same app is scanned again in the.app.zip.paths::project_root()returnsNonein a packaged build. It ignores where the build ran, the working directory and the executable's ancestors (Desktop release packages (macOS .app/.dmg, Windows NSIS, Linux .deb/.AppImage) and release-desktop workflow #94 still searched the working directory). Starting the installed app inside a hostile checkout therefore cannot load itsconfig/apps.jsonand build or run its code. Theme sheets come from the binary.release-desktop.yml(rewritten for the review)planpackage(macOS 14, Windows 2022, Ubuntu 22.04)sign-macos,sign-windowsmainreleaseenvironment. They download the artifacts and run codesign/notarytool and signtool only; nothing is checked out or built.releasemainwith a tag anddry_runoffreleaseenvironment,contents: writeHow each review finding is fixed:
.pfxis used from a file by signtool and never imported into a certificate store.refs/tags/<tag>. Every job verifies HEAD against the planned commit, and the release job also checks HEAD against the tag's commit on the server before attaching.planandpackageonly: no secrets, no signing. The signing secrets are environment secrets ofrelease.AuthKey.p8left on disk.AuthKey.p8is written with umask 077 and removed after notarytool. Analways()step also removes it, along with the temporary keychain, the.p12and the.pfx.1.97.1.tools/ci_local.pylistsrelease-desktop.ymlinNOT_LOCALwith its reason.--check-driftskips it, and reports drift if the entry ever names no workflow or a workflow ci-local runs.check_drift() == [], and a test covers the exclusion. The desktop job now also runsdesktop/scripts/test_package.py;tools/test_release_scan.pyalready runs there.Cargo.lockchange in the stack is Desktop: find the packaged octos kernel and refuse one of another revision #256'ssha2.Signing detail: codesign rewrites the kernel, and #256 checks the kernel's SHA-256. So
sign-macossigns the kernel first, rewrites the receipt inContents/Resourcesto the signed bytes, then seals the app. After that it builds a new.dmg, signs it, notarizes it and staples both. Without the secrets the sign jobs pass the packages through unsigned, with a warning.Verified locally (macOS arm64, unsigned)
/private/tmp/…,CARGO_HOMEoutside the home directory) withpython3 desktop/scripts/package.py. Output:OctoSense.app(358 MB) andOctoSense_0.1.0_aarch64.dmg(148 MB). The kernel was built from source at the pinnedae230ce(octos 2.0.3-rc.13 (ae230ce 2026-10-01)). The receipt is inContents/Resourcesand its SHA-256 matchesContents/MacOS/octos-kernel.tools/release-scan.pyover the.dmg(mounted), the.app.zip, the package receipt, the staged resources, the kernel, the binary and the.appcame backclean: 7 artifact(s), 907 file(s), 8 pattern(s)..appout of the.dmg, renamed the build tree out of reach, and ran it hidden withOCTOS_APP_CORE_BINunset and its working directory inside another OctoSense checkout'sdesktop/. Opening the Assistant (F8) with a fixture provider profile (no LLM request) loggedoctos-core: starting kernel 1: …/OctoSense.app/Contents/MacOS/octos-kernel serve --stdio …, and the pane showed "The system agent · ready".config/apps.json), so the checkout was ignored.desktop/scripts/system_apps_remote.shwithOCTOSENSE_BINset to the packaged binary: every check passed (launcher lists all system apps, Photos draws, Mail's host sign-in sheet, AI providers, bundles unpacked, no panic, no unexpected[ui-hang]).codesign --options runtime --sign -of the kernel (its SHA-256 changed). After that,codesign --entitlements … --sign -of the app passedcodesign --verify --deep --strict, and the re-signed app started its kernel.python3 -m unittest discover -s tools -p 'test_*.py': 91 tests pass.desktop/scripts/test_package.py: 10 tests pass.tools/test_ci_local.py: 15 tests pass, including the PyYAML comparison of every workflow.check_drift()returns[].actionlintis clean.tools/setup.py --check --cargopasses.cargo check --lockedpasses for-p octosense-shell -p octosenseand-p octosense --features mobile-apps.octosense::pathstests pass (new:a_packaged_build_has_no_checkout_even_inside_one).Not verified
octosense.exeandoctos-kernel.exeit installs are not, because re-signing them would mean rebuilding the NSIS installer in the signing job.desktop-vtag was created and nothing was released.Repository settings needed before signing works
Create the environment
release(Settings → Environments). Restrict its deployment refs tomainand tags matchingdesktop-v*, and add required reviewers if wanted.Add the secrets there, as environment secrets:
APPLE_CERTIFICATE,APPLE_CERTIFICATE_PASSWORD,APPLE_SIGNING_IDENTITY,APPLE_API_KEY,APPLE_API_ISSUER,APPLE_API_KEY_P8.WINDOWS_CERTIFICATE,WINDOWS_CERTIFICATE_PASSWORD.RELEASE_SCAN_EXTRA.If any of these exist as repository secrets, move them and delete the repository copies.
tools/ci-local.shdoes not run this workflow, by design.🤖 Generated with Claude Code