Verify before you ship
The verifier reads a charter against what exists and reports what is wrong with it. A typo in a deny is an error.
pnpm add @niscorp/charterWhat exists, and a charter
The verifier is handed two lists: the screens, and what the tables allow. The second is empty here.
This charter has two slips in it. The member role allows programe, and the staff role denies settngs.
import { verifyCharter } from '@niscorp/charter';
const actions = ['welcome', 'programme', 'seats', 'me.tickets', 'door.list', 'takings', 'settings'];
const charter = {
member: ['programe', 'seats', 'me.*'],
staff: { allow: ['*'], deny: ['welcome', 'me.*', 'settngs'] },
};Read the report
verifyCharter answers with errors, warnings, and what every role comes to.
The two slips are not treated alike. An allow that matches nothing loses somebody a screen, which gets noticed, so it is a warning. A deny that matches nothing protects nothing and nobody would ever notice, so it is an error.
const report = verifyCharter(charter, { actions, data: [] });
for (const issue of [...report.errors, ...report.warnings]) {
console.log(issue.level, issue.rule + ':', issue.detail);
}Refuse to start
A server checks the errors when it starts and stops if there are any. Moss does exactly this. In your own setup it is these two lines, run at boot and in CI.
if (report.errors.length > 0) console.log('not starting:', report.errors.length, 'error');What each role comes to
The report also lists every role with the names it resolves to. Because it is plain data it can be printed, reviewed and compared with the last release.
for (const role of report.perRole) console.log(role.role + ':', role.actions.join(', '));Run it.
The dead deny as an error, the dead allow as a warning, a screen no role reaches, the refusal to start, and what each role comes to.
npx tsx verify.mtserror dead-deny: role "staff" denies "settngs" (actions) which matches nothing — silent means unprotected warning dead-allow: role "member" allows "programe" (actions) which matches nothing warning orphan: action "welcome" is granted by no role — deployed but unreachable not starting: 1 error member: me.tickets, seats staff: door.list, programme, seats, settings, takings