mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 12:10:49 +00:00
Update documentation
This commit is contained in:
parent
c85802dd2e
commit
f817bf887a
8 changed files with 82 additions and 20 deletions
20
README.md
20
README.md
|
|
@ -1,8 +1,8 @@
|
||||||
# Aikido Safe Chain
|
# Aikido Safe Chain
|
||||||
|
|
||||||
The Aikido Safe Chain **prevents developers from installing malware** on their workstations through npm, npx, yarn, pnpm, pnpx, bun, and bunx. It's **free** to use and does not require any token.
|
The Aikido Safe Chain **prevents developers from installing malware** on their workstations through npm, npx, yarn, pnpm, pnpx, bun, bunx, and pip. It's **free** to use and does not require any token.
|
||||||
|
|
||||||
The Aikido Safe Chain wraps around the [npm cli](https://github.com/npm/cli), [npx](https://github.com/npm/cli/blob/latest/docs/content/commands/npx.md), [yarn](https://yarnpkg.com/), [pnpm](https://pnpm.io/), [pnpx](https://pnpm.io/cli/dlx), [bun](https://bun.sh/), and [bunx](https://bun.sh/docs/cli/bunx) to provide extra checks before installing new packages. This tool will detect when a package contains malware and prompt you to exit, preventing npm, npx, yarn, pnpm, pnpx, bun, or bunx from downloading or running the malware.
|
The Aikido Safe Chain wraps around the [npm cli](https://github.com/npm/cli), [npx](https://github.com/npm/cli/blob/latest/docs/content/commands/npx.md), [yarn](https://yarnpkg.com/), [pnpm](https://pnpm.io/), [pnpx](https://pnpm.io/cli/dlx), [bun](https://bun.sh/), [bunx](https://bun.sh/docs/cli/bunx), and [pip](https://pip.pypa.io/) to provide extra checks before installing new packages. This tool will detect when a package contains malware and prompt you to exit, preventing npm, npx, yarn, pnpm, pnpx, bun, bunx, or pip from downloading or running the malware.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
@ -15,6 +15,7 @@ Aikido Safe Chain works on Node.js version 18 and above and supports the followi
|
||||||
- ✅ **pnpx**
|
- ✅ **pnpx**
|
||||||
- ✅ **bun**
|
- ✅ **bun**
|
||||||
- ✅ **bunx**
|
- ✅ **bunx**
|
||||||
|
- ✅ **pip** (pip and pip3)
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
|
|
@ -31,14 +32,14 @@ Installing the Aikido Safe Chain is easy. You just need 3 simple steps:
|
||||||
safe-chain setup
|
safe-chain setup
|
||||||
```
|
```
|
||||||
3. **❗Restart your terminal** to start using the Aikido Safe Chain.
|
3. **❗Restart your terminal** to start using the Aikido Safe Chain.
|
||||||
- This step is crucial as it ensures that the shell aliases for npm, npx, yarn, pnpm, pnpx, bun, and bunx are loaded correctly. If you do not restart your terminal, the aliases will not be available.
|
- This step is crucial as it ensures that the shell aliases for npm, npx, yarn, pnpm, pnpx, bun, bunx, and pip/pip3 are loaded correctly. If you do not restart your terminal, the aliases will not be available.
|
||||||
4. **Verify the installation** by running:
|
4. **Verify the installation** by running:
|
||||||
```shell
|
```shell
|
||||||
npm install safe-chain-test
|
npm install safe-chain-test
|
||||||
```
|
```
|
||||||
- The output should show that Aikido Safe Chain is blocking the installation of this package as it is flagged as malware.
|
- The output should show that Aikido Safe Chain is blocking the installation of this package as it is flagged as malware.
|
||||||
|
|
||||||
When running `npm`, `npx`, `yarn`, `pnpm`, `pnpx`, `bun`, or `bunx` commands, the Aikido Safe Chain will automatically check for malware in the packages you are trying to install. If any malware is detected, it will prompt you to exit the command.
|
When running `npm`, `npx`, `yarn`, `pnpm`, `pnpx`, `bun`, `bunx`, or `pip` (including `pip3`) commands, the Aikido Safe Chain will automatically check for malware in the packages you are trying to install. If any malware is detected, it will prompt you to exit the command.
|
||||||
|
|
||||||
You can check the installed version by running:
|
You can check the installed version by running:
|
||||||
```shell
|
```shell
|
||||||
|
|
@ -47,9 +48,9 @@ safe-chain --version
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
The Aikido Safe Chain works by running a lightweight proxy server that intercepts package downloads from the npm registry. When you run npm, npx, yarn, pnpm, pnpx, bun, or bunx commands, all package downloads are routed through this local proxy, which verifies packages in real-time against **[Aikido Intel - Open Sources Threat Intelligence](https://intel.aikido.dev/?tab=malware)**. If malware is detected in any package (including deep dependencies), the proxy blocks the download before the malicious code reaches your machine.
|
The Aikido Safe Chain works by running a lightweight proxy server that intercepts package downloads from the npm registry and PyPI. When you run npm, npx, yarn, pnpm, pnpx, bun, bunx, or pip commands, all package downloads are routed through this local proxy, which verifies packages in real-time against **[Aikido Intel - Open Sources Threat Intelligence](https://intel.aikido.dev/?tab=malware)**. If malware is detected in any package (including deep dependencies), the proxy blocks the download before the malicious code reaches your machine.
|
||||||
|
|
||||||
The Aikido Safe Chain integrates with your shell to provide a seamless experience when using npm, npx, yarn, pnpm, pnpx, bun, and bunx commands. It sets up aliases for these commands so that they are wrapped by the Aikido Safe Chain commands, which manage the proxy server before executing the original commands. We currently support:
|
The Aikido Safe Chain integrates with your shell to provide a seamless experience when using npm, npx, yarn, pnpm, pnpx, bun, bunx, and pip commands. It sets up aliases for these commands so that they are wrapped by the Aikido Safe Chain commands, which manage the proxy server before executing the original commands. We currently support:
|
||||||
|
|
||||||
- ✅ **Bash**
|
- ✅ **Bash**
|
||||||
- ✅ **Zsh**
|
- ✅ **Zsh**
|
||||||
|
|
@ -59,6 +60,13 @@ The Aikido Safe Chain integrates with your shell to provide a seamless experienc
|
||||||
|
|
||||||
More information about the shell integration can be found in the [shell integration documentation](docs/shell-integration.md).
|
More information about the shell integration can be found in the [shell integration documentation](docs/shell-integration.md).
|
||||||
|
|
||||||
|
### Python / pip support
|
||||||
|
|
||||||
|
- Supports `pip` and `pip3` commands.
|
||||||
|
- Scans Python packages fetched by `pip install`, `pip download`, and `pip wheel`.
|
||||||
|
- Intercepts downloads from PyPI and checks them against Aikido's malware intelligence before they reach your machine.
|
||||||
|
- Included automatically when you run `safe-chain setup` (shell integration); **CI integration is not yet available for pip/pip3**.
|
||||||
|
|
||||||
## Uninstallation
|
## Uninstallation
|
||||||
|
|
||||||
To uninstall the Aikido Safe Chain, you can run the following command:
|
To uninstall the Aikido Safe Chain, you can run the following command:
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ function writeHelp() {
|
||||||
ui.writeInformation(
|
ui.writeInformation(
|
||||||
`- ${chalk.cyan(
|
`- ${chalk.cyan(
|
||||||
"safe-chain setup"
|
"safe-chain setup"
|
||||||
)}: This will setup your shell to wrap safe-chain around npm, npx, yarn, pnpm, pnpx, bun and bunx.`
|
)}: This will setup your shell to wrap safe-chain around npm, npx, yarn, pnpm, pnpx, bun, bunx and pip.`
|
||||||
);
|
);
|
||||||
ui.writeInformation(
|
ui.writeInformation(
|
||||||
`- ${chalk.cyan(
|
`- ${chalk.cyan(
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ export const knownAikidoTools = [
|
||||||
{ tool: "pnpx", aikidoCommand: "aikido-pnpx" },
|
{ tool: "pnpx", aikidoCommand: "aikido-pnpx" },
|
||||||
{ tool: "bun", aikidoCommand: "aikido-bun" },
|
{ tool: "bun", aikidoCommand: "aikido-bun" },
|
||||||
{ tool: "bunx", aikidoCommand: "aikido-bunx" },
|
{ tool: "bunx", aikidoCommand: "aikido-bunx" },
|
||||||
|
{ tool: "pip", aikidoCommand: "aikido-pip" },
|
||||||
// When adding a new tool here, also update the documentation for the new tool in the README.md
|
// When adding a new tool here, also update the documentation for the new tool in the README.md
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -181,4 +181,22 @@ describe("removeLinesMatchingPatternTests", () => {
|
||||||
const resultLines = result.split("\n");
|
const resultLines = result.split("\n");
|
||||||
assert.strictEqual(resultLines.length, 5, "Should have exactly 5 lines");
|
assert.strictEqual(resultLines.length, 5, "Should have exactly 5 lines");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should include pip in knownAikidoTools and in the package manager list", async () => {
|
||||||
|
// Import helpers after setting up the mock
|
||||||
|
const { knownAikidoTools, getPackageManagerList } = await import("./helpers.js");
|
||||||
|
|
||||||
|
// Verify pip tool
|
||||||
|
const hasPip = knownAikidoTools.some(
|
||||||
|
(t) => t.tool === "pip" && t.aikidoCommand === "aikido-pip"
|
||||||
|
);
|
||||||
|
assert.ok(hasPip, "knownAikidoTools should include pip");
|
||||||
|
|
||||||
|
// Verify pip appears in the human-readable list
|
||||||
|
const list = getPackageManagerList();
|
||||||
|
assert.ok(
|
||||||
|
/(^|[,\s])pip(,|\s| and)/.test(list) && /commands$/.test(list),
|
||||||
|
`getPackageManagerList should include 'pip' (actual: ${list})`
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,14 @@ function createUnixShims(shimsDir) {
|
||||||
|
|
||||||
const template = fs.readFileSync(templatePath, "utf-8");
|
const template = fs.readFileSync(templatePath, "utf-8");
|
||||||
|
|
||||||
// Create a shim for each tool
|
// Create a shim for each tool except pip for now.
|
||||||
|
// TODO(pip): Enable pip and pip3 CI support
|
||||||
|
let created = 0;
|
||||||
for (const toolInfo of knownAikidoTools) {
|
for (const toolInfo of knownAikidoTools) {
|
||||||
|
if (toolInfo.tool === "pip") {
|
||||||
|
continue; // Skip pip shims in CI for now
|
||||||
|
}
|
||||||
|
|
||||||
const shimContent = template
|
const shimContent = template
|
||||||
.replaceAll("{{PACKAGE_MANAGER}}", toolInfo.tool)
|
.replaceAll("{{PACKAGE_MANAGER}}", toolInfo.tool)
|
||||||
.replaceAll("{{AIKIDO_COMMAND}}", toolInfo.aikidoCommand);
|
.replaceAll("{{AIKIDO_COMMAND}}", toolInfo.aikidoCommand);
|
||||||
|
|
@ -57,10 +63,11 @@ function createUnixShims(shimsDir) {
|
||||||
|
|
||||||
// Make the shim executable on Unix systems
|
// Make the shim executable on Unix systems
|
||||||
fs.chmodSync(shimPath, 0o755);
|
fs.chmodSync(shimPath, 0o755);
|
||||||
|
created++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.writeInformation(
|
ui.writeInformation(
|
||||||
`Created ${knownAikidoTools.length} Unix shim(s) in ${shimsDir}`
|
`Created ${created} Unix shim(s) in ${shimsDir}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,18 +89,25 @@ function createWindowsShims(shimsDir) {
|
||||||
|
|
||||||
const template = fs.readFileSync(templatePath, "utf-8");
|
const template = fs.readFileSync(templatePath, "utf-8");
|
||||||
|
|
||||||
// Create a shim for each tool
|
// Create a shim for each tool except pip for now.
|
||||||
|
// TODO(pip): Enable pip and pip3 CI support
|
||||||
|
let created = 0;
|
||||||
for (const toolInfo of knownAikidoTools) {
|
for (const toolInfo of knownAikidoTools) {
|
||||||
|
if (toolInfo.tool === "pip") {
|
||||||
|
continue; // Skip pip shims in CI for now
|
||||||
|
}
|
||||||
|
|
||||||
const shimContent = template
|
const shimContent = template
|
||||||
.replaceAll("{{PACKAGE_MANAGER}}", toolInfo.tool)
|
.replaceAll("{{PACKAGE_MANAGER}}", toolInfo.tool)
|
||||||
.replaceAll("{{AIKIDO_COMMAND}}", toolInfo.aikidoCommand);
|
.replaceAll("{{AIKIDO_COMMAND}}", toolInfo.aikidoCommand);
|
||||||
|
|
||||||
const shimPath = path.join(shimsDir, `${toolInfo.tool}.cmd`);
|
const shimPath = path.join(shimsDir, `${toolInfo.tool}.cmd`);
|
||||||
fs.writeFileSync(shimPath, shimContent, "utf-8");
|
fs.writeFileSync(shimPath, shimContent, "utf-8");
|
||||||
|
created++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.writeInformation(
|
ui.writeInformation(
|
||||||
`Created ${knownAikidoTools.length} Windows shim(s) in ${shimsDir}`
|
`Created ${created} Windows shim(s) in ${shimsDir}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,3 +68,13 @@ function npm
|
||||||
|
|
||||||
wrapSafeChainCommand "npm" "aikido-npm" $argv
|
wrapSafeChainCommand "npm" "aikido-npm" $argv
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function pip
|
||||||
|
# Default to Python 2 major version when explicitly calling pip
|
||||||
|
wrapSafeChainCommand "pip" "aikido-pip" --target-version-major "2" $argv
|
||||||
|
end
|
||||||
|
|
||||||
|
function pip3
|
||||||
|
# Route to Python 3 when calling pip3
|
||||||
|
wrapSafeChainCommand "pip3" "aikido-pip" --target-version-major "3" $argv
|
||||||
|
end
|
||||||
|
|
|
||||||
|
|
@ -50,15 +50,6 @@ function bunx() {
|
||||||
wrapSafeChainCommand "bunx" "aikido-bunx" "$@"
|
wrapSafeChainCommand "bunx" "aikido-bunx" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
function pip() {
|
|
||||||
wrapSafeChainCommand "pip" "aikido-pip" --target-version-major "2" "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
function pip3() {
|
|
||||||
wrapSafeChainCommand "pip3" "aikido-pip" --target-version-major "3" "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function npm() {
|
function npm() {
|
||||||
if [[ "$1" == "-v" || "$1" == "--version" ]] && [[ $# -eq 1 ]]; then
|
if [[ "$1" == "-v" || "$1" == "--version" ]] && [[ $# -eq 1 ]]; then
|
||||||
# If args is just -v or --version and nothing else, just run the npm version command
|
# If args is just -v or --version and nothing else, just run the npm version command
|
||||||
|
|
@ -69,3 +60,11 @@ function npm() {
|
||||||
|
|
||||||
wrapSafeChainCommand "npm" "aikido-npm" "$@"
|
wrapSafeChainCommand "npm" "aikido-npm" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pip() {
|
||||||
|
wrapSafeChainCommand "pip" "aikido-pip" --target-version-major "2" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function pip3() {
|
||||||
|
wrapSafeChainCommand "pip3" "aikido-pip" --target-version-major "3" "$@"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,3 +86,15 @@ function npm {
|
||||||
|
|
||||||
Invoke-WrappedCommand "npm" "aikido-npm" $args
|
Invoke-WrappedCommand "npm" "aikido-npm" $args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pip {
|
||||||
|
# Default to Python 2 major version when explicitly calling pip
|
||||||
|
$forward = @("--target-version-major", "2") + $args
|
||||||
|
Invoke-WrappedCommand "pip" "aikido-pip" $forward
|
||||||
|
}
|
||||||
|
|
||||||
|
function pip3 {
|
||||||
|
# Route to Python 3 when calling pip3
|
||||||
|
$forward = @("--target-version-major", "3") + $args
|
||||||
|
Invoke-WrappedCommand "pip3" "aikido-pip" $forward
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue