@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.
@@ -5,10 +5,33 @@ import logger from "../exec/logger";
5
5
  * Enforce mandatory signature verification for tool execution
6
6
  * This is the central function that should be called before ANY tool execution
7
7
  */
8
+ /**
9
+ * Get security policy based on execution context
10
+ */
11
+ export function getSecurityPolicy(options) {
12
+ // Local files have different security policies
13
+ if (options.isLocalFile) {
14
+ return {
15
+ allowSkipVerification: true,
16
+ allowUnsigned: true,
17
+ requireInteractiveConfirmation: false,
18
+ defaultVerificationPolicy: "permissive",
19
+ };
20
+ }
21
+ // Production/registry tools have strict policies
22
+ return {
23
+ allowSkipVerification: false,
24
+ allowUnsigned: false,
25
+ requireInteractiveConfirmation: !!options.interactive,
26
+ defaultVerificationPolicy: options.verifyPolicy || "permissive",
27
+ };
28
+ }
8
29
  export async function enforceSignatureVerification(tool, options = {}) {
9
30
  const toolName = tool.name || "unknown";
31
+ // Apply centralized security policy based on context
32
+ const securityPolicy = getSecurityPolicy(options);
10
33
  // Check if verification is explicitly skipped
11
- if (options.skipVerification) {
34
+ if (options.skipVerification && securityPolicy.allowSkipVerification) {
12
35
  logger.warn(`🚨 SECURITY WARNING: Signature verification skipped for tool: ${toolName}`);
13
36
  logger.warn(` This bypasses security measures and is NOT recommended for production use!`);
14
37
  return {
@@ -29,8 +52,8 @@ export async function enforceSignatureVerification(tool, options = {}) {
29
52
  !!tool.signature;
30
53
  if (!hasSignatures) {
31
54
  logger.warn(`āš ļø Tool has no signatures: ${toolName}`);
32
- // Only allow unsigned tools if explicitly permitted (for development/testing)
33
- if (options.allowUnsigned) {
55
+ // Only allow unsigned tools if policy permits (for development/testing)
56
+ if (options.allowUnsigned || securityPolicy.allowUnsigned) {
34
57
  logger.warn(` Allowing unsigned tool execution due to allowUnsigned flag (DEV/TEST ONLY)`);
35
58
  return {
36
59
  allowed: true,
@@ -27,8 +27,6 @@ export declare class McpCoreService {
27
27
  */
28
28
  executeToolByName(name: string, inputs?: Record<string, any>, options?: {
29
29
  timeout?: string;
30
- verifyPolicy?: "permissive" | "enterprise" | "paranoid";
31
- skipVerification?: boolean;
32
30
  force?: boolean;
33
31
  dryRun?: boolean;
34
32
  }): Promise<ExecutionResult>;
@@ -37,19 +35,9 @@ export declare class McpCoreService {
37
35
  */
38
36
  executeRawTool(toolYaml: string, inputs?: Record<string, any>, options?: {
39
37
  timeout?: string;
40
- skipVerification?: boolean;
41
38
  force?: boolean;
42
39
  dryRun?: boolean;
43
40
  }): Promise<ExecutionResult>;
44
- /**
45
- * Verify a tool's signature
46
- */
47
- verifyTool(name: string, policy?: string): Promise<{
48
- verified: boolean;
49
- signatures: any[];
50
- policy: string;
51
- errors?: string[];
52
- }>;
53
41
  /**
54
42
  * Check if a tool exists
55
43
  */
@@ -38,8 +38,6 @@ export class McpCoreService {
38
38
  async executeToolByName(name, inputs = {}, options) {
39
39
  const executeOptions = {
40
40
  timeout: options?.timeout,
41
- verifyPolicy: options?.verifyPolicy,
42
- skipVerification: options?.skipVerification,
43
41
  force: options?.force,
44
42
  dryRun: options?.dryRun,
45
43
  };
@@ -51,18 +49,11 @@ export class McpCoreService {
51
49
  async executeRawTool(toolYaml, inputs = {}, options) {
52
50
  const executeOptions = {
53
51
  timeout: options?.timeout,
54
- skipVerification: options?.skipVerification,
55
52
  force: options?.force,
56
53
  dryRun: options?.dryRun,
57
54
  };
58
55
  return await this.core.executeRawTool(toolYaml, inputs, executeOptions);
59
56
  }
60
- /**
61
- * Verify a tool's signature
62
- */
63
- async verifyTool(name, policy) {
64
- return await this.core.verifyTool(name, policy);
65
- }
66
57
  /**
67
58
  * Check if a tool exists
68
59
  */
package/dist/types.d.ts CHANGED
@@ -2,6 +2,7 @@ export interface EnactTool {
2
2
  name: string;
3
3
  description: string;
4
4
  command: string;
5
+ from?: string;
5
6
  timeout?: string;
6
7
  tags?: string[];
7
8
  license?: string;
@@ -47,14 +48,14 @@ export interface EnactTool {
47
48
  value: string;
48
49
  role?: string;
49
50
  };
50
- signatures?: Record<string, {
51
+ signatures?: {
52
+ signer: string;
51
53
  algorithm: string;
52
54
  type: string;
53
- signer: string;
54
- created: string;
55
55
  value: string;
56
+ created: string;
56
57
  role?: string;
57
- }>;
58
+ }[];
58
59
  [key: string]: any;
59
60
  }
60
61
  export interface JSONSchemaDefinition {
@@ -14,7 +14,7 @@ export async function ensureConfig() {
14
14
  await mkdir(CONFIG_DIR, { recursive: true });
15
15
  }
16
16
  if (!existsSync(CONFIG_FILE)) {
17
- await writeConfig({ history: [] });
17
+ await writeFile(CONFIG_FILE, JSON.stringify({ history: [] }, null, 2));
18
18
  }
19
19
  }
20
20
  /**
@@ -1,11 +1,32 @@
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
  * Displays the CLI version with nice formatting
5
8
  */
6
9
  export function showVersion() {
7
- // Bun automatically sets npm_package_version when running scripts via package.json
8
- const version = process.env.npm_package_version || "0.0.1-dev";
10
+ let version = "0.0.1-dev";
11
+ try {
12
+ // Try to get version from environment first (for npm scripts)
13
+ if (process.env.npm_package_version) {
14
+ version = process.env.npm_package_version;
15
+ }
16
+ else {
17
+ // When running as installed binary, read from package.json
18
+ // Go up from shared/dist/utils/version.js to find package.json
19
+ const currentFile = typeof __filename !== 'undefined' ? __filename : fileURLToPath(import.meta.url);
20
+ const sharedDir = dirname(dirname(dirname(currentFile)));
21
+ const packageJsonPath = join(sharedDir, 'package.json');
22
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
23
+ version = packageJson.version;
24
+ }
25
+ }
26
+ catch (error) {
27
+ // Fall back to default version if anything fails
28
+ version = "1.0.14";
29
+ }
9
30
  const versionText = `v${version}`;
10
31
  console.error(`
11
32
  ${pc.bold("Enact CLI")} ${pc.cyan(versionText)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enactprotocol/shared",
3
- "version": "1.0.13",
3
+ "version": "1.2.0",
4
4
  "description": "Shared utilities and core functionality for Enact Protocol",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,10 +22,6 @@
22
22
  "import": "./dist/utils/index.js",
23
23
  "types": "./dist/utils/index.d.ts"
24
24
  },
25
- "./security": {
26
- "import": "./dist/security/index.js",
27
- "types": "./dist/security/index.d.ts"
28
- },
29
25
  "./services": {
30
26
  "import": "./dist/services/index.js",
31
27
  "types": "./dist/services/index.d.ts"
@@ -65,6 +61,7 @@
65
61
  "license": "MIT",
66
62
  "dependencies": {
67
63
  "@dagger.io/dagger": "^0.9.11",
64
+ "@enactprotocol/security": "^0.2.5",
68
65
  "dotenv": "^16.5.0",
69
66
  "pino": "^9.7.0",
70
67
  "pino-pretty": "^13.0.0",
@@ -76,4 +73,4 @@
76
73
  "@types/node": "^20.12.12",
77
74
  "typescript": "^5.4.5"
78
75
  }
79
- }
76
+ }
@@ -62,7 +62,7 @@ export class EnactApiClient {
62
62
  const responseData = await response.json();
63
63
 
64
64
  // Debug logging to help identify response structure issues
65
- if (process.env.NODE_ENV === "development" || process.env.DEBUG) {
65
+ if ((process.env.NODE_ENV === "development" || process.env.DEBUG) && !process.env.ENACT_SILENT) {
66
66
  console.error(`API Response for ${endpoint}:`, responseData);
67
67
  }
68
68
 
@@ -141,7 +141,7 @@ export class EnactApiClient {
141
141
 
142
142
  try {
143
143
  // Log the request for debugging
144
- if (process.env.NODE_ENV === "development" || process.env.DEBUG) {
144
+ if ((process.env.NODE_ENV === "development" || process.env.DEBUG) && !process.env.ENACT_SILENT) {
145
145
  console.error(
146
146
  `Search request to ${endpoint}:`,
147
147
  JSON.stringify(query, null, 2),
package/src/api/types.ts CHANGED
@@ -2,6 +2,7 @@ export interface EnactToolDefinition {
2
2
  name: string;
3
3
  description: string;
4
4
  command: string;
5
+ from?: string;
5
6
  version?: string;
6
7
  timeout?: string;
7
8
  tags?: string[];
@@ -37,7 +38,14 @@ export interface EnactToolDefinition {
37
38
  value: string;
38
39
  role?: string;
39
40
  };
40
- signatures?: Record<string, any>;
41
+ signatures?: {
42
+ signer: string;
43
+ algorithm: string;
44
+ type: string;
45
+ value: string;
46
+ created: string;
47
+ role?: string;
48
+ }[];
41
49
  raw_content?: string;
42
50
  namespace?: string;
43
51
  enact?: string;
@@ -87,7 +95,6 @@ export interface EnactExecOptions {
87
95
  timeout?: string;
88
96
  dry?: boolean;
89
97
  verbose?: boolean;
90
- skipVerification?: boolean; // New option to skip signature verification
91
- verifyPolicy?: string; // Verification policy to use
92
- force?: boolean; // Force execution even if verification fails
98
+ force?: boolean; // Force execution even if verification fails (legacy)
99
+ dangerouslySkipVerification?: boolean; // Skip all signature verification (DANGEROUS)
93
100
  }
@@ -409,6 +409,8 @@ export class DaggerExecutionProvider extends ExecutionProvider {
409
409
  inputs,
410
410
  environment,
411
411
  tool.timeout,
412
+ undefined,
413
+ tool,
412
414
  );
413
415
 
414
416
  logger.debug(
@@ -527,6 +529,7 @@ export class DaggerExecutionProvider extends ExecutionProvider {
527
529
  showSpinner?: boolean;
528
530
  streamOutput?: boolean;
529
531
  },
532
+ tool?: EnactTool,
530
533
  ): Promise<CommandResult> {
531
534
  const verbose = options?.verbose ?? false;
532
535
  const showSpinner = options?.showSpinner ?? false;
@@ -554,17 +557,20 @@ export class DaggerExecutionProvider extends ExecutionProvider {
554
557
  );
555
558
 
556
559
  if (verbose) {
560
+ // Determine which container image to use - prefer tool's 'from' field over default baseImage
561
+ const containerImage = tool?.from || this.options.baseImage!;
562
+
557
563
  try {
558
564
  const pc = require("picocolors");
559
565
  console.error(
560
566
  pc.cyan("\n🐳 Executing Enact command in Dagger container:"),
561
567
  );
562
568
  console.error(pc.white(substitutedCommand));
563
- console.error(pc.gray(`Base image: ${this.options.baseImage}`));
569
+ console.error(pc.gray(`Container image: ${containerImage}${tool?.from ? ' (from tool.from)' : ' (default baseImage)'}`));
564
570
  } catch (e) {
565
571
  console.error("\n🐳 Executing Enact command in Dagger container:");
566
572
  console.error(substitutedCommand);
567
- console.error(`Base image: ${this.options.baseImage}`);
573
+ console.error(`Container image: ${containerImage}${tool?.from ? ' (from tool.from)' : ' (default baseImage)'}`);
568
574
  }
569
575
  }
570
576
 
@@ -577,7 +583,7 @@ export class DaggerExecutionProvider extends ExecutionProvider {
577
583
 
578
584
  // Execute command with enhanced error handling and timeout management
579
585
  const result = await Promise.race([
580
- this.executeWithConnect(substitutedCommand, environment, inputs),
586
+ this.executeWithConnect(substitutedCommand, environment, inputs, tool),
581
587
  this.createTimeoutPromise(effectiveTimeout),
582
588
  ]);
583
589
 
@@ -627,6 +633,7 @@ export class DaggerExecutionProvider extends ExecutionProvider {
627
633
  command: string,
628
634
  environment: ExecutionEnvironment,
629
635
  inputs: Record<string, any>,
636
+ tool?: EnactTool,
630
637
  ): Promise<CommandResult> {
631
638
  return new Promise<CommandResult>((resolve, reject) => {
632
639
  // Setup abort handling
@@ -645,6 +652,7 @@ export class DaggerExecutionProvider extends ExecutionProvider {
645
652
  client,
646
653
  environment,
647
654
  inputs,
655
+ tool,
648
656
  );
649
657
  logger.debug("šŸ“¦ Container setup complete");
650
658
  const commandResult = await this.executeInContainer(
@@ -698,13 +706,17 @@ export class DaggerExecutionProvider extends ExecutionProvider {
698
706
  client: Client,
699
707
  environment: ExecutionEnvironment,
700
708
  inputs: Record<string, any>,
709
+ tool?: EnactTool,
701
710
  ): Promise<Container> {
711
+ // Determine which container image to use - prefer tool's 'from' field over default baseImage
712
+ const containerImage = tool?.from || this.options.baseImage!;
713
+
702
714
  logger.debug(
703
- `šŸš€ Setting up container with base image: ${this.options.baseImage}`,
715
+ `šŸš€ Setting up container with image: ${containerImage}${tool?.from ? ' (from tool.from)' : ' (default baseImage)'}`,
704
716
  );
705
717
 
706
718
  // Start with base container
707
- let container = client.container().from(this.options.baseImage!);
719
+ let container = client.container().from(containerImage);
708
720
  logger.debug("šŸ“¦ Base container created");
709
721
 
710
722
  // Set working directory
@@ -721,7 +733,7 @@ export class DaggerExecutionProvider extends ExecutionProvider {
721
733
 
722
734
  // Install common tools needed for Enact commands
723
735
  if (this.options.enableNetwork) {
724
- container = await this.installCommonTools(container);
736
+ container = await this.installCommonTools(container, containerImage);
725
737
  logger.debug("šŸ”§ Common tools installed");
726
738
  } else {
727
739
  logger.debug("šŸ”§ Skipping common tools installation (network disabled)");
@@ -745,14 +757,14 @@ export class DaggerExecutionProvider extends ExecutionProvider {
745
757
  * Install common tools that Enact commands might need
746
758
  * Enhanced with better error handling and timeout
747
759
  */
748
- private async installCommonTools(container: Container): Promise<Container> {
760
+ private async installCommonTools(container: Container, containerImage: string): Promise<Container> {
749
761
  logger.debug(
750
- `šŸ”§ Installing common tools for base image: ${this.options.baseImage}`,
762
+ `šŸ”§ Installing common tools for container image: ${containerImage}`,
751
763
  );
752
764
 
753
765
  try {
754
766
  // For node images, most tools are already available, so we can skip installation
755
- if (this.options.baseImage?.includes("node:")) {
767
+ if (containerImage.includes("node:")) {
756
768
  logger.debug(
757
769
  "šŸ“¦ Node.js image detected, skipping tool installation (most tools already available)",
758
770
  );
@@ -760,10 +772,10 @@ export class DaggerExecutionProvider extends ExecutionProvider {
760
772
  }
761
773
 
762
774
  // Determine package manager based on base image
763
- const isAlpine = this.options.baseImage?.includes("alpine");
775
+ const isAlpine = containerImage.includes("alpine");
764
776
  const isDebian =
765
- this.options.baseImage?.includes("debian") ||
766
- this.options.baseImage?.includes("ubuntu");
777
+ containerImage.includes("debian") ||
778
+ containerImage.includes("ubuntu");
767
779
 
768
780
  if (isAlpine) {
769
781
  logger.debug("šŸ“¦ Detected Alpine Linux, installing basic tools");
@@ -783,7 +795,7 @@ export class DaggerExecutionProvider extends ExecutionProvider {
783
795
  ]);
784
796
  } else {
785
797
  logger.warn(
786
- `Unknown base image ${this.options.baseImage}, skipping tool installation`,
798
+ `Unknown container image ${containerImage}, skipping tool installation`,
787
799
  );
788
800
  }
789
801
 
@@ -1161,6 +1173,7 @@ export class DaggerExecutionProvider extends ExecutionProvider {
1161
1173
  showSpinner: true,
1162
1174
  streamOutput: false,
1163
1175
  },
1176
+ undefined, // no tool parameter for backwards compatibility
1164
1177
  );
1165
1178
 
1166
1179
  if (result.exitCode !== 0) {