claude-dev-env 7.5.0 → 7.6.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/everything-search/scripts/everything_search.py +11 -0
- package/.agents/skills/everything-search/scripts/test_everything_search.py +1 -0
- package/.agents/skills/fresh-branch/SKILL.md +1 -0
- package/.agents/skills/fresh-branch/scripts/fresh_branch_git_commands.py +3 -0
- package/.agents/skills/fresh-branch/scripts/subprocess_window_access.py +43 -0
- package/.agents/skills/syncing-submodules/SKILL.md +1 -0
- package/.agents/skills/syncing-submodules/scripts/submodule_sync.py +4 -0
- package/.agents/skills/syncing-submodules/scripts/subprocess_window_access.py +43 -0
- package/.agents/skills/test-runner/SKILL.md +1 -0
- package/.agents/skills/test-runner/scripts/preflight_checks.py +5 -0
- package/.agents/skills/test-runner/scripts/run_tests.py +11 -0
- package/.agents/skills/test-runner/scripts/subprocess_window_access.py +43 -0
- package/.agents/skills/test-runner/scripts/test_run_tests.py +9 -7
- package/_shared/pr-loop/scripts/check_bugbot_ci.py +3 -0
- package/_shared/pr-loop/scripts/check_convergence_gates.py +3 -0
- package/_shared/pr-loop/scripts/check_pending_reviews.py +3 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/added_line_maps.py +3 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/baseline_import_isolation.py +3 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +5 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_file_sets.py +4 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_regression.py +3 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +3 -0
- package/_shared/pr-loop/scripts/codex_usage_probe.py +3 -0
- package/_shared/pr-loop/scripts/copilot_quota.py +3 -0
- package/_shared/pr-loop/scripts/fetch_copilot_reviews.py +3 -0
- package/_shared/pr-loop/scripts/fix_hookspath.py +7 -0
- package/_shared/pr-loop/scripts/post_fix_reply.py +4 -0
- package/_shared/pr-loop/scripts/preflight.py +7 -0
- package/_shared/pr-loop/scripts/preflight_self_heal.py +5 -0
- package/_shared/pr-loop/scripts/run_codex_review.py +3 -0
- package/_shared/pr-loop/scripts/subprocess_window_access.py +41 -0
- package/_shared/pr-loop/scripts/terminology_sweep.py +5 -0
- package/_shared/process-tree/scripts/process_tree_kill.py +3 -0
- package/_shared/process-tree/scripts/subprocess_window_access.py +41 -0
- package/bin/install-constants.mjs +4 -2
- package/bin/install.cursor-rules.test.mjs +57 -15
- package/bin/install.mjs +10 -15
- package/bin/pstack-model-preferences.claude.json +23 -0
- package/hooks/advisory/pr_done_reminder.py +7 -0
- package/hooks/advisory/refactor_guard.py +8 -0
- package/hooks/advisory/test_pr_done_reminder.py +21 -0
- package/hooks/advisory/test_refactor_guard.py +40 -0
- package/hooks/blocking/block_main_commit.py +4 -0
- package/hooks/blocking/code_rules_comments.py +39 -5
- package/hooks/blocking/pii_prevention_blocker_parts/repository_exemption.py +3 -0
- package/hooks/blocking/precommit_code_rules_gate.py +3 -0
- package/hooks/blocking/tdd_enforcer_parts/content_analysis.py +19 -3
- package/hooks/blocking/tdd_enforcer_parts/git_tracking.py +4 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_content_analysis.py +25 -0
- package/hooks/blocking/test_code_rules_enforcer_comment_string_awareness.py +27 -0
- package/hooks/blocking/test_code_rules_enforcer_exempt_marker_chained.py +10 -0
- package/hooks/git-hooks/git_hooks_constants/verification_notice_constants.py +0 -2
- package/hooks/git-hooks/pull_request_handoff.py +3 -0
- package/hooks/git-hooks/subprocess_window_access.py +41 -0
- package/hooks/git-hooks/test_verification_start.py +4 -0
- package/hooks/git-hooks/verification_notice_context.py +3 -0
- package/hooks/git-hooks/verification_start.py +7 -8
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +2 -0
- package/hooks/hooks_constants/subprocess_window.py +141 -0
- package/hooks/hooks_constants/subprocess_window_constants.py +9 -0
- package/hooks/hooks_constants/test_code_rules_enforcer_constants.py +6 -0
- package/hooks/hooks_constants/test_subprocess_window.py +128 -0
- package/hooks/lifecycle/enter_worktree_origin_prefetch.py +3 -0
- package/hooks/validation/mypy_validator.py +4 -0
- package/hooks/validators/README.md +1 -0
- package/hooks/validators/git_checks.py +4 -0
- package/hooks/validators/health_check.py +3 -0
- package/hooks/validators/hook_timing_harness.py +3 -0
- package/hooks/validators/mypy_integration.py +4 -0
- package/hooks/validators/ruff_integration.py +6 -0
- package/hooks/validators/run_all_validators.py +7 -0
- package/hooks/validators/subprocess_window_access.py +41 -0
- package/hooks/workflow/auto_formatter.py +8 -0
- package/hooks/workflow/test_auto_formatter.py +39 -0
- package/package.json +1 -1
- package/rules/pstack-models.md +4 -3
- package/scripts/automatic_advisory/checkout.py +8 -1
- package/scripts/automatic_advisory/cli.py +9 -3
- package/scripts/automatic_advisory/config/constants.py +0 -2
- package/scripts/automatic_advisory/execution.py +7 -1
- package/scripts/automatic_advisory/git.py +9 -1
- package/scripts/automatic_advisory/process_host.py +3 -0
- package/scripts/claude_chain_runner.py +3 -0
- package/scripts/gh_artifact_upload.py +3 -0
- package/scripts/grok_headless_runner.py +3 -0
- package/scripts/grok_patch_artifacts.py +4 -0
- package/scripts/grok_worker_preflight.py +3 -0
- package/scripts/invoke_code_review.py +3 -0
- package/scripts/local_verification/command_runner.py +3 -0
- package/scripts/local_verification/git_state.py +3 -0
- package/scripts/policy_lint/adapter_detectors.py +48 -2
- package/scripts/policy_lint/adapter_pairing.py +150 -2
- package/scripts/policy_lint/adapters.py +46 -4
- package/scripts/policy_lint/config/approved_test_pairs.py +25 -9
- package/scripts/policy_lint/config/constants.py +3 -0
- package/scripts/policy_lint/registry.py +1 -1
- package/scripts/policy_lint/selection_git.py +11 -0
- package/scripts/repository_checks/config/constants.py +5 -0
- package/scripts/repository_checks/config/policy_document.py +19 -0
- package/scripts/repository_checks/email_exemptions.py +14 -71
- package/scripts/repository_checks/path_exemptions.py +35 -0
- package/scripts/repository_checks/policy_document.py +120 -0
- package/scripts/repository_checks/tracked_secrets.py +27 -4
- package/scripts/setup_project_paths.py +3 -0
- package/scripts/spawn_grok_batch.py +3 -0
- package/scripts/subprocess_window_access.py +41 -0
- package/scripts/test_dispatcher_profile_import.py +4 -0
- package/scripts/tests/test_automatic_advisory_window_flags.py +17 -11
- package/scripts/tests/test_email_exemptions.py +37 -0
- package/scripts/tests/test_path_exemptions.py +164 -0
- package/scripts/tests/test_policy_document.py +104 -0
- package/scripts/tests/test_policy_lint_rules_function_length_scope.py +101 -0
- package/scripts/tests/test_policy_lint_rules_pairing.py +375 -0
- package/scripts/tests/test_policy_lint_rules_registry.py +116 -0
- package/scripts/tests/test_policy_lint_selection.py +34 -0
- package/scripts/tests/test_subprocess_window_access.py +118 -0
- package/scripts/tests/test_tracked_secrets.py +79 -0
- package/scripts/validate_instruction_pairs.py +3 -0
- package/scripts/verify_installable_package.py +5 -0
- package/scripts/automatic_advisory/window_flags.py +0 -41
- package/scripts/repository_checks/config/email_exemptions.py +0 -10
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import hashlib
|
|
6
|
+
import json
|
|
6
7
|
import sys
|
|
8
|
+
from collections.abc import Callable
|
|
7
9
|
from pathlib import Path
|
|
8
10
|
|
|
9
11
|
import pytest
|
|
@@ -12,6 +14,7 @@ from repository_checks.config.constants import (
|
|
|
12
14
|
CHECK_ID_TRACKED_PERSONAL_DATA,
|
|
13
15
|
FAILED_CHECK_EXIT_CODE,
|
|
14
16
|
FINDINGS_EXIT_CODE,
|
|
17
|
+
SUCCESS_EXIT_CODE,
|
|
15
18
|
)
|
|
16
19
|
from repository_checks.hook_modules import load_hooks_module
|
|
17
20
|
from repository_checks.tracked_secrets import collect_tracked_secret_findings
|
|
@@ -35,6 +38,8 @@ _OTHER_FIXTURE_EMAIL = "other-owner@company.io"
|
|
|
35
38
|
_OTHER_FIXTURE_HOME_PATH = "C:/Users/realname/notes.txt"
|
|
36
39
|
_FIXTURE_NOTES_RELATIVE_PATH = "src/notes.py"
|
|
37
40
|
_OTHER_NOTES_RELATIVE_PATH = "src/other_notes.py"
|
|
41
|
+
_FROZEN_RELATIVE_PATH = "evidence/manifest.json"
|
|
42
|
+
_STALE_DIGEST = hashlib.sha256(b"different bytes").hexdigest()
|
|
38
43
|
_PII_PREVENTION_CONSTANTS = load_hooks_module(
|
|
39
44
|
"hooks_constants.pii_prevention_constants"
|
|
40
45
|
)
|
|
@@ -151,6 +156,80 @@ def test_should_keep_owned_checker_modules_free_of_tracked_secret_findings() ->
|
|
|
151
156
|
assert collect_tracked_secret_findings(_REPOSITORY_ROOT, all_relative_paths) == []
|
|
152
157
|
|
|
153
158
|
|
|
159
|
+
def test_should_skip_every_category_in_a_frozen_file_whose_digest_matches(
|
|
160
|
+
tmp_path: Path,
|
|
161
|
+
) -> None:
|
|
162
|
+
"""One recorded digest silences the whole file, not one matched value."""
|
|
163
|
+
repository_root = tmp_path / "repo"
|
|
164
|
+
initialize_repository(repository_root)
|
|
165
|
+
_write_frozen_path_exemption_fixture(repository_root, _matching_digest)
|
|
166
|
+
commit_tracked_files(repository_root)
|
|
167
|
+
exit_code, stdout_text, _stderr_text = run_policy(repository_root)
|
|
168
|
+
assert exit_code == SUCCESS_EXIT_CODE
|
|
169
|
+
assert _pii_categories_for_path(stdout_text, _FROZEN_RELATIVE_PATH) == []
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def test_should_keep_reporting_a_frozen_file_whose_digest_is_stale(
|
|
173
|
+
tmp_path: Path,
|
|
174
|
+
) -> None:
|
|
175
|
+
repository_root = tmp_path / "repo"
|
|
176
|
+
initialize_repository(repository_root)
|
|
177
|
+
_write_frozen_path_exemption_fixture(repository_root, _stale_digest)
|
|
178
|
+
commit_tracked_files(repository_root)
|
|
179
|
+
exit_code, stdout_text, _stderr_text = run_policy(repository_root)
|
|
180
|
+
assert exit_code == FINDINGS_EXIT_CODE
|
|
181
|
+
assert _pii_categories_for_path(stdout_text, _FROZEN_RELATIVE_PATH) == [
|
|
182
|
+
_PII_CATEGORY_HOME_PATH,
|
|
183
|
+
_PII_PREVENTION_CONSTANTS.CATEGORY_SECRET,
|
|
184
|
+
]
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def test_should_exempt_a_frozen_file_named_by_a_windows_tracked_path(
|
|
188
|
+
tmp_path: Path,
|
|
189
|
+
) -> None:
|
|
190
|
+
"""Git on Windows can hand back backslashes, and the entry records slashes."""
|
|
191
|
+
repository_root = tmp_path / "repo"
|
|
192
|
+
repository_root.mkdir()
|
|
193
|
+
_write_frozen_path_exemption_fixture(repository_root, _matching_digest)
|
|
194
|
+
windows_tracked_path = _FROZEN_RELATIVE_PATH.replace("/", "\\")
|
|
195
|
+
assert (
|
|
196
|
+
collect_tracked_secret_findings(repository_root, [windows_tracked_path]) == []
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _write_frozen_path_exemption_fixture(
|
|
201
|
+
repository_root: Path, choose_digest: Callable[[Path], str]
|
|
202
|
+
) -> None:
|
|
203
|
+
frozen_path = repository_root / _FROZEN_RELATIVE_PATH
|
|
204
|
+
write_text(
|
|
205
|
+
frozen_path,
|
|
206
|
+
f"home = '{_OTHER_FIXTURE_HOME_PATH}'\ntoken = '{_SYNTHETIC_GITHUB_TOKEN}'\n",
|
|
207
|
+
)
|
|
208
|
+
write_text(
|
|
209
|
+
repository_root / "config" / "repository-policy.json",
|
|
210
|
+
json.dumps(
|
|
211
|
+
{
|
|
212
|
+
"version": 1,
|
|
213
|
+
"path_exemptions": [
|
|
214
|
+
{
|
|
215
|
+
"path": _FROZEN_RELATIVE_PATH,
|
|
216
|
+
"sha256": choose_digest(frozen_path),
|
|
217
|
+
"reason": "Frozen evidence file pinned by its consumers",
|
|
218
|
+
}
|
|
219
|
+
],
|
|
220
|
+
}
|
|
221
|
+
),
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _matching_digest(frozen_path: Path) -> str:
|
|
226
|
+
return hashlib.sha256(frozen_path.read_bytes()).hexdigest()
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _stale_digest(_frozen_path: Path) -> str:
|
|
230
|
+
return _STALE_DIGEST
|
|
231
|
+
|
|
232
|
+
|
|
154
233
|
def _write_exact_exemption_fixture(repository_root: Path) -> None:
|
|
155
234
|
write_text(
|
|
156
235
|
repository_root / _FIXTURE_NOTES_RELATIVE_PATH,
|
|
@@ -9,6 +9,8 @@ import stat
|
|
|
9
9
|
import subprocess
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
|
+
from subprocess_window_access import hidden_window_creation_flags
|
|
13
|
+
|
|
12
14
|
git_directory_name = ".git"
|
|
13
15
|
git_listing_commands = (
|
|
14
16
|
(("git", "ls-files", "--stage", "-z"), True),
|
|
@@ -32,6 +34,7 @@ def _read_git_paths_and_modes(
|
|
|
32
34
|
cwd=repository_root,
|
|
33
35
|
capture_output=True,
|
|
34
36
|
check=True,
|
|
37
|
+
creationflags=hidden_window_creation_flags(),
|
|
35
38
|
)
|
|
36
39
|
for each_record in completed_process.stdout.split(b"\0"):
|
|
37
40
|
if not each_record:
|
|
@@ -68,6 +68,8 @@ from dev_env_scripts_constants.verify_installable_package_constants import (
|
|
|
68
68
|
VERIFICATION_PASSED_MESSAGE,
|
|
69
69
|
)
|
|
70
70
|
|
|
71
|
+
from subprocess_window_access import hidden_window_creation_flags
|
|
72
|
+
|
|
71
73
|
|
|
72
74
|
def package_root_path() -> Path:
|
|
73
75
|
"""Return the claude-dev-env package root that holds package.json."""
|
|
@@ -303,6 +305,7 @@ def run_npm_pack(into_directory: Path, from_package_root: Path) -> Path:
|
|
|
303
305
|
capture_output=True,
|
|
304
306
|
text=True,
|
|
305
307
|
encoding=UTF8_ENCODING,
|
|
308
|
+
creationflags=hidden_window_creation_flags(),
|
|
306
309
|
)
|
|
307
310
|
tarball_name = _npm_pack_filename_from_json(completed.stdout)
|
|
308
311
|
return into_directory / tarball_name
|
|
@@ -439,6 +442,7 @@ def list_git_tracked_paths_under(
|
|
|
439
442
|
capture_output=True,
|
|
440
443
|
text=True,
|
|
441
444
|
encoding=UTF8_ENCODING,
|
|
445
|
+
creationflags=hidden_window_creation_flags(),
|
|
442
446
|
)
|
|
443
447
|
return frozenset(
|
|
444
448
|
each_line.replace("\\", "/")
|
|
@@ -520,6 +524,7 @@ def smoke_check_install_entrypoint(from_package_root: Path) -> str | None:
|
|
|
520
524
|
capture_output=True,
|
|
521
525
|
text=True,
|
|
522
526
|
encoding=UTF8_ENCODING,
|
|
527
|
+
creationflags=hidden_window_creation_flags(),
|
|
523
528
|
)
|
|
524
529
|
if completed.returncode == 0:
|
|
525
530
|
return None
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"""Windows creation flags that hide the advisory poller and its children.
|
|
2
|
-
|
|
3
|
-
A poller with no console makes each git call and each check open a fresh
|
|
4
|
-
console window. A hidden console is inherited by descendants, so those
|
|
5
|
-
children stay off the screen.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import subprocess
|
|
11
|
-
import sys
|
|
12
|
-
|
|
13
|
-
from .config.constants import (
|
|
14
|
-
CREATE_NEW_PROCESS_GROUP_ATTRIBUTE,
|
|
15
|
-
CREATE_NO_WINDOW_ATTRIBUTE,
|
|
16
|
-
WINDOWS_PLATFORM,
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def hidden_window_creation_flags() -> int:
|
|
21
|
-
"""Return the flag that runs a Windows child without a visible console.
|
|
22
|
-
|
|
23
|
-
Returns:
|
|
24
|
-
The hidden-console flag on Windows, zero elsewhere.
|
|
25
|
-
"""
|
|
26
|
-
if sys.platform != WINDOWS_PLATFORM:
|
|
27
|
-
return 0
|
|
28
|
-
return getattr(subprocess, CREATE_NO_WINDOW_ATTRIBUTE, 0)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def detached_poller_creation_flags() -> int:
|
|
32
|
-
"""Return the flags for the long-running poller on Windows.
|
|
33
|
-
|
|
34
|
-
Returns:
|
|
35
|
-
A new process group plus a hidden console on Windows, zero elsewhere.
|
|
36
|
-
"""
|
|
37
|
-
if sys.platform != WINDOWS_PLATFORM:
|
|
38
|
-
return 0
|
|
39
|
-
return getattr(subprocess, CREATE_NEW_PROCESS_GROUP_ATTRIBUTE, 0) | getattr(
|
|
40
|
-
subprocess, CREATE_NO_WINDOW_ATTRIBUTE, 0
|
|
41
|
-
)
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"""Repository public-email exception schema."""
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
|
|
5
|
-
CONFIG_RELATIVE_PATH = "config/repository-policy.json"
|
|
6
|
-
DIGEST_PATTERN = re.compile(r"[0-9a-f]{64}")
|
|
7
|
-
FORBIDDEN_PATH_CHARACTERS = frozenset("\\:*?[]")
|
|
8
|
-
ALL_ENTRY_FIELDS = frozenset({"path", "sha256", "reason"})
|
|
9
|
-
ALL_FORBIDDEN_PATH_SEGMENTS = frozenset({"", ".", ".."})
|
|
10
|
-
FIRST_PRINTABLE_CODEPOINT = 32
|