Skip to content

fix(core): boot embedded Postgres under non-admin user on elevated Windows#2117

Merged
gsxdsm merged 7 commits into
mainfrom
feature/win-pg-verify
Jul 15, 2026
Merged

fix(core): boot embedded Postgres under non-admin user on elevated Windows#2117
gsxdsm merged 7 commits into
mainfrom
feature/win-pg-verify

Conversation

@gsxdsm

@gsxdsm gsxdsm commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

Windows embedded Postgres verification (CI windows-latest and elevated desktop) fails because PostgreSQL refuses to run under an administrative token:

Execution of PostgreSQL by a user with administrative permissions is not permitted.

GitHub Actions runners execute as runneradmin elevated, so the existing test:embedded-postgres smoke (and any elevated Local-mode desktop launch) cannot start the server.

Fix

  • When isWindowsElevatedAdmin() is true, initdb / clients stay as the launcher, but the postgres server is started as a dedicated non-admin local user (fusion-pg) via PowerShell Start-Process -Credential.
  • Readiness waits on the postgres log line database system is ready to accept connections with a lightweight poll (no per-iteration tasklist).
  • Real-process vitest cases use a 180s timeout on Windows (package default is 15s, which killed healthy boots mid-start).
  • Builds on top of the packaged-desktop asar materialization work already on main (fix(desktop): boot embedded Postgres in packaged app and ship omp dist #2106).

Test plan

  • pnpm --filter @fusion/core test:embedded-postgres on macOS (33/33)
  • desktop-windows.yml on feature/win-pg-verify:
    • Smoke embedded Postgres on Windows
    • Build + package Windows EXE
    • Verify app.asar assets
  • Optional: download portable EXE and manual Local mode smoke on a Windows host

Summary by CodeRabbit

  • Bug Fixes

    • Improved embedded PostgreSQL startup on Windows when Fusion runs with elevated administrator privileges.
    • When elevated, the embedded database now boots under a dedicated non-administrator local account, with more reliable readiness detection, logging, and shutdown cleanup.
    • Enhanced database provisioning and now prefers 127.0.0.1 for Windows connection addressing.
  • Tests

    • Added coverage for Windows elevation detection without starting embedded PostgreSQL.
    • Increased platform-dependent timeouts for embedded real-process tests to avoid premature failures on Windows.

…ndows

GitHub windows-latest and "Run as administrator" launches hold an elevated
admin token; PostgreSQL refuses to start as that user. On elevation, initdb
still runs as the launcher, but the server process is started as a dedicated
non-admin local account (Start-Process -Credential) so CI smoke and elevated
desktop Local mode can open the cluster.

Also raise real-process vitest timeouts on Windows so the 15s package default
does not kill start() while the non-admin postmaster is still coming up.
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@gsxdsm, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 15 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4530edc6-9f70-4ff4-a87e-695b6693e3e9

📥 Commits

Reviewing files that changed from the base of the PR and between 70d5cd6 and bc041e5.

📒 Files selected for processing (1)
  • packages/core/src/__tests__/postgres/embedded-lifecycle.test.ts
📝 Walkthrough

Walkthrough

Adds a Windows elevated-admin path that starts embedded PostgreSQL under a dedicated non-admin account, integrates handle-based lifecycle shutdown and maintenance SQL provisioning, and adds elevation tests, Windows-specific integration timeouts, and release documentation.

Changes

Windows elevated embedded PostgreSQL

Layer / File(s) Summary
Non-admin server startup
packages/core/src/postgres/embedded-windows-admin.ts
Adds elevation detection, dedicated-user management, NTFS permissions, PowerShell credential launching, readiness polling, error reporting, cleanup, and a stoppable server handle.
Lifecycle integration
packages/core/src/postgres/embedded-lifecycle.ts
Resolves Windows native binaries, selects the non-admin startup path for elevated processes, uses maintenance SQL for database provisioning, tracks its handle, and delegates shutdown through it.
Validation and release documentation
packages/core/src/__tests__/postgres/embedded-lifecycle.test.ts, .changeset/win-embedded-pg-admin.md
Adds elevation probe coverage, Windows-specific real-process timeouts, and patch-release documentation.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Fusion
  participant EmbeddedPostgresLifecycle
  participant WindowsAdminStartup
  participant PowerShell
  participant PostgreSQL
  Fusion->>EmbeddedPostgresLifecycle: start embedded database
  EmbeddedPostgresLifecycle->>WindowsAdminStartup: detect elevation and start server
  WindowsAdminStartup->>PowerShell: Start-Process -Credential
  PowerShell->>PostgreSQL: launch postgres.exe as fusion-pg
  PostgreSQL-->>WindowsAdminStartup: readiness log and TCP availability
  WindowsAdminStartup-->>EmbeddedPostgresLifecycle: return server handle
  EmbeddedPostgresLifecycle->>EmbeddedPostgresLifecycle: provision database via maintenance SQL
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: embedded Postgres now boots under a non-admin user on elevated Windows.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/win-pg-verify

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR enables embedded PostgreSQL startup when Fusion runs elevated on Windows. The main changes are:

  • Launches the PostgreSQL server under a dedicated non-admin account.
  • Adds readiness polling, cancellation, cleanup, and direct maintenance SQL.
  • Uses IPv4 loopback for Windows database connections.
  • Expands Windows real-process test timeouts and elevation coverage.

Confidence Score: 4/5

This is close, but the localized Windows failure should be fixed before merging.

  • The updated cleanup, log handling, script encoding, and timeout behavior address the reported startup failures.
  • The account demotion check still parses English command output, so elevated startup can fail on non-English Windows installations.

packages/core/src/postgres/embedded-windows-admin.ts

Important Files Changed

Filename Overview
packages/core/src/postgres/embedded-windows-admin.ts Adds non-admin account setup, ACL grants, launch scripts, readiness polling, and process cleanup; the demotion check fails on localized Windows output.
packages/core/src/postgres/embedded-lifecycle.ts Integrates elevated Windows startup with lifecycle cancellation, shutdown, direct maintenance SQL, and IPv4 loopback.
packages/core/src/tests/postgres/embedded-lifecycle.test.ts Adds elevation-probe coverage and longer platform-specific budgets for real-process tests.

Reviews (7): Last reviewed commit: "fix(core): raise Windows embedded PG rea..." | Re-trigger Greptile

Comment thread packages/core/src/postgres/embedded-windows-admin.ts
Comment thread packages/core/src/postgres/embedded-windows-admin.ts Outdated
Comment thread packages/core/src/postgres/embedded-windows-admin.ts Outdated
Comment thread packages/core/src/postgres/embedded-windows-admin.ts
Comment thread packages/core/src/postgres/embedded-windows-admin.ts
After the elevated non-admin server reported ready, ensureDatabase still
called embedded-postgres.createDatabase(), which requires this.process from
.its own start() and never ran under the non-admin path. Connection helpers
also used localhost (IPv6-first on Windows).

- Ensure DB via postgres.js on 127.0.0.1 with a 10s connect timeout
- Prefer 127.0.0.1 in connection URLs on Windows
- TCP-probe 127.0.0.1 after the ready log before returning from non-admin start

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
packages/core/src/postgres/embedded-windows-admin.ts (1)

81-98: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Password has a fixed prefix/suffix, weakening effective entropy.

generatePassword() always appends the literal Fx9! prefix and #kP suffix around the randomized middle, so 7 of the ~29 characters are constant/known across every generated password for this local account. Consider guaranteeing the four complexity classes by interleaving/shuffling required characters into random positions instead of a fixed affix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/postgres/embedded-windows-admin.ts` around lines 81 - 98,
Update generatePassword() to remove the fixed `Fx9!` prefix and `#kP` suffix.
Generate the full password from randomized characters, explicitly include at
least one uppercase letter, lowercase letter, digit, and symbol, then shuffle
those required characters into random positions before returning a 29-character
password.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/postgres/embedded-lifecycle.ts`:
- Around line 1048-1070: Make the elevated-Windows startup path cancellable
during readiness polling. Update startServerAsNonAdminUser and its caller in
startInternal so the wrapper process/PID is tracked before awaiting readiness
and is terminated by the existing timeout/failure cleanup path; ensure late
readiness cannot register a server after startup has already failed.

In `@packages/core/src/postgres/embedded-windows-admin.ts`:
- Around line 405-413: Update the startup return path around readPostgresPid so
a missing postmaster.pid is surfaced explicitly instead of assigning wrapperPid
to postgresPid. Preserve the documented contract that postgresPid identifies the
actual PostgreSQL server, either by failing startup through the existing onError
flow or by making the field nullable and handling that state at callers; do not
silently substitute wrapperPid.
- Around line 109-127: Remove the generated password from process arguments at
both affected sites in embedded-windows-admin.ts: lines 109-127, update the net
user creation and reset calls to use the interactive password form and provide
the password through spawnSync input; lines 320-339, update the launch.ps1 flow
to read the password from stdin instead of a -Password parameter and pass it
through spawnSync input. Preserve the existing account and launcher behavior
without exposing the secret in command-line arguments.
- Around line 262-286: Update the launch.bat command construction around args,
argStr, and the generated pgExe invocation to safely handle arbitrary executable
arguments containing cmd.exe-sensitive characters such as quotes and percent
signs. Either reject invalid shell-sensitive values before writing the script or
apply correct cmd.exe escaping, while preserving valid PostgreSQL flags and
paths.

---

Nitpick comments:
In `@packages/core/src/postgres/embedded-windows-admin.ts`:
- Around line 81-98: Update generatePassword() to remove the fixed `Fx9!` prefix
and `#kP` suffix. Generate the full password from randomized characters,
explicitly include at least one uppercase letter, lowercase letter, digit, and
symbol, then shuffle those required characters into random positions before
returning a 29-character password.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2f70e71e-2c06-4aa9-9c8a-93f8395d39e0

📥 Commits

Reviewing files that changed from the base of the PR and between e97081f and 9575d48.

📒 Files selected for processing (4)
  • .changeset/win-embedded-pg-admin.md
  • packages/core/src/__tests__/postgres/embedded-lifecycle.test.ts
  • packages/core/src/postgres/embedded-lifecycle.ts
  • packages/core/src/postgres/embedded-windows-admin.ts

Comment thread packages/core/src/postgres/embedded-lifecycle.ts Outdated
Comment thread packages/core/src/postgres/embedded-windows-admin.ts
Comment thread packages/core/src/postgres/embedded-windows-admin.ts
Comment thread packages/core/src/postgres/embedded-windows-admin.ts Outdated
Reuse starts failed on elevated Windows because wrapper.log was appended
across launches; a prior taskkill left exit=1 in the log and the readiness
poll treated that as an immediate failure before the new postmaster came up.
Comment thread packages/core/src/postgres/embedded-lifecycle.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
packages/core/src/postgres/embedded-lifecycle.ts (1)

1065-1073: 🩺 Stability & Availability | 🔴 Critical | 🏗️ Heavy lift

Dangling promise leaves orphaned PostgreSQL processes on timeout.

This is a duplicate of a previously raised issue. The elevated Windows startup path still leaves a running PostgreSQL process behind if start() times out first. Because startServerAsNonAdminUser() only exposes a stop handle after it completes readiness polling, the outer timeout cleanup path cannot kill the wrapper while it is still waiting. When the helper later achieves readiness, startInternal() resumes on an already-failed lifecycle instance, overwrites this.nonAdminHandle, and registers a live server that nobody will stop.

Track the wrapper process PID before awaiting readiness, or pass an AbortSignal to make the helper cancellable during startup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/postgres/embedded-lifecycle.ts` around lines 1065 - 1073,
Update the elevated Windows startup flow around startServerAsNonAdminUser and
startInternal so the wrapper process can be terminated when start() times out
before readiness completes. Expose and track the wrapper PID immediately, or
make the helper accept and honor an AbortSignal; ensure timeout cleanup
cancels/stops it and prevent late readiness from assigning nonAdminHandle or
registering a server on the failed lifecycle.
🧹 Nitpick comments (1)
packages/core/src/postgres/embedded-lifecycle.ts (1)

1125-1125: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unnecessary await on synchronous function call.

openMaintenanceSql() synchronously returns the postgres tagged template function; it does not return a Promise. The await keyword at these call sites is unnecessary and can be removed for clarity.

  • packages/core/src/postgres/embedded-lifecycle.ts#L1125-L1125: remove await from const sql = await this.openMaintenanceSql();.
  • packages/core/src/postgres/embedded-lifecycle.ts#L1137-L1137: remove await from const sql = await this.openMaintenanceSql();.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/postgres/embedded-lifecycle.ts` at line 1125, Remove the
unnecessary await from both calls assigning const sql via openMaintenanceSql()
at packages/core/src/postgres/embedded-lifecycle.ts lines 1125 and 1137,
preserving the synchronous postgres tagged-template function usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@packages/core/src/postgres/embedded-lifecycle.ts`:
- Around line 1065-1073: Update the elevated Windows startup flow around
startServerAsNonAdminUser and startInternal so the wrapper process can be
terminated when start() times out before readiness completes. Expose and track
the wrapper PID immediately, or make the helper accept and honor an AbortSignal;
ensure timeout cleanup cancels/stops it and prevent late readiness from
assigning nonAdminHandle or registering a server on the failed lifecycle.

---

Nitpick comments:
In `@packages/core/src/postgres/embedded-lifecycle.ts`:
- Line 1125: Remove the unnecessary await from both calls assigning const sql
via openMaintenanceSql() at packages/core/src/postgres/embedded-lifecycle.ts
lines 1125 and 1137, preserving the synchronous postgres tagged-template
function usage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2bfda35d-b4b5-4e23-84cd-41d29b56b90c

📥 Commits

Reviewing files that changed from the base of the PR and between 9575d48 and 6b67af9.

📒 Files selected for processing (2)
  • packages/core/src/postgres/embedded-lifecycle.ts
  • packages/core/src/postgres/embedded-windows-admin.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/postgres/embedded-windows-admin.ts

gsxdsm added 2 commits July 14, 2026 22:12
tsc targets ES2022; Promise.withResolvers needs ES2024 and failed the
Windows desktop workspace build after the elevated non-admin smoke passed.
Merge origin/main (AbortSignal start cancellation) with the elevated Windows
non-admin path. Address review feedback:

- Publish stop handle as soon as the wrapper PID is known (onLaunched) and
  honor AbortSignal during readiness so outer start() timeouts kill orphans
- settleCancelledStart stops non-admin handles before embedded-postgres.stop
- Truncate/UTF-8 bat+ps1; strip Administrators from fusion-pg; sanitize flags
- Prefer 127.0.0.1 maintenance connects without unnecessary await
Comment thread packages/core/src/postgres/embedded-windows-admin.ts Outdated
Comment thread packages/core/src/postgres/embedded-windows-admin.ts Outdated
gsxdsm added 2 commits July 14, 2026 22:56
- Bundle postgres.js via static import so CLI ensureDatabase works (boot-smoke
  failed with Cannot find module 'postgres' after lazy require)
- Skip elevated non-admin boot when tests inject an EmbeddedPostgres ctor so
  delayed start cancellation coverage runs on Windows CI
- Fail closed if fusion-pg cannot be demoted from Administrators
- Honor startTimeoutMs <= 0 as unbounded on the non-admin readiness poll
Double-start cases (reuse log, VAL-CONN-006) need two elevated non-admin boots.
A 180s vitest wall left the second start racing the budget, timing out mid-
readiness and leaving EBUSY orphans on the data dir. Allow 6 minutes on win32.
Comment thread packages/core/src/postgres/embedded-windows-admin.ts
@gsxdsm gsxdsm merged commit 6c00841 into main Jul 15, 2026
8 checks passed
@gsxdsm gsxdsm deleted the feature/win-pg-verify branch July 15, 2026 07:15
@gsxdsm

gsxdsm commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator Author

Review feedback follow-up

Resolved the three open inline threads in b05bffd04:

  1. Password on argv — create/reset and Start-Process launcher take the secret via stdin only.
  2. postgresPid contract — nullable postmaster.pid only; no wrapper-pid substitution.
  3. Admin demotion — ADSI membership check (locale-independent).

Earlier review-body notes that were already on the branch:

  • Orphan on start timeoutonLaunched + AbortSignal in the non-admin readiness path (prior commit).
  • await openMaintenanceSql() — already synchronous (no await).
  • Password fixed prefix/suffixgeneratePassword() already shuffles required character classes without fixed frames.
  • postgresFlags sanitization / UTF-8 bat — already in place.

Validation: @fusion/core typecheck + unit embedded-lifecycle tests (non-process subset) passed locally. Windows full smoke/package was green on the previous tip; re-run will pick up this security hardening.

gsxdsm added a commit that referenced this pull request Jul 15, 2026
…ndows (#2117)

## Summary

Windows embedded Postgres verification (CI `windows-latest` and elevated
desktop) fails because PostgreSQL refuses to run under an administrative
token:

> Execution of PostgreSQL by a user with administrative permissions is
not permitted.

GitHub Actions runners execute as `runneradmin` elevated, so the
existing `test:embedded-postgres` smoke (and any elevated Local-mode
desktop launch) cannot start the server.

### Fix

- When `isWindowsElevatedAdmin()` is true, **initdb / clients stay as
the launcher**, but the **postgres server** is started as a dedicated
non-admin local user (`fusion-pg`) via PowerShell `Start-Process
-Credential`.
- Readiness waits on the postgres log line `database system is ready to
accept connections` with a lightweight poll (no per-iteration
`tasklist`).
- Real-process vitest cases use a **180s** timeout on Windows (package
default is 15s, which killed healthy boots mid-start).
- Builds on top of the packaged-desktop asar materialization work
already on main (#2106).

## Test plan

- [x] `pnpm --filter @fusion/core test:embedded-postgres` on macOS
(33/33)
- [ ] `desktop-windows.yml` on `feature/win-pg-verify`:
  - [ ] Smoke embedded Postgres on Windows
  - [ ] Build + package Windows EXE
  - [ ] Verify app.asar assets
- [ ] Optional: download portable EXE and manual Local mode smoke on a
Windows host

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Improved embedded PostgreSQL startup on Windows when Fusion runs with
elevated administrator privileges.
- When elevated, the embedded database now boots under a dedicated
non-administrator local account, with more reliable readiness detection,
logging, and shutdown cleanup.
- Enhanced database provisioning and now prefers `127.0.0.1` for Windows
connection addressing.

- **Tests**
- Added coverage for Windows elevation detection without starting
embedded PostgreSQL.
- Increased platform-dependent timeouts for embedded real-process tests
to avoid premature failures on Windows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
gsxdsm added a commit that referenced this pull request Jul 15, 2026
## Summary

Verification of the Fusion Linux AppImage + embedded Postgres packaging
surface (follow-on to #2106 Mac packaging and #2117 Windows PG work).

### What we found

1. **Published `v0.60.0` AppImages are broken for Local/embedded
Postgres** (pre-#2106):
- No `embedded-postgres` / `@embedded-postgres/*` in `app.asar` or
`app.asar.unpacked`
- `package.json` `main` is still `dist/main.js` (no
`main-bootstrap.cjs`)
   - No `omp-runtime` packaged
- `asar.unpacked` only has incidental natives (pi-tui, esbuild,
node-pty)

2. **Current main (post-#2106) packaging config is correct** (verified
via mac `--dir` pack on this host):
   - `main` → `dist/main-bootstrap.cjs`
   - Full `asarUnpack` of `embedded-postgres` + `@embedded-postgres/**`
   - Native bins present under `app.asar.unpacked`
   - `omp-runtime` dist present in asar

3. **Linux arm64 native PG binary smoke**
(`@embedded-postgres/linux-arm64` 15.18) in Docker: initdb → start →
create DB → persist across restart → **OK** (requires postinstall soname
symlinks from `hydrate-symlinks.js` / `pg-symlinks.json`).

4. **Host blocker:** this machine is macOS arm64 — cannot produce or
execute a Linux AppImage end-to-end. Linux packaging must run on
`ubuntu-latest` CI.

### Fix in this PR

Release jobs only checked that `*.AppImage` files existed — which is how
v0.60.0 shipped empty of Postgres. Add:

- `scripts/verify-desktop-linux-pg-packaging.mjs` — inspects
`linux-*-unpacked` trees for:
- `app.asar.unpacked` embedded-postgres + `@embedded-postgres/linux-*`
bins
  - `dist/main-bootstrap.cjs` + `package.json` main
  - `omp-runtime` presence
- Wire into `release.yml` + `test-release.yml` after AppImage artifact
checks
- Unit test lock in `release-workflow.test.ts`

## Test plan

- [x] `pnpm --filter @fusion/core test:embedded-postgres` (33/33 with
60s timeout; default 15s flaked under load)
- [x] Desktop packaging unit tests (`electron-builder-config`,
`build-bundling`, `release-workflow`)
- [x] Inspected published `Fusion-0.60.0-linux-arm64.AppImage` (checksum
OK; PG packaging absent)
- [x] Post-#2106 `electron-builder --mac --dir`: asar.unpacked has PG +
bootstrap + omp
- [x] Docker linux-arm64 native binary lifecycle smoke
- [ ] CI `build-desktop-linux` on this PR (runs the new verifier against
real linux-unpacked)

## Gaps remaining (not fixed here)

| Gap | Notes |
|-----|-------|
| Full AppImage launch + `/api/health` on Linux | Needs Linux host/CI
with display or headless Electron |
| No post-#2106 published AppImage yet | Next release will include
packaging fixes; this PR stops empty AppImages |
| README still says `linux-x64.AppImage` | Actual name is
`linux-x86_64.AppImage` (workflow already correct) |
| Windows packaged Local | Tracked by #2117 / verify-desktop |

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Added verification for Linux AppImage packaging to ensure embedded
Postgres binaries, platform files, symlinks, and runtime assets are
included correctly.
* Confirmed packaged application metadata points to the expected startup
entry point.
* Improved detection of invalid, missing, or incorrectly formatted
packaging artifacts.

* **Tests**
* Added coverage for architecture-specific binaries, exact ASAR paths,
executable files, and symlink metadata.
* Verified packaging checks run after Linux desktop artifacts are
created.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant