@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,58 @@
|
|
|
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
|
+
function printSafeChainWarning() {
|
|
39
|
+
# \033[43;30m is used to set the background color to yellow and text color to black
|
|
40
|
+
# \033[0m is used to reset the text formatting
|
|
41
|
+
printf "\033[43;30mWarning:\033[0m safe-chain is not available to protect you from installing malware. %s will run without it.\n" "$1"
|
|
42
|
+
# \033[36m is used to set the text color to cyan
|
|
43
|
+
printf "Install safe-chain by using \033[36mnpm install -g @aikidosec/safe-chain\033[0m.\n"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function wrapSafeChainCommand() {
|
|
47
|
+
local original_cmd="$1"
|
|
48
|
+
|
|
49
|
+
if command -v safe-chain > /dev/null 2>&1; then
|
|
50
|
+
# If the aikido command is available, just run it with the provided arguments
|
|
51
|
+
safe-chain "$@"
|
|
52
|
+
else
|
|
53
|
+
# If the aikido command is not available, print a warning and run the original command
|
|
54
|
+
printSafeChainWarning "$original_cmd"
|
|
55
|
+
|
|
56
|
+
command "$original_cmd" "$@"
|
|
57
|
+
fi
|
|
58
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
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 Write-SafeChainWarning {
|
|
42
|
+
param([string]$Command)
|
|
43
|
+
|
|
44
|
+
# PowerShell equivalent of ANSI color codes: yellow background, black text for "Warning:"
|
|
45
|
+
Write-Host "Warning:" -BackgroundColor Yellow -ForegroundColor Black -NoNewline
|
|
46
|
+
Write-Host " safe-chain is not available to protect you from installing malware. $Command will run without it."
|
|
47
|
+
|
|
48
|
+
# Cyan text for the install command
|
|
49
|
+
Write-Host "Install safe-chain by using " -NoNewline
|
|
50
|
+
Write-Host "npm install -g @aikidosec/safe-chain" -ForegroundColor Cyan -NoNewline
|
|
51
|
+
Write-Host "."
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function Test-CommandAvailable {
|
|
55
|
+
param([string]$Command)
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
Get-Command $Command -ErrorAction Stop | Out-Null
|
|
59
|
+
return $true
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return $false
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function Invoke-RealCommand {
|
|
67
|
+
param(
|
|
68
|
+
[string]$Command,
|
|
69
|
+
[string[]]$Arguments
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Find the real executable to avoid calling our wrapped functions
|
|
73
|
+
$realCommand = Get-Command -Name $Command -CommandType Application | Select-Object -First 1
|
|
74
|
+
if ($realCommand) {
|
|
75
|
+
& $realCommand.Source @Arguments
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function Invoke-WrappedCommand {
|
|
80
|
+
param(
|
|
81
|
+
[string]$OriginalCmd,
|
|
82
|
+
[string[]]$Arguments
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if (Test-CommandAvailable "safe-chain") {
|
|
86
|
+
& safe-chain $OriginalCmd @Arguments
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
Write-SafeChainWarning $OriginalCmd
|
|
90
|
+
Invoke-RealCommand $OriginalCmd $Arguments
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addLineToFile,
|
|
3
|
+
doesExecutableExistOnSystem,
|
|
4
|
+
removeLinesMatchingPattern,
|
|
5
|
+
} from "../helpers.js";
|
|
6
|
+
import { execSync, spawnSync } from "child_process";
|
|
7
|
+
import * as os from "os";
|
|
8
|
+
|
|
9
|
+
const shellName = "Bash";
|
|
10
|
+
const executableName = "bash";
|
|
11
|
+
const startupFileCommand = "echo ~/.bashrc";
|
|
12
|
+
const eol = "\n"; // When bash runs on Windows (e.g., Git Bash or WSL), it expects LF line endings.
|
|
13
|
+
|
|
14
|
+
function isInstalled() {
|
|
15
|
+
return doesExecutableExistOnSystem(executableName);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {import("../helpers.js").AikidoTool[]} tools
|
|
20
|
+
*
|
|
21
|
+
* @returns {boolean}
|
|
22
|
+
*/
|
|
23
|
+
function teardown(tools) {
|
|
24
|
+
const startupFile = getStartupFile();
|
|
25
|
+
|
|
26
|
+
for (const { tool } of tools) {
|
|
27
|
+
// Remove any existing alias for the tool
|
|
28
|
+
removeLinesMatchingPattern(
|
|
29
|
+
startupFile,
|
|
30
|
+
new RegExp(`^alias\\s+${tool}=`),
|
|
31
|
+
eol
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Removes the line that sources the safe-chain bash initialization script (~/.aikido/scripts/init-posix.sh)
|
|
36
|
+
removeLinesMatchingPattern(
|
|
37
|
+
startupFile,
|
|
38
|
+
/^source\s+~\/\.safe-chain\/scripts\/init-posix\.sh/,
|
|
39
|
+
eol
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function setup() {
|
|
46
|
+
const startupFile = getStartupFile();
|
|
47
|
+
|
|
48
|
+
addLineToFile(
|
|
49
|
+
startupFile,
|
|
50
|
+
`source ~/.safe-chain/scripts/init-posix.sh # Safe-chain bash initialization script`,
|
|
51
|
+
eol
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getStartupFile() {
|
|
58
|
+
try {
|
|
59
|
+
var path = execSync(startupFileCommand, {
|
|
60
|
+
encoding: "utf8",
|
|
61
|
+
shell: executableName,
|
|
62
|
+
}).trim();
|
|
63
|
+
|
|
64
|
+
return windowsFixPath(path);
|
|
65
|
+
} catch (/** @type {any} */ error) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`Command failed: ${startupFileCommand}. Error: ${error.message}`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {string} path
|
|
74
|
+
*
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
function windowsFixPath(path) {
|
|
78
|
+
try {
|
|
79
|
+
if (os.platform() !== "win32") {
|
|
80
|
+
return path;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// On windows cygwin bash, paths are returned in format /c/user/..., but we need it in format C:\user\...
|
|
84
|
+
// To convert, the cygpath -w command can be used to convert to the desired format.
|
|
85
|
+
// Cygpath only exists on Cygwin, so we first check if the command is available.
|
|
86
|
+
// If it is, we use it to convert the path.
|
|
87
|
+
if (hasCygpath()) {
|
|
88
|
+
return cygpathw(path);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return path;
|
|
92
|
+
} catch {
|
|
93
|
+
return path;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function hasCygpath() {
|
|
98
|
+
try {
|
|
99
|
+
var result = spawnSync("where", ["cygpath"], { shell: executableName });
|
|
100
|
+
return result.status === 0;
|
|
101
|
+
} catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @param {string} path
|
|
108
|
+
*
|
|
109
|
+
* @returns {string}
|
|
110
|
+
*/
|
|
111
|
+
function cygpathw(path) {
|
|
112
|
+
try {
|
|
113
|
+
var result = spawnSync("cygpath", ["-w", path], {
|
|
114
|
+
encoding: "utf8",
|
|
115
|
+
shell: executableName,
|
|
116
|
+
});
|
|
117
|
+
if (result.status === 0) {
|
|
118
|
+
return result.stdout.trim();
|
|
119
|
+
}
|
|
120
|
+
return path;
|
|
121
|
+
} catch {
|
|
122
|
+
return path;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @type {import("../shellDetection.js").Shell}
|
|
128
|
+
*/
|
|
129
|
+
export default {
|
|
130
|
+
name: shellName,
|
|
131
|
+
isInstalled,
|
|
132
|
+
setup,
|
|
133
|
+
teardown,
|
|
134
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addLineToFile,
|
|
3
|
+
doesExecutableExistOnSystem,
|
|
4
|
+
removeLinesMatchingPattern,
|
|
5
|
+
} from "../helpers.js";
|
|
6
|
+
import { execSync } from "child_process";
|
|
7
|
+
|
|
8
|
+
const shellName = "Fish";
|
|
9
|
+
const executableName = "fish";
|
|
10
|
+
const startupFileCommand = "echo ~/.config/fish/config.fish";
|
|
11
|
+
const eol = "\n"; // When fish runs on Windows (e.g., Git Bash or WSL), it expects LF line endings.
|
|
12
|
+
|
|
13
|
+
function isInstalled() {
|
|
14
|
+
return doesExecutableExistOnSystem(executableName);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {import("../helpers.js").AikidoTool[]} tools
|
|
19
|
+
*
|
|
20
|
+
* @returns {boolean}
|
|
21
|
+
*/
|
|
22
|
+
function teardown(tools) {
|
|
23
|
+
const startupFile = getStartupFile();
|
|
24
|
+
|
|
25
|
+
for (const { tool } of tools) {
|
|
26
|
+
// Remove any existing alias for the tool
|
|
27
|
+
removeLinesMatchingPattern(
|
|
28
|
+
startupFile,
|
|
29
|
+
new RegExp(`^alias\\s+${tool}\\s+`),
|
|
30
|
+
eol
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Removes the line that sources the safe-chain fish initialization script (~/.safe-chain/scripts/init-fish.fish)
|
|
35
|
+
removeLinesMatchingPattern(
|
|
36
|
+
startupFile,
|
|
37
|
+
/^source\s+~\/\.safe-chain\/scripts\/init-fish\.fish/,
|
|
38
|
+
eol
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function setup() {
|
|
45
|
+
const startupFile = getStartupFile();
|
|
46
|
+
|
|
47
|
+
addLineToFile(
|
|
48
|
+
startupFile,
|
|
49
|
+
`source ~/.safe-chain/scripts/init-fish.fish # Safe-chain Fish initialization script`,
|
|
50
|
+
eol
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getStartupFile() {
|
|
57
|
+
try {
|
|
58
|
+
return execSync(startupFileCommand, {
|
|
59
|
+
encoding: "utf8",
|
|
60
|
+
shell: executableName,
|
|
61
|
+
}).trim();
|
|
62
|
+
} catch (/** @type {any} */ error) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Command failed: ${startupFileCommand}. Error: ${error.message}`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @type {import("../shellDetection.js").Shell}
|
|
71
|
+
*/
|
|
72
|
+
export default {
|
|
73
|
+
name: shellName,
|
|
74
|
+
isInstalled,
|
|
75
|
+
setup,
|
|
76
|
+
teardown,
|
|
77
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addLineToFile,
|
|
3
|
+
doesExecutableExistOnSystem,
|
|
4
|
+
removeLinesMatchingPattern,
|
|
5
|
+
} from "../helpers.js";
|
|
6
|
+
import { execSync } from "child_process";
|
|
7
|
+
|
|
8
|
+
const shellName = "PowerShell Core";
|
|
9
|
+
const executableName = "pwsh";
|
|
10
|
+
const startupFileCommand = "echo $PROFILE";
|
|
11
|
+
|
|
12
|
+
function isInstalled() {
|
|
13
|
+
return doesExecutableExistOnSystem(executableName);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {import("../helpers.js").AikidoTool[]} tools
|
|
18
|
+
*
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
function teardown(tools) {
|
|
22
|
+
const startupFile = getStartupFile();
|
|
23
|
+
|
|
24
|
+
for (const { tool } of tools) {
|
|
25
|
+
// Remove any existing alias for the tool
|
|
26
|
+
removeLinesMatchingPattern(
|
|
27
|
+
startupFile,
|
|
28
|
+
new RegExp(`^Set-Alias\\s+${tool}\\s+`)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Remove the line that sources the safe-chain PowerShell initialization script
|
|
33
|
+
removeLinesMatchingPattern(
|
|
34
|
+
startupFile,
|
|
35
|
+
/^\.\s+["']?\$HOME[/\\].safe-chain[/\\]scripts[/\\]init-pwsh\.ps1["']?/
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function setup() {
|
|
42
|
+
const startupFile = getStartupFile();
|
|
43
|
+
|
|
44
|
+
addLineToFile(
|
|
45
|
+
startupFile,
|
|
46
|
+
`. "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1" # Safe-chain PowerShell initialization script`
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getStartupFile() {
|
|
53
|
+
try {
|
|
54
|
+
return execSync(startupFileCommand, {
|
|
55
|
+
encoding: "utf8",
|
|
56
|
+
shell: executableName,
|
|
57
|
+
}).trim();
|
|
58
|
+
} catch (/** @type {any} */ error) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Command failed: ${startupFileCommand}. Error: ${error.message}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @type {import("../shellDetection.js").Shell}
|
|
67
|
+
*/
|
|
68
|
+
export default {
|
|
69
|
+
name: shellName,
|
|
70
|
+
isInstalled,
|
|
71
|
+
setup,
|
|
72
|
+
teardown,
|
|
73
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addLineToFile,
|
|
3
|
+
doesExecutableExistOnSystem,
|
|
4
|
+
removeLinesMatchingPattern,
|
|
5
|
+
} from "../helpers.js";
|
|
6
|
+
import { execSync } from "child_process";
|
|
7
|
+
|
|
8
|
+
const shellName = "Windows PowerShell";
|
|
9
|
+
const executableName = "powershell";
|
|
10
|
+
const startupFileCommand = "echo $PROFILE";
|
|
11
|
+
|
|
12
|
+
function isInstalled() {
|
|
13
|
+
return doesExecutableExistOnSystem(executableName);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {import("../helpers.js").AikidoTool[]} tools
|
|
18
|
+
*
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
function teardown(tools) {
|
|
22
|
+
const startupFile = getStartupFile();
|
|
23
|
+
|
|
24
|
+
for (const { tool } of tools) {
|
|
25
|
+
// Remove any existing alias for the tool
|
|
26
|
+
removeLinesMatchingPattern(
|
|
27
|
+
startupFile,
|
|
28
|
+
new RegExp(`^Set-Alias\\s+${tool}\\s+`)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Remove the line that sources the safe-chain PowerShell initialization script
|
|
33
|
+
removeLinesMatchingPattern(
|
|
34
|
+
startupFile,
|
|
35
|
+
/^\.\s+["']?\$HOME[/\\].safe-chain[/\\]scripts[/\\]init-pwsh\.ps1["']?/
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function setup() {
|
|
42
|
+
const startupFile = getStartupFile();
|
|
43
|
+
|
|
44
|
+
addLineToFile(
|
|
45
|
+
startupFile,
|
|
46
|
+
`. "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1" # Safe-chain PowerShell initialization script`
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getStartupFile() {
|
|
53
|
+
try {
|
|
54
|
+
return execSync(startupFileCommand, {
|
|
55
|
+
encoding: "utf8",
|
|
56
|
+
shell: executableName,
|
|
57
|
+
}).trim();
|
|
58
|
+
} catch (/** @type {any} */ error) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Command failed: ${startupFileCommand}. Error: ${error.message}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @type {import("../shellDetection.js").Shell}
|
|
67
|
+
*/
|
|
68
|
+
export default {
|
|
69
|
+
name: shellName,
|
|
70
|
+
isInstalled,
|
|
71
|
+
setup,
|
|
72
|
+
teardown,
|
|
73
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addLineToFile,
|
|
3
|
+
doesExecutableExistOnSystem,
|
|
4
|
+
removeLinesMatchingPattern,
|
|
5
|
+
} from "../helpers.js";
|
|
6
|
+
import { execSync } from "child_process";
|
|
7
|
+
|
|
8
|
+
const shellName = "Zsh";
|
|
9
|
+
const executableName = "zsh";
|
|
10
|
+
const startupFileCommand = "echo ${ZDOTDIR:-$HOME}/.zshrc";
|
|
11
|
+
const eol = "\n"; // When zsh runs on Windows (e.g., Git Bash or WSL), it expects LF line endings.
|
|
12
|
+
|
|
13
|
+
function isInstalled() {
|
|
14
|
+
return doesExecutableExistOnSystem(executableName);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {import("../helpers.js").AikidoTool[]} tools
|
|
19
|
+
*
|
|
20
|
+
* @returns {boolean}
|
|
21
|
+
*/
|
|
22
|
+
function teardown(tools) {
|
|
23
|
+
const startupFile = getStartupFile();
|
|
24
|
+
|
|
25
|
+
for (const { tool } of tools) {
|
|
26
|
+
// Remove any existing alias for the tool
|
|
27
|
+
removeLinesMatchingPattern(
|
|
28
|
+
startupFile,
|
|
29
|
+
new RegExp(`^alias\\s+${tool}=`),
|
|
30
|
+
eol
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Removes the line that sources the safe-chain zsh initialization script (~/.aikido/scripts/init-posix.sh)
|
|
35
|
+
removeLinesMatchingPattern(
|
|
36
|
+
startupFile,
|
|
37
|
+
/^source\s+~\/\.safe-chain\/scripts\/init-posix\.sh/,
|
|
38
|
+
eol
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function setup() {
|
|
45
|
+
const startupFile = getStartupFile();
|
|
46
|
+
|
|
47
|
+
addLineToFile(
|
|
48
|
+
startupFile,
|
|
49
|
+
`source ~/.safe-chain/scripts/init-posix.sh # Safe-chain Zsh initialization script`,
|
|
50
|
+
eol
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getStartupFile() {
|
|
57
|
+
try {
|
|
58
|
+
return execSync(startupFileCommand, {
|
|
59
|
+
encoding: "utf8",
|
|
60
|
+
shell: executableName,
|
|
61
|
+
}).trim();
|
|
62
|
+
} catch (/** @type {any} */ error) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Command failed: ${startupFileCommand}. Error: ${error.message}`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default {
|
|
70
|
+
name: shellName,
|
|
71
|
+
isInstalled,
|
|
72
|
+
setup,
|
|
73
|
+
teardown,
|
|
74
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @returns {Promise<void>}
|
|
8
|
+
*/
|
|
9
|
+
export async function teardown() {
|
|
10
|
+
ui.writeInformation(
|
|
11
|
+
chalk.bold("Removing shell aliases.") +
|
|
12
|
+
` This will remove safe-chain aliases for ${getPackageManagerList()}.`
|
|
13
|
+
);
|
|
14
|
+
ui.emptyLine();
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const shells = detectShells();
|
|
18
|
+
if (shells.length === 0) {
|
|
19
|
+
ui.writeError("No supported shells detected. Cannot remove aliases.");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
ui.writeInformation(
|
|
24
|
+
`Detected ${shells.length} supported shell(s): ${shells
|
|
25
|
+
.map((shell) => chalk.bold(shell.name))
|
|
26
|
+
.join(", ")}.`
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
let updatedCount = 0;
|
|
30
|
+
for (const shell of shells) {
|
|
31
|
+
let success = false;
|
|
32
|
+
try {
|
|
33
|
+
success = shell.teardown(knownAikidoTools);
|
|
34
|
+
} catch {
|
|
35
|
+
success = false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (success) {
|
|
39
|
+
ui.writeInformation(
|
|
40
|
+
`${chalk.bold("- " + shell.name + ":")} ${chalk.green(
|
|
41
|
+
"Teardown successful"
|
|
42
|
+
)}`
|
|
43
|
+
);
|
|
44
|
+
updatedCount++;
|
|
45
|
+
} else {
|
|
46
|
+
ui.writeError(
|
|
47
|
+
`${chalk.bold("- " + shell.name + ":")} ${chalk.red(
|
|
48
|
+
"Teardown failed"
|
|
49
|
+
)}. Please check your ${shell.name} configuration.`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (updatedCount > 0) {
|
|
55
|
+
ui.emptyLine();
|
|
56
|
+
ui.writeInformation(`Please restart your terminal to apply the changes.`);
|
|
57
|
+
}
|
|
58
|
+
} catch (/** @type {any} */ error) {
|
|
59
|
+
ui.writeError(
|
|
60
|
+
`Failed to remove shell aliases: ${error.message}. Please check your shell configuration.`
|
|
61
|
+
);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|