fix: replace inherited updater provider in Gitea packages
This commit is contained in:
@@ -37,7 +37,7 @@ npm run desktop:release:linux
|
||||
|
||||
The release script builds the standalone server, initializes providers offline,
|
||||
curates the payload, boots it under Electron's bundled Node, packages AppImage
|
||||
and Debian installers, creates SHA-256 checksums, and verifies update metadata
|
||||
and Debian installers, checks the packaged Gitea updater configuration, creates SHA-256 checksums, and verifies update metadata
|
||||
against the actual installer bytes.
|
||||
|
||||
Run the packaged-runtime gates too:
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Official packages for this fork. Upstream packaging stays in electron-builder.yml.
|
||||
extends: ./electron-builder.yml
|
||||
publish:
|
||||
- provider: generic
|
||||
# Gitea resolves the latest published, non-prerelease release here.
|
||||
# Drafts remain private and do not become an update before publication.
|
||||
url: https://server2.sorokin-oleg-edu.xyz/replicated/learnharness/releases/download/latest
|
||||
# Use an object: electron-builder concatenates inherited publish arrays.
|
||||
provider: generic
|
||||
# Gitea resolves the latest published, non-prerelease release here.
|
||||
# Drafts remain private and do not become an update before publication.
|
||||
url: https://server2.sorokin-oleg-edu.xyz/replicated/learnharness/releases/download/latest
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
"test": "NODE_ENV=test tsx --test tests/*.test.ts tests/*.test.tsx",
|
||||
"lint": "eslint .",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"desktop:release:linux": "npm run build && node scripts/smoke-provider-runtime.mjs && node scripts/build-server.mjs && node scripts/smoke-server.mjs --electron && electron-builder --config electron-builder.gitea.yml --linux --x64 --publish never && node scripts/gitea-release.mjs checksums dist && node scripts/gitea-release.mjs verify dist",
|
||||
"desktop:release:linux": "rm -rf dist .next/standalone && npm run build && node scripts/smoke-provider-runtime.mjs && node scripts/build-server.mjs && node scripts/smoke-server.mjs --electron && electron-builder --config electron-builder.gitea.yml --linux --x64 --publish never && node scripts/gitea-release.mjs verify-package dist/linux-unpacked && node scripts/gitea-release.mjs checksums dist && node scripts/gitea-release.mjs verify dist",
|
||||
"desktop:dev": "concurrently -k \"next dev\" \"LH_DEV_URL=http://localhost:3000 electron .\"",
|
||||
"dev:fresh": "bash scripts/dev-fresh.sh",
|
||||
"desktop:dist": "rm -rf dist .next/standalone && next build && node scripts/smoke-provider-runtime.mjs && node scripts/build-server.mjs && node scripts/smoke-server.mjs && DEVELOPER_DIR=${DEVELOPER_DIR:-/Applications/Xcode.app/Contents/Developer} APPLE_KEYCHAIN_PROFILE=LH_NOTARY APPLE_TEAM_ID=JS6XN22HY6 electron-builder --mac --arm64"
|
||||
|
||||
@@ -35,6 +35,13 @@ export async function writeChecksums(directory, version) {
|
||||
await fsp.writeFile(path.join(directory, "SHA256SUMS"), lines.join("\n") + "\n");
|
||||
}
|
||||
|
||||
export async function verifyPackagedUpdater(directory) {
|
||||
const config = yaml.load(await fsp.readFile(path.join(directory, "resources", "app-update.yml"), "utf8"));
|
||||
assert.equal(config.provider, "generic", "packaged updater must use the Gitea generic provider");
|
||||
assert.equal(config.url, UPDATE_URL, "packaged updater must use the public Gitea release feed");
|
||||
assert(!config.owner && !config.repo, "packaged updater must not retain an upstream GitHub destination");
|
||||
}
|
||||
|
||||
export async function verifyLocal(directory, version) {
|
||||
const names = expectedLinuxAssets(version);
|
||||
const inventory = new Map();
|
||||
@@ -145,6 +152,7 @@ async function main() {
|
||||
const [command, directory = "dist"] = process.argv.slice(2);
|
||||
const { version } = JSON.parse(await fsp.readFile(path.join(ROOT, "package.json"), "utf8"));
|
||||
if (command === "checksums") await writeChecksums(directory, version);
|
||||
else if (command === "verify-package") await verifyPackagedUpdater(directory);
|
||||
else if (command === "verify") console.log(JSON.stringify(await verifyLocal(directory, version), null, 2));
|
||||
else if (command === "upload") await upload(directory, version);
|
||||
else if (command === "verify-remote") {
|
||||
@@ -153,7 +161,7 @@ async function main() {
|
||||
assert(release, "draft not found");
|
||||
await verifyRemote(release, inventory, authorization());
|
||||
console.log(`Verified draft: ${release.html_url}`);
|
||||
} else throw new Error("Usage: node scripts/gitea-release.mjs checksums|verify|upload|verify-remote [dist-directory]");
|
||||
} else throw new Error("Usage: node scripts/gitea-release.mjs checksums|verify|upload|verify-remote [dist-directory], or verify-package [unpacked-app-directory]");
|
||||
}
|
||||
if (process.argv[1] && pathToFileURL(path.resolve(process.argv[1])).href === import.meta.url) {
|
||||
main().catch((error) => { console.error(error.message); process.exitCode = 1; });
|
||||
|
||||
@@ -5,7 +5,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { after, test } from "node:test";
|
||||
import { createRequire } from "node:module";
|
||||
import { expectedLinuxAssets, writeChecksums, verifyLocal, verifyRemote, UPDATE_URL } from "../scripts/gitea-release.mjs";
|
||||
import { expectedLinuxAssets, writeChecksums, verifyLocal, verifyRemote, verifyPackagedUpdater, UPDATE_URL } from "../scripts/gitea-release.mjs";
|
||||
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "lh-gitea-gate-"));
|
||||
after(() => fs.rm(root, { recursive: true, force: true }));
|
||||
@@ -39,6 +39,7 @@ test("updater cannot point at traversal paths, other versions, or substituted in
|
||||
["traversal", (feed: any) => { feed.files[0].url = "../outside.AppImage"; }, /reference exactly/],
|
||||
["version", (feed: any) => { feed.version = "0.3.7"; }, /metadata version/],
|
||||
["hash", (feed: any) => { feed.files[0].sha512 = "bad"; }, /update checksum/],
|
||||
["duplicate", (feed: any) => { feed.files.push({ ...feed.files[1] }); }, /reference exactly/],
|
||||
] as const) {
|
||||
const directory = await fixture(name);
|
||||
const file = path.join(directory, "latest-linux.yml");
|
||||
@@ -73,11 +74,24 @@ test("remote verification downloads and hashes every draft attachment, and refus
|
||||
test("release configuration preserves packaging while replacing the upstream update origin", async () => {
|
||||
const require = createRequire(import.meta.url);
|
||||
const yaml = require("js-yaml");
|
||||
const config = yaml.load(await fs.readFile(new URL("../electron-builder.gitea.yml", import.meta.url), "utf8"));
|
||||
assert.equal(config.extends, "./electron-builder.yml");
|
||||
assert.deepEqual(config.publish, [{ provider: "generic", url: UPDATE_URL }]);
|
||||
const { getConfig } = require("app-builder-lib/out/util/config/config.js");
|
||||
const config = await getConfig(path.resolve(import.meta.dirname, ".."), "electron-builder.gitea.yml", null);
|
||||
assert.deepEqual(config.publish, { provider: "generic", url: UPDATE_URL });
|
||||
assert.equal(config.appId, "com.learnharness.LearnHarness");
|
||||
assert.deepEqual(config.linux.target.map((target: any) => target.target), ["AppImage", "deb"]);
|
||||
const workflow = yaml.load(await fs.readFile(new URL("../.gitea/workflows/release.yml", import.meta.url), "utf8"));
|
||||
assert(workflow.on.workflow_dispatch);
|
||||
assert(!workflow.on.pull_request, "untrusted pull requests must not run release publishing");
|
||||
assert.equal(workflow.permissions.releases, "write");
|
||||
});
|
||||
test("packaged updater verification refuses inherited GitHub or incorrect generic destinations", async () => {
|
||||
const directory = path.join(root, "package");
|
||||
await fs.mkdir(path.join(directory, "resources"), { recursive: true });
|
||||
const file = path.join(directory, "resources", "app-update.yml");
|
||||
await fs.writeFile(file, JSON.stringify({ provider: "github", owner: "amosblomqvist", repo: "learnharness" }));
|
||||
await assert.rejects(verifyPackagedUpdater(directory), /Gitea generic provider/);
|
||||
await fs.writeFile(file, JSON.stringify({ provider: "generic", url: "https://other.example" }));
|
||||
await assert.rejects(verifyPackagedUpdater(directory), /public Gitea release feed/);
|
||||
await fs.writeFile(file, JSON.stringify({ provider: "generic", url: UPDATE_URL }));
|
||||
await verifyPackagedUpdater(directory);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user