The in-app updater, the Scoop manifest, the Chocolatey package and the script that regenerates both read releases from https://git.kof22.com/KofTwentyTwo/gclo. ADR 0009; threat model, README and SECURITY.md follow.
The project's home moved to Gitea (#165). The owner's decision: 1.1.1 is installed once by hand from there, and every later version must update and download from there.
How it was tested
A standalone program read the live server through Velopack's GiteaSource (the library and version the app uses): stable returns 1.1.0 full and delta plus 1.0.0; dev with prereleases returns its packages.
The 1.1.0 CLI zip on Gitea has the SHA-256 pinned in both manifests.
Update-PackageManifests.ps1 dry-run in a scratch copy: valid Scoop JSON (version check kept), Chocolatey URL, hash and release notes link.
PackagingManifestTests now pin the Gitea URLs and the version check.
Gates: build, 1,072 engine and 212 CLI tests, 100% line coverage, format, script analyzer clean, UI suite 13 of 13.
Not testable here: an actual in-place update from 1.1.1 to a later version; it needs two published releases. It is on the release checklist.
Not in this PR
How a release is built and published on Gitea. .github/workflows/release.yml is unchanged and publishes to GitHub.
Checklist
Commits are signed and signed off (git commit -S -s)
Zero build warnings; format and lint are clean
Tests added or updated; the 100% coverage gate still passes
Docs updated for user-visible changes; threat model updated if the attack surface changed
No secrets, credentials, or personal data
New dependencies are justified below, or none were added (none; GiteaSource is part of Velopack)
Substantial AI assistance, if any, is noted here (written with Claude Code)
## What
The in-app updater, the Scoop manifest, the Chocolatey package and the script that regenerates both read releases from `https://git.kof22.com/KofTwentyTwo/gclo`. ADR 0009; threat model, README and SECURITY.md follow.
## Why
Closes #170
The project's home moved to Gitea (#165). The owner's decision: 1.1.1 is installed once by hand from there, and every later version must update and download from there.
## How it was tested
- A standalone program read the live server through Velopack's `GiteaSource` (the library and version the app uses): stable returns 1.1.0 full and delta plus 1.0.0; dev with prereleases returns its packages.
- The 1.1.0 CLI zip on Gitea has the SHA-256 pinned in both manifests.
- `Update-PackageManifests.ps1` dry-run in a scratch copy: valid Scoop JSON (version check kept), Chocolatey URL, hash and release notes link.
- `PackagingManifestTests` now pin the Gitea URLs and the version check.
- Gates: build, 1,072 engine and 212 CLI tests, 100% line coverage, format, script analyzer clean, UI suite 13 of 13.
- **Not testable here:** an actual in-place update from 1.1.1 to a later version; it needs two published releases. It is on the release checklist.
## Not in this PR
How a release is built and published on Gitea. `.github/workflows/release.yml` is unchanged and publishes to GitHub.
## Checklist
- [x] Commits are signed and signed off (`git commit -S -s`)
- [x] Zero build warnings; format and lint are clean
- [x] Tests added or updated; the 100% coverage gate still passes
- [x] Docs updated for user-visible changes; threat model updated if the attack surface changed
- [x] No secrets, credentials, or personal data
- [x] New dependencies are justified below, or none were added (none; `GiteaSource` is part of Velopack)
- [x] Substantial AI assistance, if any, is noted here (written with Claude Code)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Not merged yet. Two things are the owner's to answer first:
Is git.kof22.com reachable from outside the local network? From the build machine it resolves to a private address, so every check here ran internally. If it is not public, the updater, Scoop, the Help links and the Share invitation do not work for anyone outside.
How 1.1.1 is published. The release workflow builds and publishes on GitHub; nothing builds on Gitea yet.
Verified by the reviewer against the server:GiteaSource requests …/api/v1/repos/KofTwentyTwo/gclo/releases?limit=10&page=1&draft=false anonymously and downloads through browser_download_url; UpdateManager.CheckForUpdatesAsync gives the right answer for five installed-version and channel combinations with no channel crossing; Scoop's own checkver.ps1 returns 1.1.0 and auto-update finds the hash; the CLI zip matches the pinned hash.
Threat model T1 and ADR 0009 said or implied that a signature protects updates. It does not: the updater checks hashes that come from the same feed. Both now say that whoever can publish a release on the server, or holds its certificate or DNS, can deliver an update without a warning; T1 is marked accepted.
The next release would have pushed a Chocolatey package pointing at a file not yet on Gitea. Update-PackageManifests.ps1 now refuses to write a manifest whose download does not answer (checked both ways).
docs/RELEASING.md: a section on what the release on git.kof22.com must contain (same assets, same prerelease flag, before the manifests, at most nine prereleases newer than the latest stable), the verify step, and where a broken release is withdrawn.
PackagingManifestTests pin the auto-update URL, the hash URL, the release notes link, the notes and the version-check expression exactly.
"GitHub" removed from UpdateService (including a message users see); Chocolatey license and icon links; ADR 0001 and 0003 marked as amended; the README no longer claims that older versions cannot find 1.1.1.
Recorded, not changed
Velopack reads only the ten newest releases; documented as a rule for the release procedure.
Dev installs under the old app id may be offered the gclo-dev package; untested.
The winget job builds its URL from the GitHub server URL; the job is not enabled.
A v* tag pushed to Gitea may try to run release.yml there if a matching runner exists.
Gates: build, 1,072 engine and 212 CLI tests, 100% line coverage, format, script analyzer clean.
## Independent review: MERGE AFTER FIXES
**Not merged yet.** Two things are the owner's to answer first:
1. **Is git.kof22.com reachable from outside the local network?** From the build machine it resolves to a private address, so every check here ran internally. If it is not public, the updater, Scoop, the Help links and the Share invitation do not work for anyone outside.
2. **How 1.1.1 is published.** The release workflow builds and publishes on GitHub; nothing builds on Gitea yet.
**Verified by the reviewer against the server:** `GiteaSource` requests `…/api/v1/repos/KofTwentyTwo/gclo/releases?limit=10&page=1&draft=false` anonymously and downloads through `browser_download_url`; `UpdateManager.CheckForUpdatesAsync` gives the right answer for five installed-version and channel combinations with no channel crossing; Scoop's own `checkver.ps1` returns 1.1.0 and auto-update finds the hash; the CLI zip matches the pinned hash.
**Fixed in 6a26883**
- Threat model T1 and ADR 0009 said or implied that a signature protects updates. It does not: the updater checks hashes that come from the same feed. Both now say that whoever can publish a release on the server, or holds its certificate or DNS, can deliver an update without a warning; T1 is marked accepted.
- The next release would have pushed a Chocolatey package pointing at a file not yet on Gitea. `Update-PackageManifests.ps1` now refuses to write a manifest whose download does not answer (checked both ways).
- `docs/RELEASING.md`: a section on what the release on git.kof22.com must contain (same assets, same prerelease flag, before the manifests, at most nine prereleases newer than the latest stable), the verify step, and where a broken release is withdrawn.
- `PackagingManifestTests` pin the auto-update URL, the hash URL, the release notes link, the notes and the version-check expression exactly.
- "GitHub" removed from `UpdateService` (including a message users see); Chocolatey license and icon links; ADR 0001 and 0003 marked as amended; the README no longer claims that older versions cannot find 1.1.1.
**Recorded, not changed**
- Velopack reads only the ten newest releases; documented as a rule for the release procedure.
- Dev installs under the old app id may be offered the `gclo-dev` package; untested.
- The winget job builds its URL from the GitHub server URL; the job is not enabled.
- A `v*` tag pushed to Gitea may try to run `release.yml` there if a matching runner exists.
**Gates:** build, 1,072 engine and 212 CLI tests, 100% line coverage, format, script analyzer clean.
The in-app updater reads the project's releases on its own Gitea server
through Velopack's GiteaSource, anonymously. The Scoop manifest (homepage,
download, version check, auto-update), the Chocolatey package and the script
that regenerates both for a release name the same server. ADR 0009 amends
ADR 0001; the threat model records the change of where that trust is placed.
Versions up to 1.1.0 look for updates on GitHub and are updated once by hand.
Closes#170
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
- Threat model T1 and ADR 0009 state that the updater checks hashes from the
same feed and no signature: whoever can publish on the server can deliver an
update. T1 is accepted, not mitigated.
- Update-PackageManifests.ps1 refuses to write a manifest whose download does
not answer, so a package cannot be pushed before its release is on the
server.
- RELEASING.md: what a release on git.kof22.com must contain, the prerelease
flag, the ten-release window, and where a broken release is withdrawn.
- PackagingManifestTests pin the auto-update URL, the hash URL, the release
notes link and the version check exactly.
- UpdateService no longer says GitHub; the Chocolatey license and icon links
and ADR 0001/0003 follow.
Refs #170
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
Rebased onto main after #175 (388b57e); tip 61261e5. Two conflicts in the threat model's revision table, both resolved by keeping both rows (the #174 row, and the revised update-feed row of this pull request). Gates on the rebased branch, started from PowerShell: build with warnings as errors 0, engine 1,141, CLI 212, line coverage 100% on the three gated assemblies, format clean, UI suite 13 of 13.
Merging: the owner's instruction is that versions from 1.1.1 on work from git.kof22.com. How 1.1.1 itself is published, and whether the server answers from outside the owner's network, stay open and are recorded for the release step.
Rebased onto main after #175 (388b57e); tip 61261e5. Two conflicts in the threat model's revision table, both resolved by keeping both rows (the #174 row, and the revised update-feed row of this pull request). Gates on the rebased branch, started from PowerShell: build with warnings as errors 0, engine 1,141, CLI 212, line coverage 100% on the three gated assemblies, format clean, UI suite 13 of 13.
Merging: the owner's instruction is that versions from 1.1.1 on work from git.kof22.com. How 1.1.1 itself is published, and whether the server answers from outside the owner's network, stay open and are recorded for the release step.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
The in-app updater, the Scoop manifest, the Chocolatey package and the script that regenerates both read releases from
https://git.kof22.com/KofTwentyTwo/gclo. ADR 0009; threat model, README and SECURITY.md follow.Why
Closes #170
The project's home moved to Gitea (#165). The owner's decision: 1.1.1 is installed once by hand from there, and every later version must update and download from there.
How it was tested
GiteaSource(the library and version the app uses): stable returns 1.1.0 full and delta plus 1.0.0; dev with prereleases returns its packages.Update-PackageManifests.ps1dry-run in a scratch copy: valid Scoop JSON (version check kept), Chocolatey URL, hash and release notes link.PackagingManifestTestsnow pin the Gitea URLs and the version check.Not in this PR
How a release is built and published on Gitea.
.github/workflows/release.ymlis unchanged and publishes to GitHub.Checklist
git commit -S -s)GiteaSourceis part of Velopack)🤖 Generated with Claude Code
Independent review: MERGE AFTER FIXES
Not merged yet. Two things are the owner's to answer first:
Verified by the reviewer against the server:
GiteaSourcerequests…/api/v1/repos/KofTwentyTwo/gclo/releases?limit=10&page=1&draft=falseanonymously and downloads throughbrowser_download_url;UpdateManager.CheckForUpdatesAsyncgives the right answer for five installed-version and channel combinations with no channel crossing; Scoop's owncheckver.ps1returns 1.1.0 and auto-update finds the hash; the CLI zip matches the pinned hash.Fixed in
6a26883Update-PackageManifests.ps1now refuses to write a manifest whose download does not answer (checked both ways).docs/RELEASING.md: a section on what the release on git.kof22.com must contain (same assets, same prerelease flag, before the manifests, at most nine prereleases newer than the latest stable), the verify step, and where a broken release is withdrawn.PackagingManifestTestspin the auto-update URL, the hash URL, the release notes link, the notes and the version-check expression exactly.UpdateService(including a message users see); Chocolatey license and icon links; ADR 0001 and 0003 marked as amended; the README no longer claims that older versions cannot find 1.1.1.Recorded, not changed
gclo-devpackage; untested.v*tag pushed to Gitea may try to runrelease.ymlthere if a matching runner exists.Gates: build, 1,072 engine and 212 CLI tests, 100% line coverage, format, script analyzer clean.
6053d5d60eto61261e58e7Rebased onto main after #175 (
388b57e); tip61261e5. Two conflicts in the threat model's revision table, both resolved by keeping both rows (the #174 row, and the revised update-feed row of this pull request). Gates on the rebased branch, started from PowerShell: build with warnings as errors 0, engine 1,141, CLI 212, line coverage 100% on the three gated assemblies, format clean, UI suite 13 of 13.Merging: the owner's instruction is that versions from 1.1.1 on work from git.kof22.com. How 1.1.1 itself is published, and whether the server answers from outside the owner's network, stay open and are recorded for the release step.
🤖 Generated with Claude Code