fix: repair packaged release downloads
ForgeFlow quality gate / quality (push) Canceled after 0s

This commit is contained in:
NuklearRabbit
2026-07-30 00:58:34 +02:00
parent 60e8aa8fc2
commit 398f986d95
8 changed files with 48 additions and 13 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
ForgeFlow is een desktopapp voor teams die met Git, Gitea en eigen servers werken. De app toont wat lokaal gewijzigd is, wat al op Gitea staat en welke exacte commit op de server draait. Daarna begeleidt ForgeFlow je door review, commit, push, deployment en verificatie. ForgeFlow is een desktopapp voor teams die met Git, Gitea en eigen servers werken. De app toont wat lokaal gewijzigd is, wat al op Gitea staat en welke exacte commit op de server draait. Daarna begeleidt ForgeFlow je door review, commit, push, deployment en verificatie.
> Huidige release: **0.10.1** · [download de laatste Windows-release](https://gitea.itworx.tech/Jens/ForgeFlow/releases/latest) > Huidige release: **0.10.2** · [download de laatste Windows-release](https://gitea.itworx.tech/Jens/ForgeFlow/releases/latest)
![ForgeFlow release-overzicht](docs/screenshots/overview.png) ![ForgeFlow release-overzicht](docs/screenshots/overview.png)
+8 -7
View File
@@ -1,4 +1,4 @@
ForgeFlow 0.10.1 source manifest ForgeFlow 0.10.2 source manifest
SHA-256 BYTES PATH SHA-256 BYTES PATH
(The manifest excludes itself, dependencies and generated release artifacts.) (The manifest excludes itself, dependencies and generated release artifacts.)
cedceb71eb846d99c7c4019031833c1c7f93b84a1c6073aec7d2435dc744ca3d 703 .gitea/workflows/quality.yml cedceb71eb846d99c7c4019031833c1c7f93b84a1c6073aec7d2435dc744ca3d 703 .gitea/workflows/quality.yml
@@ -34,6 +34,7 @@ a0cd06a96f23a94e118feb012be0fa1ac51345951cb2ba8e67fb8c889c4c342a 5007
f79908fb3dad98c38030c6e6be7c79a1999e0478ed9c2496923891954438daa1 4581 docs/RELEASE_AUDIT_0.6.0.md f79908fb3dad98c38030c6e6be7c79a1999e0478ed9c2496923891954438daa1 4581 docs/RELEASE_AUDIT_0.6.0.md
979a0b8e129979be6b265e8571d0a3c1e9ddd4ddb6b0bf55ae748d3478e51854 2296 docs/RELEASE_NOTES_0.10.0.md 979a0b8e129979be6b265e8571d0a3c1e9ddd4ddb6b0bf55ae748d3478e51854 2296 docs/RELEASE_NOTES_0.10.0.md
0eb44bda2209a5979a6ac693ac4cd4d235c0015031e54b9e895990f37bf60054 1433 docs/RELEASE_NOTES_0.10.1.md 0eb44bda2209a5979a6ac693ac4cd4d235c0015031e54b9e895990f37bf60054 1433 docs/RELEASE_NOTES_0.10.1.md
8d713471a437a8a55b00d7e1dd95290680862107bc4e586cf27d727f6274e46c 577 docs/RELEASE_NOTES_0.10.2.md
a0c00ff76acd1682bb5e0e8dcf6589c9480da436c9c6d30780a1ed58b4dad94f 1770 docs/RELEASE_NOTES_0.2.0.md a0c00ff76acd1682bb5e0e8dcf6589c9480da436c9c6d30780a1ed58b4dad94f 1770 docs/RELEASE_NOTES_0.2.0.md
5773ead01aa4c522c556295553787482d01b1f5242f053b2c61f120c4de4fa76 5963 docs/RELEASE_NOTES_0.3.0.md 5773ead01aa4c522c556295553787482d01b1f5242f053b2c61f120c4de4fa76 5963 docs/RELEASE_NOTES_0.3.0.md
d46de73cf6c4cd5c2ba3f455a7a2af2e0d64ee9d94a97fd1a0bfb44e35c1624a 1093 docs/RELEASE_NOTES_0.3.1.md d46de73cf6c4cd5c2ba3f455a7a2af2e0d64ee9d94a97fd1a0bfb44e35c1624a 1093 docs/RELEASE_NOTES_0.3.1.md
@@ -95,14 +96,14 @@ c230b931abf2293d2d44b7a69b94c35f1142c093cc46b88739a0de5cbd6d1896 1532
4a561ead5ba7cdfaf4efce91842a4308c5f2a77980205879d83835efb8a579db 1067 LICENSE 4a561ead5ba7cdfaf4efce91842a4308c5f2a77980205879d83835efb8a579db 1067 LICENSE
1f0f388df4397e548887bbc7579fd3c864581b86469c01703201ece7a6cbf931 13667 main.cjs 1f0f388df4397e548887bbc7579fd3c864581b86469c01703201ece7a6cbf931 13667 main.cjs
91a984a89dd57a084b9a2331763cacdb061582fb590f13df379d92c1a77a2ee1 352 OVERLAY-INSTRUCTIONS.md 91a984a89dd57a084b9a2331763cacdb061582fb590f13df379d92c1a77a2ee1 352 OVERLAY-INSTRUCTIONS.md
d281af8b6fc3fc8a84bca985c6feb13c1edeaa72b5f0144816ea91dd53774a08 179806 package-lock.json 7488d75ef78a2ad9e3e96dfe23e76c4754add000b0f6c5ecb137cfee00beb7e0 179806 package-lock.json
8587168403c255c8acb1bc829629f171598d7697df362836858a0fc89b500b78 5359 package.json 6a6d1f28a67aa554c0dc27a15f3110c7b2b648d88cbba649402f449d1591c784 5397 package.json
2a597a5704c576783b8a72407fbc377fa7506b36a4596ea7f7bce126e394f837 1326 playwright.config.mjs 2a597a5704c576783b8a72407fbc377fa7506b36a4596ea7f7bce126e394f837 1326 playwright.config.mjs
69318fdf054be7aa2fe86ead9847da9da65745d8d5de548c8346f3ba0afc4892 12175 preload.cjs 69318fdf054be7aa2fe86ead9847da9da65745d8d5de548c8346f3ba0afc4892 12175 preload.cjs
abe5dd6fd68f2970cd19ef134094907c67219061d8fe9a1a08324c78de4ad437 484 PUBLISH-AND-ENABLE-UPDATE.cmd abe5dd6fd68f2970cd19ef134094907c67219061d8fe9a1a08324c78de4ad437 484 PUBLISH-AND-ENABLE-UPDATE.cmd
f018383f755352ca448e2ebb1e19b1dba412a3eb793d61e64b02953e300754fd 10538 Publish-ForgeFlow-Release.ps1 f018383f755352ca448e2ebb1e19b1dba412a3eb793d61e64b02953e300754fd 10538 Publish-ForgeFlow-Release.ps1
688fff7d2c989adb97ebb7fae38962656b70304a0aa5d27433c56adf7f136de0 4196 Publish-Missing-Binary-Release.ps1 688fff7d2c989adb97ebb7fae38962656b70304a0aa5d27433c56adf7f136de0 4196 Publish-Missing-Binary-Release.ps1
75602a7e0ce9744d5fc5a73869eec4b47877e00cfcfea68695373a04f8aa5f31 9150 README.md 1d41018ab0276fa16692d35f1b1b2cad21efb5964b540a4d1795ecddd12e21db 9150 README.md
1fa7bf646321e07e40d98f4a7529d5f748c600edd5283f62ee13574b4e97280f 14329 reports/architecture-audit.json 1fa7bf646321e07e40d98f4a7529d5f748c600edd5283f62ee13574b4e97280f 14329 reports/architecture-audit.json
c1ff18f1367691332b189bb7589843a5e0bbde4817e3dd29df4ade7ea71dbd52 1114 reports/architecture-audit.md c1ff18f1367691332b189bb7589843a5e0bbde4817e3dd29df4ade7ea71dbd52 1114 reports/architecture-audit.md
509c7bcff5280349bd9f45ed6151f70372bad7010a9ea582c13e2ccab91fe0cd 6272 scripts/acceptance.mjs 509c7bcff5280349bd9f45ed6151f70372bad7010a9ea582c13e2ccab91fe0cd 6272 scripts/acceptance.mjs
@@ -118,7 +119,7 @@ b83d443f5724ac15393567f3a688aed8315fbe3e5966832c864a9466e0669464 8102
c76507857292c5713e1c699cf02e24b80265da39af2cecd148034bdb874adbb6 5246 scripts/test-authenticode-chain.ps1 c76507857292c5713e1c699cf02e24b80265da39af2cecd148034bdb874adbb6 5246 scripts/test-authenticode-chain.ps1
4393f7dc5f417e6d601a68238f4e26791799a3634acec228fe4d79deaee85eb5 3109 scripts/validate-installed-connections.cjs 4393f7dc5f417e6d601a68238f4e26791799a3634acec228fe4d79deaee85eb5 3109 scripts/validate-installed-connections.cjs
50880ac76b7d681dc65019dc794efc3cea4ffd379507fe0518985312f5b39304 2096 scripts/verify-release-signatures.mjs 50880ac76b7d681dc65019dc794efc3cea4ffd379507fe0518985312f5b39304 2096 scripts/verify-release-signatures.mjs
fb18540c46c0be38bbb0133354838ad75c11187fe6bc0c61860d975fe7761008 17502 scripts/verify.mjs 0100191b9967f5b1614df000fac81978451b22d72a8b9c3fae90e22a822cabf0 17816 scripts/verify.mjs
0b9f03ba3c67ff7cdb2916a902ad8ce25e81a7c90b210e4ae52d2ad029efabf3 2353 scripts/write-release-checksums.mjs 0b9f03ba3c67ff7cdb2916a902ad8ce25e81a7c90b210e4ae52d2ad029efabf3 2353 scripts/write-release-checksums.mjs
619515f524cb89960370ffcbd3fafd3c0e178b95f69c5868b1dd44777f23ec1e 2081 setup-windows.ps1 619515f524cb89960370ffcbd3fafd3c0e178b95f69c5868b1dd44777f23ec1e 2081 setup-windows.ps1
dd613d04b366f2cd071a1685a414016a5fb008082ed1b4cb8b24b79c100f640a 2412 src/main/audit-service.cjs dd613d04b366f2cd071a1685a414016a5fb008082ed1b4cb8b24b79c100f640a 2412 src/main/audit-service.cjs
@@ -132,7 +133,7 @@ a2ef47d5330095b92c2bd22fcc39962091881f9cb60d02e261eb1dd1bd693170 1974
0b7476c2cfe1872601978c20a466c20fe58be35e81b2303e38a753fea62bbc27 32548 src/main/git-service.cjs 0b7476c2cfe1872601978c20a466c20fe58be35e81b2303e38a753fea62bbc27 32548 src/main/git-service.cjs
b23dfa041d9f4597d144601ab8569e69ba748a0d7a075c3ef01154eacc2640ae 7018 src/main/git-validator-policy.cjs b23dfa041d9f4597d144601ab8569e69ba748a0d7a075c3ef01154eacc2640ae 7018 src/main/git-validator-policy.cjs
ca050e9820528b555e6a1dfd89ac8be2f9a0cec6e91254897e6e3b6e116a7eb2 26317 src/main/git-validator-service.cjs ca050e9820528b555e6a1dfd89ac8be2f9a0cec6e91254897e6e3b6e116a7eb2 26317 src/main/git-validator-service.cjs
2faaef0eeec1e473db82b94243674e3812ef5869358b0ec6abf8d645a8794623 20768 src/main/gitea-service.cjs 3cc53e24e023aa0d8bf36c35ce9672ca98e6c74066512c8b59ab42274e838c22 21307 src/main/gitea-service.cjs
2ad3b2e647377f687ad987fe248a142ad399ecac98e4b49965aa7efc6093e5fa 6914 src/main/inventory-classifier.cjs 2ad3b2e647377f687ad987fe248a142ad399ecac98e4b49965aa7efc6093e5fa 6914 src/main/inventory-classifier.cjs
dafdb09133d2b6ec2161a3f0b09354551e54fc606c8107976fca37405643be91 3404 src/main/inventory-review-service.cjs dafdb09133d2b6ec2161a3f0b09354551e54fc606c8107976fca37405643be91 3404 src/main/inventory-review-service.cjs
00989577aed509a7ddfdf9f4df09a196a393a85b5ea59b21089002215e69f065 25949 src/main/ipc.cjs 00989577aed509a7ddfdf9f4df09a196a393a85b5ea59b21089002215e69f065 25949 src/main/ipc.cjs
@@ -204,7 +205,7 @@ e7aebcc0d484a6a59d463d5cb26c11b3ad56e28f6535e7c38a0fe166a41565ea 13690
c00bbd8eae5cef7856c8283d6b40dedb81083bf57ad762e89ab79e0f312da351 3271 tests/git-validator-policy.test.mjs c00bbd8eae5cef7856c8283d6b40dedb81083bf57ad762e89ab79e0f312da351 3271 tests/git-validator-policy.test.mjs
73d00729696e5067ba33dd6d43b018d89ce7fdd561a60ab66648d3283fb54d21 5370 tests/git-validator.test.mjs 73d00729696e5067ba33dd6d43b018d89ce7fdd561a60ab66648d3283fb54d21 5370 tests/git-validator.test.mjs
681ab7bcd02c4dd98d1d8d2092a3521c489d941131e7ffe5903971b940046474 2403 tests/git-workflows.test.mjs 681ab7bcd02c4dd98d1d8d2092a3521c489d941131e7ffe5903971b940046474 2403 tests/git-workflows.test.mjs
ca2c2c47b2532a74c7a77b9473ff417e0a34f0dbd8801936fd0e301a38f06a9a 18128 tests/gitea-actions.test.mjs d633c59bd910008223c834c6d7f3e5666c685a0881944263ede2d42cc69d3151 18710 tests/gitea-actions.test.mjs
fcc9a063882840dd89d74c2785284c8f2f6a9e5acec482b6d89ed8de62efdb85 9635 tests/inventory-classifier.test.mjs fcc9a063882840dd89d74c2785284c8f2f6a9e5acec482b6d89ed8de62efdb85 9635 tests/inventory-classifier.test.mjs
9643622a03ea0a88fb7d72ce43e469ff4f814902f4b3d2a672990637d66ef075 2009 tests/ipc-contract.test.mjs 9643622a03ea0a88fb7d72ce43e469ff4f814902f4b3d2a672990637d66ef075 2009 tests/ipc-contract.test.mjs
caf98cbd9de9b119dae610ee53fa333a7a11214f34762247452fbb85e8bbf725 2392 tests/log-redaction.test.mjs caf98cbd9de9b119dae610ee53fa333a7a11214f34762247452fbb85e8bbf725 2392 tests/log-redaction.test.mjs
+9
View File
@@ -0,0 +1,9 @@
# ForgeFlow 0.10.2
## Packaged updater origin repair
- Gitea release assets that expose an internal HTTP `ROOT_URL` are safely rewritten to ForgeFlow's configured public HTTPS Gitea origin.
- Authentication remains same-origin: the Gitea token is never forwarded to an internal address, CDN or unrelated redirect target.
- Published Windows executables are still validated as PE files and against their release SHA-256 sidecars before staging.
- The live authenticated updater acceptance downloads the exact published installer and proves its byte count and SHA-256 digest.
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "forgeflow", "name": "forgeflow",
"version": "0.10.1", "version": "0.10.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "forgeflow", "name": "forgeflow",
"version": "0.10.1", "version": "0.10.2",
"dependencies": { "dependencies": {
"ssh2": "1.17.0" "ssh2": "1.17.0"
}, },
+2 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "forgeflow", "name": "forgeflow",
"version": "0.10.1", "version": "0.10.2",
"private": true, "private": true,
"description": "Desktop release cockpit for local Git, Gitea Actions and controlled exact-commit deployments.", "description": "Desktop release cockpit for local Git, Gitea Actions and controlled exact-commit deployments.",
"main": "main.cjs", "main": "main.cjs",
@@ -106,6 +106,7 @@
"docs/RELEASE_NOTES_0.9.5.md", "docs/RELEASE_NOTES_0.9.5.md",
"docs/RELEASE_NOTES_0.10.0.md", "docs/RELEASE_NOTES_0.10.0.md",
"docs/RELEASE_NOTES_0.10.1.md", "docs/RELEASE_NOTES_0.10.1.md",
"docs/RELEASE_NOTES_0.10.2.md",
"docs/CURRENT_STATE.md", "docs/CURRENT_STATE.md",
"docs/MUTATION_MODEL.md", "docs/MUTATION_MODEL.md",
"docs/RELEASING.md", "docs/RELEASING.md",
+7 -2
View File
@@ -81,6 +81,7 @@ const required = [
"docs/RELEASE_NOTES_0.9.5.md", "docs/RELEASE_NOTES_0.9.5.md",
"docs/RELEASE_NOTES_0.10.0.md", "docs/RELEASE_NOTES_0.10.0.md",
"docs/RELEASE_NOTES_0.10.1.md", "docs/RELEASE_NOTES_0.10.1.md",
"docs/RELEASE_NOTES_0.10.2.md",
"docs/UPDATING.md", "docs/UPDATING.md",
"docs/DIAGNOSTICS.md", "docs/DIAGNOSTICS.md",
"docs/DEPLOYMENT_SETUP.md", "docs/DEPLOYMENT_SETUP.md",
@@ -119,9 +120,9 @@ for (const file of required) await access(path.join(root, file));
const packageJson = JSON.parse( const packageJson = JSON.parse(
await readFile(path.join(root, "package.json"), "utf8"), await readFile(path.join(root, "package.json"), "utf8"),
); );
if (packageJson.version !== "0.10.1") if (packageJson.version !== "0.10.2")
throw new Error( throw new Error(
`Expected package version 0.10.1, got ${packageJson.version}.`, `Expected package version 0.10.2, got ${packageJson.version}.`,
); );
const sourceManifest = await readFile( const sourceManifest = await readFile(
path.join(root, "SOURCE_MANIFEST.txt"), path.join(root, "SOURCE_MANIFEST.txt"),
@@ -439,6 +440,10 @@ const release0101 = await readFile(path.join(root, "docs/RELEASE_NOTES_0.10.1.md
for (const phrase of ["certificate-free updates", "case-insensitive", "read-only deploy keys", "SHA-256"]) { for (const phrase of ["certificate-free updates", "case-insensitive", "read-only deploy keys", "SHA-256"]) {
if (!release0101.includes(phrase)) throw new Error(`0.10.1 release notes are missing: ${phrase}`); if (!release0101.includes(phrase)) throw new Error(`0.10.1 release notes are missing: ${phrase}`);
} }
const release0102 = await readFile(path.join(root, "docs/RELEASE_NOTES_0.10.2.md"), "utf8");
for (const phrase of ["internal HTTP", "public HTTPS", "same-origin", "SHA-256"]) {
if (!release0102.includes(phrase)) throw new Error(`0.10.2 release notes are missing: ${phrase}`);
}
const configSource = await readFile(path.join(root, "src/main/config-store.cjs"), "utf8"); const configSource = await readFile(path.join(root, "src/main/config-store.cjs"), "utf8");
for (const mode of ["server-git", "push-bundle", "monitor-only"]) { for (const mode of ["server-git", "push-bundle", "monitor-only"]) {
if (!configSource.includes(mode)) throw new Error(`Deployment configuration is missing mode: ${mode}`); if (!configSource.includes(mode)) throw new Error(`Deployment configuration is missing mode: ${mode}`);
+6
View File
@@ -426,6 +426,12 @@ class GiteaService {
if (!downloadUrl) { if (!downloadUrl) {
throw new Error("Gitea did not provide a release asset download URL."); throw new Error("Gitea did not provide a release asset download URL.");
} }
const configuredBase = new URL(normalizeBaseUrl(this.store.data.gitea.baseUrl));
const publishedUrl = new URL(downloadUrl, configuredBase);
const releasePrefix = `/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/download/`.toLowerCase();
if (publishedUrl.origin !== configuredBase.origin && publishedUrl.protocol === "http:" && publishedUrl.pathname.toLowerCase().startsWith(releasePrefix)) {
downloadUrl = new URL(`${publishedUrl.pathname}${publishedUrl.search}`, configuredBase).toString();
}
return this.downloadAuthenticated(downloadUrl, options); return this.downloadAuthenticated(downloadUrl, options);
} }
+13
View File
@@ -156,6 +156,19 @@ test('uses a release-provided browser download URL without requesting metadata a
assert.equal(requested, 'https://gitea.example.test/attachments/direct.exe'); assert.equal(requested, 'https://gitea.example.test/attachments/direct.exe');
}); });
test('rewrites Gitea internal HTTP release URLs to the configured public origin', async () => {
const service = new GiteaService(makeStore());
let requested = '';
service.downloadAuthenticated = async (pathname) => {
requested = pathname;
return Buffer.from('asset');
};
await service.downloadReleaseAsset('Jens', 'ForgeFlow', 107, 412, {
downloadUrl: 'http://192.168.10.150:3000/Jens/ForgeFlow/releases/download/v0.10.1/ForgeFlow.exe',
});
assert.equal(requested, 'https://gitea.example.test/Jens/ForgeFlow/releases/download/v0.10.1/ForgeFlow.exe');
});
test('creates conservative default branch protection rules', async () => { test('creates conservative default branch protection rules', async () => {
const service = new GiteaService(makeStore()); const service = new GiteaService(makeStore());
let request = null; let request = null;