fix(builder): preserve startup streams and assess shell risks from accurate context

This commit is contained in:
Charles Yao committed 2026-10-26 19:12:16 -07:00
1 parent 63cbbe6d84
commit 64b2c5e5c8
11 files changed
+418 -22

No files matched your search

@@ -112,7 +112,8 @@ def test_shell_reasoning_receives_owner_scope_and_preserves_unknown_risk_and_mod
scope: dict[str, JsonValue] = {
"initial_working_directory": "request_owned_agent_workspace",
"may_contain_cloned_files": True,
"filesystem_confinement_guaranteed": False,
"initial_working_directory_is_confinement": False,
"runtime_filesystem_isolation": "not_attested_to_assessor",
}
result = assess_call(
goal="Materialize configured synthetic assets in this run workspace; preserve user artifacts.",
@@ -134,3 +135,12 @@ def test_shell_reasoning_receives_owner_scope_and_preserves_unknown_risk_and_mod
assert result.destructive is destructive
assert "uncertain" in result.risk_notice
assert result.parameters_summary == {"script": "dify-agent config skills pull --json proof"}
def test_risk_rubric_separates_observed_destruction_from_uncertain_side_effects() -> None:
from services.dify_builder.native_testing.agent_risk_assessor import _CALL_RISK_SYSTEM
assert "Unknown isolation is not evidence that isolation is disabled" in _CALL_RISK_SYSTEM
assert "Ordinary external writes such as sending, creating or publishing" in _CALL_RISK_SYSTEM
assert "Incomplete task progress or missing proof of success is not destruction" in _CALL_RISK_SYSTEM
assert "concrete destruction, damage or deletion" in _CALL_RISK_SYSTEM
@@ -18,6 +18,7 @@ from typing_extensions import TypedDict
from core.dify_builder.models import Actor
from models.dify_builder_native_tests import (
NativeEffectDispatchClaim,
NativeEffectOperation,
NativeEffectOutcome,
NativeTestInvocation,
@@ -183,9 +184,13 @@ def test_reasoning_assessment_cannot_grant_or_hide_opaque_tool_scope() -> None:
AgentCallAssessment.model_validate({**assessment.model_dump(), "approved": True})
@pytest.mark.parametrize("boundary", ["core_tool", "model", "shell_run", "bootstrap", "config_pull"])
@pytest.mark.parametrize(
("boundary", "destructive"),
[(boundary, False) for boundary in ("core_tool", "model", "shell_run", "bootstrap", "config_pull")]
+ [(boundary, True) for boundary in ("shell_run", "bootstrap", "config_pull")],
)
def test_prepare_actual_call_freezes_builder_reasoning_without_business_or_oauth(
monkeypatch: pytest.MonkeyPatch, boundary: str, operations_service: AgentOperationService
monkeypatch: pytest.MonkeyPatch, boundary: str, destructive: bool, operations_service: AgentOperationService
) -> None:
from contextlib import contextmanager
from datetime import UTC, datetime
@@ -263,7 +268,7 @@ def test_prepare_actual_call_freezes_builder_reasoning_without_business_or_oauth
"target_summary": {"tool": "write"},
"parameters_summary": {"enabled": True},
"risk_notice": "Creates one test value.",
"destructive": False,
"destructive": destructive,
}
from runtime_contracts.builder.native.agent_contracts import (
AgentParentNodeRef,
@@ -389,7 +394,9 @@ def test_prepare_actual_call_freezes_builder_reasoning_without_business_or_oauth
assert capability.execution_context is not None
assert capability.execution_context["initial_working_directory"] == "request_owned_agent_workspace"
assert capability.execution_context["may_contain_cloned_files"] is True
assert capability.execution_context["filesystem_confinement_guaranteed"] is False
assert "filesystem_confinement_guaranteed" not in capability.execution_context
assert capability.execution_context["initial_working_directory_is_confinement"] is False
assert capability.execution_context["runtime_filesystem_isolation"] == "not_attested_to_assessor"
asset_cli = capability.execution_context["configured_asset_cli"]
assert isinstance(asset_cli, dict)
assert asset_cli["may_overwrite_local_copies"] is True
@@ -407,6 +414,25 @@ def test_prepare_actual_call_freezes_builder_reasoning_without_business_or_oauth
assert "parameters" not in binding
assert result.key.occurrence_path == key.occurrence_path
if destructive:
from dify_agent.protocol.native_testing import AgentPolicyStop
from sqlalchemy import func, select
from models.dify_builder_native_tests import NativeEffectAttempt
# Encrypted payload I/O is the explicit boundary; SQL identity,
# saved verdict and the before-call reservation gate remain real.
monkeypatch.setattr(service.state_store, "_read_object", lambda _receipt: payload)
owned.bindings.update(persisted.bindings)
decision = service.bridge.before_call(
ref=AgentNativeTestRef.model_validate(ref.model_dump(mode="json")), intent=result
)
assert isinstance(decision, AgentPolicyStop)
assert decision.reason_code == "destructive_effect_forbidden"
with service.loader.session_factory() as session:
for model in (NativeEffectOperation, NativeEffectAttempt, NativeEffectDispatchClaim):
assert session.scalar(select(func.count()).select_from(model)) == 0
def test_only_the_selected_confirmed_model_can_use_the_outer_task_grant() -> None:
from services.dify_builder.native_testing.authorization import task_grant_allowed
@@ -79,6 +79,7 @@ def _receipt(status: str = "running", version: int = 1) -> NativeTestPublicRecei
class _FrameData(TypedDict):
receipt: dict[str, str]
conversation_last_seq: int
test_execution: dict[str, object]
class _DecodedFrame(TypedDict):
@@ -779,3 +780,173 @@ def test_native_model_diagnostic_owner_drift(completed: CompletedOwner, drift: s
assert observed[0]["native_category"] == "timeout"
else:
assert observed == []
@pytest.mark.parametrize(
"boundary",
["startup", "ack_context", "launched", "cancelled", "expired", "owner", "generation", "inactive", "other_policy"],
)
def test_startup_stream_defers_only_until_sql_root_initialization(
completed: CompletedOwner, monkeypatch: pytest.MonkeyPatch, boundary: str
) -> None:
from sqlalchemy import Table
from sqlalchemy.orm import make_transient
from models.dify_builder import DifyBuilderExecutionRequest
from services.dify_builder.service import DifyBuilderService
from services.dify_builder.test_actions import BuilderTestActions
from tests.unit_tests.services.dify_builder.test_service import FakeSessionLock
owner = completed
_restore_public_reads(owner, monkeypatch)
with owner.factory.begin() as sql:
for model in (NativePayloadObject, NativeTestInvocation):
table = model.__table__
assert isinstance(table, Table)
table.create(sql.connection(), checkfirst=True)
root = sql.scalar(select(NativeInvocationState))
request = sql.get(DifyBuilderExecutionRequest, owner.request_id)
scope = sql.get(NativeTestScope, owner.request_id)
assert root is not None
assert request is not None
assert scope is not None
sql.expunge(root)
make_transient(root)
state_table = NativeInvocationState.__table__
assert isinstance(state_table, Table)
sql.execute(state_table.delete())
request.state, request.native_run_id = "running", None
request.observations = [
{
"native_command_key": "start-key",
"body_digest": "a" * 64,
"receipt": _receipt("prepared")
.model_copy(update={"request_id": owner.request_id})
.model_dump(mode="json"),
}
]
scope.generation = 0
sql.add(
NativeTestInvocation(
tenant_id=owner.case.actor.tenant_id,
request_id=owner.request_id,
invocation_id="root",
active=True,
bindings={},
)
)
with owner.factory.begin() as sql:
request = sql.get(DifyBuilderExecutionRequest, owner.request_id)
scope = sql.get(NativeTestScope, owner.request_id)
invocation = sql.scalar(select(NativeTestInvocation))
assert request is not None
assert scope is not None
assert invocation is not None
if boundary == "ack_context":
sql.add(
NativePayloadObject(
id="context",
tenant_id=owner.case.actor.tenant_id,
request_id=owner.request_id,
invocation_id="root",
kind="context",
logical_key="context",
storage_key="context-storage",
payload_digest="a" * 64,
value_digest="b" * 64,
)
)
elif boundary == "launched":
request.observations = [{**request.observations[0], "admission_launched": True}]
elif boundary == "cancelled":
scope.cancelled = True
elif boundary == "expired":
scope.expires_at = datetime(2000, 1, 1, tzinfo=UTC)
elif boundary == "owner":
request.actor_id = "foreign"
elif boundary == "generation":
scope.generation = 1
elif boundary == "inactive":
invocation.active = False
elif boundary == "other_policy":
request.context_digest = "f" * 64
from services.dify_builder.native_testing.confirmed_agent_commands import ProfiledNativeTestCommands
commands = ProfiledNativeTestCommands(
sessions=owner.factory,
actor=owner.case.actor,
confirmed_factory=lambda: owner.commands,
legacy_factory=lambda: pytest.fail("unexpected legacy profile"),
)
reader = BuilderTestActions(owner.factory, lambda **_: commands)
service = DifyBuilderService(
owner.repo,
FakeSessionLock(),
lambda *_: pytest.fail("observer dispatched"),
get_app_revision_fn=lambda *_: "fixture-revision",
test_actions=reader,
)
if boundary != "startup":
assert not reader.observation_initializing(
actor=owner.case.actor, session_id=owner.session.id, test_input_id=owner.saved_id
)
from runtime_contracts.builder.execution import BuilderExecutionPolicyError
with pytest.raises(BuilderExecutionPolicyError):
owner.commands.api.get(actor=owner.case.actor, session_id=owner.session.id, request_id=owner.request_id)
if boundary != "owner":
subscription = _subscription(
monkeypatch, [json.dumps({"kind": "native_state_changed", "session_id": owner.session.id}).encode()]
)
frames = list(
wiring.stream_advance_frames(
{**_view(), "session_id": owner.session.id},
subscription,
True,
read_session_view=lambda: service._read_stream_session_view(owner.session.id, owner.case.actor),
)
)
assert [_decode(frame)["event"] for frame in frames] == ["command_started", "error"]
_assert_closed(subscription)
return
# Ordinary authenticated reads stay strict even during this startup window.
from runtime_contracts.builder.execution import BuilderExecutionPolicyError
with pytest.raises(BuilderExecutionPolicyError, match="native_state_unavailable"):
service.get_session_view(owner.session.id, owner.case.actor)
reads = 0
def read_view() -> dict[str, object] | None:
nonlocal reads
reads += 1
result = service._read_stream_session_view(owner.session.id, owner.case.actor)
if reads == 1:
assert result is None
with owner.factory.begin() as sql:
sql.add(root)
request = sql.get(DifyBuilderExecutionRequest, owner.request_id)
scope = sql.get(NativeTestScope, owner.request_id)
assert request is not None
assert scope is not None
request.state, request.native_run_id = "sealed", owner.native_id
scope.generation = 1
return result
notification = json.dumps({"kind": "native_state_changed", "session_id": owner.session.id}).encode()
subscription = _subscription(monkeypatch, [notification, notification])
frames = list(
wiring.stream_advance_frames(
{**_view(), "session_id": owner.session.id},
subscription,
True,
read_session_view=read_view,
command_id="original-command",
)
)
assert frames[1] == ": keep-alive\n\n"
events = [_decode(frame) for frame in frames if not frame.startswith(":")]
assert [event["event"] for event in events] == ["command_started", "command_finished"]
assert events[-1]["data"]["test_execution"]["request_id"] == owner.request_id
assert reads == 2
_assert_closed(subscription)
@@ -430,3 +430,40 @@ def test_observation_uses_original_command_only_for_task_stop(task_paused: bool,
assert event["data"]["command_id"] == ("command-1" if task_paused else "command-2")
assert "_task_paused" not in event["data"]
assert subscription.closed
@pytest.mark.parametrize("native_notification", [False, True])
def test_stream_defers_initializing_observation_until_real_view(native_notification: bool) -> None:
notification = json.dumps({"kind": "native_state_changed", "session_id": "s1"}).encode()
subscription = _FakeSubscription([notification if native_notification else None, notification])
views = iter([None, _view(run_status="waiting_input", version=2)])
frames = list(
wiring.stream_advance_frames(
_view(), subscription, True, read_session_view=lambda: next(views), command_id="original-command"
)
)
assert frames[1] == ": keep-alive\n\n"
events = [_event(frame) for frame in frames if not frame.startswith(":")]
assert [event["event"] for event in events] == ["command_started", "command_finished"]
assert events[-1]["data"]["version"] == 2
assert subscription.closed
@pytest.mark.parametrize("reason", ["native_state_unavailable", "native_owner_mismatch"])
def test_stream_surfaces_projection_policy_refusal_as_terminal_error(reason: str) -> None:
from runtime_contracts.builder.execution import BuilderExecutionPolicyError
subscription = _FakeSubscription([json.dumps({"kind": "native_state_changed", "session_id": "s1"}).encode()])
def read_view() -> dict[str, object]:
raise BuilderExecutionPolicyError(reason)
frames = list(
wiring.stream_advance_frames(
_view(), subscription, True, read_session_view=read_view, command_id="original-command"
)
)
events = [_event(frame) for frame in frames]
assert [event["event"] for event in events] == ["command_started", "error"]
assert events[-1]["data"]["code"] == reason
assert subscription.closed
@@ -127,6 +127,12 @@ class ActionCommands:
assert session_id
return self.receipt if test_input_id == "input-1" else None
def observation_initializing(self, *, actor: Actor, session_id: str, test_input_id: str) -> bool:
assert actor.account_id
assert session_id
assert test_input_id
return False
def current_diagnostics(
self, *, actor: Actor, session_id: str, test_input_id: str, receipt: NativeTestPublicReceipt
) -> list[dict[str, object]]: