claude-dev-env 8.46.19 → 8.46.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -431,6 +431,26 @@ def _existing_scratchpad_root(
|
|
|
431
431
|
return None
|
|
432
432
|
|
|
433
433
|
|
|
434
|
+
def _is_at_or_under_payload_working_directory(file_path: str, hook_payload: dict) -> bool:
|
|
435
|
+
"""Return True when file_path's real path sits at or under the payload ``cwd``.
|
|
436
|
+
|
|
437
|
+
Args:
|
|
438
|
+
file_path: The path the write targets.
|
|
439
|
+
hook_payload: The PreToolUse payload that may carry ``cwd``.
|
|
440
|
+
|
|
441
|
+
Returns:
|
|
442
|
+
True when the payload names a working directory and file_path resolves
|
|
443
|
+
at or under its real path.
|
|
444
|
+
"""
|
|
445
|
+
working_directory = str(hook_payload.get("cwd") or "")
|
|
446
|
+
if not working_directory:
|
|
447
|
+
return False
|
|
448
|
+
return _is_at_or_under_root(
|
|
449
|
+
_normalized_absolute_comparison_path(os.path.realpath(file_path)),
|
|
450
|
+
_normalized_absolute_comparison_path(os.path.realpath(working_directory)),
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
|
|
434
454
|
def is_under_session_scratchpad(file_path: str, hook_payload: dict) -> bool:
|
|
435
455
|
"""Return True when file_path resolves under the harness session scratchpad.
|
|
436
456
|
|
|
@@ -460,13 +480,9 @@ def is_under_session_scratchpad(file_path: str, hook_payload: dict) -> bool:
|
|
|
460
480
|
session_id = _session_id_for_scratchpad(hook_payload)
|
|
461
481
|
if not session_id:
|
|
462
482
|
return False
|
|
463
|
-
|
|
464
|
-
working_directory = str(hook_payload.get("cwd") or "")
|
|
465
|
-
if working_directory and _is_at_or_under_root(
|
|
466
|
-
_normalized_absolute_comparison_path(real_target),
|
|
467
|
-
_normalized_absolute_comparison_path(os.path.realpath(working_directory)),
|
|
468
|
-
):
|
|
483
|
+
if _is_at_or_under_payload_working_directory(file_path, hook_payload):
|
|
469
484
|
return False
|
|
485
|
+
real_target = os.path.realpath(file_path)
|
|
470
486
|
real_temp_root = os.path.realpath(tempfile.gettempdir())
|
|
471
487
|
all_relative_parts = _relative_parts_under_temp_root(real_target, real_temp_root)
|
|
472
488
|
return (
|
|
@@ -482,10 +498,10 @@ def is_ephemeral_path(file_path: str, hook_payload: dict | None = None) -> bool:
|
|
|
482
498
|
scratch directories (``/tmp`` and ``$CLAUDE_JOB_DIR/tmp``), the harness
|
|
483
499
|
session scratchpad, and a coding agent's own home-directory tooling such as
|
|
484
500
|
``~/.grok/runs/``. A path inside the payload's own working directory
|
|
485
|
-
(``cwd``) is never treated as scratch, so a repository
|
|
486
|
-
``/tmp`` still receives full
|
|
487
|
-
|
|
488
|
-
variable. The code-rules and TDD gates call the underlying predicates
|
|
501
|
+
(``cwd``) is never treated as scratch or agent tooling, so a repository
|
|
502
|
+
checked out under ``/tmp`` or ``~/.grok/runs/`` still receives full
|
|
503
|
+
enforcement. The scratchpad match reads the session id from the payload
|
|
504
|
+
when supplied, else the harness environment variable. The code-rules and TDD gates call the underlying predicates
|
|
489
505
|
``is_ephemeral_script_path``, ``is_agent_home_tooling``, and
|
|
490
506
|
``is_under_session_scratchpad`` directly.
|
|
491
507
|
|
|
@@ -501,7 +517,9 @@ def is_ephemeral_path(file_path: str, hook_payload: dict | None = None) -> bool:
|
|
|
501
517
|
repository_root = str((hook_payload or {}).get("cwd") or "")
|
|
502
518
|
if is_ephemeral_script_path(file_path, repository_root):
|
|
503
519
|
return True
|
|
504
|
-
if is_agent_home_tooling(file_path)
|
|
520
|
+
if is_agent_home_tooling(file_path) and not _is_at_or_under_payload_working_directory(
|
|
521
|
+
file_path, hook_payload or {}
|
|
522
|
+
):
|
|
505
523
|
return True
|
|
506
524
|
return is_under_session_scratchpad(file_path, hook_payload or {})
|
|
507
525
|
|
|
@@ -357,3 +357,20 @@ def test_ephemeral_path_stays_true_for_scratchpad_file_outside_payload_cwd(
|
|
|
357
357
|
assert (
|
|
358
358
|
_SHARED_MODULE.is_ephemeral_path(str(throwaway_script), payload_with_worktree_cwd) is True
|
|
359
359
|
)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def test_ephemeral_path_is_false_for_file_under_payload_cwd_inside_agent_home() -> None:
|
|
363
|
+
checkout_directory = os.path.join("/home/example", ".grok", "runs", "checkout")
|
|
364
|
+
repository_module = os.path.join(checkout_directory, "src", "service.py")
|
|
365
|
+
|
|
366
|
+
assert (
|
|
367
|
+
_SHARED_MODULE.is_ephemeral_path(repository_module, {"cwd": checkout_directory})
|
|
368
|
+
is False
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def test_ephemeral_path_stays_true_for_agent_home_file_outside_payload_cwd() -> None:
|
|
373
|
+
checkout_directory = os.path.join("/home/example", ".grok", "runs", "checkout")
|
|
374
|
+
helper_script = os.path.join("/home/example", ".grok", "runs", "worktree-health", "health.py")
|
|
375
|
+
|
|
376
|
+
assert _SHARED_MODULE.is_ephemeral_path(helper_script, {"cwd": checkout_directory}) is True
|