feat(resource): implement ResourceHandler content_hash method #1066

Merged
hamza.khyari merged 1 commits from feature/resource-handler-content-hash into master 2026-04-01 13:41:52 +00:00
Member

Summary

Implements content_hash(resource, *, algorithm='sha256') -> str on the ResourceHandler protocol and all 4 concrete handlers plus the _DefaultHandler fallback.

Closes #837

Changes

Protocol (protocol.py)

New content_hash method added to ResourceHandler protocol.

Implementations

Handler Strategy Hash Source
BaseResourceHandler Default File content or directory entry names
GitCheckoutHandler git rev-parse HEAD Commit SHA re-hashed through algorithm
FsDirectoryHandler Recursive walk Sorted relative paths + file contents
DevcontainerHandler Config file .devcontainer/devcontainer.json
DatabaseResourceHandler Connection identity SQLite: file content; Remote: connection string
_DefaultHandler Delegates Uses BaseResourceHandler logic

Sentinel Value

EMPTY_CONTENT_HASH = SHA-256 of empty input. Returned for missing, empty, or inaccessible resources.

Algorithm Support

Configurable via algorithm parameter (default sha256). Accepts any hashlib.new()-compatible name.

Tests

10 Behave scenarios: sentinel hash, determinism, change detection, fs-directory recursive hash, git-checkout hash, configurable algorithm, protocol compliance.

Design Decisions

  • Content-only: Timestamps, permissions, and other metadata do not affect the hash
  • Deterministic: Same content always produces the same hash regardless of platform
  • Git handler: Uses commit SHA (not tree hash) because it captures the full state including history
  • Sentinel: SHA-256 of empty input is a natural choice (idempotent, well-known)
## Summary Implements `content_hash(resource, *, algorithm='sha256') -> str` on the `ResourceHandler` protocol and all 4 concrete handlers plus the `_DefaultHandler` fallback. Closes #837 ## Changes ### Protocol (`protocol.py`) New `content_hash` method added to `ResourceHandler` protocol. ### Implementations | Handler | Strategy | Hash Source | |---------|----------|-------------| | `BaseResourceHandler` | Default | File content or directory entry names | | `GitCheckoutHandler` | git rev-parse HEAD | Commit SHA re-hashed through algorithm | | `FsDirectoryHandler` | Recursive walk | Sorted relative paths + file contents | | `DevcontainerHandler` | Config file | `.devcontainer/devcontainer.json` | | `DatabaseResourceHandler` | Connection identity | SQLite: file content; Remote: connection string | | `_DefaultHandler` | Delegates | Uses BaseResourceHandler logic | ### Sentinel Value `EMPTY_CONTENT_HASH` = SHA-256 of empty input. Returned for missing, empty, or inaccessible resources. ### Algorithm Support Configurable via `algorithm` parameter (default `sha256`). Accepts any `hashlib.new()`-compatible name. ## Tests 10 Behave scenarios: sentinel hash, determinism, change detection, fs-directory recursive hash, git-checkout hash, configurable algorithm, protocol compliance. ## Design Decisions - **Content-only**: Timestamps, permissions, and other metadata do not affect the hash - **Deterministic**: Same content always produces the same hash regardless of platform - **Git handler**: Uses commit SHA (not tree hash) because it captures the full state including history - **Sentinel**: SHA-256 of empty input is a natural choice (idempotent, well-known)
freemo requested review from freemo 2026-03-19 05:21:34 +00:00
freemo requested review from brent.edwards 2026-03-19 05:21:34 +00:00
freemo added this to the v3.6.0 milestone 2026-03-19 05:28:02 +00:00
hamza.khyari self-assigned this 2026-03-19 12:55:01 +00:00
Owner

Planning review (Day 42):

  • Incorrect label: This PR is labeled bug but the title and body describe a new feature implementation (content_hash method). Should be Type/Feature per CONTRIBUTING.md conventions.

Otherwise looks good: milestone set (v3.6.0), closes #837, 2 reviewers assigned (freemo + brent.edwards).

**Planning review (Day 42):** - **Incorrect label**: This PR is labeled `bug` but the title and body describe a new feature implementation (`content_hash` method). Should be `Type/Feature` per CONTRIBUTING.md conventions. Otherwise looks good: milestone set (v3.6.0), closes #837, 2 reviewers assigned (freemo + brent.edwards).
freemo added the
Priority
Medium
State
In Review
Type
Feature
labels 2026-03-23 03:33:51 +00:00
freemo approved these changes 2026-03-27 17:12:56 +00:00
Dismissed
freemo left a comment
Owner

