feat: harden server pull deployments and git hygiene

This commit is contained in:
NuklearRabbit
2026-07-28 08:27:09 +02:00
parent d4d77c827a
commit 56efd1a00c
33 changed files with 2390 additions and 633 deletions
+77 -2
View File
@@ -73,6 +73,11 @@ const required = [
"docs/RELEASE_NOTES_0.8.9.md",
"docs/RELEASE_NOTES_0.9.0.md",
"docs/RELEASE_NOTES_0.9.1.md",
"docs/RELEASE_NOTES_0.9.2.md",
"docs/RELEASE_NOTES_0.9.3.md",
"docs/RELEASE_NOTES_0.9.4.md",
"docs/RELEASE_NOTES_0.9.5.md",
"docs/RELEASE_NOTES_0.10.0.md",
"docs/UPDATING.md",
"docs/DIAGNOSTICS.md",
"docs/DEPLOYMENT_SETUP.md",
@@ -111,9 +116,9 @@ for (const file of required) await access(path.join(root, file));
const packageJson = JSON.parse(
await readFile(path.join(root, "package.json"), "utf8"),
);
if (packageJson.version !== "0.9.1")
if (packageJson.version !== "0.10.0")
throw new Error(
`Expected package version 0.9.1, got ${packageJson.version}.`,
`Expected package version 0.10.0, got ${packageJson.version}.`,
);
const sourceManifest = await readFile(
path.join(root, "SOURCE_MANIFEST.txt"),
@@ -373,6 +378,76 @@ for (const phrase of [
]) {
if (!release091.includes(phrase)) throw new Error(`0.9.1 release notes are missing: ${phrase}`);
}
const release092 = await readFile(path.join(root, "docs/RELEASE_NOTES_0.9.2.md"), "utf8");
for (const phrase of [
"Push bundle",
"server password",
"docker ps -a",
"DockerMan",
"zero counts",
]) {
if (!release092.includes(phrase)) throw new Error(`0.9.2 release notes are missing: ${phrase}`);
}
const release093 = await readFile(path.join(root, "docs/RELEASE_NOTES_0.9.3.md"), "utf8");
for (const phrase of [
"Direct copy",
"Compose YAML",
"linked automatically",
"one-click",
"no remote `git ls-remote`",
]) {
if (!release093.includes(phrase)) throw new Error(`0.9.3 release notes are missing: ${phrase}`);
}
const release094 = await readFile(path.join(root, "docs/RELEASE_NOTES_0.9.4.md"), "utf8");
for (const phrase of [
"real Compose files",
"stale service hints",
"force-recreate",
"container ID",
"previous container",
]) {
if (!release094.includes(phrase)) throw new Error(`0.9.4 release notes are missing: ${phrase}`);
}
const release095 = await readFile(path.join(root, "docs/RELEASE_NOTES_0.9.5.md"), "utf8");
for (const phrase of [
"Check / fix write access",
"exact path, user, owner, group and mode",
"preserves existing executable bits",
"never implicitly executes `docker compose down`",
"retains the backup evidence",
]) {
if (!release095.includes(phrase)) throw new Error(`0.9.5 release notes are missing: ${phrase}`);
}
const release0100 = await readFile(path.join(root, "docs/RELEASE_NOTES_0.10.0.md"), "utf8");
for (const phrase of [
"Server pull",
"read-only deploy key",
"automatic discovery",
"Git Validator",
"SSH host fingerprint",
]) {
if (!release0100.includes(phrase)) throw new Error(`0.10.0 release notes are missing: ${phrase}`);
}
const configSource = await readFile(path.join(root, "src/main/config-store.cjs"), "utf8");
for (const mode of ["server-git", "push-bundle", "monitor-only"]) {
if (!configSource.includes(mode)) throw new Error(`Deployment configuration is missing mode: ${mode}`);
}
const unraidDirectSource = await readFile(path.join(root, "src/main/unraid-deployment-service.cjs"), "utf8");
for (const requiredPhrase of [
"executePushBundle",
"executeServerGitBundle",
"configureServerGitAccess",
"server-git-access",
"git ls-remote --exit-code",
"repository-scoped read-only deploy key",
]) {
if (!unraidDirectSource.includes(requiredPhrase)) throw new Error(`Deployment source is missing: ${requiredPhrase}`);
}
const serverInventorySource = await readFile(path.join(root, "src/main/server-inventory.cjs"), "utf8");
for (const requiredPhrase of ["server-compose-file", "composeDefinitions", "remoteFolderCandidate"]) {
if (!serverInventorySource.includes(requiredPhrase)) throw new Error(`Server inventory source is missing: ${requiredPhrase}`);
}
const giteaUpdateSource = await readFile(path.join(root, "src/main/gitea-service.cjs"), "utf8");
for (const phrase of [
"browser_download_url",