claude-dev-env 2.12.0 → 2.14.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.md +61 -0
- package/CLAUDE.md +1 -57
- package/_shared/AGENTS.md +15 -0
- package/_shared/CLAUDE.md +1 -15
- package/_shared/advisor/AGENTS.md +22 -0
- package/_shared/advisor/CLAUDE.md +1 -22
- package/_shared/pr-loop/AGENTS.md +27 -0
- package/_shared/pr-loop/CLAUDE.md +1 -27
- package/_shared/pr-loop/scripts/AGENTS.md +35 -0
- package/_shared/pr-loop/scripts/CLAUDE.md +1 -35
- package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
- package/_shared/pr-loop/scripts/code_rules_gate_parts/AGENTS.md +42 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +1 -42
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/AGENTS.md +26 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -26
- package/_shared/pr-loop/scripts/test_code_rules_gate.py +0 -26
- package/_shared/pr-loop/scripts/tests/AGENTS.md +44 -0
- package/_shared/pr-loop/scripts/tests/CLAUDE.md +1 -44
- package/_shared/process-tree/AGENTS.md +41 -0
- package/_shared/process-tree/CLAUDE.md +1 -41
- package/agents/AGENTS.md +31 -0
- package/agents/CLAUDE.md +1 -32
- package/agents/clean-coder.md +6 -6
- package/agents/pr-description-writer.md +11 -81
- package/agents/test_agent_frontmatter.py +4 -4
- package/audit-rubrics/AGENTS.md +43 -0
- package/audit-rubrics/CLAUDE.md +1 -43
- package/audit-rubrics/category_rubrics/AGENTS.md +37 -0
- package/audit-rubrics/category_rubrics/CLAUDE.md +1 -37
- package/audit-rubrics/prompts/AGENTS.md +37 -0
- package/audit-rubrics/prompts/CLAUDE.md +1 -37
- package/bin/AGENTS.md +112 -0
- package/bin/CLAUDE.md +1 -112
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-constants.mjs +6 -7
- package/bin/install.mjs +71 -13
- package/bin/install.prune.test.mjs +26 -0
- package/bin/install.settings-defaults.test.mjs +60 -33
- package/bin/install.test.mjs +36 -4
- package/commands/AGENTS.md +23 -0
- package/commands/CLAUDE.md +1 -23
- package/commands/hook-log-extract.md +3 -3
- package/commands/sr-loop.md +9 -5
- package/docs/AGENTS.md +32 -0
- package/docs/CLAUDE.md +1 -33
- package/docs/CODE_RULES.md +1 -1
- package/docs/imagegen.md +22 -0
- package/docs/references/AGENTS.md +17 -0
- package/docs/references/CLAUDE.md +1 -18
- package/hooks/AGENTS.md +31 -0
- package/hooks/CLAUDE.md +1 -31
- package/hooks/_gh_pr_author_swap_utils.py +14 -0
- package/hooks/advisory/AGENTS.md +16 -0
- package/hooks/advisory/CLAUDE.md +1 -16
- package/hooks/blocking/AGENTS.md +123 -0
- package/hooks/blocking/CLAUDE.md +1 -148
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/AGENTS.md +28 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +1 -28
- package/hooks/blocking/code_rules_banned_identifiers.py +1 -1
- package/hooks/blocking/code_rules_dead_module_constant.py +149 -37
- package/hooks/blocking/code_rules_probe_chains.py +6 -2
- package/hooks/blocking/config/AGENTS.md +10 -0
- package/hooks/blocking/config/CLAUDE.md +1 -22
- package/hooks/blocking/conventional_pr_title_gate.py +1 -2
- package/hooks/blocking/gh_pr_author_restore.py +7 -2
- package/hooks/blocking/intent_only_ending_blocker.py +11 -16
- package/hooks/blocking/inventory_intent_records/AGENTS.md +26 -0
- package/hooks/blocking/inventory_intent_records/CLAUDE.md +1 -26
- package/hooks/blocking/package_inventory_stale_blocker_parts/AGENTS.md +26 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +1 -26
- package/hooks/blocking/pii_prevention_blocker_parts/AGENTS.md +24 -0
- package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +1 -24
- package/hooks/blocking/send_user_file_open_locally_blocker.py +1 -1
- package/hooks/blocking/stop_dispatcher.py +4 -4
- package/hooks/blocking/tdd_enforcer_parts/AGENTS.md +30 -0
- package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +1 -30
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -3
- package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +171 -0
- package/hooks/blocking/test_code_rules_enforcer_magic_allowlist.py +1 -1
- package/hooks/blocking/test_gh_pr_author_restore.py +2 -1
- package/hooks/blocking/test_intent_only_ending_blocker.py +4 -0
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +6 -7
- package/hooks/blocking/test_send_user_file_open_locally_blocker.py +4 -3
- package/hooks/blocking/test_shared_stdin_adoption.py +0 -2
- package/hooks/diagnostic/AGENTS.md +43 -0
- package/hooks/diagnostic/CLAUDE.md +1 -43
- package/hooks/diagnostic/hook_log_extractor.py +4 -38
- package/hooks/diagnostic/hook_log_stop_wrapper.py +6 -155
- package/hooks/diagnostic/migrations/AGENTS.md +16 -0
- package/hooks/diagnostic/migrations/CLAUDE.md +1 -16
- package/hooks/diagnostic/queries/AGENTS.md +19 -0
- package/hooks/diagnostic/queries/CLAUDE.md +1 -19
- package/hooks/diagnostic/test_hook_log_extractor.py +10 -23
- package/hooks/diagnostic/test_hook_log_stop_wrapper.py +3 -331
- package/hooks/git-hooks/AGENTS.md +31 -0
- package/hooks/git-hooks/CLAUDE.md +1 -31
- package/hooks/git-hooks/git_hooks_constants/AGENTS.md +21 -0
- package/hooks/git-hooks/git_hooks_constants/CLAUDE.md +1 -21
- package/hooks/git-hooks/git_hooks_constants/__init__.py +4 -12
- package/hooks/git-hooks/pre_push.py +49 -118
- package/hooks/git-hooks/test_pre_push.py +111 -137
- package/hooks/hooks.json +0 -35
- package/hooks/hooks_constants/AGENTS.md +104 -0
- package/hooks/hooks_constants/CLAUDE.md +1 -113
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -11
- package/hooks/hooks_constants/convergence_branch_constants.py +0 -1
- package/hooks/hooks_constants/fable_spawn_gate_constants.py +3 -4
- package/hooks/hooks_constants/hook_log_extractor_constants.py +1 -2
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +0 -8
- package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +1 -6
- package/hooks/hooks_constants/stop_dispatcher_constants.py +0 -1
- package/hooks/hooks_constants/task_list_loop_starter_constants.py +4 -3
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +1 -26
- package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +0 -5
- package/hooks/hooks_constants/test_stop_dispatcher_constants.py +0 -1
- package/hooks/hooks_constants/working_style_prompt_constants.py +29 -20
- package/hooks/lifecycle/AGENTS.md +18 -0
- package/hooks/lifecycle/CLAUDE.md +1 -20
- package/hooks/observability/AGENTS.md +20 -0
- package/hooks/observability/CLAUDE.md +1 -20
- package/hooks/session/AGENTS.md +33 -0
- package/hooks/session/CLAUDE.md +1 -33
- package/hooks/session/gh_pr_author_session_cleanup.py +7 -2
- package/hooks/session/task_list_loop_starter.py +3 -3
- package/hooks/session/test_gh_pr_author_session_cleanup.py +2 -1
- package/hooks/session/test_task_list_loop_starter.py +10 -2
- package/hooks/session/test_working_style_prompt.py +9 -4
- package/hooks/validation/AGENTS.md +20 -0
- package/hooks/validation/CLAUDE.md +1 -20
- package/hooks/validators/AGENTS.md +51 -0
- package/hooks/validators/CLAUDE.md +1 -51
- package/hooks/validators/health_check.py +52 -19
- package/hooks/validators/python_style_checks.py +1 -1
- package/hooks/validators/test_health_check.py +112 -27
- package/hooks/workflow/AGENTS.md +16 -0
- package/hooks/workflow/CLAUDE.md +1 -16
- package/installable-surfaces.manifest.json +1 -0
- package/output-styles/AGENTS.md +15 -0
- package/output-styles/CLAUDE.md +1 -15
- package/package.json +2 -1
- package/rules/AGENTS.md +61 -0
- package/rules/CLAUDE.md +1 -63
- package/rules/code-standards.md +5 -9
- package/rules/doc-prose-cuts.md +1 -1
- package/rules/gh-cli-conventions.md +0 -1
- package/rules/git-workflow.md +1 -3
- package/scripts/AGENTS.md +62 -0
- package/scripts/CLAUDE.md +1 -63
- package/scripts/_code_review_test_support.py +0 -95
- package/scripts/codex_compat_materializer.py +4 -0
- package/scripts/dev_env_scripts_constants/AGENTS.md +21 -0
- package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -21
- package/scripts/dev_env_scripts_constants/code_review_constants.py +9 -98
- package/scripts/dev_env_scripts_constants/test_code_review_constants.py +1 -44
- package/scripts/invoke_code_review.py +8 -451
- package/scripts/sync_to_cursor/AGENTS.md +23 -0
- package/scripts/sync_to_cursor/CLAUDE.md +1 -23
- package/scripts/test_invoke_code_review.py +5 -61
- package/scripts/test_invoke_code_review_cli.py +1 -45
- package/scripts/test_invoke_code_review_contract.py +1 -118
- package/scripts/test_validate_instruction_pairs.py +90 -0
- package/scripts/test_verify_installable_package.py +5 -1
- package/scripts/tests/AGENTS.md +33 -0
- package/scripts/tests/CLAUDE.md +1 -33
- package/scripts/tests/test_codex_compat_materializer.py +36 -1
- package/scripts/validate_instruction_pairs.py +183 -0
- package/settings.json +1 -10
- package/skills/AGENTS.md +72 -0
- package/skills/CLAUDE.md +1 -64
- package/skills/_shared/AGENTS.md +44 -0
- package/skills/_shared/CLAUDE.md +1 -44
- package/skills/_shared/advisor/AGENTS.md +9 -0
- package/skills/_shared/advisor/CLAUDE.md +1 -9
- package/skills/_shared/pr-loop/AGENTS.md +50 -0
- package/skills/_shared/pr-loop/CLAUDE.md +1 -50
- package/skills/_shared/pr-loop/prompts/AGENTS.md +9 -0
- package/skills/_shared/pr-loop/prompts/CLAUDE.md +1 -9
- package/skills/_shared/pr-loop/scripts/AGENTS.md +35 -0
- package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -35
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +24 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -24
- package/skills/anthropic-plan/AGENTS.md +34 -0
- package/skills/anthropic-plan/CLAUDE.md +1 -34
- package/skills/anthropic-plan/scripts/AGENTS.md +11 -0
- package/skills/anthropic-plan/scripts/CLAUDE.md +1 -11
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/AGENTS.md +16 -0
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/CLAUDE.md +1 -16
- package/skills/anthropic-plan/templates/AGENTS.md +13 -0
- package/skills/anthropic-plan/templates/CLAUDE.md +1 -13
- package/skills/anthropic-plan/workflow/AGENTS.md +14 -0
- package/skills/anthropic-plan/workflow/CLAUDE.md +1 -14
- package/skills/auditing-claude-config/AGENTS.md +21 -0
- package/skills/auditing-claude-config/CLAUDE.md +1 -21
- package/skills/autoconverge/AGENTS.md +36 -0
- package/skills/autoconverge/CLAUDE.md +1 -36
- package/skills/autoconverge/reference/AGENTS.md +16 -0
- package/skills/autoconverge/reference/CLAUDE.md +1 -16
- package/skills/autoconverge/reference/convergence.md +7 -7
- package/skills/autoconverge/reference/gotchas.md +3 -10
- package/skills/autoconverge/workflow/AGENTS.md +26 -0
- package/skills/autoconverge/workflow/CLAUDE.md +1 -26
- package/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +16 -0
- package/skills/autoconverge/workflow/autoconverge_report_constants/CLAUDE.md +1 -16
- package/skills/autoconverge/workflow/converge.contract.test.mjs +53 -1388
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +4 -3
- package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +33 -493
- package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +15 -97
- package/skills/autoconverge/workflow/converge.mjs +201 -238
- package/skills/autoconverge/workflow/converge.precatch.test.mjs +1 -1
- package/skills/bugteam/AGENTS.md +30 -0
- package/skills/bugteam/CLAUDE.md +1 -30
- package/skills/bugteam/CONSTRAINTS.md +1 -1
- package/skills/bugteam/SKILL.md +9 -0
- package/skills/bugteam/reference/AGENTS.md +20 -0
- package/skills/bugteam/reference/CLAUDE.md +1 -20
- package/skills/bugteam/reference/audit-and-teammates.md +10 -6
- package/skills/bugteam/reference/obstacles/AGENTS.md +24 -0
- package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -24
- package/skills/bugteam/scripts/AGENTS.md +30 -0
- package/skills/bugteam/scripts/CLAUDE.md +1 -30
- package/skills/bugteam/scripts/bugteam_scripts_constants/AGENTS.md +18 -0
- package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +1 -18
- package/skills/bugteam/test_skill_additions.py +9 -0
- package/skills/closeout/reference/handoff-prompt-template.md +1 -1
- package/skills/codex-review/AGENTS.md +46 -0
- package/skills/codex-review/CLAUDE.md +1 -46
- package/skills/codex-review/reference/AGENTS.md +15 -0
- package/skills/codex-review/reference/CLAUDE.md +1 -15
- package/skills/codex-review/scripts/codex_review_scripts_constants/AGENTS.md +18 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +1 -18
- package/skills/codex-review/test_skill_scaffold.py +3 -3
- package/skills/comments/SKILL.md +65 -0
- package/skills/copilot-review/AGENTS.md +18 -0
- package/skills/copilot-review/CLAUDE.md +1 -18
- package/skills/descriptions/SKILL.md +51 -0
- package/skills/emergencies/SKILL.md +42 -0
- package/skills/everything-search/AGENTS.md +17 -0
- package/skills/everything-search/CLAUDE.md +1 -17
- package/skills/fresh-branch/AGENTS.md +14 -0
- package/skills/fresh-branch/CLAUDE.md +1 -14
- package/skills/grok-spawn/AGENTS.md +28 -0
- package/skills/grok-spawn/CLAUDE.md +1 -28
- package/skills/orchestrator/SKILL.md +2 -4
- package/skills/plan-to-pr/SKILL.md +6 -7
- package/skills/plan-to-pr/reference/final-validation-tasks.md +1 -1
- package/skills/plan-to-pr/reference/process-inventory.md +2 -2
- package/skills/plan-to-pr/reference/review-loop.md +2 -2
- package/skills/plan-to-pr/reference/run-record.schema.json +1 -1
- package/skills/plan-to-pr/reference/task-seeds.md +1 -1
- package/skills/plan-to-pr/reference/task-ticket.md +3 -4
- package/skills/plan-to-pr/scripts/config/constants.py +1 -2
- package/skills/plan-to-pr/scripts/test_validate_protocol.py +1 -1
- package/skills/plan-to-pr/test_skill_contract.py +2 -2
- package/skills/pr-converge/AGENTS.md +32 -0
- package/skills/pr-converge/CLAUDE.md +1 -32
- package/skills/pr-converge/SKILL.md +13 -16
- package/skills/pr-converge/pr_converge_skill_constants/AGENTS.md +26 -0
- package/skills/pr-converge/pr_converge_skill_constants/CLAUDE.md +1 -26
- package/skills/pr-converge/reference/AGENTS.md +28 -0
- package/skills/pr-converge/reference/CLAUDE.md +1 -28
- package/skills/pr-converge/reference/obstacles/AGENTS.md +23 -0
- package/skills/pr-converge/reference/obstacles/CLAUDE.md +1 -23
- package/skills/pr-converge/reference/progress-checklist.md +6 -5
- package/skills/pr-converge/reference/state-schema.md +1 -27
- package/skills/pr-converge/scripts/AGENTS.md +46 -0
- package/skills/pr-converge/scripts/CLAUDE.md +1 -46
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/AGENTS.md +18 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -18
- package/skills/pr-converge/workflows/AGENTS.md +16 -0
- package/skills/pr-converge/workflows/CLAUDE.md +1 -16
- package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
- package/skills/pr-loop-cloud-transport/reference/identity-and-hooks.md +3 -3
- package/skills/pr-loop-lifecycle/SKILL.md +1 -1
- package/skills/pr-loop-lifecycle/reference/teardown-publish-permissions.md +1 -1
- package/skills/prototype/SKILL.md +4 -4
- package/skills/prototype/reference/honest-limitations.md +5 -5
- package/skills/prototype/reference/promotion-tasks.md +2 -2
- package/skills/prototype/workflows/promotion.md +4 -6
- package/skills/rebase/AGENTS.md +32 -0
- package/skills/rebase/CLAUDE.md +1 -32
- package/skills/recall/AGENTS.md +30 -0
- package/skills/recall/CLAUDE.md +1 -30
- package/skills/remember/AGENTS.md +31 -0
- package/skills/remember/CLAUDE.md +1 -31
- package/skills/reviews/SKILL.md +85 -0
- package/skills/session-log/AGENTS.md +32 -0
- package/skills/session-log/CLAUDE.md +1 -32
- package/skills/session-tidy/AGENTS.md +36 -0
- package/skills/session-tidy/CLAUDE.md +1 -36
- package/skills/skill-builder/AGENTS.md +49 -0
- package/skills/skill-builder/CLAUDE.md +1 -49
- package/skills/skill-builder/references/AGENTS.md +25 -0
- package/skills/skill-builder/references/CLAUDE.md +1 -25
- package/skills/skill-builder/references/deterministic-elements.md +1 -1
- package/skills/skill-builder/templates/AGENTS.md +14 -0
- package/skills/skill-builder/templates/CLAUDE.md +1 -14
- package/skills/skill-builder/workflows/AGENTS.md +19 -0
- package/skills/skill-builder/workflows/CLAUDE.md +1 -19
- package/skills/small-cl/SKILL.md +52 -0
- package/skills/task-build/AGENTS.md +29 -0
- package/skills/task-build/CLAUDE.md +1 -29
- package/skills/update/AGENTS.md +38 -0
- package/skills/update/CLAUDE.md +1 -38
- package/system-prompts/AGENTS.md +17 -0
- package/system-prompts/CLAUDE.md +1 -17
- package/system-prompts/software-engineer.xml +3 -3
- package/agents/code-verifier.md +0 -74
- package/docs/PR_DESCRIPTION_GUIDE.md +0 -157
- package/docs/references/code-review-enforcement.md +0 -132
- package/hooks/blocking/code_review_enforcement_config_bootstrap.py +0 -53
- package/hooks/blocking/code_review_gate_deny.py +0 -74
- package/hooks/blocking/code_review_pr_create_gate.py +0 -198
- package/hooks/blocking/code_review_push_gate.py +0 -145
- package/hooks/blocking/code_review_stamp_directory_write_blocker.py +0 -348
- package/hooks/blocking/code_review_stamp_store.py +0 -233
- package/hooks/blocking/code_review_stamp_write_blocker_parts/__init__.py +0 -7
- package/hooks/blocking/code_review_stamp_write_blocker_parts/conftest.py +0 -15
- package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py +0 -212
- package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py +0 -138
- package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py +0 -49
- package/hooks/blocking/code_review_stamp_write_blocker_parts/test_split_directory_change_into_stamp.py +0 -38
- package/hooks/blocking/code_verifier_spawn_preflight_gate.py +0 -483
- package/hooks/blocking/config/code_review_enforcement_constants.py +0 -143
- package/hooks/blocking/config/test_code_review_enforcement_constants.py +0 -166
- package/hooks/blocking/config/verified_commit_constants.py +0 -160
- package/hooks/blocking/config/verified_commit_context_constants.py +0 -21
- package/hooks/blocking/config/verified_commit_gate_output_constants.py +0 -14
- package/hooks/blocking/conftest.py +0 -123
- package/hooks/blocking/convergence_gate_blocker.py +0 -310
- package/hooks/blocking/pr_converge_bugteam_enforcer.py +0 -170
- package/hooks/blocking/pr_description_body_audit.py +0 -148
- package/hooks/blocking/pr_description_command_parser.py +0 -237
- package/hooks/blocking/pr_description_enforcer.py +0 -227
- package/hooks/blocking/pr_description_pr_number.py +0 -155
- package/hooks/blocking/pr_description_proof_of_work.py +0 -385
- package/hooks/blocking/pr_description_readability.py +0 -364
- package/hooks/blocking/reviewer_spawn_gate.py +0 -182
- package/hooks/blocking/test_code_review_enforcement_config_bootstrap.py +0 -62
- package/hooks/blocking/test_code_review_gate_deny.py +0 -54
- package/hooks/blocking/test_code_review_pr_create_gate.py +0 -199
- package/hooks/blocking/test_code_review_push_gate.py +0 -205
- package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +0 -199
- package/hooks/blocking/test_code_review_stamp_store.py +0 -205
- package/hooks/blocking/test_code_verifier_spawn_preflight_gate.py +0 -710
- package/hooks/blocking/test_code_verifier_tools_contract.py +0 -28
- package/hooks/blocking/test_convergence_gate_blocker.py +0 -428
- package/hooks/blocking/test_pr_converge_bugteam_enforcer.py +0 -311
- package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +0 -184
- package/hooks/blocking/test_pr_description_enforcer.py +0 -221
- package/hooks/blocking/test_pr_description_enforcer_body_audit.py +0 -247
- package/hooks/blocking/test_pr_description_enforcer_body_rules.py +0 -493
- package/hooks/blocking/test_pr_description_enforcer_command_parser.py +0 -366
- package/hooks/blocking/test_pr_description_enforcer_pr_number.py +0 -159
- package/hooks/blocking/test_pr_description_enforcer_proof_gate.py +0 -175
- package/hooks/blocking/test_pr_description_enforcer_readability.py +0 -443
- package/hooks/blocking/test_pr_description_proof_of_work.py +0 -313
- package/hooks/blocking/test_reviewer_spawn_gate.py +0 -230
- package/hooks/blocking/test_verdict_directory_write_blocker.py +0 -804
- package/hooks/blocking/test_verification_verdict_store.py +0 -974
- package/hooks/blocking/test_verified_commit_config_bootstrap.py +0 -67
- package/hooks/blocking/test_verified_commit_docs_delta.py +0 -176
- package/hooks/blocking/test_verified_commit_gate.py +0 -581
- package/hooks/blocking/test_verified_commit_gate_additional_context.py +0 -134
- package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +0 -131
- package/hooks/blocking/test_verifier_verdict_minter.py +0 -299
- package/hooks/blocking/tests/test_verified_commit_gate.py +0 -41
- package/hooks/blocking/verdict_directory_write_blocker.py +0 -687
- package/hooks/blocking/verification_verdict_store.py +0 -1039
- package/hooks/blocking/verified_commit_config_bootstrap.py +0 -63
- package/hooks/blocking/verified_commit_gate.py +0 -113
- package/hooks/blocking/verified_commit_gate_parts/CLAUDE.md +0 -28
- package/hooks/blocking/verified_commit_gate_parts/__init__.py +0 -1
- package/hooks/blocking/verified_commit_gate_parts/command_tokenization.py +0 -174
- package/hooks/blocking/verified_commit_gate_parts/deny_payload.py +0 -53
- package/hooks/blocking/verified_commit_gate_parts/deny_reason.py +0 -80
- package/hooks/blocking/verified_commit_gate_parts/directory_resolution.py +0 -170
- package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +0 -217
- package/hooks/blocking/verified_commit_gate_parts/tests/conftest.py +0 -10
- package/hooks/blocking/verified_commit_gate_parts/tests/test_command_tokenization.py +0 -94
- package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_payload.py +0 -17
- package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_reason.py +0 -38
- package/hooks/blocking/verified_commit_gate_parts/tests/test_directory_resolution.py +0 -71
- package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +0 -96
- package/hooks/blocking/verified_commit_message_accuracy_blocker.py +0 -167
- package/hooks/blocking/verifier_verdict_minter.py +0 -280
- package/hooks/hooks_constants/code_verifier_spawn_preflight_gate_constants.py +0 -64
- package/hooks/hooks_constants/convergence_gate_blocker_constants.py +0 -53
- package/hooks/hooks_constants/pr_converge_bugteam_enforcer_constants.py +0 -55
- package/hooks/hooks_constants/pr_converge_bugteam_enforcer_state.py +0 -67
- package/hooks/hooks_constants/pr_description_enforcer_constants.py +0 -167
- package/hooks/hooks_constants/pr_description_proof_of_work_constants.py +0 -107
- package/hooks/hooks_constants/reviewer_spawn_gate_constants.py +0 -41
- package/hooks/hooks_constants/test_pr_description_enforcer_constants.py +0 -292
- package/hooks/lifecycle/pr_converge_bugteam_skill_tracker.py +0 -198
- package/hooks/lifecycle/test_pr_converge_bugteam_skill_tracker.py +0 -283
- package/rules/proof-of-work-pr-comments.md +0 -22
- package/rules/verified-commit-gate-skip.md +0 -4
- package/scripts/Show-Asset.ps1 +0 -106
package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
"""Decide whether a command builds a stamp path with obfuscation and writes.
|
|
2
|
-
|
|
3
|
-
A path-obfuscation forge hides ``.claude`` or ``code-review-stamps`` inside hex
|
|
4
|
-
digits, a base64 token, a comma-separated character-code sequence, or a run of
|
|
5
|
-
``+``-joined ``chr(<int>)`` calls, then pairs the assembled path with a
|
|
6
|
-
non-redirect file write (``open(``, ``write_text``, ``Out-File``,
|
|
7
|
-
``Set-Content``, ``Add-Content``, ``tee``). The literal path matchers miss such
|
|
8
|
-
a path because it carries no plain ``code-review-stamps`` substring, so this
|
|
9
|
-
module decodes each embedded token and looks for a stamp-path segment either in
|
|
10
|
-
the decoded text or inside the write call's argument region. A bare ``>``
|
|
11
|
-
redirect to the stamp path is caught by the literal-path matchers, so a command
|
|
12
|
-
whose only write is a redirect is left alone here.
|
|
13
|
-
|
|
14
|
-
The entry hook registers the constant packages before importing this module, so
|
|
15
|
-
the ``from config...`` imports below resolve against the sibling ``config/``
|
|
16
|
-
package without a bootstrap call here.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
from __future__ import annotations
|
|
20
|
-
|
|
21
|
-
import base64
|
|
22
|
-
import binascii
|
|
23
|
-
import re
|
|
24
|
-
|
|
25
|
-
from config.code_review_enforcement_constants import (
|
|
26
|
-
ALL_STAMP_PATH_SEGMENT_BODIES,
|
|
27
|
-
ALL_STAMP_PATH_SEGMENT_NAMES,
|
|
28
|
-
)
|
|
29
|
-
from config.verified_commit_constants import (
|
|
30
|
-
BASE64_TOKEN_PATTERN,
|
|
31
|
-
CHARACTER_CODE_SEQUENCE_PATTERN,
|
|
32
|
-
CHR_CALL_CHAIN_PATTERN,
|
|
33
|
-
CHR_CALL_CODE_PATTERN,
|
|
34
|
-
HEX_DIGITS_PER_BYTE,
|
|
35
|
-
HEX_TOKEN_PATTERN,
|
|
36
|
-
NON_REDIRECT_FILE_WRITE_PRIMITIVE_PATTERN,
|
|
37
|
-
PATH_OBFUSCATION_PRIMITIVE_PATTERN,
|
|
38
|
-
WRITE_CALL_REGION_PATTERN,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
_ASCII_ENCODING = "ascii"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def _decode_hex_token(hex_token: str) -> str:
|
|
45
|
-
"""Decode a hex-digit token to text, returning empty text on failure.
|
|
46
|
-
|
|
47
|
-
Args:
|
|
48
|
-
hex_token: A run of hex digits taken from the command.
|
|
49
|
-
|
|
50
|
-
Returns:
|
|
51
|
-
The decoded ASCII text, or empty text when the token is odd-length,
|
|
52
|
-
not valid hex, or not decodable as ASCII.
|
|
53
|
-
"""
|
|
54
|
-
odd_hex_token_remainder = 1
|
|
55
|
-
if len(hex_token) % HEX_DIGITS_PER_BYTE == odd_hex_token_remainder:
|
|
56
|
-
return ""
|
|
57
|
-
try:
|
|
58
|
-
return bytes.fromhex(hex_token).decode(_ASCII_ENCODING)
|
|
59
|
-
except (ValueError, binascii.Error):
|
|
60
|
-
return ""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def _decode_base64_token(base64_token: str) -> str:
|
|
64
|
-
"""Decode a base64 token to text, returning empty text on failure.
|
|
65
|
-
|
|
66
|
-
Args:
|
|
67
|
-
base64_token: A base64-shaped token taken from the command.
|
|
68
|
-
|
|
69
|
-
Returns:
|
|
70
|
-
The decoded ASCII text, or empty text when the token is not valid
|
|
71
|
-
base64 or not decodable as ASCII.
|
|
72
|
-
"""
|
|
73
|
-
try:
|
|
74
|
-
return base64.b64decode(base64_token, validate=True).decode(_ASCII_ENCODING)
|
|
75
|
-
except (ValueError, binascii.Error):
|
|
76
|
-
return ""
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def _decode_character_code_sequence(code_sequence: str) -> str:
|
|
80
|
-
"""Decode a comma-separated character-code sequence to text.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
code_sequence: A comma-separated run of decimal character codes, each
|
|
84
|
-
within the three-digit range the source pattern admits.
|
|
85
|
-
|
|
86
|
-
Returns:
|
|
87
|
-
The decoded text.
|
|
88
|
-
"""
|
|
89
|
-
character_code_separator = ","
|
|
90
|
-
decoded_characters: list[str] = []
|
|
91
|
-
for each_code in code_sequence.split(character_code_separator):
|
|
92
|
-
code_point = int(each_code.strip())
|
|
93
|
-
decoded_characters.append(chr(code_point))
|
|
94
|
-
return "".join(decoded_characters)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def _decode_chr_call_chain(chr_chain: str) -> str:
|
|
98
|
-
"""Decode a run of ``+``-joined ``chr(<int>)`` calls to text.
|
|
99
|
-
|
|
100
|
-
Args:
|
|
101
|
-
chr_chain: A run of two or more ``+``-joined ``chr(<int>)`` calls taken
|
|
102
|
-
from the command, each code within the three-digit source range.
|
|
103
|
-
|
|
104
|
-
Returns:
|
|
105
|
-
The decoded text.
|
|
106
|
-
"""
|
|
107
|
-
decoded_characters: list[str] = []
|
|
108
|
-
for each_code in re.findall(CHR_CALL_CODE_PATTERN, chr_chain, re.IGNORECASE):
|
|
109
|
-
decoded_characters.append(chr(int(each_code)))
|
|
110
|
-
return "".join(decoded_characters)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def _append_when_present(all_decoded_texts: list[str], decoded_text: str) -> None:
|
|
114
|
-
"""Append the lowercase decoded text when it is non-empty.
|
|
115
|
-
|
|
116
|
-
Args:
|
|
117
|
-
all_decoded_texts: The running list of decoded texts to extend.
|
|
118
|
-
decoded_text: One token's decoded text, empty when the token failed.
|
|
119
|
-
|
|
120
|
-
Returns:
|
|
121
|
-
None. The list is extended in place when the text is non-empty.
|
|
122
|
-
"""
|
|
123
|
-
if decoded_text:
|
|
124
|
-
all_decoded_texts.append(decoded_text.lower())
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
def _decoded_texts_from_command(command_text: str) -> list[str]:
|
|
128
|
-
"""Decode every hex, base64, character-code, and chr-chain token a command embeds.
|
|
129
|
-
|
|
130
|
-
Args:
|
|
131
|
-
command_text: The raw command string from the tool payload.
|
|
132
|
-
|
|
133
|
-
Returns:
|
|
134
|
-
The lowercase decoded text for every token that decodes cleanly;
|
|
135
|
-
tokens that fail to decode or carry an out-of-range code are skipped.
|
|
136
|
-
"""
|
|
137
|
-
all_decoded_texts: list[str] = []
|
|
138
|
-
for each_hex_token in re.findall(HEX_TOKEN_PATTERN, command_text, re.IGNORECASE):
|
|
139
|
-
_append_when_present(all_decoded_texts, _decode_hex_token(each_hex_token))
|
|
140
|
-
for each_base64_token in re.findall(BASE64_TOKEN_PATTERN, command_text):
|
|
141
|
-
_append_when_present(all_decoded_texts, _decode_base64_token(each_base64_token))
|
|
142
|
-
for each_code_sequence in re.findall(CHARACTER_CODE_SEQUENCE_PATTERN, command_text):
|
|
143
|
-
_append_when_present(all_decoded_texts, _decode_character_code_sequence(each_code_sequence))
|
|
144
|
-
for each_chr_chain in re.findall(CHR_CALL_CHAIN_PATTERN, command_text, re.IGNORECASE):
|
|
145
|
-
_append_when_present(all_decoded_texts, _decode_chr_call_chain(each_chr_chain))
|
|
146
|
-
return all_decoded_texts
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
def _decoded_token_references_stamp_segment(command_text: str) -> bool:
|
|
150
|
-
"""Decide whether a decodable token in a command hides a stamp-path segment.
|
|
151
|
-
|
|
152
|
-
Args:
|
|
153
|
-
command_text: The raw command string from the tool payload.
|
|
154
|
-
|
|
155
|
-
Returns:
|
|
156
|
-
True when a decodable token decodes to a stamp-path segment body
|
|
157
|
-
(``claude`` or ``code-review-stamps``).
|
|
158
|
-
"""
|
|
159
|
-
all_decoded_texts = _decoded_texts_from_command(command_text)
|
|
160
|
-
return any(
|
|
161
|
-
each_segment_body in each_decoded_text
|
|
162
|
-
for each_decoded_text in all_decoded_texts
|
|
163
|
-
for each_segment_body in ALL_STAMP_PATH_SEGMENT_BODIES
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
def _write_call_region_names_stamp_segment(command_text: str) -> bool:
|
|
168
|
-
"""Decide whether a write call's argument region names a stamp-path segment.
|
|
169
|
-
|
|
170
|
-
Args:
|
|
171
|
-
command_text: The raw command string from the tool payload.
|
|
172
|
-
|
|
173
|
-
Returns:
|
|
174
|
-
True when a stamp-path segment name appears inside a non-redirect write
|
|
175
|
-
call's argument region.
|
|
176
|
-
"""
|
|
177
|
-
write_call_region_pattern = re.compile(WRITE_CALL_REGION_PATTERN, re.IGNORECASE)
|
|
178
|
-
for each_region_match in write_call_region_pattern.finditer(command_text):
|
|
179
|
-
lowercased_region = each_region_match.group(0).lower()
|
|
180
|
-
if any(each_name in lowercased_region for each_name in ALL_STAMP_PATH_SEGMENT_NAMES):
|
|
181
|
-
return True
|
|
182
|
-
return False
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def references_obfuscated_stamp_path(command_text: str) -> bool:
|
|
186
|
-
"""Decide whether a command pairs path obfuscation with a stamp-path write.
|
|
187
|
-
|
|
188
|
-
::
|
|
189
|
-
|
|
190
|
-
python -c "open(bytes.fromhex('...code-review-stamps...'),'w')" -> True
|
|
191
|
-
open(bytes.fromhex('2f746d702f78'),'w') -> False
|
|
192
|
-
|
|
193
|
-
Args:
|
|
194
|
-
command_text: The raw command string from the tool payload.
|
|
195
|
-
|
|
196
|
-
Returns:
|
|
197
|
-
True when the command holds a path-obfuscation primitive, a
|
|
198
|
-
non-redirect file write, and a stamp-path segment reachable by that
|
|
199
|
-
write — either a decoded token anywhere in the command or a plain-text
|
|
200
|
-
segment inside the write call's argument region.
|
|
201
|
-
"""
|
|
202
|
-
has_obfuscation_primitive = (
|
|
203
|
-
re.search(PATH_OBFUSCATION_PRIMITIVE_PATTERN, command_text) is not None
|
|
204
|
-
)
|
|
205
|
-
has_non_redirect_write = (
|
|
206
|
-
re.search(NON_REDIRECT_FILE_WRITE_PRIMITIVE_PATTERN, command_text) is not None
|
|
207
|
-
)
|
|
208
|
-
if not (has_obfuscation_primitive and has_non_redirect_write):
|
|
209
|
-
return False
|
|
210
|
-
if _decoded_token_references_stamp_segment(command_text):
|
|
211
|
-
return True
|
|
212
|
-
return _write_call_region_names_stamp_segment(command_text)
|
package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
"""Decide whether a split directory change reaches the stamp directory then runs a command.
|
|
2
|
-
|
|
3
|
-
A change into the Claude home (``cd ~/.claude``) followed by a change into a
|
|
4
|
-
relative ``code-review-stamps`` directory (``cd code-review-stamps``) lands in
|
|
5
|
-
the stamp directory without ever naming the two segments adjacently, so the
|
|
6
|
-
absolute-path matcher and the single-step ``cd ~/.claude/code-review-stamps``
|
|
7
|
-
matcher both miss it. The trust contract denies every shell command that
|
|
8
|
-
reaches the stamp directory, so any command after the second change — a
|
|
9
|
-
redirect, ``cp``, ``mv``, ``tee``, ``install``, or a ``python -c`` write — is a
|
|
10
|
-
forge vector. An unrelated second change (``cd hooks``) lands elsewhere and
|
|
11
|
-
passes.
|
|
12
|
-
|
|
13
|
-
The entry hook registers the constant packages before importing this module, so
|
|
14
|
-
the ``from config...`` imports below resolve against the sibling ``config/``
|
|
15
|
-
package without a bootstrap call here.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
from __future__ import annotations
|
|
19
|
-
|
|
20
|
-
import re
|
|
21
|
-
|
|
22
|
-
from config.code_review_enforcement_constants import STAMP_DIRECTORY_CHANGE_TARGET_PATTERN
|
|
23
|
-
from config.verified_commit_constants import (
|
|
24
|
-
CLAUDE_HOME_DIRECTORY_NAME,
|
|
25
|
-
CLAUDE_HOME_TARGET_BOUNDARY_PATTERN,
|
|
26
|
-
COMMAND_AFTER_DIRECTORY_CHANGE_PATTERN,
|
|
27
|
-
DIRECTORY_CHANGE_OPTION_PREFIX_PATTERN,
|
|
28
|
-
DIRECTORY_CHANGE_OPTION_TERMINATOR,
|
|
29
|
-
DIRECTORY_CHANGE_PATH_OPTIONS,
|
|
30
|
-
DIRECTORY_CHANGE_PATTERN_PREFIX,
|
|
31
|
-
DIRECTORY_CHANGE_PATTERN_SUFFIX,
|
|
32
|
-
DIRECTORY_CHANGE_TARGET_PATTERN,
|
|
33
|
-
DIRECTORY_CHANGE_VERBS,
|
|
34
|
-
)
|
|
35
|
-
from config.verified_commit_gate_output_constants import REGEX_ALTERNATION_SEPARATOR
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _directory_change_verbs_pattern() -> str:
|
|
39
|
-
"""Build the alternation of directory-change verbs for a change matcher.
|
|
40
|
-
|
|
41
|
-
Returns:
|
|
42
|
-
The regex alternation of escaped directory-change verbs in sorted order.
|
|
43
|
-
"""
|
|
44
|
-
return REGEX_ALTERNATION_SEPARATOR.join(
|
|
45
|
-
re.escape(each_verb) for each_verb in sorted(DIRECTORY_CHANGE_VERBS)
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def _directory_change_option_prefix_pattern() -> str:
|
|
50
|
-
"""Build the optional path-option prefix that may precede a change target.
|
|
51
|
-
|
|
52
|
-
Returns:
|
|
53
|
-
The regex matching zero or more leading path-option or terminator
|
|
54
|
-
tokens, ready to sit between the change suffix and target patterns.
|
|
55
|
-
"""
|
|
56
|
-
option_alternation = REGEX_ALTERNATION_SEPARATOR.join(
|
|
57
|
-
re.escape(each_option)
|
|
58
|
-
for each_option in sorted(
|
|
59
|
-
DIRECTORY_CHANGE_PATH_OPTIONS | {DIRECTORY_CHANGE_OPTION_TERMINATOR}
|
|
60
|
-
)
|
|
61
|
-
)
|
|
62
|
-
return DIRECTORY_CHANGE_OPTION_PREFIX_PATTERN % option_alternation
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def directory_change_prefix() -> str:
|
|
66
|
-
"""Build the change-verb prefix shared by the directory-change matchers.
|
|
67
|
-
|
|
68
|
-
The stamp-directory write-blocker reuses this same prefix, so a single
|
|
69
|
-
builder feeds both this module's split-change matchers and the blocker's
|
|
70
|
-
single-step change matchers, and the two never drift.
|
|
71
|
-
|
|
72
|
-
Returns:
|
|
73
|
-
The regex prefix matching a directory-change verb and any leading
|
|
74
|
-
path-option tokens, ready for a target pattern to follow.
|
|
75
|
-
"""
|
|
76
|
-
return (
|
|
77
|
-
DIRECTORY_CHANGE_PATTERN_PREFIX
|
|
78
|
-
+ _directory_change_verbs_pattern()
|
|
79
|
-
+ DIRECTORY_CHANGE_PATTERN_SUFFIX
|
|
80
|
-
+ _directory_change_option_prefix_pattern()
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def _change_into_claude_pattern() -> re.Pattern[str]:
|
|
85
|
-
"""Build the compiled matcher for a directory change into the Claude home.
|
|
86
|
-
|
|
87
|
-
Returns:
|
|
88
|
-
The compiled, case-insensitive pattern matching a change verb into any
|
|
89
|
-
path ending in ``.claude``.
|
|
90
|
-
"""
|
|
91
|
-
return re.compile(
|
|
92
|
-
directory_change_prefix()
|
|
93
|
-
+ DIRECTORY_CHANGE_TARGET_PATTERN
|
|
94
|
-
+ re.escape(CLAUDE_HOME_DIRECTORY_NAME)
|
|
95
|
-
+ CLAUDE_HOME_TARGET_BOUNDARY_PATTERN,
|
|
96
|
-
re.IGNORECASE,
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def _change_into_stamp_pattern() -> re.Pattern[str]:
|
|
101
|
-
"""Build the compiled matcher for a directory change into the stamp directory.
|
|
102
|
-
|
|
103
|
-
Returns:
|
|
104
|
-
The compiled, case-insensitive pattern matching a change verb into a
|
|
105
|
-
relative ``code-review-stamps`` directory.
|
|
106
|
-
"""
|
|
107
|
-
return re.compile(
|
|
108
|
-
directory_change_prefix() + STAMP_DIRECTORY_CHANGE_TARGET_PATTERN, re.IGNORECASE
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def changes_through_split_directory_into_stamp(command_text: str) -> bool:
|
|
113
|
-
"""Decide whether a split change reaches the stamp directory then runs a command.
|
|
114
|
-
|
|
115
|
-
::
|
|
116
|
-
|
|
117
|
-
cd ~/.claude && cd code-review-stamps && echo x > f.json -> True
|
|
118
|
-
cd ~/.claude && cd hooks && echo x > f.json -> False
|
|
119
|
-
|
|
120
|
-
Args:
|
|
121
|
-
command_text: The raw command string from the tool payload.
|
|
122
|
-
|
|
123
|
-
Returns:
|
|
124
|
-
True when a change into the Claude home precedes a change into a
|
|
125
|
-
relative stamp directory that is itself followed by any further command.
|
|
126
|
-
"""
|
|
127
|
-
change_into_claude_match = _change_into_claude_pattern().search(command_text)
|
|
128
|
-
if change_into_claude_match is None:
|
|
129
|
-
return False
|
|
130
|
-
change_into_stamp_match = _change_into_stamp_pattern().search(
|
|
131
|
-
command_text, change_into_claude_match.end()
|
|
132
|
-
)
|
|
133
|
-
if change_into_stamp_match is None:
|
|
134
|
-
return False
|
|
135
|
-
command_after_change_pattern = re.compile(COMMAND_AFTER_DIRECTORY_CHANGE_PATTERN)
|
|
136
|
-
return (
|
|
137
|
-
command_after_change_pattern.search(command_text, change_into_stamp_match.end()) is not None
|
|
138
|
-
)
|
package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"""Behavioral tests for the obfuscated-stamp-path matcher.
|
|
2
|
-
|
|
3
|
-
The matcher blocks a command that assembles a stamp path from hex, base64, or
|
|
4
|
-
``chr(<int>)`` codes and pairs it with a non-redirect file write, while a
|
|
5
|
-
decode-to-other-path one-liner passes.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
from code_review_stamp_write_blocker_parts.obfuscated_stamp_path_reference import (
|
|
11
|
-
references_obfuscated_stamp_path,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
STAMP_PATH_TEXT = "/.claude/code-review-stamps/a.json"
|
|
15
|
-
BENIGN_PATH_TEXT = "/tmp/x"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def _hex_forge_command(path_text: str) -> str:
|
|
19
|
-
return f"python -c \"open(bytes.fromhex('{path_text.encode().hex()}'),'w').write('x')\""
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def _chr_chain_forge_command(path_text: str) -> str:
|
|
23
|
-
chr_chain = "+".join(f"chr({ord(each_character)})" for each_character in path_text)
|
|
24
|
-
return f"python -c \"open({chr_chain},'w').write('x')\""
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def _character_code_forge_command(path_text: str) -> str:
|
|
28
|
-
comma_separated_codes = ",".join(str(ord(each_character)) for each_character in path_text)
|
|
29
|
-
return f"python -c \"open(bytes([{comma_separated_codes}]),'w').write('x')\""
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def test_hex_assembled_stamp_path_write_is_blocked() -> None:
|
|
33
|
-
assert references_obfuscated_stamp_path(_hex_forge_command(STAMP_PATH_TEXT))
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def test_character_code_assembled_stamp_path_write_is_blocked() -> None:
|
|
37
|
-
assert references_obfuscated_stamp_path(_character_code_forge_command(STAMP_PATH_TEXT))
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def test_chr_chain_assembled_stamp_path_write_is_blocked() -> None:
|
|
41
|
-
assert references_obfuscated_stamp_path(_chr_chain_forge_command(STAMP_PATH_TEXT))
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def test_decode_to_other_path_write_is_not_blocked() -> None:
|
|
45
|
-
assert not references_obfuscated_stamp_path(_hex_forge_command(BENIGN_PATH_TEXT))
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def test_redirect_only_stamp_reference_is_left_to_literal_matchers() -> None:
|
|
49
|
-
assert not references_obfuscated_stamp_path("echo x > ~/.claude/code-review-stamps/a.json")
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"""Behavioral tests for the split directory-change-into-stamp matcher.
|
|
2
|
-
|
|
3
|
-
The matcher blocks a command that changes into the Claude home, then into a
|
|
4
|
-
relative ``code-review-stamps`` directory, then runs any further command, while
|
|
5
|
-
an unrelated second change or a benign command passes.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
from code_review_stamp_write_blocker_parts.split_directory_change_into_stamp import (
|
|
11
|
-
changes_through_split_directory_into_stamp,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
SPLIT_CHANGE_FORGE = "cd ~/.claude && cd code-review-stamps && echo x > f.json"
|
|
15
|
-
UNRELATED_SECOND_CHANGE = "cd ~/.claude && cd hooks && echo x > f.json"
|
|
16
|
-
PYTEST_RUN = "python -m pytest test_code_review_stamp_store.py"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def test_split_change_into_stamp_then_command_is_blocked() -> None:
|
|
20
|
-
assert changes_through_split_directory_into_stamp(SPLIT_CHANGE_FORGE)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def test_unrelated_second_change_is_not_blocked() -> None:
|
|
24
|
-
assert not changes_through_split_directory_into_stamp(UNRELATED_SECOND_CHANGE)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def test_pytest_run_is_not_blocked() -> None:
|
|
28
|
-
assert not changes_through_split_directory_into_stamp(PYTEST_RUN)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def test_change_into_stamp_without_following_command_is_not_blocked() -> None:
|
|
32
|
-
assert not changes_through_split_directory_into_stamp("cd ~/.claude && cd code-review-stamps")
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def test_pushd_split_change_into_stamp_then_command_is_blocked() -> None:
|
|
36
|
-
assert changes_through_split_directory_into_stamp(
|
|
37
|
-
"pushd ~/.claude && pushd code-review-stamps && cp a b"
|
|
38
|
-
)
|