@enactprotocol/shared 1.2.13 → 2.0.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 (207) hide show
  1. package/README.md +44 -0
  2. package/dist/config.d.ts +164 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +386 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/constants.d.ts +15 -5
  7. package/dist/constants.d.ts.map +1 -0
  8. package/dist/constants.js +24 -8
  9. package/dist/constants.js.map +1 -0
  10. package/dist/execution/command.d.ts +102 -0
  11. package/dist/execution/command.d.ts.map +1 -0
  12. package/dist/execution/command.js +262 -0
  13. package/dist/execution/command.js.map +1 -0
  14. package/dist/execution/index.d.ts +12 -0
  15. package/dist/execution/index.d.ts.map +1 -0
  16. package/dist/execution/index.js +17 -0
  17. package/dist/execution/index.js.map +1 -0
  18. package/dist/execution/runtime.d.ts +82 -0
  19. package/dist/execution/runtime.d.ts.map +1 -0
  20. package/dist/execution/runtime.js +273 -0
  21. package/dist/execution/runtime.js.map +1 -0
  22. package/dist/execution/types.d.ts +306 -0
  23. package/dist/execution/types.d.ts.map +1 -0
  24. package/dist/execution/types.js +14 -0
  25. package/dist/execution/types.js.map +1 -0
  26. package/dist/execution/validation.d.ts +43 -0
  27. package/dist/execution/validation.d.ts.map +1 -0
  28. package/dist/execution/validation.js +430 -0
  29. package/dist/execution/validation.js.map +1 -0
  30. package/dist/index.d.ts +21 -21
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +49 -25
  33. package/dist/index.js.map +1 -0
  34. package/dist/manifest/index.d.ts +7 -0
  35. package/dist/manifest/index.d.ts.map +1 -0
  36. package/dist/manifest/index.js +10 -0
  37. package/dist/manifest/index.js.map +1 -0
  38. package/dist/manifest/loader.d.ts +76 -0
  39. package/dist/manifest/loader.d.ts.map +1 -0
  40. package/dist/manifest/loader.js +146 -0
  41. package/dist/manifest/loader.js.map +1 -0
  42. package/dist/manifest/parser.d.ts +64 -0
  43. package/dist/manifest/parser.d.ts.map +1 -0
  44. package/dist/manifest/parser.js +135 -0
  45. package/dist/manifest/parser.js.map +1 -0
  46. package/dist/manifest/validator.d.ts +95 -0
  47. package/dist/manifest/validator.d.ts.map +1 -0
  48. package/dist/manifest/validator.js +258 -0
  49. package/dist/manifest/validator.js.map +1 -0
  50. package/dist/paths.d.ts +57 -0
  51. package/dist/paths.d.ts.map +1 -0
  52. package/dist/paths.js +93 -0
  53. package/dist/paths.js.map +1 -0
  54. package/dist/registry.d.ts +73 -0
  55. package/dist/registry.d.ts.map +1 -0
  56. package/dist/registry.js +147 -0
  57. package/dist/registry.js.map +1 -0
  58. package/dist/resolver.d.ts +89 -0
  59. package/dist/resolver.d.ts.map +1 -0
  60. package/dist/resolver.js +282 -0
  61. package/dist/resolver.js.map +1 -0
  62. package/dist/types/index.d.ts +6 -0
  63. package/dist/types/index.d.ts.map +1 -0
  64. package/dist/types/index.js +5 -0
  65. package/dist/types/index.js.map +1 -0
  66. package/dist/types/manifest.d.ts +201 -0
  67. package/dist/types/manifest.d.ts.map +1 -0
  68. package/dist/types/manifest.js +13 -0
  69. package/dist/types/manifest.js.map +1 -0
  70. package/dist/types.d.ts +5 -132
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +5 -3
  73. package/dist/types.js.map +1 -0
  74. package/dist/utils/fs.d.ts +105 -0
  75. package/dist/utils/fs.d.ts.map +1 -0
  76. package/dist/utils/fs.js +233 -0
  77. package/dist/utils/fs.js.map +1 -0
  78. package/dist/utils/logger.d.ts +102 -25
  79. package/dist/utils/logger.d.ts.map +1 -0
  80. package/dist/utils/logger.js +214 -57
  81. package/dist/utils/logger.js.map +1 -0
  82. package/dist/utils/version.d.ts +60 -2
  83. package/dist/utils/version.d.ts.map +1 -0
  84. package/dist/utils/version.js +255 -31
  85. package/dist/utils/version.js.map +1 -0
  86. package/package.json +16 -58
  87. package/src/config.ts +510 -0
  88. package/src/constants.ts +36 -0
  89. package/src/execution/command.ts +314 -0
  90. package/src/execution/index.ts +73 -0
  91. package/src/execution/runtime.ts +308 -0
  92. package/src/execution/types.ts +379 -0
  93. package/src/execution/validation.ts +508 -0
  94. package/src/index.ts +238 -30
  95. package/src/manifest/index.ts +36 -0
  96. package/src/manifest/loader.ts +187 -0
  97. package/src/manifest/parser.ts +173 -0
  98. package/src/manifest/validator.ts +309 -0
  99. package/src/paths.ts +108 -0
  100. package/src/registry.ts +219 -0
  101. package/src/resolver.ts +345 -0
  102. package/src/types/index.ts +30 -0
  103. package/src/types/manifest.ts +255 -0
  104. package/src/types.ts +5 -188
  105. package/src/utils/fs.ts +281 -0
  106. package/src/utils/logger.ts +270 -59
  107. package/src/utils/version.ts +304 -36
  108. package/tests/config.test.ts +515 -0
  109. package/tests/execution/command.test.ts +317 -0
  110. package/tests/execution/validation.test.ts +384 -0
  111. package/tests/fixtures/invalid-tool.yaml +4 -0
  112. package/tests/fixtures/valid-tool.md +62 -0
  113. package/tests/fixtures/valid-tool.yaml +40 -0
  114. package/tests/index.test.ts +8 -0
  115. package/tests/manifest/loader.test.ts +291 -0
  116. package/tests/manifest/parser.test.ts +345 -0
  117. package/tests/manifest/validator.test.ts +394 -0
  118. package/tests/manifest-types.test.ts +358 -0
  119. package/tests/paths.test.ts +153 -0
  120. package/tests/registry.test.ts +231 -0
  121. package/tests/resolver.test.ts +272 -0
  122. package/tests/utils/fs.test.ts +388 -0
  123. package/tests/utils/logger.test.ts +480 -0
  124. package/tests/utils/version.test.ts +390 -0
  125. package/tsconfig.json +12 -0
  126. package/dist/LocalToolResolver.d.ts +0 -84
  127. package/dist/LocalToolResolver.js +0 -353
  128. package/dist/api/enact-api.d.ts +0 -130
  129. package/dist/api/enact-api.js +0 -428
  130. package/dist/api/index.d.ts +0 -2
  131. package/dist/api/index.js +0 -2
  132. package/dist/api/types.d.ts +0 -103
  133. package/dist/api/types.js +0 -1
  134. package/dist/core/DaggerExecutionProvider.d.ts +0 -169
  135. package/dist/core/DaggerExecutionProvider.js +0 -1029
  136. package/dist/core/DirectExecutionProvider.d.ts +0 -23
  137. package/dist/core/DirectExecutionProvider.js +0 -406
  138. package/dist/core/EnactCore.d.ts +0 -162
  139. package/dist/core/EnactCore.js +0 -597
  140. package/dist/core/NativeExecutionProvider.d.ts +0 -9
  141. package/dist/core/NativeExecutionProvider.js +0 -16
  142. package/dist/core/index.d.ts +0 -3
  143. package/dist/core/index.js +0 -3
  144. package/dist/exec/index.d.ts +0 -3
  145. package/dist/exec/index.js +0 -3
  146. package/dist/exec/logger.d.ts +0 -11
  147. package/dist/exec/logger.js +0 -57
  148. package/dist/exec/validate.d.ts +0 -5
  149. package/dist/exec/validate.js +0 -167
  150. package/dist/lib/enact-direct.d.ts +0 -150
  151. package/dist/lib/enact-direct.js +0 -159
  152. package/dist/lib/index.d.ts +0 -1
  153. package/dist/lib/index.js +0 -1
  154. package/dist/security/index.d.ts +0 -3
  155. package/dist/security/index.js +0 -3
  156. package/dist/security/security.d.ts +0 -23
  157. package/dist/security/security.js +0 -137
  158. package/dist/security/sign.d.ts +0 -103
  159. package/dist/security/sign.js +0 -666
  160. package/dist/security/verification-enforcer.d.ts +0 -53
  161. package/dist/security/verification-enforcer.js +0 -204
  162. package/dist/services/McpCoreService.d.ts +0 -98
  163. package/dist/services/McpCoreService.js +0 -124
  164. package/dist/services/index.d.ts +0 -1
  165. package/dist/services/index.js +0 -1
  166. package/dist/utils/config.d.ts +0 -111
  167. package/dist/utils/config.js +0 -342
  168. package/dist/utils/env-loader.d.ts +0 -54
  169. package/dist/utils/env-loader.js +0 -270
  170. package/dist/utils/help.d.ts +0 -36
  171. package/dist/utils/help.js +0 -248
  172. package/dist/utils/index.d.ts +0 -7
  173. package/dist/utils/index.js +0 -7
  174. package/dist/utils/silent-monitor.d.ts +0 -67
  175. package/dist/utils/silent-monitor.js +0 -242
  176. package/dist/utils/timeout.d.ts +0 -5
  177. package/dist/utils/timeout.js +0 -23
  178. package/dist/web/env-manager-server.d.ts +0 -29
  179. package/dist/web/env-manager-server.js +0 -367
  180. package/dist/web/index.d.ts +0 -1
  181. package/dist/web/index.js +0 -1
  182. package/src/LocalToolResolver.ts +0 -424
  183. package/src/api/enact-api.ts +0 -604
  184. package/src/api/index.ts +0 -2
  185. package/src/api/types.ts +0 -114
  186. package/src/core/DaggerExecutionProvider.ts +0 -1357
  187. package/src/core/DirectExecutionProvider.ts +0 -484
  188. package/src/core/EnactCore.ts +0 -847
  189. package/src/core/index.ts +0 -3
  190. package/src/exec/index.ts +0 -3
  191. package/src/exec/logger.ts +0 -63
  192. package/src/exec/validate.ts +0 -238
  193. package/src/lib/enact-direct.ts +0 -254
  194. package/src/lib/index.ts +0 -1
  195. package/src/services/McpCoreService.ts +0 -201
  196. package/src/services/index.ts +0 -1
  197. package/src/utils/config.ts +0 -438
  198. package/src/utils/env-loader.ts +0 -370
  199. package/src/utils/help.ts +0 -257
  200. package/src/utils/index.ts +0 -7
  201. package/src/utils/silent-monitor.ts +0 -328
  202. package/src/utils/timeout.ts +0 -26
  203. package/src/web/env-manager-server.ts +0 -465
  204. package/src/web/index.ts +0 -1
  205. package/src/web/static/app.js +0 -663
  206. package/src/web/static/index.html +0 -117
  207. package/src/web/static/style.css +0 -291
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@enactprotocol/shared",
3
- "version": "1.2.13",
4
- "description": "Shared utilities and core functionality for Enact Protocol",
3
+ "version": "2.0.1",
4
+ "description": "Core business logic and utilities for Enact",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -9,68 +9,26 @@
9
9
  ".": {
10
10
  "import": "./dist/index.js",
11
11
  "types": "./dist/index.d.ts"
12
- },
13
- "./core": {
14
- "import": "./dist/core/index.js",
15
- "types": "./dist/core/index.d.ts"
16
- },
17
- "./exec": {
18
- "import": "./dist/exec/index.js",
19
- "types": "./dist/exec/index.d.ts"
20
- },
21
- "./utils": {
22
- "import": "./dist/utils/index.js",
23
- "types": "./dist/utils/index.d.ts"
24
- },
25
- "./services": {
26
- "import": "./dist/services/index.js",
27
- "types": "./dist/services/index.d.ts"
28
- },
29
- "./web": {
30
- "import": "./dist/web/index.js",
31
- "types": "./dist/web/index.d.ts"
32
- },
33
- "./api": {
34
- "import": "./dist/api/index.js",
35
- "types": "./dist/api/index.d.ts"
36
- },
37
- "./lib": {
38
- "import": "./dist/lib/index.js",
39
- "types": "./dist/lib/index.d.ts"
40
12
  }
