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.
- package/.agents/skills/privacy-hygiene/SKILL.md +1 -0
- package/.agents/skills/pull-request/scripts/pull_request.py +1 -0
- package/.agents/skills/pull-request/scripts/test_pull_request.py +2 -0
- package/docs/second-claude-account.md +8 -1
- package/hooks/hooks.json +25 -0
- package/hooks/hooks_constants/skill_loaded_reminder_constants.py +58 -0
- package/hooks/session/skill_loaded_reminder.py +199 -0
- package/hooks/session/test_skill_loaded_reminder.py +206 -0
- package/package.json +1 -1
- package/rules/durable-post-artifacts.md +26 -1
- package/rules/prefer-existing-tools.md +35 -0
- package/rules/review-closure-is-a-check.md +1 -1
- package/scripts/claude_account_choice.py +51 -6
- package/scripts/dev_env_scripts_constants/claude_account_constants.py +15 -0
- package/scripts/dev_env_scripts_constants/gh_artifact_upload_constants.py +27 -0
- package/scripts/dev_env_scripts_constants/private_term_constants.py +60 -0
- package/scripts/dev_env_scripts_constants/test_claude_account_constants.py +25 -0
- package/scripts/dev_env_scripts_constants/test_private_term_constants.py +29 -0
- package/scripts/durable_post_lint.py +47 -1
- package/scripts/durable_post_lint_config/config/constants.py +1 -0
- package/scripts/gh_artifact_upload.py +56 -3
- package/scripts/private_term_scan.py +135 -0
- package/scripts/private_terms.py +87 -0
- package/scripts/repository_checks/config/constants.py +3 -0
- package/scripts/repository_checks/runner.py +7 -0
- package/scripts/repository_checks/tracked_private_terms.py +57 -0
- package/scripts/test_claude_account_choice.py +28 -0
- package/scripts/test_durable_post_lint.py +90 -0
- package/scripts/tests/test_gh_artifact_upload.py +75 -0
- package/scripts/tests/test_match_exemptions.py +2 -2
- package/scripts/tests/test_private_term_scan.py +176 -0
- package/scripts/tests/test_private_terms.py +59 -0
- package/scripts/tests/test_repository_policy.py +2 -0
- package/scripts/tests/test_runner.py +20 -0
- package/scripts/tests/test_tracked_private_terms.py +71 -0
- 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.
|
|
49
|
+
_OWNED_ADDRESS = "10.0.0.14"
|
|
50
50
|
_OWNED_ADDRESS_RELATIVE_PATH = "src/runner.py"
|
|
51
51
|
|
|
52
52
|
|