7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
83 lines
2.8 KiB
Python
83 lines
2.8 KiB
Python
"""The egress denial-guidance helper must turn machine reason codes into clear,
|
|
actionable user messages (what was blocked + how to allow it)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from local_deep_research.security.egress.guidance import denial_guidance
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"reason,target,must_contain",
|
|
[
|
|
# Scope blocks name the scope AND the setting to change.
|
|
(
|
|
"scope_mismatch_private_only",
|
|
"arxiv",
|
|
["Private only", "Egress Scope"],
|
|
),
|
|
(
|
|
"scope_mismatch_public_only",
|
|
"library",
|
|
["Public only", "Egress Scope"],
|
|
),
|
|
("strict_not_primary", "wikipedia", ["Strict", "primary"]),
|
|
# Inference blocks name the require-local toggle.
|
|
("provider_cloud_only", "openai", ["Require local LLM", "openai"]),
|
|
("provider_cloud", "openai", ["Require local embeddings"]),
|
|
("provider_remote", "ollama", ["local"]),
|
|
# Hard rule: metadata cannot be overridden.
|
|
("blocked_metadata_ip", None, ["cannot be overridden", "metadata"]),
|
|
("elasticsearch_cloud_id_public_egress", None, ["Cloud ID", "hosts"]),
|
|
("unknown_egress_scope", None, ["unrecognised", "Egress Scope"]),
|
|
],
|
|
)
|
|
def test_guidance_is_clear_and_actionable(reason, target, must_contain):
|
|
msg = denial_guidance(reason, target=target)
|
|
assert msg and len(msg) > 20
|
|
for needle in must_contain:
|
|
assert needle in msg, f"{reason}: expected '{needle}' in: {msg}"
|
|
|
|
|
|
def test_guidance_inserts_target():
|
|
msg = denial_guidance("scope_mismatch_private_only", target="arxiv")
|
|
assert "arxiv" in msg
|
|
|
|
|
|
def test_non_policy_reasons_get_honest_explanation_not_setting_advice():
|
|
# A malformed URL isn't a policy block the user fixes via settings.
|
|
msg = denial_guidance("url_malformed")
|
|
assert "malformed" in msg
|
|
assert "Egress Scope" not in msg
|
|
|
|
|
|
def test_unknown_reason_is_safe_and_nonempty():
|
|
msg = denial_guidance("brand_new_code_42", target="X")
|
|
assert "X" in msg
|
|
assert "brand_new_code_42" in msg # surfaced for support
|
|
assert msg # never empty
|
|
|
|
|
|
def test_target_none_falls_back_to_this_action():
|
|
msg = denial_guidance("scope_mismatch_private_only") # no target
|
|
assert msg.startswith("This action")
|
|
assert "Egress Scope" in msg
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"reason,needle",
|
|
[
|
|
("no_hostname", "no host"),
|
|
("unsupported_scheme", "http/https"),
|
|
("dangerous_scheme", "non-web scheme"),
|
|
("host_unclassified", "resolved or classified"),
|
|
("internal_error", "internal error"),
|
|
],
|
|
)
|
|
def test_all_non_policy_reasons_explain_without_setting_advice(reason, needle):
|
|
msg = denial_guidance(reason)
|
|
assert needle in msg
|
|
# These are parse/format failures, not a policy the user toggles.
|
|
assert "Egress Scope" not in msg
|