Files
cleveragents-core/features/resource_handler_crud.feature
hamza.khyari 90e5bbb99c
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 17s
CI / lint (pull_request) Successful in 3m17s
CI / unit_tests (pull_request) Successful in 3m38s
CI / quality (pull_request) Successful in 3m42s
CI / typecheck (pull_request) Successful in 3m54s
CI / security (pull_request) Successful in 4m2s
CI / docker (pull_request) Successful in 50s
CI / e2e_tests (pull_request) Successful in 8m32s
CI / integration_tests (pull_request) Successful in 6m54s
CI / coverage (pull_request) Successful in 14m10s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (pull_request) Successful in 59m15s
feat(resource): implement ResourceHandler CRUD and discovery methods
Extend the ResourceHandler protocol with six content operations (read,
write, delete, list_children, diff, discover_children) and four frozen
dataclass result types (Content, WriteResult, DeleteResult, DiffResult).

Handler implementations:
- GitCheckoutHandler: read via git show (binary-safe), write/delete via
  filesystem ops, list via git ls-tree, diff via git diff --no-index
  with locale-safe shortstat parsing, discover via git ls-tree -d
- FsDirectoryHandler: full CRUD via pathlib/os/difflib/shutil
- DevcontainerHandler: read/write/discover via devcontainer exec
- CloudResourceHandler: NotImplementedError stubs for protocol compliance
- DatabaseResourceHandler: inherits base NotImplementedError stubs

Security:
- Path traversal guard (_safe_resolve) on all read/write/delete ops
  using os.sep-suffixed startswith check to prevent prefix collisions
- Empty-path deletion rejected with PermissionError

Tests:
- 22 Behave scenarios (115 steps): CRUD for FsDirectory and GitCheckout,
  path traversal rejection (3 scenarios), NotImplementedError defaults
- 2 Robot integration tests: read -> write -> diff cycle on real temp
  directories and git repos

ISSUES CLOSED: #827
2026-03-24 13:53:41 +00:00

182 lines
9.2 KiB
Gherkin

