/** * Per-module hook jail exemption check (per-module-jail-policy task 3.3). * * One finding per module the operator exempted from the fleet's jail policy. * Severity `todo`, deliberately NOT `drift`: the operator chose this, so it * is a list of recorded exceptions to revisit, not a system that moved away * from a desired state. `todo` never escalates the verdict past READY, which * is what keeps `system update` from treating an exemption as work to do. */ import type { JailExemption } from '../jail-exemptions'; import type { DriftFinding } from './types'; export interface JailExemptionsAuditDeps { /** * The exemptions, from the shared collector (`services/jail-exemptions.ts`). * A fleet with none contributes nothing — that is the normal state, and * emitting a "no exemptions" finding would be a surface reporting an * exemption nobody set (task 3.4). */ exemptions: JailExemption[]; } export async function auditJailExemptions(deps: JailExemptionsAuditDeps): Promise { return deps.exemptions.map((exemption) => ({ category: 'jail_exemptions' as const, severity: 'todo' as const, code: 'hook_jail_exemption', subject: exemption.moduleId, message: `${exemption.moduleId} runs under jail policy '${exemption.policy}', weaker than the system's '${exemption.systemPolicy}'`, details: [ 'Its hooks run with the weaker posture while the rest of the fleet jails.', 'The operator recorded this per-module policy with `celilo module jail`.', 'Exemptions are deliberate, which is why this is todo and not drift —', 'but an exemption nobody remembers is how a jail quietly stops covering', 'the fleet. Revisit it: either the reason still holds, or clear it.', '', `To review: celilo module jail ${exemption.moduleId}`, `To clear: celilo module jail ${exemption.moduleId} --clear`, ].join('\n'), remediation: `Clear it with 'celilo module jail ${exemption.moduleId} --clear' if the module now jails cleanly`, actionable: false, })); }