Skip to content

feat: enforce custom rule hermeticity at runtime - #868

Merged
kvlonge merged 4 commits into
mainfrom
feat/chi-399-runtime-hermeticity
Sep 28, 2026
Merged

kvlonge merged 4 commits into
mainfrom
feat/chi-399-runtime-hermeticity

Conversation

@kvlonge

@kvlonge kvlonge commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Why

Custom-Rule results are cached, so a Rule must depend only on tracked inputs. The old check banned calls by name and allowed a short import list: it rejected pure code (re.compile, fnmatch, json, helpers named exists) and accepted environment reads, commands, directory listing and indirect file access, and it missed module-level state and set-order dependence. A module-level edit could also leave a stale cached result.

Changes

  • Runtime guard in the custom-Rule host: an audit hook rejects file, directory, process, network and ctypes access and non-allowlisted imports from Rule code; ctx.project.tree reads stay allowed. Errors name the Rule and line.
  • The host starts with a minimal environment, PYTHONHASHSEED=0 and -P, clears os.environ and runs from the project directory before Rules load.
  • Import check covers the Rule file and its import closure only, with a purity-based allowlist; the call-name ban is removed.
  • evaluate_rule evaluates each subject twice and fails when findings differ.
  • Rule fingerprints hash the whole Rule file plus its import closure.
  • Docs state the guard protects cache correctness, not security.

Verification

  • DuckDB E2E through sqb compile for allowed modules, each rejected access, scrubbed environment, fixed set order, working directory, stale-cache invalidation and ctx.project.tree tracking; harness and import-check unit tests. New tests fail on the old code.
  • make test, make check-ci and the hygiene scan pass; one independent review.

Replace the call-name ban with a runtime audit-hook guard in the custom
rule host, launch the host with a scrubbed environment and a fixed hash
seed, widen the import allowlist to pure deterministic stdlib modules,
limit the static import check to the fingerprinted import closure, and
make the public rule harness detect state leaking between evaluations.
Hash each Rule's full source file plus its import closure so any module
statement edit invalidates cached results, pin the custom host's working
directory to the resolved project directory and drop the invocation
directory from its import path, and state in the docs that the guard is
for cache correctness rather than a sandbox.
Route unaudited os and os.path metadata calls through the runtime guard
so Rule code probing file existence or stat results is rejected with the
non-hermetic error, and resolve every repository-owned rules module a
Rule can execute (relative and multi-name imports, package initializers,
and function-local imports) for both the static import check and the
implementation fingerprint.
@kvlonge
kvlonge enabled auto-merge (squash) September 28, 2026 14:08
@kvlonge
kvlonge merged commit 5fdb062 into main Sep 28, 2026
55 of 57 checks passed
@kvlonge
kvlonge deleted the feat/chi-399-runtime-hermeticity branch September 28, 2026 14:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant