493e5cf8a1
CI / benchmark-publish (pull_request) Has been skipped
CI / quality (pull_request) Successful in 20s
CI / lint (pull_request) Successful in 20s
CI / build (pull_request) Successful in 28s
CI / security (pull_request) Successful in 33s
CI / typecheck (pull_request) Successful in 34s
CI / integration_tests (pull_request) Successful in 3m38s
CI / benchmark-regression (pull_request) Successful in 26m8s
CI / unit_tests (pull_request) Successful in 29m12s
CI / docker (pull_request) Successful in 1m2s
CI / coverage (pull_request) Successful in 50m23s
- Add read_only kwarg to ExecuteStubActor.execute(), propagated to ChangeSetCapture; PlanExecutor._run_execute_with_stub passes plan.read_only through the execution path (P1 #2 fix) - Replace CLI fail-fast and Action-Skill stub scenarios with real ExecuteStubActor spy test and SkillContext.enforce_write_guard integration tests (P2 #1 fix) - Update docs: remove unimplemented Layer 5 (Action-Skill), add ExecuteStubActor wiring description, fix test command (P2 #2 fix) ISSUES CLOSED: #322
129 lines
6.7 KiB
Gherkin
129 lines
6.7 KiB
Gherkin
@unit
|
|
Feature: Read-only action enforcement
|
|
As a plan operator
|
|
I need the system to enforce read-only constraints at every layer
|
|
So that read-only plans never produce side-effects
|
|
|
|
Background:
|
|
Given the read-only enforcement modules are available
|
|
|
|
# ── ToolRuntime._enforce_capabilities ────────────────────────────────
|
|
|
|
Scenario: Read-only plan blocks a write-capable tool with tool name in error
|
|
Given a tool "builtin/file-write" with writes=True and read_only=False
|
|
And a tool execution context with plan_id "plan-ro-1" and read_only True
|
|
When I enforce capabilities on the tool
|
|
Then a ToolAccessDeniedError should be raised for the tool
|
|
And the access-denied message should contain "builtin/file-write"
|
|
And the access-denied message should contain "read-only"
|
|
|
|
Scenario: Read-only plan allows a read-only tool
|
|
Given a tool "builtin/search" with writes=False and read_only=True
|
|
And a tool execution context with plan_id "plan-ro-2" and read_only True
|
|
When I enforce capabilities on the tool
|
|
Then no enforcement error should be raised
|
|
|
|
Scenario: Non-read-only plan allows a write-capable tool
|
|
Given a tool "builtin/file-write" with writes=True and read_only=False
|
|
And a tool execution context with plan_id "plan-rw-1" and read_only False
|
|
When I enforce capabilities on the tool
|
|
Then no enforcement error should be raised
|
|
|
|
Scenario: Tool with writes=True is blocked even when cap.read_only is unset
|
|
Given a tool "builtin/hybrid-tool" with writes=True and read_only=False
|
|
And a tool execution context with plan_id "plan-ro-3" and read_only True
|
|
When I enforce capabilities on the tool
|
|
Then a ToolAccessDeniedError should be raised for the tool
|
|
And the access-denied message should contain "builtin/hybrid-tool"
|
|
|
|
Scenario: Tool with neither read_only nor writes passes on read-only plan
|
|
Given a tool "builtin/noop" with writes=False and read_only=False
|
|
And a tool execution context with plan_id "plan-ro-4" and read_only True
|
|
When I enforce capabilities on the tool
|
|
Then no enforcement error should be raised
|
|
|
|
# ── SkillContext.enforce_write_guard ──────────────────────────────────
|
|
|
|
Scenario: SkillContext enforce_write_guard blocks write tool with tool name
|
|
Given a read-only SkillContext for plan "plan-sk-1"
|
|
When I call enforce_write_guard with tool_name "skill/writer"
|
|
Then a SkillExecutionError should be raised for the guard
|
|
And the write-guard error message should contain "skill/writer"
|
|
And the write-guard error type should be PERMISSION_DENIED
|
|
|
|
Scenario: SkillContext enforce_write_guard allows on writable context
|
|
Given a writable SkillContext for plan "plan-sk-2"
|
|
When I call enforce_write_guard with tool_name "skill/writer"
|
|
Then no write-guard error should be raised
|
|
|
|
# ── ChangeSetCapture read-only enforcement ───────────────────────────
|
|
|
|
Scenario: ChangeSet builder rejects write entry when plan is read-only
|
|
Given a ChangeSetCapture with plan_id "plan-cs-1" and read_only True
|
|
When I try to wrap a write-capable tool spec
|
|
Then a ReadOnlyViolationError should be raised for the capture
|
|
And the capture error message should contain "read-only"
|
|
|
|
Scenario: ChangeSet builder allows wrapping when not read-only
|
|
Given a ChangeSetCapture with plan_id "plan-cs-2" and read_only False
|
|
When I try to wrap a write-capable tool spec
|
|
Then no capture error should be raised
|
|
|
|
Scenario: ChangeSet builder passes read-only tool through unchanged
|
|
Given a ChangeSetCapture with plan_id "plan-cs-3" and read_only True
|
|
When I wrap a read-only tool spec
|
|
Then the wrapped tool spec should be returned unchanged
|
|
|
|
# ── ExecuteStubActor read-only propagation ─────────────────────────────
|
|
|
|
Scenario: ExecuteStubActor propagates read_only to ChangeSetCapture
|
|
When I execute via ExecuteStubActor with read_only True
|
|
Then the stub actor should create a read-only ChangeSetCapture
|
|
|
|
Scenario: ExecuteStubActor allows writes when not read-only
|
|
When I execute via ExecuteStubActor with read_only False
|
|
Then the stub actor should create a writable ChangeSetCapture
|
|
|
|
# ── File write tool blocked ──────────────────────────────────────────
|
|
|
|
Scenario: File write tool blocked under read-only plan via ToolRuntime
|
|
Given a tool "builtin/file-write" with writes=True and read_only=False
|
|
And a tool execution context with plan_id "plan-fw-1" and read_only True
|
|
When I enforce capabilities on the tool
|
|
Then a ToolAccessDeniedError should be raised for the tool
|
|
And the access-denied message should contain "builtin/file-write"
|
|
|
|
# ── Git push tool blocked ────────────────────────────────────────────
|
|
|
|
Scenario: Git push tool blocked under read-only plan via ToolRuntime
|
|
Given a tool "git/push" with writes=True and read_only=False
|
|
And a tool execution context with plan_id "plan-gp-1" and read_only True
|
|
When I enforce capabilities on the tool
|
|
Then a ToolAccessDeniedError should be raised for the tool
|
|
And the access-denied message should contain "git/push"
|
|
|
|
# ── Read-only SkillContext blocks write tool ───────────────────────────
|
|
|
|
Scenario: Read-only SkillContext blocks write tool via enforce_write_guard
|
|
Given a read-only SkillContext for plan "plan-compat-1"
|
|
When I call enforce_write_guard with tool_name "test/write-tool"
|
|
Then a SkillExecutionError should be raised for the guard
|
|
And the write-guard error message should contain "test/write-tool"
|
|
|
|
Scenario: Writable SkillContext allows write tool
|
|
Given a writable SkillContext for plan "plan-compat-2"
|
|
When I call enforce_write_guard with tool_name "test/write-tool"
|
|
Then no write-guard error should be raised
|
|
|
|
# ── Plan -> ToolExecutionContext propagation ──────────────────────────
|
|
|
|
Scenario: ToolExecutionContext carries plan_read_only from plan
|
|
Given a Plan domain model with read_only=True and plan_id "plan-ex-1"
|
|
When I create a ToolExecutionContext from the plan
|
|
Then the propagated context plan_read_only should be True
|
|
|
|
Scenario: ToolExecutionContext writable for writable plan
|
|
Given a Plan domain model with read_only=False and plan_id "plan-ex-2"
|
|
When I create a ToolExecutionContext from the plan
|
|
Then the propagated context plan_read_only should be False
|