Files
wehub-resource-sync 4b6817381b
Benchmark image — build + push to ECR (any adapter) / build + push (push) Waiting to run
CI / quality (ubuntu-latest) (push) Waiting to run
CI / test (tools-runtime) (push) Waiting to run
CI / test (e2e-general) (push) Waiting to run
CI / test (cli-runtime) (push) Waiting to run
CI / test (e2e-provider-and-openclaw) (push) Waiting to run
CI / test (integrations-and-misc) (push) Waiting to run
CI / coverage-report (push) Blocked by required conditions
CI / test-kubernetes (push) Waiting to run
CI / should-run-thorough (push) Waiting to run
CI / test-thorough (cloudwatch-demo) (push) Blocked by required conditions
CI / test-thorough (flink-ecs) (push) Blocked by required conditions
CI / test-thorough (upstream-lambda) (push) Blocked by required conditions
CI / test-thorough (prefect-ecs-fargate) (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Blocked by required conditions
Release / publish-release (push) Blocked by required conditions
Release / publish-main-release (push) Blocked by required conditions
Release / prepare (push) Waiting to run
Release / verify (push) Blocked by required conditions
Release / build-python-dist (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Blocked by required conditions
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Waiting to run
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

110 lines
3.8 KiB
Python

"""End-to-end tests for guardrail overlapping keyword redaction."""
from __future__ import annotations
import re
from platform.guardrails.engine import GuardrailEngine
from platform.guardrails.rules import GuardrailAction, GuardrailRule
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _make_rule(
name: str = "test",
action: str = "redact",
patterns: list[str] | None = None,
keywords: list[str] | None = None,
replacement: str = "",
) -> GuardrailRule:
compiled = tuple(re.compile(p, re.IGNORECASE) for p in (patterns or []))
kws = tuple(k.lower() for k in (keywords or []))
return GuardrailRule(
name=name,
action=GuardrailAction(action),
patterns=compiled,
keywords=kws,
replacement=replacement,
)
# ---------------------------------------------------------------------------
# 1. Guardrails overlapping keyword redaction — full pipeline
# ---------------------------------------------------------------------------
class TestOverlappingRedactionE2E:
"""Prove that overlapping keywords are fully redacted through the complete
scan → audit → redact pipeline, not just in isolation."""
def test_secret_and_secret_key_across_rules(self) -> None:
"""Two rules, shorter keyword is a prefix of the longer one."""
engine = GuardrailEngine(
[
_make_rule(name="generic", keywords=["secret"]),
_make_rule(name="specific", keywords=["secret_key"]),
]
)
result = engine.apply("export secret_key=hunter2")
# The longer match must win — no leftover "_key"
assert "_key" not in result
assert "=hunter2" in result
assert "secret" not in result.lower().replace("[redacted:", "")
def test_api_and_api_key_single_rule(self) -> None:
"""Both keywords in the same rule."""
engine = GuardrailEngine(
[
_make_rule(name="creds", keywords=["api", "api_key"]),
]
)
result = engine.apply("set api_key=abc123")
assert "_key" not in result
assert "=abc123" in result
def test_multiple_overlapping_occurrences(self) -> None:
"""Multiple overlapping pairs in one string."""
engine = GuardrailEngine(
[
_make_rule(name="r1", keywords=["pass"]),
_make_rule(name="r2", keywords=["password"]),
]
)
text = "password=foo and pass=bar"
result = engine.apply(text)
# "password" should be fully redacted (not "word" leftover)
assert "word" not in result.split("and")[0]
# "pass" alone should also be redacted
assert "=bar" in result
def test_pattern_and_keyword_overlap(self) -> None:
"""A regex pattern and a keyword overlap on the same span."""
engine = GuardrailEngine(
[
_make_rule(name="pat", patterns=[r"AKIA[A-Z0-9]{16}"]),
_make_rule(name="kw", keywords=["akia"]),
]
)
text = "key=AKIAIOSFODNN7EXAMPLE"
result = engine.apply(text)
# The longer regex match should win
assert "AKIA" not in result
assert "key=" in result
def test_full_scan_apply_audit_cycle(self) -> None:
"""Scan, check matches, then apply — the real engine flow."""
engine = GuardrailEngine(
[
_make_rule(name="tokens", keywords=["token", "token_secret"]),
]
)
text = "auth token_secret=xyz and token=abc"
# Apply correctly redacts overlapping matches without leftovers.
result = engine.apply(text)
assert "_secret" not in result
assert "=xyz" in result
assert "=abc" in result