Protect private bank configuration from drift reconciliation (Refs #152)
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import { posix } from 'node:path';
|
||||
import { gameOfServer, relDestForKind, type ArtifactKind } from '../config.js';
|
||||
|
||||
export const BANK_CONFIG_FILE = 'electric_cherry_bank.cfg';
|
||||
|
||||
export function isPrivateConfigPath(path: string, game = 't5'): boolean {
|
||||
return (
|
||||
posix.normalize(path.replaceAll('\\', '/')) ===
|
||||
posix.join(relDestForKind('config', game), BANK_CONFIG_FILE)
|
||||
);
|
||||
}
|
||||
|
||||
export function isPrivateConfigTarget(server: string, kind: string, path: string): boolean {
|
||||
if (kind !== 'script' && kind !== 'config' && kind !== 'baseline' && kind !== 'plugin')
|
||||
throw new Error('Invalid artifact kind');
|
||||
const game = gameOfServer(server);
|
||||
return isPrivateConfigPath(
|
||||
posix.join(relDestForKind(kind, game), path.replaceAll('\\', '/')),
|
||||
game
|
||||
);
|
||||
}
|
||||
|
||||
export function assertPublicFileTarget(server: string, kind: ArtifactKind, path: string): void {
|
||||
if (isPrivateConfigTarget(server, kind, path))
|
||||
throw new Error(
|
||||
'Private bank configuration cannot be captured or changed by a file campaign.'
|
||||
);
|
||||
}
|
||||
|
||||
export function isReservedConfigFilename(path: string): boolean {
|
||||
return posix.basename(path.replaceAll('\\', '/')).toLowerCase() === BANK_CONFIG_FILE;
|
||||
}
|
||||
|
||||
// Legacy campaign evidence omits the kind and stores the path relative to its destination.
|
||||
export function isPrivateConfigEvidencePath(path: string): boolean {
|
||||
return (
|
||||
posix.normalize(path.replaceAll('\\', '/')) === BANK_CONFIG_FILE ||
|
||||
isPrivateConfigPath(path)
|
||||
);
|
||||
}
|
||||
|
||||
/** Credential injection uses bank.configPath, never a shared file's path field. */
|
||||
export class PrivateFileOperationError extends Error {
|
||||
constructor() {
|
||||
super('Private bank configuration cannot be read or changed by file operations.');
|
||||
}
|
||||
}
|
||||
|
||||
export function assertPublicFilePayload(value: unknown): void {
|
||||
if (!value || typeof value !== 'object') return;
|
||||
if ('path' in value && typeof value.path === 'string' && isPrivateConfigPath(value.path))
|
||||
throw new PrivateFileOperationError();
|
||||
for (const item of Object.values(value)) assertPublicFilePayload(item);
|
||||
}
|
||||
Reference in New Issue
Block a user