Commit Graph
291 Commits
Author SHA1 Message Date
Jeremy 38361c33f1 fix(installer): stop the fallback on a doubly-registered copy; check the launcher restore in the execute sequence
- The uninstall-record fallback read the deduplicated install list, so a copy
  registered per-user and per-machine reported only the machine record and the
  update went ahead. It now reads every record of the product code and gives no
  scope when they disagree, so the update stops as the probe path does.
- The launcher policy check returned before looking at InstallExecuteSequence.
  It now requires CraftRestoreLauncherFolder after AppSearch and before
  CostInitialize, so silent updates cannot lose the folder.
- Launcher self-detection also looks in ArtCraft\Launcher (the folder the MSI
  uses) and reads its folder from the publisher-named registry key.
- README notes that a custom folder the account cannot write installs for
  everyone, with an administrator prompt.
2026-10-27 21:34:48 +00:00
Jeremy ed34ecc898 fix(installer): keep updating when the Windows Installer lookup cannot run, and elevate custom protected folders
Two review findings on the MSI update path.

- The update context came from a PowerShell and Windows Installer COM probe,
  and any failure to run it blocked the update with the real error dropped
  (Constrained Language Mode, AppLocker or WDAC, a slow first start). The error
  is now logged. When the probe cannot run at all, the context comes from the
  uninstall record the copy was found by (HKLM is per-machine, the account's
  own HKCU is per-user). A probe that ran and gave no answer, or a copy
  registered for both contexts, still stops the update.
- A fresh install into a custom folder under Program Files passed no scope, so a
  package that defaults to per-user could not write there. A fresh install into
  a folder this account cannot write now asks for the per-machine context, and
  Windows prompts for permission.
2026-10-27 21:13:30 +00:00
aiongg e4f26d24fe ci: use storytold/craft-common-actions at the merged installer-policy commit 2026-10-27 20:52:02 +00:00
Jeremy 2d9c1f8da0 docs(installer): note that the 32-bit all-users folder is Program Files (x86); tidy wording 2026-10-27 12:25:18 +00:00
Jeremy ab4e227536 fix(installer): find the exe in the uninstall record's own scope
Look for the executable in the recorded folder first, then in App Paths and the usual folders of the
record's own hive and registry view, so a per-machine entry never stands in for a per-user record.
2026-10-27 12:25:17 +00:00
Jeremy a83a505bc7 fix(installer): detect apps in the ArtCraft suite folder and describe the per-user default install location 2026-10-27 12:09:01 +00:00
Jeremy f6413ce476 fix(installer): read InstallDir from the uninstall record's registry view; align fixture WiX warnings and CI checkout 2026-10-27 11:45:43 +00:00
Jeremy 3a54a96a64 fix(installer): address scope and ARM64 review feedback 2026-10-27 10:50:58 +00:00
Jeremy 4084181e5a feat(installer): preserve app update context and install path 2026-10-26 22:18:45 +00:00
Jeremy d73819619d native(install): keep MSI updates in the registered installation context
Craft app MSIs are becoming dual-scope packages that default to a per-user
install. An update must land in the same Windows Installer context as the
copy it replaces: a per-machine copy needs elevation and writes HKLM
registrations, and a per-user one must not silently duplicate itself
per-machine (or the other way round). The context is read from the product
code's registration and passed to msiexec (ALLUSERS=1 for per-machine, the
documented ALLUSERS=2 + MSIINSTALLPERUSER=1 for per-user). A fresh install
passes nothing and takes the package's own default, so the current
per-machine-only packages keep behaving exactly as before.

