Skip to content
Open
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
228 changes: 227 additions & 1 deletion doc/admin-guide/configuration/hrw4u.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -529,10 +529,58 @@ Groups
...
}

Control Flow
------------

HRW4U conditionals use ``if``, ``elif``, and ``else`` blocks. Each branch
takes a condition expression followed by a ``{ ... }`` body of statements:

.. code-block:: none

if condition {
statement;
} elif other-condition {
statement;
} else {
statement;
}

``elif`` and ``else`` are optional and can be chained. Branches can be nested
to arbitrary depth:

.. code-block:: none

REMAP {
if inbound.status > 399 {
if inbound.status < 500 {
if inbound.status == 404 {
inbound.resp.X-Error = "not-found";
} elif inbound.status == 403 {
inbound.resp.X-Error = "forbidden";
}
} else {
inbound.resp.X-Error = "server-error";
}
}
}

The ``break;`` statement exits the current section immediately, skipping any
remaining statements and branches:

.. code-block:: none

REMAP {
if inbound.req.X-Internal != "1" {
break;
}
# Only reached for internal requests
inbound.req.X-Debug = "on";
}

Condition operators
-------------------

HRW4U supports the following condition operators, which are used in `if (...)` expressions:
HRW4U supports the following condition operators, which are used in ``if`` expressions:

==================== ========================= ============================================
Operator HRW4U Syntax Description
Expand Down Expand Up @@ -589,6 +637,184 @@ Run with `--debug all` to trace:
- Condition evaluations
- State and output emission

Sandbox Policy Enforcement
==========================

Organizations deploying HRW4U across teams can restrict which language features
are permitted using a sandbox configuration file. Features can be **denied**
(compilation fails with an error) or **warned** (compilation succeeds but a
warning is emitted). Both modes support the same feature categories.

Pass the sandbox file with ``--sandbox``:

.. code-block:: none

hrw4u --sandbox /etc/trafficserver/hrw4u-sandbox.yaml rules.hrw4u

The sandbox file is YAML with a single top-level ``sandbox`` key. A JSON
Schema for editor validation and autocomplete is provided at
``tools/hrw4u/schema/sandbox.schema.json``.

.. code-block:: yaml

sandbox:
message: | # optional: shown once after all errors/warnings
...
deny:
sections: [ ... ] # section names, e.g. TXN_START
functions: [ ... ] # function names, e.g. run-plugin
conditions: [ ... ] # condition keys, e.g. geo.
operators: [ ... ] # operator keys, e.g. inbound.conn.dscp
language: [ ... ] # break, variables, in, else, elif
warn:
functions: [ ... ] # same categories as deny
conditions: [ ... ]

All lists are optional. If ``--sandbox`` is omitted, all features are permitted.
When a sandbox file is provided it must contain a top-level ``sandbox:`` key;
an empty policy can be expressed as ``sandbox: {}``.
A feature may not appear in both ``deny`` and ``warn``.

Denied Sections
---------------

The ``sections`` list accepts any of the HRW4U section names listed in the
`Sections`_ table, plus ``VARS`` to deny the variable declaration block.
A denied section causes the entire block to be rejected; the body is not
validated.

Functions
---------

The ``functions`` list accepts any of the statement-function names used in
HRW4U source. The complete set of deniable functions is:

====================== =============================================
Function Description
====================== =============================================
``add-header`` Add a header (``+=`` operator equivalent)
``counter`` Increment an ATS statistics counter
``keep_query`` Keep only specified query parameters
``no-op`` Explicit no-op statement
``remove_query`` Remove specified query parameters
``run-plugin`` Invoke an external remap plugin
``set-body-from`` Set response body from a URL
``set-config`` Override an ATS configuration variable
``set-debug`` Enable per-transaction ATS debug logging
``set-plugin-cntl`` Set a plugin control flag
``set-redirect`` Issue an HTTP redirect response
``skip-remap`` Skip remap processing (open proxy)
====================== =============================================

Conditions and Operators
------------------------

The ``conditions`` and ``operators`` lists use the same dot-notation keys shown
in the `Conditions`_ and `Operators`_ tables above (e.g. ``inbound.req.``,
``geo.``, ``outbound.conn.``).

Entries ending with ``.`` use **prefix matching** — ``geo.`` denies all
``geo.*`` lookups (``geo.city``, ``geo.ASN``, etc.). Entries without a trailing
``.`` are matched exactly, which allows fine-grained control over sub-values:

.. code-block:: yaml

