@enactprotocol/shared 1.0.13 → 1.2.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.
- package/dist/api/enact-api.js +2 -2
- package/dist/api/types.d.ts +10 -3
- package/dist/core/DaggerExecutionProvider.d.ts +1 -1
- package/dist/core/DaggerExecutionProvider.js +23 -19
- package/dist/core/EnactCore.d.ts +36 -19
- package/dist/core/EnactCore.js +157 -219
- package/dist/core/NativeExecutionProvider.d.ts +9 -0
- package/dist/core/NativeExecutionProvider.js +16 -0
- package/dist/index.d.ts +0 -4
- package/dist/index.js +0 -4
- package/dist/lib/enact-direct.d.ts +0 -15
- package/dist/lib/enact-direct.js +0 -11
- package/dist/security/sign.d.ts +5 -5
- package/dist/security/sign.js +247 -113
- package/dist/security/verification-enforcer.d.ts +12 -0
- package/dist/security/verification-enforcer.js +26 -3
- package/dist/services/McpCoreService.d.ts +0 -12
- package/dist/services/McpCoreService.js +0 -9
- package/dist/types.d.ts +5 -4
- package/dist/utils/config.js +1 -1
- package/dist/utils/version.js +23 -2
- package/package.json +3 -6
- package/src/api/enact-api.ts +2 -2
- package/src/api/types.ts +11 -4
- package/src/core/DaggerExecutionProvider.ts +26 -13
- package/src/core/EnactCore.ts +226 -270
- package/src/index.ts +0 -5
- package/src/lib/enact-direct.ts +0 -21
- package/src/services/McpCoreService.ts +0 -20
- package/src/types.ts +10 -12
- package/src/utils/config.ts +1 -1
- package/src/utils/version.ts +23 -2
- package/src/security/index.ts +0 -3
- package/src/security/security.ts +0 -188
- package/src/security/sign.ts +0 -797
- package/src/security/verification-enforcer.ts +0 -268
package/src/index.ts
CHANGED
|
@@ -22,11 +22,6 @@ export * from './utils/logger';
|
|
|
22
22
|
export * from './utils/silent-monitor';
|
|
23
23
|
export * from './utils/timeout';
|
|
24
24
|
|
|
25
|
-
// Security
|
|
26
|
-
export * from './security/security';
|
|
27
|
-
export { verifyTool, shouldExecuteTool, VERIFICATION_POLICIES } from './security/sign';
|
|
28
|
-
export type { VerificationPolicy as SecurityVerificationPolicy } from './security/sign';
|
|
29
|
-
export * from './security/verification-enforcer';
|
|
30
25
|
|
|
31
26
|
// Services
|
|
32
27
|
export * from './services/McpCoreService';
|
package/src/lib/enact-direct.ts
CHANGED
|
@@ -20,7 +20,6 @@ export class EnactDirect {
|
|
|
20
20
|
apiUrl?: string;
|
|
21
21
|
supabaseUrl?: string;
|
|
22
22
|
authToken?: string;
|
|
23
|
-
verificationPolicy?: "permissive" | "enterprise" | "paranoid";
|
|
24
23
|
defaultTimeout?: string;
|
|
25
24
|
} = {},
|
|
26
25
|
) {
|
|
@@ -33,7 +32,6 @@ export class EnactDirect {
|
|
|
33
32
|
"https://xjnhhxwxovjifdxdwzih.supabase.co",
|
|
34
33
|
executionProvider: "direct",
|
|
35
34
|
authToken: options.authToken || process.env.ENACT_AUTH_TOKEN,
|
|
36
|
-
verificationPolicy: options.verificationPolicy || "permissive",
|
|
37
35
|
defaultTimeout: options.defaultTimeout || "30s",
|
|
38
36
|
});
|
|
39
37
|
}
|
|
@@ -75,24 +73,6 @@ export class EnactDirect {
|
|
|
75
73
|
return this.core.getToolInfo(name, version);
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
/**
|
|
79
|
-
* Verify a tool's cryptographic signatures
|
|
80
|
-
*
|
|
81
|
-
* @param name - Tool name
|
|
82
|
-
* @param policy - Verification policy
|
|
83
|
-
* @returns Verification result
|
|
84
|
-
*/
|
|
85
|
-
async verifyTool(
|
|
86
|
-
name: string,
|
|
87
|
-
policy?: "permissive" | "enterprise" | "paranoid",
|
|
88
|
-
): Promise<{
|
|
89
|
-
verified: boolean;
|
|
90
|
-
signatures: any[];
|
|
91
|
-
policy: string;
|
|
92
|
-
errors?: string[];
|
|
93
|
-
}> {
|
|
94
|
-
return this.core.verifyTool(name, policy);
|
|
95
|
-
}
|
|
96
76
|
|
|
97
77
|
/**
|
|
98
78
|
* Execute a tool from raw YAML definition
|
|
@@ -173,7 +153,6 @@ export class EnactDirect {
|
|
|
173
153
|
async getStatus(): Promise<{
|
|
174
154
|
executionProvider: string;
|
|
175
155
|
apiUrl: string;
|
|
176
|
-
verificationPolicy: string;
|
|
177
156
|
defaultTimeout: string;
|
|
178
157
|
authenticated: boolean;
|
|
179
158
|
}> {
|
|
@@ -62,16 +62,12 @@ export class McpCoreService {
|
|
|
62
62
|
inputs: Record<string, any> = {},
|
|
63
63
|
options?: {
|
|
64
64
|
timeout?: string;
|
|
65
|
-
verifyPolicy?: "permissive" | "enterprise" | "paranoid";
|
|
66
|
-
skipVerification?: boolean;
|
|
67
65
|
force?: boolean;
|
|
68
66
|
dryRun?: boolean;
|
|
69
67
|
},
|
|
70
68
|
): Promise<ExecutionResult> {
|
|
71
69
|
const executeOptions: ToolExecuteOptions = {
|
|
72
70
|
timeout: options?.timeout,
|
|
73
|
-
verifyPolicy: options?.verifyPolicy,
|
|
74
|
-
skipVerification: options?.skipVerification,
|
|
75
71
|
force: options?.force,
|
|
76
72
|
dryRun: options?.dryRun,
|
|
77
73
|
};
|
|
@@ -87,14 +83,12 @@ export class McpCoreService {
|
|
|
87
83
|
inputs: Record<string, any> = {},
|
|
88
84
|
options?: {
|
|
89
85
|
timeout?: string;
|
|
90
|
-
skipVerification?: boolean;
|
|
91
86
|
force?: boolean;
|
|
92
87
|
dryRun?: boolean;
|
|
93
88
|
},
|
|
94
89
|
): Promise<ExecutionResult> {
|
|
95
90
|
const executeOptions: ToolExecuteOptions = {
|
|
96
91
|
timeout: options?.timeout,
|
|
97
|
-
skipVerification: options?.skipVerification,
|
|
98
92
|
force: options?.force,
|
|
99
93
|
dryRun: options?.dryRun,
|
|
100
94
|
};
|
|
@@ -102,20 +96,6 @@ export class McpCoreService {
|
|
|
102
96
|
return await this.core.executeRawTool(toolYaml, inputs, executeOptions);
|
|
103
97
|
}
|
|
104
98
|
|
|
105
|
-
/**
|
|
106
|
-
* Verify a tool's signature
|
|
107
|
-
*/
|
|
108
|
-
async verifyTool(
|
|
109
|
-
name: string,
|
|
110
|
-
policy?: string,
|
|
111
|
-
): Promise<{
|
|
112
|
-
verified: boolean;
|
|
113
|
-
signatures: any[];
|
|
114
|
-
policy: string;
|
|
115
|
-
errors?: string[];
|
|
116
|
-
}> {
|
|
117
|
-
return await this.core.verifyTool(name, policy);
|
|
118
|
-
}
|
|
119
99
|
|
|
120
100
|
/**
|
|
121
101
|
* Check if a tool exists
|
package/src/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ export interface EnactTool {
|
|
|
6
6
|
command: string; // Shell command to execute with version pins
|
|
7
7
|
|
|
8
8
|
// RECOMMENDED FIELDS
|
|
9
|
+
from?: string; // Container image to run the command on (optional, defaults to system shell)
|
|
9
10
|
timeout?: string; // Go duration format: "30s", "5m", "1h" (default: "30s")
|
|
10
11
|
tags?: string[]; // Tags for search and categorization
|
|
11
12
|
license?: string; // SPDX License identifier (e.g., "MIT", "Apache-2.0")
|
|
@@ -70,18 +71,15 @@ export interface EnactTool {
|
|
|
70
71
|
role?: string; // Optional description of the signer
|
|
71
72
|
};
|
|
72
73
|
|
|
73
|
-
// Multi-signature support (
|
|
74
|
-
signatures?:
|
|
75
|
-
string
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
role?: string; // Optional description of the signer (e.g., "author", "maintainer")
|
|
83
|
-
}
|
|
84
|
-
>;
|
|
74
|
+
// Multi-signature support (array format)
|
|
75
|
+
signatures?: {
|
|
76
|
+
signer: string; // Signer identifier (UUID or human-readable name)
|
|
77
|
+
algorithm: string; // Hash algorithm: "sha256"
|
|
78
|
+
type: string; // Signature type: "ecdsa-p256"
|
|
79
|
+
value: string; // Base64 encoded signature
|
|
80
|
+
created: string; // ISO timestamp
|
|
81
|
+
role?: string; // Optional description of the signer (e.g., "author", "reviewer", "approver")
|
|
82
|
+
}[];
|
|
85
83
|
|
|
86
84
|
// Extensions pattern (x-prefixed fields)
|
|
87
85
|
[key: string]: any; // Allow x- prefixed extension fields
|
package/src/utils/config.ts
CHANGED
package/src/utils/version.ts
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
// src/utils/version.ts
|
|
2
2
|
import pc from "picocolors";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
|
+
import { join, dirname } from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Displays the CLI version with nice formatting
|
|
6
9
|
*/
|
|
7
10
|
export function showVersion(): void {
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
let version = "0.0.1-dev";
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
// Try to get version from environment first (for npm scripts)
|
|
15
|
+
if (process.env.npm_package_version) {
|
|
16
|
+
version = process.env.npm_package_version;
|
|
17
|
+
} else {
|
|
18
|
+
// When running as installed binary, read from package.json
|
|
19
|
+
// Go up from shared/dist/utils/version.js to find package.json
|
|
20
|
+
const currentFile = typeof __filename !== 'undefined' ? __filename : fileURLToPath(import.meta.url);
|
|
21
|
+
const sharedDir = dirname(dirname(dirname(currentFile)));
|
|
22
|
+
const packageJsonPath = join(sharedDir, 'package.json');
|
|
23
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
24
|
+
version = packageJson.version;
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// Fall back to default version if anything fails
|
|
28
|
+
version = "1.0.14";
|
|
29
|
+
}
|
|
30
|
+
|
|
10
31
|
const versionText = `v${version}`;
|
|
11
32
|
|
|
12
33
|
console.error(`
|
package/src/security/index.ts
DELETED
package/src/security/security.ts
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
// src/security/security.ts - Simplified security module for CLI core
|
|
2
|
-
import logger from "../exec/logger";
|
|
3
|
-
import type { EnactTool } from "../types";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Verify the signature of an Enact tool before execution
|
|
7
|
-
* @param tool The tool to verify
|
|
8
|
-
* @returns Boolean indicating validity
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Verify that a command is safe to execute
|
|
13
|
-
* @param command The command to verify
|
|
14
|
-
* @param tool The tool containing the command
|
|
15
|
-
* @returns Object with safety status and warnings
|
|
16
|
-
*/
|
|
17
|
-
export function verifyCommandSafety(
|
|
18
|
-
command: string,
|
|
19
|
-
tool: EnactTool,
|
|
20
|
-
): {
|
|
21
|
-
isSafe: boolean;
|
|
22
|
-
warnings: string[];
|
|
23
|
-
blocked?: string[];
|
|
24
|
-
} {
|
|
25
|
-
const warnings: string[] = [];
|
|
26
|
-
const blocked: string[] = [];
|
|
27
|
-
|
|
28
|
-
// Dangerous command patterns that should be blocked
|
|
29
|
-
const dangerousPatterns = [
|
|
30
|
-
/rm\s+-rf\s+\//, // rm -rf /
|
|
31
|
-
/rm\s+-rf\s+\*/, // rm -rf *
|
|
32
|
-
/>\s*\/dev\/sd[a-z]/, // Writing to disk devices
|
|
33
|
-
/dd\s+if=.*of=\/dev/, // Direct disk writing
|
|
34
|
-
/mkfs/, // Format filesystem
|
|
35
|
-
/fdisk/, // Disk partitioning
|
|
36
|
-
/passwd/, // Password changes
|
|
37
|
-
/sudo\s+passwd/, // Password changes with sudo
|
|
38
|
-
/chmod\s+777/, // Overly permissive permissions
|
|
39
|
-
/curl.*\|\s*sh/, // Piping curl to shell
|
|
40
|
-
/wget.*\|\s*sh/, // Piping wget to shell
|
|
41
|
-
/exec\s+sh/, // Executing shell
|
|
42
|
-
/\/etc\/passwd/, // Accessing password file
|
|
43
|
-
/\/etc\/shadow/, // Accessing shadow file
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
// Check for dangerous patterns
|
|
47
|
-
for (const pattern of dangerousPatterns) {
|
|
48
|
-
if (pattern.test(command)) {
|
|
49
|
-
blocked.push(
|
|
50
|
-
`Potentially dangerous command pattern detected: ${pattern.source}`,
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Warning patterns that are suspicious but not necessarily blocked
|
|
56
|
-
const warningPatterns = [
|
|
57
|
-
/sudo\s+/, // Sudo usage
|
|
58
|
-
/su\s+/, // User switching
|
|
59
|
-
/systemctl/, // System service control
|
|
60
|
-
/service\s+/, // Service control
|
|
61
|
-
/mount/, // Mounting filesystems
|
|
62
|
-
/umount/, // Unmounting filesystems
|
|
63
|
-
/iptables/, // Firewall rules
|
|
64
|
-
/crontab/, // Cron job management
|
|
65
|
-
];
|
|
66
|
-
|
|
67
|
-
// Check for warning patterns
|
|
68
|
-
for (const pattern of warningPatterns) {
|
|
69
|
-
if (pattern.test(command)) {
|
|
70
|
-
warnings.push(
|
|
71
|
-
`Potentially privileged operation detected: ${pattern.source}`,
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Check for version pinning (security best practice)
|
|
77
|
-
if (command.includes("npx ") && !command.match(/npx\s+[^@#\s]+[@#]/)) {
|
|
78
|
-
if (!command.includes("github:")) {
|
|
79
|
-
warnings.push(
|
|
80
|
-
"NPX package not version-pinned - consider using @version or github:org/repo#commit",
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
command.includes("uvx ") &&
|
|
87
|
-
!command.includes("git+") &&
|
|
88
|
-
!command.includes("@")
|
|
89
|
-
) {
|
|
90
|
-
warnings.push(
|
|
91
|
-
"UVX package not version-pinned - consider using @version or git+ URL",
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (
|
|
96
|
-
command.includes("docker run") &&
|
|
97
|
-
!command.match(/:[^@\s]+(@sha256:|:\w)/)
|
|
98
|
-
) {
|
|
99
|
-
warnings.push(
|
|
100
|
-
"Docker image not version-pinned - consider using specific tags or digests",
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Check for network access patterns
|
|
105
|
-
if (tool.annotations?.openWorldHint !== true) {
|
|
106
|
-
const networkPatterns = [
|
|
107
|
-
/curl\s+/, // HTTP requests
|
|
108
|
-
/wget\s+/, // HTTP requests
|
|
109
|
-
/http[s]?:\/\//, // HTTP URLs
|
|
110
|
-
/ftp:\/\//, // FTP URLs
|
|
111
|
-
/ssh\s+/, // SSH connections
|
|
112
|
-
/scp\s+/, // SCP transfers
|
|
113
|
-
/rsync.*::/, // Rsync over network
|
|
114
|
-
];
|
|
115
|
-
|
|
116
|
-
for (const pattern of networkPatterns) {
|
|
117
|
-
if (pattern.test(command)) {
|
|
118
|
-
warnings.push(
|
|
119
|
-
"Network access detected but openWorldHint not set to true",
|
|
120
|
-
);
|
|
121
|
-
break;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Check for destructive operations
|
|
127
|
-
if (tool.annotations?.destructiveHint !== true) {
|
|
128
|
-
const destructivePatterns = [
|
|
129
|
-
/rm\s+/, // File removal
|
|
130
|
-
/rmdir\s+/, // Directory removal
|
|
131
|
-
/mv\s+.*\s+\/dev\//, // Moving to device files
|
|
132
|
-
/>\s*[^&]/, // File redirection (overwriting)
|
|
133
|
-
/tee\s+/, // Writing to files
|
|
134
|
-
];
|
|
135
|
-
|
|
136
|
-
for (const pattern of destructivePatterns) {
|
|
137
|
-
if (pattern.test(command)) {
|
|
138
|
-
warnings.push(
|
|
139
|
-
"Potentially destructive operation detected but destructiveHint not set to true",
|
|
140
|
-
);
|
|
141
|
-
break;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
isSafe: blocked.length === 0,
|
|
148
|
-
warnings,
|
|
149
|
-
...(blocked.length > 0 && { blocked }),
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Sanitize environment variables to prevent injection attacks
|
|
155
|
-
* @param envVars Environment variables to sanitize
|
|
156
|
-
* @returns Sanitized environment variables
|
|
157
|
-
*/
|
|
158
|
-
export function sanitizeEnvironmentVariables(
|
|
159
|
-
envVars: Record<string, any>,
|
|
160
|
-
): Record<string, string> {
|
|
161
|
-
const sanitized: Record<string, string> = {};
|
|
162
|
-
|
|
163
|
-
for (const [key, value] of Object.entries(envVars)) {
|
|
164
|
-
// Validate environment variable name
|
|
165
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
166
|
-
logger.warn(`Invalid environment variable name: ${key}`);
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Convert value to string and sanitize
|
|
171
|
-
const strValue = String(value);
|
|
172
|
-
|
|
173
|
-
// Check for potentially dangerous characters
|
|
174
|
-
if (strValue.includes("\n") || strValue.includes("\r")) {
|
|
175
|
-
logger.warn(`Environment variable ${key} contains newline characters`);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (strValue.includes("$(") || strValue.includes("`")) {
|
|
179
|
-
logger.warn(
|
|
180
|
-
`Environment variable ${key} contains command substitution patterns`,
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
sanitized[key] = strValue;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return sanitized;
|
|
188
|
-
}
|