neutron-security
The package that decides whether ordinary app Motoko is allowed into a complete Neutron actor.
It defines one ordered policy, projected over two compiler paths:
| Path | Where it runs |
|---|---|
| Packaging | mopack, over every final module of an app being packed |
| Compilation | neutron-compiler, over every reachable module before assembly |
Both current paths use the same deterministic rule order. With the same policy and reviewed whitelist, the packager and install-time scan agree; an archive created under an older toolchain is still revalidated by the current compiler and can be rejected by a newer policy.
How the analysis works
Two views of the source are combined.
A Motoko-aware lexer preserves facts that the bundled simplified AST erases. It skips nested comments, strings, and character literals; distinguishes brace-based record extension from parenthesized call contexts; and reports source lines for diagnostics.
The AST is authoritative for what counts as an acquisition. Only dotted members and object-pattern fields are treated as name-based acquisitions — so renaming a privileged primitive during import or destructuring does not evade the policy, while harmless local names, type fields, and record-literal keys remain usable.
The two paths differ in how they combine these:
- The browser compiler starts from a compact member inspection plus source-only facts. If the lexer sees a privileged spelling that compact facts do not explain, that single module falls back to full AST parsing. The spelling is a fallback trigger, not a finding.
- The packager always parses the full AST and intersects readable text candidates with its authoritative findings.
What is checked
See Static checks for the complete rule list and
the reasoning behind each one. In summary the policy blocks actor and
shared-function references, raw inter-canister calls, cycle primitives, raw
stable memory and Regions, certification APIs, the <system> capability, raw
caller attributes, canister environment access, process-wide Candid limits, and
raw timers.
Fixtures
The package ships allowed/ and disallowed/ sample Motoko files and a checker
that runs the policy over both directories. The check command also scans core
production source for app-specific imports, identities, methods, and retired
vocabulary. The same fixture logic is covered by the package's test suite, and
unexpected parser failures fail that suite rather than being silently
tolerated.
One retained legacy fixture is an expected parser failure, because the obsolete form it contains is rejected before policy matching even begins.
The dump.ts utility prints the vendored compiler's parsed AST for one Motoko
file, which is useful when diagnosing how a policy pattern sees that source.
The whitelist
Two identical hash maps live in neutron-scripts and neutron-compiler. They
record exactly two reviewed pinned Motoko Core facades: Principal.mo and
Runtime.mo.
The role of the whitelist is narrow and worth stating precisely: if a final module's content hash matches an entry, the dangerous findings recorded for that exact content are accepted. It does not trust a package name, and it does not trust other modules in the same package.
Random.mo is deliberately absent, because it embeds paid management-canister
raw_rand access. Apps that need entropy declare the kernel randomness
capability instead and receive a scoped handle with concurrency, result-size,
lifecycle, and cycle-reserve enforcement.
The generator refuses to add any Core module other than those two.