@griffin-app/griffin-plan-executor 0.1.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.
Files changed (114) hide show
  1. package/README.md +152 -0
  2. package/dist/adapters/axios.d.ts +5 -0
  3. package/dist/adapters/axios.d.ts.map +1 -0
  4. package/dist/adapters/axios.js +36 -0
  5. package/dist/adapters/axios.js.map +1 -0
  6. package/dist/adapters/index.d.ts +3 -0
  7. package/dist/adapters/index.d.ts.map +1 -0
  8. package/dist/adapters/index.js +3 -0
  9. package/dist/adapters/index.js.map +1 -0
  10. package/dist/adapters/stub.d.ts +22 -0
  11. package/dist/adapters/stub.d.ts.map +1 -0
  12. package/dist/adapters/stub.js +36 -0
  13. package/dist/adapters/stub.js.map +1 -0
  14. package/dist/events/emitter.d.ts +68 -0
  15. package/dist/events/emitter.d.ts.map +1 -0
  16. package/dist/events/emitter.js +83 -0
  17. package/dist/events/emitter.js.map +1 -0
  18. package/dist/events/emitter.test.d.ts +2 -0
  19. package/dist/events/emitter.test.d.ts.map +1 -0
  20. package/dist/events/emitter.test.js +251 -0
  21. package/dist/events/emitter.test.js.map +1 -0
  22. package/dist/events/index.d.ts +3 -0
  23. package/dist/events/index.d.ts.map +1 -0
  24. package/dist/events/index.js +3 -0
  25. package/dist/events/index.js.map +1 -0
  26. package/dist/events/types.d.ts +109 -0
  27. package/dist/events/types.d.ts.map +1 -0
  28. package/dist/events/types.js +9 -0
  29. package/dist/events/types.js.map +1 -0
  30. package/dist/executor.d.ts +4 -0
  31. package/dist/executor.d.ts.map +1 -0
  32. package/dist/executor.js +732 -0
  33. package/dist/executor.js.map +1 -0
  34. package/dist/executor.test.d.ts +2 -0
  35. package/dist/executor.test.d.ts.map +1 -0
  36. package/dist/executor.test.js +1524 -0
  37. package/dist/executor.test.js.map +1 -0
  38. package/dist/index.d.ts +8 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +12 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/secrets/index.d.ts +14 -0
  43. package/dist/secrets/index.d.ts.map +1 -0
  44. package/dist/secrets/index.js +18 -0
  45. package/dist/secrets/index.js.map +1 -0
  46. package/dist/secrets/providers/aws.d.ts +63 -0
  47. package/dist/secrets/providers/aws.d.ts.map +1 -0
  48. package/dist/secrets/providers/aws.js +111 -0
  49. package/dist/secrets/providers/aws.js.map +1 -0
  50. package/dist/secrets/providers/env.d.ts +36 -0
  51. package/dist/secrets/providers/env.d.ts.map +1 -0
  52. package/dist/secrets/providers/env.js +37 -0
  53. package/dist/secrets/providers/env.js.map +1 -0
  54. package/dist/secrets/providers/index.d.ts +7 -0
  55. package/dist/secrets/providers/index.d.ts.map +1 -0
  56. package/dist/secrets/providers/index.js +7 -0
  57. package/dist/secrets/providers/index.js.map +1 -0
  58. package/dist/secrets/providers/vault.d.ts +75 -0
  59. package/dist/secrets/providers/vault.d.ts.map +1 -0
  60. package/dist/secrets/providers/vault.js +143 -0
  61. package/dist/secrets/providers/vault.js.map +1 -0
  62. package/dist/secrets/registry.d.ts +61 -0
  63. package/dist/secrets/registry.d.ts.map +1 -0
  64. package/dist/secrets/registry.js +182 -0
  65. package/dist/secrets/registry.js.map +1 -0
  66. package/dist/secrets/resolver.d.ts +40 -0
  67. package/dist/secrets/resolver.d.ts.map +1 -0
  68. package/dist/secrets/resolver.js +178 -0
  69. package/dist/secrets/resolver.js.map +1 -0
  70. package/dist/secrets/secrets.test.d.ts +2 -0
  71. package/dist/secrets/secrets.test.d.ts.map +1 -0
  72. package/dist/secrets/secrets.test.js +243 -0
  73. package/dist/secrets/secrets.test.js.map +1 -0
  74. package/dist/secrets/types.d.ts +71 -0
  75. package/dist/secrets/types.d.ts.map +1 -0
  76. package/dist/secrets/types.js +38 -0
  77. package/dist/secrets/types.js.map +1 -0
  78. package/dist/shared.d.ts +8 -0
  79. package/dist/shared.d.ts.map +1 -0
  80. package/dist/shared.js +30 -0
  81. package/dist/shared.js.map +1 -0
  82. package/dist/test-plan-types.d.ts +43 -0
  83. package/dist/test-plan-types.d.ts.map +1 -0
  84. package/dist/test-plan-types.js +2 -0
  85. package/dist/test-plan-types.js.map +1 -0
  86. package/dist/types.d.ts +77 -0
  87. package/dist/types.d.ts.map +1 -0
  88. package/dist/types.js +3 -0
  89. package/dist/types.js.map +1 -0
  90. package/package.json +35 -0
  91. package/src/adapters/axios.ts +41 -0
  92. package/src/adapters/index.ts +2 -0
  93. package/src/adapters/stub.ts +47 -0
  94. package/src/events/emitter.test.ts +316 -0
  95. package/src/events/emitter.ts +133 -0
  96. package/src/events/index.ts +2 -0
  97. package/src/events/types.ts +132 -0
  98. package/src/executor.test.ts +1674 -0
  99. package/src/executor.ts +986 -0
  100. package/src/index.ts +69 -0
  101. package/src/secrets/index.ts +41 -0
  102. package/src/secrets/providers/aws.ts +179 -0
  103. package/src/secrets/providers/env.ts +66 -0
  104. package/src/secrets/providers/index.ts +15 -0
  105. package/src/secrets/providers/vault.ts +257 -0
  106. package/src/secrets/registry.ts +234 -0
  107. package/src/secrets/resolver.ts +249 -0
  108. package/src/secrets/secrets.test.ts +318 -0
  109. package/src/secrets/types.ts +105 -0
  110. package/src/shared.ts +46 -0
  111. package/src/test-plan-types.ts +49 -0
  112. package/src/types.ts +95 -0
  113. package/tsconfig.json +20 -0
  114. package/vitest.config.ts +14 -0