sandbox:
deny:
operators:
- http.cntl.SKIP_REMAP # deny just this sub-value
conditions:
- geo.ASN # deny ASN lookups specifically
warn:
operators:
- http.cntl. # warn on all other http.cntl.* usage
conditions:
- geo. # warn on remaining geo.* lookups

Prefix entries and exact entries can be combined across ``deny`` and ``warn``
to create graduated policies — deny the dangerous sub-values while warning on
the rest.

Language Constructs
-------------------

The ``language`` list accepts a fixed set of constructs:

================ ===================================================
Construct What it controls
================ ===================================================
``break`` The ``break;`` statement (early section exit)
``variables`` The entire ``VARS`` section and all variable usage
``else`` The ``else { ... }`` branch of conditionals
``elif`` The ``elif ... { ... }`` branch of conditionals
``in`` The ``in [...]`` and ``!in [...]`` set membership operators
================ ===================================================

Output
------

When a denied feature is used the error output looks like:

.. code-block:: none

rules.hrw4u:3:4: error: 'set-debug' is denied by sandbox policy (function)

This feature is restricted by CDN-SRE policy.
Contact cdn-sre@example.com for exceptions.

When a warned feature is used the compiler emits a warning but succeeds:

.. code-block:: none

rules.hrw4u:5:4: warning: 'set-config' is warned by sandbox policy (function)

This feature is restricted by CDN-SRE policy.
Contact cdn-sre@example.com for exceptions.

The sandbox message is shown once at the end of the output, regardless of how
many denial errors or warnings were found. Warnings alone do not cause a
non-zero exit code.

Example Configuration
---------------------

A typical policy for a CDN team where remap plugin authors should not have
access to low-level or dangerous features, with transitional warnings for
features being phased out:

.. code-block:: yaml

sandbox:
message: |
This feature is not permitted by CDN-SRE policy.
To request an exception, file a ticket at https://help.example.com/cdn

deny:
# Disallow hooks that run outside the normal remap context
sections:
- TXN_START
- TXN_CLOSE
- PRE_REMAP

# Disallow functions that affect ATS internals or load arbitrary code
functions:
- run-plugin
- skip-remap

# Deny a specific dangerous sub-value
operators:
- http.cntl.SKIP_REMAP

warn:
# These functions will be denied in a future release
functions:
- set-debug
- set-config

# Warn on all remaining http.cntl usage
operators:
- http.cntl.

Examples
========

Expand Down
1 change: 1 addition & 0 deletions tools/hrw4u/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
build/
dist/
uv.lock
*.spec
13 changes: 7 additions & 6 deletions tools/hrw4u/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ UTILS_FILES=src/symbols_base.py \
SRC_FILES_HRW4U=src/visitor.py \
src/symbols.py \
src/suggestions.py \
src/kg_visitor.py \
src/procedures.py
src/procedures.py \
src/sandbox.py \
src/kg_visitor.py

ALL_HRW4U_FILES=$(SHARED_FILES) $(UTILS_FILES) $(SRC_FILES_HRW4U)

Expand Down Expand Up @@ -170,10 +171,10 @@ test:

# Build standalone binaries (optional)
build: gen
uv run pyinstaller --onefile --name hrw4u --strip $(SCRIPT_HRW4U)
uv run pyinstaller --onefile --name u4wrh --strip $(SCRIPT_U4WRH)
uv run pyinstaller --onefile --name hrw4u-lsp --strip $(SCRIPT_LSP)
uv run pyinstaller --onefile --name hrw4u-kg --strip $(SCRIPT_KG)
uv run pyinstaller --onedir --name hrw4u --strip $(SCRIPT_HRW4U)
uv run pyinstaller --onedir --name u4wrh --strip $(SCRIPT_U4WRH)
uv run pyinstaller --onedir --name hrw4u-lsp --strip $(SCRIPT_LSP)
uv run pyinstaller --onedir --name hrw4u-kg --strip $(SCRIPT_KG)

# Wheel packaging (adjust pyproject to include both packages if desired)
package: gen
Expand Down
2 changes: 2 additions & 0 deletions tools/hrw4u/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ classifiers = [
]
dependencies = [
"antlr4-python3-runtime>=4.9,<5.0",
"pyyaml>=6.0,<7.0",
"rapidfuzz>=3.0,<4.0",
]

Expand Down Expand Up @@ -77,6 +78,7 @@ markers = [
"reverse: marks tests for reverse conversion (header_rewrite -> hrw4u)",
"ast: marks tests for AST validation",
"procedures: marks tests for procedure expansion",
"sandbox: marks tests for sandbox policy enforcement",
]

[dependency-groups]
Expand Down
Loading