feat(opsserver): add health, audit, cluster health, and durable credential management hardening

This commit is contained in:
2026-04-30 07:10:21 +00:00
parent c3e5cabe3d
commit f4e5f02d0c
34 changed files with 1722 additions and 320 deletions
+63
View File
@@ -0,0 +1,63 @@
import type * as interfaces from '../../ts_interfaces/index.ts';
export interface IAuditLogEntry {
timestamp: number;
actorUserId: string;
action: string;
targetType: string;
targetId?: string;
success: boolean;
message?: string;
metadata?: Record<string, string | number | boolean>;
}
export class AuditLogger {
constructor(private storageDirectory: string) {}
public get auditLogPath(): string {
return `${this.storageDirectory}/.objectstorage/audit.log`;
}
public async log(entry: Omit<IAuditLogEntry, 'timestamp'>): Promise<void> {
const logEntry: IAuditLogEntry = {
timestamp: Date.now(),
...entry,
};
const dirPath = this.auditLogPath.substring(0, this.auditLogPath.lastIndexOf('/'));
await Deno.mkdir(dirPath, { recursive: true });
await Deno.writeTextFile(this.auditLogPath, `${JSON.stringify(logEntry)}\n`, {
append: true,
create: true,
mode: 0o600,
});
await this.restrictAuditLogPermissions();
}
public async listRecent(limit = 100): Promise<interfaces.data.IAuditEntry[]> {
let content = '';
try {
content = await Deno.readTextFile(this.auditLogPath);
} catch (error) {
if (error instanceof Deno.errors.NotFound) {
return [];
}
throw error;
}
return content
.trim()
.split('\n')
.filter(Boolean)
.slice(-limit)
.map((line) => JSON.parse(line) as interfaces.data.IAuditEntry)
.reverse();
}
private async restrictAuditLogPermissions(): Promise<void> {
try {
await Deno.chmod(this.auditLogPath, 0o600);
} catch {
// chmod is not available on every platform Deno supports.
}
}
}