Files
electric-cherry/src/lib/server/provisioning/safety-override.ts
T

45 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { db } from '../db/index.js';
import { getHost } from '../hosts/index.js';
import { recordProgress } from './progress.js';
import type { ProvisioningDetail } from '../../provisioning-detail.js';
export const safetyOverrideCapability = 'instance.safety-override';
export function safetyOverride(id: string): ProvisioningDetail['safetyOverride'] {
return db().prepare(`SELECT actor_id AS actorId, actor_name AS actorName, confirmed_at AS confirmedAt
FROM provisioning_safety_overrides WHERE deployment_id=?`).get(id) as ProvisioningDetail['safetyOverride'] ?? null;
}
/** Approval belongs to one unsubmitted operation and its original live instance. */
export function safetyOverrideAvailability(id: string): { applicable: boolean; unavailableReason: string | null } {
const target = db().prepare(`SELECT i.host_id FROM server_deployments d
JOIN native_provisioning n ON n.deployment_id=d.id
JOIN native_instances i ON i.id=n.instance_id AND i.server=d.server AND i.generation=n.generation AND i.retired_at IS NULL
WHERE d.id=? AND d.server_deleted_at IS NULL AND d.action IN ('restart','stop','rebuild','destroy')
AND d.state IN ('queued','waiting') AND d.submitted_at IS NULL AND n.operation_id IS NULL
AND NOT EXISTS (SELECT 1 FROM ec_host_migrations m WHERE m.deployment_id=d.id)
AND NOT EXISTS (SELECT 1 FROM native_creation_cancellations c WHERE c.cleanup_id=d.id)
AND NOT EXISTS (SELECT 1 FROM provisioning_safety_overrides o WHERE o.deployment_id=d.id)`)
.get(id) as { host_id: string } | undefined;
if (!target) return { applicable: false, unavailableReason: null };
return { applicable: true, unavailableReason: getHost(target.host_id)?.inventory.capabilities?.includes(safetyOverrideCapability)
? null : 'Update this host’s agent before using admin override.' };
}
export function enableSafetyOverride(id: string, actor: { id: string; username: string }): { ok: true } | { ok: false; error: string } {
return db().transaction(() => {
// A retried confirmation never sends or repeats a command.
if (safetyOverride(id)) return { ok: true as const };
const availability = safetyOverrideAvailability(id);
if (!availability.applicable) return { ok: false as const, error: 'This operation can no longer be overridden. Refresh to see its current state.' };
if (availability.unavailableReason) return { ok: false as const, error: availability.unavailableReason };
const confirmedAt = new Date().toISOString();
db().prepare('INSERT INTO provisioning_safety_overrides(deployment_id,actor_id,actor_name,confirmed_at) VALUES(?,?,?,?)')
.run(id, actor.id, actor.username, confirmedAt);
recordProgress(id, { event: { kind: 'safety-override',
message: `Admin override confirmed by ${actor.username}: bypass player safety checks for this operation.`,
details: { actorId: actor.id, actorName: actor.username, confirmedAt, checks: ['player-occupancy'] } } });
return { ok: true as const };
})();
}