@aikidosec/safe-chain 1.4.9 → 1.5.1

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.
Files changed (32) hide show
  1. package/README.md +34 -6
  2. package/bin/aikido-uvx.js +16 -0
  3. package/bin/safe-chain.js +18 -1
  4. package/docs/Release.md +25 -0
  5. package/docs/shell-integration.md +4 -4
  6. package/npm-shrinkwrap.json +53 -942
  7. package/package.json +3 -4
  8. package/src/config/configFile.js +2 -2
  9. package/src/config/safeChainDir.js +71 -0
  10. package/src/installLocation.js +42 -0
  11. package/src/packagemanager/currentPackageManager.js +3 -0
  12. package/src/packagemanager/uvx/createUvxPackageManager.js +18 -0
  13. package/src/registryProxy/certUtils.js +3 -3
  14. package/src/registryProxy/interceptors/pip/modifyPipInfo.js +17 -0
  15. package/src/registryProxy/interceptors/pip/pipInterceptor.js +2 -0
  16. package/src/scanning/malwareDatabase.js +41 -38
  17. package/src/scanning/newPackagesListCache.js +16 -19
  18. package/src/shell-integration/helpers.js +6 -14
  19. package/src/shell-integration/path-wrappers/templates/unix-wrapper.template.sh +16 -1
  20. package/src/shell-integration/path-wrappers/templates/windows-wrapper.template.cmd +3 -2
  21. package/src/shell-integration/setup-ci.js +9 -29
  22. package/src/shell-integration/setup.js +3 -22
  23. package/src/shell-integration/startup-scripts/init-fish.fish +8 -1
  24. package/src/shell-integration/startup-scripts/init-posix.sh +17 -1
  25. package/src/shell-integration/startup-scripts/init-pwsh.ps1 +6 -1
  26. package/src/shell-integration/supported-shells/bash.js +75 -5
  27. package/src/shell-integration/supported-shells/fish.js +7 -5
  28. package/src/shell-integration/supported-shells/powershell.js +7 -5
  29. package/src/shell-integration/supported-shells/windowsPowershell.js +7 -5
  30. package/src/shell-integration/supported-shells/zsh.js +7 -5
  31. package/src/shell-integration/teardown.js +3 -1
  32. package/src/ultimate/ultimateTroubleshooting.js +0 -111
@@ -2,7 +2,8 @@
2
2
  # $IsWindows is only available in PowerShell Core 6.0+. If it doesn't exist, assume Windows PowerShell
3
3
  $isWindowsPlatform = if (Test-Path variable:IsWindows) { $IsWindows } else { $true }
4
4
  $pathSeparator = if ($isWindowsPlatform) { ';' } else { ':' }
5
- $safeChainBin = Join-Path (Join-Path $HOME '.safe-chain') 'bin'
5
+ $safeChainBase = Split-Path -Parent $PSScriptRoot
6
+ $safeChainBin = Join-Path $safeChainBase 'bin'
6
7
  $env:PATH = "$env:PATH$pathSeparator$safeChainBin"
7
8
 
8
9
  function npx {
@@ -52,6 +53,10 @@ function uv {
52
53
  Invoke-WrappedCommand "uv" $args $MyInvocation.Line $MyInvocation.OffsetInLine
53
54
  }
54
55
 
56
+ function uvx {
57
+ Invoke-WrappedCommand "uvx" $args $MyInvocation.Line $MyInvocation.OffsetInLine
58
+ }
59
+
55
60
  function poetry {
56
61
  Invoke-WrappedCommand "poetry" $args $MyInvocation.Line $MyInvocation.OffsetInLine
57
62
  }
@@ -3,8 +3,10 @@ import {
3
3
  doesExecutableExistOnSystem,
4
4
  removeLinesMatchingPattern,
5
5
  } from "../helpers.js";
6
+ import { getScriptsDir } from "../../config/safeChainDir.js";
6
7
  import { execSync, spawnSync } from "child_process";
7
8
  import * as os from "os";
9
+ import path from "path";
8
10
 
9
11
  const shellName = "Bash";
10
12
  const executableName = "bash";
@@ -32,10 +34,10 @@ function teardown(tools) {
32
34
  );
33
35
  }
34
36
 
35
- // Removes the line that sources the safe-chain bash initialization script (~/.safe-chain/scripts/init-posix.sh)
37
+ // Remove sourcing line to disable safe-chain shell integration
36
38
  removeLinesMatchingPattern(
37
39
  startupFile,
38
- /^source\s+~\/\.safe-chain\/scripts\/init-posix\.sh/,
40
+ /^source\s+.*init-posix\.sh.*#\s*Safe-chain/,
39
41
  eol
40
42
  );
41
43
 
@@ -44,10 +46,11 @@ function teardown(tools) {
44
46
 
45
47
  function setup() {
46
48
  const startupFile = getStartupFile();
49
+ const scriptsDir = getShellScriptsDir();
47
50
 
48
51
  addLineToFile(
49
52
  startupFile,
50
- `source ~/.safe-chain/scripts/init-posix.sh # Safe-chain bash initialization script`,
53
+ `source ${path.posix.join(scriptsDir, "init-posix.sh")} # Safe-chain bash initialization script`,
51
54
  eol
52
55
  );
53
56
 
@@ -94,6 +97,51 @@ function windowsFixPath(path) {
94
97
  }
95
98
  }
96
99
 
100
+ function getShellScriptsDir() {
101
+ return toBashPath(getScriptsDir());
102
+ }
103
+
104
+ /**
105
+ * @param {string} path
106
+ *
107
+ * @returns {string}
108
+ */
109
+ function toBashPath(path) {
110
+ try {
111
+ if (os.platform() !== "win32") {
112
+ return path.replace(/\\/g, "/");
113
+ }
114
+
115
+ const directWindowsPath = windowsPathToBashPath(path);
116
+ if (directWindowsPath) {
117
+ return directWindowsPath;
118
+ }
119
+
120
+ if (hasCygpath()) {
121
+ return convertCygwinPathToUnix(path);
122
+ }
123
+
124
+ return path.replace(/\\/g, "/");
125
+ } catch {
126
+ return path.replace(/\\/g, "/");
127
+ }
128
+ }
129
+
130
+ /**
131
+ * @param {string} path
132
+ *
133
+ * @returns {string | undefined}
134
+ */
135
+ function windowsPathToBashPath(path) {
136
+ const match = /^([A-Za-z]):[\\/](.*)$/.exec(path);
137
+ if (!match) {
138
+ return undefined;
139
+ }
140
+
141
+ const [, driveLetter, rest] = match;
142
+ return `/${driveLetter.toLowerCase()}/${rest.replace(/\\/g, "/")}`;
143
+ }
144
+
97
145
  function hasCygpath() {
98
146
  try {
99
147
  var result = spawnSync("where", ["cygpath"], { shell: executableName });
@@ -123,18 +171,40 @@ function cygpathw(path) {
123
171
  }
124
172
  }
125
173
 
174
+ /**
175
+ * @param {string} path
176
+ *
177
+ * @returns {string}
178
+ */
179
+ function convertCygwinPathToUnix(path) {
180
+ try {
181
+ var result = spawnSync("cygpath", ["-u", path], {
182
+ encoding: "utf8",
183
+ shell: executableName,
184
+ });
185
+ if (result.status === 0) {
186
+ return result.stdout.trim();
187
+ }
188
+ return path.replace(/\\/g, "/");
189
+ } catch {
190
+ return path.replace(/\\/g, "/");
191
+ }
192
+ }
193
+
126
194
  function getManualTeardownInstructions() {
195
+ const scriptsDir = getShellScriptsDir();
127
196
  return [
128
197
  `Remove the following line from your ~/.bashrc file:`,
129
- ` source ~/.safe-chain/scripts/init-posix.sh`,
198
+ ` source ${path.posix.join(scriptsDir, "init-posix.sh")}`,
130
199
  `Then restart your terminal or run: source ~/.bashrc`,
131
200
  ];
132
201
  }
133
202
 
134
203
  function getManualSetupInstructions() {
204
+ const scriptsDir = getShellScriptsDir();
135
205
  return [
136
206
  `Add the following line to your ~/.bashrc file:`,
137
- ` source ~/.safe-chain/scripts/init-posix.sh`,
207
+ ` source ${path.posix.join(scriptsDir, "init-posix.sh")}`,
138
208
  `Then restart your terminal or run: source ~/.bashrc`,
139
209
  ];
140
210
  }
@@ -3,7 +3,9 @@ import {
3
3
  doesExecutableExistOnSystem,
4
4
  removeLinesMatchingPattern,
5
5
  } from "../helpers.js";
6
+ import { getScriptsDir } from "../../config/safeChainDir.js";
6
7
  import { execSync } from "child_process";
8
+ import path from "path";
7
9
 
8
10
  const shellName = "Fish";
9
11
  const executableName = "fish";
@@ -31,10 +33,10 @@ function teardown(tools) {
31
33
  );
32
34
  }
33
35
 
34
- // Removes the line that sources the safe-chain fish initialization script (~/.safe-chain/scripts/init-fish.fish)
36
+ // Remove sourcing line to prevent safe-chain initialization in future shell sessions
35
37
  removeLinesMatchingPattern(
36
38
  startupFile,
37
- /^source\s+~\/\.safe-chain\/scripts\/init-fish\.fish/,
39
+ /^source\s+.*init-fish\.fish.*#\s*Safe-chain/,
38
40
  eol
39
41
  );
40
42
 
@@ -46,7 +48,7 @@ function setup() {
46
48
 
47
49
  addLineToFile(
48
50
  startupFile,
49
- `source ~/.safe-chain/scripts/init-fish.fish # Safe-chain Fish initialization script`,
51
+ `source ${path.join(getScriptsDir(), "init-fish.fish")} # Safe-chain Fish initialization script`,
50
52
  eol
51
53
  );
52
54
 
@@ -69,7 +71,7 @@ function getStartupFile() {
69
71
  function getManualTeardownInstructions() {
70
72
  return [
71
73
  `Remove the following line from your ~/.config/fish/config.fish file:`,
72
- ` source ~/.safe-chain/scripts/init-fish.fish`,
74
+ ` source ${path.join(getScriptsDir(), "init-fish.fish")}`,
73
75
  `Then restart your terminal or run: source ~/.config/fish/config.fish`,
74
76
  ];
75
77
  }
@@ -77,7 +79,7 @@ function getManualTeardownInstructions() {
77
79
  function getManualSetupInstructions() {
78
80
  return [
79
81
  `Add the following line to your ~/.config/fish/config.fish file:`,
80
- ` source ~/.safe-chain/scripts/init-fish.fish`,
82
+ ` source ${path.join(getScriptsDir(), "init-fish.fish")}`,
81
83
  `Then restart your terminal or run: source ~/.config/fish/config.fish`,
82
84
  ];
83
85
  }
@@ -4,7 +4,9 @@ import {
4
4
  removeLinesMatchingPattern,
5
5
  validatePowerShellExecutionPolicy,
6
6
  } from "../helpers.js";
7
+ import { getScriptsDir } from "../../config/safeChainDir.js";
7
8
  import { execSync } from "child_process";
9
+ import path from "path";
8
10
 
9
11
  const shellName = "PowerShell Core";
10
12
  const executableName = "pwsh";
@@ -30,10 +32,10 @@ function teardown(tools) {
30
32
  );
31
33
  }
32
34
 
33
- // Remove the line that sources the safe-chain PowerShell initialization script
35
+ // Remove sourcing line to prevent shell from loading safe-chain after uninstallation
34
36
  removeLinesMatchingPattern(
35
37
  startupFile,
36
- /^\.\s+["']?\$HOME[/\\].safe-chain[/\\]scripts[/\\]init-pwsh\.ps1["']?/,
38
+ /^\.\s+["']?.*init-pwsh\.ps1["']?.*#\s*Safe-chain/,
37
39
  );
38
40
 
39
41
  return true;
@@ -52,7 +54,7 @@ async function setup() {
52
54
 
53
55
  addLineToFile(
54
56
  startupFile,
55
- `. "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1" # Safe-chain PowerShell initialization script`,
57
+ `. "${path.join(getScriptsDir(), "init-pwsh.ps1")}" # Safe-chain PowerShell initialization script`,
56
58
  );
57
59
 
58
60
  return true;
@@ -74,7 +76,7 @@ function getStartupFile() {
74
76
  function getManualTeardownInstructions() {
75
77
  return [
76
78
  `Remove the following line from your PowerShell profile (run "echo $PROFILE" to find its location):`,
77
- ` . "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1"`,
79
+ ` . "${path.join(getScriptsDir(), "init-pwsh.ps1")}"`,
78
80
  `Then restart your terminal or run: . $PROFILE`,
79
81
  ];
80
82
  }
@@ -82,7 +84,7 @@ function getManualTeardownInstructions() {
82
84
  function getManualSetupInstructions() {
83
85
  return [
84
86
  `Add the following line to your PowerShell profile (run "echo $PROFILE" to find its location):`,
85
- ` . "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1"`,
87
+ ` . "${path.join(getScriptsDir(), "init-pwsh.ps1")}"`,
86
88
  `Then restart your terminal or run: . $PROFILE`,
87
89
  ];
88
90
  }
@@ -4,7 +4,9 @@ import {
4
4
  removeLinesMatchingPattern,
5
5
  validatePowerShellExecutionPolicy,
6
6
  } from "../helpers.js";
7
+ import { getScriptsDir } from "../../config/safeChainDir.js";
7
8
  import { execSync } from "child_process";
9
+ import path from "path";
8
10
 
9
11
  const shellName = "Windows PowerShell";
10
12
  const executableName = "powershell";
@@ -30,10 +32,10 @@ function teardown(tools) {
30
32
  );
31
33
  }
32
34
 
33
- // Remove the line that sources the safe-chain PowerShell initialization script
35
+ // Remove sourcing line to clean up safe-chain integration from the shell profile
34
36
  removeLinesMatchingPattern(
35
37
  startupFile,
36
- /^\.\s+["']?\$HOME[/\\].safe-chain[/\\]scripts[/\\]init-pwsh\.ps1["']?/,
38
+ /^\.\s+["']?.*init-pwsh\.ps1["']?.*#\s*Safe-chain/,
37
39
  );
38
40
 
39
41
  return true;
@@ -52,7 +54,7 @@ async function setup() {
52
54
 
53
55
  addLineToFile(
54
56
  startupFile,
55
- `. "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1" # Safe-chain PowerShell initialization script`,
57
+ `. "${path.join(getScriptsDir(), "init-pwsh.ps1")}" # Safe-chain PowerShell initialization script`,
56
58
  );
57
59
 
58
60
  return true;
@@ -74,7 +76,7 @@ function getStartupFile() {
74
76
  function getManualTeardownInstructions() {
75
77
  return [
76
78
  `Remove the following line from your PowerShell profile (run "echo $PROFILE" to find its location):`,
77
- ` . "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1"`,
79
+ ` . "${path.join(getScriptsDir(), "init-pwsh.ps1")}"`,
78
80
  `Then restart your terminal or run: . $PROFILE`,
79
81
  ];
80
82
  }
@@ -82,7 +84,7 @@ function getManualTeardownInstructions() {
82
84
  function getManualSetupInstructions() {
83
85
  return [
84
86
  `Add the following line to your PowerShell profile (run "echo $PROFILE" to find its location):`,
85
- ` . "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1"`,
87
+ ` . "${path.join(getScriptsDir(), "init-pwsh.ps1")}"`,
86
88
  `Then restart your terminal or run: . $PROFILE`,
87
89
  ];
88
90
  }
@@ -3,7 +3,9 @@ import {
3
3
  doesExecutableExistOnSystem,
4
4
  removeLinesMatchingPattern,
5
5
  } from "../helpers.js";
6
+ import { getScriptsDir } from "../../config/safeChainDir.js";
6
7
  import { execSync } from "child_process";
8
+ import path from "path";
7
9
 
8
10
  const shellName = "Zsh";
9
11
  const executableName = "zsh";
@@ -31,10 +33,10 @@ function teardown(tools) {
31
33
  );
32
34
  }
33
35
 
34
- // Removes the line that sources the safe-chain zsh initialization script (~/.safe-chain/scripts/init-posix.sh)
36
+ // Remove sourcing line to complete shell integration cleanup
35
37
  removeLinesMatchingPattern(
36
38
  startupFile,
37
- /^source\s+~\/\.safe-chain\/scripts\/init-posix\.sh/,
39
+ /^source\s+.*init-posix\.sh.*#\s*Safe-chain/,
38
40
  eol
39
41
  );
40
42
 
@@ -46,7 +48,7 @@ function setup() {
46
48
 
47
49
  addLineToFile(
48
50
  startupFile,
49
- `source ~/.safe-chain/scripts/init-posix.sh # Safe-chain Zsh initialization script`,
51
+ `source ${path.join(getScriptsDir(), "init-posix.sh")} # Safe-chain Zsh initialization script`,
50
52
  eol
51
53
  );
52
54
 
@@ -69,7 +71,7 @@ function getStartupFile() {
69
71
  function getManualTeardownInstructions() {
70
72
  return [
71
73
  `Remove the following line from your ~/.zshrc file:`,
72
- ` source ~/.safe-chain/scripts/init-posix.sh`,
74
+ ` source ${path.join(getScriptsDir(), "init-posix.sh")}`,
73
75
  `Then restart your terminal or run: source ~/.zshrc`,
74
76
  ];
75
77
  }
@@ -77,7 +79,7 @@ function getManualTeardownInstructions() {
77
79
  function getManualSetupInstructions() {
78
80
  return [
79
81
  `Add the following line to your ~/.zshrc file:`,
80
- ` source ~/.safe-chain/scripts/init-posix.sh`,
82
+ ` source ${path.join(getScriptsDir(), "init-posix.sh")}`,
81
83
  `Then restart your terminal or run: source ~/.zshrc`,
82
84
  ];
83
85
  }
@@ -1,7 +1,8 @@
1
1
  import chalk from "chalk";
2
2
  import { ui } from "../environment/userInteraction.js";
3
3
  import { detectShells } from "./shellDetection.js";
4
- import { knownAikidoTools, getPackageManagerList, getShimsDir, getScriptsDir } from "./helpers.js";
4
+ import { knownAikidoTools, getPackageManagerList } from "./helpers.js";
5
+ import { getShimsDir, getScriptsDir } from "../config/safeChainDir.js";
5
6
  import fs from "fs";
6
7
 
7
8
  /**
@@ -109,4 +110,5 @@ export async function teardownDirectories() {
109
110
  );
110
111
  }
111
112
  }
113
+
112
114
  }
@@ -1,111 +0,0 @@
1
- import { platform } from 'os';
2
- import { ui } from "../environment/userInteraction.js";
3
- import { readFileSync, existsSync } from "node:fs";
4
- import {randomUUID} from "node:crypto";
5
- import {createWriteStream} from "fs";
6
- import archiver from 'archiver';
7
- import path from "node:path";
8
-
9
- export async function printUltimateLogs() {
10
- const { proxyLogPath, ultimateLogPath, proxyErrLogPath, ultimateErrLogPath } = getPathsPerPlatform();
11
-
12
- await printLogs(
13
- "SafeChain Proxy",
14
- proxyLogPath,
15
- proxyErrLogPath
16
- );
17
-
18
- await printLogs(
19
- "SafeChain Ultimate",
20
- ultimateLogPath,
21
- ultimateErrLogPath
22
- );
23
- }
24
-
25
- export async function troubleshootingExport() {
26
- const { logDir } = getPathsPerPlatform();
27
- return new Promise((resolve, reject) => {
28
- if (!existsSync(logDir)) {
29
- ui.writeError(`Log directory not found: ${logDir}`);
30
- reject(new Error(`Log directory not found: ${logDir}`));
31
- return;
32
- }
33
-
34
- const date = new Date().toISOString().split('T')[0];
35
- const uuid = randomUUID();
36
- const zipFileName = `safechain-ultimate-${date}-${uuid}.zip`;
37
- const output = createWriteStream(zipFileName);
38
- const archive = archiver('zip', { zlib: { level: 9 } });
39
-
40
- output.on('close', () => {
41
- ui.writeInformation(`Logs collected and zipped as: ${path.resolve(zipFileName)}`);
42
- resolve(zipFileName);
43
- });
44
-
45
- archive.on('error', (/** @type {Error} */ err) => {
46
- ui.writeError(`Failed to zip logs: ${err.message}`);
47
- reject(err);
48
- });
49
-
50
- archive.pipe(output);
51
- archive.directory(logDir, false);
52
- archive.finalize();
53
- });
54
- }
55
-
56
-
57
- function getPathsPerPlatform() {
58
- const os = platform();
59
- if (os === 'win32') {
60
- const logDir = `C:\\ProgramData\\AikidoSecurity\\SafeChainUltimate\\logs`;
61
- return {
62
- logDir,
63
- proxyLogPath: `${logDir}\\SafeChainProxy.log`,
64
- ultimateLogPath: `${logDir}\\SafeChainUltimate.log`,
65
- proxyErrLogPath: `${logDir}\\SafeChainProxy.err`,
66
- ultimateErrLogPath: `${logDir}\\SafeChainUltimate.err`,
67
- };
68
- } else if (os === 'darwin') {
69
- const logDir = `/Library/Logs/AikidoSecurity/SafeChainUltimate`;
70
- return {
71
- logDir,
72
- proxyLogPath: `${logDir}/safechain-proxy.log`,
73
- ultimateLogPath: `${logDir}/safechain-ultimate.log`,
74
- proxyErrLogPath: `${logDir}/safechain-proxy.error.log`,
75
- ultimateErrLogPath: `${logDir}/safechain-ultimate.error.log`,
76
- };
77
- } else {
78
- throw new Error('Unsupported platform for log printing.');
79
- }
80
- }
81
-
82
- /**
83
- * @param {string} appName
84
- * @param {string} logPath
85
- * @param {string} errLogPath
86
- */
87
- async function printLogs(appName, logPath, errLogPath) {
88
- ui.writeInformation(`=== ${appName} Logs ===`);
89
- try {
90
- if (existsSync(logPath)) {
91
- const logs = readFileSync(logPath, "utf-8");
92
- ui.writeInformation(logs);
93
- } else {
94
- ui.writeWarning(`${appName} log file not found: ${logPath}`);
95
- }
96
- } catch (error) {
97
- ui.writeError(`Failed to read ${appName} logs: ${error}`);
98
- }
99
-
100
- ui.writeInformation(`=== ${appName} Error Logs ===`);
101
- try {
102
- if (existsSync(errLogPath)) {
103
- const errLogs = readFileSync(errLogPath, "utf-8");
104
- ui.writeInformation(errLogs);
105
- } else {
106
- ui.writeInformation(`No error log file found for ${appName}.`);
107
- }
108
- } catch (error) {
109
- ui.writeError(`Failed to read ${appName} error logs: ${error}`);
110
- }
111
- }