ixt-cli 0.8.0__tar.gz → 0.8.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.
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/PKG-INFO +21 -40
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/README.md +19 -38
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/pyproject.toml +2 -2
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/.gitignore +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/__main__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/backends/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/backends/binary.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/backends/binary_resolver.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/backends/node.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/backends/python.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/argparse_completion.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/cmd_apply.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/cmd_cache.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/cmd_config.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/cmd_info.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/cmd_install.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/cmd_misc.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/cmd_registry.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/cmd_upgrade.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/commands.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/parser.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/cli/render.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/asset_index.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/asset_pattern_cache.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/env_policy.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/flags.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/fs_policy.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/heuristics.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/models.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/registry.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/settings.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/setup_toml.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/config/toml.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/apply.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/apply_actions.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/backend.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/bootstrap.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/cache.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/discover.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/doctor.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/export.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/expose.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/extract.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/hooks.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/identity.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/inject.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/install.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/install_local.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/locks.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/pathlink.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/resolution_stats.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/resolve.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/resolve_cache.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/runtimes.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/save.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/setup_completions.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/setup_path.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/core/upgrade.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/data/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/data/asset_index.json +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/data/heuristics.toml +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/data/registry.toml +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/libs/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/libs/constants.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/libs/fmt.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/libs/logger.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/libs/output.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/libs/req_spec.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/libs/semver.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/libs/shell.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/libs/style.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/net/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/net/github_api.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/net/gitlab_api.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/net/http.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/net/npm.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/net/pypi.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/net/source.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/platform/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/src/ixt/platform/win.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/conftest.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/e2e/README.md +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/e2e/conftest.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/e2e/docker/Dockerfile.alpine +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/e2e/docker/Dockerfile.fedora +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/e2e/docker/Dockerfile.ubuntu +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/e2e/playground_incus.sh +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/e2e/run_e2e_docker.sh +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/e2e/run_e2e_incus.sh +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/e2e/runtime_matrix.sh +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/e2e/test_e2e.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/integration/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/integration/test_lifecycle.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/integration/test_policy_runtime.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/__init__.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_apply.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_argparse_completion.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_asset_index.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_asset_pattern_cache.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_backend.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_binary_backend.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_bootstrap.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_cache.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_cli.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_discover.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_doctor.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_env_policy.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_export.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_expose.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_extract.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_flags.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_fs_policy.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_github_api.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_gitlab_api.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_heuristics.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_hooks.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_http.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_inject.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_install.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_install_local.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_models.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_namespacing.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_node_backend.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_output.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_pathlink.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_platform.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_python_backend.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_registry.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_req_spec.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_resolve.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_resolve_cache.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_runtimes.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_save.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_semver.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_settings.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_setup_path.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_setup_toml.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_source.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_style.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_toml.py +0 -0
- {ixt_cli-0.8.0 → ixt_cli-0.8.1}/tests/unit/test_upgrade.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ixt-cli
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.1
|
|
4
4
|
Summary: Universal CLI tool isolator - manage Python, Node, and binary tools with per-tool isolation
|
|
5
5
|
Project-URL: Homepage, https://gitlab.com/pytgaen-group/ixt
|
|
6
6
|
Project-URL: Repository, https://gitlab.com/pytgaen-group/ixt.git
|
|
7
7
|
Project-URL: Issues, https://gitlab.com/pytgaen-group/ixt/-/issues
|
|
8
|
-
Project-URL: Documentation, https://gitlab.
|
|
8
|
+
Project-URL: Documentation, https://ixt-39f604.gitlab.io
|
|
9
9
|
Author-email: Gaëtan Montury <10528250-pytgaen@users.noreply.gitlab.com>
|
|
10
10
|
License: MIT
|
|
11
11
|
Keywords: cli,github,isolation,npm,package-manager,pypi,tool
|
|
@@ -27,7 +27,7 @@ Requires-Python: >=3.10
|
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
|
|
29
29
|
<p align="center">
|
|
30
|
-
<img src="assets/ixt.jpg" alt="ixt" width="600">
|
|
30
|
+
<img src="https://ixt-39f604.gitlab.io/assets/ixt.jpg" alt="ixt" width="600">
|
|
31
31
|
</p>
|
|
32
32
|
|
|
33
33
|
<h1 align="center">ixt — Universal CLI Tool Isolator</h1>
|
|
@@ -40,17 +40,22 @@ Description-Content-Type: text/markdown
|
|
|
40
40
|
</p>
|
|
41
41
|
|
|
42
42
|
<p align="center">
|
|
43
|
-
<img src="assets/wip.jpg" alt="Work in Progress" width="300">
|
|
43
|
+
<img src="https://ixt-39f604.gitlab.io/assets/wip.jpg" alt="Work in Progress" width="300">
|
|
44
44
|
</p>
|
|
45
45
|
|
|
46
46
|
**One CLI for Python, Node, and binary tools — each in its own isolated env.**
|
|
47
|
-
**Optional Linux runtime policy can restrict env vars and filesystem access per tool.**
|
|
48
47
|
|
|
49
48
|
*Zero third-party deps. Zero system pollution. One command, any ecosystem.*
|
|
50
49
|
|
|
50
|
+
- **Day-one GitHub releases** — install a tool the day it ships, without
|
|
51
|
+
waiting for a formula, registry entry, or plugin.
|
|
52
|
+
- **No system runtime needed** — ixt is pure Python stdlib; `uv` and `bun` are
|
|
53
|
+
bootstrapped on first use, so the host does not need Node, npm, or a package
|
|
54
|
+
manager pre-installed.
|
|
55
|
+
|
|
51
56
|
```bash
|
|
52
57
|
ixt tool install ruff # Python (PyPI)
|
|
53
|
-
ixt tool install @anthropic-ai/claude-code #
|
|
58
|
+
ixt tool install @anthropic-ai/claude-code # npm package via bun
|
|
54
59
|
ixt tool install ripgrep # Binary (GitHub — via built-in registry)
|
|
55
60
|
```
|
|
56
61
|
|
|
@@ -62,10 +67,10 @@ From PyPI. The published package is `ixt-cli`; it installs the `ixt` command.
|
|
|
62
67
|
|
|
63
68
|
```bash
|
|
64
69
|
# One-shot via uvx (requires uv)
|
|
65
|
-
uvx --from ixt-cli
|
|
70
|
+
uvx --from ixt-cli ixt --help
|
|
66
71
|
|
|
67
72
|
# Persistent install via uv tool
|
|
68
|
-
uv tool install ixt-cli
|
|
73
|
+
uv tool install ixt-cli
|
|
69
74
|
```
|
|
70
75
|
|
|
71
76
|
Or from source:
|
|
@@ -83,16 +88,16 @@ ixt setup path
|
|
|
83
88
|
|
|
84
89
|
### Integrity verification
|
|
85
90
|
|
|
86
|
-
Release tags are SSH-signed. Installing from PyPI
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
Release tags are SSH-signed. Installing from PyPI does not verify the Git tag
|
|
92
|
+
signature locally. Use the clone flow when you want to verify a signed release
|
|
93
|
+
before installing:
|
|
89
94
|
|
|
90
95
|
```bash
|
|
91
96
|
# Verify the signed tag (requires the maintainer's SSH public key in git's allowed_signers)
|
|
92
97
|
git clone https://gitlab.com/pytgaen-group/ixt.git && cd ixt
|
|
93
98
|
git fetch --tags
|
|
94
|
-
git verify-tag
|
|
95
|
-
git checkout --detach
|
|
99
|
+
git verify-tag vX.Y.Z
|
|
100
|
+
git checkout --detach vX.Y.Z
|
|
96
101
|
uv tool install .
|
|
97
102
|
```
|
|
98
103
|
|
|
@@ -144,30 +149,6 @@ ixt tool install @npm:prettier
|
|
|
144
149
|
ixt tool install @gh:BurntSushi/ripgrep
|
|
145
150
|
```
|
|
146
151
|
|
|
147
|
-
## 🛡️ Runtime policy
|
|
148
|
-
|
|
149
|
-
Dependency isolation is the baseline — but ixt also lets you control **what each tool can see at runtime**: which environment variables it receives, which filesystem paths it can read or write. This is a runtime policy for commands launched through ixt shims, not a sandbox for install-time package-manager scripts. If the install step itself is untrusted, use a disposable VM/container/user.
|
|
150
|
-
|
|
151
|
-
```bash
|
|
152
|
-
# Avoid passing secrets in the runtime environment
|
|
153
|
-
ixt tool config some-cli env base os-common
|
|
154
|
-
ixt tool config some-cli env allow '*RUFF*'
|
|
155
|
-
|
|
156
|
-
# Restrict filesystem at runtime: read-only host, hide ~/.aws and ~/.ssh
|
|
157
|
-
ixt tool config some-cli fs base app-common
|
|
158
|
-
ixt tool config some-cli fs scratch ~/.aws ~/.ssh
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
When a policy is active, the PATH shim becomes a small Python wrapper that — when [bubblewrap](https://github.com/containers/bubblewrap) is installed — runs the tool with PID isolation and a private `/proc`. The filtered env reaches the tool, and `/proc/$PPID/environ` reads from inside cannot recover the host secrets. Filesystem policy also requires bwrap. Without bwrap, env policy still cleans the env reaching the tool but `/proc` reads remain exfiltrable — the shim warns once per session in this **degraded "hygiene-only" mode**. Reset the policy and you're back to a direct symlink with zero overhead.
|
|
162
|
-
|
|
163
|
-
The policy is replayable: declare `env_base`, `env_allow`, `fs_scratch`, etc. inside `ixt.toml` and `ixt tool apply` reproduces it on any machine. Use `IXT_SHIM_DEBUG=1` to dump the effective env, `IXT_POLICY_QUIET=1` to silence the degraded-mode warning, `IXT_DISABLE_BWRAP=1` to force degraded mode for debugging.
|
|
164
|
-
|
|
165
|
-
> ⚠️ **Linux only for now.** Enforcement relies on POSIX `execve` and Linux namespaces. On macOS/Windows the policy is saved to `ixt.json` but **not enforced at runtime** — the tool runs with the full environment.
|
|
166
|
-
> Install [bubblewrap](https://github.com/containers/bubblewrap) for **effective env/fs enforcement**: `sudo apt install bubblewrap` / `sudo dnf install bubblewrap` / `sudo pacman -S bubblewrap` / `sudo apk add bubblewrap`. The env axis runs without it but only as a hygiene measure (cleans logs/traces); the fs axis requires it and errors out otherwise. Network isolation is not implemented yet.
|
|
167
|
-
> This is not a general malware sandbox.
|
|
168
|
-
|
|
169
|
-
[Full policy reference →](https://gitlab.com/pytgaen-group/ixt/-/blob/main/docs/policy/index.md)
|
|
170
|
-
|
|
171
152
|
## 📚 Built-in Registry
|
|
172
153
|
|
|
173
154
|
ixt ships with a built-in registry that maps common tool names to their source. No need to remember the GitHub path:
|
|
@@ -262,12 +243,12 @@ $IXT_CACHE_HOME/ # default ~/.cache/ixt (respects $XDG_CACHE_HOME)
|
|
|
262
243
|
| | uv tool | pipx | npm -g | aqua | mise | proto | **ixt** |
|
|
263
244
|
| ------------------------ | ------- | ---- | ------ | ---- | --------- | ----- | ------- |
|
|
264
245
|
| Python tools (PyPI) | ✅ | ✅ | — | — | ✅ (pipx) | — | ✅ |
|
|
265
|
-
|
|
|
246
|
+
| npm packages | — | — | ✅ | — | ✅ (npm) | — | ✅ |
|
|
266
247
|
| GitHub Releases binaries | — | — | — | ✅ | ✅ (ubi) | ~ | ✅ |
|
|
248
|
+
| Day-one GitHub releases | — | — | — | ❌ | ❌ | ~ | ✅ |
|
|
267
249
|
| Dependency isolation | ✅ | ✅ | ❌ | — | partial | — | ✅ |
|
|
268
250
|
| Fine-grained exposure | — | — | — | — | — | — | ✅ |
|
|
269
|
-
|
|
|
270
|
-
| Bootstrap from scratch | — | — | — | — | curl | curl | ✅ |
|
|
251
|
+
| No system runtime needed | — | — | ❌ | ❌ | ❌ | ❌ | ✅ |
|
|
271
252
|
| Declarative config | — | — | — | YAML | TOML | TOML | TOML |
|
|
272
253
|
|
|
273
254
|
ixt is **not** a runtime version manager (mise, proto, asdf cover that). It manages the **last mile**: install, isolate, expose and group CLI tools across three ecosystems.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="assets/ixt.jpg" alt="ixt" width="600">
|
|
2
|
+
<img src="https://ixt-39f604.gitlab.io/assets/ixt.jpg" alt="ixt" width="600">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<h1 align="center">ixt — Universal CLI Tool Isolator</h1>
|
|
@@ -12,17 +12,22 @@
|
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
<p align="center">
|
|
15
|
-
<img src="assets/wip.jpg" alt="Work in Progress" width="300">
|
|
15
|
+
<img src="https://ixt-39f604.gitlab.io/assets/wip.jpg" alt="Work in Progress" width="300">
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
**One CLI for Python, Node, and binary tools — each in its own isolated env.**
|
|
19
|
-
**Optional Linux runtime policy can restrict env vars and filesystem access per tool.**
|
|
20
19
|
|
|
21
20
|
*Zero third-party deps. Zero system pollution. One command, any ecosystem.*
|
|
22
21
|
|
|
22
|
+
- **Day-one GitHub releases** — install a tool the day it ships, without
|
|
23
|
+
waiting for a formula, registry entry, or plugin.
|
|
24
|
+
- **No system runtime needed** — ixt is pure Python stdlib; `uv` and `bun` are
|
|
25
|
+
bootstrapped on first use, so the host does not need Node, npm, or a package
|
|
26
|
+
manager pre-installed.
|
|
27
|
+
|
|
23
28
|
```bash
|
|
24
29
|
ixt tool install ruff # Python (PyPI)
|
|
25
|
-
ixt tool install @anthropic-ai/claude-code #
|
|
30
|
+
ixt tool install @anthropic-ai/claude-code # npm package via bun
|
|
26
31
|
ixt tool install ripgrep # Binary (GitHub — via built-in registry)
|
|
27
32
|
```
|
|
28
33
|
|
|
@@ -34,10 +39,10 @@ From PyPI. The published package is `ixt-cli`; it installs the `ixt` command.
|
|
|
34
39
|
|
|
35
40
|
```bash
|
|
36
41
|
# One-shot via uvx (requires uv)
|
|
37
|
-
uvx --from ixt-cli
|
|
42
|
+
uvx --from ixt-cli ixt --help
|
|
38
43
|
|
|
39
44
|
# Persistent install via uv tool
|
|
40
|
-
uv tool install ixt-cli
|
|
45
|
+
uv tool install ixt-cli
|
|
41
46
|
```
|
|
42
47
|
|
|
43
48
|
Or from source:
|
|
@@ -55,16 +60,16 @@ ixt setup path
|
|
|
55
60
|
|
|
56
61
|
### Integrity verification
|
|
57
62
|
|
|
58
|
-
Release tags are SSH-signed. Installing from PyPI
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
Release tags are SSH-signed. Installing from PyPI does not verify the Git tag
|
|
64
|
+
signature locally. Use the clone flow when you want to verify a signed release
|
|
65
|
+
before installing:
|
|
61
66
|
|
|
62
67
|
```bash
|
|
63
68
|
# Verify the signed tag (requires the maintainer's SSH public key in git's allowed_signers)
|
|
64
69
|
git clone https://gitlab.com/pytgaen-group/ixt.git && cd ixt
|
|
65
70
|
git fetch --tags
|
|
66
|
-
git verify-tag
|
|
67
|
-
git checkout --detach
|
|
71
|
+
git verify-tag vX.Y.Z
|
|
72
|
+
git checkout --detach vX.Y.Z
|
|
68
73
|
uv tool install .
|
|
69
74
|
```
|
|
70
75
|
|
|
@@ -116,30 +121,6 @@ ixt tool install @npm:prettier
|
|
|
116
121
|
ixt tool install @gh:BurntSushi/ripgrep
|
|
117
122
|
```
|
|
118
123
|
|
|
119
|
-
## 🛡️ Runtime policy
|
|
120
|
-
|
|
121
|
-
Dependency isolation is the baseline — but ixt also lets you control **what each tool can see at runtime**: which environment variables it receives, which filesystem paths it can read or write. This is a runtime policy for commands launched through ixt shims, not a sandbox for install-time package-manager scripts. If the install step itself is untrusted, use a disposable VM/container/user.
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
# Avoid passing secrets in the runtime environment
|
|
125
|
-
ixt tool config some-cli env base os-common
|
|
126
|
-
ixt tool config some-cli env allow '*RUFF*'
|
|
127
|
-
|
|
128
|
-
# Restrict filesystem at runtime: read-only host, hide ~/.aws and ~/.ssh
|
|
129
|
-
ixt tool config some-cli fs base app-common
|
|
130
|
-
ixt tool config some-cli fs scratch ~/.aws ~/.ssh
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
When a policy is active, the PATH shim becomes a small Python wrapper that — when [bubblewrap](https://github.com/containers/bubblewrap) is installed — runs the tool with PID isolation and a private `/proc`. The filtered env reaches the tool, and `/proc/$PPID/environ` reads from inside cannot recover the host secrets. Filesystem policy also requires bwrap. Without bwrap, env policy still cleans the env reaching the tool but `/proc` reads remain exfiltrable — the shim warns once per session in this **degraded "hygiene-only" mode**. Reset the policy and you're back to a direct symlink with zero overhead.
|
|
134
|
-
|
|
135
|
-
The policy is replayable: declare `env_base`, `env_allow`, `fs_scratch`, etc. inside `ixt.toml` and `ixt tool apply` reproduces it on any machine. Use `IXT_SHIM_DEBUG=1` to dump the effective env, `IXT_POLICY_QUIET=1` to silence the degraded-mode warning, `IXT_DISABLE_BWRAP=1` to force degraded mode for debugging.
|
|
136
|
-
|
|
137
|
-
> ⚠️ **Linux only for now.** Enforcement relies on POSIX `execve` and Linux namespaces. On macOS/Windows the policy is saved to `ixt.json` but **not enforced at runtime** — the tool runs with the full environment.
|
|
138
|
-
> Install [bubblewrap](https://github.com/containers/bubblewrap) for **effective env/fs enforcement**: `sudo apt install bubblewrap` / `sudo dnf install bubblewrap` / `sudo pacman -S bubblewrap` / `sudo apk add bubblewrap`. The env axis runs without it but only as a hygiene measure (cleans logs/traces); the fs axis requires it and errors out otherwise. Network isolation is not implemented yet.
|
|
139
|
-
> This is not a general malware sandbox.
|
|
140
|
-
|
|
141
|
-
[Full policy reference →](https://gitlab.com/pytgaen-group/ixt/-/blob/main/docs/policy/index.md)
|
|
142
|
-
|
|
143
124
|
## 📚 Built-in Registry
|
|
144
125
|
|
|
145
126
|
ixt ships with a built-in registry that maps common tool names to their source. No need to remember the GitHub path:
|
|
@@ -234,12 +215,12 @@ $IXT_CACHE_HOME/ # default ~/.cache/ixt (respects $XDG_CACHE_HOME)
|
|
|
234
215
|
| | uv tool | pipx | npm -g | aqua | mise | proto | **ixt** |
|
|
235
216
|
| ------------------------ | ------- | ---- | ------ | ---- | --------- | ----- | ------- |
|
|
236
217
|
| Python tools (PyPI) | ✅ | ✅ | — | — | ✅ (pipx) | — | ✅ |
|
|
237
|
-
|
|
|
218
|
+
| npm packages | — | — | ✅ | — | ✅ (npm) | — | ✅ |
|
|
238
219
|
| GitHub Releases binaries | — | — | — | ✅ | ✅ (ubi) | ~ | ✅ |
|
|
220
|
+
| Day-one GitHub releases | — | — | — | ❌ | ❌ | ~ | ✅ |
|
|
239
221
|
| Dependency isolation | ✅ | ✅ | ❌ | — | partial | — | ✅ |
|
|
240
222
|
| Fine-grained exposure | — | — | — | — | — | — | ✅ |
|
|
241
|
-
|
|
|
242
|
-
| Bootstrap from scratch | — | — | — | — | curl | curl | ✅ |
|
|
223
|
+
| No system runtime needed | — | — | ❌ | ❌ | ❌ | ❌ | ✅ |
|
|
243
224
|
| Declarative config | — | — | — | YAML | TOML | TOML | TOML |
|
|
244
225
|
|
|
245
226
|
ixt is **not** a runtime version manager (mise, proto, asdf cover that). It manages the **last mile**: install, isolate, expose and group CLI tools across three ecosystems.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ixt-cli"
|
|
7
|
-
version = "0.8.
|
|
7
|
+
version = "0.8.1" # to bump
|
|
8
8
|
description = "Universal CLI tool isolator - manage Python, Node, and binary tools with per-tool isolation"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -49,7 +49,7 @@ ixt = "ixt.cli:main"
|
|
|
49
49
|
Homepage = "https://gitlab.com/pytgaen-group/ixt"
|
|
50
50
|
Repository = "https://gitlab.com/pytgaen-group/ixt.git"
|
|
51
51
|
Issues = "https://gitlab.com/pytgaen-group/ixt/-/issues"
|
|
52
|
-
Documentation = "https://gitlab.
|
|
52
|
+
Documentation = "https://ixt-39f604.gitlab.io"
|
|
53
53
|
|
|
54
54
|
[tool.hatch.build.targets.wheel]
|
|
55
55
|
packages = ["src/ixt"]
|
|
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
|