Feature: Resource handler CRUD and discovery operations
Tests for read, write, delete, list_children, diff, and discover_children
methods on GitCheckoutHandler, FsDirectoryHandler, and base handler
NotImplementedError defaults.
Issue #827: ResourceHandler CRUD and discovery methods.
# ============================================================
# FsDirectoryHandler CRUD
# ============================================================
Scenario: FsDirectory handler read returns file content
Given a temp directory with file "hello.txt" containing "Hello World"
And an fs-directory resource pointing to that directory
When I call read on the fs-directory handler with path "hello.txt"
Then the content data should be "Hello World"
And the content encoding should be "utf-8"
And the content hash should not be empty
Scenario: FsDirectory handler read of root returns directory listing
Given a temp directory with file "a.txt" containing "aaa"
And a temp sub-file "b.txt" containing "bbb"
And an fs-directory resource pointing to that directory
When I call read on the fs-directory handler for the root
Then the content text should contain "a.txt"
And the content text should contain "b.txt"
Scenario: FsDirectory handler read of missing path raises FileNotFoundError
Given a temp directory with file "only.txt" containing "data"
And an fs-directory resource pointing to that directory
When I call read on the fs-directory handler with path "missing.txt"
Then a crud FileNotFoundError should be raised
Scenario: FsDirectory handler write creates a new file
Given an empty temp directory
And an fs-directory resource pointing to that directory
When I call write on the fs-directory handler with path "new.txt" and data "New Content"
Then the write result should be successful
And the write result bytes_written should be 11
And the file "new.txt" should exist in the temp directory with content "New Content"
Scenario: FsDirectory handler write creates parent directories
Given an empty temp directory
And an fs-directory resource pointing to that directory
When I call write on the fs-directory handler with path "sub/dir/file.txt" and data "Nested"
Then the write result should be successful
And the file "sub/dir/file.txt" should exist in the temp directory with content "Nested"
Scenario: FsDirectory handler delete removes a file
Given a temp directory with file "doomed.txt" containing "bye"
And an fs-directory resource pointing to that directory
When I call delete on the fs-directory handler with path "doomed.txt"
Then the delete result should be successful
And the file "doomed.txt" should not exist in the temp directory
Scenario: FsDirectory handler delete of missing path raises FileNotFoundError
Given an empty temp directory
And an fs-directory resource pointing to that directory
When I call delete on the fs-directory handler with path "ghost.txt"
Then a crud FileNotFoundError should be raised
Scenario: FsDirectory handler list_children returns sorted entries
Given a temp directory with file "c.txt" containing "c"
And a temp sub-file "a.txt" containing "a"
And a temp sub-directory "subdir"
And an fs-directory resource pointing to that directory
When I call list_children on the fs-directory handler
Then the children list should equal ["a.txt", "c.txt", "subdir"]
Scenario: FsDirectory handler diff detects changes between directories
Given a temp directory with file "same.txt" containing "same"
And a temp sub-file "changed.txt" containing "original"
And an fs-directory resource pointing to that directory
And a second temp directory with file "same.txt" containing "same"
And a second temp sub-file "changed.txt" containing "modified"
When I call diff on the fs-directory handler against the second directory
Then the diff result should have changes
And the diff files_changed should be 1
And the diff insertions should be greater than 0
Scenario: FsDirectory handler diff detects no changes for identical directories
Given a temp directory with file "same.txt" containing "identical"
And an fs-directory resource pointing to that directory
And a second temp directory with file "same.txt" containing "identical"
When I call diff on the fs-directory handler against the second directory
Then the diff result should have no changes
Scenario: FsDirectory handler discover_children returns subdirectories
Given a temp directory with file "file.txt" containing "data"
And a temp sub-directory "alpha"
And a temp sub-directory "beta"
And an fs-directory resource pointing to that directory
When I call discover_children on the fs-directory handler
Then the discovered children should have 2 items
And the discovered children names should include "alpha"
And the discovered children names should include "beta"
# ============================================================
# GitCheckoutHandler CRUD
# ============================================================
Scenario: GitCheckout handler read returns tracked file content
Given a temp git repo with file "readme.md" containing "# Hello"
And a git-checkout resource pointing to that repo
When I call read on the git-checkout handler with path "readme.md"
Then the content data should be "# Hello"
And the content hash should not be empty
Scenario: GitCheckout handler write creates a new file in the repo
Given a temp git repo with file "initial.txt" containing "start"
And a git-checkout resource pointing to that repo
When I call write on the git-checkout handler with path "added.txt" and data "new file"
Then the write result should be successful
And the file "added.txt" should exist in the temp git repo with content "new file"
Scenario: GitCheckout handler delete removes a tracked file
Given a temp git repo with file "remove_me.txt" containing "deletable"
And a git-checkout resource pointing to that repo
When I call delete on the git-checkout handler with path "remove_me.txt"
Then the delete result should be successful
And the file "remove_me.txt" should not exist in the temp git repo
Scenario: GitCheckout handler list_children returns tracked entries
Given a temp git repo with file "a.py" containing "# a"
And a temp git sub-file "b.py" containing "# b"
And a git-checkout resource pointing to that repo
When I call list_children on the git-checkout handler
Then the children list should contain "a.py"
And the children list should contain "b.py"
Scenario: GitCheckout handler diff detects changes against another location
Given a temp git repo with file "code.py" containing "print('hello')"
And a git-checkout resource pointing to that repo
And a second temp directory with file "code.py" containing "print('world')"
When I call diff on the git-checkout handler against the second directory
Then the diff result should have changes
Scenario: GitCheckout handler discover_children returns top-level directories
Given a temp git repo with file "root.txt" containing "root"
And a temp git sub-directory "src" with file "main.py" containing "# main"
And a git-checkout resource pointing to that repo
When I call discover_children on the git-checkout handler
Then the discovered children names should include "src"
# ============================================================
# BaseResourceHandler NotImplementedError defaults
# ============================================================
Scenario: Database handler read raises NotImplementedError
Given a database resource handler
And a dummy database resource
When I call read on the database handler
Then a crud NotImplementedError should be raised with message containing "database"
Scenario: Database handler write raises NotImplementedError
Given a database resource handler
And a dummy database resource
When I call write on the database handler with path "table" and data "row"
Then a crud NotImplementedError should be raised with message containing "database"
# ============================================================
# Security: path traversal rejection
# ============================================================
Scenario: FsDirectory handler read rejects path traversal
Given a temp directory with file "safe.txt" containing "safe"
And an fs-directory resource pointing to that directory
When I call read on the fs-directory handler with path "../../etc/passwd"
Then a crud PermissionError should be raised
Scenario: FsDirectory handler write rejects path traversal
Given a temp directory with file "safe.txt" containing "safe"
And an fs-directory resource pointing to that directory
When I call write on the fs-directory handler with path "../../tmp/evil.txt" and data "pwned"
Then a crud PermissionError should be raised
Scenario: GitCheckout handler read rejects path traversal
Given a temp git repo with file "safe.txt" containing "safe"
And a git-checkout resource pointing to that repo
When I call read on the git-checkout handler with path "../../etc/passwd"
Then a crud PermissionError should be raised