Detection now also reads the per-user places a dual-scope package records
itself: the HKCU InstallDir, App Paths under HKCU, and the user's own
Programs folder.
2026-10-26 15:04:26 +00:00
Dylan M. Taylor 7aafad661a native(install): split the archive unpack and the flat-layout move into helpers (S3776) (#903) 2026-10-25 21:14:39 -04:00
Dylan M. Taylor 40b319458e packaging(macos): read stapler arguments into locals (S7679) (#902) 2026-10-25 21:08:28 -04:00
Dylan M. Taylor 6c5f5ea2f5 Merge pull request #898 from storytold/chore/deps-safe-refresh
chore(deps): refresh serde_json, winresource, plist, ureq, tray-icon
2026-10-25 19:03:58 -04:00
skylar 53edc87ac2 style: rustfmt tray.rs 2026-10-25 16:52:55 -06:00
skylar c77c63dce4 chore(deps): bump serde_json, winresource, plist, ureq, tray-icon 2026-10-25 16:36:25 -06:00
Dylan M. TaylorandCodebuff a9ac66106e build: pin craft-update to craft-libs main (495e597) (#896)
Picks up the update prompt fix that draws its close mark and version pill
without glyphs a font may lack, so the prompt no longer takes the app down
when a bundled face has no ✕ or →.

Part of tracking issue storytold/craft-libs#319

🤖 Generated with Codebuff

Co-authored-by: Codebuff <noreply@codebuff.com>
2026-10-25 17:37:28 -04:00
Dylan M. Taylor e2b1b73a08 refactor: delegate self-update functionality to craft-update (#871)
* refactor: delegate self_update to craft-update

* ci: point craft-update patch to dylanmtaylor/craft-libs branch

* nix: set allowBuiltinFetchGit for git dependencies

* chore(deps): update craft-update commit

* build: pin craft-update to storytold/craft-libs fe61243 and drop the temporary patch

* fix(update): share craft_update::Stop so pause and cancel reach the self-update

* build: pin craft-update to the dirs-free, zip 9 build

Satisfies cargo-deny: no MPL-2.0 option-ext, no zip 8 advisories, and a versioned git dependency instead of a wildcard.

* build: pin craft-update to craft-libs main (b9ba47f)
2026-10-25 13:40:46 -04:00
skylar taylor-barrick 4ab652afd8 Migrate Craft Launcher to egui 0.37 (#873)
* Migrate Launcher to egui 0.37 and preserve current-main behavior

* egui037: record final published pins and local qualification

* fix(ui): gate CJK language drawing until fonts are installed

* Document migrated launcher UI contracts and regression invariants
2026-10-25 10:49:00 -04:00
Brandon ThomasandClaude Opus 5.5 932e718bbc Release 0.8.1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.8.1
2026-10-25 09:52:58 -04:00
Brandon ThomasandClaude Opus 5.5 1da85f9f61 macOS packaging: retry stapler when Apple's CloudKit drops the connection
The 0.8.0 release's macOS job failed with 'The validate action failed! Error 68' (NSURLErrorDomain -1005 from api.apple-cloudkit.com) after both notarizations were Accepted. Same helper as VectorCraft's packaging/macos/package.sh (craftrules learnings/ci-and-release.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 09:52:35 -04:00
Brandon ThomasandClaude Opus 5.5 75274994e7 Release 0.8.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 09:44:58 -04:00
Dylan M. Taylor f0cb3b0439 Merge pull request #870 from dylanmtaylor/security/xtask-mirror-hardening
fix(security): enforce bounded reads, deadlines, and terminal escaping in local mirror
2026-10-24 22:37:29 -04:00
Dylan M. Taylor 2d122457d1 Merge pull request #869 from dylanmtaylor/security/single-instance-challenge-response
fix(security): implement mutual challenge-response for single-instance IPC
2026-10-24 22:37:26 -04:00
Dylan M. Taylor 44cbaeedce Merge pull request #868 from dylanmtaylor/security/proxy-loopback-credential-logging
security: bypass proxy for loopback and suppress HTTP wire credential logging (F-003, F-005)
2026-10-24 22:37:23 -04:00
Dylan M. Taylor 5f8cfd3c9a Merge pull request #867 from dylanmtaylor/security/artifact-identity-binding
security: bind artifact URL identity in install and self-update (F-010, F-011, F-015)
2026-10-24 22:37:18 -04:00
Dylan M. Taylor ca67541cbd Merge pull request #865 from dylanmtaylor/security/decoded-payload-limits
security: bound decoded HTTP responses and screenshot decoding (F-006, F-008, F-009)
2026-10-24 22:37:15 -04:00
Dylan M. Taylor 3f84a88967 Merge pull request #864 from dylanmtaylor/security/release-url-confinement
security: confine release HTML URLs and sanitize browser open links (F-004, F-007)
2026-10-24 22:37:12 -04:00
Dylan M. Taylor fab99e46e8 Merge pull request #866 from dylanmtaylor/security/tar-archive-filesystem-safety
security: harden archive extraction, layout normalization, and file enumeration (F-001, F-002, F-012, F-013, F-014)
2026-10-24 22:36:58 -04:00
Dylan M. Taylor 248db064eb security(install): skip records under symlinked directories in remove_files 2026-10-24 22:36:35 -04:00
Dylan M. Taylor 6bd7efa57c install(freebsd): record non-traversed symlink entries in tree manifest 2026-10-24 22:25:12 -04:00
Dylan M. Taylor ad40581d64 fix: implement constant-time equality in pure Rust without modifying Cargo.lock 2026-10-24 22:23:33 -04:00
Dylan M. Taylor a9ac09060a fix(install): parse release tag and filename from release download URLs
- Validates tag and artifact filename from /releases/download/ URLs without breaking mock/loopback URLs.
2026-10-24 22:21:43 -04:00
Dylan M. Taylor f8c691e55c fix(clippy): remove redundant let binding in rogue-server test 2026-10-24 22:18:58 -04:00
Dylan M. Taylor 72b9418c05 fix(security): address review comments on proxy and logging
- Redact Bearer tokens with multiple spaces and add regression test.
- Explicitly disable proxies on direct and direct_download ureq agents.
- Add direct_download agent with download timeout profile for loopback downloads.
- Preserve proxy username, password, and NO_PROXY exclusions in proxy::pick().
2026-10-24 22:18:27 -04:00
Dylan M. Taylor df0b2e4d96 fix(install): enforce URL filename and tag identity checks when release.version is absent
- Retains download URL filename and release tag checks in bind_artifact_version even when semantic version parsing is unavailable.
2026-10-24 22:15:21 -04:00
Dylan M. Taylor d31ee123b5 fix(install): defer directory unpacking, use effective entry size, and fix FreeBSD paths
- Uses entry.size() rather than header.size() to account for PAX size headers in cumulative unpack limits.
- Defers directory extraction until child entries are written to avoid restrictive directory modes preventing child file creation.
- Returns error when tree file enumeration exceeds limits or fails to read directory.
- Supports both /usr/local and ~/.local install prefixes based on needs_root.
2026-10-24 22:14:22 -04:00
Dylan M. Taylor 6f2c7e7b44 fix(http): restrict oversized check to resuming partial downloads
Allows a full 200 response to replace an existing oversized partial file instead of erroneously rejecting it.
2026-10-24 22:12:07 -04:00
Dylan M. Taylor 07cd50b3f0 fix(security): validate fallback release URL and reject dot segments in feed repos
- Validates constructed fallback release URLs with safe_release_html_url to prevent command injection from malformed tags.
- Rejects empty, '.' and '..' path components in RawApp::into_app and RawRepoRename::into_rename.
2026-10-24 22:11:28 -04:00
Dylan M. Taylor ec40f2e1cd fix(security): enforce bounded reads, deadlines, and terminal escaping in local mirror
Resolves F-019 (CWE-400), F-020 (CWE-117), and F-021 (CWE-117).
- Enforces per-byte read deadlines and socket timeouts during header parsing.
- Bounds maximum line length (8 KiB) and maximum total headers size (64 KiB) to prevent slowloris/DoS.
- Sanitizes request method and target before logging to stderr to prevent ANSI escape sequence injection.
2026-10-24 22:10:07 -04:00
Dylan M. Taylor 886fa562d3 fix(security): implement mutual challenge-response for single-instance IPC
Resolves F-016 (CWE-522) and F-017 (CWE-287).
- Replaces cleartext transmission of persistent bearer token with ephemeral mutual challenge-response.
- Client initiates handshake with ephemeral client nonce without disclosing token.
- Server proves possession of per-user token via SHA-256 HMAC-style proof before client discloses client proof.
- Uses constant-time equality check to prevent timing leaks.
- Replayed or stale auth proofs across handshakes are rejected via fresh server nonces.
2026-10-24 22:07:59 -04:00
Dylan M. Taylor 004fe617af security: bypass proxy for loopback and suppress HTTP wire credential logging (F-003, F-005) 2026-10-24 21:58:20 -04:00
Dylan M. Taylor 0594ec7f03 security: bind artifact URL identity in install and self-update (F-010, F-011, F-015) 2026-10-24 21:52:05 -04:00
Dylan M. Taylor 5ec7596b61 security: harden archive extraction, layout normalization, and file enumeration (F-001, F-002, F-012, F-013, F-014) 2026-10-24 21:49:55 -04:00
Dylan M. Taylor ab5e83ffd1 security: bound decoded HTTP responses and screenshot decoding (F-006, F-008, F-009) 2026-10-24 21:47:13 -04:00
Dylan M. Taylor 416a3ff148 security: confine release HTML URLs and sanitize browser open links (F-004, F-007) 2026-10-24 21:42:38 -04:00
Brandon ThomasandClaude Opus 5.5 c0fa1c69f4 Tests: start the tray-sleep clock before the waker thread (#850)
with_no_window_it_sleeps_until_woken read Instant::now() after spawning
the thread whose 200 ms pause it measures, so a runner that held the
test thread back between the two failed started.elapsed() >= pause
(seen on main's ubuntu CI). Read the clock first.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 02:54:12 -04:00
Brandon ThomasandClaude Opus 5.5 fdcd6fb631 Tests: retry the version probe of a script a test just wrote (ETXTBSY) (#848)
reads_binary_version_when_the_cli_uses_the_display_name_or_a_former_id
failed now and then: another test thread that forks while the script is
still open for writing holds that descriptor until it execs, and running
the script in that window fails with ETXTBSY. Both binary_version tests
now retry a miss for up to a second.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 02:17:58 -04:00
Brandon ThomasandClaude Opus 5.5 517786fc81 Tests: pick Simplified Chinese through AccessKit now that it sorts last (#720) (#849)
#720 lists the languages by their own name, so 简体中文 is now the last
row of the language picker, below the fold of the popup's scroll area.
The pointer click that kittest's click() simulates landed outside the
visible part, nothing was chosen, and the Chinese test failed on main on
both Linux (no font: language stayed "en") and Windows. Clicking via
AccessKit doesn't need the row on screen; the picker itself is fine,
people scroll it.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 02:17:47 -04:00
c8870ccf8c Say once, the first time, that closing the window keeps the launcher in the tray (#376)
The close button parks the launcher in the tray by design, but to
someone who doesn't know that, a window that vanishes with nothing to
show for it looks hung, and the reports end with killing the process
(#45, #215).

The first time the window closes to the tray, a system notification
says the launcher is still running, that it's in the tray, and that
Settings can turn this off. `LauncherUi::hidden_to_tray` sends it
through the host and records it in `Settings::tray_hint_shown`, so it
happens once per install. The desktop shell calls it from the
close-request path only, for both ways of going to the tray; a window
hidden from the tray icon, or started hidden at login, gets no hint.

Two strings, with rows in all ten complete catalogs. A UI test checks
the hint is sent once and recorded.

Co-authored-by: YangXZ2008 <141027290+YangXZ2008@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-24 01:44:17 -04:00
803d5f57a4 fix(windows): launch system helpers by absolute path (#815)
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-24 01:44:10 -04:00