Regex gate
The regex gate matches one configured part of the current request. It can
inspect the complete body, selected JSON string fields, normalized JSON message
blocks, path, query, or selected header values. It returns audit-safe findings
with type regex_match.
Choose what to scan with scan.kind, then choose what to do with
scan.action.kind. This example replaces matches in the request body:
name: customer-identifiers
kind: regex
scan:
kind: body
action:
kind: replace
template: '[{entity}]'
pattern_catalog:
entities:
- name: customer-id
rules:
- name: customer-id-rule
pattern: '\bCUST-[0-9]{8}\b'
confidence: high
The body is decoded as strict UTF-8. Path and query scans use the exact text in the request model. A header scan matches each selected header value on its own; a match cannot span two values. Header names are case-insensitive:
name: labeled-headers
kind: regex
scan:
kind: header
names: [x-customer-note, x-request-label]
action:
kind: deny
pattern_catalog: patterns.yaml
The header scan sees the current request snapshot, including validated header
mutations from earlier gates. The regex gate does not return header mutations
itself.
OpenShell permits writes only in the x-openshell-middleware- namespace, so a
general regex replacement cannot rewrite arbitrary selected headers. A custom
gate can return supported header writes or removals when it declares the
GateCapability.MUTATE_HEADERS capability.
Structured JSON fields
json-fields parses the current body as strict UTF-8 JSON and scans only string
values selected by typed paths. The selectors are part of the general
egress_gate.request_content contract, which is also
available to custom gates. A json-fields selector starts at the document
root:
name: message-identifiers
kind: regex
scan:
kind: json-fields
selectors:
- segments:
- kind: key
value: messages
- kind: each
- kind: key
value: content
action:
kind: replace
template: '[{entity}]'
pattern_catalog: patterns.yaml
Missing paths and non-string terminal values produce no scan text. Overlapping selectors select the same JSON string once. Matches cannot span two selected string values. Structured replacement re-encodes each selected string token and preserves every source byte outside selected tokens, including whitespace, number spellings, key order, and escaping in unrelated strings.
The JSON parser rejects invalid UTF-8, malformed JSON, duplicate object keys,
non-standard constants, invalid Unicode scalar values, and configured parsing
limits. Invalid UTF-8 produces body_encoding_invalid; invalid strict JSON
produces body_format_invalid.
Normalized message blocks
message-blocks builds on the same JSON document. A json-message-map selects
one or more message arrays, reads each message role, and applies relative
text_selectors. Optional tool_input_selectors and tool_output_selectors
classify provider- or harness-specific fields explicitly. The mapping requires
at least one selector across those three groups. The scan can then filter
normalized roles and block kinds:
name: model-visible-identifiers
kind: regex
scan:
kind: message-blocks
message_mapping:
kind: json-message-map
messages:
segments:
- kind: key
value: request
- kind: key
value: messages
role_key: role
text_selectors:
- segments:
- kind: key
value: content
- segments:
- kind: key
value: content
- kind: each
- kind: key
value: text
roles: [system, developer, user, tool]
block_kinds: [text, tool_output]
action:
kind: deny
pattern_catalog: patterns.yaml
Known roles are system, developer, user, assistant, and tool; other or
missing roles normalize to unknown. Text selected from a tool message is a
tool_output; other selected text is text. Message mappings are policy
configuration, so harness-specific envelopes do not require changes to regex
matching. A custom gate can reuse the public RequestContentParser,
MessageBlocksParser, and MessageBlockExtractor surfaces when it needs the
same text-target and replacement contracts with a different semantic
extractor.
A catalog can be inline or in a relative .yaml or .yml file. Relative paths
resolve from the Egress Gate process working directory, not from the policy
file. Use an inline catalog when the process does not have a stable working
directory. The gate rejects absolute paths, path traversal, symlinks, YAML
aliases, duplicate keys, invalid body UTF-8, unsafe patterns, and oversized
catalogs.
Each entity has a stable, bounded name and one or more rules. Rule confidence
is low, medium, or high. Optional flags are ignore_case, multiline,
dot_all, and ascii. Do not use named capture groups or inline flags.
Patterns must produce non-empty matches. Findings include overlapping
detections. Replacement uses deterministic, non-overlapping matches.
Actions
scan.action.kind |
Match result |
|---|---|
detect |
proceed, findings, no request mutation |
deny |
terminal deny, findings, egress_gate_regex_denied |
replace |
proceed, findings, explicit body replacement |
detect and deny work with every scan kind. replace exists in the complete
body, json-fields, and message-blocks schemas. It cannot be configured for
a path, query, or header scan.
This structure keeps unsupported combinations out of generated schemas and
editor suggestions. OpenShell middleware results cannot rewrite a request path
or query. Header replacement is not part of the built-in gate.
The replace action owns its template. It returns a body replacement even when
there is no match. This preserves the operator's explicit intent to replace the
current body. Invalid body UTF-8 is a stable body_encoding_invalid service
failure. A structured scan whose UTF-8 body is not strict JSON produces the
stable body_format_invalid failure.
The regex gate does not edit the body in place. It returns the replacement in
RequestMutations. The pipeline processor uses it to build the next immutable
HttpRequest snapshot. If the pipeline allows the request, Egress Gate includes
the replacement in the final mutations returned to the OpenShell supervisor.
Replacement templates contain literal text and the {entity} field only.
Output size is projected before rendering and is bounded by the advertised
OpenShell body limit.
Scan reference
scan.kind |
Additional fields | Supported action.kind values |
|---|---|---|
body |
none | detect, deny, replace |
json-fields |
non-empty typed selectors |
detect, deny, replace |
message-blocks |
message_mapping; optional roles and block_kinds |
detect, deny, replace |
path |
none | detect, deny |
query |
none | detect, deny |
header |
non-empty names list |
detect, deny |
Configure another regex gate when different request parts need different catalogs or actions. Keeping one scan per gate makes matches, findings, and replacement offsets unambiguous.