diff --git a/README.md b/README.md index f041983..f006331 100644 --- a/README.md +++ b/README.md @@ -98,13 +98,7 @@ You can find all available versions on the [releases page](https://github.com/Ai npm install safe-chain-test ``` - For Python: - - ```shell - pip3 install safe-chain-pi-test - ``` - - - The output should show that Aikido Safe Chain is blocking the installation of these test packages as they are flagged as malware. + - The output should show that Aikido Safe Chain is blocking the installation of this test package as it is flagged as malware. When running `npm`, `npx`, `yarn`, `pnpm`, `pnpx`, `bun`, `bunx`, `pip`, `pip3`, `uv`, `uvx`, `poetry` and `pipx` commands, the Aikido Safe Chain will automatically check for malware in the packages you are trying to install. It also intercepts Python module invocations for pip when available (e.g., `python -m pip install ...`, `python3 -m pip download ...`). If any malware is detected, it will prompt you to exit the command. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 456fe58..9f088cb 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -36,13 +36,7 @@ Verify that malware detection is working: npm install safe-chain-test ``` -**For Python:** - -```bash -pip3 install safe-chain-pi-test -``` - -These test packages are flagged as malware and should be blocked by Safe Chain. +This test package is flagged as malware and should be blocked by Safe Chain. **If the test package installs successfully instead of being blocked**, see [Malware Not Being Blocked](#malware-not-being-blocked) below. diff --git a/test/e2e/pip.e2e.spec.js b/test/e2e/pip.e2e.spec.js index b06978f..f80fbae 100644 --- a/test/e2e/pip.e2e.spec.js +++ b/test/e2e/pip.e2e.spec.js @@ -125,32 +125,6 @@ describe("E2E: pip coverage", () => { ); }); - it(`safe-chain blocks installation of malicious Python packages`, async () => { - const shell = await container.openShell("zsh"); - const result = await shell.runCommand( - "pip3 install --break-system-packages safe-chain-pi-test" - ); - - assert.ok( - result.output.includes("blocked 1 malicious package downloads:"), - `Output did not include expected text. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("safe_chain_pi_test@0.0.1"), - `Output did not include expected text. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Output did not include expected text. Output was:\n${result.output}` - ); - - const listResult = await shell.runCommand("pip3 list"); - assert.ok( - !listResult.output.includes("safe-chain-pi-test"), - `Malicious package was installed despite safe-chain protection. Output of 'pip3 list' was:\n${listResult.output}` - ); - }); - it(`python -m pip routes to aikido-pip (uses pip command)`, async () => { const shell = await container.openShell("zsh"); const result = await shell.runCommand( diff --git a/test/e2e/pipx.e2e.spec.js b/test/e2e/pipx.e2e.spec.js index a554aa6..0e54de8 100644 --- a/test/e2e/pipx.e2e.spec.js +++ b/test/e2e/pipx.e2e.spec.js @@ -37,23 +37,6 @@ describe("E2E: pipx coverage", () => { ); }); - it(`safe-chain blocks installation of malicious Python packages via pipx`, async () => { - const shell = await container.openShell("zsh"); - - const result = await shell.runCommand( - "pipx install safe-chain-pi-test" - ); - - assert.ok( - result.output.includes("blocked by safe-chain"), - `Expected malware to be blocked. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Expected exit message. Output was:\n${result.output}` - ); - }); - it(`pipx upgrade upgrades installed packages`, async () => { const shell = await container.openShell("zsh"); @@ -82,23 +65,6 @@ describe("E2E: pipx coverage", () => { ); }); - it(`pipx run blocks malicious tool download`, async () => { - const shell = await container.openShell("zsh"); - - const result = await shell.runCommand( - "pipx run safe-chain-pi-test --version" - ); - - assert.ok( - result.output.includes("blocked by safe-chain"), - `Expected malicious run to be blocked. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Expected exit message. Output was:\n${result.output}` - ); - }); - it(`pipx runpip installs safe dependency inside an app venv`, async () => { const shell = await container.openShell("zsh"); @@ -115,26 +81,6 @@ describe("E2E: pipx coverage", () => { ); }); - it(`pipx runpip blocks malicious dependency install`, async () => { - const shell = await container.openShell("zsh"); - - // Prepare an app environment - await shell.runCommand("pipx install ruff"); - - const result = await shell.runCommand( - "pipx runpip ruff install safe-chain-pi-test" - ); - - assert.ok( - result.output.includes("blocked by safe-chain"), - `Expected malicious dependency to be blocked. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Expected exit message. Output was:\n${result.output}` - ); - }); - it(`pipx list shows installed packages`, async () => { const shell = await container.openShell("zsh"); @@ -180,21 +126,4 @@ describe("E2E: pipx coverage", () => { ); }); - it('pipx inject blocks malicious packages from being installed into existing venvs', async () => { - const shell = await container.openShell("zsh"); - - await shell.runCommand("pipx install ruff --safe-chain-logging=verbose"); - const result = await shell.runCommand( - "pipx inject ruff safe-chain-pi-test --safe-chain-logging=verbose" - ); - - assert.ok( - result.output.includes("blocked by safe-chain"), - `Expected malicious package to be blocked. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Expected exit message. Output was:\n${result.output}` - ); - }); }); diff --git a/test/e2e/poetry.e2e.spec.js b/test/e2e/poetry.e2e.spec.js index 58b74fd..4fdf947 100644 --- a/test/e2e/poetry.e2e.spec.js +++ b/test/e2e/poetry.e2e.spec.js @@ -63,26 +63,6 @@ describe("E2E: poetry coverage", () => { ); }); - it(`safe-chain blocks installation of malicious Python packages via poetry`, async () => { - const shell = await container.openShell("zsh"); - - await shell.runCommand("mkdir /tmp/test-poetry-malware && cd /tmp/test-poetry-malware"); - await shell.runCommand("cd /tmp/test-poetry-malware && poetry init --no-interaction"); - - const result = await shell.runCommand( - "cd /tmp/test-poetry-malware && poetry add safe-chain-pi-test" - ); - - assert.ok( - result.output.includes("blocked by safe-chain"), - `Expected malware to be blocked. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Expected exit message. Output was:\n${result.output}` - ); - }); - it(`poetry install installs dependencies from pyproject.toml`, async () => { const shell = await container.openShell("zsh"); @@ -291,80 +271,6 @@ describe("E2E: poetry coverage", () => { ); }); - it(`blocks malware during poetry install`, async () => { - const shell = await container.openShell("zsh"); - - // Create a project with malware in dependencies - await shell.runCommand("mkdir /tmp/test-poetry-install-malware && cd /tmp/test-poetry-install-malware"); - await shell.runCommand("cd /tmp/test-poetry-install-malware && poetry init --no-interaction"); - - // Add malware package - this will create lock file and attempt download - const result = await shell.runCommand( - "cd /tmp/test-poetry-install-malware && poetry add safe-chain-pi-test 2>&1" - ); - - assert.ok( - result.output.includes("blocked by safe-chain"), - `Expected malware to be blocked during add (which triggers install). Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Expected exit message. Output was:\n${result.output}` - ); - }); - - it(`blocks malware when updating to add malicious dependency`, async () => { - const shell = await container.openShell("zsh"); - - await shell.runCommand("mkdir /tmp/test-poetry-update-add && cd /tmp/test-poetry-update-add"); - await shell.runCommand("cd /tmp/test-poetry-update-add && poetry init --no-interaction"); - - // Start with a safe dependency - await shell.runCommand("cd /tmp/test-poetry-update-add && poetry add requests"); - - // Now try to add malware via add command - const result = await shell.runCommand( - "cd /tmp/test-poetry-update-add && poetry add safe-chain-pi-test 2>&1" - ); - - assert.ok( - result.output.includes("blocked by safe-chain"), - `Expected malware to be blocked. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Expected exit message. Output was:\n${result.output}` - ); - }); - - it(`blocks malware when installing from requirements with malicious package`, async () => { - const shell = await container.openShell("zsh"); - - await shell.runCommand("mkdir /tmp/test-poetry-req-malware && cd /tmp/test-poetry-req-malware"); - await shell.runCommand("cd /tmp/test-poetry-req-malware && poetry init --no-interaction"); - - // Try to add malware directly - this is the primary vector - const result = await shell.runCommand( - "cd /tmp/test-poetry-req-malware && poetry add safe-chain-pi-test requests 2>&1" - ); - - assert.ok( - result.output.includes("blocked by safe-chain"), - `Expected malware to be blocked. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Expected exit message. Output was:\n${result.output}` - ); - - // Verify safe package was also not installed due to malware in batch - const listResult = await shell.runCommand("cd /tmp/test-poetry-req-malware && poetry show"); - assert.ok( - !listResult.output.includes("requests"), - `Safe package should not be installed when batch includes malware. Output was:\n${listResult.output}` - ); - }); - it(`poetry non-network commands work correctly`, async () => { const shell = await container.openShell("zsh"); diff --git a/test/e2e/safe-chain-cli-python.e2e.spec.js b/test/e2e/safe-chain-cli-python.e2e.spec.js index 15dbf94..818e1b7 100644 --- a/test/e2e/safe-chain-cli-python.e2e.spec.js +++ b/test/e2e/safe-chain-cli-python.e2e.spec.js @@ -92,17 +92,4 @@ describe("E2E: safe-chain CLI python/pip support", () => { ); }); - it("safe-chain blocks malicious package via pip3", async () => { - const shell = await container.openShell("zsh"); - await shell.runCommand("pip3 cache purge"); - - const result = await shell.runCommand( - "safe-chain pip3 install --break-system-packages safe-chain-pi-test" - ); - - assert.ok( - result.output.includes("blocked 1 malicious package downloads"), - `Should have blocked malware. Output was:\n${result.output}` - ); - }); }); diff --git a/test/e2e/uv.e2e.spec.js b/test/e2e/uv.e2e.spec.js index 9d5f3b9..2b28d7d 100644 --- a/test/e2e/uv.e2e.spec.js +++ b/test/e2e/uv.e2e.spec.js @@ -122,33 +122,6 @@ describe("E2E: uv coverage", () => { ); }); - it(`safe-chain blocks installation of malicious Python packages via uv`, async () => { - const shell = await container.openShell("zsh"); - - const result = await shell.runCommand( - "uv pip install --system --break-system-packages safe-chain-pi-test" - ); - - assert.ok( - result.output.includes("blocked 1 malicious package downloads:"), - `Output did not include expected text. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("safe_chain_pi_test@0.0.1"), - `Output did not include expected text. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Output did not include expected text. Output was:\n${result.output}` - ); - - const listResult = await shell.runCommand("uv pip list --system"); - assert.ok( - !listResult.output.includes("safe-chain-pi-test"), - `Malicious package was installed despite safe-chain protection. Output of 'uv pip list' was:\n${listResult.output}` - ); - }); - it(`uv pip install from GitHub URL using the CA bundle`, async () => { const shell = await container.openShell("zsh"); const result = await shell.runCommand( @@ -406,30 +379,6 @@ describe("E2E: uv coverage", () => { ); }); - it(`safe-chain blocks malicious packages via uv add`, async () => { - const shell = await container.openShell("zsh"); - - // Initialize a new uv project - await shell.runCommand("uv init test-project-malware"); - - const result = await shell.runCommand( - "cd test-project-malware && uv add safe-chain-pi-test" - ); - - assert.ok( - result.output.includes("blocked 1 malicious package downloads:"), - `Output did not include expected text. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("safe_chain_pi_test@0.0.1"), - `Output did not include expected text. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Output did not include expected text. Output was:\n${result.output}` - ); - }); - it(`uv tool install installs a global tool`, async () => { const shell = await container.openShell("zsh"); const result = await shell.runCommand( @@ -443,20 +392,6 @@ describe("E2E: uv coverage", () => { ); }); - it(`safe-chain blocks malicious packages via uv tool install`, async () => { - const shell = await container.openShell("zsh"); - const result = await shell.runCommand("uv tool install safe-chain-pi-test"); - - assert.ok( - result.output.includes("blocked 1 malicious package downloads:"), - `Output did not include expected text. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("safe_chain_pi_test@0.0.1"), - `Output did not include expected text. Output was:\n${result.output}` - ); - }); - it(`uv run --with installs ephemeral dependency`, async () => { const shell = await container.openShell("zsh"); @@ -475,22 +410,6 @@ describe("E2E: uv coverage", () => { ); }); - it(`safe-chain blocks malicious packages via uv run --with`, async () => { - const shell = await container.openShell("zsh"); - - // Create a simple Python script - await shell.runCommand("echo 'print(\"test\")' > test_script2.py"); - - const result = await shell.runCommand( - "uv run --with safe-chain-pi-test test_script2.py" - ); - - assert.ok( - result.output.includes("blocked 1 malicious package downloads:"), - `Output did not include expected text. Output was:\n${result.output}` - ); - }); - it(`uv sync syncs project dependencies`, async () => { const shell = await container.openShell("zsh"); diff --git a/test/e2e/uvx.e2e.spec.js b/test/e2e/uvx.e2e.spec.js index 12dfc0f..415f782 100644 --- a/test/e2e/uvx.e2e.spec.js +++ b/test/e2e/uvx.e2e.spec.js @@ -40,23 +40,6 @@ describe("E2E: uvx coverage", () => { ); }); - it(`safe-chain blocks malicious packages via uvx`, async () => { - const shell = await container.openShell("zsh"); - - const result = await shell.runCommand( - "uvx safe-chain-pi-test" - ); - - assert.ok( - result.output.includes("blocked by safe-chain"), - `Expected malicious package to be blocked. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Expected exit message. Output was:\n${result.output}` - ); - }); - it(`uvx with --from flag runs a safe tool`, async () => { const shell = await container.openShell("zsh"); @@ -70,23 +53,6 @@ describe("E2E: uvx coverage", () => { ); }); - it(`uvx with --from flag blocks malicious packages`, async () => { - const shell = await container.openShell("zsh"); - - const result = await shell.runCommand( - "uvx --from safe-chain-pi-test some-command" - ); - - assert.ok( - result.output.includes("blocked by safe-chain"), - `Expected malicious package to be blocked with --from. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Expected exit message. Output was:\n${result.output}` - ); - }); - it(`uvx with specific version runs successfully`, async () => { const shell = await container.openShell("zsh"); @@ -113,20 +79,4 @@ describe("E2E: uvx coverage", () => { ); }); - it(`uvx with --with flag blocks malicious additional dependencies`, async () => { - const shell = await container.openShell("zsh"); - - const result = await shell.runCommand( - "uvx --with safe-chain-pi-test ruff --version" - ); - - assert.ok( - result.output.includes("blocked by safe-chain"), - `Expected malicious --with dependency to be blocked. Output was:\n${result.output}` - ); - assert.ok( - result.output.includes("Exiting without installing malicious packages."), - `Expected exit message. Output was:\n${result.output}` - ); - }); });