feat(FN-5605): add linux gpg signing for release artifacts
Implements Linux GPG signing for the release pipeline by adding a `sign-linux.sh` helper, wiring it into the release and test-release workflows, including `.asc` signature files in release collectors, and documenting the full signing workflow in CODE_SIGNING.md with a note in the desktop README. Fusion-Task-Id: FN-5605 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> Fusion-Task-Id: FN-5605
This commit is contained in:
@@ -357,8 +357,20 @@ Desktop packaging is configured in `electron-builder.yml`.
|
||||
- macOS: `Fusion-<version>-mac-arm64.dmg`, `Fusion-<version>-mac-x64.dmg`, matching `.zip` variants, `.sha256` sidecars, and `.blockmap` files.
|
||||
- Linux: `Fusion-<version>-linux-x64.AppImage` with `.sha256`, plus best-effort `.deb` and `.tar.gz` outputs (and sidecars) when available on the runner image.
|
||||
- Tag-less release rehearsal workflow (`.github/workflows/test-release.yml`) mirrors that artifact collection path without publishing a real GitHub Release.
|
||||
- macOS Developer ID signing/notarization and Linux signing are not wired in these release jobs yet; release-attached macOS/Linux artifacts are currently unsigned and follow-up tasks will add signing flows.
|
||||
- Linux desktop artifacts now include detached GPG signature sidecars: `*.AppImage.asc`, `*.deb.asc`, and `*.tar.gz.asc` when Linux signing secrets are configured in CI.
|
||||
- Linux `.deb` and `.tar.gz` outputs are best-effort and may be absent on some runner images without failing the release.
|
||||
|
||||
### Linux signing
|
||||
|
||||
Every signed Linux desktop release includes `*.asc` detached signature sidecars alongside the binary artifacts.
|
||||
|
||||
Verification example:
|
||||
|
||||
```bash
|
||||
gpg --import KEYS && gpg --verify Fusion-<version>-linux-x64.AppImage.asc Fusion-<version>-linux-x64.AppImage
|
||||
```
|
||||
|
||||
The public key (`KEYS`) must be distributed out-of-band. See `docs/CODE_SIGNING.md` for canonical setup, key publication, and troubleshooting guidance.
|
||||
- Isolated manual Windows build path: `.github/workflows/desktop-windows.yml` (`workflow_dispatch` on `windows-latest`) runs `electron-builder --win --x64 --arm64 --publish never`.
|
||||
- ARM64 artifacts are cross-built on the `windows-latest` x64 runner; execution/validation still requires a Windows ARM64 device or emulator.
|
||||
- Deep link protocol: `fusion://`
|
||||
|
||||
@@ -59,3 +59,44 @@ describe("desktop release workflow wiring", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("desktop linux signing wiring", () => {
|
||||
it("wires Linux GPG secret-guarded signing and asc uploads in both workflows", async () => {
|
||||
const release = await readRepoFile(".github/workflows/release.yml");
|
||||
const testRelease = await readRepoFile(".github/workflows/test-release.yml");
|
||||
|
||||
for (const workflow of [release, testRelease]) {
|
||||
expect(workflow).toContain("secrets.LINUX_GPG_PRIVATE_KEY");
|
||||
expect(workflow).toContain("secrets.LINUX_GPG_PASSPHRASE");
|
||||
expect(workflow).toContain("secrets.LINUX_GPG_KEY_ID");
|
||||
expect(workflow).toContain("LINUX_GPG_PRIVATE_KEY != ''");
|
||||
expect(workflow).toContain("scripts/sign-linux.sh");
|
||||
expect(workflow).toContain("Fusion-*-linux-*.AppImage.asc");
|
||||
expect(workflow).toContain("Fusion-*-linux-*.deb.asc");
|
||||
expect(workflow).toContain("Fusion-*-linux-*.tar.gz.asc");
|
||||
expect(workflow).not.toMatch(/echo\s+["']?\$\{?\s*(secrets\.)?LINUX_GPG_PASSPHRASE/);
|
||||
expect(workflow).not.toMatch(/cat\s+["']?\$\{?\s*(secrets\.)?LINUX_GPG_PASSPHRASE/);
|
||||
}
|
||||
});
|
||||
|
||||
it("collectors in both workflows include asc signatures", async () => {
|
||||
const release = await readRepoFile(".github/workflows/release.yml");
|
||||
const testRelease = await readRepoFile(".github/workflows/test-release.yml");
|
||||
|
||||
expect(release).toContain('-name "*.asc"');
|
||||
expect(testRelease).toContain('-name "*.asc"');
|
||||
});
|
||||
|
||||
it("sign-linux.sh contains expected guarded gpg sign and verify shape", async () => {
|
||||
const script = await readRepoFile("scripts/sign-linux.sh");
|
||||
|
||||
expect(script).toContain("set -euo pipefail");
|
||||
expect(script).toContain("LINUX_GPG_PRIVATE_KEY");
|
||||
expect(script).toContain("LINUX_GPG_PASSPHRASE");
|
||||
expect(script).toContain("LINUX_GPG_KEY_ID");
|
||||
expect(script).toContain("gpg --verify");
|
||||
expect(script).toContain("--detach-sign");
|
||||
expect(script).toContain("--armor");
|
||||
expect(script).toContain("Linux signing skipped (LINUX_GPG_PRIVATE_KEY not set)");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user