Require release versions for script uploads
CI / checks (push) Successful in 5m26s

This commit is contained in:
2026-10-12 18:46:57 -04:00
parent ffda04f276
commit 2f52dcb1ef
50 changed files with 871 additions and 113 deletions
@@ -39,7 +39,14 @@ export async function POST({ params, request }: { params: { id: string }; reques
if (isHttpError(error)) throw error;
return json(
{ ok: false, error: (error as Error).message },
{ status: error instanceof BetaError || error instanceof ScriptError ? 409 : 400 }
{
status:
error instanceof ScriptError && error.kind === 'invalid-release-version'
? 400
: error instanceof BetaError || error instanceof ScriptError
? 409
: 400
}
);
}
}
+4 -1
View File
@@ -89,7 +89,10 @@ export async function POST({ request, url }: { request: Request; url: URL }) {
return json({ ok: true, script, versionId: version.id });
} catch (err) {
if (err instanceof ScriptError) {
return json({ ok: false, error: err.message, kind: err.kind }, { status: 409 });
return json(
{ ok: false, error: err.message, kind: err.kind },
{ status: err.kind === 'invalid-release-version' ? 400 : 409 }
);
}
throw err;
}
+1 -1
View File
@@ -50,7 +50,7 @@ export async function GET({ params }: { params: { id: string } }) {
script.kind === 'script' || script.kind === 'plugin'
? db()
.prepare(
`SELECT i.server, v.version, v.id AS versionId, i.updated_at AS recordedAt FROM server_scripts i JOIN script_versions v ON v.id = i.script_version_id WHERE v.script_id = ? AND i.rel_path = ? ORDER BY i.server`
`SELECT i.server, v.version, v.release_version, v.id AS versionId, i.updated_at AS recordedAt FROM server_scripts i JOIN script_versions v ON v.id = i.script_version_id WHERE v.script_id = ? AND i.rel_path = ? ORDER BY i.server`
)
.all(id, script.target_rel_path)
: [],
+13 -12
View File
@@ -1,8 +1,11 @@
import { artifactFormBody } from '$lib/server/request-body.js';
import { json } from '@sveltejs/kit';
import { uploadNewVersion, getScript, ScriptError } from '$lib/server/fleet/scripts.js';
import { createHash } from 'node:crypto';
import { db } from '$lib/server/db/index.js';
import {
uploadNewVersion,
getScript,
getLatestVersion,
ScriptError
} from '$lib/server/fleet/scripts.js';
import { findRunningBetaForScript } from '$lib/server/fleet/beta.js';
function parseId(idRaw: string): number | null {
@@ -11,7 +14,7 @@ function parseId(idRaw: string): number | null {
}
// Multipart POST — creates a new version from an uploaded file. Fields:
// content (file), notes and releaseVersion (optional). Response includes a "betaRequired" hint
// content (file), notes (optional) and releaseVersion (required for scripts). Response includes a "betaRequired" hint
// when the script has a scope so the UI can nudge the operator to open a beta.
export async function POST({ params, request }: { params: { id: string }; request: Request }) {
const scriptId = parseId(params.id);
@@ -45,21 +48,16 @@ export async function POST({ params, request }: { params: { id: string }; reques
{ status: 409 }
);
}
const sha = createHash('sha256').update(content).digest('hex');
const existing = db()
.prepare(
'SELECT id, version, sha256, size FROM script_versions WHERE script_id = ? AND sha256 = ? ORDER BY version DESC LIMIT 1'
)
.get(scriptId, sha);
if (existing) return json({ ok: true, version: existing, reused: true });
}
try {
const releaseVersion = form.has('releaseVersion')
? String(form.get('releaseVersion'))
: undefined;
const previous = getLatestVersion(scriptId);
const version = uploadNewVersion(scriptId, content, notes, releaseVersion);
return json({
ok: true,
reused: script.kind === 'script' && version.version <= (previous?.version ?? 0),
version: {
id: version.id,
version: version.version,
@@ -73,7 +71,10 @@ export async function POST({ params, request }: { params: { id: string }; reques
});
} catch (err) {
if (err instanceof ScriptError) {
return json({ ok: false, error: err.message, kind: err.kind }, { status: 409 });
return json(
{ ok: false, error: err.message, kind: err.kind },
{ status: err.kind === 'invalid-release-version' ? 400 : 409 }
);
}
throw err;
}
+1 -1
View File
@@ -15,7 +15,7 @@ export async function POST({ request }: { request: Request }) {
.digest('hex');
const duplicates = db()
.prepare(
`SELECT v.script_id AS scriptId, v.id AS versionId, v.version
`SELECT v.script_id AS scriptId, v.id AS versionId, v.version, v.release_version
FROM script_versions v JOIN scripts s ON s.id = v.script_id
WHERE s.kind = 'script' AND v.sha256 = ? ORDER BY v.version DESC`
)