feat(fpagent): pin releases, report upgrades, restart the service

The installer gains --tag to install a specific release (gateway route
/fpagent/releases/tags/:tag), derives the git hash from the asset name,
and hands it to the bundle installer as VERSION so upgrades are reported
and the installed version is recorded. Service restart on upgrade lives
in the bundle installer, which owns the systemd unit.
This commit is contained in:
2026-10-02 11:26:35 +01:00
parent 0698a9c9a9
commit 2ad4aa63c6
3 changed files with 135 additions and 18 deletions
+18 -5
View File
@@ -345,12 +345,9 @@ export function createApp(overrides = {}) {
message: 'The Fingerprint Agent installer is not configured on this deployment.',
});
app.get('/fpagent/releases/latest', async (req, res) => {
if (!cfg.giteaToken) return installerNotConfigured(res);
const releasePayload = async (res, giteaPath) => {
try {
const r = await cfg.giteaFetch(`${giteaBase()}/api/v1/repos/${cfg.fpagentRepo}/releases/latest`, {
headers: giteaHeaders(),
});
const r = await cfg.giteaFetch(`${giteaBase()}${giteaPath}`, { headers: giteaHeaders() });
if (!r.ok) {
return res.status(502).json({ ok: false, message: 'Could not reach the Fingerprint Agent releases.' });
}
@@ -372,6 +369,22 @@ export function createApp(overrides = {}) {
} catch {
res.status(502).json({ ok: false, message: 'Could not reach the Fingerprint Agent releases.' });
}
};
app.get('/fpagent/releases/latest', (req, res) => {
if (!cfg.giteaToken) return installerNotConfigured(res);
return releasePayload(res, `/api/v1/repos/${cfg.fpagentRepo}/releases/latest`);
});
app.get('/fpagent/releases/tags/:tag', (req, res) => {
if (!cfg.giteaToken) return installerNotConfigured(res);
if (!SAFE_ASSET.test(req.params.tag)) {
return res.status(400).json({ ok: false, message: 'Unknown release tag.' });
}
return releasePayload(
res,
`/api/v1/repos/${cfg.fpagentRepo}/releases/tags/${encodeURIComponent(req.params.tag)}`
);
});
app.get('/fpagent/releases/download/:tag/:name', async (req, res) => {