Repository navigation
ctrlrun 0.1.0a1
Pre-release
Pre-release
First packaged release. The v0.1 kernel is complete: every acceptance test in
docs/SPEC-v0.1.md §7 passes, including the multi-process concurrency test.
Added
- Action — canonical form,
action_hash, deep-frozen arguments.floatis rejected in
arguments:0.1and0.10are the same money and different hashes. - Policy — YAML loader with
ALLOW/APPROVE/DENYand fail-closed defaults. An
unknown action is denied; there is no default-allow. See the config-breaking rule below
for how condition keys are validated. @ctrlrun.protect()— binds a function call to an Action, evaluates it, and executes
from the action's canonical arguments rather than the caller's objects.- Approval binding — approvals carry the
action_hashof what a human saw, and are
single-use and expiring. A mutated action cannot present an approval granted for another. - Effect key and reservation — template-resolved effect identity, reserved atomically
across processes viaBEGIN IMMEDIATEand a unique constraint oneffect_key. - Effect state machine —
NEW → RESERVED → EXECUTING → COMMITTED | FAILED | AMBIGUOUS.
Only an executor raisingNotExecutedproducesFAILED; every other exception, timeouts
included, producesAMBIGUOUS, and only a human resolves it. - Receipts and events — portable JSONL evidence for every action.
- CLI —
init,demo,approve,deny,receipts,effects,resolve. ctrlrun demo— four failure scenarios, in process, no network.SECURITY.mdanddocs/CLAIMS.md, which maps every README claim to its code and test.
Config-breaking rules
Rules that reject a policy file which an earlier build of this kernel would have loaded.
A ctrlrun.yaml written before this release may need an edit; the process refuses to start
until it gets one, which is the point.
- A condition key naming an
Actionfield is now a load-timePolicyError. The
reserved names areaction_id,agent,environment,principal,resourceand
user.when: { environment_eq: production }reads exactly like it scopes a rule to
production, and matched nothing at all — conditions address an action's arguments, and
those are not arguments. Combined with a catch-alldecision: allowbeneath it, a rule
that looked restrictive silently permitted everything. If a protected function genuinely
takes an argument by one of those names, rename the argument (SPEC-v0.1 §3.2). Only the
whole name is reserved:resource_id_eqis unaffected. - A condition on an argument the action does not carry now logs a warning. The decision
is unchanged — still false, still never an error, per SPEC-v0.1 §3.2 — but a typo such as
amont_lteno longer disappears in silence. Nothing to edit; expect new log output.
Notes
- Requires Python ≥ 3.11. Runtime dependencies are
pyyamlandclick. - Single-host only: reservation is atomic across processes on one machine via SQLite.
Multi-host needs the Postgres store planned for v0.6. - Receipts are not signed. A database administrator can alter history (v0.6).
- Approver identity is free text and is not authenticated (v0.3).
- Generated ids (
act_,apr_,ctr_) are 128 bits. An approval id is not a bearer token
in v0.1 — consuming one needs write access to the store — but it becomes one with the
webhook provider in v0.2, and an id format cannot be widened after records exist. - Effect key templates do not escape placeholder values, so a crafted argument can make two
distinct effects share one key. The result is a refusal rather than a double execution;
docs/THREAT_MODEL.mdstates the limit and the workaround. - Policy conditions address an action's arguments only. Scoping a rule by environment,
resource or principal arrives with the authority model in v0.3.