Skip to content

fix: Port eval identifier validation and persona template rendering to v1 - #6806

Merged
GWeale merged 3 commits into
v1from
backport-v1-pr17
Aug 19, 2026
Merged

fix: Port eval identifier validation and persona template rendering to v1#6806
GWeale merged 3 commits into
v1from
backport-v1-pr17

Conversation

@GWeale

@GWeale GWeale commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Ports three evaluation commits from main to the v1 branch.

  1. Validate local eval path segments (7b87f910)

    • New private module evaluation/_path_validation.py holds validate_path_segment.
    • app_name, eval_set_id and eval_set_result_id raise ValueError when empty, when they contain a null byte, / or \, or when the whole value is . or ... A dot inside a value is fine: app.v2 passes.
    • Breaking: an app_name that nests eval storage under a hierarchical name raises. Flatten the name; there is no opt-out.
  2. Validate path segments in the GCS eval managers (a56f6e13)

    • The same check runs in both GCS managers, on every read, write, list, update and delete entry point.
  3. Render nested persona templates through the enclosing environment (30493bae)

    • Both user-simulator prompt builders render nested persona strings with template_env.from_string, and both outer environments are SandboxedEnvironment.
    • A persona behaviour name, description or rubric that uses attribute access raises during prompt construction. Ordinary placeholders such as {{ stop_signal }} render normally.

GWeale added 3 commits August 17, 2026 23:01
`LocalEvalSetsManager` and `LocalEvalSetResultsManager` interpolated the
caller-supplied `app_name`, `eval_set_id` and `eval_set_result_id` straight
into a filesystem path, so an identifier containing a separator or a
traversal segment addressed a directory outside the app's own eval storage.

They now call a new shared helper, `evaluation._path_validation
.validate_path_segment`, before any path is constructed. The helper rejects
empty values, null bytes, `/`, `\`, `.` and `..`.

Behaviour change: these identifiers now raise `ValueError` for the values
listed above. Callers that relied on a separator in `app_name` to nest eval
storage under a hierarchical name are affected.

Port of 7b87f91 on main.
…rs (v1)

`GcsEvalSetsManager` and `GcsEvalSetResultsManager` interpolated
`app_name`, `eval_set_id` and `eval_set_result_id` straight into a blob
name. A separator or a traversal segment in one of those identifiers
therefore composed a key addressing a different app's prefix on a shared
evaluation bucket. The only guard on this branch was `_validate_id`, called
from `create_eval_set` alone; every read, list and update path reached the
blob-name builders unchecked, and `app_name` was never checked at all.

Both managers now call `validate_path_segment` before building a blob name,
the same helper the local managers use.

Behaviour change: these identifiers now raise `ValueError` when empty or
when they contain a null byte, `/`, `\`, `.` or `..`. A deployment using
hierarchical app names for GCS-backed eval storage is affected.

Port of a56f6e1 on main.
…(v1)

Both user-simulator prompt builders render nested persona strings through a
`render_string_filter`, and that filter built a fresh `jinja2.Template` from
the persona text and rendered it. A fresh `Template` uses jinja2's default
environment, so the nested render ran with no sandbox regardless of the
outer environment. A persona behaviour name such as
`{{ ''.__class__.__mro__ }}` was evaluated during prompt construction and
could walk the type hierarchy. `per_turn_user_simulator_quality_prompts.py`
was additionally building its outer environment with a plain `Environment`.

The filter now renders through the enclosing environment with
`template_env.from_string(...)`, and the per-turn builder's environment is a
`SandboxedEnvironment` like the other one. `context.get_all()` is passed
because `from_string(...).render()` takes a mapping rather than a jinja2
`Context`.

Behaviour change: a persona that relies on attribute traversal in a nested
template now raises `jinja2.exceptions.SecurityError` during prompt
construction. Supported placeholders such as `{{ stop_signal }}` render
exactly as before.

Port of 30493ba on main.
@GWeale GWeale changed the title fix: Port evaluation path validation and persona template sandboxing to v1 fix: Port eval identifier validation and persona template rendering to v1 Aug 19, 2026
@GWeale
GWeale merged commit 0a4a5c6 into v1 Aug 19, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants