permits: block lists what it may read, write, run and reach.
It is default-deny engine policy: nothing in the SDK grants more, and the
engine refuses a task that reaches past the boundary before anything starts.
A refused run
list-notes.nika runs ls but declares permits: {}, zero authority:
list-notes.nika
permits.mts
permits: {} with exactly that grant,
and the same calls succeed:
./node_modules/.bin/nika check list-notes.nika --infer-permits drafts the
tightest block for a file. An absent permits: block is refused the same way
(NIKA-AUTH-006): zero authority, with no boundary to judge against.
Read the boundary before you run
A localcheck() report carries the boundary the engine judged, so your
application can apply its own policy before admitting a workflow, for
example a reviewed allowlist of programs:
A report describes the bytes the engine read at that moment;
run()
re-admits the file’s current content. If the file can change between the two
calls, gate its integrity, or capture a snapshot first. The SDK types these
fields as unknown: narrow them as above.
What the engine enforces at run time
The check judges literal arguments. At run time the engine re-judges what the check could not know (computed paths, resolved programs, symlinks) and confinesexec: children in the OS sandbox (Seatbelt on macOS, bubblewrap on
Linux). A run that reaches past the boundary then fails with NIKA-SEC-004
as result data. Security describes every law, including
the ones no permits: entry can open.
Which version is this?
Which version is this?
Security model
Permits, taint, the order law and the lethal trifecta.
Security boundary
The SDK’s own seams: argv, tokens, secrets.