claude-dev-env 8.8.0 → 8.9.0

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.
Files changed (36) hide show
  1. package/.agents/skills/privacy-hygiene/SKILL.md +1 -0
  2. package/.agents/skills/pull-request/scripts/pull_request.py +1 -0
  3. package/.agents/skills/pull-request/scripts/test_pull_request.py +2 -0
  4. package/docs/second-claude-account.md +8 -1
  5. package/hooks/hooks.json +25 -0
  6. package/hooks/hooks_constants/skill_loaded_reminder_constants.py +58 -0
  7. package/hooks/session/skill_loaded_reminder.py +199 -0
  8. package/hooks/session/test_skill_loaded_reminder.py +206 -0
  9. package/package.json +1 -1
  10. package/rules/durable-post-artifacts.md +26 -1
  11. package/rules/prefer-existing-tools.md +35 -0
  12. package/rules/review-closure-is-a-check.md +1 -1
  13. package/scripts/claude_account_choice.py +51 -6
  14. package/scripts/dev_env_scripts_constants/claude_account_constants.py +15 -0
  15. package/scripts/dev_env_scripts_constants/gh_artifact_upload_constants.py +27 -0
  16. package/scripts/dev_env_scripts_constants/private_term_constants.py +60 -0
  17. package/scripts/dev_env_scripts_constants/test_claude_account_constants.py +25 -0
  18. package/scripts/dev_env_scripts_constants/test_private_term_constants.py +29 -0
  19. package/scripts/durable_post_lint.py +47 -1
  20. package/scripts/durable_post_lint_config/config/constants.py +1 -0
  21. package/scripts/gh_artifact_upload.py +56 -3
  22. package/scripts/private_term_scan.py +135 -0
  23. package/scripts/private_terms.py +87 -0
  24. package/scripts/repository_checks/config/constants.py +3 -0
  25. package/scripts/repository_checks/runner.py +7 -0
  26. package/scripts/repository_checks/tracked_private_terms.py +57 -0
  27. package/scripts/test_claude_account_choice.py +28 -0
  28. package/scripts/test_durable_post_lint.py +90 -0
  29. package/scripts/tests/test_gh_artifact_upload.py +75 -0
  30. package/scripts/tests/test_match_exemptions.py +2 -2
  31. package/scripts/tests/test_private_term_scan.py +176 -0
  32. package/scripts/tests/test_private_terms.py +59 -0
  33. package/scripts/tests/test_repository_policy.py +2 -0
  34. package/scripts/tests/test_runner.py +20 -0
  35. package/scripts/tests/test_tracked_private_terms.py +71 -0
  36. package/scripts/tests/test_tracked_secrets.py +1 -1
@@ -20,6 +20,7 @@ from repository_checks.config.constants import (
20
20
  CHECK_ID_PACKAGE_INVENTORY,
21
21
  CHECK_ID_PYTEST_TESTPATHS,
22
22
  CHECK_ID_TRACKED_PERSONAL_DATA,
23
+ CHECK_ID_TRACKED_PRIVATE_TERMS,
23
24
  FOLLOWUP_LEDGER_MODULE_NAME,
24
25
  SUCCESS_EXIT_CODE,
25
26
  )
@@ -52,6 +53,7 @@ def test_should_keep_stable_check_identifiers() -> None:
52
53
  CHECK_ID_PACKAGE_INVENTORY,
53
54
  CHECK_ID_PYTEST_TESTPATHS,
54
55
  CHECK_ID_TRACKED_PERSONAL_DATA,
56
+ CHECK_ID_TRACKED_PRIVATE_TERMS,
55
57
  )
56
58
 
57
59
 
@@ -12,6 +12,7 @@ if str(_TESTS_DIRECTORY) not in sys.path:
12
12
  sys.path.insert(0, str(_TESTS_DIRECTORY))
13
13
 
14
14
  from repository_checks.config.constants import (
15
+ CHECK_ID_TRACKED_PRIVATE_TERMS,
15
16
  FAILED_CHECK_EXIT_CODE,
16
17
  FINDINGS_EXIT_CODE,
17
18
  )
@@ -57,3 +58,22 @@ def test_should_emit_stable_sorted_findings(tmp_path: Path) -> None:
57
58
  assert first_exit_code == FINDINGS_EXIT_CODE
58
59
  assert first_stdout == second_stdout
59
60
  assert first_stdout.index("alpha/CLAUDE.md") < first_stdout.index("zeta/CLAUDE.md")
