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
8 changes: 8 additions & 0 deletions .github/workflows/release-desktop-multi-os.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ jobs:
platform_label: linux
files: |
src-tauri/target/release/bundle/**/*.AppImage
src-tauri/target/release/bundle/**/*.AppImage.zsync
src-tauri/target/release/bundle/**/*.deb
- runner: macos-latest
platform_label: macos
Expand Down Expand Up @@ -351,6 +352,11 @@ jobs:
codesign --verify --strict --verbose=4 "${TARGET_BIN}"
"${TARGET_BIN}" --version

- name: Remove previous AppImage update controls
if: runner.os == 'Linux'
shell: bash
run: find src-tauri -maxdepth 1 -type f -name '*.AppImage.zsync' -delete

- name: Build desktop bundle
run: npm run tauri:build:mini

Expand All @@ -365,6 +371,8 @@ jobs:
exit 1
fi
for artifact in "${artifacts[@]}"; do
# Tauri builds in src-tauri; bundled zsyncmake writes basename.zsync in that CWD.
mv -- "src-tauri/$(basename "$artifact").zsync" "${artifact}.zsync"
npm run verify:appimage -- "${artifact}" src-tauri/bin/server-x86_64-unknown-linux-gnu
done

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ ref

# Tauri / Rust build outputs
src-tauri/target/
src-tauri/*.AppImage.zsync
src-tauri/target-dev-lowmem/
src-tauri/gen/
src/backend/wasm/target/
Expand Down
10 changes: 8 additions & 2 deletions .trellis/spec/backend/quality-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,22 @@ Changes to the Tauri CLI, sidecars, Linux build runner, or release workflow must

### Commands

Use `npm run tauri:build:mini`, then `npm run verify:appimage -- <image.AppImage> <original-server-sidecar>`. Both verifier arguments are required and must come from the same build.
Use `npm run tauri:build:mini`, move the generated `src-tauri/<AppImage basename>.zsync` next to the final image, then run `npm run verify:appimage -- <image.AppImage> <original-server-sidecar>`. Both verifier arguments and the adjacent control file must come from the same build. Clear previous `src-tauri/*.AppImage.zsync` before building so a missing generator cannot reuse old output.

### Boundary and environment

The Linux runner selects `scripts/appimage-patchelf.js` through `PATCHELF`. `NOTE_CONNECTION_APPIMAGE_PATCHELF` identifies the original executable; `NOTE_CONNECTION_APPIMAGE_SERVER_SUFFIX` and `NOTE_CONNECTION_APPIMAGE_SERVER_SHA256` identify the protected pkg sidecar. Only its `--set-rpath` write is suppressed; dependency queries and other ELF operations remain enabled. AppRun supplies the sidecar's library search path. Never rewrite pkg's completed ELF payload offsets.

`scripts/appimage-update.js` owns the native `gh-releases-zsync` contract for the current amd64 release. The Linux runner passes it through `LDAI_UPDATE_INFORMATION`; the official bundled appimagetool/zsyncmake generates the control after the final metadata/signing writes. Tauri CLI 2.12.1 changes CWD to `src-tauri` in `crates/tauri-cli/src/build.rs:166`, and official zsyncmake 0.6.2 emits basename.zsync in that CWD. The release workflow already owns final artifact paths, so it moves each exact control beside its image and fails if absent. Do not add a second Tauri CLI parser or search guessed directories to collect it.

Keep the product release Latest and Godot mirrors `latest=false`. Publish exactly one matching amd64 `.zsync` with its AppImage, and include both in checksums and the final asset manifest. An unsupported architecture must not pass the current release gate. Preserve v1.9.0: it lacks embedded metadata, so testing it as a delta seed requires the explicit new control URL.

### Validation and errors

The final verifier rejects inaccessible stored SquashFS modes, invalid integration symlinks, missing desktop executables/icons, invalid image decoding, and any server hash mismatch. A matching path with changed bytes makes the patchelf adapter fail. Metadata success alone does not prove that the ELF loader, WebView, or backend starts.

The same two-argument verifier requires correct embedded update information and the adjacent control file. It validates the official plain-file header, basename/relative URL, exact Length/SHA-1 and checksum table length `ceil(Length / Blocksize) * (rsum_bytes + checksum_bytes)`. The first `Hash-Lengths` field is a sequence count, not bytes per table entry. Never implement rsync weak hashes or MD4 to duplicate the official updater; table-content correctness is accepted through official reconstruction followed by full target SHA-256 equality.

### Acceptance cases

- Good: the Ubuntu 22.04 artifact launches as a normal user, serves authenticated graph/reader requests, and shuts down its sidecars.
Expand All @@ -96,7 +102,7 @@ The final verifier rejects inaccessible stored SquashFS modes, invalid integrati

### Required tests

Run the portability and patchelf behavioral suites. Verify the final image on the baseline OS and a newer host, retaining its SHA-256, logs, and screenshots. The installed Markdown worker must be discovered under Tauri's suffixless name and report `engine: pulldown` without a missing-worker fallback.
Run the update, portability and patchelf behavioral suites. Update tests must cover a good official control fixture, missing/stale controls, same-size image corruption, malformed headers/tables and wrong owner/repository/channel/architecture/URL. Verify the final image on the baseline OS and a newer host, retaining its SHA-256, logs, and screenshots. The installed Markdown worker must be discovered under Tauri's suffixless name and report `engine: pulldown` without a missing-worker fallback.

Run the offline simulation worker suite and load a graph with external networking disabled, keeping loopback available for the sidecar. Graph layout dependencies must be bundled; an initial window and successful graph API do not establish that worker-produced node positions render.

Expand Down
4 changes: 2 additions & 2 deletions docs/diataxis-map.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,11 @@
"id": "release-and-governance",
"category": "reference",
"en": {
"canonical": ["docs/en/release_v1.6.0_report.md", "docs/release_notes_v1.6.0.md"],
"canonical": ["docs/en/release_v1.6.0_report.md", "docs/release_notes_v1.6.0.md", "docs/release_notes_v1.9.1.md"],
"diataxis": "docs/diataxis/en/reference/release-and-governance.md"
},
"zh": {
"canonical": ["docs/zh/release_v1.6.0_report.md", "docs/release_notes_v1.6.0.md"],
"canonical": ["docs/zh/release_v1.6.0_report.md", "docs/release_notes_v1.6.0.md", "docs/release_notes_v1.9.1.md"],
"diataxis": "docs/diataxis/zh/reference/release-and-governance.md"
}
},
Expand Down
21 changes: 17 additions & 4 deletions docs/diataxis/en/how-to/test-linux-appimage.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,34 @@ Install the usual Tauri Linux build dependencies and the artifact verifier tools
```bash
sudo apt-get install desktop-file-utils libgdk-pixbuf2.0-bin squashfs-tools
npm ci
find src-tauri -maxdepth 1 -type f -name '*.AppImage.zsync' -delete
npm run tauri:build:mini
npm run verify:appimage -- src-tauri/target/release/bundle/appimage/NoteConnection_1.8.0_amd64.AppImage src-tauri/bin/server-x86_64-unknown-linux-gnu
sha256sum src-tauri/target/release/bundle/appimage/*.AppImage
appimage=src-tauri/target/release/bundle/appimage/NoteConnection_1.9.1_amd64.AppImage
mv -- "src-tauri/$(basename "$appimage").zsync" "${appimage}.zsync"
npm run verify:appimage -- "$appimage" src-tauri/bin/server-x86_64-unknown-linux-gnu
sha256sum "$appimage" "${appimage}.zsync"
```

Substitute the actual release filename. `verify:appimage` reads the final SquashFS manifest, checks that packaged files are readable and executables/directories usable by users other than the build owner, then extracts into a fresh temporary directory with `unsquashfs`. This preserves stored permissions; the AppImage runtime's `--appimage-extract` can replace directory modes with 0700.
Substitute the actual release filename and output directory, including any custom Cargo target directory. The official bundled `zsyncmake` writes `<AppImage basename>.zsync` in Tauri's `src-tauri` working directory even when the image output is absolute. Move that exact file beside the image; a missing source is a build failure. The release workflow clears previous controls before building and performs this move before verification and either upload.

`verify:appimage` requires the adjacent `.zsync`, checks native update information, filename/relative URL, file length, SHA-1 and checksum-table structure against the exact final image. It then reads the final SquashFS manifest, checks that packaged files are readable and executables/directories usable by users other than the build owner, and extracts into a fresh temporary directory with `unsquashfs`. This preserves stored permissions; the AppImage runtime's `--appimage-extract` can replace directory modes with 0700.

The verifier rejects absolute, escaping, dangling, or cyclic integration links, checks `.DirIcon`, the root desktop entry, `AppRun`, `AppRun.wrapped`, the desktop `Exec` target and themed icon, validates the desktop file with `desktop-file-validate`, and decodes the icon with GDK Pixbuf. The required second argument is the original server sidecar from the same build: the packaged server must match its complete SHA-256, including the appended pkg payload. It deletes its temporary extraction on success or failure. The Linux release workflow runs it before either artifact upload.

Run the regression suite with:

```bash
npm test -- --runInBand src/appimage.portability.test.ts src/appimage.patchelf.test.ts src/simulation.worker.offline.test.ts
npm test -- --runInBand src/appimage.update.test.ts src/appimage.portability.test.ts src/appimage.patchelf.test.ts src/simulation.worker.offline.test.ts
```

## Verify native updates and publish the pair

The Linux release contract currently supports amd64. Its embedded information is `gh-releases-zsync|Jacobinwwey|NoteConnection|latest|NoteConnection_*_amd64.AppImage.zsync`, owned by `scripts/appimage-update.js`. Keep exactly one matching control asset in the product release. Other architectures need their own explicit release contract before publication. Product releases must be marked Latest when the accepted draft is published; Godot mirror releases remain `latest=false`.

Use the plugin's bundled official generator. It runs after appimagetool finishes metadata and signing. Do not alter the AppImage after generation. Publish the AppImage and its adjacent `.zsync` together in the same GitHub release, include both in `SHA256SUMS.txt` and the asset manifest, and verify downloaded bytes against the accepted CI build. The zsync `URL` is the AppImage basename, resolved relative to its control-file URL. Do not replace it with a build-host path or generate a control file from an earlier image.

The artifact gate checks the control header and table structure. Establish actual delta reconstruction separately with an official AppImageUpdate/zsync client, preserving its version, command, logs and target SHA-256 comparison. A v1.9.0 AppImage can supply local seed bytes when the new control URL is explicitly provided; it cannot discover updates by itself because v1.9.0 contains no update information. Before publication, serve the exact CI candidate and its unchanged control file together from a local HTTP server that supports Range requests, and provide that control URL explicitly to the client. Require reconstructed SHA-256 to equal the candidate. After publication, repeat against `https://github.com/Jacobinwwey/NoteConnection/releases/download/v1.9.1/NoteConnection_1.9.1_amd64.AppImage.zsync` and verify the public download matches the accepted candidate. Test automatic discovery with a metadata-bearing image after the product release is Latest.

## Verify application behavior

The artifact gate checks packaging. Also launch the actual final AppImage on Ubuntu 22.04 from a directory outside the repository as a normal user. Use isolated XDG config/data directories, `NOTE_CONNECTION_CONFIG_PATH`, and disposable Markdown notes; keep the operating-system home and toolchain caches in their normal locations. Confirm a real visible window, successful graph loading, note reading, switching into and out of Path mode, and clean shutdown of the server and Godot sidecars. Retain the exact artifact SHA-256, source commit, installed Tauri CLI version, command output, and screenshots with the test report.
Expand Down
1 change: 1 addition & 0 deletions docs/diataxis/en/reference/release-and-governance.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This page is the governance index for release pipelines, docs delivery, and lear
- [docs/release_notes_v1.6.0.md](../../../release_notes_v1.6.0.md)
- [docs/release_notes_v1.6.7.md](../../../release_notes_v1.6.7.md)
- [docs/release_notes_v1.7.0.md](../../../release_notes_v1.7.0.md)
- [docs/release_notes_v1.9.1.md](../../../release_notes_v1.9.1.md)
- [Knowledge Mastery Evolution Roadmap](../explanation/knowledge-mastery-evolution-roadmap.md)
- [Development Progress Dashboard](../explanation/development-progress-dashboard.md)

Expand Down
1 change: 1 addition & 0 deletions docs/diataxis/zh/reference/release-and-governance.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [docs/release_notes_v1.6.0.md](../../../release_notes_v1.6.0.md)
- [docs/release_notes_v1.6.7.md](../../../release_notes_v1.6.7.md)
- [docs/release_notes_v1.7.0.md](../../../release_notes_v1.7.0.md)
- [docs/release_notes_v1.9.1.md](../../../release_notes_v1.9.1.md)
- [知识彻底掌握演进路线图](../explanation/knowledge-mastery-evolution-roadmap.md)
- [开发进度看板](../explanation/development-progress-dashboard.md)

Expand Down
Loading
Loading