@n8n/scan-community-package 0.1.0 → 0.1.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.
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@n8n/scan-community-package",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Static code analyser for n8n community packages",
5
5
  "license": "none",
6
6
  "packageManager": "pnpm@10.2.1",
7
- "bin": "scanner/scan-community-package.mjs",
7
+ "bin": "scanner/cli.mjs",
8
8
  "files": [
9
9
  "scanner"
10
10
  ],
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ const args = process.argv.slice(2);
4
+ if (args.length < 1) {
5
+ console.error(
6
+ "Usage: npx @n8n/scan-community-package <package-name>[@version]",
7
+ );
8
+ process.exit(1);
9
+ }
10
+
11
+ import { resolvePackage, analyzePackageByName } from "./scanner.mjs";
12
+
13
+ const packageSpec = args[0];
14
+ const { packageName, version } = resolvePackage(packageSpec);
15
+ try {
16
+ const result = await analyzePackageByName(packageName, version);
17
+
18
+ if (result.passed) {
19
+ console.log(
20
+ `✅ Package ${packageName}@${result.version} has passed all security checks`,
21
+ );
22
+ } else {
23
+ console.log(
24
+ `❌ Package ${packageName}@${result.version} has failed security checks`,
25
+ );
26
+ console.log(`Reason: ${result.message}`);
27
+
28
+ if (result.details) {
29
+ console.log("\nDetails:");
30
+ console.log(result.details);
31
+ }
32
+ }
33
+ } catch (error) {
34
+ console.error("Analysis failed:", error);
35
+ process.exit(1);
36
+ }
@@ -18,7 +18,27 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
18
18
  const TEMP_DIR = tmp.dirSync({ unsafeCleanup: true }).name;
19
19
  const registry = "https://registry.npmjs.org/";
20
20
 
21
- async function downloadAndExtractPackage(packageName, version) {
21
+ export const resolvePackage = (packageSpec) => {
22
+ let packageName, version;
23
+ if (packageSpec.startsWith("@")) {
24
+ if (packageSpec.includes("@", 1)) {
25
+ // Handle scoped packages with versions
26
+ const lastAtIndex = packageSpec.lastIndexOf("@");
27
+ return {
28
+ packageName: packageSpec.substring(0, lastAtIndex),
29
+ version: packageSpec.substring(lastAtIndex + 1),
30
+ };
31
+ } else {
32
+ // Handle scoped packages without version
33
+ return { packageName: packageSpec, version: null };
34
+ }
35
+ }
36
+ // Handle regular packages
37
+ const parts = packageSpec.split("@");
38
+ return { packageName: parts[0], version: parts[1] || null };
39
+ };
40
+
41
+ const downloadAndExtractPackage = async (packageName, version) => {
22
42
  try {
23
43
  // Download the tarball
24
44
  execSync(`npm -q pack ${packageName}@${version}`, { cwd: TEMP_DIR });
@@ -42,9 +62,9 @@ async function downloadAndExtractPackage(packageName, version) {
42
62
  console.error(`\nFailed to download package: ${error.message}`);
43
63
  throw error;
44
64
  }
45
- }
65
+ };
46
66
 
47
- async function analyzePackage(packageDir) {
67
+ const analyzePackage = async (packageDir) => {
48
68
  const { default: eslintPlugin } = await import("./eslint-plugin.mjs");
49
69
  const eslint = new ESLint({
50
70
  cwd: packageDir,
@@ -102,9 +122,9 @@ async function analyzePackage(packageDir) {
102
122
  error,
103
123
  };
104
124
  }
105
- }
125
+ };
106
126
 
107
- export async function analyzePackageByName(packageName, version) {
127
+ export const analyzePackageByName = async (packageName, version) => {
108
128
  try {
109
129
  let exactVersion = version;
110
130
 
@@ -156,66 +176,4 @@ export async function analyzePackageByName(packageName, version) {
156
176
  message: `Analysis failed: ${error.message}`,
157
177
  };
158
178
  }
159
- }
160
-
161
- const resolvePackage = (packageSpec) => {
162
- let packageName, version;
163
- if (packageSpec.startsWith("@")) {
164
- if (packageSpec.includes("@", 1)) {
165
- // Handle scoped packages with versions
166
- const lastAtIndex = packageSpec.lastIndexOf("@");
167
- return {
168
- packageName: packageSpec.substring(0, lastAtIndex),
169
- version: packageSpec.substring(lastAtIndex + 1),
170
- };
171
- } else {
172
- // Handle scoped packages without version
173
- return { packageName: packageSpec, version: null };
174
- }
175
- }
176
- // Handle regular packages
177
- const parts = packageSpec.split("@");
178
- return { packageName: parts[0], version: parts[1] || null };
179
179
  };
180
-
181
- async function main() {
182
- const args = process.argv.slice(2);
183
-
184
- if (args.length < 1) {
185
- console.error(
186
- "Usage: node scan-community-package.mjs <package-name>[@version]",
187
- );
188
- process.exit(1);
189
- }
190
-
191
- const packageSpec = args[0];
192
- const { packageName, version } = resolvePackage(packageSpec);
193
-
194
- try {
195
- const result = await analyzePackageByName(packageName, version);
196
-
197
- if (result.passed) {
198
- console.log(
199
- `✅ Package ${packageName}@${result.version} has passed all security checks`,
200
- );
201
- } else {
202
- console.log(
203
- `❌ Package ${packageName}@${result.version} has failed security checks`,
204
- );
205
- console.log(`Reason: ${result.message}`);
206
-
207
- if (result.details) {
208
- console.log("\nDetails:");
209
- console.log(result.details);
210
- }
211
- }
212
- } catch (error) {
213
- console.error("Analysis failed:", error);
214
- process.exit(1);
215
- }
216
- }
217
-
218
- // In ESM, check if the current file is being executed directly
219
- if (import.meta.url === `file://${process.argv[1]}`) {
220
- void main();
221
- }