61
+
62
+
63
+ def test_should_fail_closed_when_the_private_term_check_cannot_read_a_file(
64
+ tmp_path: Path, monkeypatch: pytest.MonkeyPatch
65
+ ) -> None:
66
+ repository_root = seed_clean_repository(tmp_path / "repo")
67
+
68
+ def fail_private_term_scan(
69
+ _repository_root: Path, _all_tracked_paths: object
70
+ ) -> list[object]:
71
+ raise OSError("tracked file unreadable")
72
+
73
+ monkeypatch.setattr(
74
+ "repository_checks.runner.collect_tracked_private_term_findings",
75
+ fail_private_term_scan,
76
+ )
77
+ exit_code, stdout_text, _stderr_text = run_policy(repository_root)
78
+ assert exit_code == FAILED_CHECK_EXIT_CODE
79
+ assert f"error: rule failed: {CHECK_ID_TRACKED_PRIVATE_TERMS}" in stdout_text
@@ -0,0 +1,71 @@
1
+ """Behavior tests for the tracked private-term check."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+ from dev_env_scripts_constants.private_term_constants import PrivateTermDigest
11
+ from repository_checks import tracked_private_terms
12
+ from repository_checks.config.constants import (
13
+ CHECK_ID_TRACKED_PRIVATE_TERMS,
14
+ FINDINGS_EXIT_CODE,
15
+ SUCCESS_EXIT_CODE,
16
+ )
17
+
18
+ _TESTS_DIRECTORY = Path(__file__).resolve().parent
19
+ if str(_TESTS_DIRECTORY) not in sys.path:
20
+ sys.path.insert(0, str(_TESTS_DIRECTORY))
21
+
22
+ from repository_policy_test_support import (
23
+ commit_tracked_files,
24
+ initialize_repository,
25
+ run_policy,
26
+ write_text,
27
+ )
28
+
29
+ _FIXTURE_TERM = "acmewidget"
30
+
31
+
32
+ @pytest.fixture(autouse=True)
33
+ def private_fixture_terms(monkeypatch: pytest.MonkeyPatch) -> None:
34
+ monkeypatch.setattr(
35
+ tracked_private_terms,
36
+ "ALL_PRIVATE_TERM_DIGESTS",
37
+ frozenset(
38
+ {
39
+ PrivateTermDigest(
40
+ length=len(_FIXTURE_TERM),
41
+ sha256=hashlib.sha256(_FIXTURE_TERM.encode("utf-8")).hexdigest(),
42
+ )
43
+ }
44
+ ),
45
+ )
46
+
47
+
48
+ def test_should_flag_a_tracked_file_naming_a_private_organization(
49
+ tmp_path: Path,
50
+ ) -> None:
51
+ repository_root = tmp_path / "repo"
52
+ initialize_repository(repository_root)
53
+ write_text(repository_root / "docs" / "notes.md", "intro\nBuilt by Acme Widgets.\n")
54
+ commit_tracked_files(repository_root)
55
+ exit_code, stdout_text, _stderr_text = run_policy(repository_root)
56
+ assert exit_code == FINDINGS_EXIT_CODE
57
+ assert f"{CHECK_ID_TRACKED_PRIVATE_TERMS}: docs/notes.md:" in stdout_text
58
+ assert "Line 2" in stdout_text
59
+ assert "Acme" not in stdout_text
60
+
61
+
62
+ def test_should_pass_a_tree_that_names_no_private_organization(
63
+ tmp_path: Path,
64
+ ) -> None:
65
+ repository_root = tmp_path / "repo"
66
+ initialize_repository(repository_root)
67
+ write_text(repository_root / "docs" / "notes.md", "An acme of widget design.\n")
68
+ commit_tracked_files(repository_root)
69
+ exit_code, stdout_text, _stderr_text = run_policy(repository_root)
70
+ assert exit_code == SUCCESS_EXIT_CODE
71
+ assert stdout_text == ""
@@ -46,7 +46,7 @@ _PII_PREVENTION_CONSTANTS = load_hooks_module(
46
46
  _PII_CATEGORY_EMAIL = _PII_PREVENTION_CONSTANTS.CATEGORY_EMAIL
47
47
  _PII_CATEGORY_HOME_PATH = _PII_PREVENTION_CONSTANTS.CATEGORY_HOME_PATH
48
48
  _PII_CATEGORY_PRIVATE_IP = _PII_PREVENTION_CONSTANTS.CATEGORY_PRIVATE_IP
49
- _OWNED_ADDRESS = "10.83.21.14"
49
+ _OWNED_ADDRESS = "10.0.0.14"
50
50
  _OWNED_ADDRESS_RELATIVE_PATH = "src/runner.py"
51
51
 
52
52