feat: initial public release (MAESTRO)

This commit is contained in:
oss-sync
2026-06-03 05:08:00 +00:00
commit f5c7666f6b
823 changed files with 184150 additions and 0 deletions
+201
View File
@@ -0,0 +1,201 @@
/**
* SSH audit log: dedicated table with pending → completed/failed/denied/aborted lifecycle.
*
* Design rationale (codex review CRITICAL #6):
* Tool operations begin a pending audit row, commit, THEN issue the remote call.
* If the orchestrator crashes mid-call, the pending row remains and is reconciled
* to 'aborted' on next boot (see ssh-recovery.ts). This gives us "execution
* happened, outcome unknown" forensics rather than "no record at all".
*
* All write operations are inside a transaction (better-sqlite3 default for prepare+run
* with .transaction wrappers when needed).
*
* Plan: docs/superpowers/plans/2026-05-12-ssh-tool-integration.md (Phase 1).
*/
import type Database from 'better-sqlite3';
export type SshAuditOutcome = 'pending' | 'success' | 'failed' | 'denied' | 'aborted';
export interface BeginAuditInput {
action: string;
entityType?: string;
entityId?: string;
connectionId?: string;
ownerId?: string | null;
actingUserId?: string;
jobId?: string;
pieceName?: string;
reason?: string;
detail?: Record<string, unknown>;
/** ISO8601 timestamp; defaults to now. */
startedAt?: string;
}
export interface SshAuditRow {
id: number;
action: string;
entityType: string | null;
entityId: string | null;
connectionId: string | null;
ownerId: string | null;
actingUserId: string | null;
jobId: string | null;
pieceName: string | null;
outcome: SshAuditOutcome;
reason: string | null;
detail: Record<string, unknown> | null;
startedAt: string;
completedAt: string | null;
}
interface RawRow {
id: number;
action: string;
entity_type: string | null;
entity_id: string | null;
connection_id: string | null;
owner_id: string | null;
acting_user_id: string | null;
job_id: string | null;
piece_name: string | null;
outcome: SshAuditOutcome;
reason: string | null;
detail: string | null;
started_at: string;
completed_at: string | null;
}
function fromRow(r: RawRow): SshAuditRow {
return {
id: r.id,
action: r.action,
entityType: r.entity_type,
entityId: r.entity_id,
connectionId: r.connection_id,
ownerId: r.owner_id,
actingUserId: r.acting_user_id,
jobId: r.job_id,
pieceName: r.piece_name,
outcome: r.outcome,
reason: r.reason,
detail: r.detail ? (JSON.parse(r.detail) as Record<string, unknown>) : null,
startedAt: r.started_at,
completedAt: r.completed_at,
};
}
export interface SshAuditRepo {
/** Insert a pending audit row. Commits before returning (synchronous via better-sqlite3). */
begin(input: BeginAuditInput): number;
/**
* Update an existing pending row to a terminal outcome. Idempotent: if the row
* was already completed, this is a no-op (returns false). Returns true if the
* row was 'pending' and was updated.
*/
complete(id: number, outcome: Exclude<SshAuditOutcome, 'pending'>, detail?: Record<string, unknown>): boolean;
/** Convenience: begin + complete in one call, for actions with no remote operation. */
beginAndComplete(input: BeginAuditInput, outcome: Exclude<SshAuditOutcome, 'pending'>): number;
listForConnection(connectionId: string, limit?: number): SshAuditRow[];
listForOwner(ownerId: string, limit?: number): SshAuditRow[];
listPending(): SshAuditRow[];
getById(id: number): SshAuditRow | null;
}
export function createAuditRepo(db: Database.Database): SshAuditRepo {
const insertStmt = db.prepare(`
INSERT INTO ssh_audit_log (
action, entity_type, entity_id, connection_id, owner_id,
acting_user_id, job_id, piece_name, outcome, reason, detail,
started_at, completed_at
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?, ?, NULL)
`);
const completeStmt = db.prepare(`
UPDATE ssh_audit_log
SET outcome = ?, detail = ?, completed_at = ?
WHERE id = ? AND outcome = 'pending'
`);
const selectByIdStmt = db.prepare(`SELECT * FROM ssh_audit_log WHERE id = ?`);
const selectByConnStmt = db.prepare(
`SELECT * FROM ssh_audit_log WHERE connection_id = ? ORDER BY started_at DESC LIMIT ?`,
);
const selectByOwnerStmt = db.prepare(
`SELECT * FROM ssh_audit_log WHERE owner_id = ? ORDER BY started_at DESC LIMIT ?`,
);
const selectPendingStmt = db.prepare(
`SELECT * FROM ssh_audit_log WHERE outcome = 'pending' ORDER BY started_at ASC`,
);
function begin(input: BeginAuditInput): number {
const startedAt = input.startedAt ?? new Date().toISOString();
const detailJson = input.detail ? JSON.stringify(input.detail) : null;
const result = insertStmt.run(
input.action,
input.entityType ?? null,
input.entityId ?? null,
input.connectionId ?? null,
input.ownerId ?? null,
input.actingUserId ?? null,
input.jobId ?? null,
input.pieceName ?? null,
input.reason ?? null,
detailJson,
startedAt,
);
return result.lastInsertRowid as number;
}
function complete(
id: number,
outcome: Exclude<SshAuditOutcome, 'pending'>,
detail?: Record<string, unknown>,
): boolean {
// Merge detail with any existing detail (caller-supplied wins for overlapping keys).
let mergedDetail: string | null = null;
const existing = selectByIdStmt.get(id) as RawRow | undefined;
if (existing) {
const existingDetail = existing.detail
? (JSON.parse(existing.detail) as Record<string, unknown>)
: {};
const merged: Record<string, unknown> = { ...existingDetail, ...(detail ?? {}) };
mergedDetail = JSON.stringify(merged);
} else if (detail) {
mergedDetail = JSON.stringify(detail);
}
const completedAt = new Date().toISOString();
const r = completeStmt.run(outcome, mergedDetail, completedAt, id);
return r.changes > 0;
}
function beginAndComplete(
input: BeginAuditInput,
outcome: Exclude<SshAuditOutcome, 'pending'>,
): number {
return db.transaction(() => {
const id = begin(input);
complete(id, outcome);
return id;
})();
}
return {
begin,
complete,
beginAndComplete,
listForConnection(connectionId, limit = 50) {
return (selectByConnStmt.all(connectionId, limit) as RawRow[]).map(fromRow);
},
listForOwner(ownerId, limit = 50) {
return (selectByOwnerStmt.all(ownerId, limit) as RawRow[]).map(fromRow);
},
listPending() {
return (selectPendingStmt.all() as RawRow[]).map(fromRow);
},
getById(id) {
const r = selectByIdStmt.get(id) as RawRow | undefined;
return r ? fromRow(r) : null;
},
};
}