generated from coulomb/repo-seed
Access controlled knowledge gateway functionality
This commit is contained in:
@@ -17,6 +17,7 @@ def test_builtin_extension_registry_lists_query_processors_and_backend():
|
||||
assert "runtime.context" in ids
|
||||
assert "runtime.form-state" in ids
|
||||
assert "runtime.assessment" in ids
|
||||
assert "policy.local-label" in ids
|
||||
|
||||
|
||||
def test_builtin_processor_descriptors_capture_safety_and_provenance():
|
||||
@@ -81,3 +82,18 @@ def test_builtin_runtime_descriptors_expose_boundaries():
|
||||
assert {capability.id for capability in form_state.capabilities} >= {"forms", "rules"}
|
||||
assert assessment.kind == "assessment-runner"
|
||||
assert assessment.safety["provider_calls"] == "adapter-only"
|
||||
|
||||
|
||||
def test_builtin_policy_descriptor_exposes_cli_and_adapter_boundary():
|
||||
registry = builtin_extension_registry()
|
||||
|
||||
descriptor = registry.get("policy.local-label")
|
||||
|
||||
assert descriptor.kind == "policy-gateway"
|
||||
assert descriptor.safety["network"] is False
|
||||
assert {capability.id for capability in descriptor.capabilities} >= {
|
||||
"policy",
|
||||
"policy_filter",
|
||||
}
|
||||
assert "mkt policy check" in descriptor.cli["commands"]
|
||||
assert "RelationshipPolicyAdapter" in descriptor.metadata["external_adapters"]
|
||||
|
||||
211
tests/test_policy_gateway.py
Normal file
211
tests/test_policy_gateway.py
Normal file
@@ -0,0 +1,211 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from click.testing import CliRunner
|
||||
|
||||
from markitect_tool.cli import main
|
||||
from markitect_tool.policy import LocalLabelPolicy, LocalLabelPolicyGateway
|
||||
|
||||
|
||||
POLICY_TEXT = """id: example-policy
|
||||
mode: enforce
|
||||
default_labels: [public]
|
||||
default_subject: public-agent
|
||||
subjects:
|
||||
public-agent:
|
||||
allowed_labels: [public]
|
||||
trust_zones: [public]
|
||||
internal-agent:
|
||||
allowed_labels: [public, internal]
|
||||
trust_zones: [public, internal]
|
||||
path_rules:
|
||||
- id: private-path
|
||||
pattern: private/**
|
||||
labels: [internal]
|
||||
trust_zone: internal
|
||||
"""
|
||||
|
||||
|
||||
def test_local_label_policy_authorizes_by_labels_and_path_rules():
|
||||
gateway = LocalLabelPolicyGateway(LocalLabelPolicy.from_mapping(_policy_mapping()))
|
||||
|
||||
public = gateway.authorize(
|
||||
"public-agent",
|
||||
"query",
|
||||
"public.md",
|
||||
context={"object": {"path": "public.md", "labels": ["public"], "trust_zone": "public"}},
|
||||
)
|
||||
private = gateway.authorize(
|
||||
"public-agent",
|
||||
"query",
|
||||
"private/doc.md",
|
||||
context={"object": {"path": "private/doc.md"}},
|
||||
)
|
||||
internal = gateway.authorize(
|
||||
"internal-agent",
|
||||
"query",
|
||||
"private/doc.md",
|
||||
context={"object": {"path": "private/doc.md"}},
|
||||
)
|
||||
|
||||
assert public["allowed"] is True
|
||||
assert private["allowed"] is False
|
||||
assert private["effect"] == "deny"
|
||||
assert "lacks labels" in private["reason"]
|
||||
assert internal["allowed"] is True
|
||||
|
||||
|
||||
def test_policy_filter_can_redact_denied_results():
|
||||
policy = LocalLabelPolicy.from_mapping(_policy_mapping() | {"on_denied": "redact"})
|
||||
gateway = LocalLabelPolicyGateway(policy)
|
||||
|
||||
result = gateway.filter_results(
|
||||
"public-agent",
|
||||
"search",
|
||||
[
|
||||
{"path": "public.md", "text": "Visible", "policy": {"labels": ["public"]}},
|
||||
{"path": "private/doc.md", "text": "Secret"},
|
||||
],
|
||||
)
|
||||
|
||||
assert result["policy"]["redacted"] == 1
|
||||
assert len(result["results"]) == 2
|
||||
assert result["results"][1]["text"] == "[redacted by policy]"
|
||||
assert result["diagnostics"][0]["code"] == "policy.result.redacted"
|
||||
|
||||
|
||||
def test_policy_audit_mode_keeps_results_but_records_would_deny():
|
||||
gateway = LocalLabelPolicyGateway(LocalLabelPolicy.from_mapping(_policy_mapping()), mode="audit")
|
||||
|
||||
result = gateway.filter_results(
|
||||
"public-agent",
|
||||
"query",
|
||||
[{"path": "private/doc.md", "text": "Internal"}],
|
||||
)
|
||||
|
||||
assert len(result["results"]) == 1
|
||||
assert result["policy"]["audit_denied"] == 1
|
||||
assert result["results"][0]["policy"]["effect"] == "audit_denied"
|
||||
|
||||
|
||||
def test_mkt_policy_check_reports_denied_decision(tmp_path: Path):
|
||||
policy_file = tmp_path / "policy.yaml"
|
||||
policy_file.write_text(POLICY_TEXT, encoding="utf-8")
|
||||
|
||||
result = CliRunner().invoke(
|
||||
main,
|
||||
[
|
||||
"policy",
|
||||
"check",
|
||||
"public-agent",
|
||||
"query",
|
||||
"private/doc.md",
|
||||
"--policy",
|
||||
str(policy_file),
|
||||
"--path",
|
||||
"private/doc.md",
|
||||
],
|
||||
)
|
||||
|
||||
assert result.exit_code == 1
|
||||
assert "denied" in result.output
|
||||
assert "lacks labels" in result.output
|
||||
|
||||
|
||||
def test_mkt_search_filters_local_index_results_by_policy(tmp_path: Path):
|
||||
policy_file = tmp_path / "policy.yaml"
|
||||
private_dir = tmp_path / "private"
|
||||
private_dir.mkdir()
|
||||
policy_file.write_text(POLICY_TEXT, encoding="utf-8")
|
||||
(tmp_path / "public.md").write_text("# Public\n\nKnowledge for everyone.\n", encoding="utf-8")
|
||||
(private_dir / "restricted.md").write_text(
|
||||
"# Restricted\n\nKnowledge for internal work.\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
runner = CliRunner()
|
||||
|
||||
indexed = runner.invoke(main, ["cache", "index", str(tmp_path), "--root", str(tmp_path)])
|
||||
result = runner.invoke(
|
||||
main,
|
||||
[
|
||||
"search",
|
||||
"Knowledge",
|
||||
"--root",
|
||||
str(tmp_path),
|
||||
"--policy",
|
||||
str(policy_file),
|
||||
"--subject",
|
||||
"public-agent",
|
||||
"--format",
|
||||
"json",
|
||||
],
|
||||
)
|
||||
data = json.loads(result.output)
|
||||
|
||||
assert indexed.exit_code == 0
|
||||
assert result.exit_code == 0
|
||||
assert data["count"] >= 1
|
||||
assert all("private/restricted.md" != match["path"] for match in data["matches"])
|
||||
assert data["policy"]["denied"] >= 1
|
||||
|
||||
|
||||
def test_mkt_cache_query_filters_indexed_documents_by_policy(tmp_path: Path):
|
||||
policy_file = tmp_path / "policy.yaml"
|
||||
private_dir = tmp_path / "private"
|
||||
private_dir.mkdir()
|
||||
policy_file.write_text(POLICY_TEXT, encoding="utf-8")
|
||||
(tmp_path / "public.md").write_text("# Public\n\n## Decision\n\nShare it.\n", encoding="utf-8")
|
||||
(private_dir / "restricted.md").write_text(
|
||||
"# Restricted\n\n## Decision\n\nKeep it internal.\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
runner = CliRunner()
|
||||
|
||||
indexed = runner.invoke(main, ["cache", "index", str(tmp_path), "--root", str(tmp_path)])
|
||||
result = runner.invoke(
|
||||
main,
|
||||
[
|
||||
"cache",
|
||||
"query",
|
||||
"sections[heading=Decision]",
|
||||
"--root",
|
||||
str(tmp_path),
|
||||
"--policy",
|
||||
str(policy_file),
|
||||
"--subject",
|
||||
"public-agent",
|
||||
"--format",
|
||||
"json",
|
||||
],
|
||||
)
|
||||
data = json.loads(result.output)
|
||||
|
||||
assert indexed.exit_code == 0
|
||||
assert result.exit_code == 0
|
||||
assert data["count"] == 1
|
||||
assert data["matches"][0]["source_path"] == "public.md"
|
||||
assert data["policy"]["denied"] == 1
|
||||
|
||||
|
||||
def _policy_mapping() -> dict:
|
||||
return {
|
||||
"id": "example-policy",
|
||||
"mode": "enforce",
|
||||
"default_labels": ["public"],
|
||||
"default_subject": "public-agent",
|
||||
"subjects": {
|
||||
"public-agent": {"allowed_labels": ["public"], "trust_zones": ["public"]},
|
||||
"internal-agent": {
|
||||
"allowed_labels": ["public", "internal"],
|
||||
"trust_zones": ["public", "internal"],
|
||||
},
|
||||
},
|
||||
"path_rules": [
|
||||
{
|
||||
"id": "private-path",
|
||||
"pattern": "private/**",
|
||||
"labels": ["internal"],
|
||||
"trust_zone": "internal",
|
||||
}
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user