@@ -0,0 +1,143 @@
1
+ /**
2
+ * HashiCorp Vault secret provider.
3
+ *
4
+ * Reads secrets from HashiCorp Vault KV secrets engine (v1 and v2).
5
+ * Supports field extraction from JSON secrets.
6
+ *
7
+ * Usage in DSL:
8
+ * secret("vault:secret/data/myapp/config")
9
+ * secret("vault:secret/data/myapp/config", { field: "api_key" })
10
+ * secret("vault:secret/data/myapp/config", { version: "2" })
11
+ */
12
+ import { SecretResolutionError } from "../types.js";
13
+ export class VaultProvider {
14
+ name = "vault";
15
+ address;
16
+ token;
17
+ httpClient;
18
+ namespace;
19
+ kvVersion;
20
+ prefix;
21
+ // Simple in-memory cache with TTL
22
+ cache = new Map();
23
+ cacheTtlMs = 5 * 60 * 1000; // 5 minutes
24
+ constructor(options) {
25
+ this.address = options.address.replace(/\/$/, ""); // Remove trailing slash
26
+ this.token = options.token;
27
+ this.httpClient = options.httpClient;
28
+ this.namespace = options.namespace;
29
+ this.kvVersion = options.kvVersion ?? 2;
30
+ this.prefix = options.prefix ?? "";
31
+ }
32
+ async resolve(ref, options) {
33
+ const secretPath = this.prefix + ref;
34
+ const version = options?.version;
35
+ const cacheKey = `${secretPath}:${version ?? "latest"}`;
36
+ // Check cache
37
+ const cached = this.cache.get(cacheKey);
38
+ if (cached && cached.expires > Date.now()) {
39
+ return this.extractField(cached.value, options?.field, ref);
40
+ }
41
+ try {
42
+ // Build request URL
43
+ let url = `${this.address}/v1/${secretPath}`;
44
+ if (this.kvVersion === 2 && version) {
45
+ url += `?version=${version}`;
46
+ }
47
+ // Build headers
48
+ const headers = {
49
+ "X-Vault-Token": this.token,
50
+ };
51
+ if (this.namespace) {
52
+ headers["X-Vault-Namespace"] = this.namespace;
53
+ }
54
+ const response = await this.httpClient.get(url, { headers });
55
+ if (response.status === 404) {
56
+ throw new SecretResolutionError(`Secret "${secretPath}" not found in Vault`, { provider: this.name, ref });
57
+ }
58
+ if (response.status === 403) {
59
+ throw new SecretResolutionError(`Access denied to secret "${secretPath}". Check Vault policies.`, { provider: this.name, ref });
60
+ }
61
+ if (response.status !== 200) {
62
+ throw new SecretResolutionError(`Vault returned status ${response.status} for secret "${secretPath}"`, { provider: this.name, ref });
63
+ }
64
+ // Parse response based on KV version
65
+ const data = response.data;
66
+ let secretData;
67
+ if (this.kvVersion === 2) {
68
+ // KV v2 wraps data in an extra "data" object
69
+ const kvData = data?.data;
70
+ if (!kvData?.data) {
71
+ throw new SecretResolutionError(`Invalid KV v2 response structure for secret "${secretPath}"`, { provider: this.name, ref });
72
+ }
73
+ secretData = kvData.data;
74
+ }
75
+ else {
76
+ // KV v1 has data directly
77
+ if (!data?.data || typeof data.data !== "object") {
78
+ throw new SecretResolutionError(`Invalid KV v1 response structure for secret "${secretPath}"`, { provider: this.name, ref });
79
+ }
80
+ secretData = data.data;
81
+ }
82
+ // Cache the secret data
83
+ this.cache.set(cacheKey, {
84
+ value: secretData,
85
+ expires: Date.now() + this.cacheTtlMs,
86
+ });
87
+ return this.extractField(secretData, options?.field, ref);
88
+ }
89
+ catch (error) {
90
+ if (error instanceof SecretResolutionError) {
91
+ throw error;
92
+ }
93
+ throw new SecretResolutionError(`Failed to retrieve secret "${secretPath}" from Vault: ${error instanceof Error ? error.message : String(error)}`, { provider: this.name, ref, cause: error });
94
+ }
95
+ }
96
+ /**
97
+ * Extract a field from the secret data.
98
+ * If no field is specified, returns the entire data as JSON string.
99
+ */
100
+ extractField(secretData, field, ref) {
101
+ if (!field) {
102
+ // Return entire secret as JSON if no field specified
103
+ return JSON.stringify(secretData);
104
+ }
105
+ const value = secretData[field];
106
+ if (value === undefined) {
107
+ throw new SecretResolutionError(`Field "${field}" not found in secret "${ref}"`, { provider: this.name, ref });
108
+ }
109
+ // Convert to string if not already
110
+ return typeof value === "string" ? value : JSON.stringify(value);
111
+ }
112
+ async validate() {
113
+ // Verify we can authenticate with Vault
114
+ try {
115
+ const headers = {
116
+ "X-Vault-Token": this.token,
117
+ };
118
+ if (this.namespace) {
119
+ headers["X-Vault-Namespace"] = this.namespace;
120
+ }
121
+ const response = await this.httpClient.get(`${this.address}/v1/auth/token/lookup-self`, { headers });
122
+ if (response.status === 403) {
123
+ throw new Error("Invalid or expired Vault token");
124
+ }
125
+ if (response.status !== 200) {
126
+ throw new Error(`Vault authentication check failed with status ${response.status}`);
127
+ }
128
+ }
129
+ catch (error) {
130
+ if (error instanceof Error && error.message.includes("Vault")) {
131
+ throw error;
132
+ }
133
+ throw new Error(`Failed to connect to Vault at ${this.address}: ${error instanceof Error ? error.message : String(error)}`);
134
+ }
135
+ }
136
+ /**
137
+ * Clear the cache. Useful for testing or forced refresh.
138
+ */
139
+ clearCache() {
140
+ this.cache.clear();
141
+ }
142
+ }
143
+ //# sourceMappingURL=vault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.js","sourceRoot":"","sources":["../../../src/secrets/providers/vault.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Secret provider registry for managing multiple secret providers.
3
+ */
4
+ import type { SecretProvider, SecretRefData } from "./types.js";
5
+ /**
6
+ * Registry for managing and accessing secret providers.
7
+ * Supports multiple providers simultaneously (e.g., env + aws + vault).
8
+ */
9
+ export declare class SecretProviderRegistry {
10
+ private providers;
11
+ /**
12
+ * Register a secret provider.
13
+ * @param provider - The provider to register
14
+ * @throws Error if a provider with the same name is already registered
15
+ */
16
+ register(provider: SecretProvider): void;
17
+ /**
18
+ * Unregister a secret provider by name.
19
+ * @param name - The provider name to remove
20
+ * @returns true if the provider was removed, false if it wasn't registered
21
+ */
22
+ unregister(name: string): boolean;
23
+ /**
24
+ * Get a registered provider by name.
25
+ * @param name - The provider name
26
+ * @throws Error if the provider is not registered
27
+ */
28
+ get(name: string): SecretProvider;
29
+ /**
30
+ * Check if a provider is registered.
31
+ */
32
+ has(name: string): boolean;
33
+ /**
34
+ * Get all registered provider names.
35
+ */
36
+ getProviderNames(): string[];
37
+ /**
38
+ * Resolve a secret reference using the appropriate provider.
39
+ * @param secretRef - The secret reference data
40
+ * @returns The resolved secret value
41
+ * @throws SecretResolutionError if resolution fails
42
+ */
43
+ resolve(secretRef: SecretRefData): Promise<string>;
44
+ /**
45
+ * Resolve multiple secrets, grouped by provider for efficiency.
46
+ * @param refs - Array of secret reference data
47
+ * @returns Map of "provider:ref" to resolved value
48
+ * @throws SecretResolutionError if any resolution fails (fail-fast)
49
+ */
50
+ resolveMany(refs: SecretRefData[]): Promise<Map<string, string>>;
51
+ /**
52
+ * Validate all registered providers.
53
+ * @throws Error if any provider validation fails
54
+ */
55
+ validateAll(): Promise<void>;
56
+ /**
57
+ * Create a unique key for a secret reference (for caching/deduplication).
58
+ */
59
+ makeKey(secretRef: SecretRefData): string;
60
+ }
61
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/secrets/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEd,MAAM,YAAY,CAAC;AAGpB;;;GAGG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,SAAS,CAAqC;IAEtD;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IASxC;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc;IAcjC;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B;;OAEG;IACH,gBAAgB,IAAI,MAAM,EAAE;IAI5B;;;;;OAKG;IACG,OAAO,CAAC,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAyBxD;;;;;OAKG;IACG,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IA6FtE;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBlC;;OAEG;IACH,OAAO,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM;CAM1C"}
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Secret provider registry for managing multiple secret providers.
3
+ */
4
+ import { SecretResolutionError } from "./types.js";
5
+ /**
6
+ * Registry for managing and accessing secret providers.
7
+ * Supports multiple providers simultaneously (e.g., env + aws + vault).
8
+ */
9
+ export class SecretProviderRegistry {
10
+ providers = new Map();
11
+ /**
12
+ * Register a secret provider.
13
+ * @param provider - The provider to register
14
+ * @throws Error if a provider with the same name is already registered
15
+ */
16
+ register(provider) {
17
+ if (this.providers.has(provider.name)) {
18
+ throw new Error(`Secret provider "${provider.name}" is already registered`);
19
+ }
20
+ this.providers.set(provider.name, provider);
21
+ }
22
+ /**
23
+ * Unregister a secret provider by name.
24
+ * @param name - The provider name to remove
25
+ * @returns true if the provider was removed, false if it wasn't registered
26
+ */
27
+ unregister(name) {
28
+ return this.providers.delete(name);
29
+ }
30
+ /**
31
+ * Get a registered provider by name.
32
+ * @param name - The provider name
33
+ * @throws Error if the provider is not registered
34
+ */
35
+ get(name) {
36
+ const provider = this.providers.get(name);
37
+ if (!provider) {
38
+ const available = [...this.providers.keys()];
39
+ throw new SecretResolutionError(`Secret provider "${name}" is not configured. Available providers: ${available.length > 0 ? available.join(", ") : "(none)"}`, { provider: name, ref: "" });
40
+ }
41
+ return provider;
42
+ }
43
+ /**
44
+ * Check if a provider is registered.
45
+ */
46
+ has(name) {
47
+ return this.providers.has(name);
48
+ }
49
+ /**
50
+ * Get all registered provider names.
51
+ */
52
+ getProviderNames() {
53
+ return [...this.providers.keys()];
54
+ }
55
+ /**
56
+ * Resolve a secret reference using the appropriate provider.
57
+ * @param secretRef - The secret reference data
58
+ * @returns The resolved secret value
59
+ * @throws SecretResolutionError if resolution fails
60
+ */
61
+ async resolve(secretRef) {
62
+ const provider = this.get(secretRef.provider);
63
+ try {
64
+ return await provider.resolve(secretRef.ref, {
65
+ version: secretRef.version,
66
+ field: secretRef.field,
67
+ });
68
+ }
69
+ catch (error) {
70
+ if (error instanceof SecretResolutionError) {
71
+ throw error;
72
+ }
73
+ throw new SecretResolutionError(`Failed to resolve secret "${secretRef.provider}:${secretRef.ref}": ${error instanceof Error ? error.message : String(error)}`, {
74
+ provider: secretRef.provider,
75
+ ref: secretRef.ref,
76
+ cause: error,
77
+ });
78
+ }
79
+ }
80
+ /**
81
+ * Resolve multiple secrets, grouped by provider for efficiency.
82
+ * @param refs - Array of secret reference data
83
+ * @returns Map of "provider:ref" to resolved value
84
+ * @throws SecretResolutionError if any resolution fails (fail-fast)
85
+ */
86
+ async resolveMany(refs) {
87
+ if (refs.length === 0) {
88
+ return new Map();
89
+ }
90
+ // Group refs by provider
91
+ const byProvider = new Map();
92
+ for (const secretRef of refs) {
93
+ const key = this.makeKey(secretRef);
94
+ const group = byProvider.get(secretRef.provider) || [];
95
+ group.push({
96
+ ref: secretRef.ref,
97
+ options: {
98
+ version: secretRef.version,
99
+ field: secretRef.field,
100
+ },
101
+ key,
102
+ });
103
+ byProvider.set(secretRef.provider, group);
104
+ }
105
+ // Resolve each provider's secrets
106
+ const results = new Map();
107
+ for (const [providerName, providerRefs] of byProvider) {
108
+ const provider = this.get(providerName);
109
+ // Use batch resolution if available, otherwise resolve individually
110
+ if (provider.resolveMany) {
111
+ const batchRefs = providerRefs.map((r) => ({
112
+ ref: r.ref,
113
+ options: r.options,
114
+ }));
115
+ try {
116
+ const batchResults = await provider.resolveMany(batchRefs);
117
+ for (const providerRef of providerRefs) {
118
+ const value = batchResults.get(providerRef.ref);
119
+ if (value === undefined) {
120
+ throw new SecretResolutionError(`Secret "${providerName}:${providerRef.ref}" not found in batch results`, { provider: providerName, ref: providerRef.ref });
121
+ }
122
+ results.set(providerRef.key, value);
123
+ }
124
+ }
125
+ catch (error) {
126
+ if (error instanceof SecretResolutionError) {
127
+ throw error;
128
+ }
129
+ throw new SecretResolutionError(`Batch resolution failed for provider "${providerName}": ${error instanceof Error ? error.message : String(error)}`, {
130
+ provider: providerName,
131
+ ref: providerRefs[0]?.ref || "",
132
+ cause: error,
133
+ });
134
+ }
135
+ }
136
+ else {
137
+ // Resolve individually (fail-fast on first error)
138
+ for (const providerRef of providerRefs) {
139
+ try {
140
+ const value = await provider.resolve(providerRef.ref, providerRef.options);
141
+ results.set(providerRef.key, value);
142
+ }
143
+ catch (error) {
144
+ if (error instanceof SecretResolutionError) {
145
+ throw error;
146
+ }
147
+ throw new SecretResolutionError(`Failed to resolve secret "${providerName}:${providerRef.ref}": ${error instanceof Error ? error.message : String(error)}`, { provider: providerName, ref: providerRef.ref, cause: error });
148
+ }
149
+ }
150
+ }
151
+ }
152
+ return results;
153
+ }
154
+ /**
155
+ * Validate all registered providers.
156
+ * @throws Error if any provider validation fails
157
+ */
158
+ async validateAll() {
159
+ for (const [name, provider] of this.providers) {
160
+ if (provider.validate) {
161
+ try {
162
+ await provider.validate();
163
+ }
164
+ catch (error) {
165
+ throw new Error(`Provider "${name}" validation failed: ${error instanceof Error ? error.message : String(error)}`);
166
+ }
167
+ }
168
+ }
169
+ }
170
+ /**
171
+ * Create a unique key for a secret reference (for caching/deduplication).
172
+ */
173
+ makeKey(secretRef) {
174
+ const parts = [secretRef.provider, secretRef.ref];
175
+ if (secretRef.version)
176
+ parts.push(`v:${secretRef.version}`);
177
+ if (secretRef.field)
178
+ parts.push(`f:${secretRef.field}`);
179
+ return parts.join(":");
180
+ }
181
+ }
182
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/secrets/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Secret resolution utilities for test plans.
3
+ */
4
+ import { TestPlanV1 } from "griffin/types";
5
+ import type { SecretProviderRegistry } from "./registry.js";
6
+ import type { SecretRefData } from "./types.js";
7
+ /**
8
+ * Collected secret references from a plan.
9
+ */
10
+ interface CollectedSecrets {
11
+ /** All unique secret references found */
12
+ refs: SecretRefData[];
13
+ /** Paths where secrets were found (for substitution) */
14
+ paths: Array<{
15
+ path: (string | number)[];
16
+ secretRef: SecretRefData;
17
+ }>;
18
+ }
19
+ /**
20
+ * Collect all secret references from a test plan.
21
+ * Scans endpoint headers and bodies for $secret markers.
22
+ */
23
+ export declare function collectSecretsFromPlan(plan: TestPlanV1): CollectedSecrets;
24
+ /**
25
+ * Resolve all secrets in a plan and return a new plan with substituted values.
26
+ * The original plan is not modified.
27
+ *
28
+ * @param plan - The test plan containing secret references
29
+ * @param registry - The secret provider registry
30
+ * @returns A new plan with all secrets resolved to their values
31
+ * @throws SecretResolutionError if any secret cannot be resolved (fail-fast)
32
+ */
33
+ export declare function resolveSecretsInPlan(plan: TestPlanV1, registry: SecretProviderRegistry): Promise<TestPlanV1>;
34
+ /**
35
+ * Check if a plan contains any secret references.
36
+ * Useful for short-circuiting resolution when no secrets are present.
37
+ */
38
+ export declare function planHasSecrets(plan: TestPlanV1): boolean;
39
+ export {};
40
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/secrets/resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAQ,MAAM,eAAe,CAAC;AAEjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EAAa,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3D;;GAEG;AACH,UAAU,gBAAgB;IACxB,yCAAyC;IACzC,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,wDAAwD;IACxD,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;QAC1B,SAAS,EAAE,aAAa,CAAC;KAC1B,CAAC,CAAC;CACJ;AAwCD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,gBAAgB,CAmDzE;AAsCD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,sBAAsB,GAC/B,OAAO,CAAC,UAAU,CAAC,CA+BrB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAsBxD"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Secret resolution utilities for test plans.
3
+ */
4
+ import { NodeType } from "griffin/schema";
5
+ import { isSecretRef } from "./types.js";
6
+ /**
7
+ * Recursively collect all secret references from a value.
8
+ * @param value - The value to scan
9
+ * @param currentPath - Current path in the object tree
10
+ * @param collected - Accumulator for found secrets
11
+ */
12
+ function collectSecretsFromValue(value, currentPath, collected) {
13
+ if (value === null || value === undefined) {
14
+ return;
15
+ }
16
+ if (isSecretRef(value)) {
17
+ collected.refs.push(value.$secret);
18
+ collected.paths.push({
19
+ path: [...currentPath],
20
+ secretRef: value.$secret,
21
+ });
22
+ return;
23
+ }
24
+ if (Array.isArray(value)) {
25
+ for (let i = 0; i < value.length; i++) {
26
+ collectSecretsFromValue(value[i], [...currentPath, i], collected);
27
+ }
28
+ return;
29
+ }
30
+ if (typeof value === "object") {
31
+ for (const [key, val] of Object.entries(value)) {
32
+ collectSecretsFromValue(val, [...currentPath, key], collected);
33
+ }
34
+ }
35
+ }
36
+ /**
37
+ * Collect all secret references from a test plan.
38
+ * Scans endpoint headers and bodies for $secret markers.
39
+ */
40
+ export function collectSecretsFromPlan(plan) {
41
+ const collected = {
42
+ refs: [],
43
+ paths: [],
44
+ };
45
+ for (let nodeIndex = 0; nodeIndex < plan.nodes.length; nodeIndex++) {
46
+ const node = plan.nodes[nodeIndex];
47
+ // Only endpoints can have secrets (in headers and body)
48
+ if (node.type !== NodeType.ENDPOINT) {
49
+ continue;
50
+ }
51
+ //const endpoint = node;
52
+ // Scan headers
53
+ if (node.headers) {
54
+ for (const [headerKey, headerValue] of Object.entries(node.headers)) {
55
+ collectSecretsFromValue(headerValue, ["nodes", nodeIndex, "headers", headerKey], collected);
56
+ }
57
+ }
58
+ // Scan body
59
+ if (node.body !== undefined) {
60
+ collectSecretsFromValue(node.body, ["nodes", nodeIndex, "body"], collected);
61
+ }
62
+ }
63
+ // Deduplicate refs by creating a unique key
64
+ const seen = new Set();
65
+ const uniqueRefs = [];
66
+ for (const ref of collected.refs) {
67
+ const key = `${ref.provider}:${ref.ref}:${ref.version || ""}:${ref.field || ""}`;
68
+ if (!seen.has(key)) {
69
+ seen.add(key);
70
+ uniqueRefs.push(ref);
71
+ }
72
+ }
73
+ collected.refs = uniqueRefs;
74
+ return collected;
75
+ }
76
+ /**
77
+ * Set a value at a path in an object.
78
+ * Creates intermediate objects/arrays as needed.
79
+ */
80
+ function setAtPath(obj, path, value) {
81
+ if (path.length === 0) {
82
+ return;
83
+ }
84
+ let current = obj;
85
+ for (let i = 0; i < path.length - 1; i++) {
86
+ const key = path[i];
87
+ if (current[key] === undefined) {
88
+ // Create intermediate object or array based on next key type
89
+ current[key] = typeof path[i + 1] === "number" ? [] : {};
90
+ }
91
+ current = current[key];
92
+ }
93
+ current[path[path.length - 1]] = value;
94
+ }
95
+ /**
96
+ * Deep clone a value.
97
+ */
98
+ function deepClone(value) {
99
+ if (value === null || value === undefined) {
100
+ return value;
101
+ }
102
+ return JSON.parse(JSON.stringify(value));
103
+ }
104
+ /**
105
+ * Resolve all secrets in a plan and return a new plan with substituted values.
106
+ * The original plan is not modified.
107
+ *
108
+ * @param plan - The test plan containing secret references
109
+ * @param registry - The secret provider registry
110
+ * @returns A new plan with all secrets resolved to their values
111
+ * @throws SecretResolutionError if any secret cannot be resolved (fail-fast)
112
+ */
113
+ export async function resolveSecretsInPlan(plan, registry) {
114
+ // Collect all secret references
115
+ const collected = collectSecretsFromPlan(plan);
116
+ if (collected.refs.length === 0) {
117
+ // No secrets to resolve
118
+ return plan;
119
+ }
120
+ // Resolve all secrets (fail-fast on any error)
121
+ const resolved = await registry.resolveMany(collected.refs);
122
+ // Clone the plan for modification
123
+ const resolvedPlan = deepClone(plan);
124
+ // Substitute resolved values at each path
125
+ for (const { path, secretRef } of collected.paths) {
126
+ const key = registry.makeKey(secretRef);
127
+ const value = resolved.get(key);
128
+ if (value === undefined) {
129
+ // This shouldn't happen if resolveMany worked correctly
130
+ throw new Error(`Internal error: resolved value not found for secret "${secretRef.provider}:${secretRef.ref}"`);
131
+ }
132
+ setAtPath(resolvedPlan, path, value);
133
+ }
134
+ return resolvedPlan;
135
+ }
136
+ /**
137
+ * Check if a plan contains any secret references.
138
+ * Useful for short-circuiting resolution when no secrets are present.
139
+ */
140
+ export function planHasSecrets(plan) {
141
+ for (const node of plan.nodes) {
142
+ if (node.type !== NodeType.ENDPOINT) {
143
+ continue;
144
+ }
145
+ // Check headers
146
+ if (node.headers) {
147
+ for (const headerValue of Object.values(node.headers)) {
148
+ if (isSecretRef(headerValue)) {
149
+ return true;
150
+ }
151
+ }
152
+ }
153
+ // Check body (recursive check)
154
+ if (node.body !== undefined && containsSecretRef(node.body)) {
155
+ return true;
156
+ }
157
+ }
158
+ return false;
159
+ }
160
+ /**
161
+ * Recursively check if a value contains any secret references.
162
+ */
163
+ function containsSecretRef(value) {
164
+ if (value === null || value === undefined) {
165
+ return false;
166
+ }
167
+ if (isSecretRef(value)) {
168
+ return true;
169
+ }
170
+ if (Array.isArray(value)) {
171
+ return value.some(containsSecretRef);
172
+ }
173
+ if (typeof value === "object") {
174
+ return Object.values(value).some(containsSecretRef);
175
+ }
176
+ return false;
177
+ }
178
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/secrets/resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=secrets.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.test.d.ts","sourceRoot":"","sources":["../../src/secrets/secrets.test.ts"],"names":[],"mappings":""}