Remove legacy runtime deployment paths
This commit is contained in:
@@ -1243,21 +1243,6 @@
|
||||
}
|
||||
],
|
||||
"installPlans": [
|
||||
{
|
||||
"key": "install-scum-server",
|
||||
"title": "Install SCUM Dedicated Server",
|
||||
"platforms": [
|
||||
"windows"
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"type": "steamcmd-app",
|
||||
"targetKey": "server/install-root",
|
||||
"packageManager": "steamcmd",
|
||||
"packageName": "3792580"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "install-steamcmd-linux",
|
||||
"title": "Install SteamCMD",
|
||||
@@ -1416,7 +1401,7 @@
|
||||
"targetKey": "ue4ss/scum-simple-rcon",
|
||||
"modKey": "scum_simple_rcon",
|
||||
"dllRef": "ue4ss/Mods/scum_simple_rcon/dlls/main.dll",
|
||||
"scumExecutableChecksum": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
"targetExecutableChecksum": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
"ue4ssAbi": "ue4ss-3.0",
|
||||
"supportedTargets": [
|
||||
{
|
||||
|
||||
@@ -109,12 +109,6 @@
|
||||
"items": { "$ref": "#/$defs/runtimeInstallPlan" },
|
||||
"uniqueItems": true
|
||||
},
|
||||
"serverDeployments": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/runtimeServerDeploymentProfile" },
|
||||
"uniqueItems": true,
|
||||
"maxItems": 8
|
||||
},
|
||||
"logSources": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/runtimeLogSource" },
|
||||
@@ -557,9 +551,9 @@
|
||||
"required": ["type", "targetKey"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": { "enum": ["package", "verified-download", "steamcmd-app", "manual"] },
|
||||
"type": { "enum": ["package", "verified-download", "manual"] },
|
||||
"targetKey": { "$ref": "#/$defs/logicalKey" },
|
||||
"packageManager": { "enum": ["winget", "choco", "scoop", "apt", "yum", "dnf", "pacman", "zypper", "brew", "steamcmd", "manual"] },
|
||||
"packageManager": { "enum": ["winget", "choco", "scoop", "apt", "yum", "dnf", "pacman", "zypper", "brew"] },
|
||||
"packageName": { "type": "string", "pattern": "^[a-zA-Z0-9_.:+@/-]+$", "maxLength": 120 },
|
||||
"version": { "type": "string", "maxLength": 80 },
|
||||
"downloadRef": { "type": "string", "pattern": "^https://[a-zA-Z0-9._~:/?#\\[\\]@!$&'()*+,;=%-]+$", "maxLength": 240 },
|
||||
@@ -576,16 +570,6 @@
|
||||
{
|
||||
"if": { "properties": { "type": { "const": "verified-download" } }, "required": ["type"] },
|
||||
"then": { "required": ["downloadRef", "checksum"] }
|
||||
},
|
||||
{
|
||||
"if": { "properties": { "type": { "const": "steamcmd-app" } }, "required": ["type"] },
|
||||
"then": {
|
||||
"required": ["packageName"],
|
||||
"properties": {
|
||||
"packageManager": { "const": "steamcmd" },
|
||||
"packageName": { "type": "string", "pattern": "^[0-9]{1,12}$" }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -600,68 +584,6 @@
|
||||
"steps": { "type": "array", "items": { "$ref": "#/$defs/runtimeInstallStep" }, "minItems": 1, "maxItems": 64 }
|
||||
}
|
||||
},
|
||||
"runtimeServerConfigMapping": {
|
||||
"type": "object",
|
||||
"required": ["fieldKey", "configKey", "valueType"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"fieldKey": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9._/-]*$", "maxLength": 80 },
|
||||
"configKey": { "$ref": "#/$defs/logicalKey" },
|
||||
"valueType": { "enum": ["text", "integer", "number", "boolean", "port"] },
|
||||
"required": { "type": "boolean" }
|
||||
}
|
||||
},
|
||||
"runtimeServerDiscoveryMarker": {
|
||||
"type": "object",
|
||||
"required": ["key", "kind", "targetKey"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"key": { "$ref": "#/$defs/logicalKey" },
|
||||
"kind": { "enum": ["file.exists", "command.version", "port.open", "steam.app"] },
|
||||
"targetKey": { "$ref": "#/$defs/logicalKey" },
|
||||
"expected": { "type": "string", "maxLength": 120 },
|
||||
"required": { "type": "boolean" }
|
||||
}
|
||||
},
|
||||
"runtimeServerVerificationCheck": {
|
||||
"type": "object",
|
||||
"required": ["key", "kind", "targetKey"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"key": { "$ref": "#/$defs/logicalKey" },
|
||||
"kind": { "enum": ["executable.present", "version.matches", "port.bound", "config.readable", "process.healthy"] },
|
||||
"targetKey": { "$ref": "#/$defs/logicalKey" },
|
||||
"required": { "type": "boolean" }
|
||||
}
|
||||
},
|
||||
"runtimeServerDeploymentProfile": {
|
||||
"type": "object",
|
||||
"required": ["key", "version", "supportedTargets", "steamAppId", "executableKey", "installRootKey", "configKey", "configFormat", "configMappings", "discoveryMarkers", "verificationChecks"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"key": { "$ref": "#/$defs/logicalKey" },
|
||||
"version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z.-]+)?$" },
|
||||
"supportedTargets": { "type": "array", "items": { "$ref": "#/$defs/runtimeTarget" }, "minItems": 1, "uniqueItems": true },
|
||||
"steamAppId": { "type": "string", "pattern": "^[0-9]{1,12}$" },
|
||||
"executableKey": { "$ref": "#/$defs/logicalKey" },
|
||||
"installRootKey": { "$ref": "#/$defs/logicalKey" },
|
||||
"configKey": { "$ref": "#/$defs/logicalKey" },
|
||||
"configFormat": { "enum": ["ini", "json", "yaml", "properties"] },
|
||||
"prerequisites": { "type": "array", "items": { "$ref": "#/$defs/runtimeServerPrerequisite" }, "maxItems": 16 },
|
||||
"configMappings": { "type": "array", "items": { "$ref": "#/$defs/runtimeServerConfigMapping" }, "minItems": 1, "maxItems": 32, "uniqueItems": true },
|
||||
"discoveryMarkers": { "type": "array", "items": { "$ref": "#/$defs/runtimeServerDiscoveryMarker" }, "minItems": 1, "maxItems": 32, "uniqueItems": true },
|
||||
"verificationChecks": { "type": "array", "items": { "$ref": "#/$defs/runtimeServerVerificationCheck" }, "minItems": 4, "maxItems": 16, "uniqueItems": true }
|
||||
}
|
||||
},
|
||||
"runtimeServerPrerequisite": {
|
||||
"type": "object",
|
||||
"required": ["key", "kind"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"key": { "$ref": "#/$defs/logicalKey" },
|
||||
"kind": { "enum": ["steamcmd", "windows-vcredist", "windows-directx"] }
|
||||
}
|
||||
},
|
||||
"runtimeLogSource": {
|
||||
"type": "object",
|
||||
"required": ["key", "kind", "streamKey"],
|
||||
@@ -724,7 +646,7 @@
|
||||
"targetKey": { "$ref": "#/$defs/logicalKey" },
|
||||
"modKey": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,79}$" },
|
||||
"dllRef": { "type": "string", "pattern": "^ue4ss/Mods/[a-z0-9][a-z0-9_-]{0,79}/dlls/main\\.dll$", "maxLength": 160 },
|
||||
"scumExecutableChecksum": { "type": "string", "pattern": "^sha256:[a-fA-F0-9]{64}$" },
|
||||
"targetExecutableChecksum": { "type": "string", "pattern": "^sha256:[a-fA-F0-9]{64}$" },
|
||||
"ue4ssAbi": { "type": "string", "pattern": "^[A-Za-z0-9._-]{1,80}$" },
|
||||
"supportedTargets": { "type": "array", "items": { "$ref": "#/$defs/runtimeTarget" }, "minItems": 1, "maxItems": 1, "uniqueItems": true },
|
||||
"updateOnStart": { "const": true },
|
||||
@@ -733,7 +655,7 @@
|
||||
"allOf": [
|
||||
{
|
||||
"if": { "properties": { "releaseState": { "const": "ready" } }, "required": ["releaseState"] },
|
||||
"then": { "required": ["releaseUrl", "checksum", "sizeBytes", "scumExecutableChecksum", "ue4ssAbi"] }
|
||||
"then": { "required": ["releaseUrl", "checksum", "sizeBytes", "targetExecutableChecksum", "ue4ssAbi"] }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -320,26 +320,9 @@ function validateDependencyPlans(manifest: unknown): string[] {
|
||||
}
|
||||
|
||||
function validateServerDeploymentProfiles(manifest: unknown): string[] {
|
||||
if (typeof manifest !== "object" || manifest === null || !("server" in manifest)) return [];
|
||||
const record = manifest as { server?: { createFields?: Array<{ key?: string }> }; runtimeProfiles?: { serverDeployments?: Array<any> } };
|
||||
const declaredFields = new Set((record.server?.createFields ?? []).map((field) => field.key).filter((key): key is string => Boolean(key)));
|
||||
const errors: string[] = [];
|
||||
for (const [index, profile] of (record.runtimeProfiles?.serverDeployments ?? []).entries()) {
|
||||
const location = `manifest.runtimeProfiles.serverDeployments[${index}]`;
|
||||
const mappingKeys = new Set<string>();
|
||||
for (const [mappingIndex, mapping] of (profile.configMappings ?? []).entries()) {
|
||||
const mappingLocation = `${location}.configMappings[${mappingIndex}]`;
|
||||
if (!declaredFields.has(mapping.fieldKey)) errors.push(`${mappingLocation}.fieldKey: must reference a declared server.createFields key`);
|
||||
if (mappingKeys.has(mapping.fieldKey)) errors.push(`${mappingLocation}.fieldKey: duplicate mapping`);
|
||||
mappingKeys.add(mapping.fieldKey);
|
||||
}
|
||||
const requiredChecks = new Set(["executable.present", "port.bound", "config.readable", "process.healthy"]);
|
||||
for (const check of profile.verificationChecks ?? []) {
|
||||
if (check.required) requiredChecks.delete(check.kind);
|
||||
}
|
||||
for (const missing of requiredChecks) errors.push(`${location}.verificationChecks: required check ${missing} is missing`);
|
||||
}
|
||||
return errors;
|
||||
if (typeof manifest !== "object" || manifest === null || !("server" in manifest)) return [];
|
||||
const record = manifest as { runtimeProfiles?: { serverDeployments?: unknown } };
|
||||
return record.runtimeProfiles?.serverDeployments === undefined ? [] : ["manifest.runtimeProfiles.serverDeployments: legacy server deployment profiles are no longer supported"];
|
||||
}
|
||||
|
||||
function validateUnsupportedLegacyClientManagerDeclarations(manifest: unknown): string[] {
|
||||
@@ -380,7 +363,7 @@ function validateDLLExtensionProfiles(manifest: unknown): string[] {
|
||||
targetKey?: string;
|
||||
modKey?: string;
|
||||
dllRef?: string;
|
||||
scumExecutableChecksum?: string;
|
||||
targetExecutableChecksum?: string;
|
||||
ue4ssAbi?: string;
|
||||
supportedTargets?: Array<{ os?: string; arch?: string }>;
|
||||
updateOnStart?: boolean;
|
||||
@@ -415,8 +398,8 @@ function validateDLLExtensionProfiles(manifest: unknown): string[] {
|
||||
errors.push(`${location}.releaseState: must be ready or unpublished`);
|
||||
}
|
||||
if (profile.releaseState === "ready") {
|
||||
if (!checksumPattern.test(profile.checksum ?? "") || !checksumPattern.test(profile.scumExecutableChecksum ?? "")) {
|
||||
errors.push(`${location}: release and SCUM executable SHA-256 checksums are required`);
|
||||
if (!checksumPattern.test(profile.checksum ?? "") || !checksumPattern.test(profile.targetExecutableChecksum ?? "")) {
|
||||
errors.push(`${location}: release and target executable SHA-256 checksums are required`);
|
||||
}
|
||||
if (!Number.isInteger(profile.sizeBytes) || (profile.sizeBytes ?? 0) < 1 || (profile.sizeBytes ?? 0) > 128 * 1024 * 1024) {
|
||||
errors.push(`${location}.sizeBytes: must be a bounded DLL size`);
|
||||
|
||||
@@ -387,9 +387,9 @@ export interface RuntimeDependencyProbe {
|
||||
}
|
||||
|
||||
export interface RuntimeInstallStep {
|
||||
type: "package" | "verified-download" | "steamcmd-app" | "manual";
|
||||
type: "package" | "verified-download" | "manual";
|
||||
targetKey: string;
|
||||
packageManager?: "winget" | "choco" | "scoop" | "apt" | "yum" | "dnf" | "pacman" | "zypper" | "brew" | "steamcmd" | "manual";
|
||||
packageManager?: "winget" | "choco" | "scoop" | "apt" | "yum" | "dnf" | "pacman" | "zypper" | "brew";
|
||||
packageName?: string;
|
||||
version?: string;
|
||||
downloadRef?: string;
|
||||
@@ -444,7 +444,7 @@ export interface RuntimeDLLExtensionProfile {
|
||||
targetKey: string;
|
||||
modKey: string;
|
||||
dllRef: string;
|
||||
scumExecutableChecksum?: `sha256:${string}`;
|
||||
targetExecutableChecksum?: `sha256:${string}`;
|
||||
ue4ssAbi?: string;
|
||||
supportedTargets: [{ os: "windows"; arch: "amd64" }];
|
||||
updateOnStart: true;
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
{"key": "unsafe-install", "title": "bash -c installer", "steps": [{"type": "manual", "targetKey": "manual"}]},
|
||||
{"key": "unsafe-download", "title": "Unsafe dependency download", "steps": [{"type": "verified-download", "targetKey": "tool", "downloadRef": "https://127.0.0.1/tool", "checksum": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}]}
|
||||
],
|
||||
"serverDeployments": [
|
||||
{"key": "legacy", "version": "1.0.0"}
|
||||
],
|
||||
"clientManagers": [
|
||||
{
|
||||
"key": "unsafe-client",
|
||||
|
||||
@@ -165,6 +165,7 @@ describe("plugin manifest validation", () => {
|
||||
const installScript = fs.readFileSync(path.join(pluginDir, installAction.executableKey), "utf8");
|
||||
const startScript = fs.readFileSync(path.join(pluginDir, startAction.executableKey), "utf8");
|
||||
expect(manifest.runtimeProfiles.serverDeployments).toBeUndefined();
|
||||
expect(JSON.stringify(manifest.runtimeProfiles.installPlans ?? [])).not.toContain("steamcmd-app");
|
||||
expect(assetPaths).toEqual(expect.arrayContaining(["actions/install.json", "actions/start.json", "bin/scum-install-update.cmd", "bin/scum-start.cmd", "assets/map/scum-map-overview.jpg"]));
|
||||
expect(installAction).toMatchObject({ executableKey: "bin/scum-install-update.cmd", environment: { SERVER_STEAM_APP_ID: "3792580", SERVER_STEAMCMD_UPDATE_ARGS: "+login anonymous +app_update 3792580 +quit" } });
|
||||
expect(installAction.timeoutMs).toBe(7200000);
|
||||
@@ -709,6 +710,7 @@ describe("plugin manifest validation", () => {
|
||||
expect(errors.some((error) => error.includes("raw host path"))).toBe(true);
|
||||
expect(errors.some((error) => error.includes("arbitrary shell"))).toBe(true);
|
||||
expect(errors.some((error) => error.includes("not approved for dependency download"))).toBe(true);
|
||||
expect(errors.some((error) => error.includes("runtimeProfiles.serverDeployments") && error.includes("no longer supported"))).toBe(true);
|
||||
expect(errors.some((error) => error.includes("runtimeProfiles.clientManagers") && error.includes("no longer supported"))).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user