v0.11.2
Fixed
-
Stored evidence is scrubbed independently of outbound enforcement. Both
SDKs scan the final prompt and response before signing and emission, preserving
not_evaluatedverdicts on observe-only callbacks while keeping PII whose
configured action resolves toblockorredactout of the stored copy.
(1c7bc68,31efaa2) -
Provider-bound PII enforcement covers every text role on direct wrapper
paths. System, user, assistant, and tool-result text now share the pre-call
block/redaction pass. (52d80c6) -
The vendored integration gate cannot pass zero suites. Import failures and
a suite-count mismatch are terminal, and the offline gate requires all 23
declared suites. (aac7744) -
Sender-visible terminal delivery loss starts a signed fresh chain. Ingest
rejection, permanent failure, and retry exhaustion arm reasoned gap markers;
failed markers are counted without recursive replacement.
(7b041e1) -
Both external policy connectors pin their approved DNS snapshot. Mixed
public/private answers are refused, sockets use approved numeric addresses
while retaining Host/SNI, redirects are not followed, and injected transport
seams are explicitly trusted. (bcd7ce5,5c8de50,7dcb9a1) -
Current Gemini clients are governed in both SDKs. TypeScript supports
@google/genaiunary/streaming methods with explicit wrapping and module
interception; Python supports the corresponding sync/asyncgoogle-genai
resource methods through explicit wrapping. (b3695e8,461d73d) -
Applied NLP-only redaction fails closed in TypeScript. A Presidio analyzer
or anonymizer failure can no longer fall back to a regex redactor that cannot
locate the detected type; the provider call is refused even under fail-open
detector posture. (1712bd5) -
Session taint detects injection without a separate PII rule. Enabling the
latch now runs its built-in injection scan directly in both SDKs, without
fabricating PII telemetry when no PII policy exists, and escalates later
session egress as configured. (6c315e5) -
Python preserves explicit blank principal precedence. An ambient subject
no longer replaces an explicitly empty or whitespaceuser_id; required
principal enforcement refuses it consistently with TypeScript, and the
signed record keeps the same explicit value. (4b6f272) -
The evaluation conformance contract matches the hardened engines. Spec
version 1.2 and cross-SDK fixtures now pin deny-wins resolution, local versus
remote malformed-rule handling, action-bound approvals, current rule hashing,
and detection-versus-application failure posture. KD-11 is closed.
(062bfc8) -
Monitor mode retains clean governed events at any sample rate. The shared
emission gates cover wrapper, integration, and standalone execution-span
paths while enforce mode keeps ordinary allowed-call sampling.
(3d3e2f1,7fd5495,3e11332) -
Stream evidence opt-out no longer bypasses enforcement. TypeScript
streamingMode: "skip"still avoids wrapping an allowed stream in enforce
mode, but only after pre-call block/redaction has run; monitor mode records
the stream despite the opt-out. (8e1bbb1) -
Haystack prompt blocks no longer create raw-input exception snapshots. A
terminal conditional output prevents the downstream generator from becoming
runnable and returns only a safe block branch. (027663d) -
A retained MCP task facade cannot keep a raw client binding. TypeScript
repairs an already-issued experimental facade onto the governed Proxy and
fails loudly for an opaque shape it cannot repair. (8ad7d65) -
Optional integration ranges stop before untested future majors. Resolver
metadata now matches the reviewed major lines instead of making open-ended
compatibility promises. (0484553) -
Python package metadata uses the current SPDX license form. Builds retain
LICENSEandNOTICEwithout deprecated classifier or manifest warnings.
(dc372d5) -
Release benchmark evidence is reproducible and retained. Two complete
TypeScript/Python passes publish raw overhead, stress, chain, loss, and memory
results for the measured revision; fake ingest transports acknowledge the
exact accepted count used by current sender reconciliation.
(a6fe59c,a8c8185,c970505) -
Observe-only PII storage no longer claims outbound redaction. Framework
callbacks now reportaction_taken: "not_evaluated"when they redact only
the stored event copy, and preserve the requested action, detected types, and
unchanged outbound status undermetadata.obsvr_telemetry.
(b015b58,0d8b9f2) -
Detector failures and tool observations retain their correct reporting
boundary. Hostile metadata access resolves through fail mode, response-only
canary findings become policy flags, and OpenAI Agents tool spans no longer
duplicate model-observer compliance. (7b091cc) -
Python now governs Anthropic provider tool runners. Messages runner
construction sends the initial prompt through the normal pre-call policy and
installs governed copies of local runnable tools before dispatch is
registered, while preserving hosted tool definitions. Sync and async
Messages runners are covered from Anthropic 0.68.0, and async managed-session
local tools are covered from 0.103.0 without claiming governance over remote
session model traffic. -
Python now keeps legacy Gemini chat sessions inside governance.
start_chat()returned the provider's rawChatSession, so both sync and
async messages bypassed pre-call policy and audit. The factory now returns a
transparent governed session whosesend_messageandsend_message_async
calls enforce the same block, redaction, stream, and response rules as direct
generation. -
Python now governs OpenAI and Anthropic
with_streaming_responsecalls.
Policy runs before a response context manager is created, preserving the
providers' deferred sync and async request lifecycle while preventing blocked
prompts from reaching context entry. Parsed or read response content is
captured once when the context exits, with the raw status, headers, and body
accessors still available to callers. -
Python now governs OpenAI and Anthropic
with_raw_responsecalls. The
accessor objects were outside proxy traversal, so their text-generation
methods bypassed every pre-call block and redaction. The explicit raw-response
paths now run through the same sync/async pipeline, preserve the raw response
object returned to the caller, and use its cached typed view for response
policy and audit extraction. The deferredwith_streaming_responsecontext
managers remain a separate boundary. -
Python now governs legacy Gemini's async generation method. The declared
google-generativeaiintegration interceptedgenerate_contentbut handed
generate_content_asyncstraight to the provider with no policy or audit
event. The real 0.8.6 package exposes it as a coroutine with the same request
shape; it now runs through the async governance pipeline, including outbound
redaction and pre-provider blocking. -
Python retry and byte-split items cannot fall out of the signed chain when
producers refill the public queue. The worker put an already-signed item
back into that bounded queue; a concurrent producer could fill the slot first,
makingput_nowaitdrop the signed item while later events still chained to
it. Worker-owned pending lanes now retain those items in order until terminal
delivery, and queue-drain accounting follows the original submission. -
Security correction: a customer hook can no longer erase an existing block. The
published advanced-options example combined an SSN block with an
on_pre_call/onPreCallhook whose ordinary path returnedallow; that
explicit allow replaced the PII verdict and sent the SSN to the provider.
Pre-call enforcement is now monotonic in both SDKs and on both TypeScript
pipelines: hooks may add a block or redaction, whileallowonly preserves
a call that no earlier layer blocked. External-oracle regressions assert the
provider receives zero calls for the published composition. -
Policy-change events use the signed delivery queue.
set_tenant_policy
/setTenantPolicyposted through a private one-off HTTP client that ignored
every response status, retried nothing, updated no delivery counter, emitted
no default warning, and placed the governance event outside the SDK chain.
Both SDKs now enqueue the event through their normal sender, so rejection,
retry exhaustion, shutdown flushing, counters, signatures, and loss reporting
have the same semantics as every other audit event. -
A
policy_rulesentry written as a mapping enforces. It reached the rule
engine uncoerced and raised on the first attribute read, where the detector
guard resolved the raise byfailMode— open by default — so ablockrule
written that way did not block and the call went to the provider behind a
stderr notice.policy_floorhad always accepted mappings, which is most of
why a caller expected the other tier to. Both tiers of rule now hold to one
schema and differ only in what an invalid rule costs: a/policiespoll drops
it and firessdk:rule_rejected,init()throws and names the index and the
field. That newly refuses a rule missingenabled, one with a misspelled
type, one claiming the reservedsdk:/backend:namespace, and aregex
pattern the ReDoS validator rejects — each of which previously produced a rule
the engine skipped in silence. (2d25f64) -
obsvr.wrap()governs the.stream()helpers in Python. They were
outside the method table, so the proxy returned the provider's own bound
method and no pipeline ran: on one wrapped client apii_policyof
{ssn: "block"}refusedcreate(stream=True)and letmessages.stream(...)
through with the SSN in it.messages.stream,beta.messages.stream,
chat.completions.streamandresponses.streamare governed now and emit one
event per run. Python also governs the Anthropic runner surfaces described
earlier in this release section.
(0db5816) -
The TypeScript OpenAI Agents tracing processor scans what it stores. It
ran no policy pipeline of any kind, so at any sample rate it wrote the agent's
prompt and response into the signed event raw, while the Python twin ran the
observe-only PII net and the READMEs described the scan as running in both.
(b64cabb) -
No event describes a provider call that has not happened. Both provider
SDKs decorate their asynccreatewith a@required_argsvalidator that is
itself a plain function, soinspect.iscoroutinefunctionreported False and
the sync pipeline ran on an async client: an event withsuccess: true, an
empty response and zero latency was written when the coroutine was
CONSTRUCTED, before the provider had been contacted and while the call could
still fail. Affectedmessages.createandchat.completions.createon the
async clients;responses.createcarries no such decorator and was always
right. (30cb339) -
A tool-result redaction that could not be applied is no longer recorded as
applied. A content item whosetextcould not be assigned was swallowed by
a per-itemexcept Exception: passinside the MCP sanitizer, so the raw
result travelled to the model under an event stampedredacted. The failure
now reaches the guard that exists: blocked underfailMode: "closed", and
under open the result is delivered with apolicy_flagthat files the types
as detected, drops the redaction claim and names the lost layer.
(179848d) -
A
govern_toolgate whose evaluation raised recordsnot_evaluated. It
recordedallowed— a verdict asserting a gate looked and permitted — on a
call where the gate raised and the tool ran ungoverned, with no trace of the
lost layer. Same vocabulary the MCP boundary already used for this failure.
(9328dec) -
The six NLP-only PII types are removed from the REQUEST, not only from the
record.name,person,address,location,medicaland
national_idhave no built-in regex pattern, and Python ran the Presidio
anonymizer over the stored copy alone while rewriting the outbound request
with the regex tier — so aredactverdict on one of them produced an event
readingredactedwith the value intact on the wire. Both that and the
attribution defect came from one place: the analyzer call returned an empty
list for "found nothing" and for "did not answer", so a 500ms timeout was
indistinguishable from a clean scan andaction_sourcecredited
builtin+presidiowhenever the URL was merely configured. Behaviour
change: with Presidio configured and one of those six resolving to
redact, an anonymizer that does not answer now blocks the call.
(3f7d657) -
init(auto=True)reaches a client class a framework already imported.
from openai import OpenAIbinds the class object into the importing module,
so rebinding the provider module afterwards could not reach it: a framework
imported beforeinit()kept constructing the ungoverned class while the
report named every provider alias as intercepted and nothing warned. Driven
against the real packages, crewai, ag2, LlamaIndex, Haystack and
openai-agents were all ungoverned that way — three from the bare top-level
import. Resolved by identity, so a framework's own unrelated class of the
same name is untouched.
(9e3dbda) -
hardDeletion.endpointis inside the SSRF guard. The fourth
customer-configured outbound URL, carrying a DELETE with theX-API-Key
header, was outside it while the security notes said every such URL was
validated. (b7ff312)
Changed
- Documentation: the coverage claims this release moved, and several that
were simply wrong. "The SDK can emit only content hashes" described an
option that exists in neither SDK; the seventeen governed method paths are
the table across every provider rather than the coverage of one client, and
completions.createand the assistants surface are in no table at all;
Cloudflare Workers AI has no Python path; the session-taint latch never arms
on injection without apiiPolicyco-requisite that went unstated; the
stored-copy scrub holds on the framework integrations in TypeScript only; and
the package table was two releases stale.
(d6c5bb3)