41
13
  },
42
- "files": [
43
- "dist/**/*",
44
- "src/**/*"
45
- ],
46
14
  "scripts": {
47
- "build": "tsc",
48
- "dev": "tsc --watch",
15
+ "build": "tsc --build",
16
+ "clean": "rm -rf dist",
49
17
  "test": "bun test",
50
- "test:watch": "bun test --watch",
51
- "test:coverage": "bun test --coverage"
18
+ "typecheck": "tsc --noEmit"
52
19
  },
53
- "keywords": [
54
- "enact",
55
- "enact-protocol",
56
- "shared",
57
- "utilities",
58
- "core"
59
- ],
60
- "author": "EnactProtocol",
61
- "license": "MIT",
62
20
  "dependencies": {
63
- "@dagger.io/dagger": "^0.9.11",
64
- "@enactprotocol/security": "0.2.7",
65
- "dotenv": "^16.5.0",
66
- "pino": "^9.7.0",
67
- "pino-pretty": "^13.0.0",
68
- "strip-ansi": "^7.1.0",
69
- "yaml": "^2.8.0",
70
- "zod": "^3.25.67"
21
+ "@enactprotocol/trust": "workspace:*",
22
+ "js-yaml": "^4.1.1",
23
+ "zod": "^4.1.13"
71
24
  },
