@quiltdata/benchling-webhook 0.5.4 → 0.6.1-20251104T043302Z

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 (107) hide show
  1. package/README.md +295 -12
  2. package/dist/bin/benchling-webhook.d.ts +1 -1
  3. package/dist/bin/benchling-webhook.d.ts.map +1 -1
  4. package/dist/bin/benchling-webhook.js +12 -22
  5. package/dist/bin/benchling-webhook.js.map +1 -1
  6. package/dist/bin/cdk-dev.js +59 -3
  7. package/dist/bin/cli.js +27 -9
  8. package/dist/bin/cli.js.map +1 -1
  9. package/dist/bin/commands/deploy.d.ts +6 -2
  10. package/dist/bin/commands/deploy.d.ts.map +1 -1
  11. package/dist/bin/commands/deploy.js +151 -90
  12. package/dist/bin/commands/deploy.js.map +1 -1
  13. package/dist/bin/commands/setup-wizard.d.ts +22 -0
  14. package/dist/bin/commands/setup-wizard.d.ts.map +1 -0
  15. package/dist/bin/commands/setup-wizard.js +47 -0
  16. package/dist/bin/commands/setup-wizard.js.map +1 -0
  17. package/dist/bin/config-profiles.d.ts +59 -0
  18. package/dist/bin/config-profiles.d.ts.map +1 -0
  19. package/dist/bin/config-profiles.js +272 -0
  20. package/dist/bin/config-profiles.js.map +1 -0
  21. package/dist/bin/create-secret.d.ts +25 -0
  22. package/dist/bin/create-secret.d.ts.map +1 -0
  23. package/dist/bin/create-secret.js +239 -0
  24. package/dist/bin/create-secret.js.map +1 -0
  25. package/dist/lib/benchling-auth-validator.d.ts +65 -0
  26. package/dist/lib/benchling-auth-validator.d.ts.map +1 -0
  27. package/dist/lib/benchling-auth-validator.js +213 -0
  28. package/dist/lib/benchling-auth-validator.js.map +1 -0
  29. package/dist/lib/benchling-webhook-stack.d.ts +13 -10
  30. package/dist/lib/benchling-webhook-stack.d.ts.map +1 -1
  31. package/dist/lib/benchling-webhook-stack.js +25 -69
  32. package/dist/lib/benchling-webhook-stack.js.map +1 -1
  33. package/dist/lib/config-logger.d.ts +191 -0
  34. package/dist/lib/config-logger.d.ts.map +1 -0
  35. package/dist/lib/config-logger.js +372 -0
  36. package/dist/lib/config-logger.js.map +1 -0
  37. package/dist/lib/configuration-saver.d.ts +75 -0
  38. package/dist/lib/configuration-saver.d.ts.map +1 -0
  39. package/dist/lib/configuration-saver.js +145 -0
  40. package/dist/lib/configuration-saver.js.map +1 -0
  41. package/dist/lib/configuration-validator.d.ts +63 -0
  42. package/dist/lib/configuration-validator.d.ts.map +1 -0
  43. package/dist/lib/configuration-validator.js +136 -0
  44. package/dist/lib/configuration-validator.js.map +1 -0
  45. package/dist/lib/configuration-wizard.d.ts +52 -0
  46. package/dist/lib/configuration-wizard.d.ts.map +1 -0
  47. package/dist/lib/configuration-wizard.js +193 -0
  48. package/dist/lib/configuration-wizard.js.map +1 -0
  49. package/dist/lib/fargate-service.d.ts +18 -9
  50. package/dist/lib/fargate-service.d.ts.map +1 -1
  51. package/dist/lib/fargate-service.js +177 -61
  52. package/dist/lib/fargate-service.js.map +1 -1
  53. package/dist/lib/quilt-config-resolver.d.ts +53 -0
  54. package/dist/lib/quilt-config-resolver.d.ts.map +1 -0
  55. package/dist/lib/quilt-config-resolver.js +100 -0
  56. package/dist/lib/quilt-config-resolver.js.map +1 -0
  57. package/dist/lib/s3-bucket-validator.d.ts +76 -0
  58. package/dist/lib/s3-bucket-validator.d.ts.map +1 -0
  59. package/dist/lib/s3-bucket-validator.js +237 -0
  60. package/dist/lib/s3-bucket-validator.js.map +1 -0
  61. package/dist/lib/types/config.d.ts +398 -0
  62. package/dist/lib/types/config.d.ts.map +1 -0
  63. package/dist/lib/types/config.js +11 -0
  64. package/dist/lib/types/config.js.map +1 -0
  65. package/dist/lib/utils/config-loader.d.ts +48 -0
  66. package/dist/lib/utils/config-loader.d.ts.map +1 -0
  67. package/dist/lib/utils/config-loader.js +109 -0
  68. package/dist/lib/utils/config-loader.js.map +1 -0
  69. package/dist/lib/utils/config-resolver.d.ts +138 -0
  70. package/dist/lib/utils/config-resolver.d.ts.map +1 -0
  71. package/dist/lib/utils/config-resolver.js +272 -0
  72. package/dist/lib/utils/config-resolver.js.map +1 -0
  73. package/dist/lib/utils/config.d.ts +50 -0
  74. package/dist/lib/utils/config.d.ts.map +1 -1
  75. package/dist/lib/utils/config.js +86 -0
  76. package/dist/lib/utils/config.js.map +1 -1
  77. package/dist/lib/utils/secrets.d.ts +174 -0
  78. package/dist/lib/utils/secrets.d.ts.map +1 -0
  79. package/dist/lib/utils/secrets.js +351 -0
  80. package/dist/lib/utils/secrets.js.map +1 -0
  81. package/dist/lib/xdg-cli-wrapper.d.ts +113 -0
  82. package/dist/lib/xdg-cli-wrapper.d.ts.map +1 -0
  83. package/dist/lib/xdg-cli-wrapper.js +288 -0
  84. package/dist/lib/xdg-cli-wrapper.js.map +1 -0
  85. package/dist/lib/xdg-config.d.ts +187 -0
  86. package/dist/lib/xdg-config.d.ts.map +1 -0
  87. package/dist/lib/xdg-config.js +562 -0
  88. package/dist/lib/xdg-config.js.map +1 -0
  89. package/dist/package.json +34 -26
  90. package/dist/scripts/config-health-check.d.ts +78 -0
  91. package/dist/scripts/config-health-check.d.ts.map +1 -0
  92. package/dist/scripts/config-health-check.js +559 -0
  93. package/dist/scripts/config-health-check.js.map +1 -0
  94. package/dist/scripts/infer-quilt-config.d.ts +50 -0
  95. package/dist/scripts/infer-quilt-config.d.ts.map +1 -0
  96. package/dist/scripts/infer-quilt-config.js +353 -0
  97. package/dist/scripts/infer-quilt-config.js.map +1 -0
  98. package/dist/scripts/install-wizard.d.ts +34 -0
  99. package/dist/scripts/install-wizard.d.ts.map +1 -0
  100. package/dist/scripts/install-wizard.js +719 -0
  101. package/dist/scripts/install-wizard.js.map +1 -0
  102. package/dist/scripts/sync-secrets.d.ts +63 -0
  103. package/dist/scripts/sync-secrets.d.ts.map +1 -0
  104. package/dist/scripts/sync-secrets.js +424 -0
  105. package/dist/scripts/sync-secrets.js.map +1 -0
  106. package/env.template +60 -47
  107. package/package.json +34 -26
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Configuration loading helpers for application startup
3
+ *
4
+ * Provides simplified configuration loading for both production (from AWS)
5
+ * and testing (from environment variables).
6
+ */
7
+ import { type ResolvedConfig } from "./config-resolver";
8
+ /**
9
+ * Load configuration for production (from AWS CloudFormation and Secrets Manager)
10
+ *
11
+ * Reads QuiltStackARN and BenchlingSecret from environment variables and
12
+ * resolves complete configuration by querying AWS APIs.
13
+ *
14
+ * @returns Complete resolved configuration
15
+ * @throws Error if required environment variables are missing
16
+ * @throws ConfigResolverError if AWS resolution fails
17
+ *
18
+ * @example
19
+ * // In production/container
20
+ * const config = await loadConfig();
21
+ * console.log(`Database: ${config.quiltDatabase}`);
22
+ */
23
+ export declare function loadConfig(): Promise<ResolvedConfig>;
24
+ /**
25
+ * Load configuration for testing (from environment variables directly)
26
+ *
27
+ * Only available when NODE_ENV=test. Provides backward compatibility
28
+ * with existing test suite by reading configuration from individual
29
+ * environment variables instead of AWS services.
30
+ *
31
+ * @returns Partial configuration from environment variables
32
+ * @throws Error if called outside test environment
33
+ *
34
+ * @example
35
+ * // In test files
36
+ * process.env.NODE_ENV = 'test';
37
+ * process.env.QUILT_CATALOG = 'test.catalog.com';
38
+ * const config = loadConfigForTesting();
39
+ */
40
+ export declare function loadConfigForTesting(): Partial<ResolvedConfig>;
41
+ /**
42
+ * Format ConfigResolverError for console output
43
+ *
44
+ * @param error - The error to format
45
+ * @returns Formatted error message
46
+ */
47
+ export declare function formatConfigError(error: unknown): string;
48
+ //# sourceMappingURL=config-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../../lib/utils/config-loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAkB,KAAK,cAAc,EAAuB,MAAM,mBAAmB,CAAC;AAE7F;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,cAAc,CAAC,CAyB1D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAAC,cAAc,CAAC,CAgC9D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUxD"}
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ /**
3
+ * Configuration loading helpers for application startup
4
+ *
5
+ * Provides simplified configuration loading for both production (from AWS)
6
+ * and testing (from environment variables).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.loadConfig = loadConfig;
10
+ exports.loadConfigForTesting = loadConfigForTesting;
11
+ exports.formatConfigError = formatConfigError;
12
+ const config_resolver_1 = require("./config-resolver");
13
+ /**
14
+ * Load configuration for production (from AWS CloudFormation and Secrets Manager)
15
+ *
16
+ * Reads QuiltStackARN and BenchlingSecret from environment variables and
17
+ * resolves complete configuration by querying AWS APIs.
18
+ *
19
+ * @returns Complete resolved configuration
20
+ * @throws Error if required environment variables are missing
21
+ * @throws ConfigResolverError if AWS resolution fails
22
+ *
23
+ * @example
24
+ * // In production/container
25
+ * const config = await loadConfig();
26
+ * console.log(`Database: ${config.quiltDatabase}`);
27
+ */
28
+ async function loadConfig() {
29
+ const quiltStackArn = process.env.QuiltStackARN;
30
+ const benchlingSecret = process.env.BenchlingSecret;
31
+ if (!quiltStackArn || !benchlingSecret) {
32
+ const missing = [];
33
+ if (!quiltStackArn)
34
+ missing.push("QuiltStackARN");
35
+ if (!benchlingSecret)
36
+ missing.push("BenchlingSecret");
37
+ throw new Error(`Missing required environment variables: ${missing.join(", ")}\n\n` +
38
+ "The container requires exactly 2 environment variables:\n" +
39
+ " QuiltStackARN: ARN of your Quilt CloudFormation stack\n" +
40
+ " Example: arn:aws:cloudformation:us-east-1:123456789012:stack/QuiltStack/abc-123\n\n" +
41
+ " BenchlingSecret: Name or ARN of AWS Secrets Manager secret\n" +
42
+ " Example: my-benchling-creds\n\n" +
43
+ "Documentation: https://github.com/quiltdata/benchling-webhook#configuration");
44
+ }
45
+ const resolver = new config_resolver_1.ConfigResolver();
46
+ return await resolver.resolve({
47
+ quiltStackArn,
48
+ benchlingSecret,
49
+ });
50
+ }
51
+ /**
52
+ * Load configuration for testing (from environment variables directly)
53
+ *
54
+ * Only available when NODE_ENV=test. Provides backward compatibility
55
+ * with existing test suite by reading configuration from individual
56
+ * environment variables instead of AWS services.
57
+ *
58
+ * @returns Partial configuration from environment variables
59
+ * @throws Error if called outside test environment
60
+ *
61
+ * @example
62
+ * // In test files
63
+ * process.env.NODE_ENV = 'test';
64
+ * process.env.QUILT_CATALOG = 'test.catalog.com';
65
+ * const config = loadConfigForTesting();
66
+ */
67
+ function loadConfigForTesting() {
68
+ if (process.env.NODE_ENV !== "test") {
69
+ throw new Error("loadConfigForTesting() should only be used in test environment (NODE_ENV=test)");
70
+ }
71
+ return {
72
+ // AWS
73
+ awsRegion: process.env.AWS_REGION || process.env.CDK_DEFAULT_REGION || "us-east-1",
74
+ awsAccount: process.env.CDK_DEFAULT_ACCOUNT || "123456789012",
75
+ // Quilt
76
+ quiltCatalog: process.env.QUILT_CATALOG || "test.catalog.com",
77
+ quiltDatabase: process.env.QUILT_DATABASE || "test_db",
78
+ quiltUserBucket: process.env.QUILT_USER_BUCKET || "test-bucket",
79
+ queueArn: process.env.QUEUE_ARN || "arn:aws:sqs:us-east-1:123456789012:test-queue",
80
+ // Benchling
81
+ benchlingTenant: process.env.BENCHLING_TENANT || "test-tenant",
82
+ benchlingClientId: process.env.BENCHLING_CLIENT_ID || "test-client-id",
83
+ benchlingClientSecret: process.env.BENCHLING_CLIENT_SECRET || "test-client-secret",
84
+ benchlingAppDefinitionId: process.env.BENCHLING_APP_DEFINITION_ID,
85
+ benchlingApiUrl: process.env.BENCHLING_API_URL,
86
+ // Optional
87
+ pkgPrefix: process.env.PKG_PREFIX || "benchling",
88
+ pkgKey: process.env.PKG_KEY || "experiment_id",
89
+ logLevel: process.env.LOG_LEVEL || "INFO",
90
+ webhookAllowList: process.env.WEBHOOK_ALLOW_LIST,
91
+ enableWebhookVerification: process.env.ENABLE_WEBHOOK_VERIFICATION !== "false",
92
+ };
93
+ }
94
+ /**
95
+ * Format ConfigResolverError for console output
96
+ *
97
+ * @param error - The error to format
98
+ * @returns Formatted error message
99
+ */
100
+ function formatConfigError(error) {
101
+ if (error instanceof config_resolver_1.ConfigResolverError) {
102
+ return error.format();
103
+ }
104
+ if (error instanceof Error) {
105
+ return `Error: ${error.message}`;
106
+ }
107
+ return `Unknown error: ${String(error)}`;
108
+ }
109
+ //# sourceMappingURL=config-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../../lib/utils/config-loader.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAmBH,gCAyBC;AAkBD,oDAgCC;AAQD,8CAUC;AA9GD,uDAA6F;AAE7F;;;;;;;;;;;;;;GAcG;AACI,KAAK,UAAU,UAAU;IAC5B,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAChD,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAEpD,IAAI,CAAC,aAAa,IAAI,CAAC,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,IAAI,CAAC,aAAa;YAAE,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAClD,IAAI,CAAC,eAAe;YAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAEtD,MAAM,IAAI,KAAK,CACX,2CAA2C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YACzE,2DAA2D;YAC3D,2DAA2D;YAC3D,yFAAyF;YACzF,gEAAgE;YAChE,qCAAqC;YACrC,6EAA6E,CAC1E,CAAC;IACN,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,gCAAc,EAAE,CAAC;IACtC,OAAO,MAAM,QAAQ,CAAC,OAAO,CAAC;QAC1B,aAAa;QACb,eAAe;KAClB,CAAC,CAAC;AACP,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,oBAAoB;IAChC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CACX,gFAAgF,CACnF,CAAC;IACN,CAAC;IAED,OAAO;QACP,MAAM;QACF,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,WAAW;QAClF,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,cAAc;QAE7D,QAAQ;QACR,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,kBAAkB;QAC7D,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,SAAS;QACtD,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,aAAa;QAC/D,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,+CAA+C;QAElF,YAAY;QACZ,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,aAAa;QAC9D,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,gBAAgB;QACtE,qBAAqB,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,oBAAoB;QAClF,wBAAwB,EAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B;QACjE,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAE9C,WAAW;QACX,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,WAAW;QAChD,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,eAAe;QAC9C,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;QACzC,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAChD,yBAAyB,EAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B,KAAK,OAAO;KACjF,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,KAAc;IAC5C,IAAI,KAAK,YAAY,qCAAmB,EAAE,CAAC;QACvC,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QACzB,OAAO,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC;IACrC,CAAC;IAED,OAAO,kBAAkB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Configuration Resolver for Secrets-Only Architecture
3
+ *
4
+ * This module resolves complete application configuration from just two sources:
5
+ * 1. QuiltStackARN - CloudFormation stack ARN for Quilt infrastructure
6
+ * 2. BenchlingSecret - AWS Secrets Manager secret containing Benchling credentials
7
+ *
8
+ * All other configuration is derived from these two sources by querying AWS APIs.
9
+ */
10
+ import { CloudFormationClient } from "@aws-sdk/client-cloudformation";
11
+ import { SecretsManagerClient } from "@aws-sdk/client-secrets-manager";
12
+ import { type BenchlingSecretData } from "./secrets";
13
+ /**
14
+ * Complete resolved configuration for the application
15
+ */
16
+ export interface ResolvedConfig {
17
+ awsRegion: string;
18
+ awsAccount: string;
19
+ quiltCatalog: string;
20
+ quiltDatabase: string;
21
+ quiltUserBucket: string;
22
+ queueArn: string;
23
+ benchlingTenant: string;
24
+ benchlingClientId: string;
25
+ benchlingClientSecret: string;
26
+ benchlingAppDefinitionId?: string;
27
+ benchlingApiUrl?: string;
28
+ pkgPrefix?: string;
29
+ pkgKey?: string;
30
+ logLevel?: string;
31
+ webhookAllowList?: string;
32
+ enableWebhookVerification?: boolean;
33
+ }
34
+ /**
35
+ * Options for ConfigResolver
36
+ */
37
+ export interface ConfigResolverOptions {
38
+ quiltStackArn: string;
39
+ benchlingSecret: string;
40
+ mockCloudFormation?: CloudFormationClient;
41
+ mockSecretsManager?: SecretsManagerClient;
42
+ }
43
+ /**
44
+ * Parsed CloudFormation stack ARN
45
+ */
46
+ export interface ParsedStackArn {
47
+ region: string;
48
+ account: string;
49
+ stackName: string;
50
+ stackId: string;
51
+ }
52
+ /**
53
+ * Custom error for configuration resolution failures
54
+ */
55
+ export declare class ConfigResolverError extends Error {
56
+ readonly suggestion?: string | undefined;
57
+ readonly details?: string | undefined;
58
+ constructor(message: string, suggestion?: string | undefined, details?: string | undefined);
59
+ /**
60
+ * Format error for CLI/logs with suggestions
61
+ */
62
+ format(): string;
63
+ }
64
+ /**
65
+ * Parse CloudFormation stack ARN into components
66
+ *
67
+ * @param arn - CloudFormation stack ARN
68
+ * @returns Parsed ARN components
69
+ * @throws ConfigResolverError if ARN is invalid
70
+ *
71
+ * @example
72
+ * parseStackArn('arn:aws:cloudformation:us-east-1:123456789012:stack/QuiltStack/abc-123')
73
+ * // Returns: { region: 'us-east-1', account: '123456789012', stackName: 'QuiltStack', stackId: 'abc-123' }
74
+ */
75
+ export declare function parseStackArn(arn: string): ParsedStackArn;
76
+ /**
77
+ * Extract stack outputs from CloudFormation
78
+ *
79
+ * @param client - CloudFormation client
80
+ * @param stackName - Name of the stack
81
+ * @returns Map of output keys to values
82
+ * @throws ConfigResolverError if stack not found or inaccessible
83
+ */
84
+ export declare function extractStackOutputs(client: CloudFormationClient, stackName: string): Promise<Record<string, string>>;
85
+ /**
86
+ * Fetch and validate secret from AWS Secrets Manager
87
+ *
88
+ * @param client - Secrets Manager client
89
+ * @param region - AWS region
90
+ * @param secretIdentifier - Secret name or ARN
91
+ * @returns Validated secret data
92
+ * @throws ConfigResolverError if secret not found or invalid
93
+ */
94
+ export declare function resolveAndFetchSecret(client: SecretsManagerClient, region: string, secretIdentifier: string): Promise<BenchlingSecretData>;
95
+ /**
96
+ * Main configuration resolver class
97
+ *
98
+ * Resolves complete application configuration from CloudFormation and Secrets Manager.
99
+ * Implements caching to avoid repeated AWS API calls.
100
+ */
101
+ export declare class ConfigResolver {
102
+ private cache;
103
+ /**
104
+ * Resolve complete configuration from AWS
105
+ *
106
+ * @param options - Configuration resolver options
107
+ * @returns Complete resolved configuration
108
+ * @throws ConfigResolverError if resolution fails
109
+ */
110
+ resolve(options: ConfigResolverOptions): Promise<ResolvedConfig>;
111
+ /**
112
+ * Validate that required CloudFormation outputs are present
113
+ *
114
+ * @param outputs - Stack outputs
115
+ * @throws ConfigResolverError if required outputs are missing
116
+ */
117
+ private validateRequiredOutputs;
118
+ /**
119
+ * Resolve catalog URL from stack outputs
120
+ *
121
+ * @param outputs - Stack outputs
122
+ * @returns Normalized catalog URL (hostname only)
123
+ * @throws ConfigResolverError if catalog URL cannot be determined
124
+ */
125
+ private resolveCatalogUrl;
126
+ /**
127
+ * Normalize catalog URL to hostname only (remove protocol and trailing slash)
128
+ *
129
+ * @param url - Catalog URL
130
+ * @returns Normalized hostname
131
+ */
132
+ private normalizeCatalogUrl;
133
+ /**
134
+ * Clear cached configuration (for testing only)
135
+ */
136
+ clearCache(): void;
137
+ }
138
+ //# sourceMappingURL=config-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-resolver.d.ts","sourceRoot":"","sources":["../../../lib/utils/config-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACH,oBAAoB,EAEvB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACH,oBAAoB,EAEvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEH,KAAK,mBAAmB,EAC3B,MAAM,WAAW,CAAC;AAEnB;;GAEG;AACH,MAAM,WAAW,cAAc;IAE7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IAGnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IAGjB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IAGzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IAExB,kBAAkB,CAAC,EAAE,oBAAoB,CAAC;IAC1C,kBAAkB,CAAC,EAAE,oBAAoB,CAAC;CAC3C;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;aAG1B,UAAU,CAAC,EAAE,MAAM;aACnB,OAAO,CAAC,EAAE,MAAM;gBAF5B,OAAO,EAAE,MAAM,EACH,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,OAAO,CAAC,EAAE,MAAM,YAAA;IAUhC;;KAEC;IACD,MAAM,IAAI,MAAM;CAanB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAqBzD;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACrC,MAAM,EAAE,oBAAoB,EAC5B,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiCjC;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACvC,MAAM,EAAE,oBAAoB,EAC5B,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAiE9B;AAED;;;;;GAKG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,KAAK,CAA+B;IAE5C;;;;;;KAMC;IACK,OAAO,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC;IAkEtE;;;;;KAKC;IACD,OAAO,CAAC,uBAAuB;IAmB/B;;;;;;KAMC;IACD,OAAO,CAAC,iBAAiB;IA0BzB;;;;;KAKC;IACD,OAAO,CAAC,mBAAmB;IAI3B;;KAEC;IACD,UAAU,IAAI,IAAI;CAGrB"}
@@ -0,0 +1,272 @@
1
+ "use strict";
2
+ /**
3
+ * Configuration Resolver for Secrets-Only Architecture
4
+ *
5
+ * This module resolves complete application configuration from just two sources:
6
+ * 1. QuiltStackARN - CloudFormation stack ARN for Quilt infrastructure
7
+ * 2. BenchlingSecret - AWS Secrets Manager secret containing Benchling credentials
8
+ *
9
+ * All other configuration is derived from these two sources by querying AWS APIs.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ConfigResolver = exports.ConfigResolverError = void 0;
13
+ exports.parseStackArn = parseStackArn;
14
+ exports.extractStackOutputs = extractStackOutputs;
15
+ exports.resolveAndFetchSecret = resolveAndFetchSecret;
16
+ const client_cloudformation_1 = require("@aws-sdk/client-cloudformation");
17
+ const client_secrets_manager_1 = require("@aws-sdk/client-secrets-manager");
18
+ const secrets_1 = require("./secrets");
19
+ /**
20
+ * Custom error for configuration resolution failures
21
+ */
22
+ class ConfigResolverError extends Error {
23
+ constructor(message, suggestion, details) {
24
+ super(message);
25
+ this.suggestion = suggestion;
26
+ this.details = details;
27
+ this.name = "ConfigResolverError";
28
+ if (Error.captureStackTrace) {
29
+ Error.captureStackTrace(this, ConfigResolverError);
30
+ }
31
+ }
32
+ /**
33
+ * Format error for CLI/logs with suggestions
34
+ */
35
+ format() {
36
+ let output = `❌ Configuration Error: ${this.message}`;
37
+ if (this.suggestion) {
38
+ output += `\n 💡 ${this.suggestion}`;
39
+ }
40
+ if (this.details) {
41
+ output += `\n ℹ️ ${this.details}`;
42
+ }
43
+ return output;
44
+ }
45
+ }
46
+ exports.ConfigResolverError = ConfigResolverError;
47
+ /**
48
+ * Parse CloudFormation stack ARN into components
49
+ *
50
+ * @param arn - CloudFormation stack ARN
51
+ * @returns Parsed ARN components
52
+ * @throws ConfigResolverError if ARN is invalid
53
+ *
54
+ * @example
55
+ * parseStackArn('arn:aws:cloudformation:us-east-1:123456789012:stack/QuiltStack/abc-123')
56
+ * // Returns: { region: 'us-east-1', account: '123456789012', stackName: 'QuiltStack', stackId: 'abc-123' }
57
+ */
58
+ function parseStackArn(arn) {
59
+ const pattern = /^arn:aws:cloudformation:([a-z0-9-]+):(\d{12}):stack\/([^/]+)\/(.+)$/;
60
+ const match = arn.match(pattern);
61
+ if (!match) {
62
+ throw new ConfigResolverError("Invalid CloudFormation stack ARN format", "ARN must match: arn:aws:cloudformation:region:account:stack/name/id", `Received: ${arn}`);
63
+ }
64
+ const [, region, account, stackName, stackId] = match;
65
+ return {
66
+ region,
67
+ account,
68
+ stackName,
69
+ stackId,
70
+ };
71
+ }
72
+ /**
73
+ * Extract stack outputs from CloudFormation
74
+ *
75
+ * @param client - CloudFormation client
76
+ * @param stackName - Name of the stack
77
+ * @returns Map of output keys to values
78
+ * @throws ConfigResolverError if stack not found or inaccessible
79
+ */
80
+ async function extractStackOutputs(client, stackName) {
81
+ const command = new client_cloudformation_1.DescribeStacksCommand({ StackName: stackName });
82
+ try {
83
+ const response = await client.send(command);
84
+ const stack = response.Stacks?.[0];
85
+ if (!stack) {
86
+ throw new ConfigResolverError(`Stack not found: ${stackName}`, "Ensure the CloudFormation stack exists and is accessible");
87
+ }
88
+ const outputs = stack.Outputs || [];
89
+ return Object.fromEntries(outputs.map((o) => [o.OutputKey, o.OutputValue]));
90
+ }
91
+ catch (error) {
92
+ if (error instanceof ConfigResolverError) {
93
+ throw error;
94
+ }
95
+ if (error.name === "ValidationError") {
96
+ throw new ConfigResolverError(`Invalid stack name: ${stackName}`, "Check that the stack name is correct");
97
+ }
98
+ throw new ConfigResolverError(`Failed to describe stack: ${error.message}`, "Check AWS credentials and permissions");
99
+ }
100
+ }
101
+ /**
102
+ * Fetch and validate secret from AWS Secrets Manager
103
+ *
104
+ * @param client - Secrets Manager client
105
+ * @param region - AWS region
106
+ * @param secretIdentifier - Secret name or ARN
107
+ * @returns Validated secret data
108
+ * @throws ConfigResolverError if secret not found or invalid
109
+ */
110
+ async function resolveAndFetchSecret(client, region, secretIdentifier) {
111
+ try {
112
+ const command = new client_secrets_manager_1.GetSecretValueCommand({ SecretId: secretIdentifier });
113
+ const response = await client.send(command);
114
+ if (!response.SecretString) {
115
+ throw new ConfigResolverError("Secret does not contain string data", "Ensure secret is stored as JSON string, not binary");
116
+ }
117
+ // Parse JSON
118
+ let data;
119
+ try {
120
+ data = JSON.parse(response.SecretString);
121
+ }
122
+ catch (parseError) {
123
+ throw new ConfigResolverError("Secret contains invalid JSON", "Ensure secret value is valid JSON", `Parse error: ${parseError.message}`);
124
+ }
125
+ // Validate structure
126
+ const validation = (0, secrets_1.validateSecretData)(data);
127
+ if (!validation.valid) {
128
+ const errors = validation.errors
129
+ .map((e) => `${e.field}: ${e.message}`)
130
+ .join("; ");
131
+ throw new ConfigResolverError("Invalid secret structure", errors, "Expected format: {\"client_id\":\"...\",\"client_secret\":\"...\",\"tenant\":\"...\"}");
132
+ }
133
+ return data;
134
+ }
135
+ catch (error) {
136
+ if (error instanceof ConfigResolverError) {
137
+ throw error;
138
+ }
139
+ if (error.name === "ResourceNotFoundException") {
140
+ throw new ConfigResolverError(`Secret not found: ${secretIdentifier}`, "Ensure the secret exists in AWS Secrets Manager and is accessible", `Region: ${region}`);
141
+ }
142
+ if (error.name === "AccessDeniedException") {
143
+ throw new ConfigResolverError(`Access denied to secret: ${secretIdentifier}`, "Ensure the IAM role has secretsmanager:GetSecretValue permission", `Region: ${region}`);
144
+ }
145
+ throw new ConfigResolverError(`Failed to fetch secret: ${error.message}`, "Check AWS credentials and permissions");
146
+ }
147
+ }
148
+ /**
149
+ * Main configuration resolver class
150
+ *
151
+ * Resolves complete application configuration from CloudFormation and Secrets Manager.
152
+ * Implements caching to avoid repeated AWS API calls.
153
+ */
154
+ class ConfigResolver {
155
+ constructor() {
156
+ this.cache = null;
157
+ }
158
+ /**
159
+ * Resolve complete configuration from AWS
160
+ *
161
+ * @param options - Configuration resolver options
162
+ * @returns Complete resolved configuration
163
+ * @throws ConfigResolverError if resolution fails
164
+ */
165
+ async resolve(options) {
166
+ // Return cached config if available
167
+ if (this.cache) {
168
+ return this.cache;
169
+ }
170
+ // Step 1: Parse stack ARN
171
+ const parsed = parseStackArn(options.quiltStackArn);
172
+ // Step 2: Create AWS clients (or use mocks for testing)
173
+ const cfnClient = options.mockCloudFormation ||
174
+ new client_cloudformation_1.CloudFormationClient({ region: parsed.region });
175
+ const smClient = options.mockSecretsManager ||
176
+ new client_secrets_manager_1.SecretsManagerClient({ region: parsed.region });
177
+ // Step 3: Fetch stack outputs
178
+ const outputs = await extractStackOutputs(cfnClient, parsed.stackName);
179
+ // Step 4: Validate required outputs
180
+ this.validateRequiredOutputs(outputs);
181
+ // Step 5: Fetch Benchling secret
182
+ const secret = await resolveAndFetchSecret(smClient, parsed.region, options.benchlingSecret);
183
+ // Step 6: Resolve catalog URL
184
+ const catalog = this.resolveCatalogUrl(outputs);
185
+ // Step 7: Assemble complete configuration
186
+ const config = {
187
+ // AWS
188
+ awsRegion: parsed.region,
189
+ awsAccount: parsed.account,
190
+ // Quilt
191
+ quiltCatalog: catalog,
192
+ quiltDatabase: outputs.UserAthenaDatabaseName,
193
+ quiltUserBucket: outputs.UserBucket || outputs.BucketName,
194
+ queueArn: outputs.PackagerQueueArn,
195
+ // Benchling
196
+ benchlingTenant: secret.tenant,
197
+ benchlingClientId: secret.client_id,
198
+ benchlingClientSecret: secret.client_secret,
199
+ benchlingAppDefinitionId: secret.app_definition_id,
200
+ benchlingApiUrl: secret.api_url,
201
+ // Optional defaults
202
+ pkgPrefix: "benchling",
203
+ pkgKey: "experiment_id",
204
+ logLevel: "INFO",
205
+ enableWebhookVerification: true,
206
+ };
207
+ // Cache for container lifetime
208
+ this.cache = config;
209
+ return config;
210
+ }
211
+ /**
212
+ * Validate that required CloudFormation outputs are present
213
+ *
214
+ * @param outputs - Stack outputs
215
+ * @throws ConfigResolverError if required outputs are missing
216
+ */
217
+ validateRequiredOutputs(outputs) {
218
+ const required = ["UserAthenaDatabaseName", "PackagerQueueArn"];
219
+ // UserBucket or BucketName (at least one required)
220
+ if (!outputs.UserBucket && !outputs.BucketName) {
221
+ required.push("UserBucket or BucketName");
222
+ }
223
+ const missing = required.filter((key) => !outputs[key]);
224
+ if (missing.length > 0) {
225
+ throw new ConfigResolverError(`Missing required CloudFormation outputs: ${missing.join(", ")}`, "Ensure your Quilt stack exports these outputs", `Available outputs: ${Object.keys(outputs).join(", ")}`);
226
+ }
227
+ }
228
+ /**
229
+ * Resolve catalog URL from stack outputs
230
+ *
231
+ * @param outputs - Stack outputs
232
+ * @returns Normalized catalog URL (hostname only)
233
+ * @throws ConfigResolverError if catalog URL cannot be determined
234
+ */
235
+ resolveCatalogUrl(outputs) {
236
+ // Option 1: Direct from Catalog or CatalogDomain output
237
+ if (outputs.Catalog) {
238
+ return this.normalizeCatalogUrl(outputs.Catalog);
239
+ }
240
+ if (outputs.CatalogDomain) {
241
+ return this.normalizeCatalogUrl(outputs.CatalogDomain);
242
+ }
243
+ // Option 2: Extract from API Gateway endpoint
244
+ if (outputs.ApiGatewayEndpoint) {
245
+ try {
246
+ const url = new URL(outputs.ApiGatewayEndpoint);
247
+ return url.hostname;
248
+ }
249
+ catch {
250
+ // Invalid URL, fall through to error
251
+ }
252
+ }
253
+ throw new ConfigResolverError("Cannot determine catalog URL", "Stack must export \"Catalog\", \"CatalogDomain\", or \"ApiGatewayEndpoint\"");
254
+ }
255
+ /**
256
+ * Normalize catalog URL to hostname only (remove protocol and trailing slash)
257
+ *
258
+ * @param url - Catalog URL
259
+ * @returns Normalized hostname
260
+ */
261
+ normalizeCatalogUrl(url) {
262
+ return url.replace(/^https?:\/\//, "").replace(/\/$/, "");
263
+ }
264
+ /**
265
+ * Clear cached configuration (for testing only)
266
+ */
267
+ clearCache() {
268
+ this.cache = null;
269
+ }
270
+ }
271
+ exports.ConfigResolver = ConfigResolver;
272
+ //# sourceMappingURL=config-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-resolver.js","sourceRoot":"","sources":["../../../lib/utils/config-resolver.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AA+GH,sCAqBC;AAUD,kDAoCC;AAWD,sDAqEC;AAhQD,0EAGwC;AACxC,4EAGyC;AACzC,uCAGmB;AAoDnB;;GAEG;AACH,MAAa,mBAAoB,SAAQ,KAAK;IAC1C,YACI,OAAe,EACH,UAAmB,EACnB,OAAgB;QAE5B,KAAK,CAAC,OAAO,CAAC,CAAC;QAHH,eAAU,GAAV,UAAU,CAAS;QACnB,YAAO,GAAP,OAAO,CAAS;QAG5B,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAElC,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC1B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;QACvD,CAAC;IACL,CAAC;IAED;;KAEC;IACD,MAAM;QACF,IAAI,MAAM,GAAG,0BAA0B,IAAI,CAAC,OAAO,EAAE,CAAC;QAEtD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAClB,MAAM,IAAI,WAAW,IAAI,CAAC,UAAU,EAAE,CAAC;QAC3C,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,MAAM,IAAI,YAAY,IAAI,CAAC,OAAO,EAAE,CAAC;QACzC,CAAC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ;AA9BD,kDA8BC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,aAAa,CAAC,GAAW;IACrC,MAAM,OAAO,GACb,qEAAqE,CAAC;IACtE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEjC,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,MAAM,IAAI,mBAAmB,CACzB,yCAAyC,EACzC,qEAAqE,EACrE,aAAa,GAAG,EAAE,CACrB,CAAC;IACN,CAAC;IAED,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;IAEtD,OAAO;QACH,MAAM;QACN,OAAO;QACP,SAAS;QACT,OAAO;KACV,CAAC;AACN,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,mBAAmB,CACrC,MAA4B,EAC5B,SAAiB;IAEjB,MAAM,OAAO,GAAG,IAAI,6CAAqB,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;IAEpE,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;QAEnC,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,MAAM,IAAI,mBAAmB,CACzB,oBAAoB,SAAS,EAAE,EAC/B,0DAA0D,CAC7D,CAAC;QACN,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;QACpC,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAU,EAAE,CAAC,CAAC,WAAY,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACtB,IAAI,KAAK,YAAY,mBAAmB,EAAE,CAAC;YACvC,MAAM,KAAK,CAAC;QAChB,CAAC;QAED,IAAK,KAAe,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC9C,MAAM,IAAI,mBAAmB,CACzB,uBAAuB,SAAS,EAAE,EAClC,sCAAsC,CACzC,CAAC;QACN,CAAC;QAED,MAAM,IAAI,mBAAmB,CACzB,6BAA8B,KAAe,CAAC,OAAO,EAAE,EACvD,uCAAuC,CAC1C,CAAC;IACN,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACI,KAAK,UAAU,qBAAqB,CACvC,MAA4B,EAC5B,MAAc,EACd,gBAAwB;IAExB,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,8CAAqB,CAAC,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC,CAAC;QAC1E,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE5C,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;YACzB,MAAM,IAAI,mBAAmB,CACzB,qCAAqC,EACrC,oDAAoD,CACvD,CAAC;QACN,CAAC;QAED,aAAa;QACb,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,UAAU,EAAE,CAAC;YAClB,MAAM,IAAI,mBAAmB,CACzB,8BAA8B,EAC9B,mCAAmC,EACnC,gBAAiB,UAAoB,CAAC,OAAO,EAAE,CAClD,CAAC;QACN,CAAC;QAED,qBAAqB;QACrB,MAAM,UAAU,GAAG,IAAA,4BAAkB,EAAC,IAAI,CAAC,CAAC;QAE5C,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM;iBAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;iBACtC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChB,MAAM,IAAI,mBAAmB,CACzB,0BAA0B,EAC1B,MAAM,EACN,uFAAuF,CAC1F,CAAC;QACN,CAAC;QAED,OAAO,IAA2B,CAAC;IACvC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACtB,IAAI,KAAK,YAAY,mBAAmB,EAAE,CAAC;YACvC,MAAM,KAAK,CAAC;QAChB,CAAC;QAED,IAAK,KAAe,CAAC,IAAI,KAAK,2BAA2B,EAAE,CAAC;YACxD,MAAM,IAAI,mBAAmB,CACzB,qBAAqB,gBAAgB,EAAE,EACvC,mEAAmE,EACnE,WAAW,MAAM,EAAE,CACtB,CAAC;QACN,CAAC;QAED,IAAK,KAAe,CAAC,IAAI,KAAK,uBAAuB,EAAE,CAAC;YACpD,MAAM,IAAI,mBAAmB,CACzB,4BAA4B,gBAAgB,EAAE,EAC9C,kEAAkE,EAClE,WAAW,MAAM,EAAE,CACtB,CAAC;QACN,CAAC;QAED,MAAM,IAAI,mBAAmB,CACzB,2BAA4B,KAAe,CAAC,OAAO,EAAE,EACrD,uCAAuC,CAC1C,CAAC;IACN,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAa,cAAc;IAA3B;QACY,UAAK,GAA0B,IAAI,CAAC;IAqJhD,CAAC;IAnJG;;;;;;KAMC;IACD,KAAK,CAAC,OAAO,CAAC,OAA8B;QAC5C,oCAAoC;QAChC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,KAAK,CAAC;QACtB,CAAC;QAED,0BAA0B;QAC1B,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAEpD,wDAAwD;QACxD,MAAM,SAAS,GACjB,OAAO,CAAC,kBAAkB;YAC1B,IAAI,4CAAoB,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAElD,MAAM,QAAQ,GAChB,OAAO,CAAC,kBAAkB;YAC1B,IAAI,6CAAoB,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAElD,8BAA8B;QAC9B,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QAEvE,oCAAoC;QACpC,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAEtC,iCAAiC;QACjC,MAAM,MAAM,GAAG,MAAM,qBAAqB,CACtC,QAAQ,EACR,MAAM,CAAC,MAAM,EACb,OAAO,CAAC,eAAe,CAC1B,CAAC;QAEF,8BAA8B;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAEhD,0CAA0C;QAC1C,MAAM,MAAM,GAAmB;YAC3B,MAAM;YACN,SAAS,EAAE,MAAM,CAAC,MAAM;YACxB,UAAU,EAAE,MAAM,CAAC,OAAO;YAE1B,QAAQ;YACR,YAAY,EAAE,OAAO;YACrB,aAAa,EAAE,OAAO,CAAC,sBAAsB;YAC7C,eAAe,EAAE,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU;YACzD,QAAQ,EAAE,OAAO,CAAC,gBAAgB;YAElC,YAAY;YACZ,eAAe,EAAE,MAAM,CAAC,MAAM;YAC9B,iBAAiB,EAAE,MAAM,CAAC,SAAS;YACnC,qBAAqB,EAAE,MAAM,CAAC,aAAa;YAC3C,wBAAwB,EAAE,MAAM,CAAC,iBAAiB;YAClD,eAAe,EAAE,MAAM,CAAC,OAAO;YAE/B,oBAAoB;YACpB,SAAS,EAAE,WAAW;YACtB,MAAM,EAAE,eAAe;YACvB,QAAQ,EAAE,MAAM;YAChB,yBAAyB,EAAE,IAAI;SAClC,CAAC;QAEF,+BAA+B;QAC/B,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;QAEpB,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;;;;KAKC;IACO,uBAAuB,CAAC,OAA+B;QAC3D,MAAM,QAAQ,GAAG,CAAC,wBAAwB,EAAE,kBAAkB,CAAC,CAAC;QAEhE,mDAAmD;QACnD,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YAC7C,QAAQ,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QAED,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAExD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,mBAAmB,CACzB,4CAA4C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAChE,+CAA+C,EAC/C,sBAAsB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC1D,CAAC;QACN,CAAC;IACL,CAAC;IAED;;;;;;KAMC;IACO,iBAAiB,CAAC,OAA+B;QACzD,wDAAwD;QACpD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrD,CAAC;QAED,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAC3D,CAAC;QAED,8CAA8C;QAC9C,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;gBAChD,OAAO,GAAG,CAAC,QAAQ,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACL,qCAAqC;YACzC,CAAC;QACL,CAAC;QAED,MAAM,IAAI,mBAAmB,CACzB,8BAA8B,EAC9B,6EAA6E,CAChF,CAAC;IACN,CAAC;IAED;;;;;KAKC;IACO,mBAAmB,CAAC,GAAW;QACnC,OAAO,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED;;KAEC;IACD,UAAU;QACN,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACtB,CAAC;CACJ;AAtJD,wCAsJC"}
@@ -1,4 +1,6 @@
1
1
  export interface Config {
2
+ quiltStackArn?: string;
3
+ benchlingSecret?: string;
2
4
  quiltCatalog: string;
3
5
  quiltUserBucket: string;
4
6
  quiltDatabase: string;
@@ -6,6 +8,7 @@ export interface Config {
6
8
  benchlingClientId: string;
7
9
  benchlingClientSecret: string;
8
10
  benchlingAppDefinitionId: string;
11
+ benchlingSecrets?: string;
9
12
  cdkAccount: string;
10
13
  cdkRegion: string;
11
14
  awsProfile?: string;
@@ -30,6 +33,7 @@ export interface ConfigOptions {
30
33
  profile?: string;
31
34
  region?: string;
32
35
  imageTag?: string;
36
+ benchlingSecrets?: string;
33
37
  }
34
38
  export interface ValidationResult {
35
39
  valid: boolean;
@@ -50,6 +54,52 @@ export declare function getQuilt3Catalog(): string | undefined;
50
54
  * Load .env file and expand variables
51
55
  */
52
56
  export declare function loadDotenv(filePath: string): Record<string, string>;
57
+ /**
58
+ * Process benchling-secrets parameter, handling @file.json syntax
59
+ *
60
+ * Supports three input formats:
61
+ * - ARN: `arn:aws:secretsmanager:...` - passed through unchanged
62
+ * - JSON: `{"client_id":"...","client_secret":"...","tenant":"..."}` - passed through unchanged
63
+ * - File: `@secrets.json` - reads file content from path after @ symbol
64
+ *
65
+ * @param input - The benchling-secrets value (ARN, JSON, or @filepath)
66
+ * @returns Processed secret string (trimmed)
67
+ * @throws Error if file not found or not readable
68
+ *
69
+ * @example
70
+ * // Pass through ARN
71
+ * processBenchlingSecretsInput("arn:aws:secretsmanager:...")
72
+ * // Returns: "arn:aws:secretsmanager:..."
73
+ *
74
+ * @example
75
+ * // Pass through JSON
76
+ * processBenchlingSecretsInput('{"client_id":"...","client_secret":"...","tenant":"..."}')
77
+ * // Returns: '{"client_id":"...","client_secret":"...","tenant":"..."}'
78
+ *
79
+ * @example
80
+ * // Read from file
81
+ * processBenchlingSecretsInput("@secrets.json")
82
+ * // Returns: contents of secrets.json (trimmed)
83
+ */
84
+ export declare function processBenchlingSecretsInput(input: string): string;
85
+ /**
86
+ * Mask sensitive parts of ARN for display
87
+ *
88
+ * Shows region and partial secret name, masks account ID for security.
89
+ * Account ID is masked as ****XXXX where XXXX are the last 4 digits.
90
+ *
91
+ * @param arn - AWS Secrets Manager ARN to mask
92
+ * @returns Masked ARN string or original input if not valid ARN format
93
+ *
94
+ * @example
95
+ * maskArn("arn:aws:secretsmanager:us-east-1:123456789012:secret:name")
96
+ * // Returns: "arn:aws:secretsmanager:us-east-1:****9012:secret:name"
97
+ *
98
+ * @example
99
+ * maskArn("not-an-arn")
100
+ * // Returns: "not-an-arn"
101
+ */
102
+ export declare function maskArn(arn: string): string;
53
103
  /**
54
104
  * Load configuration from multiple sources with priority:
55
105
  * 1. CLI options (highest)