@aikidosec/safe-chain 0.0.4-connect-timeout-beta
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.
- package/LICENSE +674 -0
- package/README.md +257 -0
- package/bin/aikido-bun.js +14 -0
- package/bin/aikido-bunx.js +14 -0
- package/bin/aikido-npm.js +14 -0
- package/bin/aikido-npx.js +14 -0
- package/bin/aikido-pip.js +20 -0
- package/bin/aikido-pip3.js +21 -0
- package/bin/aikido-pnpm.js +14 -0
- package/bin/aikido-pnpx.js +14 -0
- package/bin/aikido-python.js +30 -0
- package/bin/aikido-python3.js +30 -0
- package/bin/aikido-uv.js +16 -0
- package/bin/aikido-yarn.js +14 -0
- package/bin/safe-chain.js +190 -0
- package/docs/banner.svg +151 -0
- package/docs/npm-to-binary-migration.md +89 -0
- package/docs/safe-package-manager-demo.gif +0 -0
- package/docs/safe-package-manager-demo.png +0 -0
- package/docs/shell-integration.md +149 -0
- package/package.json +68 -0
- package/src/api/aikido.js +54 -0
- package/src/api/npmApi.js +71 -0
- package/src/config/cliArguments.js +138 -0
- package/src/config/configFile.js +192 -0
- package/src/config/environmentVariables.js +7 -0
- package/src/config/settings.js +100 -0
- package/src/environment/environment.js +14 -0
- package/src/environment/userInteraction.js +122 -0
- package/src/main.js +104 -0
- package/src/packagemanager/_shared/matchesCommand.js +18 -0
- package/src/packagemanager/bun/createBunPackageManager.js +53 -0
- package/src/packagemanager/currentPackageManager.js +72 -0
- package/src/packagemanager/npm/createPackageManager.js +72 -0
- package/src/packagemanager/npm/dependencyScanner/commandArgumentScanner.js +74 -0
- package/src/packagemanager/npm/dependencyScanner/nullScanner.js +9 -0
- package/src/packagemanager/npm/parsing/parsePackagesFromInstallArgs.js +144 -0
- package/src/packagemanager/npm/runNpmCommand.js +25 -0
- package/src/packagemanager/npm/utils/abbrevs-generated.js +359 -0
- package/src/packagemanager/npm/utils/cmd-list.js +174 -0
- package/src/packagemanager/npm/utils/npmCommands.js +34 -0
- package/src/packagemanager/npx/createPackageManager.js +15 -0
- package/src/packagemanager/npx/dependencyScanner/commandArgumentScanner.js +43 -0
- package/src/packagemanager/npx/parsing/parsePackagesFromArguments.js +130 -0
- package/src/packagemanager/npx/runNpxCommand.js +25 -0
- package/src/packagemanager/pip/createPackageManager.js +21 -0
- package/src/packagemanager/pip/pipSettings.js +30 -0
- package/src/packagemanager/pip/runPipCommand.js +175 -0
- package/src/packagemanager/pnpm/createPackageManager.js +57 -0
- package/src/packagemanager/pnpm/dependencyScanner/commandArgumentScanner.js +35 -0
- package/src/packagemanager/pnpm/parsing/parsePackagesFromArguments.js +109 -0
- package/src/packagemanager/pnpm/runPnpmCommand.js +36 -0
- package/src/packagemanager/uv/createUvPackageManager.js +18 -0
- package/src/packagemanager/uv/runUvCommand.js +71 -0
- package/src/packagemanager/yarn/createPackageManager.js +41 -0
- package/src/packagemanager/yarn/dependencyScanner/commandArgumentScanner.js +35 -0
- package/src/packagemanager/yarn/parsing/parsePackagesFromArguments.js +128 -0
- package/src/packagemanager/yarn/runYarnCommand.js +41 -0
- package/src/registryProxy/certBundle.js +95 -0
- package/src/registryProxy/certUtils.js +128 -0
- package/src/registryProxy/http-utils.js +17 -0
- package/src/registryProxy/interceptors/createInterceptorForEcoSystem.js +25 -0
- package/src/registryProxy/interceptors/interceptorBuilder.js +140 -0
- package/src/registryProxy/interceptors/npm/modifyNpmInfo.js +177 -0
- package/src/registryProxy/interceptors/npm/npmInterceptor.js +47 -0
- package/src/registryProxy/interceptors/npm/parseNpmPackageUrl.js +43 -0
- package/src/registryProxy/interceptors/pipInterceptor.js +115 -0
- package/src/registryProxy/mitmRequestHandler.js +231 -0
- package/src/registryProxy/plainHttpProxy.js +95 -0
- package/src/registryProxy/registryProxy.js +184 -0
- package/src/registryProxy/tunnelRequestHandler.js +180 -0
- package/src/scanning/audit/index.js +129 -0
- package/src/scanning/index.js +82 -0
- package/src/scanning/malwareDatabase.js +131 -0
- package/src/shell-integration/helpers.js +213 -0
- package/src/shell-integration/path-wrappers/templates/unix-wrapper.template.sh +22 -0
- package/src/shell-integration/path-wrappers/templates/windows-wrapper.template.cmd +24 -0
- package/src/shell-integration/setup-ci.js +170 -0
- package/src/shell-integration/setup.js +127 -0
- package/src/shell-integration/shellDetection.js +37 -0
- package/src/shell-integration/startup-scripts/include-python/init-fish.fish +94 -0
- package/src/shell-integration/startup-scripts/include-python/init-posix.sh +81 -0
- package/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 +115 -0
- package/src/shell-integration/startup-scripts/init-fish.fish +71 -0
- package/src/shell-integration/startup-scripts/init-posix.sh +58 -0
- package/src/shell-integration/startup-scripts/init-pwsh.ps1 +92 -0
- package/src/shell-integration/supported-shells/bash.js +134 -0
- package/src/shell-integration/supported-shells/fish.js +77 -0
- package/src/shell-integration/supported-shells/powershell.js +73 -0
- package/src/shell-integration/supported-shells/windowsPowershell.js +73 -0
- package/src/shell-integration/supported-shells/zsh.js +74 -0
- package/src/shell-integration/teardown.js +64 -0
- package/src/utils/safeSpawn.js +137 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { ui } from "../environment/userInteraction.js";
|
|
3
|
+
import { getPackageManagerList, knownAikidoTools } from "./helpers.js";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
import { includePython } from "../config/cliArguments.js";
|
|
9
|
+
import { ECOSYSTEM_PY } from "../config/settings.js";
|
|
10
|
+
|
|
11
|
+
/** @type {string} */
|
|
12
|
+
// This checks the current file's dirname in a way that's compatible with:
|
|
13
|
+
// - Modulejs (import.meta.url)
|
|
14
|
+
// - ES modules (__dirname)
|
|
15
|
+
// This is needed because safe-chain's npm package is built using ES modules,
|
|
16
|
+
// but building the binaries requires commonjs.
|
|
17
|
+
let dirname;
|
|
18
|
+
if (import.meta.url) {
|
|
19
|
+
const filename = fileURLToPath(import.meta.url);
|
|
20
|
+
dirname = path.dirname(filename);
|
|
21
|
+
} else {
|
|
22
|
+
dirname = __dirname;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Loops over the detected shells and calls the setup function for each.
|
|
27
|
+
*/
|
|
28
|
+
export async function setupCi() {
|
|
29
|
+
ui.writeInformation(
|
|
30
|
+
chalk.bold("Setting up shell aliases.") +
|
|
31
|
+
` This will wrap safe-chain around ${getPackageManagerList()}.`
|
|
32
|
+
);
|
|
33
|
+
ui.emptyLine();
|
|
34
|
+
|
|
35
|
+
const shimsDir = path.join(os.homedir(), ".safe-chain", "shims");
|
|
36
|
+
const binDir = path.join(os.homedir(), ".safe-chain", "bin");
|
|
37
|
+
// Create the shims directory if it doesn't exist
|
|
38
|
+
if (!fs.existsSync(shimsDir)) {
|
|
39
|
+
fs.mkdirSync(shimsDir, { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
createShims(shimsDir);
|
|
43
|
+
ui.writeInformation(`Created shims in ${shimsDir}`);
|
|
44
|
+
modifyPathForCi(shimsDir, binDir);
|
|
45
|
+
ui.writeInformation(`Added shims directory to PATH for CI environments.`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {string} shimsDir
|
|
50
|
+
*
|
|
51
|
+
* @returns {void}
|
|
52
|
+
*/
|
|
53
|
+
function createUnixShims(shimsDir) {
|
|
54
|
+
// Read the template file
|
|
55
|
+
const templatePath = path.resolve(
|
|
56
|
+
dirname,
|
|
57
|
+
"path-wrappers",
|
|
58
|
+
"templates",
|
|
59
|
+
"unix-wrapper.template.sh"
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (!fs.existsSync(templatePath)) {
|
|
63
|
+
ui.writeError(`Template file not found: ${templatePath}`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const template = fs.readFileSync(templatePath, "utf-8");
|
|
68
|
+
|
|
69
|
+
// Create a shim for each tool
|
|
70
|
+
let created = 0;
|
|
71
|
+
for (const toolInfo of getToolsToSetup()) {
|
|
72
|
+
const shimContent = template
|
|
73
|
+
.replaceAll("{{PACKAGE_MANAGER}}", toolInfo.tool)
|
|
74
|
+
.replaceAll("{{AIKIDO_COMMAND}}", toolInfo.aikidoCommand);
|
|
75
|
+
|
|
76
|
+
const shimPath = path.join(shimsDir, toolInfo.tool);
|
|
77
|
+
fs.writeFileSync(shimPath, shimContent, "utf-8");
|
|
78
|
+
|
|
79
|
+
// Make the shim executable on Unix systems
|
|
80
|
+
fs.chmodSync(shimPath, 0o755);
|
|
81
|
+
created++;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
ui.writeInformation(`Created ${created} Unix shim(s) in ${shimsDir}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {string} shimsDir
|
|
89
|
+
*
|
|
90
|
+
* @returns {void}
|
|
91
|
+
*/
|
|
92
|
+
function createWindowsShims(shimsDir) {
|
|
93
|
+
// Read the template file
|
|
94
|
+
const templatePath = path.resolve(
|
|
95
|
+
dirname,
|
|
96
|
+
"path-wrappers",
|
|
97
|
+
"templates",
|
|
98
|
+
"windows-wrapper.template.cmd"
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
if (!fs.existsSync(templatePath)) {
|
|
102
|
+
ui.writeError(`Windows template file not found: ${templatePath}`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const template = fs.readFileSync(templatePath, "utf-8");
|
|
107
|
+
|
|
108
|
+
// Create a shim for each tool
|
|
109
|
+
let created = 0;
|
|
110
|
+
for (const toolInfo of getToolsToSetup()) {
|
|
111
|
+
const shimContent = template
|
|
112
|
+
.replaceAll("{{PACKAGE_MANAGER}}", toolInfo.tool)
|
|
113
|
+
.replaceAll("{{AIKIDO_COMMAND}}", toolInfo.aikidoCommand);
|
|
114
|
+
|
|
115
|
+
const shimPath = `${shimsDir}/${toolInfo.tool}.cmd`;
|
|
116
|
+
fs.writeFileSync(shimPath, shimContent, "utf-8");
|
|
117
|
+
created++;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
ui.writeInformation(`Created ${created} Windows shim(s) in ${shimsDir}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @param {string} shimsDir
|
|
125
|
+
*
|
|
126
|
+
* @returns {void}
|
|
127
|
+
*/
|
|
128
|
+
function createShims(shimsDir) {
|
|
129
|
+
if (os.platform() === "win32") {
|
|
130
|
+
createWindowsShims(shimsDir);
|
|
131
|
+
} else {
|
|
132
|
+
createUnixShims(shimsDir);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @param {string} shimsDir
|
|
138
|
+
* @param {string} binDir
|
|
139
|
+
*
|
|
140
|
+
* @returns {void}
|
|
141
|
+
*/
|
|
142
|
+
function modifyPathForCi(shimsDir, binDir) {
|
|
143
|
+
if (process.env.GITHUB_PATH) {
|
|
144
|
+
// In GitHub Actions, append the shims directory to GITHUB_PATH
|
|
145
|
+
fs.appendFileSync(
|
|
146
|
+
process.env.GITHUB_PATH,
|
|
147
|
+
shimsDir + os.EOL + binDir + os.EOL,
|
|
148
|
+
"utf-8"
|
|
149
|
+
);
|
|
150
|
+
ui.writeInformation(
|
|
151
|
+
`Added shims directory to GITHUB_PATH for GitHub Actions.`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (process.env.TF_BUILD) {
|
|
156
|
+
// In Azure Pipelines, prepending the path is done via a logging command:
|
|
157
|
+
// ##vso[task.prependpath]/path/to/add
|
|
158
|
+
// Logging this to stdout will cause the Azure Pipelines agent to pick it up
|
|
159
|
+
ui.writeInformation("##vso[task.prependpath]" + shimsDir);
|
|
160
|
+
ui.writeInformation("##vso[task.prependpath]" + binDir);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function getToolsToSetup() {
|
|
165
|
+
if (includePython()) {
|
|
166
|
+
return knownAikidoTools;
|
|
167
|
+
} else {
|
|
168
|
+
return knownAikidoTools.filter((tool) => tool.ecoSystem !== ECOSYSTEM_PY);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { ui } from "../environment/userInteraction.js";
|
|
3
|
+
import { detectShells } from "./shellDetection.js";
|
|
4
|
+
import { knownAikidoTools, getPackageManagerList } from "./helpers.js";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import os from "os";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { includePython } from "../config/cliArguments.js";
|
|
9
|
+
import { fileURLToPath } from "url";
|
|
10
|
+
|
|
11
|
+
/** @type {string} */
|
|
12
|
+
// This checks the current file's dirname in a way that's compatible with:
|
|
13
|
+
// - Modulejs (import.meta.url)
|
|
14
|
+
// - ES modules (__dirname)
|
|
15
|
+
// This is needed because safe-chain's npm package is built using ES modules,
|
|
16
|
+
// but building the binaries requires commonjs.
|
|
17
|
+
let dirname;
|
|
18
|
+
if (import.meta.url) {
|
|
19
|
+
const filename = fileURLToPath(import.meta.url);
|
|
20
|
+
dirname = path.dirname(filename);
|
|
21
|
+
} else {
|
|
22
|
+
dirname = __dirname;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Loops over the detected shells and calls the setup function for each.
|
|
27
|
+
*/
|
|
28
|
+
export async function setup() {
|
|
29
|
+
ui.writeInformation(
|
|
30
|
+
chalk.bold("Setting up shell aliases.") +
|
|
31
|
+
` This will wrap safe-chain around ${getPackageManagerList()}.`
|
|
32
|
+
);
|
|
33
|
+
ui.emptyLine();
|
|
34
|
+
|
|
35
|
+
copyStartupFiles();
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const shells = detectShells();
|
|
39
|
+
if (shells.length === 0) {
|
|
40
|
+
ui.writeError("No supported shells detected. Cannot set up aliases.");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
ui.writeInformation(
|
|
45
|
+
`Detected ${shells.length} supported shell(s): ${shells
|
|
46
|
+
.map((shell) => chalk.bold(shell.name))
|
|
47
|
+
.join(", ")}.`
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
let updatedCount = 0;
|
|
51
|
+
for (const shell of shells) {
|
|
52
|
+
if (setupShell(shell)) {
|
|
53
|
+
updatedCount++;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (updatedCount > 0) {
|
|
58
|
+
ui.emptyLine();
|
|
59
|
+
ui.writeInformation(`Please restart your terminal to apply the changes.`);
|
|
60
|
+
}
|
|
61
|
+
} catch (/** @type {any} */ error) {
|
|
62
|
+
ui.writeError(
|
|
63
|
+
`Failed to set up shell aliases: ${error.message}. Please check your shell configuration.`
|
|
64
|
+
);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Calls the setup function for the given shell and reports the result.
|
|
71
|
+
* @param {import("./shellDetection.js").Shell} shell
|
|
72
|
+
*/
|
|
73
|
+
function setupShell(shell) {
|
|
74
|
+
let success = false;
|
|
75
|
+
let error;
|
|
76
|
+
try {
|
|
77
|
+
shell.teardown(knownAikidoTools); // First, tear down to prevent duplicate aliases
|
|
78
|
+
success = shell.setup(knownAikidoTools);
|
|
79
|
+
} catch (/** @type {any} */ err) {
|
|
80
|
+
success = false;
|
|
81
|
+
error = err;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (success) {
|
|
85
|
+
ui.writeInformation(
|
|
86
|
+
`${chalk.bold("- " + shell.name + ":")} ${chalk.green(
|
|
87
|
+
"Setup successful"
|
|
88
|
+
)}`
|
|
89
|
+
);
|
|
90
|
+
} else {
|
|
91
|
+
ui.writeError(
|
|
92
|
+
`${chalk.bold("- " + shell.name + ":")} ${chalk.red(
|
|
93
|
+
"Setup failed"
|
|
94
|
+
)}. Please check your ${shell.name} configuration.`
|
|
95
|
+
);
|
|
96
|
+
if (error) {
|
|
97
|
+
let message = ` Error: ${error.message}`;
|
|
98
|
+
if (error.code) {
|
|
99
|
+
message += ` (code: ${error.code})`;
|
|
100
|
+
}
|
|
101
|
+
ui.writeError(message);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return success;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function copyStartupFiles() {
|
|
109
|
+
const startupFiles = ["init-posix.sh", "init-pwsh.ps1", "init-fish.fish"];
|
|
110
|
+
|
|
111
|
+
for (const file of startupFiles) {
|
|
112
|
+
const targetDir = path.join(os.homedir(), ".safe-chain", "scripts");
|
|
113
|
+
const targetPath = path.join(os.homedir(), ".safe-chain", "scripts", file);
|
|
114
|
+
|
|
115
|
+
if (!fs.existsSync(targetDir)) {
|
|
116
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Use absolute path for source
|
|
120
|
+
const sourcePath = path.join(
|
|
121
|
+
dirname,
|
|
122
|
+
includePython() ? "startup-scripts/include-python" : "startup-scripts",
|
|
123
|
+
file
|
|
124
|
+
);
|
|
125
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import zsh from "./supported-shells/zsh.js";
|
|
2
|
+
import bash from "./supported-shells/bash.js";
|
|
3
|
+
import powershell from "./supported-shells/powershell.js";
|
|
4
|
+
import windowsPowershell from "./supported-shells/windowsPowershell.js";
|
|
5
|
+
import fish from "./supported-shells/fish.js";
|
|
6
|
+
import { ui } from "../environment/userInteraction.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {Object} Shell
|
|
10
|
+
* @property {string} name
|
|
11
|
+
* @property {() => boolean} isInstalled
|
|
12
|
+
* @property {(tools: import("./helpers.js").AikidoTool[]) => boolean} setup
|
|
13
|
+
* @property {(tools: import("./helpers.js").AikidoTool[]) => boolean} teardown
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @returns {Shell[]}
|
|
18
|
+
*/
|
|
19
|
+
export function detectShells() {
|
|
20
|
+
let possibleShells = [zsh, bash, powershell, windowsPowershell, fish];
|
|
21
|
+
let availableShells = [];
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
for (const shell of possibleShells) {
|
|
25
|
+
if (shell.isInstalled()) {
|
|
26
|
+
availableShells.push(shell);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
} catch (/** @type {any} */ error) {
|
|
30
|
+
ui.writeError(
|
|
31
|
+
`We were not able to detect which shells are installed on your system. Please check your shell configuration. Error: ${error.message}`
|
|
32
|
+
);
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return availableShells;
|
|
37
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
set -gx PATH $PATH $HOME/.safe-chain/bin
|
|
2
|
+
|
|
3
|
+
function npx
|
|
4
|
+
wrapSafeChainCommand "npx" $argv
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
function yarn
|
|
8
|
+
wrapSafeChainCommand "yarn" $argv
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
function pnpm
|
|
12
|
+
wrapSafeChainCommand "pnpm" $argv
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
function pnpx
|
|
16
|
+
wrapSafeChainCommand "pnpx" $argv
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
function bun
|
|
20
|
+
wrapSafeChainCommand "bun" $argv
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
function bunx
|
|
24
|
+
wrapSafeChainCommand "bunx" $argv
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
function npm
|
|
28
|
+
# If args is just -v or --version and nothing else, just run the `npm -v` command
|
|
29
|
+
# This is because nvm uses this to check the version of npm
|
|
30
|
+
set argc (count $argv)
|
|
31
|
+
if test $argc -eq 1
|
|
32
|
+
switch $argv[1]
|
|
33
|
+
case "-v" "--version"
|
|
34
|
+
command npm $argv
|
|
35
|
+
return
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
wrapSafeChainCommand "npm" $argv
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
function pip
|
|
44
|
+
wrapSafeChainCommand "pip" $argv
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
function pip3
|
|
48
|
+
wrapSafeChainCommand "pip3" $argv
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
function uv
|
|
52
|
+
wrapSafeChainCommand "uv" $argv
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# `python -m pip`, `python -m pip3`.
|
|
56
|
+
function python
|
|
57
|
+
wrapSafeChainCommand "python" $argv
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# `python3 -m pip`, `python3 -m pip3'.
|
|
61
|
+
function python3
|
|
62
|
+
wrapSafeChainCommand "python3" $argv
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
function printSafeChainWarning
|
|
66
|
+
set original_cmd $argv[1]
|
|
67
|
+
|
|
68
|
+
# Fish equivalent of ANSI color codes: yellow background, black text for "Warning:"
|
|
69
|
+
set_color -b yellow black
|
|
70
|
+
printf "Warning:"
|
|
71
|
+
set_color normal
|
|
72
|
+
printf " safe-chain is not available to protect you from installing malware. %s will run without it.\n" $original_cmd
|
|
73
|
+
|
|
74
|
+
# Cyan text for the install command
|
|
75
|
+
printf "Install safe-chain by using "
|
|
76
|
+
set_color cyan
|
|
77
|
+
printf "npm install -g @aikidosec/safe-chain"
|
|
78
|
+
set_color normal
|
|
79
|
+
printf ".\n"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
function wrapSafeChainCommand
|
|
83
|
+
set original_cmd $argv[1]
|
|
84
|
+
set cmd_args $argv[2..-1]
|
|
85
|
+
|
|
86
|
+
if type -q safe-chain
|
|
87
|
+
# If the safe-chain command is available, just run it with the provided arguments
|
|
88
|
+
safe-chain $original_cmd $cmd_args
|
|
89
|
+
else
|
|
90
|
+
# If the safe-chain command is not available, print a warning and run the original command
|
|
91
|
+
printSafeChainWarning $original_cmd
|
|
92
|
+
command $original_cmd $cmd_args
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export PATH="$PATH:$HOME/.safe-chain/bin"
|
|
2
|
+
|
|
3
|
+
function npx() {
|
|
4
|
+
wrapSafeChainCommand "npx" "$@"
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function yarn() {
|
|
8
|
+
wrapSafeChainCommand "yarn" "$@"
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function pnpm() {
|
|
12
|
+
wrapSafeChainCommand "pnpm" "$@"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function pnpx() {
|
|
16
|
+
wrapSafeChainCommand "pnpx" "$@"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function bun() {
|
|
20
|
+
wrapSafeChainCommand "bun" "$@"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function bunx() {
|
|
24
|
+
wrapSafeChainCommand "bunx" "$@"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function npm() {
|
|
28
|
+
if [[ "$1" == "-v" || "$1" == "--version" ]] && [[ $# -eq 1 ]]; then
|
|
29
|
+
# If args is just -v or --version and nothing else, just run the npm version command
|
|
30
|
+
# This is because nvm uses this to check the version of npm
|
|
31
|
+
command npm "$@"
|
|
32
|
+
return
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
wrapSafeChainCommand "npm" "$@"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
function pip() {
|
|
40
|
+
wrapSafeChainCommand "pip" "$@"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function pip3() {
|
|
44
|
+
wrapSafeChainCommand "pip3" "$@"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function uv() {
|
|
48
|
+
wrapSafeChainCommand "uv" "$@"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# `python -m pip`, `python -m pip3`.
|
|
52
|
+
function python() {
|
|
53
|
+
wrapSafeChainCommand "python" "$@"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# `python3 -m pip`, `python3 -m pip3'.
|
|
57
|
+
function python3() {
|
|
58
|
+
wrapSafeChainCommand "python3" "$@"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function printSafeChainWarning() {
|
|
62
|
+
# \033[43;30m is used to set the background color to yellow and text color to black
|
|
63
|
+
# \033[0m is used to reset the text formatting
|
|
64
|
+
printf "\033[43;30mWarning:\033[0m safe-chain is not available to protect you from installing malware. %s will run without it.\n" "$1"
|
|
65
|
+
# \033[36m is used to set the text color to cyan
|
|
66
|
+
printf "Install safe-chain by using \033[36mnpm install -g @aikidosec/safe-chain\033[0m.\n"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function wrapSafeChainCommand() {
|
|
70
|
+
local original_cmd="$1"
|
|
71
|
+
|
|
72
|
+
if command -v safe-chain > /dev/null 2>&1; then
|
|
73
|
+
# If the aikido command is available, just run it with the provided arguments
|
|
74
|
+
safe-chain "$@"
|
|
75
|
+
else
|
|
76
|
+
# If the aikido command is not available, print a warning and run the original command
|
|
77
|
+
printSafeChainWarning "$original_cmd"
|
|
78
|
+
|
|
79
|
+
command "$original_cmd" "$@"
|
|
80
|
+
fi
|
|
81
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Use cross-platform path separator (: on Unix, ; on Windows)
|
|
2
|
+
$pathSeparator = if ($IsWindows) { ';' } else { ':' }
|
|
3
|
+
$safeChainBin = Join-Path $HOME '.safe-chain' 'bin'
|
|
4
|
+
$env:PATH = "$env:PATH$pathSeparator$safeChainBin"
|
|
5
|
+
|
|
6
|
+
function npx {
|
|
7
|
+
Invoke-WrappedCommand "npx" $args
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function yarn {
|
|
11
|
+
Invoke-WrappedCommand "yarn" $args
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function pnpm {
|
|
15
|
+
Invoke-WrappedCommand "pnpm" $args
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function pnpx {
|
|
19
|
+
Invoke-WrappedCommand "pnpx" $args
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function bun {
|
|
23
|
+
Invoke-WrappedCommand "bun" $args
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function bunx {
|
|
27
|
+
Invoke-WrappedCommand "bunx" $args
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function npm {
|
|
31
|
+
# If args is just -v or --version and nothing else, just run the npm version command
|
|
32
|
+
# This is because nvm uses this to check the version of npm
|
|
33
|
+
if (($args.Length -eq 1) -and (($args[0] -eq "-v") -or ($args[0] -eq "--version"))) {
|
|
34
|
+
Invoke-RealCommand "npm" $args
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Invoke-WrappedCommand "npm" $args
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function pip {
|
|
42
|
+
Invoke-WrappedCommand "pip" $args
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function pip3 {
|
|
46
|
+
Invoke-WrappedCommand "pip3" $args
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function uv {
|
|
50
|
+
Invoke-WrappedCommand "uv" $args
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# `python -m pip`, `python -m pip3`.
|
|
54
|
+
function python {
|
|
55
|
+
Invoke-WrappedCommand 'python' $args
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# `python3 -m pip`, `python3 -m pip3'.
|
|
59
|
+
function python3 {
|
|
60
|
+
Invoke-WrappedCommand 'python3' $args
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
function Write-SafeChainWarning {
|
|
65
|
+
param([string]$Command)
|
|
66
|
+
|
|
67
|
+
# PowerShell equivalent of ANSI color codes: yellow background, black text for "Warning:"
|
|
68
|
+
Write-Host "Warning:" -BackgroundColor Yellow -ForegroundColor Black -NoNewline
|
|
69
|
+
Write-Host " safe-chain is not available to protect you from installing malware. $Command will run without it."
|
|
70
|
+
|
|
71
|
+
# Cyan text for the install command
|
|
72
|
+
Write-Host "Install safe-chain by using " -NoNewline
|
|
73
|
+
Write-Host "npm install -g @aikidosec/safe-chain" -ForegroundColor Cyan -NoNewline
|
|
74
|
+
Write-Host "."
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function Test-CommandAvailable {
|
|
78
|
+
param([string]$Command)
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
Get-Command $Command -ErrorAction Stop | Out-Null
|
|
82
|
+
return $true
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return $false
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function Invoke-RealCommand {
|
|
90
|
+
param(
|
|
91
|
+
[string]$Command,
|
|
92
|
+
[string[]]$Arguments
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Find the real executable to avoid calling our wrapped functions
|
|
96
|
+
$realCommand = Get-Command -Name $Command -CommandType Application | Select-Object -First 1
|
|
97
|
+
if ($realCommand) {
|
|
98
|
+
& $realCommand.Source @Arguments
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function Invoke-WrappedCommand {
|
|
103
|
+
param(
|
|
104
|
+
[string]$OriginalCmd,
|
|
105
|
+
[string[]]$Arguments
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if (Test-CommandAvailable "safe-chain") {
|
|
109
|
+
& safe-chain $OriginalCmd @Arguments
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
Write-SafeChainWarning $OriginalCmd
|
|
113
|
+
Invoke-RealCommand $OriginalCmd $Arguments
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
set -gx PATH $PATH $HOME/.safe-chain/bin
|
|
2
|
+
|
|
3
|
+
function npx
|
|
4
|
+
wrapSafeChainCommand "npx" $argv
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
function yarn
|
|
8
|
+
wrapSafeChainCommand "yarn" $argv
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
function pnpm
|
|
12
|
+
wrapSafeChainCommand "pnpm" $argv
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
function pnpx
|
|
16
|
+
wrapSafeChainCommand "pnpx" $argv
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
function bun
|
|
20
|
+
wrapSafeChainCommand "bun" $argv
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
function bunx
|
|
24
|
+
wrapSafeChainCommand "bunx" $argv
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
function npm
|
|
28
|
+
# If args is just -v or --version and nothing else, just run the `npm -v` command
|
|
29
|
+
# This is because nvm uses this to check the version of npm
|
|
30
|
+
set argc (count $argv)
|
|
31
|
+
if test $argc -eq 1
|
|
32
|
+
switch $argv[1]
|
|
33
|
+
case "-v" "--version"
|
|
34
|
+
command npm $argv
|
|
35
|
+
return
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
wrapSafeChainCommand "npm" $argv
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
function printSafeChainWarning
|
|
43
|
+
set original_cmd $argv[1]
|
|
44
|
+
|
|
45
|
+
# Fish equivalent of ANSI color codes: yellow background, black text for "Warning:"
|
|
46
|
+
set_color -b yellow black
|
|
47
|
+
printf "Warning:"
|
|
48
|
+
set_color normal
|
|
49
|
+
printf " safe-chain is not available to protect you from installing malware. %s will run without it.\n" $original_cmd
|
|
50
|
+
|
|
51
|
+
# Cyan text for the install command
|
|
52
|
+
printf "Install safe-chain by using "
|
|
53
|
+
set_color cyan
|
|
54
|
+
printf "npm install -g @aikidosec/safe-chain"
|
|
55
|
+
set_color normal
|
|
56
|
+
printf ".\n"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
function wrapSafeChainCommand
|
|
60
|
+
set original_cmd $argv[1]
|
|
61
|
+
set cmd_args $argv[2..-1]
|
|
62
|
+
|
|
63
|
+
if type -q safe-chain
|
|
64
|
+
# If the safe-chain command is available, just run it with the provided arguments
|
|
65
|
+
safe-chain $original_cmd $cmd_args
|
|
66
|
+
else
|
|
67
|
+
# If the safe-chain command is not available, print a warning and run the original command
|
|
68
|
+
printSafeChainWarning $original_cmd
|
|
69
|
+
command $original_cmd $cmd_args
|
|
70
|
+
end
|
|
71
|
+
end
|