Skip to content

fix: GDPR purge gaps, utcnow deprecation, PDP enforcement module#29

Open
NellInc wants to merge 4 commits intomainfrom
fix/gdpr-purge-and-utcnow
Open

fix: GDPR purge gaps, utcnow deprecation, PDP enforcement module#29
NellInc wants to merge 4 commits intomainfrom
fix/gdpr-purge-and-utcnow

Conversation

@NellInc
Copy link
Copy Markdown
Contributor

@NellInc NellInc commented Apr 6, 2026

Summary

  • GDPR purge persistence gap closedpurge_by_session() now scrubs exported JSON files and propagates to registered external sinks (Redis, DB) via register_purge_handler(). Thread-safe with tombstone receipts for regulatory evidence.
  • datetime.utcnow() fully eliminated — all 14 instances across source and test files replaced with datetime.now(timezone.utc).
  • PDP enforcement module (vcp/enforcement.py) — standalone policy enforcement for VCP bundles. PDPPlugin interface, PDPEnforcer orchestrator, 3 built-in plugins (refusal boundary, adherence level, bundle expiry). No safety-stack dependency required.

Context

Follow-up to PR #23. The code review audit (2026-03-27) flagged persistence-layer gaps in the GDPR purge and the absence of PDP plugin enforcement in the SDK. Elena's PR addressed the in-memory tombstone and session_id_hash gating but left exported-file purge and external-sink propagation unhandled.

What changed

Area Files Lines
GDPR purge + handlers audit.py +120
PDP enforcement enforcement.py (new) +400
utcnow deprecation registry.py, 2 test files +14/-14
Exports + CHANGELOG __init__.py, CHANGELOG.md +30
Tests test_vcp_audit.py, test_vcp_enforcement.py (new) +320

Test plan

  • 64 tests pass (40 audit + 24 enforcement), 0 failures
  • ruff lint clean on all changed files
  • Thread-safety reviewed: file purge and path tracking inside self._lock
  • Adversarial code review performed — 3 HIGH (thread safety), 2 MEDIUM (escalation logging, adherence policy) all fixed
  • Purge handler tested: invocation, exception resilience, warning when log_callback set without handler

🤖 Generated with Claude Code

NellInc and others added 4 commits April 6, 2026 14:09
Closes persistence-layer gaps from PR #23 code review and adds the
PDP plugin enforcement that was flagged as unbuilt in the SDK.

GDPR/audit fixes:
- purge_by_session() now scrubs exported JSON files (not just in-memory)
- Tombstone receipt includes file_entries_removed and files_purged
- export_json() tracks paths for later purge propagation
- Tests cover file purge, missing file handling, path tracking

datetime.utcnow() deprecation:
- Fix last 2 instances in identity/registry.py (default_factory)
- All source files now use datetime.now(timezone.utc)

PDP enforcement module (vcp/enforcement.py):
- PDPPlugin abstract interface for enforcement plugins
- PDPEnforcer orchestrator with priority ordering and fail-closed
- RefusalBoundaryPlugin: bundle verification enforcement
- AdherenceLevelPlugin: minimum adherence level gating
- BundleExpiryPlugin: expired bundle blocking
- 23 tests covering all plugins and edge cases

Co-Authored-By: Claude <noreply@anthropic.com>
…, adherence policy

Thread safety (3 HIGH):
- Move _purge_exported_files() inside self._lock in purge_by_session()
- Protect export_json() path tracking with self._lock
- Prevents TOCTOU between concurrent export/purge and path list mutation

Enforcement module (2 MEDIUM):
- Log warning when ESCALATE is promoted to BLOCK (no escalation handler)
- Add require_declaration flag to AdherenceLevelPlugin so bundles
  without an adherence level can be blocked rather than silently allowed
- Remove redundant hasattr check in BundleExpiryPlugin

Co-Authored-By: Claude <noreply@anthropic.com>
Purge handler propagation (was: log_callback sinks undiscoverable):
- Add register_purge_handler() so external sinks (Redis, DB) register
  their own session-purge logic
- purge_by_session() calls all handlers, includes results in tombstone
- Warns if log_callback is set but no purge handler covers it
- 4 new tests: handler invocation, exception resilience, warning

Enforcement plugins_evaluated accuracy (was: counted registered, not run):
- Track actual evaluation count via loop counter

Co-Authored-By: Claude <noreply@anthropic.com>
- Replace 12 datetime.utcnow() in test_vcp_redis_state.py and test_vectors.py
- Fix ruff I001 import sorting in __init__.py
- Fix ruff UP015 unnecessary "r" mode in audit.py
- Wrap long lines in test_vcp_redis_state.py (E501)
- Add CHANGELOG entry for v4.1.0

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant