Charter · guide

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.

Install it
pnpm add @niscorp/charter
Step 1 of 4

What 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.

What exists, and a charter
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'] },
};
Step 2 of 4

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.

Read the report
const report = verifyCharter(charter, { actions, data: [] });
for (const issue of [...report.errors, ...report.warnings]) {
  console.log(issue.level, issue.rule + ':', issue.detail);
}
Step 3 of 4

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.

Refuse to start
if (report.errors.length > 0) console.log('not starting:', report.errors.length, 'error');
Step 4 of 4

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.

What each role comes to
for (const role of report.perRole) console.log(role.role + ':', role.actions.join(', '));
Then

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.

Run it
npx tsx verify.mts
It prints
error 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