Remove pre-1.0 audit and protected request scaffolding

This commit is contained in:
npc0-hue
2026-08-20 23:42:02 +08:00
parent 40b35b05c7
commit a7e2e4c6c0
130 changed files with 526 additions and 3767 deletions
+6 -50
View File
@@ -675,8 +675,7 @@ export function validateGameClientBridgeCatalog(manifest: unknown): string[] {
if (typeof manifest !== "object" || manifest === null) {
return [];
}
type ProtectedRequest = { kind?: string; transportKey?: string; targetKey?: string; textField?: string; maxTextBytes?: number };
type BridgeCommand = { type?: string; approvalLevel?: string; payloadSchemaRef?: string; resultSchemaRef?: string; protectedRequest?: ProtectedRequest };
type BridgeCommand = { type?: string; approvalLevel?: string; payloadSchemaRef?: string; resultSchemaRef?: string };
type BridgeQueryTemplate = {
key?: string;
permission?: string;
@@ -703,7 +702,6 @@ export function validateGameClientBridgeCatalog(manifest: unknown): string[] {
timestampField?: string;
activeWindowSeconds?: number;
activityTarget?: BridgeLogProjectionTarget;
announcement?: { profileKey?: string; commandType?: string; textField?: string; newTextTemplate?: string; returningTextTemplate?: string };
};
};
type BridgeOperationSafety = { requiresApproval?: boolean; requiresOfflinePlayer?: boolean; requiresMaintenanceWindow?: boolean; requiresBeforeValue?: boolean; requiresConfirmation?: boolean; backupRequired?: boolean };
@@ -806,44 +804,10 @@ export function validateGameClientBridgeCatalog(manifest: unknown): string[] {
for (const [index, command] of (bridge.commands ?? []).entries()) {
const location = `manifest.gameClientBridge.commands[${index}]`;
const type = command.type ?? "";
const unsafeTypeReason = command.protectedRequest ? undefined : unsafeGameClientBridgeCommandTypeReason(type);
const unsafeTypeReason = unsafeGameClientBridgeCommandTypeReason(type);
if (unsafeTypeReason) {
errors.push(`${location}.type: ${unsafeTypeReason}`);
}
if (!command.approvalLevel) {
errors.push(`${location}.approvalLevel: approval metadata is required`);
}
const protectedRequest = command.protectedRequest;
if (protectedRequest) {
if (!new Set(["sql", "rcon", "program"]).has(protectedRequest.kind ?? "")) {
errors.push(`${location}.protectedRequest.kind: must be sql, rcon, or program`);
}
if (!/^[A-Za-z][A-Za-z0-9._-]{0,79}$/.test(protectedRequest.textField ?? "")) {
errors.push(`${location}.protectedRequest.textField: must be a safe bounded field name`);
}
if (!Number.isInteger(protectedRequest.maxTextBytes) || (protectedRequest.maxTextBytes ?? 0) < 1 || (protectedRequest.maxTextBytes ?? 0) > 16384) {
errors.push(`${location}.protectedRequest.maxTextBytes: must be between 1 and 16384`);
}
const transport = transportProfiles.find((candidate) => candidate.key === protectedRequest.transportKey);
if (!transport) {
errors.push(`${location}.protectedRequest.transportKey: must reference a declared runtime transport profile`);
} else {
if (!protectedRequest.targetKey || protectedRequest.targetKey !== transport.targetKey) {
errors.push(`${location}.protectedRequest.targetKey: must match the declared runtime transport target`);
}
const expectedCapability = { sql: "remote.run.protected.sql", rcon: "remote.run.protected.rcon", program: "remote.run.program.command" }[protectedRequest.kind ?? ""];
if (protectedRequest.kind === "sql" && transport.kind !== "mysql" && transport.kind !== "sqlite") {
errors.push(`${location}.protectedRequest.transportKey: sql requests require mysql or sqlite transport`);
}
if ((protectedRequest.kind === "rcon" && transport.kind !== "rcon") || (protectedRequest.kind === "program" && transport.kind !== "program")) {
errors.push(`${location}.protectedRequest.transportKey: transport kind does not match protected request kind`);
}
if (expectedCapability && !transport.capabilities?.includes(expectedCapability)) {
errors.push(`${location}.protectedRequest.transportKey: is missing required protected transport capability`);
}
}
}
for (const [field, ref] of [["payloadSchemaRef", command.payloadSchemaRef], ["resultSchemaRef", command.resultSchemaRef]] as const) {
if (ref && !isSafeRelativeJsonRef(ref)) {
errors.push(`${location}.${field}: raw host paths and unsafe schema references are not allowed`);
@@ -966,14 +930,6 @@ export function validateGameClientBridgeCatalog(manifest: unknown): string[] {
if (!fieldNamePattern.test(presence.timestampField ?? "") || !targetFields.has(presence.timestampField ?? "")) errors.push(`${location}.presence.timestampField: must reference a projected target field`);
if (!Number.isInteger(presence.activeWindowSeconds) || (presence.activeWindowSeconds ?? 0) < 1 || (presence.activeWindowSeconds ?? 0) > 31536000) errors.push(`${location}.presence.activeWindowSeconds: must be between 1 and 31536000`);
if (presence.activityTarget) errors.push(...validateProjectionTarget(`${location}.presence.activityTarget`, presence.activityTarget, captures));
const announcement = presence.announcement;
const manager = declaration.runtimeProfiles?.clientManagers?.find((candidate) => candidate.key === announcement?.profileKey && candidate.health?.requiredCapabilities?.includes("game-client.bridge"));
if (!manager) errors.push(`${location}.presence.announcement.profileKey: must reference a declared game-client bridge profile`);
const command = (bridge.commands ?? []).find((candidate) => candidate.type === announcement?.commandType);
if (!command) errors.push(`${location}.presence.announcement.commandType: must reference a declared command`);
if (!fieldNamePattern.test(announcement?.textField ?? "") || (command?.protectedRequest && command.protectedRequest.textField !== announcement?.textField)) errors.push(`${location}.presence.announcement.textField: must be safe and match the command protected request`);
if (!announcement?.newTextTemplate || announcement.newTextTemplate.length > 4096) errors.push(`${location}.presence.announcement.newTextTemplate: must be a non-empty bounded template`);
if (!announcement?.returningTextTemplate || announcement.returningTextTemplate.length > 4096) errors.push(`${location}.presence.announcement.returningTextTemplate: must be a non-empty bounded template`);
}
for (const [index, operationTemplate] of (bridge.operationTemplates ?? []).entries()) {
const location = `manifest.gameClientBridge.operationTemplates[${index}]`;
@@ -989,8 +945,8 @@ export function validateGameClientBridgeCatalog(manifest: unknown): string[] {
if (!operationTemplate.permission || !declaredPermissions.has(operationTemplate.permission)) {
errors.push(`${location}.permission: permission must be declared by the plugin manifest`);
}
if (!new Set(["operator", "platform-admin"]).has(operationTemplate.approvalLevel ?? "")) {
errors.push(`${location}.approvalLevel: must require operator or platform-admin approval`);
if (!new Set(["none", "operator", "platform-admin"]).has(operationTemplate.approvalLevel ?? "")) {
errors.push(`${location}.approvalLevel: must be none, operator, or platform-admin`);
}
if (!new Set(["rcon", "sqlite-mutation"]).has(operationTemplate.kind ?? "")) {
errors.push(`${location}.kind: must be rcon or sqlite-mutation`);
@@ -1015,8 +971,8 @@ export function validateGameClientBridgeCatalog(manifest: unknown): string[] {
errors.push(`${location}.targetKey: must match the declared runtime transport target`);
}
if (operationTemplate.kind === "rcon") {
if (transport.kind !== "rcon" || !transport.capabilities?.includes("remote.run.protected.rcon")) {
errors.push(`${location}.transportKey: rcon operations require remote.run.protected.rcon transport`);
if (transport.kind !== "rcon" || !transport.capabilities?.includes("remote.run.rcon.command")) {
errors.push(`${location}.transportKey: rcon operations require remote.run.rcon.command transport`);
}
if (operationTemplate.maxRowsAffected !== undefined) {
errors.push(`${location}.maxRowsAffected: only sqlite-mutation operations may declare affected row bounds`);