Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 68 additions & 29 deletions adapters/bifrost/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,20 @@ selects only its own language's core assertions — every row is now expanded:
for the expanded 29-template kernels — and writes a dedicated report. The Java
calibration slice also
covers one-hop helper flow. Generated workspaces live outside the repository so
repository ignore rules cannot hide fixtures from Bifrost's indexer. Sanitizer
lowering is a future Bifrost CLI capability.
repository ignore rules cannot hide fixtures from Bifrost's indexer.

**Sanitizer lowering is not a future capability; this README used to say it
was.** The sentence *"Sanitizer lowering is a future Bifrost CLI capability"*
stood here until it was measured and found false: the RQLP `analysis` grammar
accepts a `(sanitizer …)` stanza, the declaration suppresses a flow on a
completing run, deleting it restores that flow with a full witness, and an
undeclared sanitizer-shaped sibling is not suppressed. That measurement is
[Amendment A9](../../docs/modeling-matrix.md#a9--2026-08-27-bifrosts-sanitizer-category-is-promoted-the-readmes-lowering-claim-was-false),
which promotes category Z of the modeling matrix for this adapter. The retired
sentence is quoted by the tool-native profile's own category-Z rationale, whose
cell turns on the absent shipped endpoint catalog rather than on lowering and is
left for that document's own amendment.

External semantic-model activation requires an embedding
with an explicit catalog, so the modeled-external case is reported as
`unsupported` by this CLI adapter with an explicit retained reason. It is not a
Expand Down Expand Up @@ -540,20 +552,24 @@ population with its own denominator: it is never in a core denominator, and no
number here is ever added to or averaged with a kernel number. The two answer
different questions.

The preregistered partition scores **one of six categories** for this adapter
The preregistered partition scored **one of six categories** for this adapter
— declared sources and sinks — and that is the honest starting position for a
standalone policy CLI whose modeling surface lives in an embedding. The other
five categories are `unsupported` with the preregistration's rationale retained
verbatim, decided from the template identity **before the binary is invoked**:
sanitizer lowering and external semantic-model activation are recorded in this
README as future CLI capabilities, and the propagator, entry-root, and
standalone policy CLI whose modeling surface lives in an embedding.
[Amendment A9](../../docs/modeling-matrix.md#a9--2026-08-27-bifrosts-sanitizer-category-is-promoted-the-readmes-lowering-claim-was-false)
added a second, **declared sanitizers**, on a measurement that contradicted this
README. The remaining four are `unsupported` with the preregistration's
rationale retained verbatim, decided from the template identity **before the
binary is invoked**: external semantic-model activation is recorded in this
README as a future CLI capability, and the propagator, entry-root, and
persistence-boundary cells are the document's *to be verified* cells, which its
own rule treats as unsupported until shown otherwise. An `unsupported` cell is
coverage, never a negative and never a false negative.

The model is `adapters/bifrost/policies/model-python.rqlp`: two endpoint sets,
adding the declared source `fetch_remote` beside `dfb_source` and the declared
sink `record` beside `dfb_sink`. Unlike every committed kernel policy it sets
sink `record` beside `dfb_sink`, plus — since Amendment A9 — one `:sanitizers`
entry declaring `scrub` and deliberately not its sibling `sanitize`. Unlike
every committed kernel policy it sets
`:call-modeling (call-modeling :unmodeled require-model)` rather than
`optimistic`, which is
[the load-bearing-model requirement](../../docs/modeling-matrix.md#the-load-bearing-model-requirement);
Expand All @@ -562,7 +578,10 @@ the runner reads the policy before the run and refuses one that does not.
The first run, on the pinned v0.10.6 build, decides all four scored assertions
correctly — two `reached` positives and two `not-reached` negatives, with no
`inconclusive` and no `runner-error` — and takes the preregistered
`unsupported` on the other twenty. **Load-bearing verification:** re-running
`unsupported` on the other twenty. **Re-run pending:** that report predates
Amendment A9, so its four sanitizer cells are still recorded there as
`unsupported`; the scored evidence for them lands with the next evidence
re-run. **Load-bearing verification:** re-running
the same four fixtures under a policy identical except that the two declared
endpoint entries are removed drops both positives from one finding to zero. The
model, not the propagation, is what this tier scores. See [the Python
Expand All @@ -574,15 +593,18 @@ Separate from every kernel above, and never pooled with one. The
[modeling matrix](../../docs/modeling-matrix.md) scores whether an engine can
*be told* things — a source it did not know, a sanitizer, a summary, an entry
point, a persistence boundary — and its preregistered partition gives this
adapter **category S alone**: declared sources and declared sinks, two of the
twelve templates. The other five categories are `unsupported` for the
standalone policy CLI, decided from the template identity before the binary is
invoked and retained verbatim with the document's own rationale.
adapter **categories S and Z** — declared sources and sinks, and declared
sanitizers, four of the twelve templates. S was preregistered; Z arrived with
[Amendment A9](../../docs/modeling-matrix.md#a9--2026-08-27-bifrosts-sanitizer-category-is-promoted-the-readmes-lowering-claim-was-false).
The other four categories are `unsupported` for the standalone policy CLI,
decided from the template identity before the binary is invoked and retained
verbatim with the document's own rationale.

- Artifact: `adapters/bifrost/policies/model-javascript.rqlp`. It declares two
`:sources` entries bound to `return-value` and two `:sinks` entries bound to
`(argument :index 0)`, and nothing for categories P, Z, O, E, or B — a
declined category is absent from the artifact rather than approximated in it.
`:sources` entries bound to `return-value`, two `:sinks` entries bound to
`(argument :index 0)`, one `:sanitizers` entry declaring `scrub` and not its
sibling `sanitize`, and nothing for categories P, O, E, or B — a declined
category is absent from the artifact rather than approximated in it.
- Load-bearing model: the policy sets `:call-modeling (call-modeling :unmodeled
require-model)`, which the pinned v0.10.6 build accepts. The runner refuses
the artifact if that setting is missing, and refuses it again if it names the
Expand All @@ -607,6 +629,11 @@ invoked and retained verbatim with the document's own rationale.
twenty assertions are capability coverage with no analyzer invocation at all.
Its configuration hash is
`25e1399fb9b7c2e5dfa469d56e9b4edeccff655f1d8866290f4f55d29eb7117f`.
- **Re-run pending.** That row and that hash describe the pre-A9 run and the
pre-A9 artifact. The committed policy now carries the sanitizer declaration,
so the next run of this slice scores four more cells and reports a different
configuration hash; until it lands, the retained report records category Z as
`unsupported`.
- **Load-bearing verification.** Removing the `Config.fetchRemote` source entry
from a copy of the policy drops `model-declared-source-positive` from one
finding to zero
Expand All @@ -618,15 +645,17 @@ See [the JavaScript modeling matrix](../../docs/javascript-modeling.md).
## Java taint-modeling matrix

Wave M1's last row, and the same shape as the two above. The
[modeling matrix](../../docs/modeling-matrix.md) gives this adapter **category S
alone** — declared sources and declared sinks, two of the twelve templates —
and the other five categories are `unsupported` for the standalone policy CLI,
decided from the template identity before the binary is invoked and retained
verbatim with the document's own rationale.
[modeling matrix](../../docs/modeling-matrix.md) gives this adapter
**categories S and Z** — declared sources and sinks, and declared sanitizers
since [Amendment A9](../../docs/modeling-matrix.md#a9--2026-08-27-bifrosts-sanitizer-category-is-promoted-the-readmes-lowering-claim-was-false),
four of the twelve templates — and the other four categories are `unsupported`
for the standalone policy CLI, decided from the template identity before the
binary is invoked and retained verbatim with the document's own rationale.

- Artifact: `adapters/bifrost/policies/model-java.rqlp`. Two `:sources` entries
bound to `return-value`, two `:sinks` entries bound to
`(argument :index 0)`, and nothing for categories P, Z, O, E, or B.
`(argument :index 0)`, one `:sanitizers` entry declaring `Clean.scrub` and not
its sibling `Clean.sanitize`, and nothing for categories P, O, E, or B.
- Load-bearing model: the policy sets `:call-modeling (call-modeling :unmodeled
require-model)`. The preregistration recorded the pinned CLI's *acceptance* of
that setting as one of two unverified facts behind Bifrost's category-P cell;
Expand All @@ -647,6 +676,11 @@ verbatim with the document's own rationale.
`inconclusive` cells are that language's engine incompleteness, not a modeling
property. Its configuration hash is
`921d2c8e531813bf7c9bb93fd6da710e62020f60f9caadc7ac0096c5c31121d9`.
- **Re-run pending.** That row and that hash describe the pre-A9 run and the
pre-A9 artifact. The committed policy now carries the sanitizer declaration,
so the next run of this slice scores four more cells and reports a different
configuration hash; until it lands, the retained report records category Z as
`unsupported`.
- **Load-bearing verification.** Removing the `Config.fetchRemote` source entry
from a copy of the policy drops `model-declared-source-positive` from one
finding to zero
Expand All @@ -656,8 +690,10 @@ See [the Java modeling matrix](../../docs/java-modeling.md).

## JavaScript tool-native probe set

Zero of six, decided before the CLI is invoked — and the twelve assertions were
produced without launching Bifrost at all.
Zero of six, decided before the CLI is asked about a fixture — and the twelve
assertions were produced without Bifrost analyzing anything. The run reads the
pinned binary's version banner once so its report names an observed pin
([the run-level identity is witnessed](../../docs/native-profile.md#the-run-level-identity-is-witnessed-including-at-0--6)).

The tool-native activation contract is built-in policy packs only:
`--policy-pack` / `--policy-category` / `--policy-id` over the catalog
Expand Down Expand Up @@ -697,8 +733,8 @@ for the contract and [the Java row](../../docs/java-native.md) for the results.
`0badb216237f88ed709f45e32283b0ea8030875e742424c3377e1fbce525c6d3`.

**Result: zero of six templates activated, twelve `unsupported` outcomes, and
the binary was never invoked.** Every cell is decided from the template
identity before the CLI is touched, with the preregistered rationale retained
the CLI was never asked about a fixture.** Every cell is decided from the
template identity before the CLI analyzes anything, with the preregistered rationale retained
verbatim under `reports/raw/bifrost-java-native/<case-id>-unsupported.json`.
The standalone policy CLI ships no taint policy and no source or sink endpoint
catalog — bifrost-dev **#2620** is the open issue under which the first ones
Expand Down Expand Up @@ -732,8 +768,11 @@ Wave N1's final row, and it closes the wave. See
`reports/raw/bifrost-python-native/`.

**Result: zero of six templates activated, twelve `unsupported` outcomes, and
the binary was never invoked** — verified by running the command with a
nonexistent binary path and getting byte-identical evidence. The standalone
the CLI was never asked about a fixture.** The retained decisions are
byte-identical whatever the binary reports; the run does read its version
banner once, so the nonexistent-path check this row was originally verified
with no longer holds, by design
([the run-level identity is witnessed](../../docs/native-profile.md#the-run-level-identity-is-witnessed-including-at-0--6)). The standalone
policy CLI ships no taint policy and no source or sink endpoint catalog, so no
template can produce a finding regardless of what else the engine expresses;
the sanitizer and external-summary rows restate this README's own statements
Expand Down
7 changes: 7 additions & 0 deletions adapters/bifrost/policies/model-java.rqlp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
:sources (endpoint-set :entries [
(source :id input :display-name "benchmark input" :categories [input.user-controlled] :selector (rql :schema-version 1 (language java (call :callee (name "dfb_source")))) :bind return-value :labels [attacker-controlled])
(source :id declared-source :display-name "Config.fetchRemote" :categories [input.user-controlled] :selector (rql :schema-version 1 (language java (call :callee (name "fetchRemote")))) :bind return-value :labels [attacker-controlled])])
;; One sanitizer declaration, `in: 0 / out: return`, removing the label the
;; sources add. `Clean.scrub` is declared; the sibling `Clean.sanitize` is
;; deliberately absent, which is what template 6 measures. Category Z is
;; scored for this adapter by Amendment A9
;; (docs/modeling-matrix.md#amendments).
:sanitizers (endpoint-set :entries [
(sanitizer :id declared-sanitizer :selector (rql :schema-version 1 (language java (call :callee (name "scrub")))) :input (argument :index 0) :output return-value :removes [attacker-controlled])])
:sinks (endpoint-set :entries [
(sink :id sink :display-name "benchmark sink" :categories [data.sensitive] :selector (rql :schema-version 1 (language java (call :callee (name "dfb_sink")))) :dangerous-operand (argument :index 0) :accepts [attacker-controlled])
(sink :id declared-sink :display-name "Audit.record" :categories [data.sensitive] :selector (rql :schema-version 1 (language java (call :callee (name "record")))) :dangerous-operand (argument :index 0) :accepts [attacker-controlled])])) )
19 changes: 14 additions & 5 deletions adapters/bifrost/policies/model-javascript.rqlp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
; DataFlowBench benchmark-controlled taint-modeling matrix — JavaScript.
;
; The preregistered partition (docs/modeling-matrix.md#bifrost--v0106-build-18d09c57)
; scores category S — declared sources and sinks — for this adapter and nothing
; else. Categories P, Z, O, E, and B are `unsupported` for Bifrost's standalone
; policy CLI, so this policy declares nothing for them: an artifact that
; declared a category the partition declines would be a translated
; approximation, which the equivalence contract forbids.
; scored category S — declared sources and sinks — for this adapter and nothing
; else; Amendment A9 (docs/modeling-matrix.md#amendments) added category Z,
; declared sanitizers, on a measurement of the pinned CLI. Categories P, O, E,
; and B remain `unsupported` for Bifrost's standalone policy CLI, so this policy
; declares nothing for them: an artifact that declared a category the partition
; declines would be a translated approximation, which the equivalence contract
; forbids.
;
; `:unmodeled require-model` is the load-bearing-model requirement of
; docs/modeling-matrix.md#the-load-bearing-model-requirement. Every committed
Expand All @@ -30,6 +32,13 @@
:sources (endpoint-set :entries [
(source :id benchmark-input :display-name "benchmark input" :categories [input.user-controlled] :selector (rql :schema-version 1 (language javascript (call :callee (name "dfb_source")))) :bind return-value :labels [attacker-controlled])
(source :id declared-source :display-name "declared source Config.fetchRemote" :categories [input.user-controlled] :selector (rql :schema-version 1 (language javascript (call :callee (name "fetchRemote")))) :bind return-value :labels [attacker-controlled])])
;; One sanitizer declaration, `in: 0 / out: return`, removing the label the
;; sources add. `scrub` is declared; the sibling `sanitize` — same shape,
;; same identity body, a name at least as sanitizer-shaped — is deliberately
;; absent, which is what template 6 measures. Category Z is scored for this
;; adapter by Amendment A9 (docs/modeling-matrix.md#amendments).
:sanitizers (endpoint-set :entries [
(sanitizer :id declared-sanitizer :selector (rql :schema-version 1 (language javascript (call :callee (name "scrub")))) :input (argument :index 0) :output return-value :removes [attacker-controlled])])
;; Two sink declarations, both `in: 0`: the benchmark sink, and
;; `Audit.record`. The sibling `Audit.discard` is deliberately absent.
:sinks (endpoint-set :entries [
Expand Down
7 changes: 7 additions & 0 deletions adapters/bifrost/policies/model-python.rqlp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
:sources (endpoint-set :entries [
(source :id benchmark-input :display-name "benchmark input" :categories [input.user-controlled] :selector (rql :schema-version 1 (language python (call :callee (name "dfb_source")))) :bind return-value :labels [attacker-controlled])
(source :id declared-source :display-name "declared source Config.fetchRemote" :categories [input.user-controlled] :selector (rql :schema-version 1 (language python (call :callee (name "fetch_remote")))) :bind return-value :labels [attacker-controlled])])
;; One sanitizer declaration, `in: 0 / out: return`, removing the label the
;; sources add. `scrub` is declared; the sibling `sanitize` — same shape,
;; same identity body, a name at least as sanitizer-shaped — is deliberately
;; absent, which is what template 6 measures. Category Z is scored for this
;; adapter by Amendment A9 (docs/modeling-matrix.md#amendments).
:sanitizers (endpoint-set :entries [
(sanitizer :id declared-sanitizer :selector (rql :schema-version 1 (language python (call :callee (name "scrub")))) :input (argument :index 0) :output return-value :removes [attacker-controlled])])
:sinks (endpoint-set :entries [
(sink :id benchmark-sink :display-name "benchmark sink" :categories [data.sensitive] :selector (rql :schema-version 1 (language python (call :callee (name "dfb_sink")))) :dangerous-operand (argument :index 0) :accepts [attacker-controlled])
(sink :id declared-sink :display-name "declared sink Audit.record" :categories [data.sensitive] :selector (rql :schema-version 1 (language python (call :callee (name "record")))) :dangerous-operand (argument :index 0) :accepts [attacker-controlled])])) )
Loading
Loading