Files
cleveragents-core/features/copy_on_write_sandbox.feature
T
khyari hamza cc45b5ff2c feat(sandbox): add git_worktree and copy_on_write sandbox strategies
Implement GitWorktreeSandbox (worktree creation, commit+merge, rollback,
cleanup, branch sanitization, git timeouts) and CopyOnWriteSandbox
(directory copy, diff-based commit, rollback, cleanup).

Update SandboxFactory to wire new strategies, remove stale overlay/
versioning constants, add snapshot placeholder, align resource type
mapping to spec types (git-checkout, fs-mount, fs-directory, fs-file).

Add 40 Behave scenarios (19 git_worktree + 21 copy_on_write) with gwt/cow
prefixed steps. Update existing sandbox_factory_coverage feature (21
scenarios) to reflect new factory behavior.

All quality gates pass: ruff, pyright, 2325 scenarios, 97% coverage.

TASK-006 / Stage B4
2026-02-14 04:01:20 +00:00

142 lines
6.2 KiB
Gherkin

Feature: Copy-on-write sandbox lifecycle
As a developer
I want a sandbox that isolates plan changes in a directory copy
So that the original directory is unmodified until changes are committed
Background:
Given a cow test directory is initialised
# --- Creation ---
Scenario: Create a copy-on-write sandbox
When a cow sandbox is created for plan "plan-001"
Then the cow sandbox should be in the "created" state
And the cow sandbox context should reference plan "plan-001"
And the cow sandbox context should have strategy metadata "copy_on_write"
And the cow sandbox path should exist
Scenario: Creating a sandbox with empty plan_id raises ValueError
When a cow sandbox is created with empty plan_id
Then a cow ValueError should be raised with message "plan_id cannot be empty"
Scenario: Creating a sandbox with empty resource_id raises ValueError
When a cow sandbox is prepared with empty resource_id
Then a cow ValueError should be raised with message "resource_id cannot be empty"
Scenario: Creating a sandbox with empty original_path raises ValueError
When a cow sandbox is prepared with empty original_path
Then a cow ValueError should be raised with message "original_path cannot be empty"
Scenario: Creating a sandbox on a non-existent directory raises SandboxCreationError
Given a cow non-existent directory
When a cow sandbox is created on the non-existent directory for plan "plan-001"
Then a cow SandboxCreationError should be raised
# --- Path resolution ---
Scenario: Resolve a path in the sandbox copy
When a cow sandbox is created for plan "plan-001"
And the cow path "data/file.txt" is resolved
Then the cow resolved path should be inside the sandbox copy
And the cow sandbox should be in the "active" state
Scenario: Path traversal is rejected
When a cow sandbox is created for plan "plan-001"
And the cow path "../etc/passwd" is resolved
Then a cow ValueError should be raised with message "Path traversal not allowed"
Scenario: Resolving a path on a cleaned-up sandbox raises SandboxStateError
When a cow sandbox is created for plan "plan-001"
And the cow sandbox is cleaned up
And the cow path "file.txt" is resolved on a cleaned-up sandbox
Then a cow SandboxStateError should be raised
# --- Commit ---
Scenario: Commit with no changes produces empty result
When a cow sandbox is created for plan "plan-001"
And the cow sandbox is committed
Then the cow commit result should indicate success
And the cow commit result should have 0 changed files
And the cow commit result should have 0 added files
And the cow commit result should have 0 deleted files
Scenario: Commit with a new file syncs it to original
When a cow sandbox is created for plan "plan-001"
And a cow file "new_file.txt" is created in the sandbox with content "hello world"
And the cow sandbox is committed
Then the cow commit result should indicate success
And the cow commit result should have 1 added files
And the cow file "new_file.txt" should exist in the original directory with content "hello world"
Scenario: Commit with a modified file syncs the change
When a cow sandbox is created for plan "plan-001"
And the cow existing file "existing.txt" is modified in the sandbox with content "updated"
And the cow sandbox is committed
Then the cow commit result should indicate success
And the cow commit result should have 1 changed files
And the cow file "existing.txt" in the original should have content "updated"
Scenario: Commit with a deleted file removes it from original
When a cow sandbox is created for plan "plan-001"
And the cow existing file "existing.txt" is deleted from the sandbox
And the cow sandbox is committed
Then the cow commit result should indicate success
And the cow commit result should have 1 deleted files
And the cow file "existing.txt" should not exist in the original directory
Scenario: Commit on a cleaned-up sandbox raises SandboxStateError
When a cow sandbox is created for plan "plan-001"
And the cow sandbox is cleaned up
And the cow sandbox commit is attempted on cleaned-up sandbox
Then a cow SandboxStateError should be raised
# --- Rollback ---
Scenario: Rollback restores the sandbox to original state
When a cow sandbox is created for plan "plan-001"
And a cow file "temp.txt" is created in the sandbox with content "temporary"
And the cow path "temp.txt" is resolved
And the cow sandbox is rolled back
Then the cow sandbox should be in the "rolled_back" state
And the cow file "temp.txt" should not exist in the sandbox
Scenario: Rollback on a non-active sandbox raises SandboxStateError
When a cow sandbox is created for plan "plan-001"
And the cow sandbox rollback is attempted on created sandbox
Then a cow SandboxStateError should be raised
# --- Cleanup ---
Scenario: Cleanup removes the sandbox directory
When a cow sandbox is created for plan "plan-001"
And the cow sandbox is cleaned up
Then the cow sandbox should be in the "cleaned_up" state
And the cow sandbox path should not exist
Scenario: Cleanup is idempotent
When a cow sandbox is created for plan "plan-001"
And the cow sandbox is cleaned up
And the cow sandbox is cleaned up again
Then the cow sandbox should be in the "cleaned_up" state
# --- Protocol properties ---
Scenario: Sandbox has a unique ULID identifier
When a cow sandbox is instantiated
Then the cow sandbox_id should be a valid ULID
And the cow sandbox status should be "pending"
And the cow sandbox context should be None
# --- Diff computation ---
Scenario: Diff detects added, modified, and deleted files
When a cow sandbox is created for plan "plan-001"
And a cow file "added.txt" is created in the sandbox with content "new"
And the cow existing file "existing.txt" is modified in the sandbox with content "changed"
And the cow existing file "to_delete.txt" is deleted from the sandbox
And the cow sandbox is committed
Then the cow commit result should have 1 added files
And the cow commit result should have 1 changed files
And the cow commit result should have 1 deleted files