claude-dev-env 2.4.0 → 2.7.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/CLAUDE.md +26 -59
- package/_shared/pr-loop/scripts/_claude_permissions_common.py +84 -0
- package/_shared/pr-loop/scripts/code_rules_gate.py +6 -3
- package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +12 -2
- package/_shared/pr-loop/scripts/code_rules_gate_parts/baseline_import_isolation.py +309 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_regression.py +540 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +206 -70
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/__init__.py +1 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/_repo_test_helpers.py +76 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_baseline_import_isolation.py +248 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_regression.py +309 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_running.py +91 -58
- package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +306 -306
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/claude_permissions_constants.py +44 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +202 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/copilot_quota_constants.py +24 -24
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/stale_worktree_rule_sweep_constants.py +107 -107
- package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +290 -48
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +42 -2
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +36 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +100 -1
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -497
- package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +311 -2
- package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep.py +301 -301
- package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep_constants.py +85 -85
- package/_shared/pr-loop/worker-spawn.md +1 -1
- package/agents/CLAUDE.md +3 -2
- package/agents/caveman.md +0 -1
- package/agents/clasp-deployment-orchestrator.md +0 -1
- package/agents/clean-coder.md +0 -1
- package/agents/code-advisor.md +0 -1
- package/agents/code-quality-agent.md +1 -2
- package/agents/code-verifier.md +36 -8
- package/agents/deep-research.md +0 -1
- package/agents/docs-agent.md +0 -1
- package/agents/git-commit-crafter.md +0 -1
- package/agents/issue-tracker.md +42 -0
- package/agents/plan-packet-validator.md +0 -1
- package/agents/pr-description-writer.md +0 -1
- package/agents/test_agent_frontmatter.py +67 -18
- package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +143 -141
- package/bin/CLAUDE.md +68 -5
- package/bin/codex-compat.mjs +104 -0
- package/bin/codex-compat.test.mjs +51 -0
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-constants.mjs +88 -0
- package/bin/install.mjs +1138 -114
- package/bin/install.prune.test.mjs +869 -19
- package/bin/install.test.mjs +906 -2
- package/codex-capability-map.json +13 -0
- package/commands/implement.md +1 -1
- package/commands/right-size.md +1 -1
- package/docs/CLAUDE.md +1 -0
- package/docs/CODE_RULES.md +2 -0
- package/docs/codex-compatibility.md +25 -0
- package/docs/host-pool-health-monitor.md +102 -0
- package/docs/nas-ssh-invocation.md +96 -12
- package/docs/references/CLAUDE.md +4 -2
- package/docs/references/advisor-tool.md +13 -0
- package/docs/references/code-review-enforcement.md +35 -0
- package/docs/references/team-advisor-skill.md +14 -0
- package/hooks/blocking/CLAUDE.md +4 -0
- package/hooks/blocking/code_review_pr_create_gate.py +7 -3
- package/hooks/blocking/code_review_push_gate.py +9 -4
- package/hooks/blocking/code_review_stamp_directory_write_blocker.py +8 -0
- package/hooks/blocking/config/__init__.py +5 -5
- package/hooks/blocking/config/code_review_enforcement_constants.py +40 -7
- package/hooks/blocking/config/test_code_review_enforcement_constants.py +58 -0
- package/hooks/blocking/config/verified_commit_constants.py +160 -159
- package/hooks/blocking/eli11_reply_enforcer.py +479 -0
- package/hooks/blocking/gh_body_arg_blocker.py +1 -1
- package/hooks/blocking/nas_ssh_binary_enforcer.py +8 -46
- package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +256 -0
- package/hooks/blocking/pre_tool_use_dispatcher.py +24 -24
- package/hooks/blocking/shell_substitution_blocker.py +129 -0
- package/hooks/blocking/state_description_blocker.py +1 -1
- package/hooks/blocking/stop_dispatcher.py +1 -1
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +2 -3
- package/hooks/blocking/test_code_review_pr_create_gate.py +14 -0
- package/hooks/blocking/test_code_review_push_gate.py +16 -0
- package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +19 -0
- package/hooks/blocking/test_eli11_reply_enforcer.py +457 -0
- package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +231 -0
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +10 -1
- package/hooks/blocking/test_shell_substitution_blocker.py +124 -0
- package/hooks/blocking/test_stop_dispatcher.py +23 -0
- package/hooks/blocking/test_unscoped_search_blocker.py +102 -0
- package/hooks/blocking/test_verdict_directory_write_blocker.py +804 -808
- package/hooks/blocking/test_verification_verdict_store.py +54 -0
- package/hooks/blocking/test_verified_commit_gate.py +581 -581
- package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -131
- package/hooks/blocking/unscoped_search_blocker.py +391 -0
- package/hooks/blocking/verdict_directory_write_blocker.py +687 -687
- package/hooks/blocking/verification_verdict_store.py +1039 -1036
- package/hooks/blocking/verified_commit_message_accuracy_blocker.py +167 -167
- package/hooks/blocking/verifier_verdict_minter.py +280 -280
- package/hooks/git-hooks/CLAUDE.md +3 -0
- package/hooks/git-hooks/conftest.py +30 -0
- package/hooks/git-hooks/gate_utils.py +2 -2
- package/hooks/git-hooks/git_hooks_constants/__init__.py +41 -2
- package/hooks/git-hooks/pre_push.py +75 -4
- package/hooks/git-hooks/pre_push_base_reference.py +166 -0
- package/hooks/git-hooks/test_config.py +0 -15
- package/hooks/git-hooks/test_gate_utils.py +3 -15
- package/hooks/git-hooks/test_pre_commit.py +1 -15
- package/hooks/git-hooks/test_pre_push.py +257 -23
- package/hooks/git-hooks/test_pre_push_base_reference.py +339 -0
- package/hooks/hooks.json +10 -12
- package/hooks/hooks_constants/CLAUDE.md +7 -2
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +4 -4
- package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +101 -0
- package/hooks/hooks_constants/enter_worktree_prefetch_constants.py +18 -18
- package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +2 -8
- package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +48 -0
- package/hooks/hooks_constants/ruff_integration_constants.py +16 -0
- package/hooks/hooks_constants/shell_command_segments.py +82 -0
- package/hooks/hooks_constants/shell_substitution_blocker_constants.py +67 -0
- package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -0
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +5 -6
- package/hooks/hooks_constants/test_stop_dispatcher_constants.py +1 -0
- package/hooks/hooks_constants/unscoped_search_blocker_constants.py +153 -0
- package/hooks/lifecycle/enter_worktree_origin_prefetch.py +163 -146
- package/hooks/lifecycle/test_enter_worktree_origin_prefetch.py +185 -178
- package/hooks/pyproject.toml +1 -0
- package/hooks/validators/CLAUDE.md +1 -0
- package/hooks/validators/config/__init__.py +0 -0
- package/hooks/validators/config/directory_exemption_constants.py +183 -0
- package/hooks/validators/config/test_directory_exemption_constants.py +21 -0
- package/hooks/validators/conftest.py +4 -0
- package/hooks/validators/ruff_integration.py +49 -5
- package/hooks/validators/run_all_validators.py +206 -9
- package/hooks/validators/test_directory_exemption_constants.py +185 -0
- package/hooks/validators/test_python_antipattern_checks.py +110 -5
- package/hooks/validators/test_ruff_integration.py +92 -1
- package/hooks/validators/test_run_all_validators.py +115 -68
- package/hooks/validators/test_run_all_validators_pretooluse.py +159 -1
- package/package.json +13 -3
- package/rules/CLAUDE.md +17 -22
- package/rules/agent-spawn-protocol.md +6 -6
- package/rules/anti-corollary-tests.md +1 -1
- package/rules/bdd.md +1 -1
- package/rules/cleanup-temp-files.md +10 -4
- package/rules/code-standards.md +7 -0
- package/rules/conservative-action.md +1 -5
- package/rules/context7.md +0 -4
- package/rules/destructive-commands.md +47 -0
- package/rules/doc-inventory-integrity.md +48 -0
- package/rules/doc-prose-cuts.md +58 -0
- package/rules/docstring-prose-matches-implementation.md +53 -44
- package/rules/durable-post-artifacts.md +0 -4
- package/rules/eli11-replies.md +31 -0
- package/rules/explore-thoroughly.md +4 -4
- package/rules/falsify-before-green.md +68 -0
- package/rules/file-global-constants.md +1 -1
- package/rules/filesystem-search.md +51 -0
- package/rules/gh-cli-conventions.md +27 -0
- package/rules/git-workflow.md +26 -0
- package/rules/hedging-claims.md +9 -0
- package/rules/long-horizon-autonomy.md +0 -4
- package/rules/measurement-denominators.md +48 -0
- package/rules/nas-ssh-invocation.md +23 -5
- package/rules/parallel-tools.md +2 -2
- package/rules/plain-illustrative-docstrings.md +3 -7
- package/rules/plain-language.md +2 -0
- package/rules/proof-of-work-pr-comments.md +0 -4
- package/rules/re-stage-before-commit.md +2 -0
- package/rules/research-mode.md +10 -0
- package/rules/shell-invocation.md +21 -0
- package/rules/testing.md +4 -0
- package/rules/verified-commit-gate-skip.md +3 -27
- package/rules/verify-before-asking.md +5 -0
- package/rules/windows-filesystem-safe.md +1 -1
- package/rules/workers-done-before-complete.md +4 -0
- package/scripts/CLAUDE.md +1 -0
- package/scripts/Capture-PoolHealth.ps1 +410 -0
- package/scripts/Migrate-ShellPolicy.ps1 +1 -1
- package/scripts/_code_review_test_support.py +404 -0
- package/scripts/claude_chain_runner.py +141 -1
- package/scripts/codex_capability_bridge.py +171 -0
- package/scripts/codex_compat_materializer.py +1087 -0
- package/scripts/codex_compat_watcher.py +502 -0
- package/scripts/conftest.py +16 -1
- package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -1
- package/scripts/dev_env_scripts_constants/claude_chain_constants.py +9 -0
- package/scripts/dev_env_scripts_constants/code_review_constants.py +37 -0
- package/scripts/invoke_code_review.py +11 -4
- package/scripts/resolve_worker_spawn.py +626 -626
- package/scripts/spawn_grok_batch.py +672 -672
- package/scripts/sync_to_cursor/rules.py +0 -10
- package/scripts/test_claude_chain_runner.py +131 -0
- package/scripts/test_invoke_code_review.py +85 -908
- package/scripts/test_invoke_code_review_chain.py +70 -0
- package/scripts/test_invoke_code_review_cli.py +192 -0
- package/scripts/test_invoke_code_review_contract.py +256 -0
- package/scripts/test_invoke_code_review_git.py +123 -0
- package/scripts/test_invoke_code_review_mode.py +99 -0
- package/scripts/test_resolve_worker_spawn.py +1014 -1014
- package/scripts/tests/test_code_review_constants.py +80 -0
- package/scripts/tests/test_codex_capability_bridge.py +91 -0
- package/scripts/tests/test_codex_compat_materializer.py +632 -0
- package/scripts/tests/test_codex_compat_watcher.py +599 -0
- package/scripts/tests/test_sync_to_cursor.py +0 -1
- package/skills/CLAUDE.md +2 -0
- package/skills/auditing-claude-config/SKILL.md +114 -114
- package/skills/autoconverge/SKILL.md +427 -427
- package/skills/autoconverge/reference/convergence.md +24 -3
- package/skills/autoconverge/workflow/CLAUDE.md +1 -0
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +3 -3
- package/skills/autoconverge/workflow/converge.contract.test.mjs +1263 -1263
- package/skills/autoconverge/workflow/converge.mjs +168 -1
- package/skills/autoconverge/workflow/converge.p2-advance.test.mjs +202 -0
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +265 -265
- package/skills/bugteam/reference/copilot-gap-analysis.md +1 -1
- package/skills/closeout/SKILL.md +33 -50
- package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +8 -0
- package/skills/codex-review/scripts/run_codex_review.py +233 -1
- package/skills/codex-review/scripts/test_run_codex_review.py +189 -0
- package/skills/condensing-instructions/SKILL.md +72 -0
- package/skills/copilot-review/SKILL.md +119 -119
- package/skills/e-code-review/SKILL.md +52 -0
- package/skills/e-code-review/reference/fix.md +54 -0
- package/skills/e-code-review/reference/loop.md +43 -0
- package/skills/e-code-review/reference/low.md +57 -0
- package/skills/e-code-review/reference/medium.md +153 -0
- package/skills/e-code-review/reference/xhigh.md +182 -0
- package/skills/e-simplify/SKILL.md +97 -0
- package/skills/fresh-branch/CLAUDE.md +1 -1
- package/skills/fresh-branch/SKILL.md +5 -6
- package/skills/fresh-branch/scripts/create_fresh_branch.py +42 -24
- package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +1 -3
- package/skills/fresh-branch/scripts/test_create_fresh_branch.py +30 -126
- package/skills/issue-tracker/SKILL.md +92 -0
- package/skills/issue-tracker/reference/epic-and-sub-issue-model.md +55 -0
- package/skills/issue-tracker/reference/handoff-schema.md +64 -0
- package/skills/issue-tracker/reference/operation-matrix.md +41 -0
- package/skills/orchestrator/SKILL.md +177 -22
- package/skills/orchestrator/scripts/status_gate.py +625 -0
- package/skills/orchestrator/scripts/status_gate_constants/__init__.py +1 -0
- package/skills/orchestrator/scripts/status_gate_constants/config/__init__.py +1 -0
- package/skills/orchestrator/scripts/status_gate_constants/config/constants.py +47 -0
- package/skills/orchestrator/scripts/test_status_gate.py +439 -0
- package/skills/orchestrator-refresh/SKILL.md +129 -35
- package/skills/plan-to-pr/SKILL.md +155 -0
- package/skills/plan-to-pr/reference/final-validation-tasks.md +15 -0
- package/skills/plan-to-pr/reference/model-routing.md +36 -0
- package/skills/plan-to-pr/reference/packet-contract.md +43 -0
- package/skills/plan-to-pr/reference/packet-schema.json +57 -0
- package/skills/plan-to-pr/reference/process-inventory.md +22 -0
- package/skills/plan-to-pr/reference/review-loop.md +33 -0
- package/skills/plan-to-pr/reference/run-record.schema.json +27 -0
- package/skills/plan-to-pr/reference/self-audit-tasks.md +15 -0
- package/skills/plan-to-pr/reference/task-seeds.md +14 -0
- package/skills/plan-to-pr/reference/task-ticket.md +38 -0
- package/skills/plan-to-pr/scripts/config/__init__.py +1 -0
- package/skills/plan-to-pr/scripts/config/constants.py +193 -0
- package/skills/plan-to-pr/scripts/create_packet.py +173 -0
- package/skills/plan-to-pr/scripts/test_create_packet.py +102 -0
- package/skills/plan-to-pr/scripts/test_validate_packet.py +256 -0
- package/skills/plan-to-pr/scripts/test_validate_protocol.py +135 -0
- package/skills/plan-to-pr/scripts/test_validate_run.py +158 -0
- package/skills/plan-to-pr/scripts/validate_packet.py +655 -0
- package/skills/plan-to-pr/scripts/validate_protocol.py +622 -0
- package/skills/plan-to-pr/scripts/validate_run.py +173 -0
- package/skills/plan-to-pr/test_skill_contract.py +207 -0
- package/skills/plan-to-pr/test_task_ticket_contract.py +151 -0
- package/skills/pr-converge/SKILL.md +472 -469
- package/skills/pr-converge/reference/examples.md +3 -3
- package/skills/pr-converge/reference/fix-protocol.md +1 -1
- package/skills/pr-converge/reference/ground-rules.md +7 -4
- package/skills/pr-converge/reference/multi-pr-orchestration.md +4 -1
- package/skills/pr-converge/reference/per-tick.md +5 -5
- package/skills/pr-converge/reference/progress-checklist.md +1 -1
- package/skills/pr-converge/scripts/check_convergence_gates.py +279 -279
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -507
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -84
- package/skills/pr-converge/test_step5_host_branch.py +1 -1
- package/skills/pr-fix-protocol/SKILL.md +1 -1
- package/skills/privacy-hygiene/SKILL.md +68 -68
- package/skills/privacy-hygiene/reference/sweep-procedure.md +1 -1
- package/skills/prototype/workflows/promotion.md +1 -1
- package/skills/release-notes-html/SKILL.md +164 -0
- package/skills/session-log/SKILL.md +1 -1
- package/skills/task-build/CLAUDE.md +8 -7
- package/skills/task-build/SKILL.md +16 -8
- package/skills/task-build/reference/tool-routing.md +19 -0
- package/rules/claude-md-orphan-file.md +0 -28
- package/rules/cleanup-command-forms.md +0 -23
- package/rules/code-reviews.md +0 -11
- package/rules/env-var-table-code-drift.md +0 -10
- package/rules/gh-body-file.md +0 -5
- package/rules/gh-paginate.md +0 -3
- package/rules/hook-prose-matches-detector.md +0 -15
- package/rules/no-historical-clutter.md +0 -26
- package/rules/no-inline-destructive-literals.md +0 -9
- package/rules/no-justification-noise.md +0 -61
- package/rules/package-inventory-stale-entry.md +0 -25
- package/rules/right-sized-engineering.md +0 -28
- package/rules/self-contained-docs.md +0 -17
- package/rules/shell-invocation-policy.md +0 -5
- package/rules/tdd.md +0 -7
- package/skills/closeout/reference/issue-body-templates.md +0 -108
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Specifications for the permission modes the review binary is asked for.
|
|
2
|
+
|
|
3
|
+
The review binary accepts one permission mode for an ordinary caller and a
|
|
4
|
+
different one for root. Naming the wrong mode means the binary refuses the
|
|
5
|
+
call, no review runs, and no stamp is ever minted.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import importlib
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
import pytest
|
|
14
|
+
|
|
15
|
+
from dev_env_scripts_constants import code_review_constants
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
BYPASS_MODE_TOKEN: str = "bypassPermissions"
|
|
19
|
+
ACCEPT_EDITS_MODE_TOKEN: str = "acceptEdits"
|
|
20
|
+
ROOT_USER_ID: int = 0
|
|
21
|
+
UNPRIVILEGED_USER_ID: int = 1000
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _permission_mode_seen_by(
|
|
25
|
+
monkeypatch: pytest.MonkeyPatch, effective_user_id: int
|
|
26
|
+
) -> str:
|
|
27
|
+
"""Read the review permission mode a caller with this user id resolves."""
|
|
28
|
+
monkeypatch.setattr(os, "geteuid", lambda: effective_user_id)
|
|
29
|
+
reloaded_constants = importlib.reload(code_review_constants)
|
|
30
|
+
return str(reloaded_constants.REVIEW_PERMISSION_MODE)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_root_detection_agrees_with_this_process(
|
|
34
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
35
|
+
) -> None:
|
|
36
|
+
monkeypatch.setattr(os, "geteuid", lambda: ROOT_USER_ID)
|
|
37
|
+
reloaded_constants = importlib.reload(code_review_constants)
|
|
38
|
+
|
|
39
|
+
assert reloaded_constants.IS_ROOT_CALLER is True
|
|
40
|
+
assert reloaded_constants.ROOT_EFFECTIVE_USER_ID == ROOT_USER_ID
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_bypass_mode_names_the_token_the_binary_reads() -> None:
|
|
44
|
+
assert code_review_constants.PERMISSION_MODE_BYPASS == BYPASS_MODE_TOKEN
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_accept_edits_mode_names_the_token_the_binary_reads() -> None:
|
|
48
|
+
assert code_review_constants.PERMISSION_MODE_ACCEPT_EDITS == ACCEPT_EDITS_MODE_TOKEN
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_a_root_caller_resolves_the_mode_the_binary_accepts(
|
|
52
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
53
|
+
) -> None:
|
|
54
|
+
assert _permission_mode_seen_by(monkeypatch, ROOT_USER_ID) == (
|
|
55
|
+
ACCEPT_EDITS_MODE_TOKEN
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_an_ordinary_caller_resolves_the_bypass_mode(
|
|
60
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
61
|
+
) -> None:
|
|
62
|
+
assert _permission_mode_seen_by(monkeypatch, UNPRIVILEGED_USER_ID) == (
|
|
63
|
+
BYPASS_MODE_TOKEN
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_a_platform_without_a_user_id_still_loads_the_constants(
|
|
68
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
69
|
+
) -> None:
|
|
70
|
+
"""Windows exposes no ``os.geteuid``, and the module still imports.
|
|
71
|
+
|
|
72
|
+
Reading a missing ``os.geteuid`` raises, and every caller of the review
|
|
73
|
+
invoker dies at import. A platform that reports no user id is never the
|
|
74
|
+
root the review binary refuses, so it reads as an ordinary caller.
|
|
75
|
+
"""
|
|
76
|
+
monkeypatch.delattr(os, "geteuid", raising=False)
|
|
77
|
+
reloaded_constants = importlib.reload(code_review_constants)
|
|
78
|
+
|
|
79
|
+
assert reloaded_constants.IS_ROOT_CALLER is False
|
|
80
|
+
assert reloaded_constants.REVIEW_PERMISSION_MODE == BYPASS_MODE_TOKEN
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from codex_capability_bridge import translate_capability
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.mark.parametrize("source_surface, expected_target, capability_payload", [("TaskList", "update_plan", {"plan": []}), ("TaskCreate", "update_plan", {"name": "review", "status": "pending"}), ("TaskUpdate", "update_plan", {"name": "review", "status": "pending"}), ("Task", "multi_agent_v1__spawn_agent", {"prompt": "review"}), ("SendMessage", "multi_agent_v1__send_input", {"message": "review"}), ("TaskOutput", "multi_agent_v1__wait_agent", {"task_id": "task-1"}), ("TaskStop", "multi_agent_v1__close_agent", {"task_id": "task-1"})])
|
|
12
|
+
def test_maps_capability(source_surface: str, expected_target: str, capability_payload: dict[str, object]) -> None:
|
|
13
|
+
translated_record = translate_capability(source_surface, capability_payload)
|
|
14
|
+
assert translated_record["target"] == expected_target
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_normalizes_alias_and_task_payload() -> None:
|
|
18
|
+
translated_record = translate_capability("task_create", {"subject": "write tests", "status": "in-progress"})
|
|
19
|
+
assert translated_record["payload"] == {"plan": [{"step": "write tests", "status": "in_progress"}]}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_rejects_bad_payload_and_schedule() -> None:
|
|
23
|
+
assert translate_capability("TaskUpdate", {"name": "x", "status": "later"})["status"] == "malformed"
|
|
24
|
+
assert translate_capability("ScheduleWakeup", {})["status"] == "unsupported"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_rejects_unknown_and_private_paths() -> None:
|
|
28
|
+
assert translate_capability("NoSuchSurface", {})["status"] == "unknown"
|
|
29
|
+
assert translate_capability("SendMessage", {"message": "C:\\Users\\melan\\secret"})["status"] == "rejected"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@pytest.mark.parametrize("private_path", ["C:/private/file", "\\\\server\\share\\file", "/private/file", "~/secret", "$HOME/secret", "%USERPROFILE%\\secret", "safe/../secret"])
|
|
33
|
+
def test_rejects_absolute_private_and_traversal_paths(private_path: str) -> None:
|
|
34
|
+
assert translate_capability("SendMessage", {"message": private_path})["status"] == "rejected"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_validates_mapped_surface_payloads() -> None:
|
|
38
|
+
assert translate_capability("spawn", {"message": "hello"})["status"] == "malformed"
|
|
39
|
+
assert translate_capability("stop", {"task_id": 3})["status"] == "malformed"
|
|
40
|
+
assert translate_capability("TaskList", {"plan": [{"step": "review"}]})["status"] == "malformed"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_translation_is_byte_identical_for_repeated_input() -> None:
|
|
44
|
+
payload = {"message": "hello", "agent_id": "agent-1"}
|
|
45
|
+
first_json = json.dumps(translate_capability("message", payload), sort_keys=True, separators=(",", ":"))
|
|
46
|
+
second_json = json.dumps(translate_capability("message", payload), sort_keys=True, separators=(",", ":"))
|
|
47
|
+
assert first_json == second_json
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_translation_does_not_execute_payload() -> None:
|
|
51
|
+
payload = {"message": "__import__('subprocess').run('whoami')"}
|
|
52
|
+
translated_record = translate_capability("message", payload)
|
|
53
|
+
assert translated_record["payload"] == payload
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_translation_is_deterministic_and_cli_is_json() -> None:
|
|
57
|
+
payload = {"message": "hello", "agent_id": "agent-1"}
|
|
58
|
+
first_record = translate_capability("SendMessage", payload)
|
|
59
|
+
second_record = translate_capability("SendMessage", payload)
|
|
60
|
+
assert first_record == second_record
|
|
61
|
+
script_path = Path(__file__).parents[1] / "codex_capability_bridge.py"
|
|
62
|
+
cli_run = subprocess.run([sys.executable, str(script_path), "SendMessage", json.dumps(payload)], capture_output=True, text=True, check=True)
|
|
63
|
+
assert json.loads(cli_run.stdout) == first_record
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_cli_rejects_malformed_payload_with_one_json_error_record() -> None:
|
|
67
|
+
script_path = Path(__file__).parents[1] / "codex_capability_bridge.py"
|
|
68
|
+
cli_run = subprocess.run(
|
|
69
|
+
[sys.executable, str(script_path), "SendMessage", "{"],
|
|
70
|
+
capture_output=True,
|
|
71
|
+
text=True,
|
|
72
|
+
)
|
|
73
|
+
assert cli_run.returncode != 0
|
|
74
|
+
assert json.loads(cli_run.stdout) == {
|
|
75
|
+
"source": "unknown",
|
|
76
|
+
"status": "error",
|
|
77
|
+
"error": "payload must be valid JSON",
|
|
78
|
+
}
|
|
79
|
+
assert cli_run.stderr == ""
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_cli_rejects_malformed_arguments_with_one_json_error_record() -> None:
|
|
83
|
+
script_path = Path(__file__).parents[1] / "codex_capability_bridge.py"
|
|
84
|
+
cli_run = subprocess.run(
|
|
85
|
+
[sys.executable, str(script_path)],
|
|
86
|
+
capture_output=True,
|
|
87
|
+
text=True,
|
|
88
|
+
)
|
|
89
|
+
assert cli_run.returncode != 0
|
|
90
|
+
assert json.loads(cli_run.stdout)["status"] == "error"
|
|
91
|
+
assert cli_run.stderr == ""
|