@jishankai/solid-cli 1.0.0

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.
@@ -0,0 +1,42 @@
1
+ import { execa } from 'execa';
2
+
3
+ /**
4
+ * Execute a shell command and return the result
5
+ * @param {string} command - The command to execute
6
+ * @param {Array} args - Command arguments
7
+ * @param {Object} options - Additional options
8
+ * @param {boolean} options.quiet - Suppress error logging
9
+ * @returns {Promise<string>} - Command output
10
+ */
11
+ export async function executeCommand(command, args = [], options = {}) {
12
+ const { quiet = false } = options;
13
+ try {
14
+ const { stdout } = await execa(command, args);
15
+ return stdout;
16
+ } catch (error) {
17
+ if (!quiet) {
18
+ console.error(`Command failed: ${command} ${args.join(' ')}`);
19
+ }
20
+ return '';
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Execute a shell command with shell syntax
26
+ * @param {string} command - The full command string
27
+ * @param {Object} options - Additional options
28
+ * @param {boolean} options.quiet - Suppress error logging
29
+ * @returns {Promise<string>} - Command output
30
+ */
31
+ export async function executeShellCommand(command, options = {}) {
32
+ const { quiet = false } = options;
33
+ try {
34
+ const { stdout } = await execa('sh', ['-c', command]);
35
+ return stdout;
36
+ } catch (error) {
37
+ if (!quiet) {
38
+ console.error(`Shell command failed: ${command}`);
39
+ }
40
+ return '';
41
+ }
42
+ }
@@ -0,0 +1,121 @@
1
+ import { existsSync } from 'fs';
2
+
3
+ import { executeShellCommand } from './commander.js';
4
+
5
+ /**
6
+ * Escape a string for safe inclusion as a single-quoted shell argument.
7
+ * @param {string} value
8
+ * @returns {string}
9
+ */
10
+ function shellQuote(value) {
11
+ const safe = String(value).replace(/'/g, `'"'"'`);
12
+ return `'${safe}'`;
13
+ }
14
+
15
+ /**
16
+ * Get code signing / Gatekeeper assessment for a local executable.
17
+ *
18
+ * NOTE:
19
+ * - Uses `spctl` (Gatekeeper) and `codesign` outputs.
20
+ * - Returns best-effort results; does not throw.
21
+ * - Uses `cache` (Map) when provided to avoid repeated shell calls.
22
+ *
23
+ * @param {string} filePath
24
+ * @param {Map<string, object>} [cache]
25
+ * @returns {Promise<{
26
+ * path: string,
27
+ * exists: boolean,
28
+ * hasAbsolutePath: boolean,
29
+ * spctlAccepted: boolean,
30
+ * spctlOutput: string,
31
+ * codesignOutput: string,
32
+ * teamIdentifier: string|null,
33
+ * authorities: string[],
34
+ * signedByApple: boolean,
35
+ * signedByDeveloperId: boolean
36
+ * }>}
37
+ */
38
+ export async function getSignatureAssessment(filePath, cache) {
39
+ const rawPath = String(filePath || '');
40
+
41
+ // Some collectors may return a path plus args (e.g. "/path/to/bin --flag").
42
+ // If the full string doesn't exist on disk, fall back to first token.
43
+ let path = rawPath;
44
+ if (path.includes(' ') && path.startsWith('/')) {
45
+ const firstToken = path.split(' ')[0];
46
+ if (existsSync(firstToken)) {
47
+ path = firstToken;
48
+ }
49
+ }
50
+
51
+ const hasAbsolutePath = path.startsWith('/');
52
+ const exists = hasAbsolutePath ? existsSync(path) : false;
53
+
54
+ if (!hasAbsolutePath || !exists) {
55
+ return {
56
+ path: rawPath,
57
+ exists,
58
+ hasAbsolutePath,
59
+ spctlAccepted: false,
60
+ spctlOutput: '',
61
+ codesignOutput: '',
62
+ teamIdentifier: null,
63
+ authorities: [],
64
+ signedByApple: false,
65
+ signedByDeveloperId: false
66
+ };
67
+ }
68
+
69
+ if (cache && cache.has(path)) {
70
+ return cache.get(path);
71
+ }
72
+
73
+ const quoted = shellQuote(path);
74
+
75
+ const spctlOutput = await executeShellCommand(
76
+ `spctl -a -vv --type execute ${quoted} 2>&1 || true`,
77
+ { quiet: true }
78
+ );
79
+
80
+ const codesignOutput = await executeShellCommand(
81
+ `codesign -dv --verbose=4 ${quoted} 2>&1 || true`,
82
+ { quiet: true }
83
+ );
84
+
85
+ const spctlAccepted = spctlOutput.toLowerCase().includes('accepted');
86
+
87
+ const authorities = [];
88
+ let teamIdentifier = null;
89
+
90
+ for (const line of codesignOutput.split('\n')) {
91
+ const trimmed = line.trim();
92
+ if (trimmed.startsWith('Authority=')) {
93
+ authorities.push(trimmed.replace('Authority=', '').trim());
94
+ }
95
+ if (trimmed.startsWith('TeamIdentifier=')) {
96
+ teamIdentifier = trimmed.replace('TeamIdentifier=', '').trim() || null;
97
+ }
98
+ }
99
+
100
+ const signedByApple = authorities.some(a => a.toLowerCase().includes('apple'));
101
+ const signedByDeveloperId = authorities.some(a => a.toLowerCase().includes('developer id'));
102
+
103
+ const assessment = {
104
+ path,
105
+ exists,
106
+ hasAbsolutePath,
107
+ spctlAccepted,
108
+ spctlOutput,
109
+ codesignOutput,
110
+ teamIdentifier,
111
+ authorities,
112
+ signedByApple,
113
+ signedByDeveloperId
114
+ };
115
+
116
+ if (cache) {
117
+ cache.set(path, assessment);
118
+ }
119
+
120
+ return assessment;
121
+ }