cc45b5ff2c
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
130 lines
5.5 KiB
Gherkin
130 lines
5.5 KiB
Gherkin
Feature: Git worktree sandbox lifecycle
|
|
As a developer
|
|
I want a sandbox that isolates plan changes in a git worktree
|
|
So that the original repository is unmodified until changes are committed
|
|
|
|
Background:
|
|
Given a gwt test git repository is initialised
|
|
|
|
# --- Creation ---
|
|
|
|
Scenario: Create a git worktree sandbox
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
Then the gwt sandbox should be in the "created" state
|
|
And the gwt sandbox context should reference plan "plan-001"
|
|
And the gwt sandbox context should have strategy metadata "git_worktree"
|
|
And the gwt sandbox worktree path should exist
|
|
|
|
Scenario: Creating a sandbox with empty plan_id raises ValueError
|
|
When a gwt sandbox is created with empty plan_id
|
|
Then a gwt ValueError should be raised with message "plan_id cannot be empty"
|
|
|
|
Scenario: Creating a sandbox with empty resource_id raises ValueError
|
|
When a gwt sandbox is prepared with empty resource_id
|
|
Then a gwt ValueError should be raised with message "resource_id cannot be empty"
|
|
|
|
Scenario: Creating a sandbox with empty original_path raises ValueError
|
|
When a gwt sandbox is prepared with empty original_path
|
|
Then a gwt ValueError should be raised with message "original_path cannot be empty"
|
|
|
|
Scenario: Creating a sandbox with non-positive timeout raises ValueError
|
|
When a gwt sandbox is prepared with zero timeout
|
|
Then a gwt ValueError should be raised with message "git_timeout must be positive"
|
|
|
|
Scenario: Creating a sandbox on a non-git directory raises SandboxCreationError
|
|
Given a gwt non-git directory
|
|
When a gwt sandbox is created on the non-git directory for plan "plan-001"
|
|
Then a gwt SandboxCreationError should be raised
|
|
|
|
# --- Path resolution ---
|
|
|
|
Scenario: Resolve a path in the worktree
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
And the gwt path "src/main.py" is resolved
|
|
Then the gwt resolved path should be inside the worktree
|
|
And the gwt sandbox should be in the "active" state
|
|
|
|
Scenario: Path traversal is rejected
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
And the gwt path "../etc/passwd" is resolved
|
|
Then a gwt ValueError should be raised with message "Path traversal not allowed"
|
|
|
|
Scenario: Resolving a path on a cleaned-up sandbox raises SandboxStateError
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
And the gwt sandbox is cleaned up
|
|
And the gwt path "file.txt" is resolved on a cleaned-up sandbox
|
|
Then a gwt SandboxStateError should be raised
|
|
|
|
# --- Commit ---
|
|
|
|
Scenario: Commit with no changes produces empty result
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
And the gwt sandbox is committed with message "empty commit"
|
|
Then the gwt commit result should indicate success
|
|
And the gwt commit result should have 0 changed files
|
|
|
|
Scenario: Commit with changes merges back to original branch
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
And a gwt file "new_file.txt" is created in the worktree with content "hello"
|
|
And the gwt sandbox is committed with message "add new file"
|
|
Then the gwt commit result should indicate success
|
|
And the gwt commit result should have 1 added files
|
|
And the gwt file "new_file.txt" should exist in the original repo
|
|
|
|
Scenario: Commit with modified file reports changes
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
And the gwt existing file "README.md" is modified in the worktree
|
|
And the gwt sandbox is committed with message "modify readme"
|
|
Then the gwt commit result should indicate success
|
|
And the gwt commit result should have 1 changed files
|
|
|
|
Scenario: Commit on a cleaned-up sandbox raises SandboxStateError
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
And the gwt sandbox is cleaned up
|
|
And the gwt sandbox commit is attempted on cleaned-up sandbox
|
|
Then a gwt SandboxStateError should be raised
|
|
|
|
# --- Rollback ---
|
|
|
|
Scenario: Rollback discards worktree changes
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
And a gwt file "temp.txt" is created in the worktree with content "temporary"
|
|
And the gwt path "temp.txt" is resolved
|
|
And the gwt sandbox is rolled back
|
|
Then the gwt sandbox should be in the "rolled_back" state
|
|
And the gwt file "temp.txt" should not exist in the worktree
|
|
|
|
Scenario: Rollback on a non-active sandbox raises SandboxStateError
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
And the gwt sandbox rollback is attempted on created sandbox
|
|
Then a gwt SandboxStateError should be raised
|
|
|
|
# --- Cleanup ---
|
|
|
|
Scenario: Cleanup removes worktree and branch
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
And the gwt sandbox is cleaned up
|
|
Then the gwt sandbox should be in the "cleaned_up" state
|
|
And the gwt sandbox worktree path should not exist
|
|
And the gwt sandbox branch should not exist
|
|
|
|
Scenario: Cleanup is idempotent
|
|
When a gwt sandbox is created for plan "plan-001"
|
|
And the gwt sandbox is cleaned up
|
|
And the gwt sandbox is cleaned up again
|
|
Then the gwt sandbox should be in the "cleaned_up" state
|
|
|
|
# --- Branch sanitisation ---
|
|
|
|
Scenario: Branch name is sanitised from plan ID
|
|
When a gwt sandbox is created for plan "plan with spaces!@#"
|
|
Then the gwt sandbox branch name should be safe for git
|
|
|
|
# --- Protocol properties ---
|
|
|
|
Scenario: Sandbox has a unique ULID identifier
|
|
When a gwt sandbox is instantiated
|
|
Then the gwt sandbox_id should be a valid ULID
|
|
And the gwt sandbox status should be "pending"
|
|
And the gwt sandbox context should be None
|