Review: feat(resource): implement ResourceHandler content_hash method

Approved. Solid implementation with good test coverage.

Minor Suggestions

  • Base handler shallow dir hash: BaseResourceHandler.content_hash() only hashes sorted(os.listdir(path)) entry names, not content. All concrete handlers override this, but consider a more prominent warning in the docstring.
  • Private attribute mutation: _DefaultHandler.content_hash() creates a BaseResourceHandler() and mutates _default_strategy and _type_label — consider a factory method instead.
  • .gitignore exclusion: FsDirectoryHandler recursive walk hashes everything including .git/ directories. Consider excluding .git/ by default.

What's Good

  • Deterministic hashing per handler type: file content for fs, git rev-parse HEAD for git, devcontainer.json for devcontainer, connection-string for database.
  • Well-known sentinel EMPTY_CONTENT_HASH.
  • Chunked 64KB reads avoiding memory blowouts.
  • Configurable algorithm parameter.
  • 12 BDD scenarios covering sentinels, determinism, change detection, algorithm variation, and protocol compliance.
## Review: feat(resource): implement ResourceHandler content_hash method **Approved.** Solid implementation with good test coverage. ### Minor Suggestions - **Base handler shallow dir hash**: `BaseResourceHandler.content_hash()` only hashes `sorted(os.listdir(path))` entry names, not content. All concrete handlers override this, but consider a more prominent warning in the docstring. - **Private attribute mutation**: `_DefaultHandler.content_hash()` creates a `BaseResourceHandler()` and mutates `_default_strategy` and `_type_label` — consider a factory method instead. - **`.gitignore` exclusion**: `FsDirectoryHandler` recursive walk hashes everything including `.git/` directories. Consider excluding `.git/` by default. ### What's Good - Deterministic hashing per handler type: file content for fs, `git rev-parse HEAD` for git, devcontainer.json for devcontainer, connection-string for database. - Well-known sentinel `EMPTY_CONTENT_HASH`. - Chunked 64KB reads avoiding memory blowouts. - Configurable `algorithm` parameter. - 12 BDD scenarios covering sentinels, determinism, change detection, algorithm variation, and protocol compliance.
hamza.khyari force-pushed feature/resource-handler-content-hash from faba9a3ff3 to bb73838d93 2026-03-31 11:27:48 +00:00 Compare
hamza.khyari dismissed freemo's review 2026-03-31 11:27:48 +00:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

hamza.khyari force-pushed feature/resource-handler-content-hash from bb73838d93 to 88334bfd33 2026-03-31 11:49:54 +00:00 Compare
hamza.khyari force-pushed feature/resource-handler-content-hash from 88334bfd33 to 3d7d32f671 2026-03-31 12:01:28 +00:00 Compare
hamza.khyari force-pushed feature/resource-handler-content-hash from 3d7d32f671 to ec249298fd 2026-03-31 12:19:03 +00:00 Compare
hamza.khyari force-pushed feature/resource-handler-content-hash from ec249298fd to f2bf356fbc 2026-03-31 14:12:59 +00:00 Compare
hamza.khyari force-pushed feature/resource-handler-content-hash from f2bf356fbc to a7e0c4094a 2026-03-31 14:19:04 +00:00 Compare
hamza.khyari force-pushed feature/resource-handler-content-hash from a7e0c4094a to fc8b943db7 2026-03-31 14:49:15 +00:00 Compare
hamza.khyari force-pushed feature/resource-handler-content-hash from fc8b943db7 to 027cee36ad 2026-03-31 15:22:21 +00:00 Compare
hamza.khyari force-pushed feature/resource-handler-content-hash from 027cee36ad to f57851c0ff 2026-03-31 15:42:28 +00:00 Compare
hamza.khyari force-pushed feature/resource-handler-content-hash from f57851c0ff to 56382af264 2026-04-01 12:34:34 +00:00 Compare
hamza.khyari force-pushed feature/resource-handler-content-hash from 56382af264 to 9e108eda1d 2026-04-01 13:01:19 +00:00 Compare
hamza.khyari force-pushed feature/resource-handler-content-hash from 9e108eda1d to 18b9d61e35 2026-04-01 13:02:48 +00:00 Compare
hamza.khyari scheduled this pull request to auto merge when all checks succeed 2026-04-01 13:40:02 +00:00
hamza.khyari merged commit 49058c3a72 into master 2026-04-01 13:41:52 +00:00
hamza.khyari deleted branch feature/resource-handler-content-hash 2026-04-01 13:41:59 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: cleveragents/cleveragents-core#1066