72
25
  "devDependencies": {
73
- "@types/node": "^20.12.12",
74
- "typescript": "^5.4.5"
75
- }
26
+ "@types/js-yaml": "^4.0.9",
27
+ "@types/json-schema": "^7.0.15",
28
+ "@types/node": "^22.10.1",
29
+ "typescript": "^5.7.2"
30
+ },
31
+ "keywords": ["enact", "core", "manifest", "execution"],
32
+ "author": "Enact Protocol",
33
+ "license": "Apache-2.0"
76
34
  }
package/src/config.ts ADDED
@@ -0,0 +1,510 @@
1
+ /**
2
+ * Configuration manager for Enact CLI
3
+ * Handles reading and writing ~/.enact/config.yaml
4
+ */
5
+
6
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
7
+ import { dirname, join } from "node:path";
8
+ import yaml from "js-yaml";
9
+ import { getConfigPath, getEnactHome } from "./paths";
10
+
11
+ /**
12
+ * Trust configuration for attestation verification
13
+ *
14
+ * Uses a unified model: all trust is based on cryptographic attestations.
15
+ * Publishers who want their tools trusted should self-sign them.
16
+ * Third-party reviewers can add additional attestations.
17
+ */
18
+ export interface TrustConfig {
19
+ /**
20
+ * List of trusted auditor identities (provider:identity format, e.g., github:alice)
21
+ * Anyone who signs with these identities is trusted - whether they authored
22
+ * the tool (self-attestation) or reviewed it (third-party audit).
23
+ */
24
+ auditors?: string[];
25
+ /** Trust policy: 'require_attestation' blocks without trust, 'prompt' asks user, 'allow' installs anyway */
26
+ policy?: "require_attestation" | "prompt" | "allow";
27
+ /** Minimum number of trusted attestations required */
28
+ minimum_attestations?: number;
29
+ }
30
+
31
+ /**
32
+ * Cache configuration
33
+ */
34
+ export interface CacheConfig {
35
+ /** Maximum cache size in megabytes */
36
+ maxSizeMb?: number;
37
+ /** Cache TTL in seconds */
38
+ ttlSeconds?: number;
39
+ }
40
+
41
+ /**
42
+ * Execution configuration
43
+ */
44
+ export interface ExecutionConfig {
45
+ /** Default timeout for tool execution (e.g., "30s", "5m") */
46
+ defaultTimeout?: string;
47
+ /** Whether to run in verbose mode */
48
+ verbose?: boolean;
49
+ }
50
+
51
+ /**
52
+ * Registry configuration
53
+ */
54
+ export interface RegistryConfig {
55
+ /** Default registry URL */
56
+ url?: string;
57
+ /** Authentication token for registry (stored reference, not actual token) */
58
+ authTokenRef?: string;
59
+ /** Direct authentication token (for local development) */
60
+ authToken?: string;
61
+ }
62
+
63
+ /**
64
+ * Complete Enact configuration
65
+ */
66
+ export interface EnactConfig {
67
+ /** Configuration file version */
68
+ version?: string;
69
+ /** Trust settings for verification */
70
+ trust?: TrustConfig;
71
+ /** Cache settings */
72
+ cache?: CacheConfig;
73
+ /** Execution defaults */
74
+ execution?: ExecutionConfig;
75
+ /** Registry settings */
76
+ registry?: RegistryConfig;
77
+ }
78
+
79
+ /**
80
+ * Default configuration values
81
+ */
82
+ export const DEFAULT_CONFIG: EnactConfig = {
83
+ version: "1.0.0",
84
+ trust: {
85
+ auditors: [],
86
+ policy: "prompt",
87
+ minimum_attestations: 1,
88
+ },
89
+ cache: {
90
+ maxSizeMb: 1024, // 1GB
91
+ ttlSeconds: 86400 * 7, // 7 days
92
+ },
93
+ execution: {
94
+ defaultTimeout: "30s",
95
+ verbose: false,
96
+ },
97
+ registry: {
98
+ url: "https://siikwkfgsmouioodghho.supabase.co/functions/v1",
99
+ },
100
+ };
101
+
102
+ /**
103
+ * Deep merge two objects, with source values overwriting target values
104
+ */
105
+ function deepMerge(target: EnactConfig, source: Partial<EnactConfig>): EnactConfig {
106
+ const result: EnactConfig = { ...target };
107
+
108
+ // Merge trust config
109
+ if (source.trust !== undefined) {
110
+ result.trust = { ...target.trust, ...source.trust };
111
+ }
112
+
113
+ // Merge cache config
114
+ if (source.cache !== undefined) {
115
+ result.cache = { ...target.cache, ...source.cache };
116
+ }
117
+
118
+ // Merge execution config
119
+ if (source.execution !== undefined) {
120
+ result.execution = { ...target.execution, ...source.execution };
121
+ }
122
+
123
+ // Merge registry config
124
+ if (source.registry !== undefined) {
125
+ result.registry = { ...target.registry, ...source.registry };
126
+ }
127
+
128
+ // Copy top-level primitives
129
+ if (source.version !== undefined) {
130
+ result.version = source.version;
131
+ }
132
+
133
+ return result;
134
+ }
135
+
136
+ /**
137
+ * Load configuration from ~/.enact/config.yaml
138
+ * Returns default config if file doesn't exist or is invalid
139
+ * @returns The loaded configuration merged with defaults
140
+ */
141
+ export function loadConfig(): EnactConfig {
142
+ const configPath = getConfigPath();
143
+
144
+ if (!existsSync(configPath)) {
145
+ return { ...DEFAULT_CONFIG };
146
+ }
147
+
148
+ try {
149
+ const content = readFileSync(configPath, "utf-8");
150
+ const parsed = yaml.load(content) as Partial<EnactConfig> | null;
151
+
152
+ if (!parsed || typeof parsed !== "object") {
153
+ return { ...DEFAULT_CONFIG };
154
+ }
155
+
156
+ // Merge with defaults to ensure all fields exist
157
+ return deepMerge(DEFAULT_CONFIG, parsed);
158
+ } catch {
159
+ // Return defaults on any error (parse error, read error, etc.)
160
+ return { ...DEFAULT_CONFIG };
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Save configuration to ~/.enact/config.yaml
166
+ * Creates the ~/.enact/ directory if it doesn't exist
167
+ * @param config - The configuration to save
168
+ */
169
+ export function saveConfig(config: EnactConfig): void {
170
+ const configPath = getConfigPath();
171
+ const enactHome = getEnactHome();
172
+
173
+ // Ensure ~/.enact/ directory exists
174
+ if (!existsSync(enactHome)) {
175
+ mkdirSync(enactHome, { recursive: true });
176
+ }
177
+
178
+ // Ensure parent directory exists (should be ~/.enact/ but be safe)
179
+ const parentDir = dirname(configPath);
180
+ if (!existsSync(parentDir)) {
181
+ mkdirSync(parentDir, { recursive: true });
182
+ }
183
+
184
+ const yamlContent = yaml.dump(config, {
185
+ indent: 2,
186
+ lineWidth: 120,
187
+ noRefs: true,
188
+ });
189
+
190
+ writeFileSync(configPath, yamlContent, "utf-8");
191
+ }
192
+
193
+ /**
194
+ * Get a configuration value by dot-notation key path
195
+ * @param key - Dot-notation path (e.g., "trust.policy", "cache.maxSizeMb")
196
+ * @param defaultValue - Default value if key doesn't exist
197
+ * @returns The configuration value or default
198
+ */
199
+ export function getConfigValue<T>(key: string, defaultValue: T): T {
200
+ const config = loadConfig();
201
+ const keys = key.split(".");
202
+
203
+ let current: unknown = config;
204
+ for (const k of keys) {
205
+ if (current === null || current === undefined || typeof current !== "object") {
206
+ return defaultValue;
207
+ }
208
+ current = (current as Record<string, unknown>)[k];
209
+ }
210
+
211
+ return current === undefined ? defaultValue : (current as T);
212
+ }
213
+
214
+ /**
215
+ * Set a configuration value by dot-notation key path and persist
216
+ * @param key - Dot-notation path (e.g., "trust.policy", "cache.maxSizeMb")
217
+ * @param value - The value to set
218
+ */
219
+ export function setConfigValue<T>(key: string, value: T): void {
220
+ const config = loadConfig();
221
+ const keys = key.split(".");
222
+ const lastKey = keys.pop();
223
+
224
+ if (!lastKey) {
225
+ throw new Error("Invalid configuration key");
226
+ }
227
+
228
+ // Navigate to parent object, creating intermediate objects as needed
229
+ let current: Record<string, unknown> = config as Record<string, unknown>;
230
+ for (const k of keys) {
231
+ if (current[k] === undefined || current[k] === null || typeof current[k] !== "object") {
232
+ current[k] = {};
233
+ }
234
+ current = current[k] as Record<string, unknown>;
235
+ }
236
+
237
+ // Set the value
238
+ current[lastKey] = value;
239
+
240
+ // Persist
241
+ saveConfig(config);
242
+ }
243
+
244
+ /**
245
+ * Reset configuration to defaults
246
+ * This will overwrite the existing config file
247
+ */
248
+ export function resetConfig(): void {
249
+ saveConfig({ ...DEFAULT_CONFIG });
250
+ }
251
+
252
+ /**
253
+ * Check if a configuration file exists
254
+ * @returns true if ~/.enact/config.yaml exists
255
+ */
256
+ export function configExists(): boolean {
257
+ return existsSync(getConfigPath());
258
+ }
259
+
260
+ /**
261
+ * Ensure global setup is complete
262
+ * Creates ~/.enact/ directory structure and default config if they don't exist.
263
+ * This is a non-interactive initialization that runs silently.
264
+ * @returns true if setup was performed, false if already initialized
265
+ */
266
+ export function ensureGlobalSetup(): boolean {
267
+ const enactHome = getEnactHome();
268
+ const configPath = getConfigPath();
269
+ const cacheDir = join(enactHome, "cache");
270
+
271
+ let performedSetup = false;
272
+
273
+ // Ensure ~/.enact/ directory exists
274
+ if (!existsSync(enactHome)) {
275
+ mkdirSync(enactHome, { recursive: true });
276
+ performedSetup = true;
277
+ }
278
+
279
+ // Ensure ~/.enact/cache/ directory exists
280
+ if (!existsSync(cacheDir)) {
281
+ mkdirSync(cacheDir, { recursive: true });
282
+ performedSetup = true;
283
+ }
284
+
285
+ // Create default config if it doesn't exist
286
+ if (!existsSync(configPath)) {
287
+ saveConfig({ ...DEFAULT_CONFIG });
288
+ performedSetup = true;
289
+ }
290
+
291
+ return performedSetup;
292
+ }
293
+
294
+ // =============================================================================
295
+ // Local Trust Management
296
+ // =============================================================================
297
+
298
+ /**
299
+ * Get list of trusted identities from local config
300
+ * @returns Array of identities in provider:identity format
301
+ */
302
+ export function getTrustedIdentities(): string[] {
303
+ const config = loadConfig();
304
+ return config.trust?.auditors ?? [];
305
+ }
306
+
307
+ /**
308
+ * Add an identity to the local trusted list
309
+ * @param identity - Identity in provider:identity format (e.g., github:alice)
310
+ * @returns true if added, false if already exists
311
+ */
312
+ export function addTrustedIdentity(identity: string): boolean {
313
+ const config = loadConfig();
314
+ const auditors = config.trust?.auditors ?? [];
315
+
316
+ // Check if already exists
317
+ if (auditors.includes(identity)) {
318
+ return false;
319
+ }
320
+
321
+ // Add to list
322
+ auditors.push(identity);
323
+
324
+ // Update config
325
+ if (!config.trust) {
326
+ config.trust = { ...DEFAULT_CONFIG.trust };
327
+ }
328
+ config.trust.auditors = auditors;
329
+
330
+ saveConfig(config);
331
+ return true;
332
+ }
333
+
334
+ /**
335
+ * Remove an identity from the local trusted list
336
+ * @param identity - Identity in provider:identity format
337
+ * @returns true if removed, false if not found
338
+ */
339
+ export function removeTrustedIdentity(identity: string): boolean {
340
+ const config = loadConfig();
341
+ const auditors = config.trust?.auditors ?? [];
342
+
343
+ const index = auditors.indexOf(identity);
344
+ if (index === -1) {
345
+ return false;
346
+ }
347
+
348
+ // Remove from list
349
+ auditors.splice(index, 1);
350
+
351
+ // Update config
352
+ if (!config.trust) {
353
+ config.trust = { ...DEFAULT_CONFIG.trust };
354
+ }
355
+ config.trust.auditors = auditors;
356
+
357
+ saveConfig(config);
358
+ return true;
359
+ }
360
+
361
+ /**
362
+ * Check if an identity is in the local trusted list
363
+ * Supports wildcards like github:my-org/* and *@company.com
364
+ * @param identity - Identity to check
365
+ * @returns true if trusted
366
+ */
367
+ export function isIdentityTrusted(identity: string): boolean {
368
+ const trustedIdentities = getTrustedIdentities();
369
+
370
+ // Check exact match first
371
+ if (trustedIdentities.includes(identity)) {
372
+ return true;
373
+ }
374
+
375
+ // Check wildcard matches (e.g., github:my-org/* matches github:my-org/alice)
376
+ for (const trusted of trustedIdentities) {
377
+ if (trusted.endsWith("/*")) {
378
+ const prefix = trusted.slice(0, -2); // Remove /*
379
+ if (identity.startsWith(`${prefix}/`)) {
380
+ return true;
381
+ }
382
+ }
383
+
384
+ // Check email wildcards (e.g., *@company.com)
385
+ if (trusted.includes("*@")) {
386
+ const domainPart = trusted.split("*@")[1];
387
+ if (identity.endsWith(`@${domainPart}`)) {
388
+ return true;
389
+ }
390
+ }
391
+ }
392
+
393
+ return false;
394
+ }
395
+
396
+ // Legacy aliases for backward compatibility
397
+ /** @deprecated Use getTrustedIdentities instead */
398
+ export const getTrustedAuditors = getTrustedIdentities;
399
+ /** @deprecated Use addTrustedIdentity instead */
400
+ export const addTrustedAuditor = addTrustedIdentity;
401
+ /** @deprecated Use removeTrustedIdentity instead */
402
+ export const removeTrustedAuditor = removeTrustedIdentity;
403
+ /** @deprecated Use isIdentityTrusted instead */
404
+ export const isAuditorTrusted = isIdentityTrusted;
405
+
406
+ /**
407
+ * Convert OIDC identity to provider:identity format
408
+ * @param email - Email from Sigstore certificate
409
+ * @param issuer - OIDC issuer URL (optional, improves accuracy)
410
+ * @param username - Provider username if known (optional)
411
+ * @returns Identity in provider:identity format (e.g., github:keithagroves)
412
+ */
413
+ export function emailToProviderIdentity(email: string, issuer?: string, username?: string): string {
414
+ // If we have a username and can determine the provider, use that
415
+ if (username && issuer) {
416
+ const provider = issuerToProvider(issuer);
417
+ if (provider) {
418
+ return `${provider}:${username}`;
419
+ }
420
+ }
421
+
422
+ // Determine provider from issuer URL if available
423
+ if (issuer) {
424
+ const provider = issuerToProvider(issuer);
425
+ if (provider) {
426
+ // Try to extract username from email for GitHub
427
+ if (provider === "github" && email.endsWith("@users.noreply.github.com")) {
428
+ // GitHub noreply format: "123456+username@users.noreply.github.com"
429
+ // or just "username@users.noreply.github.com"
430
+ const localPart = email.replace("@users.noreply.github.com", "");
431
+ const plusIndex = localPart.indexOf("+");
432
+ const extractedUsername = plusIndex >= 0 ? localPart.slice(plusIndex + 1) : localPart;
433
+ return `github:${extractedUsername}`;
434
+ }
435
+ // Use email as the identity since we don't have username
436
+ return `${provider}:${email}`;
437
+ }
438
+ }
439
+
440
+ // Common OIDC providers and their email domains (fallback)
441
+ const providerMap: Record<string, string> = {
442
+ "@users.noreply.github.com": "github",
443
+ "@github.com": "github",
444
+ "@gmail.com": "google",
445
+ "@googlemail.com": "google",
446
+ "@outlook.com": "microsoft",
447
+ "@hotmail.com": "microsoft",
448
+ "@live.com": "microsoft",
449
+ };
450
+
451
+ // Try to match provider by email domain
452
+ for (const [domain, provider] of Object.entries(providerMap)) {
453
+ if (email.endsWith(domain)) {
454
+ let extractedUsername = email.substring(0, email.length - domain.length);
455
+ // Handle GitHub noreply format: "123456+username@users.noreply.github.com"
456
+ if (provider === "github" && domain === "@users.noreply.github.com") {
457
+ const plusIndex = extractedUsername.indexOf("+");
458
+ if (plusIndex >= 0) {
459
+ extractedUsername = extractedUsername.slice(plusIndex + 1);
460
+ }
461
+ }
462
+ return `${provider}:${extractedUsername}`;
463
+ }
464
+ }
465
+
466
+ // If no match, check for GitHub workflow identity
467
+ // Format: https://github.com/{org}/{workflow}
468
+ if (email.startsWith("https://github.com/")) {
469
+ const path = email.replace("https://github.com/", "");
470
+ return `github:${path}`;
471
+ }
472
+
473
+ // Fall back to email as-is
474
+ return email;
475
+ }
476
+
477
+ /**
478
+ * Convert OIDC issuer URL to provider name
479
+ */
480
+ function issuerToProvider(issuer: string): string | undefined {
481
+ if (issuer.includes("github.com")) return "github";
482
+ if (issuer.includes("accounts.google.com")) return "google";
483
+ if (issuer.includes("login.microsoftonline.com")) return "microsoft";
484
+ if (issuer.includes("gitlab.com")) return "gitlab";
485
+ return undefined;
486
+ }
487
+
488
+ /**
489
+ * Get minimum required attestations from config
490
+ * @returns Minimum number of trusted attestations required
491
+ */
492
+ export function getMinimumAttestations(): number {
493
+ const config = loadConfig();
494
+ return config.trust?.minimum_attestations ?? 1;
495
+ }
496
+
497
+ /**
498
+ * Get trust policy from config
499
+ * @returns Trust policy: 'require_attestation', 'prompt', or 'allow'
500
+ */
501
+ export function getTrustPolicy(): "require_attestation" | "prompt" | "allow" {
502
+ const config = loadConfig();
503
+ // Handle legacy 'require_audit' value (cast to string for comparison)
504
+ const policy = config.trust?.policy as string | undefined;
505
+ if (policy === "require_audit") {
506
+ return "require_attestation";
507
+ }
508
+ // Default to require_attestation - trust must be explicit
509
+ return (policy as "require_attestation" | "prompt" | "allow") ?? "require_attestation";
510
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Enact Constants
3
+ *
4
+ * Centralized configuration for Enact URLs and identifiers.
5
+ * This ensures consistency across all packages.
6
+ *
7
+ * Note: Attestation type constants (ENACT_TOOL_TYPE, ENACT_AUDIT_TYPE, etc.)
8
+ * are defined in @enactprotocol/trust and re-exported here for convenience.
9
+ */
10
+
11
+ // Re-export attestation constants from trust package
12
+ export {
13
+ ENACT_BASE_URL,
14
+ ENACT_TOOL_TYPE,
15
+ ENACT_AUDIT_TYPE,
16
+ ENACT_BUILD_TYPE,
17
+ INTOTO_STATEMENT_TYPE,
18
+ SLSA_PROVENANCE_TYPE,
19
+ } from "@enactprotocol/trust";
20
+
21
+ // ============================================================================
22
+ // Runtime URLs (can be overridden by environment)
23
+ // ============================================================================
24
+
25
+ /**
26
+ * The Enact API base URL (Supabase Edge Functions)
27
+ * Override with ENACT_API_URL environment variable
28
+ */
29
+ import { ENACT_BASE_URL as BASE_URL } from "@enactprotocol/trust";
30
+ export const ENACT_API_URL = process.env.ENACT_API_URL || `${BASE_URL}/api`;
31
+
32
+ /**
33
+ * The Enact web application URL
34
+ * Override with ENACT_WEB_URL environment variable
35
+ */
36
+ export const ENACT_WEB_URL = process.env.ENACT_WEB_URL || BASE_URL;