@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,137 @@
|
|
|
1
|
+
import { spawn, execSync } from "child_process";
|
|
2
|
+
import os from "os";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} arg
|
|
6
|
+
*
|
|
7
|
+
* @returns {string}
|
|
8
|
+
*/
|
|
9
|
+
function sanitizeShellArgument(arg) {
|
|
10
|
+
// If argument contains shell metacharacters, wrap in double quotes
|
|
11
|
+
// and escape characters that are special even inside double quotes
|
|
12
|
+
if (hasShellMetaChars(arg)) {
|
|
13
|
+
// Inside double quotes, we need to escape: " $ ` \
|
|
14
|
+
return '"' + escapeDoubleQuoteContent(arg) + '"';
|
|
15
|
+
}
|
|
16
|
+
return arg;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {string} arg
|
|
21
|
+
*
|
|
22
|
+
* @returns {boolean}
|
|
23
|
+
*/
|
|
24
|
+
function hasShellMetaChars(arg) {
|
|
25
|
+
// Shell metacharacters that need escaping
|
|
26
|
+
// These characters have special meaning in shells and need to be quoted
|
|
27
|
+
// Whenever one of these characters is present, we should quote the argument
|
|
28
|
+
// Characters: space, ", &, ', |, ;, <, >, (, ), $, `, \, !, *, ?, [, ], {, }, ~, #
|
|
29
|
+
const shellMetaChars = /[ "&'|;<>()$`\\!*?[\]{}~#]/;
|
|
30
|
+
return shellMetaChars.test(arg);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} arg
|
|
35
|
+
*
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
function escapeDoubleQuoteContent(arg) {
|
|
39
|
+
// Escape special characters for shell safety
|
|
40
|
+
// This escapes ", $, `, and \ by prefixing them with a backslash
|
|
41
|
+
return arg.replace(/(["`$\\])/g, "\\$1");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {string} command
|
|
46
|
+
* @param {string[]} args
|
|
47
|
+
*
|
|
48
|
+
* @returns {string}
|
|
49
|
+
*/
|
|
50
|
+
function buildCommand(command, args) {
|
|
51
|
+
if (args.length === 0) {
|
|
52
|
+
return command;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const escapedArgs = args.map(sanitizeShellArgument);
|
|
56
|
+
|
|
57
|
+
return `${command} ${escapedArgs.join(" ")}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {string} command
|
|
62
|
+
*
|
|
63
|
+
* @returns {string}
|
|
64
|
+
*/
|
|
65
|
+
function resolveCommandPath(command) {
|
|
66
|
+
// command will be "npm", "yarn", etc.
|
|
67
|
+
// Use 'command -v' to find the full path
|
|
68
|
+
const fullPath = execSync(`command -v ${command}`, {
|
|
69
|
+
encoding: "utf8",
|
|
70
|
+
}).trim();
|
|
71
|
+
|
|
72
|
+
if (!fullPath) {
|
|
73
|
+
throw new Error(`Command not found: ${command}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return fullPath;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {string} command
|
|
81
|
+
* @param {string[]} args
|
|
82
|
+
* @param {import("child_process").SpawnOptions} options
|
|
83
|
+
*
|
|
84
|
+
* @returns {Promise<{status: number, stdout: string, stderr: string}>}
|
|
85
|
+
*/
|
|
86
|
+
export async function safeSpawn(command, args, options = {}) {
|
|
87
|
+
// The command is always one of our supported package managers.
|
|
88
|
+
// It should always be alphanumeric or _ or -
|
|
89
|
+
// Reject any command names with suspicious characters
|
|
90
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(command)) {
|
|
91
|
+
throw new Error(`Invalid command name: ${command}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return new Promise((resolve, reject) => {
|
|
95
|
+
// Windows requires shell: true because .bat and .cmd files are not executable
|
|
96
|
+
// without a terminal. On Unix/macOS, we resolve the full path first, then use
|
|
97
|
+
// array args (safer, no escaping needed).
|
|
98
|
+
// See: https://nodejs.org/api/child_process.html#child_processspawncommand-args-options
|
|
99
|
+
let child;
|
|
100
|
+
if (os.platform() === "win32") {
|
|
101
|
+
const fullCommand = buildCommand(command, args);
|
|
102
|
+
child = spawn(fullCommand, { ...options, shell: true });
|
|
103
|
+
} else {
|
|
104
|
+
const fullPath = resolveCommandPath(command);
|
|
105
|
+
child = spawn(fullPath, args, options);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// When stdio is piped, we need to collect the output
|
|
109
|
+
let stdout = "";
|
|
110
|
+
let stderr = "";
|
|
111
|
+
|
|
112
|
+
child.stdout?.on("data", (data) => {
|
|
113
|
+
stdout += data.toString();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
child.stderr?.on("data", (data) => {
|
|
117
|
+
stderr += data.toString();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
child.on("close", (code) => {
|
|
121
|
+
// Code is null if it terminated by a signal. This should never
|
|
122
|
+
// happen in our code. If this happens, return 1 error code.
|
|
123
|
+
|
|
124
|
+
code = code ?? 1;
|
|
125
|
+
|
|
126
|
+
resolve({
|
|
127
|
+
status: code,
|
|
128
|
+
stdout: stdout,
|
|
129
|
+
stderr: stderr,
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
child.on("error", (error) => {
|
|
134
|
+
reject(error);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["es2023"],
|
|
4
|
+
"module": "node16",
|
|
5
|
+
"strict": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"moduleResolution": "node16",
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"checkJs": true,
|
|
10
|
+
"noEmit": true,
|
|
11
|
+
"resolveJsonModule": true
|
|
12
|
+
},
|
|
13
|
+
"include": [
|
|
14
|
+
"src/**/*.js",
|
|
15
|
+
"bin/**/*.js"
|
|
16
|
+
],
|
|
17
|
+
"exclude": [
|
|
18
|
+
"node_modules",
|
|
19
|
+
"src/**/*.spec.js"
|
|
20
|
+
]
|
|
21
|
+
}
|