Add player moderation workflows and game integration
CI / checks (push) Successful in 7m27s

This commit is contained in:
2026-10-15 21:33:50 -04:00
parent c91d49c298
commit 8b372fa2c1
50 changed files with 4744 additions and 354 deletions
+27 -4
View File
@@ -1,6 +1,6 @@
import {
assertPublicFilePayload,
BANK_CONFIG_FILE,
PRIVATE_CONFIG_FILES,
PrivateFileOperationError,
isPrivateConfigPath
} from '../fleet/private-config.js';
@@ -1454,7 +1454,7 @@ export function getHostOperationPayload(hostId: string, id: string): Buffer {
.get(id, hostId) as { payload: Buffer } | undefined;
if (!row) throw new Error('Host operation was not found for this host.');
// Block old private-file commands before delivery to agents predating the guard.
if (row.payload.includes(BANK_CONFIG_FILE))
if (PRIVATE_CONFIG_FILES.some((filename) => row.payload.includes(filename)))
assertPublicFilePayload(JSON.parse(row.payload.toString()));
if (
!row.payload.includes('"contentSha256"') ||
@@ -1485,10 +1485,15 @@ export function reportHostOperationStatus(
if (['completed', 'failed'].includes(operation.state)) return operation;
const state = input.state as HostOperationState;
if (operation.state === 'running' && state === 'accepted') return operation;
const error =
let error =
input.error === undefined || input.error === null
? null
: String(input.error).slice(0, 4000);
if (operation.kind === 'instance.configure-moderation' && error)
error = error.replace(
/ec_(?:moderation|bank)_[A-Za-z0-9_-]+/g,
'[redacted credential]'
);
let result = input.result === undefined ? null : JSON.stringify(input.result);
if (result !== null && Buffer.byteLength(result) > 128 * 1024 * 1024)
throw new Error('Operation result exceeds the limit.');
@@ -1504,7 +1509,9 @@ export function reportHostOperationStatus(
? { redacted: true }
: operation.kind === 'logs.read'
? logResultMetadata(input.result)
: input.result
: operation.kind === 'instance.configure-moderation'
? moderationConfigurationReceipt(input.result)
: input.result
);
result = JSON.stringify(packed.value);
referenceBlobs('operation-result', id, packed.hashes);
@@ -1568,6 +1575,22 @@ export function reportHostOperationStatus(
queueMicrotask(() => workEvents.emit(`operation:${id}`));
return operation;
}
/** Configuration replies contain status only, never echoed dvars, file bodies or credentials. */
function moderationConfigurationReceipt(value: unknown): Record<string, unknown> {
const result =
value && typeof value === 'object' && !Array.isArray(value)
? (value as Record<string, unknown>)
: {};
return {
configured: result.configured === true,
...(Number.isSafeInteger(result.generation) ? { generation: result.generation } : {}),
liveLoad: ['sent', 'unconfirmed', 'deferred'].includes(result.liveLoad as string)
? result.liveLoad
: 'unconfirmed',
...(result.reconciled === true ? { reconciled: true } : {})
};
}
export function reportHostOperation(
hostId: string,
id: string,