1
0
Fork 0

release(0.6.0): the raw-html narrowing ships, and the version claims it already made become true

The narrowing landed in 736f370 and its prose asserted `0.6.0` in thirteen places
-- README's public front page among them -- while every version surface still read
0.5.0. That is the same defect class the last three commits were spent correcting:
a published number no measurement backs. Two ways out, land it or neutralize the
references; operator chose to cut.

SURFACES MOVED (the eight the 0.5.0 sweep established, plus the ninth verified)

  pyproject.toml           0.5.0 -> 0.6.0
  __init__.py              0.5.0 -> 0.6.0
  CHANGELOG.md             [Unreleased] -> [0.6.0], fresh [Unreleased]
  README.md                badge, `Status: v0.6`, install tag @v0.6.0
  SECURITY.md              support window `0.5.x` -> `0.6.x`
  docs/BRIEF.md            `v0.5 (alpha)` -> `v0.6 (alpha)`
  docs/ADOPTION-BRIEF.md   `v0.5.0` x2, and 717 -> 727 passing
  CLAUDE.md                `v0.5 (alpha)` -> `v0.6`, plus what 0.6.0 changed
  forge description        178 codepoints, carries no version claim -- verified,
                           not moved. A surface can be checked and stay still.

Measurement provenance is left alone, as in 0.5.0: `tests/test_disposition.py`'s
"0.5.0 axis separation", `disposition.py` and `calibration.py` docstrings,
LIMITATIONS' 0.5.0 reference, every dated claim in docs/PLAN-v1.md. Bumping those
falsifies the record rather than updating it.

MINOR, NOT PATCH: 0.6.0 loosens the upload door. A document whose only finding was
a doc-relative URL attribute on an inactive tag name, or an attribute-less
`<base />`, now WARNs where it was held -- 25 documents in the reference corpus, 2
in each wiki corpus.

VERIFIED BEFORE COMMITTING, NOT AFTER

  727 passed; coverage 128/128 recall, 6/6 documented gaps hold
  docs/LIMITATIONS.md: 33 items, README says 33
  rawhtml-census PRODUCTION row equals `A + base-url` on all three populations --
    the shipped predicate measured, not a hypothesis about it
  redos-sweep: 0 candidates of 152 patterns
  docs/fp-sweep.py still imports the private names it reaches into
  no tracked file carries a stale current-state version claim

Still to prove before the tag: `git show` over this commit's README, and a clean
clone install at this sha.
This commit is contained in:
Kjell Tore Guttormsen 2026-08-11 18:01:36 +02:00
commit 6bcb898632
9 changed files with 32 additions and 13 deletions

View file

@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
Nothing yet.
## [0.6.0] — 2026-08-11
### Changed — `active:raw-html` stops firing on two things that carry no affordance ### Changed — `active:raw-html` stops firing on two things that carry no affordance
`is_active_tag` had two over-reaching branches, both measured on consumer corpora `is_active_tag` had two over-reaching branches, both measured on consumer corpora

View file

