mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-11-13 17:58:18 +00:00
docs(spec,steering): lift access-control-prover to capability level; engine/target split, pattern discipline, complexity caps, breadth map
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
# Code Standards (2026-10-29)
|
||||
|
||||
Applies to new code and amended code from this date. Existing modules are grandfathered
|
||||
until their migration is scheduled in the breadth map; no mass renames.
|
||||
|
||||
## Specification level (the horizontal-capability rule)
|
||||
|
||||
Specifications describe the way and the concept, not per-target inventories.
|
||||
|
||||
- A spec defines **capabilities of the acquisition mechanism**: how recognition
|
||||
knowledge for any target is represented, proposed, verified, and promoted. It never
|
||||
enumerates a target's vocabulary (`ServletHolder`, `doNotifyCommit`,
|
||||
`voteOnAttribute`, ...) as work items or acceptance criteria.
|
||||
- Per-target knowledge is **data** (fact rows, strategy registrations) produced through
|
||||
the acquisition pipeline -- an LLM can produce it per target; the engine verifies it.
|
||||
- Concrete repositories and frameworks appear in specs only as **benchmark evidence**:
|
||||
named cases the acquired data must satisfy, never lists to implement.
|
||||
- Litmus: if a requirement's acceptance criteria would not survive swapping the target
|
||||
repository family, the requirement is written at the wrong level. Lift it.
|
||||
|
||||
## Engine / target split (the anti-monolith rule)
|
||||
|
||||
The abstract-interpretation engine is agnostic. Target knowledge (framework names,
|
||||
recognition vocabulary, WordPress/Stapler/Symfony/Jetty/Laravel specifics) never lives
|
||||
inside engine modules.
|
||||
|
||||
- **Engine modules** (`semantic/obligations/check.py`, `dominance.py`, `cfg_dominance.py`,
|
||||
`paths.py`, `resolution.py`, `operations.py`, `trace.py`): no framework or product names.
|
||||
If a framework identifier appears in an engine module, the split has been violated.
|
||||
- **Target knowledge lives in exactly two visible places:**
|
||||
1. **Data**: `ruleset/obligations/*.toml` and future fact files -- operation rows,
|
||||
discharger rows, handler-name families. Adding a framework's vocabulary is a data
|
||||
change, reviewable in one place.
|
||||
2. **Strategy modules**: one module per recognition concern under `mapping/` (registry
|
||||
pattern, see below), each file naming its target in its filename and registering
|
||||
itself in one table.
|
||||
- **The system adjusts by growing data and strategies, never by editing the engine.** The
|
||||
fact-proposal lane (LLM proposes, engine verifies, repetition promotes to rows) is the
|
||||
automated path for the same rule.
|
||||
|
||||
## Pattern discipline (GoF)
|
||||
|
||||
- **Strategy + Registry** for entry recognisers: `mapping/` gains a recogniser registry;
|
||||
each framework family is one strategy module. New recognisers land there; the legacy
|
||||
blocks inside `mapping.py` migrate family by family (tracked in the breadth map).
|
||||
- **Interpreter (data-driven)** for obligation facts: TOML rows are the language; the
|
||||
checker interprets them. New target vocabulary = new rows.
|
||||
- **Adapter** at engine seams: `hunt/prover.py`'s callers adapter binds the IR to the
|
||||
caller index; witnesses flow into the checker through one interface
|
||||
(`check_obligations`).
|
||||
- **Factory** for witnesses stays inside `obligations/enforcement.py` for now, but
|
||||
enforcement is a target-aware seam (it reads Symfony/Laravel/Tornado constructs): treat
|
||||
it as adapter territory; engine modules must not import it.
|
||||
|
||||
## Complexity caps
|
||||
|
||||
- Cyclomatic (McCabe) complexity: **<= 10 per function**.
|
||||
- Logical lines of code: **<= 50 per function, <= 400 per new module**.
|
||||
- A task is not done while a function it touched exceeds the caps; split the function.
|
||||
- Automated gate (ruff C901 / xenon in CI) is not wired yet; caps are enforced at review
|
||||
time. Wiring the gate is tracked in the breadth map.
|
||||
|
||||
## Idiomatic naming
|
||||
|
||||
- Names state what a value semantically is, in the pipeline's vocabulary: `entry_point`,
|
||||
`trace`, `obligation`, `witness`, `discharge`, `finding`, `judgment`.
|
||||
- Collections name their elements: `entry_point_records`, `judgments_by_key`,
|
||||
`findings_by_push`. Mappings use `_by_<key>`; sequences are plural. No `eps`, `recs`,
|
||||
`d2`, `tmp2`.
|
||||
- Booleans are predicates: `is_public`, `has_dominating_guard`, `dominates_entry`. Avoid
|
||||
negated names (`not_unflagged`).
|
||||
- Row/record destructuring uses the record's field names, not positional `a, b`.
|
||||
- Renaming debt in existing modules is recorded in the breadth map, not fixed drive-by.
|
||||
Reference in New Issue
Block a user