codeprobe 0.3.3__tar.gz → 0.3.5__tar.gz
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.
- {codeprobe-0.3.3 → codeprobe-0.3.5}/PKG-INFO +1 -1
- {codeprobe-0.3.3 → codeprobe-0.3.5}/pyproject.toml +1 -1
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/adapters/_base.py +1 -1
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/adapters/claude.py +20 -10
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe.egg-info/PKG-INFO +1 -1
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_adapters.py +46 -13
- {codeprobe-0.3.3 → codeprobe-0.3.5}/LICENSE +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/README.md +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/setup.cfg +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/__main__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/adapters/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/adapters/codex.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/adapters/copilot.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/adapters/openai_compat.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/adapters/protocol.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/adapters/session.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/adapters/telemetry.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/analysis/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/analysis/ranking.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/analysis/report.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/analysis/stats.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/api.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/assess/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/assess/heuristics.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/assess_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/doctor_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/experiment_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/init_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/interpret_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/json_display.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/mine_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/preamble_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/probe_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/ratings_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/rich_display.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/run_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/scaffold_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/validate_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/wizard.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/cli/yaml_writer.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/config/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/config/loader.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/_shared.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/adaptive.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/counterfactual.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/debate.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/decision_tree.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/elo.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/fingerprint.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/mutation.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/pareto.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/sprt.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/contrib/tournament.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/__main__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/checkpoint.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/events.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/executor.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/experiment.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/isolation.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/llm.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/mcp_discovery.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/preamble.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/registry.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/sandbox.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/core/scoring.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/loaders/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/loaders/suite.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/_graph.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/_lang.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/comprehension.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/comprehension_writer.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/curator.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/curator_backends.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/curator_tiers.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/extractor.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/org_scale.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/org_scale_families.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/org_scale_oracle.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/org_scale_scanner.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/org_scale_validate.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/sg_ground_truth.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/sources.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/mining/writer.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/models/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/models/evalrc.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/models/experiment.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/models/preamble.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/models/suite.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/models/task.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/preambles/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/preambles/github.md +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/preambles/sourcegraph.md +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/probe/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/probe/adapter.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/probe/generator.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/probe/writer.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/ratings/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/ratings/collector.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/scaffold/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/scaffold/writer.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/templates/__init__.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/templates/evalrc-mcp-comparison.yaml +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/templates/evalrc-model-comparison.yaml +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe/templates/evalrc-prompt-comparison.yaml +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe.egg-info/SOURCES.txt +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe.egg-info/dependency_links.txt +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe.egg-info/entry_points.txt +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe.egg-info/requires.txt +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/src/codeprobe.egg-info/top_level.txt +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_adapter_contracts.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_analysis.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_api.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_artifact_scorer.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_assess.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_changed_symbols.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_checkpoint.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_checkpoint_scoring.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_cli.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_comprehension.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_config_loader.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_contrib.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_ctrlc_integration.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_curator_backends.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_curator_core.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_curator_integration.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_curator_tiers.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_doctor_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_events.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_executor.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_executor_events.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_experiment_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_experiment_core.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_init_wizard.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_json_display.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_llm.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_loaders.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_mcp_families_mining.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_mcp_validate.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_mine_goals.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_mine_presets.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_mine_profiles.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_mining.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_models.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_new_families.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_openai_compat.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_oracle_types.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_org_scale.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_pipeline_integration.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_preamble.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_preamble_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_probe.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_probe_adapter.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_ratings.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_ratings_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_registry.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_run_config_resolution.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_scaffold.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_scanner_refactor.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_scoring.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_session.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_sg_ground_truth.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_shell_shim.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_show_prompt.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_suite.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_telemetry.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_validate_cmd.py +0 -0
- {codeprobe-0.3.3 → codeprobe-0.3.5}/tests/test_weighted_f1.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeprobe
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
4
4
|
Summary: Benchmark AI coding agents against your own codebase. Mine real tasks from repo history, run agents, interpret results.
|
|
5
5
|
Author: codeprobe contributors
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -158,7 +158,7 @@ class BaseAdapter:
|
|
|
158
158
|
text=True,
|
|
159
159
|
timeout=config.timeout_seconds,
|
|
160
160
|
cwd=config.cwd,
|
|
161
|
-
env=_adapter_safe_env(session_env),
|
|
161
|
+
env=_adapter_safe_env(session_env) if session_env else None,
|
|
162
162
|
)
|
|
163
163
|
except subprocess.TimeoutExpired as exc:
|
|
164
164
|
duration = time.monotonic() - start
|
|
@@ -78,22 +78,32 @@ class ClaudeAdapter(BaseAdapter):
|
|
|
78
78
|
"""Return a per-slot CLAUDE_CONFIG_DIR for session isolation.
|
|
79
79
|
|
|
80
80
|
Copies authentication credentials from the real ``~/.claude/``
|
|
81
|
-
directory so the agent subprocess can authenticate.
|
|
81
|
+
directory so the agent subprocess can authenticate. If no credential
|
|
82
|
+
files are found (e.g. auth lives in the system keychain), skips
|
|
83
|
+
isolation and lets the agent use the real config dir.
|
|
82
84
|
"""
|
|
85
|
+
real_config = Path.home() / ".claude"
|
|
86
|
+
_CRED_NAMES = ("credentials.json", ".credentials.json")
|
|
87
|
+
|
|
88
|
+
# Check whether any copyable credential files exist.
|
|
89
|
+
has_creds = real_config.is_dir() and any(
|
|
90
|
+
(real_config / name).is_file() for name in _CRED_NAMES
|
|
91
|
+
)
|
|
92
|
+
if not has_creds:
|
|
93
|
+
# No file-based credentials found — don't override config dir
|
|
94
|
+
# so the CLI can use keychain / default auth.
|
|
95
|
+
return {}
|
|
96
|
+
|
|
83
97
|
config_dir = (
|
|
84
98
|
Path(tempfile.gettempdir()) / "codeprobe-claude" / f"slot-{slot_id}"
|
|
85
99
|
)
|
|
86
100
|
config_dir.mkdir(parents=True, exist_ok=True)
|
|
87
101
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
src = real_config / name
|
|
94
|
-
dst = config_dir / name
|
|
95
|
-
if src.is_file():
|
|
96
|
-
shutil.copy2(src, dst)
|
|
102
|
+
for name in _CRED_NAMES:
|
|
103
|
+
src = real_config / name
|
|
104
|
+
dst = config_dir / name
|
|
105
|
+
if src.is_file():
|
|
106
|
+
shutil.copy2(src, dst)
|
|
97
107
|
|
|
98
108
|
return {"CLAUDE_CONFIG_DIR": str(config_dir)}
|
|
99
109
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeprobe
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
4
4
|
Summary: Benchmark AI coding agents against your own codebase. Mine real tasks from repo history, run agents, interpret results.
|
|
5
5
|
Author: codeprobe contributors
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -274,9 +274,10 @@ class _StubAdapter(BaseAdapter):
|
|
|
274
274
|
|
|
275
275
|
|
|
276
276
|
class TestBaseAdapterEnvWhitelist:
|
|
277
|
-
"""Verify subprocess.run()
|
|
277
|
+
"""Verify subprocess.run() env handling: inherit when no isolation, filter when isolated."""
|
|
278
278
|
|
|
279
|
-
def
|
|
279
|
+
def test_inherits_full_env_without_session_env(self) -> None:
|
|
280
|
+
"""Without session isolation, subprocess inherits the full parent env."""
|
|
280
281
|
adapter = _StubAdapter()
|
|
281
282
|
config = AgentConfig(timeout_seconds=5)
|
|
282
283
|
fake_result = subprocess.CompletedProcess(
|
|
@@ -286,22 +287,36 @@ class TestBaseAdapterEnvWhitelist:
|
|
|
286
287
|
adapter.run("test", config)
|
|
287
288
|
|
|
288
289
|
_, kwargs = mock_run.call_args
|
|
289
|
-
assert "env"
|
|
290
|
-
|
|
290
|
+
assert kwargs.get("env") is None, "env=None inherits parent process env"
|
|
291
|
+
|
|
292
|
+
def test_filters_env_with_session_env(self) -> None:
|
|
293
|
+
"""With session isolation, subprocess gets a filtered env."""
|
|
294
|
+
adapter = _StubAdapter()
|
|
295
|
+
config = AgentConfig(timeout_seconds=5)
|
|
296
|
+
fake_result = subprocess.CompletedProcess(
|
|
297
|
+
args=["fake-agent"], returncode=0, stdout="ok", stderr=""
|
|
298
|
+
)
|
|
299
|
+
session_env = {"CLAUDE_CONFIG_DIR": "/tmp/test"}
|
|
300
|
+
with patch("subprocess.run", return_value=fake_result) as mock_run:
|
|
301
|
+
adapter.run("test", config, session_env=session_env)
|
|
302
|
+
|
|
303
|
+
env = mock_run.call_args[1]["env"]
|
|
291
304
|
assert isinstance(env, dict)
|
|
305
|
+
assert env.get("CLAUDE_CONFIG_DIR") == "/tmp/test"
|
|
292
306
|
|
|
293
|
-
def
|
|
307
|
+
def test_filtered_env_includes_path_and_home(self) -> None:
|
|
294
308
|
adapter = _StubAdapter()
|
|
295
309
|
config = AgentConfig(timeout_seconds=5)
|
|
296
310
|
fake_result = subprocess.CompletedProcess(
|
|
297
311
|
args=["fake-agent"], returncode=0, stdout="ok", stderr=""
|
|
298
312
|
)
|
|
313
|
+
session_env = {"CLAUDE_CONFIG_DIR": "/tmp/test"}
|
|
299
314
|
with patch("subprocess.run", return_value=fake_result) as mock_run:
|
|
300
315
|
import os
|
|
301
316
|
|
|
302
317
|
old_path = os.environ.get("PATH", "")
|
|
303
318
|
old_home = os.environ.get("HOME", "")
|
|
304
|
-
adapter.run("test", config)
|
|
319
|
+
adapter.run("test", config, session_env=session_env)
|
|
305
320
|
|
|
306
321
|
env = mock_run.call_args[1]["env"]
|
|
307
322
|
if old_path:
|
|
@@ -309,18 +324,19 @@ class TestBaseAdapterEnvWhitelist:
|
|
|
309
324
|
if old_home:
|
|
310
325
|
assert env.get("HOME") == old_home
|
|
311
326
|
|
|
312
|
-
def
|
|
327
|
+
def test_filtered_env_excludes_random_secrets(self) -> None:
|
|
313
328
|
adapter = _StubAdapter()
|
|
314
329
|
config = AgentConfig(timeout_seconds=5)
|
|
315
330
|
fake_result = subprocess.CompletedProcess(
|
|
316
331
|
args=["fake-agent"], returncode=0, stdout="ok", stderr=""
|
|
317
332
|
)
|
|
333
|
+
session_env = {"CLAUDE_CONFIG_DIR": "/tmp/test"}
|
|
318
334
|
import os
|
|
319
335
|
|
|
320
336
|
os.environ["MY_SUPER_SECRET_DB_PASSWORD"] = "hunter2"
|
|
321
337
|
try:
|
|
322
338
|
with patch("subprocess.run", return_value=fake_result) as mock_run:
|
|
323
|
-
adapter.run("test", config)
|
|
339
|
+
adapter.run("test", config, session_env=session_env)
|
|
324
340
|
env = mock_run.call_args[1]["env"]
|
|
325
341
|
assert "MY_SUPER_SECRET_DB_PASSWORD" not in env
|
|
326
342
|
finally:
|
|
@@ -1146,18 +1162,35 @@ class TestClaudeMcpConfig:
|
|
|
1146
1162
|
|
|
1147
1163
|
|
|
1148
1164
|
class TestIsolateSession:
|
|
1149
|
-
def test_claude_isolate_session_returns_config_dir(self) -> None:
|
|
1165
|
+
def test_claude_isolate_session_returns_config_dir(self, tmp_path: Path) -> None:
|
|
1150
1166
|
adapter = ClaudeAdapter()
|
|
1151
|
-
|
|
1167
|
+
fake_home = tmp_path / "home"
|
|
1168
|
+
(fake_home / ".claude").mkdir(parents=True)
|
|
1169
|
+
(fake_home / ".claude" / ".credentials.json").write_text("{}")
|
|
1170
|
+
with patch.object(Path, "home", return_value=fake_home):
|
|
1171
|
+
env = adapter.isolate_session(0)
|
|
1152
1172
|
assert "CLAUDE_CONFIG_DIR" in env
|
|
1153
1173
|
assert "slot-0" in env["CLAUDE_CONFIG_DIR"]
|
|
1154
1174
|
|
|
1155
|
-
def test_claude_isolate_session_different_slots(self) -> None:
|
|
1175
|
+
def test_claude_isolate_session_different_slots(self, tmp_path: Path) -> None:
|
|
1156
1176
|
adapter = ClaudeAdapter()
|
|
1157
|
-
|
|
1158
|
-
|
|
1177
|
+
fake_home = tmp_path / "home"
|
|
1178
|
+
(fake_home / ".claude").mkdir(parents=True)
|
|
1179
|
+
(fake_home / ".claude" / ".credentials.json").write_text("{}")
|
|
1180
|
+
with patch.object(Path, "home", return_value=fake_home):
|
|
1181
|
+
env0 = adapter.isolate_session(0)
|
|
1182
|
+
env1 = adapter.isolate_session(1)
|
|
1159
1183
|
assert env0["CLAUDE_CONFIG_DIR"] != env1["CLAUDE_CONFIG_DIR"]
|
|
1160
1184
|
|
|
1185
|
+
def test_claude_isolate_session_skips_when_no_creds(self, tmp_path: Path) -> None:
|
|
1186
|
+
"""When no credential files exist, returns empty dict."""
|
|
1187
|
+
adapter = ClaudeAdapter()
|
|
1188
|
+
fake_home = tmp_path / "home"
|
|
1189
|
+
(fake_home / ".claude").mkdir(parents=True)
|
|
1190
|
+
with patch.object(Path, "home", return_value=fake_home):
|
|
1191
|
+
env = adapter.isolate_session(0)
|
|
1192
|
+
assert env == {}
|
|
1193
|
+
|
|
1161
1194
|
def test_base_adapter_isolate_session_returns_empty(self) -> None:
|
|
1162
1195
|
adapter = _StubAdapter()
|
|
1163
1196
|
env = adapter.isolate_session(42)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|