mirror of
https://github.com/NCBM/plyngent.git
synced 2026-11-07 15:37:55 +08:00
test: cover the approval line and the policy records
Registry cases (none / once / round / grant / YOLO / denial / error / handler record / closest answer wins), the wire cap keeping the line, the three policy paths that record their answer, and a pretty detail that ignores the header. The existing confirm tests now assert the line they gain.
This commit is contained in:
@@ -33,9 +33,9 @@ async def test_yolo_only_skips_yolo_tagged_tools() -> None:
|
||||
on_confirm=confirm,
|
||||
yolo=True,
|
||||
)
|
||||
assert await reg.execute("yolo_ok", "{}") == "y"
|
||||
assert await reg.execute("yolo_ok", "{}") == "[approval] yolo (auto)\ny"
|
||||
assert calls == []
|
||||
assert await reg.execute("no_yolo", "{}") == "n"
|
||||
assert await reg.execute("no_yolo", "{}") == "[approval] user (once)\nn"
|
||||
assert calls == ["no_yolo"]
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ async def test_yolo_off_keeps_the_yolo_tagged_prompt() -> None:
|
||||
return True
|
||||
|
||||
reg = ToolRegistry([yolo_ok], danger=danger, on_confirm=confirm, yolo=False)
|
||||
assert await reg.execute("yolo_ok", "{}") == "y"
|
||||
assert await reg.execute("yolo_ok", "{}") == "[approval] user (once)\ny"
|
||||
assert calls == ["yolo_ok"]
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ async def test_yolo_keeps_a_reason_that_refuses_the_skip() -> None:
|
||||
return True
|
||||
|
||||
reg = ToolRegistry([escalated], danger=danger, on_confirm=confirm, yolo=True)
|
||||
assert await reg.execute("escalated", "{}") == "x"
|
||||
assert await reg.execute("escalated", "{}") == "[approval] user (once)\nx"
|
||||
assert seen == ["interpreter 'python' + privilege escalation sudo"]
|
||||
|
||||
|
||||
@@ -103,8 +103,10 @@ async def test_trustable_grant_once() -> None:
|
||||
session_state=session,
|
||||
)
|
||||
with bind_tool_context(session=session):
|
||||
assert await reg.execute("trust_me", "{}") == "ok"
|
||||
assert await reg.execute("trust_me", "{}") == "ok"
|
||||
assert await reg.execute("trust_me", "{}") == "[approval] user (once)\nok"
|
||||
# The TRUSTABLE grant answers from here on: nobody is asked, and the
|
||||
# result says so.
|
||||
assert await reg.execute("trust_me", "{}") == "[approval] grant (session)\nok"
|
||||
assert calls == ["trust_me"]
|
||||
|
||||
|
||||
@@ -123,8 +125,8 @@ async def test_untagged_trustable_prompts_every_time() -> None:
|
||||
return True
|
||||
|
||||
reg = ToolRegistry([always_ask], danger=danger, on_confirm=confirm, yolo=False)
|
||||
assert await reg.execute("always_ask", "{}") == "ok"
|
||||
assert await reg.execute("always_ask", "{}") == "ok"
|
||||
assert await reg.execute("always_ask", "{}") == "[approval] user (once)\nok"
|
||||
assert await reg.execute("always_ask", "{}") == "[approval] user (once)\nok"
|
||||
assert calls == ["always_ask", "always_ask"]
|
||||
|
||||
|
||||
@@ -151,7 +153,7 @@ async def test_trustable_grant_persists_to_session_data() -> None:
|
||||
yolo=False,
|
||||
session_state=session,
|
||||
)
|
||||
assert await reg.execute("trust_me", "{}") == "ok"
|
||||
assert await reg.execute("trust_me", "{}") == "[approval] user (once)\nok"
|
||||
assert has_grant(session, "trust_me")
|
||||
loaded = await store.load()
|
||||
assert isinstance(loaded, dict)
|
||||
@@ -170,7 +172,7 @@ async def test_trustable_grant_persists_to_session_data() -> None:
|
||||
yolo=False,
|
||||
session_state=session2,
|
||||
)
|
||||
assert await reg2.execute("trust_me", "{}") == "ok"
|
||||
assert await reg2.execute("trust_me", "{}") == "[approval] grant (session)\nok"
|
||||
assert calls == ["trust_me"]
|
||||
|
||||
|
||||
|
||||
@@ -188,6 +188,35 @@ def test_classify_danger_fetch() -> None:
|
||||
assert isinstance(reason2, str) and "DELETE" in reason2
|
||||
|
||||
|
||||
async def test_a_private_host_answer_is_recorded_as_a_user_process_approval(workspace: Path) -> None:
|
||||
"""The prompt that opened loopback for this process is what the result says."""
|
||||
del workspace
|
||||
from plyngent.agent import Approval
|
||||
from plyngent.tools.context import collect_approvals
|
||||
from plyngent.tools.net.grants import ensure_host_allowed, set_fetch_policy_confirm_hook
|
||||
|
||||
set_fetch_policy_confirm_hook(lambda *_args: True)
|
||||
try:
|
||||
with collect_approvals() as recorded:
|
||||
await ensure_host_allowed("http://127.0.0.1:9/")
|
||||
finally:
|
||||
set_fetch_policy_confirm_hook(None)
|
||||
assert recorded == [Approval("user", "process")]
|
||||
|
||||
|
||||
async def test_a_private_host_grant_is_recorded_as_a_process_grant(workspace: Path) -> None:
|
||||
"""A second fetch to the granted host asks nobody, and says so."""
|
||||
del workspace
|
||||
from plyngent.agent import Approval
|
||||
from plyngent.tools.context import collect_approvals
|
||||
from plyngent.tools.net.grants import ensure_host_allowed
|
||||
|
||||
grant_private_host("127.0.0.1", 9)
|
||||
with collect_approvals() as recorded:
|
||||
await ensure_host_allowed("http://127.0.0.1:9/")
|
||||
assert recorded == [Approval("grant", "process")]
|
||||
|
||||
|
||||
async def test_fetch_get_post_put_delete(workspace: Path, http_server: str) -> None:
|
||||
del workspace
|
||||
base = http_server
|
||||
|
||||
@@ -344,6 +344,30 @@ async def test_skill_write_session_grant_is_asked_once(tmp_path: Path) -> None:
|
||||
assert (root / "acme" / "notes.md").read_text(encoding="utf-8") == "note\n"
|
||||
|
||||
|
||||
async def test_a_skill_write_says_which_answer_let_it_through(tmp_path: Path) -> None:
|
||||
"""Once, this chat, and the standing config each read differently."""
|
||||
from plyngent.agent import Approval
|
||||
from plyngent.tools.context import collect_approvals
|
||||
|
||||
root = _write_root(tmp_path)
|
||||
with _bound(tmp_path, root, policy=SkillWritePolicy(confirm=lambda *_args: True)), collect_approvals() as once:
|
||||
created = await skill_create.handler("once-skill", "d", "b")
|
||||
|
||||
def for_the_chat(*_args: object) -> SkillWriteDecision:
|
||||
return SkillWriteDecision(allow=True, session=True)
|
||||
|
||||
with _bound(tmp_path, root, policy=SkillWritePolicy(confirm=for_the_chat)), collect_approvals() as chat:
|
||||
_ = await skill_create.handler("chat-skill", "d", "b")
|
||||
_ = await skill_edit.handler("chat-skill", append="\nMore.\n")
|
||||
|
||||
with _bound(tmp_path, root, policy=SkillWritePolicy(allow_all=True)), collect_approvals() as config:
|
||||
_ = await skill_create.handler("config-skill", "d", "b")
|
||||
|
||||
assert once == [Approval("user", "once")], created
|
||||
assert chat == [Approval("user", "session"), Approval("grant", "session")]
|
||||
assert config == [Approval("config", "policy")]
|
||||
|
||||
|
||||
async def test_skill_write_denylist_wins_over_a_grant(tmp_path: Path) -> None:
|
||||
root = _write_root(tmp_path)
|
||||
with _bound(tmp_path, root, policy=SkillWritePolicy(allow_all=True)):
|
||||
|
||||
@@ -235,6 +235,41 @@ def test_command_denylist_policy_confirm_allow(workspace: object) -> None:
|
||||
clear_policy_allowed_commands()
|
||||
|
||||
|
||||
def test_a_denylist_answer_is_recorded_as_a_user_process_approval(workspace: object) -> None:
|
||||
"""The answer that let the call through is what the result has to say."""
|
||||
del workspace
|
||||
from plyngent.agent import Approval
|
||||
from plyngent.tools.context import collect_approvals
|
||||
from plyngent.tools.workspace import clear_policy_allowed_commands, set_policy_confirm_hook
|
||||
|
||||
set_policy_confirm_hook(lambda *_args: True)
|
||||
clear_policy_allowed_commands()
|
||||
try:
|
||||
with collect_approvals() as recorded:
|
||||
check_command_allowed(["sudo", "id"])
|
||||
finally:
|
||||
set_policy_confirm_hook(None)
|
||||
clear_policy_allowed_commands()
|
||||
assert recorded == [Approval("user", "process")]
|
||||
|
||||
|
||||
def test_a_matching_denylist_grant_is_recorded_as_a_process_grant(workspace: object) -> None:
|
||||
"""Nobody is asked the second time, and the result says so."""
|
||||
del workspace
|
||||
from plyngent.agent import Approval
|
||||
from plyngent.tools.context import collect_approvals
|
||||
from plyngent.tools.workspace import clear_policy_allowed_commands, grant_policy_command
|
||||
|
||||
clear_policy_allowed_commands()
|
||||
grant_policy_command("sudo")
|
||||
try:
|
||||
with collect_approvals() as recorded:
|
||||
check_command_allowed(["sudo", "id"])
|
||||
finally:
|
||||
clear_policy_allowed_commands()
|
||||
assert recorded == [Approval("grant", "process")]
|
||||
|
||||
|
||||
def test_command_denylist_policy_confirm_deny(workspace: object) -> None:
|
||||
del workspace
|
||||
from plyngent.tools.workspace import (
|
||||
|
||||
Reference in New Issue
Block a user