Documentation
¶
Overview ¶
Package normgate is a write-time ResultAdmitter that closes the context-MMU's measured DETECTION gap: the v0.1 ctxmmu matches injection markers and secret shapes as raw ASCII regex/substring, so any obfuscation (char-spacing, base64, homoglyph, zero-width, fullwidth, bidi, format-variant secrets) walks straight through (~100% evasion, measured on a private transcript-derived corpus). normgate is a NORMALIZE-AND-RESCAN driver: it canonicalizes a COPY of the result bytes (strip invisibles, fold homoglyph/fullwidth, reverse bidi, decode base64/hex, de-separate single-letter runs), broadens the secret vocabulary to real formats the regex never enumerated, and runs the detectors over that canonical view.
It registers at rank 5 — BEFORE ctxmmu (rank 10) — so it composes in FRONT of the existing gate: a hit pages the bytes out and stubs the payload in place (same convention as ctxmmu), and the rank-10 gate then sees a benign stub. This is the "plug a SOTA-informed driver into the fused core" demonstration — the kernel walks the registry; enabling normgate is one blank-import line.
PROVENANCE (the ABI Ref.Taint seam, unused by ctxmmu v0.1): the fold is monotonic (most-restrictive wins), so a chained driver can only ADD restriction, never remove a false positive a later driver imposes. normgate therefore treats provenance as a FIRST-CLASS input to its OWN verdict: an injection-shaped result whose source is a TRUSTED LOCAL read (the agent reading its own files) is paged out as a RETRIEVABLE Transform, not sealed as a Quarantine — closing the "quarantined my own source code" false positives. Untrusted egress still quarantines. Secrets quarantine regardless of source (a leaked credential is worth holding even from a local read).
The de-obfuscating canonicalization + lexical detection lives in internal/canon (one primitive, tested once, reused by the read-time recall re-screen too). normgate keeps only the POLICY: what to DO with a canon finding given its provenance.
Index ¶
- Constants
- Variables
- type Gate
- func (g *Gate) Admit(ctx context.Context, c *abi.ToolCall, r *abi.Result) abi.Verdict
- func (g *Gate) Caps() []abi.Capability
- func (g *Gate) Clear(id string)
- func (g *Gate) Evicted() int64
- func (g *Gate) HeldLen() int
- func (g *Gate) PageIn(ctx context.Context, id string) ([]byte, canon.Findings, error)
- func (g *Gate) Stats() (total, quarantined, transformed int64)
Constants ¶
const DefaultMaxHeld = 8192
DefaultMaxHeld bounds the quarantine-handle ledger so a long-lived gate on a poison/obfuscation-heavy stream cannot grow `held` without bound. Like ctxmmu's twin ledger (and ifc/ratelimit), this is a process-lifetime cap: every quarantine minted a permanent held["ng-q<n>"] entry with no removal path, so the registered rank-5 Default gate leaked one entry per caught threat for the life of the server. Oldest handles drop first (FIFO); the bytes live in the shared CAS keyed by digest.
Variables ¶
var Default = New()
Default is the registered gate.
Functions ¶
This section is empty.
Types ¶
type Gate ¶
type Gate struct {
// contains filtered or unexported fields
}
Gate is the normalize-and-rescan ResultAdmitter.
func New ¶
func New() *Gate
New builds the registered-default-shaped gate with the standard ledger bound, overridable at process start via FAK_NORMGATE_MAX_HELD (the FAK_WORKERS/FAK_BUDGET/FAK_NORMGATE idiom: a sensible default with an env escape hatch).
func NewWithLimit ¶
NewWithLimit builds a gate whose held ledger holds at most maxHeld handles (oldest dropped first). A non-positive maxHeld falls back to DefaultMaxHeld. Used by the leak-regression test to exercise eviction with a small bound.
func (*Gate) Admit ¶
Admit normalizes-and-rescans. On a detected (and provenance-relevant) threat it performs the page-out side-effect in place (ctxmmu's convention) and returns the verdict; the rank-10 gate then sees a benign stub.
func (*Gate) Caps ¶
func (g *Gate) Caps() []abi.Capability
func (*Gate) Clear ¶
Clear records a witness clearance for a quarantined id (the page-in gate). It is NECESSARY but NOT SUFFICIENT: PageIn still re-screens the bytes, so clearing a held credential does not launder it back into context. Clearing an unknown/evicted id is a harmless no-op — PageIn refuses it anyway.
func (*Gate) Evicted ¶
Evicted reports the lifetime count of held entries dropped by the maxHeld bound.
func (*Gate) HeldLen ¶
HeldLen reports the current number of quarantine handles in the bounded ledger (≤ maxHeld); Evicted reports how many were dropped by the bound over the gate's lifetime. Together they make the bound observable (HeldLen plateaus while Evicted climbs) — and give `held` a reader so the ledger is not write-only dead state.
func (*Gate) PageIn ¶
PageIn is the gated read of the held quarantine map (#76): the bytes paged out at quarantineOut are returned ONLY through this gate, never by a raw map read. It enforces two gates, mirroring recall's read-time re-screen:
- a witness Clear(id) must have run — an uncleared (or unknown/evicted) id is refused fail-closed, exactly like ctxmmu.PageIn;
- the retrieved bytes are RE-SCREENED through canon.Scan — the same de-obfuscating primitive normgate uses at write time. A SECRET re-screen hit refuses release even after a witness clear: a leaked credential does not launder back into context (normgate's secrets-are-absolute policy, normgate.go top-of-file, joined with recall's "clearance does not launder poison"). An injection-only hit is released so a witness can retrieve the caught payload for forensics/inspection.
The fresh Findings ride back with the bytes so a retrieval is never blind to what it is handling. An evicted id's CAS bytes were unpinned and may be gone — that surfaces as a resolve error, the safe direction.