conduct-cli 0.14.0__tar.gz → 0.14.1__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.
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/PKG-INFO +1 -1
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/pyproject.toml +1 -1
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/guard.py +28 -15
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli.egg-info/PKG-INFO +1 -1
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_proxy_env.py +34 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/LICENSE +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/README.md +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/setup.cfg +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/setup.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/__init__.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/api.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/guard_policy.md +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/hooks/__init__.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/hooks/base.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/hooks/posttooluse.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/hooks/precompact.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/hooks/pretooluse.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/hooks/session_parser.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/hooks/session_report_push.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/hooks/session_start.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/hooks/stop.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/log_util.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/main.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/memory.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/paxel.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli/tool_groups.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli.egg-info/SOURCES.txt +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli.egg-info/dependency_links.txt +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli.egg-info/entry_points.txt +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli.egg-info/requires.txt +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/src/conduct_cli.egg-info/top_level.txt +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_advisory_and_hook.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_api_client.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_bash_operator_signature.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_bash_scan_target.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_blast_radius.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_cli_matrix.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_cmd_run.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_command_word_matcher.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_drain_daemon_health.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_guard_approvals.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_guard_policy.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_guard_savings.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_hook_dispatch.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_hook_journal.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_hook_receipt.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_install_all.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_instruction_files.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_journal_drain.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_log_util.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_pretooluse_approval_e2e.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_pretooluse_check_policy.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_proxy_coverage.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_report_tool_coverage.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_signed_policy.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_switch.py +0 -0
- {conduct_cli-0.14.0 → conduct_cli-0.14.1}/tests/test_token_lifecycle.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: conduct-cli
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.1
|
|
4
4
|
Summary: Runtime governance for AI agents. CLI for Conduct AI — secure, govern, install agents, manage projects, run tests
|
|
5
5
|
Author-email: Conduct AI <hello@conductai.ai>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "conduct-cli"
|
|
7
|
-
version = "0.14.
|
|
7
|
+
version = "0.14.1"
|
|
8
8
|
description = "Runtime governance for AI agents. CLI for Conduct AI — secure, govern, install agents, manage projects, run tests"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "Apache-2.0" }
|
|
@@ -1781,6 +1781,24 @@ def _post_local_findings(cfg: dict, base_url: str, findings: list[dict]) -> None
|
|
|
1781
1781
|
print(f" {YELLOW}Audit upload skipped: {e}{RESET}")
|
|
1782
1782
|
|
|
1783
1783
|
|
|
1784
|
+
_LEGACY_CLAUDE_BYPASSES = {
|
|
1785
|
+
"alias claude='env -u ANTHROPIC_BASE_URL claude'",
|
|
1786
|
+
(
|
|
1787
|
+
"function claude { "
|
|
1788
|
+
"$prev=$env:ANTHROPIC_BASE_URL; $env:ANTHROPIC_BASE_URL=$null; "
|
|
1789
|
+
"try { & claude @args } finally { $env:ANTHROPIC_BASE_URL=$prev } }"
|
|
1790
|
+
),
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
|
|
1794
|
+
def _remove_legacy_claude_bypass(content: str) -> str:
|
|
1795
|
+
"""Remove only proxy-bypass aliases previously generated by Conduct."""
|
|
1796
|
+
return "".join(
|
|
1797
|
+
line for line in content.splitlines(keepends=True)
|
|
1798
|
+
if line.strip() not in _LEGACY_CLAUDE_BYPASSES
|
|
1799
|
+
)
|
|
1800
|
+
|
|
1801
|
+
|
|
1784
1802
|
def _write_proxy_env_windows(agent_token: str, proxy_url: str) -> tuple[Path, bool]:
|
|
1785
1803
|
"""Windows equivalent of _write_proxy_env — PowerShell profile + env.ps1."""
|
|
1786
1804
|
CONDUCT_DIR.mkdir(parents=True, exist_ok=True)
|
|
@@ -1814,16 +1832,14 @@ def _write_proxy_env_windows(agent_token: str, proxy_url: str) -> tuple[Path, bo
|
|
|
1814
1832
|
rc = wps5_profile
|
|
1815
1833
|
|
|
1816
1834
|
existing = rc.read_text() if rc.exists() else ""
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
"try { & claude @args } finally { $env:ANTHROPIC_BASE_URL=$prev } }"
|
|
1821
|
-
)
|
|
1835
|
+
cleaned = _remove_legacy_claude_bypass(existing)
|
|
1836
|
+
bypass_removed = cleaned != existing
|
|
1837
|
+
existing = cleaned
|
|
1822
1838
|
PS_SOURCE_LINE = 'if (Test-Path "$HOME/.conduct/env.ps1") { . "$HOME/.conduct/env.ps1" }'
|
|
1823
1839
|
|
|
1824
1840
|
if SHELL_RC_MARKER in existing:
|
|
1825
|
-
if
|
|
1826
|
-
rc.write_text(existing
|
|
1841
|
+
if bypass_removed:
|
|
1842
|
+
rc.write_text(existing)
|
|
1827
1843
|
return rc, True
|
|
1828
1844
|
return rc, False
|
|
1829
1845
|
|
|
@@ -1831,7 +1847,6 @@ def _write_proxy_env_windows(agent_token: str, proxy_url: str) -> tuple[Path, bo
|
|
|
1831
1847
|
addition = (
|
|
1832
1848
|
f"\n\n{SHELL_RC_MARKER}\n"
|
|
1833
1849
|
f"{PS_SOURCE_LINE}\n"
|
|
1834
|
-
f"{CLAUDE_ALIAS}\n"
|
|
1835
1850
|
)
|
|
1836
1851
|
rc.write_text(existing.rstrip() + addition if existing else addition.lstrip())
|
|
1837
1852
|
return rc, True
|
|
@@ -1889,22 +1904,20 @@ def _write_proxy_env(agent_token: str, proxy_url: str) -> tuple[Path, bool]:
|
|
|
1889
1904
|
return Path(), False
|
|
1890
1905
|
|
|
1891
1906
|
existing = rc.read_text() if rc.exists() else ""
|
|
1892
|
-
|
|
1907
|
+
cleaned = _remove_legacy_claude_bypass(existing)
|
|
1908
|
+
bypass_removed = cleaned != existing
|
|
1909
|
+
existing = cleaned
|
|
1893
1910
|
|
|
1894
1911
|
if SHELL_RC_MARKER in existing:
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
rc.write_text(existing.rstrip() + f"\n{CLAUDE_ALIAS}\n")
|
|
1912
|
+
if bypass_removed:
|
|
1913
|
+
rc.write_text(existing)
|
|
1898
1914
|
return rc, True
|
|
1899
1915
|
return rc, False
|
|
1900
1916
|
|
|
1901
1917
|
rc.parent.mkdir(parents=True, exist_ok=True)
|
|
1902
|
-
# ponytail: alias strips ANTHROPIC_BASE_URL so Claude Code auth isn't routed
|
|
1903
|
-
# through the Guard proxy (Claude Code governs agents; it isn't one)
|
|
1904
1918
|
addition = (
|
|
1905
1919
|
f"\n\n{SHELL_RC_MARKER}\n"
|
|
1906
1920
|
f"{SHELL_SOURCE_LINE}\n"
|
|
1907
|
-
f"{CLAUDE_ALIAS}\n"
|
|
1908
1921
|
)
|
|
1909
1922
|
rc.write_text(existing.rstrip() + addition if existing else addition.lstrip())
|
|
1910
1923
|
return rc, True
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: conduct-cli
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.1
|
|
4
4
|
Summary: Runtime governance for AI agents. CLI for Conduct AI — secure, govern, install agents, manage projects, run tests
|
|
5
5
|
Author-email: Conduct AI <hello@conductai.ai>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -61,6 +61,26 @@ def test_shell_rc_source_line_added_once_across_multiple_syncs(tmp_path, monkeyp
|
|
|
61
61
|
rc_text = (tmp_path / ".zshrc").read_text()
|
|
62
62
|
assert rc_text.count(guard.SHELL_RC_MARKER) == 1
|
|
63
63
|
assert rc_text.count(guard.SHELL_SOURCE_LINE) == 1
|
|
64
|
+
assert "env -u ANTHROPIC_BASE_URL" not in rc_text
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@pytestmark_posix
|
|
68
|
+
def test_sync_removes_generated_claude_proxy_bypass(tmp_path, monkeypatch):
|
|
69
|
+
_redirect_home(tmp_path, monkeypatch)
|
|
70
|
+
monkeypatch.setenv("SHELL", "/bin/zsh")
|
|
71
|
+
zshrc = tmp_path / ".zshrc"
|
|
72
|
+
custom_alias = "alias claude-work='claude --worktree'"
|
|
73
|
+
zshrc.write_text(
|
|
74
|
+
f"{custom_alias}\n{guard.SHELL_RC_MARKER}\n{guard.SHELL_SOURCE_LINE}\n"
|
|
75
|
+
"alias claude='env -u ANTHROPIC_BASE_URL claude'\n"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
_, changed = guard._write_proxy_env("abc", "https://api.conductai.ai/gateway/v1")
|
|
79
|
+
|
|
80
|
+
content = zshrc.read_text()
|
|
81
|
+
assert changed is True
|
|
82
|
+
assert "env -u ANTHROPIC_BASE_URL" not in content
|
|
83
|
+
assert custom_alias in content
|
|
64
84
|
|
|
65
85
|
|
|
66
86
|
@pytestmark_posix
|
|
@@ -212,6 +232,20 @@ def test_windows_appends_source_line_to_powershell_profile_once(tmp_path, monkey
|
|
|
212
232
|
text = profile.read_text()
|
|
213
233
|
assert text.count(guard.SHELL_RC_MARKER) == 1
|
|
214
234
|
assert text.count('. "$HOME/.conduct/env.ps1"') == 1
|
|
235
|
+
assert "$env:ANTHROPIC_BASE_URL=$null" not in text
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def test_windows_sync_removes_generated_claude_proxy_bypass(tmp_path, monkeypatch):
|
|
239
|
+
_redirect_home_windows(tmp_path, monkeypatch)
|
|
240
|
+
profile = tmp_path / "Documents" / "PowerShell" / "Microsoft.PowerShell_profile.ps1"
|
|
241
|
+
profile.parent.mkdir(parents=True)
|
|
242
|
+
bypass = next(value for value in guard._LEGACY_CLAUDE_BYPASSES if value.startswith("function claude"))
|
|
243
|
+
profile.write_text(f"{guard.SHELL_RC_MARKER}\n{bypass}\n")
|
|
244
|
+
|
|
245
|
+
_, changed = guard._write_proxy_env("abc", "https://api.conductai.ai/gateway/v1")
|
|
246
|
+
|
|
247
|
+
assert changed is True
|
|
248
|
+
assert "$env:ANTHROPIC_BASE_URL=$null" not in profile.read_text()
|
|
215
249
|
|
|
216
250
|
|
|
217
251
|
def test_windows_prefers_ps7_profile_when_no_wps5_exists(tmp_path, monkeypatch):
|
|
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
|