@ -11,7 +11,7 @@ framework-agnostisk kode.
Referanse-implementasjon: `claude-code-llm-wiki` Stage B (`tools/wiki_ingest/`). Referanse-implementasjon: `claude-code-llm-wiki` Stage B (`tools/wiki_ingest/`).
Lexikon-seed: `injection-patterns.mjs` fra `llm-security`-pluginen. Lexikon-seed: `injection-patterns.mjs` fra `llm-security`-pluginen.
Repoet er på **v0.5 (alpha)**: stdlib-kjernen er bygget og testet (15 moduler + Repoet er på **v0.6 (alpha)**: stdlib-kjernen er bygget og testet (15 moduler +
topp-nivå wiring, showcase + korpus), inkl. OKF-adapter og aktivt-innhold- topp-nivå wiring, showcase + korpus), inkl. OKF-adapter og aktivt-innhold-
detektor (EchoLeak-klassen) i output-gaten. Mode-b `import_bundle` skanner detektor (EchoLeak-klassen) i output-gaten. Mode-b `import_bundle` skanner
reserverte strukturfiler (`index.md`/`log.md`) i mottatte bundles i stedet for å reserverte strukturfiler (`index.md`/`log.md`) i mottatte bundles i stedet for å
@ -19,7 +19,9 @@ path-avvise dem; upload-front-end beholder shadow-reject (`allow_reserved=False`
Output-gatens decode-and-rescan mater dekodet base64-klartekst gjennom BÅDE lexicon Output-gatens decode-and-rescan mater dekodet base64-klartekst gjennom BÅDE lexicon
og secret-egress (LLM02), så en base64-innpakket credential fanges som og secret-egress (LLM02), så en base64-innpakket credential fanges som
`decoded:egress:*` i stedet for å forsvinne; hex-innpakket er en dokumentert `decoded:egress:*` i stedet for å forsvinne; hex-innpakket er en dokumentert
restgap (entropy eksponerer kun base64-klartekst). restgap (entropy eksponerer kun base64-klartekst). `active:raw-html` krever nå et
EKSTERNT mål på URL-attributt-grenen, og `<base>` er ute av det aktive navnesettet;
scanner og mutator har hver sin predikat (`is_active_tag` / `is_defangable_tag`).
Start med `docs/BRIEF.md` for design, `README.md` for bruk, `docs/PLAN.md` for Start med `docs/BRIEF.md` for design, `README.md` for bruk, `docs/PLAN.md` for
byggerekkefølgen. byggerekkefølgen.

View file

@ -2,7 +2,7 @@
Write-time defensive layer for Python pipelines that persist LLM output: sanitize, fence, tool-less quarantined transform, capability isolation, scan before persist, fail-secure. Write-time defensive layer for Python pipelines that persist LLM output: sanitize, fence, tool-less quarantined transform, capability isolation, scan before persist, fail-secure.
![Version](https://img.shields.io/badge/version-0.5.0-blue) ![Version](https://img.shields.io/badge/version-0.6.0-blue)
![Status](https://img.shields.io/badge/status-alpha-orange) ![Status](https://img.shields.io/badge/status-alpha-orange)
![Python](https://img.shields.io/badge/python-3.10%2B-purple) ![Python](https://img.shields.io/badge/python-3.10%2B-purple)
![License](https://img.shields.io/badge/license-MIT-lightgrey) ![License](https://img.shields.io/badge/license-MIT-lightgrey)
@ -33,7 +33,7 @@ at write time, never assumed from the format. Any pipeline ingesting external da
into an agent-read store has this shape; an OKF wiki is its canonical form — which into an agent-read store has this shape; an OKF wiki is its canonical form — which
is why the guard ships a first-class OKF adapter (below). is why the guard ships a first-class OKF adapter (below).
**Status:** `v0.5`, alpha. The stdlib-only core — its detector, contract, and **Status:** `v0.6`, alpha. The stdlib-only core — its detector, contract, and
OKF-adapter modules plus the top-level wiring — is built and tested, exercised by OKF-adapter modules plus the top-level wiring — is built and tested, exercised by
an end-to-end showcase and adversarial + false-positive corpora. The public API an end-to-end showcase and adversarial + false-positive corpora. The public API
may still change. There are real limitations, stated plainly below; read them. may still change. There are real limitations, stated plainly below; read them.
@ -43,7 +43,7 @@ may still change. There are real limitations, stated plainly below; read them.
Not on PyPI. The guard is distributed from its Forgejo origin — pin a release tag: Not on PyPI. The guard is distributed from its Forgejo origin — pin a release tag:
```bash ```bash
pip install "llm-ingestion-guard @ git+https://git.fromaitochitta.com/open/llm-ingestion-pipeline-security.git@v0.5.0" pip install "llm-ingestion-guard @ git+https://git.fromaitochitta.com/open/llm-ingestion-pipeline-security.git@v0.6.0"
``` ```
The `open/` mirror is anonymously readable, so CI needs no deploy key, token, or The `open/` mirror is anonymously readable, so CI needs no deploy key, token, or

View file

@ -6,7 +6,7 @@ downstream corpus. Reports are welcome.
## Supported versions ## Supported versions
The project is pre-1.0 (`0.5.x`, alpha). Only the latest published version receives The project is pre-1.0 (`0.6.x`, alpha). Only the latest published version receives
fixes; there are no back-ported security branches yet. Pin a version and watch the fixes; there are no back-ported security branches yet. Pin a version and watch the
`CHANGELOG.md` `### Security` entries. `CHANGELOG.md` `### Security` entries.

View file

@ -4,7 +4,7 @@
especially one converging on Google's Open Knowledge Format (OKF v0.1) — and needs especially one converging on Google's Open Knowledge Format (OKF v0.1) — and needs
to decide **when** and **where** to add a write-time ingestion guard. to decide **when** and **where** to add a write-time ingestion guard.
**Status of the guard:** `v0.5.0` (alpha). Stdlib-only core, framework-agnostic. **Status of the guard:** `v0.6.0` (alpha). Stdlib-only core, framework-agnostic.
Public API may still change. Read the known-limitations section before you rely Public API may still change. Read the known-limitations section before you rely
on it. on it.
@ -140,9 +140,9 @@ live payload:
python -m llm_ingestion_guard.coverage # exit 0 = all as documented python -m llm_ingestion_guard.coverage # exit 0 = all as documented
``` ```
As of `v0.5.0`: **128 / 128 defended classes demonstrated (recall 100%)** and **6 / As of `v0.6.0`: **128 / 128 defended classes demonstrated (recall 100%)** and **6 /
6 documented gaps still hold** (a *closed* gap fails the test, forcing a doc 6 documented gaps still hold** (a *closed* gap fails the test, forcing a doc
update). The matrix is the single source of truth for the test suite (**717 update). The matrix is the single source of truth for the test suite (**727
passing**), which also asserts total recall, that every lexicon pattern has a passing**), which also asserts total recall, that every lexicon pattern has a
case (so the matrix cannot fall behind the lexicon), the full LLM02 secret-egress case (so the matrix cannot fall behind the lexicon), the full LLM02 secret-egress
set, and the container-layer front-end (CSV formula-injection, zip-slip/bomb, set, and the container-layer front-end (CSV formula-injection, zip-slip/bomb,

View file

@ -3,7 +3,7 @@
**A reusable, minimal, dependency-light defensive layer for LLM *ingestion* **A reusable, minimal, dependency-light defensive layer for LLM *ingestion*
pipelines — the write-time siblings of query-time chatbot guardrails.** pipelines — the write-time siblings of query-time chatbot guardrails.**
Status: implemented — v0.5 (alpha). This document defines what the repo contains Status: implemented — v0.6 (alpha). This document defines what the repo contains
and why; the stdlib-only core is built and tested (see `README.md` for usage and and why; the stdlib-only core is built and tested (see `README.md` for usage and
`docs/PLAN.md` for the build order). `docs/PLAN.md` for the build order).

View file

@ -222,7 +222,11 @@ items; this is the full list, each with the mechanism.
target (an element outside the active name set carrying `href="/en/agent-sdk/quickstart"` target (an element outside the active name set carrying `href="/en/agent-sdk/quickstart"`
reaches no attacker-controlled host), and `<base>` left the active *name* set (APIM's reaches no attacker-controlled host), and `<base>` left the active *name* set (APIM's
attribute-less `<base />` means "run the inherited policy"; HTML's `<base>` has its attribute-less `<base />` means "run the inherited policy"; HTML's `<base>` has its
whole affordance in an `href` the attribute branch still catches). Measured before whole affordance in an `href` the attribute branch still catches). `<base />` appears
in **25 of reference-corpus's 389** documents — count it with
`grep -rlE '<base\s*/?>'`, because a loose `grep '<base'` says 30 and is wrong: it
also matches the literal `<base64_string>` placeholder, which is not a tag this
detector ever fired on. Measured before
and after in one session against one corpus state — `docs/rawhtml-census.py`, whose and after in one session against one corpus state — `docs/rawhtml-census.py`, whose
`PRODUCTION` row re-measures the shipped predicate rather than a hypothesis: `PRODUCTION` row re-measures the shipped predicate rather than a hypothesis:
reference-corpus 133 → **108** of 389, vendor-harvest 100 → **98** of 187, reference-corpus 133 → **108** of 389, vendor-harvest 100 → **98** of 187,
@ -247,6 +251,14 @@ items; this is the full list, each with the mechanism.
Recovering the rest is **not** a further narrowing — it needs a carrier split and a Recovering the rest is **not** a further narrowing — it needs a carrier split and a
new label (`active:raw-html-link`), because raw HTML has no ordinary form and the new label (`active:raw-html-link`), because raw HTML has no ordinary form and the
class collapses to one finding per document. class collapses to one finding per document.
**The external-target test now gates one more surface, and it is a literal one.**
`_has_external_target` matches `^(?:[A-Za-z][A-Za-z0-9+.\-]*:|//)`, so a
backslash-separated authority — `href="\\evil.example/x"` — reads as relative and
now grades down, although WHATWG URL parsing normalizes backslashes to slashes for
special schemes and a browser would resolve it externally. This is inherited, not
introduced: the markdown paths have applied the same predicate since 0.3.1. It is
recorded here rather than fixed because the fix belongs to the predicate, not to
the raw-HTML branch that newly depends on it.
**The scanner and the mutator no longer share a predicate.** Until 0.6.0 `neutralize` **The scanner and the mutator no longer share a predicate.** Until 0.6.0 `neutralize`
imported `is_active_tag` by name, so any narrowing moved the opt-in mutator too, and imported `is_active_tag` by name, so any narrowing moved the opt-in mutator too, and
no test discriminated the two halves. They are now `is_active_tag` and no test discriminated the two halves. They are now `is_active_tag` and

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "llm-ingestion-guard" name = "llm-ingestion-guard"
version = "0.5.0" version = "0.6.0"
description = "Write-time defensive layer for Python pipelines that persist LLM output: sanitize, fence, tool-less quarantined transform, capability isolation, scan before persist, fail-secure." description = "Write-time defensive layer for Python pipelines that persist LLM output: sanitize, fence, tool-less quarantined transform, capability isolation, scan before persist, fail-secure."
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"

View file

@ -63,7 +63,7 @@ from .grounding import (
) )
from . import okf from . import okf
__version__ = "0.5.0" __version__ = "0.6.0"
# --- §6 bookends: the two library-side halves around the transform --------- # --- §6 bookends: the two library-side halves around the transform ---------