@pipeline-builder/pipeline-core 0.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.
- package/LICENSE +202 -0
- package/README.md +69 -0
- package/lib/cdk.d.ts +38 -0
- package/lib/cdk.js +44 -0
- package/lib/config/app-config.d.ts +109 -0
- package/lib/config/app-config.js +197 -0
- package/lib/config/aws-config-cdk.d.ts +49 -0
- package/lib/config/aws-config-cdk.js +65 -0
- package/lib/config/billing-config.d.ts +24 -0
- package/lib/config/billing-config.js +497 -0
- package/lib/config/config-types.d.ts +346 -0
- package/lib/config/config-types.js +4 -0
- package/lib/config/entitlements.d.ts +23 -0
- package/lib/config/entitlements.js +46 -0
- package/lib/config/handler-constants.d.ts +10 -0
- package/lib/config/handler-constants.js +39 -0
- package/lib/config/infrastructure-config.d.ts +66 -0
- package/lib/config/infrastructure-config.js +197 -0
- package/lib/config/server-config.d.ts +53 -0
- package/lib/config/server-config.js +175 -0
- package/lib/config/service-client.d.ts +13 -0
- package/lib/config/service-client.js +20 -0
- package/lib/core/artifact-manager.d.ts +62 -0
- package/lib/core/artifact-manager.js +83 -0
- package/lib/core/id-generator.d.ts +50 -0
- package/lib/core/id-generator.js +50 -0
- package/lib/core/metadata-builder.d.ts +48 -0
- package/lib/core/metadata-builder.js +278 -0
- package/lib/core/metadata-helpers.d.ts +31 -0
- package/lib/core/metadata-helpers.js +55 -0
- package/lib/core/network-types.d.ts +200 -0
- package/lib/core/network-types.js +4 -0
- package/lib/core/network.d.ts +33 -0
- package/lib/core/network.js +112 -0
- package/lib/core/pipeline-helpers.d.ts +61 -0
- package/lib/core/pipeline-helpers.js +563 -0
- package/lib/core/pipeline-types.d.ts +118 -0
- package/lib/core/pipeline-types.js +131 -0
- package/lib/core/role-types.d.ts +254 -0
- package/lib/core/role-types.js +4 -0
- package/lib/core/role.d.ts +14 -0
- package/lib/core/role.js +117 -0
- package/lib/core/security-group-types.d.ts +84 -0
- package/lib/core/security-group-types.js +4 -0
- package/lib/core/security-group.d.ts +14 -0
- package/lib/core/security-group.js +33 -0
- package/lib/handlers/plugin-lookup-handler.d.ts +32 -0
- package/lib/handlers/plugin-lookup-handler.js +292 -0
- package/lib/handlers/pnpm-lock.yaml +12 -0
- package/lib/index.d.ts +45 -0
- package/lib/index.js +53 -0
- package/lib/pipeline/pipeline-builder.d.ts +123 -0
- package/lib/pipeline/pipeline-builder.js +476 -0
- package/lib/pipeline/pipeline-configuration.d.ts +81 -0
- package/lib/pipeline/pipeline-configuration.js +214 -0
- package/lib/pipeline/plugin-lookup.d.ts +131 -0
- package/lib/pipeline/plugin-lookup.js +316 -0
- package/lib/pipeline/plugin-spec.d.ts +138 -0
- package/lib/pipeline/plugin-spec.js +4 -0
- package/lib/pipeline/source-builder.d.ts +62 -0
- package/lib/pipeline/source-builder.js +164 -0
- package/lib/pipeline/source-types.d.ts +221 -0
- package/lib/pipeline/source-types.js +4 -0
- package/lib/pipeline/stage-builder.d.ts +78 -0
- package/lib/pipeline/stage-builder.js +129 -0
- package/lib/pipeline/step-types.d.ts +222 -0
- package/lib/pipeline/step-types.js +4 -0
- package/lib/template/evaluator.d.ts +42 -0
- package/lib/template/evaluator.js +164 -0
- package/lib/template/index.d.ts +34 -0
- package/lib/template/index.js +118 -0
- package/lib/template/metrics.d.ts +10 -0
- package/lib/template/metrics.js +43 -0
- package/lib/template/plugin-resolver.d.ts +8 -0
- package/lib/template/plugin-resolver.js +48 -0
- package/lib/template/tokenizer.d.ts +49 -0
- package/lib/template/tokenizer.js +233 -0
- package/lib/template/topo-sort.d.ts +17 -0
- package/lib/template/topo-sort.js +88 -0
- package/lib/template/validate.d.ts +45 -0
- package/lib/template/validate.js +96 -0
- package/lib/template/walker.d.ts +34 -0
- package/lib/template/walker.js +83 -0
- package/package.json +184 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { BuilderProps } from './pipeline-builder.js';
|
|
2
|
+
import type { CodeCommitOptions, CodeStarOptions, GitHubOptions, S3Options, SourceType } from './source-types.js';
|
|
3
|
+
import type { PluginOptions, StageOptions, StepCustomization } from './step-types.js';
|
|
4
|
+
import type { CodeBuildDefaults, NetworkConfig } from '../core/network-types.js';
|
|
5
|
+
import type { MetaDataType } from '../core/pipeline-types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Validated and processed pipeline configuration (business logic layer).
|
|
8
|
+
* This class handles all non-CDK logic: validation, sanitization, and metadata merging.
|
|
9
|
+
* It can be tested independently without CDK dependencies.
|
|
10
|
+
*
|
|
11
|
+
* ## Metadata merge chain (last wins)
|
|
12
|
+
*
|
|
13
|
+
* 1. `BuilderProps.global` — base metadata inherited by all steps
|
|
14
|
+
* 2. `BuilderProps.defaults.metadata` — pipeline-level CodeBuild defaults metadata
|
|
15
|
+
* 3. `BuilderProps.synth.metadata` or `StageStepOptions.metadata` — per-step metadata
|
|
16
|
+
* 4. `plugin.metadata` — plugin's own metadata (merged in `createCodeBuildStep`)
|
|
17
|
+
* 5. `metadataForXxx()` — extracted CDK props spread last into construct calls
|
|
18
|
+
*
|
|
19
|
+
* Steps 1–3 are merged here into `this.metadata.merged`.
|
|
20
|
+
* Step 4 happens in `createCodeBuildStep` via `merge(metadata, plugin.metadata)`.
|
|
21
|
+
* Step 5 is spread last in the CDK constructor call, giving metadata full override authority.
|
|
22
|
+
*/
|
|
23
|
+
export declare class PipelineConfiguration {
|
|
24
|
+
readonly project: string;
|
|
25
|
+
readonly organization: string;
|
|
26
|
+
readonly pipelineName: string;
|
|
27
|
+
readonly metadata: {
|
|
28
|
+
readonly global: MetaDataType;
|
|
29
|
+
readonly synth: MetaDataType;
|
|
30
|
+
readonly merged: MetaDataType;
|
|
31
|
+
};
|
|
32
|
+
readonly source: SourceType;
|
|
33
|
+
readonly plugin: PluginOptions;
|
|
34
|
+
readonly network: NetworkConfig | undefined;
|
|
35
|
+
readonly defaults: CodeBuildDefaults | undefined;
|
|
36
|
+
readonly synthCustomization: StepCustomization;
|
|
37
|
+
readonly stages: StageOptions[] | undefined;
|
|
38
|
+
/** Pipeline-level template variables, exposed to `{{ pipeline.vars.* }}`. */
|
|
39
|
+
readonly vars: Record<string, unknown>;
|
|
40
|
+
constructor(props: BuilderProps);
|
|
41
|
+
/**
|
|
42
|
+
* Template scope exposed as `pipeline.*` to pipeline configs, plugin specs, and
|
|
43
|
+
* the source builder. Built once here so every consumer — the synth step, each
|
|
44
|
+
* stage step, and the source token — resolves `{{ pipeline.* }}` against the
|
|
45
|
+
* identical snapshot (no drift between call sites).
|
|
46
|
+
*/
|
|
47
|
+
getPipelineScope(): Record<string, unknown>;
|
|
48
|
+
/**
|
|
49
|
+
* Validates BuilderProps to ensure all required fields are present.
|
|
50
|
+
* Throws an error with detailed messages if validation fails.
|
|
51
|
+
*/
|
|
52
|
+
private validateProps;
|
|
53
|
+
/**
|
|
54
|
+
* Extracts S3 source options with defaults applied.
|
|
55
|
+
*
|
|
56
|
+
* @returns S3 options with `objectKey` defaulting to `'source.zip'` and `trigger` defaulting to `NONE`
|
|
57
|
+
* @throws {Error} If the configured source type is not `s3`
|
|
58
|
+
*/
|
|
59
|
+
getS3Options(): Required<Pick<S3Options, 'bucketName' | 'objectKey' | 'trigger'>> & Omit<S3Options, 'bucketName' | 'objectKey' | 'trigger'>;
|
|
60
|
+
/**
|
|
61
|
+
* Extracts GitHub source options with defaults applied.
|
|
62
|
+
*
|
|
63
|
+
* @returns GitHub options with `branch` defaulting to `'main'` and `trigger` defaulting to `NONE`
|
|
64
|
+
* @throws {Error} If the configured source type is not `github`
|
|
65
|
+
*/
|
|
66
|
+
getGitHubOptions(): Required<Pick<GitHubOptions, 'repo' | 'branch' | 'trigger'>> & Omit<GitHubOptions, 'repo' | 'branch' | 'trigger'>;
|
|
67
|
+
/**
|
|
68
|
+
* Extracts CodeStar source options with defaults applied.
|
|
69
|
+
*
|
|
70
|
+
* @returns CodeStar options with `branch` defaulting to `'main'`, `trigger` defaulting to `NONE`, and `codeBuildCloneOutput` defaulting to `false`
|
|
71
|
+
* @throws {Error} If the configured source type is not `codestar`
|
|
72
|
+
*/
|
|
73
|
+
getCodeStarOptions(): Required<Pick<CodeStarOptions, 'repo' | 'branch' | 'trigger' | 'codeBuildCloneOutput' | 'connectionArn'>>;
|
|
74
|
+
/**
|
|
75
|
+
* Extracts CodeCommit source options with defaults applied.
|
|
76
|
+
*
|
|
77
|
+
* @returns CodeCommit options with `branch` defaulting to `'main'` and `trigger` defaulting to `NONE`
|
|
78
|
+
* @throws {Error} If the configured source type is not `codecommit`
|
|
79
|
+
*/
|
|
80
|
+
getCodeCommitOptions(): Required<Pick<CodeCommitOptions, 'repositoryName' | 'branch' | 'trigger'>>;
|
|
81
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { CoreConstants } from '../config/app-config.js';
|
|
4
|
+
import { merge, replaceNonAlphanumeric } from '../core/metadata-helpers.js';
|
|
5
|
+
import { TriggerType } from '../core/pipeline-types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Validated and processed pipeline configuration (business logic layer).
|
|
8
|
+
* This class handles all non-CDK logic: validation, sanitization, and metadata merging.
|
|
9
|
+
* It can be tested independently without CDK dependencies.
|
|
10
|
+
*
|
|
11
|
+
* ## Metadata merge chain (last wins)
|
|
12
|
+
*
|
|
13
|
+
* 1. `BuilderProps.global` — base metadata inherited by all steps
|
|
14
|
+
* 2. `BuilderProps.defaults.metadata` — pipeline-level CodeBuild defaults metadata
|
|
15
|
+
* 3. `BuilderProps.synth.metadata` or `StageStepOptions.metadata` — per-step metadata
|
|
16
|
+
* 4. `plugin.metadata` — plugin's own metadata (merged in `createCodeBuildStep`)
|
|
17
|
+
* 5. `metadataForXxx()` — extracted CDK props spread last into construct calls
|
|
18
|
+
*
|
|
19
|
+
* Steps 1–3 are merged here into `this.metadata.merged`.
|
|
20
|
+
* Step 4 happens in `createCodeBuildStep` via `merge(metadata, plugin.metadata)`.
|
|
21
|
+
* Step 5 is spread last in the CDK constructor call, giving metadata full override authority.
|
|
22
|
+
*/
|
|
23
|
+
export class PipelineConfiguration {
|
|
24
|
+
project;
|
|
25
|
+
organization;
|
|
26
|
+
pipelineName;
|
|
27
|
+
metadata;
|
|
28
|
+
source;
|
|
29
|
+
plugin;
|
|
30
|
+
network;
|
|
31
|
+
defaults;
|
|
32
|
+
synthCustomization;
|
|
33
|
+
stages;
|
|
34
|
+
/** Pipeline-level template variables, exposed to `{{ pipeline.vars.* }}`. */
|
|
35
|
+
vars;
|
|
36
|
+
constructor(props) {
|
|
37
|
+
this.validateProps(props);
|
|
38
|
+
// Sanitize project and organization names
|
|
39
|
+
this.project = replaceNonAlphanumeric(props.project, '_').toLowerCase();
|
|
40
|
+
this.organization = replaceNonAlphanumeric(props.organization, '_').toLowerCase();
|
|
41
|
+
// Calculate pipeline name
|
|
42
|
+
this.pipelineName = props.pipelineName ?? `${this.organization}-${this.project}-pipeline`;
|
|
43
|
+
// Metadata merging: global → defaults → synth-specific
|
|
44
|
+
const global = { ...(props.global ?? {}) };
|
|
45
|
+
const withDefaults = merge(global, props.defaults?.metadata ?? {});
|
|
46
|
+
this.metadata = {
|
|
47
|
+
global,
|
|
48
|
+
synth: props.synth.metadata ?? {},
|
|
49
|
+
merged: merge(withDefaults, props.synth.metadata ?? {}),
|
|
50
|
+
};
|
|
51
|
+
// Expose synth/builder properties directly
|
|
52
|
+
this.source = props.synth.source;
|
|
53
|
+
this.plugin = props.synth.plugin;
|
|
54
|
+
this.network = props.synth.network;
|
|
55
|
+
this.defaults = props.defaults;
|
|
56
|
+
this.synthCustomization = {
|
|
57
|
+
preInstallCommands: props.synth.preInstallCommands,
|
|
58
|
+
postInstallCommands: props.synth.postInstallCommands,
|
|
59
|
+
preCommands: props.synth.preCommands,
|
|
60
|
+
postCommands: props.synth.postCommands,
|
|
61
|
+
env: props.synth.env,
|
|
62
|
+
};
|
|
63
|
+
this.stages = props.stages;
|
|
64
|
+
this.vars = props.vars ?? {};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Template scope exposed as `pipeline.*` to pipeline configs, plugin specs, and
|
|
68
|
+
* the source builder. Built once here so every consumer — the synth step, each
|
|
69
|
+
* stage step, and the source token — resolves `{{ pipeline.* }}` against the
|
|
70
|
+
* identical snapshot (no drift between call sites).
|
|
71
|
+
*/
|
|
72
|
+
getPipelineScope() {
|
|
73
|
+
return {
|
|
74
|
+
pipeline: {
|
|
75
|
+
projectName: this.project,
|
|
76
|
+
project: this.project,
|
|
77
|
+
orgId: this.organization,
|
|
78
|
+
organization: this.organization,
|
|
79
|
+
pipelineName: this.pipelineName,
|
|
80
|
+
metadata: this.metadata.merged,
|
|
81
|
+
vars: this.vars,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Validates BuilderProps to ensure all required fields are present.
|
|
87
|
+
* Throws an error with detailed messages if validation fails.
|
|
88
|
+
*/
|
|
89
|
+
validateProps(props) {
|
|
90
|
+
const errors = [];
|
|
91
|
+
if (!props.project) {
|
|
92
|
+
errors.push('BuilderProps.project is required');
|
|
93
|
+
}
|
|
94
|
+
if (!props.organization) {
|
|
95
|
+
errors.push('BuilderProps.organization is required');
|
|
96
|
+
}
|
|
97
|
+
if (!props.synth?.source) {
|
|
98
|
+
errors.push('BuilderProps.synth.source is required');
|
|
99
|
+
}
|
|
100
|
+
if (!props.synth?.plugin) {
|
|
101
|
+
errors.push('BuilderProps.synth.plugin is required');
|
|
102
|
+
}
|
|
103
|
+
else if (!props.synth.plugin.name?.trim()) {
|
|
104
|
+
errors.push('BuilderProps.synth.plugin.name must be a non-empty string');
|
|
105
|
+
}
|
|
106
|
+
// Validate repo format for GitHub and CodeStar sources (both use "owner/repo")
|
|
107
|
+
const sourceType = props.synth?.source?.type;
|
|
108
|
+
if (sourceType === 'github' || sourceType === 'codestar') {
|
|
109
|
+
const repo = props.synth?.source?.options?.repo;
|
|
110
|
+
if (repo && !repo.includes('/')) {
|
|
111
|
+
errors.push(`Invalid ${sourceType} repository format: "${repo}". Expected format: "owner/repo"`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Validate pipeline name length (AWS max 100 characters)
|
|
115
|
+
const MAX_PIPELINE_NAME_LENGTH = CoreConstants.PIPELINE_NAME_MAX_LENGTH;
|
|
116
|
+
const pipelineName = props.pipelineName
|
|
117
|
+
?? `${replaceNonAlphanumeric(props.organization ?? '', '_').toLowerCase()}-${replaceNonAlphanumeric(props.project ?? '', '_').toLowerCase()}-pipeline`;
|
|
118
|
+
if (pipelineName.length > MAX_PIPELINE_NAME_LENGTH) {
|
|
119
|
+
errors.push(`Pipeline name "${pipelineName}" exceeds AWS maximum of ${MAX_PIPELINE_NAME_LENGTH} characters (${pipelineName.length})`);
|
|
120
|
+
}
|
|
121
|
+
// Validate stages
|
|
122
|
+
if (props.stages) {
|
|
123
|
+
const stageNames = new Set();
|
|
124
|
+
for (const stage of props.stages) {
|
|
125
|
+
if (!stage.stageName?.trim()) {
|
|
126
|
+
errors.push('Each stage must have a non-empty stageName');
|
|
127
|
+
}
|
|
128
|
+
else if (stageNames.has(stage.stageName)) {
|
|
129
|
+
errors.push(`Duplicate stage name: "${stage.stageName}"`);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
stageNames.add(stage.stageName);
|
|
133
|
+
}
|
|
134
|
+
if (!stage.steps?.length) {
|
|
135
|
+
errors.push(`Stage "${stage.stageName ?? '(unnamed)'}" must have at least one step`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (errors.length > 0) {
|
|
140
|
+
throw new Error('Pipeline configuration validation failed:\n' +
|
|
141
|
+
errors.map(e => ` - ${e}`).join('\n'));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Extracts S3 source options with defaults applied.
|
|
146
|
+
*
|
|
147
|
+
* @returns S3 options with `objectKey` defaulting to `'source.zip'` and `trigger` defaulting to `NONE`
|
|
148
|
+
* @throws {Error} If the configured source type is not `s3`
|
|
149
|
+
*/
|
|
150
|
+
getS3Options() {
|
|
151
|
+
const source = this.source;
|
|
152
|
+
if (source.type !== 's3') {
|
|
153
|
+
throw new Error('Source type is not S3');
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
...source.options,
|
|
157
|
+
objectKey: source.options.objectKey ?? 'source.zip',
|
|
158
|
+
trigger: source.options.trigger ?? TriggerType.NONE,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Extracts GitHub source options with defaults applied.
|
|
163
|
+
*
|
|
164
|
+
* @returns GitHub options with `branch` defaulting to `'main'` and `trigger` defaulting to `NONE`
|
|
165
|
+
* @throws {Error} If the configured source type is not `github`
|
|
166
|
+
*/
|
|
167
|
+
getGitHubOptions() {
|
|
168
|
+
const source = this.source;
|
|
169
|
+
if (source.type !== 'github') {
|
|
170
|
+
throw new Error('Source type is not GitHub');
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
...source.options,
|
|
174
|
+
branch: source.options.branch ?? 'main',
|
|
175
|
+
trigger: source.options.trigger ?? TriggerType.NONE,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Extracts CodeStar source options with defaults applied.
|
|
180
|
+
*
|
|
181
|
+
* @returns CodeStar options with `branch` defaulting to `'main'`, `trigger` defaulting to `NONE`, and `codeBuildCloneOutput` defaulting to `false`
|
|
182
|
+
* @throws {Error} If the configured source type is not `codestar`
|
|
183
|
+
*/
|
|
184
|
+
getCodeStarOptions() {
|
|
185
|
+
const source = this.source;
|
|
186
|
+
if (source.type !== 'codestar') {
|
|
187
|
+
throw new Error('Source type is not CodeStar');
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
...source.options,
|
|
191
|
+
branch: source.options.branch ?? 'main',
|
|
192
|
+
trigger: source.options.trigger ?? TriggerType.NONE,
|
|
193
|
+
codeBuildCloneOutput: source.options.codeBuildCloneOutput ?? false,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Extracts CodeCommit source options with defaults applied.
|
|
198
|
+
*
|
|
199
|
+
* @returns CodeCommit options with `branch` defaulting to `'main'` and `trigger` defaulting to `NONE`
|
|
200
|
+
* @throws {Error} If the configured source type is not `codecommit`
|
|
201
|
+
*/
|
|
202
|
+
getCodeCommitOptions() {
|
|
203
|
+
const source = this.source;
|
|
204
|
+
if (source.type !== 'codecommit') {
|
|
205
|
+
throw new Error('Source type is not CodeCommit');
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
...source.options,
|
|
209
|
+
branch: source.options.branch ?? 'main',
|
|
210
|
+
trigger: source.options.trigger ?? TriggerType.NONE,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGlwZWxpbmUtY29uZmlndXJhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9waXBlbGluZS9waXBlbGluZS1jb25maWd1cmF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFLdEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3hELE9BQU8sRUFBRSxLQUFLLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUc1RSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFeEQ7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCxNQUFNLE9BQU8scUJBQXFCO0lBQ2hCLE9BQU8sQ0FBUztJQUNoQixZQUFZLENBQVM7SUFDckIsWUFBWSxDQUFTO0lBQ3JCLFFBQVEsQ0FJdEI7SUFDYyxNQUFNLENBQWE7SUFDbkIsTUFBTSxDQUFnQjtJQUN0QixPQUFPLENBQTRCO0lBQ25DLFFBQVEsQ0FBZ0M7SUFDeEMsa0JBQWtCLENBQW9CO0lBQ3RDLE1BQU0sQ0FBNkI7SUFDbkQsNkVBQTZFO0lBQzdELElBQUksQ0FBMEI7SUFFOUMsWUFBWSxLQUFtQjtRQUM3QixJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTFCLDBDQUEwQztRQUMxQyxJQUFJLENBQUMsT0FBTyxHQUFHLHNCQUFzQixDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDeEUsSUFBSSxDQUFDLFlBQVksR0FBRyxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUFFLEdBQUcsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBRWxGLDBCQUEwQjtRQUMxQixJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQyxZQUFZLElBQUksR0FBRyxJQUFJLENBQUMsWUFBWSxJQUFJLElBQUksQ0FBQyxP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Q0gsb0JBQW9CO1FBQ2xCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUM7UUFDM0IsSUFBSSxNQUFNLENBQUMsSUFBSSxLQUFLLFlBQVksRUFBRSxDQUFDO1lBQ2pDLE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQStCLENBQUMsQ0FBQztRQUNuRCxDQUFDO1FBRUQsT0FBTztZQUNMLEdBQUcsTUFBTSxDQUFDLE9BQU87WUFDakIsTUFBTSxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxJQUFJLE1BQU07WUFDdkMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxJQUFJLFdBQVcsQ0FBQyxJQUFJO1NBQ3BELENBQUM7SUFDSixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHR5cGUgeyBCdWlsZGVyUHJvcHMgfSBmcm9tICcuL3BpcGVsaW5lLWJ1aWxkZXIuanMnO1xuaW1wb3J0IHR5cGUgeyBDb2RlQ29tbWl0T3B0aW9ucywgQ29kZVN0YXJPcHRpb25zLCBHaXRIdWJPcHRpb25zLCBTM09wdGlvbnMsIFNvdXJjZVR5cGUgfSBmcm9tICcuL3NvdXJjZS10eXBlcy5qcyc7XG5pbXBvcnQgdHlwZSB7IFBsdWdpbk9wdGlvbnMsIFN0YWdlT3B0aW9ucywgU3RlcEN1c3RvbWl6YXRpb24gfSBmcm9tICcuL3N0ZXAtdHlwZXMuanMnO1xuaW1wb3J0IHsgQ29yZUNvbnN0YW50cyB9IGZyb20gJy4uL2NvbmZpZy9hcHAtY29uZmlnLmpzJztcbmltcG9ydCB7IG1lcmdlLCByZXBsYWNlTm9uQWxwaGFudW1lcmljIH0gZnJvbSAnLi4vY29yZS9tZXRhZGF0YS1oZWxwZXJzLmpzJztcbmltcG9ydCB0eXBlIHsgQ29kZUJ1aWxkRGVmYXVsdHMsIE5ldHdvcmtDb25maWcgfSBmcm9tICcuLi9jb3JlL25ldHdvcmstdHlwZXMuanMnO1xuaW1wb3J0IHR5cGUgeyBNZXRhRGF0YVR5cGUgfSBmcm9tICcuLi9jb3JlL3BpcGVsaW5lLXR5cGVzLmpzJztcbmltcG9ydCB7IFRyaWdnZXJUeXBlIH0gZnJvbSAnLi4vY29yZS9waXBlbGluZS10eXBlcy5qcyc7XG5cbi8qKlxuICogVmFsaWRhdGVkIGFuZCBwcm9jZXNzZWQgcGlwZWxpbmUgY29uZmlndXJhdGlvbiAoYnVzaW5lc3MgbG9naWMgbGF5ZXIpLlxuICogVGhpcyBjbGFzcyBoYW5kbGVzIGFsbCBub24tQ0RLIGxvZ2ljOiB2YWxpZGF0aW9uLCBzYW5pdGl6YXRpb24sIGFuZCBtZXRhZGF0YSBtZXJnaW5nLlxuICogSXQgY2FuIGJlIHRlc3RlZCBpbmRlcGVuZGVudGx5IHdpdGhvdXQgQ0RLIGRlcGVuZGVuY2llcy5cbiAqXG4gKiAjIyBNZXRhZGF0YSBtZXJnZSBjaGFpbiAobGFzdCB3aW5zKVxuICpcbiAqIDEuIGBCdWlsZGVyUHJvcHMuZ2xvYmFsYCDigJQgYmFzZSBtZXRhZGF0YSBpbmhlcml0ZWQgYnkgYWxsIHN0ZXBzXG4gKiAyLiBgQnVpbGRlclByb3BzLmRlZmF1bHRzLm1ldGFkYXRhYCDigJQgcGlwZWxpbmUtbGV2ZWwgQ29kZUJ1aWxkIGRlZmF1bHRzIG1ldGFkYXRhXG4gKiAzLiBgQnVpbGRlclByb3BzLnN5bnRoLm1ldGFkYXRhYCBvciBgU3RhZ2VTdGVwT3B0aW9ucy5tZXRhZGF0YWAg4oCUIHBlci1zdGVwIG1ldGFkYXRhXG4gKiA0LiBgcGx1Z2luLm1ldGFkYXRhYCDigJQgcGx1Z2luJ3Mgb3duIG1ldGFkYXRhIChtZXJnZWQgaW4gYGNyZWF0ZUNvZGVCdWlsZFN0ZXBgKVxuICogNS4gYG1ldGFkYXRhRm9yWHh4KClgIOKAlCBleHRyYWN0ZWQgQ0RLIHByb3BzIHNwcmVhZCBsYXN0IGludG8gY29uc3RydWN0IGNhbGxzXG4gKlxuICogU3RlcHMgMeKAkzMgYXJlIG1lcmdlZCBoZXJlIGludG8gYHRoaXMubWV0YWRhdGEubWVyZ2VkYC5cbiAqIFN0ZXAgNCBoYXBwZW5zIGluIGBjcmVhdGVDb2RlQnVpbGRTdGVwYCB2aWEgYG1lcmdlKG1ldGFkYXRhLCBwbHVnaW4ubWV0YWRhdGEpYC5cbiAqIFN0ZXAgNSBpcyBzcHJlYWQgbGFzdCBpbiB0aGUgQ0RLIGNvbnN0cnVjdG9yIGNhbGwsIGdpdmluZyBtZXRhZGF0YSBmdWxsIG92ZXJyaWRlIGF1dGhvcml0eS5cbiAqL1xuZXhwb3J0IGNsYXNzIFBpcGVsaW5lQ29uZmlndXJhdGlvbiB7XG4gIHB1YmxpYyByZWFkb25seSBwcm9qZWN0OiBzdHJpbmc7XG4gIHB1YmxpYyByZWFkb25seSBvcmdhbml6YXRpb246IHN0cmluZztcbiAgcHVibGljIHJlYWRvbmx5IHBpcGVsaW5lTmFtZTogc3RyaW5nO1xuICBwdWJsaWMgcmVhZG9ubHkgbWV0YWRhdGE6IHtcbiAgICByZWFkb25seSBnbG9iYWw6IE1ldGFEYXRhVHlwZTtcbiAgICByZWFkb25seSBzeW50aDogTWV0YURhdGFUeXBlO1xuICAgIHJlYWRvbmx5IG1lcmdlZDogTWV0YURhdGFUeXBlO1xuICB9O1xuICBwdWJsaWMgcmVhZG9ubHkgc291cmNlOiBTb3VyY2VUeXBlO1xuICBwdWJsaWMgcmVhZG9ubHkgcGx1Z2luOiBQbHVnaW5PcHRpb25zO1xuICBwdWJsaWMgcmVhZG9ubHkgbmV0d29yazogTmV0d29ya0NvbmZpZyB8IHVuZGVmaW5lZDtcbiAgcHVibGljIHJlYWRvbmx5IGRlZmF1bHRzOiBDb2RlQnVpbGREZWZhdWx0cyB8IHVuZGVmaW5lZDtcbiAgcHVibGljIHJlYWRvbmx5IHN5bnRoQ3VzdG9taXphdGlvbjogU3RlcEN1c3RvbWl6YXRpb247XG4gIHB1YmxpYyByZWFkb25seSBzdGFnZXM6IFN0YWdlT3B0aW9uc1tdIHwgdW5kZWZpbmVkO1xuICAvKiogUGlwZWxpbmUtbGV2ZWwgdGVtcGxhdGUgdmFyaWFibGVzLCBleHBvc2VkIHRvIGB7eyBwaXBlbGluZS52YXJzLiogfX1gLiAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdmFyczogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG5cbiAgY29uc3RydWN0b3IocHJvcHM6IEJ1aWxkZXJQcm9wcykge1xuICAgIHRoaXMudmFsaWRhdGVQcm9wcyhwcm9wcyk7XG5cbiAgICAvLyBTYW5pdGl6ZSBwcm9qZWN0IGFuZCBvcmdhbml6YXRpb24gbmFtZXNcbiAgICB0aGlzLnByb2plY3QgPSByZXBsYWNlTm9uQWxwaGFudW1lcmljKHByb3BzLnByb2plY3QsICdfJykudG9Mb3dlckNhc2UoKTtcbiAgICB0aGlzLm9yZ2FuaXphdGlvbiA9IHJlcGxhY2VOb25BbHBoYW51bWVyaWMocHJvcHMub3JnYW5pemF0aW9uLCAnXycpLnRvTG93ZXJDYXNlKCk7XG5cbiAgICAvLyBDYWxjdWxhdGUgcGlwZWxpbmUgbmFtZVxuICAgIHRoaXMucGlwZWxpbmVOYW1lID0gcHJvcHMucGlwZWxpbmVOYW1lID8/IGAke3RoaXMub3JnYW5pemF0aW9ufS0ke3RoaXMucHJvamVjdH0tcGlwZWxpbmVgO1xuXG4gICAgLy8gTWV0YWRhdGEgbWVyZ2luZzogZ2xvYmFsIOKGkiBkZWZhdWx0cyDihpIgc3ludGgtc3BlY2lmaWNcbiAgICBjb25zdCBnbG9iYWwgPSB7IC4uLihwcm9wcy5nbG9iYWwgPz8ge30pIH07XG4gICAgY29uc3Qgd2l0aERlZmF1bHRzID0gbWVyZ2UoZ2xvYmFsLCBwcm9wcy5kZWZhdWx0cz8ubWV0YWRhdGEgPz8ge30pO1xuICAgIHRoaXMubWV0YWRhdGEgPSB7XG4gICAgICBnbG9iYWwsXG4gICAgICBzeW50aDogcHJvcHMuc3ludGgubWV0YWRhdGEgPz8ge30sXG4gICAgICBtZXJnZWQ6IG1lcmdlKHdpdGhEZWZhdWx0cywgcHJvcHMuc3ludGgubWV0YWRhdGEgPz8ge30pLFxuICAgIH07XG5cbiAgICAvLyBFeHBvc2Ugc3ludGgvYnVpbGRlciBwcm9wZXJ0aWVzIGRpcmVjdGx5XG4gICAgdGhpcy5zb3VyY2UgPSBwcm9wcy5zeW50aC5zb3VyY2U7XG4gICAgdGhpcy5wbHVnaW4gPSBwcm9wcy5zeW50aC5wbHVnaW47XG4gICAgdGhpcy5uZXR3b3JrID0gcHJvcHMuc3ludGgubmV0d29yaztcbiAgICB0aGlzLmRlZmF1bHRzID0gcHJvcHMuZGVmYXVsdHM7XG4gICAgdGhpcy5zeW50aEN1c3RvbWl6YXRpb24gPSB7XG4gICAgICBwcmVJbnN0YWxsQ29tbWFuZHM6IHByb3BzLnN5bnRoLnByZUluc3RhbGxDb21tYW5kcyxcbiAgICAgIHBvc3RJbnN0YWxsQ29tbWFuZHM6IHByb3BzLnN5bnRoLnBvc3RJbnN0YWxsQ29tbWFuZHMsXG4gICAgICBwcmVDb21tYW5kczogcHJvcHMuc3ludGgucHJlQ29tbWFuZHMsXG4gICAgICBwb3N0Q29tbWFuZHM6IHByb3BzLnN5bnRoLnBvc3RDb21tYW5kcyxcbiAgICAgIGVudjogcHJvcHMuc3ludGguZW52LFxuICAgIH07XG4gICAgdGhpcy5zdGFnZXMgPSBwcm9wcy5zdGFnZXM7XG4gICAgdGhpcy52YXJzID0gcHJvcHMudmFycyA/PyB7fTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUZW1wbGF0ZSBzY29wZSBleHBvc2VkIGFzIGBwaXBlbGluZS4qYCB0byBwaXBlbGluZSBjb25maWdzLCBwbHVnaW4gc3BlY3MsIGFuZFxuICAgKiB0aGUgc291cmNlIGJ1aWxkZXIuIEJ1aWx0IG9uY2UgaGVyZSBzbyBldmVyeSBjb25zdW1lciDigJQgdGhlIHN5bnRoIHN0ZXAsIGVhY2hcbiAgICogc3RhZ2Ugc3RlcCwgYW5kIHRoZSBzb3VyY2UgdG9rZW4g4oCUIHJlc29sdmVzIGB7eyBwaXBlbGluZS4qIH19YCBhZ2FpbnN0IHRoZVxuICAgKiBpZGVudGljYWwgc25hcHNob3QgKG5vIGRyaWZ0IGJldHdlZW4gY2FsbCBzaXRlcykuXG4gICAqL1xuICBnZXRQaXBlbGluZVNjb3BlKCk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgICByZXR1cm4ge1xuICAgICAgcGlwZWxpbmU6IHtcbiAgICAgICAgcHJvamVjdE5hbWU6IHRoaXMucHJvamVjdCxcbiAgICAgICAgcHJvamVjdDogdGhpcy5wcm9qZWN0LFxuICAgICAgICBvcmdJZDogdGhpcy5vcmdhbml6YXRpb24sXG4gICAgICAgIG9yZ2FuaXphdGlvbjogdGhpcy5vcmdhbml6YXRpb24sXG4gICAgICAgIHBpcGVsaW5lTmFtZTogdGhpcy5waXBlbGluZU5hbWUsXG4gICAgICAgIG1ldGFkYXRhOiB0aGlzLm1ldGFkYXRhLm1lcmdlZCxcbiAgICAgICAgdmFyczogdGhpcy52YXJzLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyBCdWlsZGVyUHJvcHMgdG8gZW5zdXJlIGFsbCByZXF1aXJlZCBmaWVsZHMgYXJlIHByZXNlbnQuXG4gICAqIFRocm93cyBhbiBlcnJvciB3aXRoIGRldGFpbGVkIG1lc3NhZ2VzIGlmIHZhbGlkYXRpb24gZmFpbHMuXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlUHJvcHMocHJvcHM6IEJ1aWxkZXJQcm9wcyk6IHZvaWQge1xuICAgIGNvbnN0IGVycm9yczogc3RyaW5nW10gPSBbXTtcblxuICAgIGlmICghcHJvcHMucHJvamVjdCkge1xuICAgICAgZXJyb3JzLnB1c2goJ0J1aWxkZXJQcm9wcy5wcm9qZWN0IGlzIHJlcXVpcmVkJyk7XG4gICAgfVxuXG4gICAgaWYgKCFwcm9wcy5vcmdhbml6YXRpb24pIHtcbiAgICAgIGVycm9ycy5wdXNoKCdCdWlsZGVyUHJvcHMub3JnYW5pemF0aW9uIGlzIHJlcXVpcmVkJyk7XG4gICAgfVxuXG4gICAgaWYgKCFwcm9wcy5zeW50aD8uc291cmNlKSB7XG4gICAgICBlcnJvcnMucHVzaCgnQnVpbGRlclByb3BzLnN5bnRoLnNvdXJjZSBpcyByZXF1aXJlZCcpO1xuICAgIH1cblxuICAgIGlmICghcHJvcHMuc3ludGg/LnBsdWdpbikge1xuICAgICAgZXJyb3JzLnB1c2goJ0J1aWxkZXJQcm9wcy5zeW50aC5wbHVnaW4gaXMgcmVxdWlyZWQnKTtcbiAgICB9IGVsc2UgaWYgKCFwcm9wcy5zeW50aC5wbHVnaW4ubmFtZT8udHJpbSgpKSB7XG4gICAgICBlcnJvcnMucHVzaCgnQnVpbGRlclByb3BzLnN5bnRoLnBsdWdpbi5uYW1lIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nJyk7XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgcmVwbyBmb3JtYXQgZm9yIEdpdEh1YiBhbmQgQ29kZVN0YXIgc291cmNlcyAoYm90aCB1c2UgXCJvd25lci9yZXBvXCIpXG4gICAgY29uc3Qgc291cmNlVHlwZSA9IHByb3BzLnN5bnRoPy5zb3VyY2U/LnR5cGU7XG4gICAgaWYgKHNvdXJjZVR5cGUgPT09ICdnaXRodWInIHx8IHNvdXJjZVR5cGUgPT09ICdjb2Rlc3RhcicpIHtcbiAgICAgIGNvbnN0IHJlcG8gPSBwcm9wcy5zeW50aD8uc291cmNlPy5vcHRpb25zPy5yZXBvO1xuICAgICAgaWYgKHJlcG8gJiYgIXJlcG8uaW5jbHVkZXMoJy8nKSkge1xuICAgICAgICBlcnJvcnMucHVzaChgSW52YWxpZCAke3NvdXJjZVR5cGV9IHJlcG9zaXRvcnkgZm9ybWF0OiBcIiR7cmVwb31cIi4gRXhwZWN0ZWQgZm9ybWF0OiBcIm93bmVyL3JlcG9cImApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIHBpcGVsaW5lIG5hbWUgbGVuZ3RoIChBV1MgbWF4IDEwMCBjaGFyYWN0ZXJzKVxuICAgIGNvbnN0IE1BWF9QSVBFTElORV9OQU1FX0xFTkdUSCA9IENvcmVDb25zdGFudHMuUElQRUxJTkVfTkFNRV9NQVhfTEVOR1RIO1xuICAgIGNvbnN0IHBpcGVsaW5lTmFtZSA9IHByb3BzLnBpcGVsaW5lTmFtZVxuICAgICAgPz8gYCR7cmVwbGFjZU5vbkFscGhhbnVtZXJpYyhwcm9wcy5vcmdhbml6YXRpb24gPz8gJycsICdfJykudG9Mb3dlckNhc2UoKX0tJHtyZXBsYWNlTm9uQWxwaGFudW1lcmljKHByb3BzLnByb2plY3QgPz8gJycsICdfJykudG9Mb3dlckNhc2UoKX0tcGlwZWxpbmVgO1xuICAgIGlmIChwaXBlbGluZU5hbWUubGVuZ3RoID4gTUFYX1BJUEVMSU5FX05BTUVfTEVOR1RIKSB7XG4gICAgICBlcnJvcnMucHVzaChgUGlwZWxpbmUgbmFtZSBcIiR7cGlwZWxpbmVOYW1lfVwiIGV4Y2VlZHMgQVdTIG1heGltdW0gb2YgJHtNQVhfUElQRUxJTkVfTkFNRV9MRU5HVEh9IGNoYXJhY3RlcnMgKCR7cGlwZWxpbmVOYW1lLmxlbmd0aH0pYCk7XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgc3RhZ2VzXG4gICAgaWYgKHByb3BzLnN0YWdlcykge1xuICAgICAgY29uc3Qgc3RhZ2VOYW1lcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgICAgZm9yIChjb25zdCBzdGFnZSBvZiBwcm9wcy5zdGFnZXMpIHtcbiAgICAgICAgaWYgKCFzdGFnZS5zdGFnZU5hbWU/LnRyaW0oKSkge1xuICAgICAgICAgIGVycm9ycy5wdXNoKCdFYWNoIHN0YWdlIG11c3QgaGF2ZSBhIG5vbi1lbXB0eSBzdGFnZU5hbWUnKTtcbiAgICAgICAgfSBlbHNlIGlmIChzdGFnZU5hbWVzLmhhcyhzdGFnZS5zdGFnZU5hbWUpKSB7XG4gICAgICAgICAgZXJyb3JzLnB1c2goYER1cGxpY2F0ZSBzdGFnZSBuYW1lOiBcIiR7c3RhZ2Uuc3RhZ2VOYW1lfVwiYCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc3RhZ2VOYW1lcy5hZGQoc3RhZ2Uuc3RhZ2VOYW1lKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXN0YWdlLnN0ZXBzPy5sZW5ndGgpIHtcbiAgICAgICAgICBlcnJvcnMucHVzaChgU3RhZ2UgXCIke3N0YWdlLnN0YWdlTmFtZSA/PyAnKHVubmFtZWQpJ31cIiBtdXN0IGhhdmUgYXQgbGVhc3Qgb25lIHN0ZXBgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChlcnJvcnMubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnUGlwZWxpbmUgY29uZmlndXJhdGlvbiB2YWxpZGF0aW9uIGZhaWxlZDpcXG4nICtcbiAgICAgICAgZXJyb3JzLm1hcChlID0+IGAgIC0gJHtlfWApLmpvaW4oJ1xcbicpLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdHMgUzMgc291cmNlIG9wdGlvbnMgd2l0aCBkZWZhdWx0cyBhcHBsaWVkLlxuICAgKlxuICAgKiBAcmV0dXJucyBTMyBvcHRpb25zIHdpdGggYG9iamVjdEtleWAgZGVmYXVsdGluZyB0byBgJ3NvdXJjZS56aXAnYCBhbmQgYHRyaWdnZXJgIGRlZmF1bHRpbmcgdG8gYE5PTkVgXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgY29uZmlndXJlZCBzb3VyY2UgdHlwZSBpcyBub3QgYHMzYFxuICAgKi9cbiAgZ2V0UzNPcHRpb25zKCk6IFJlcXVpcmVkPFBpY2s8UzNPcHRpb25zLCAnYnVja2V0TmFtZScgfCAnb2JqZWN0S2V5JyB8ICd0cmlnZ2VyJz4+ICYgT21pdDxTM09wdGlvbnMsICdidWNrZXROYW1lJyB8ICdvYmplY3RLZXknIHwgJ3RyaWdnZXInPiB7XG4gICAgY29uc3Qgc291cmNlID0gdGhpcy5zb3VyY2U7XG4gICAgaWYgKHNvdXJjZS50eXBlICE9PSAnczMnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NvdXJjZSB0eXBlIGlzIG5vdCBTMycpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICAuLi5zb3VyY2Uub3B0aW9ucyxcbiAgICAgIG9iamVjdEtleTogc291cmNlLm9wdGlvbnMub2JqZWN0S2V5ID8/ICdzb3VyY2UuemlwJyxcbiAgICAgIHRyaWdnZXI6IHNvdXJjZS5vcHRpb25zLnRyaWdnZXIgPz8gVHJpZ2dlclR5cGUuTk9ORSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEV4dHJhY3RzIEdpdEh1YiBzb3VyY2Ugb3B0aW9ucyB3aXRoIGRlZmF1bHRzIGFwcGxpZWQuXG4gICAqXG4gICAqIEByZXR1cm5zIEdpdEh1YiBvcHRpb25zIHdpdGggYGJyYW5jaGAgZGVmYXVsdGluZyB0byBgJ21haW4nYCBhbmQgYHRyaWdnZXJgIGRlZmF1bHRpbmcgdG8gYE5PTkVgXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgY29uZmlndXJlZCBzb3VyY2UgdHlwZSBpcyBub3QgYGdpdGh1YmBcbiAgICovXG4gIGdldEdpdEh1Yk9wdGlvbnMoKTogUmVxdWlyZWQ8UGljazxHaXRIdWJPcHRpb25zLCAncmVwbycgfCAnYnJhbmNoJyB8ICd0cmlnZ2VyJz4+ICYgT21pdDxHaXRIdWJPcHRpb25zLCAncmVwbycgfCAnYnJhbmNoJyB8ICd0cmlnZ2VyJz4ge1xuICAgIGNvbnN0IHNvdXJjZSA9IHRoaXMuc291cmNlO1xuICAgIGlmIChzb3VyY2UudHlwZSAhPT0gJ2dpdGh1YicpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignU291cmNlIHR5cGUgaXMgbm90IEdpdEh1YicpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICAuLi5zb3VyY2Uub3B0aW9ucyxcbiAgICAgIGJyYW5jaDogc291cmNlLm9wdGlvbnMuYnJhbmNoID8/ICdtYWluJyxcbiAgICAgIHRyaWdnZXI6IHNvdXJjZS5vcHRpb25zLnRyaWdnZXIgPz8gVHJpZ2dlclR5cGUuTk9ORSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEV4dHJhY3RzIENvZGVTdGFyIHNvdXJjZSBvcHRpb25zIHdpdGggZGVmYXVsdHMgYXBwbGllZC5cbiAgICpcbiAgICogQHJldHVybnMgQ29kZVN0YXIgb3B0aW9ucyB3aXRoIGBicmFuY2hgIGRlZmF1bHRpbmcgdG8gYCdtYWluJ2AsIGB0cmlnZ2VyYCBkZWZhdWx0aW5nIHRvIGBOT05FYCwgYW5kIGBjb2RlQnVpbGRDbG9uZU91dHB1dGAgZGVmYXVsdGluZyB0byBgZmFsc2VgXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgY29uZmlndXJlZCBzb3VyY2UgdHlwZSBpcyBub3QgYGNvZGVzdGFyYFxuICAgKi9cbiAgZ2V0Q29kZVN0YXJPcHRpb25zKCk6IFJlcXVpcmVkPFBpY2s8Q29kZVN0YXJPcHRpb25zLCAncmVwbycgfCAnYnJhbmNoJyB8ICd0cmlnZ2VyJyB8ICdjb2RlQnVpbGRDbG9uZU91dHB1dCcgfCAnY29ubmVjdGlvbkFybic+PiB7XG4gICAgY29uc3Qgc291cmNlID0gdGhpcy5zb3VyY2U7XG4gICAgaWYgKHNvdXJjZS50eXBlICE9PSAnY29kZXN0YXInKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NvdXJjZSB0eXBlIGlzIG5vdCBDb2RlU3RhcicpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICAuLi5zb3VyY2Uub3B0aW9ucyxcbiAgICAgIGJyYW5jaDogc291cmNlLm9wdGlvbnMuYnJhbmNoID8/ICdtYWluJyxcbiAgICAgIHRyaWdnZXI6IHNvdXJjZS5vcHRpb25zLnRyaWdnZXIgPz8gVHJpZ2dlclR5cGUuTk9ORSxcbiAgICAgIGNvZGVCdWlsZENsb25lT3V0cHV0OiBzb3VyY2Uub3B0aW9ucy5jb2RlQnVpbGRDbG9uZU91dHB1dCA/PyBmYWxzZSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEV4dHJhY3RzIENvZGVDb21taXQgc291cmNlIG9wdGlvbnMgd2l0aCBkZWZhdWx0cyBhcHBsaWVkLlxuICAgKlxuICAgKiBAcmV0dXJucyBDb2RlQ29tbWl0IG9wdGlvbnMgd2l0aCBgYnJhbmNoYCBkZWZhdWx0aW5nIHRvIGAnbWFpbidgIGFuZCBgdHJpZ2dlcmAgZGVmYXVsdGluZyB0byBgTk9ORWBcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSBjb25maWd1cmVkIHNvdXJjZSB0eXBlIGlzIG5vdCBgY29kZWNvbW1pdGBcbiAgICovXG4gIGdldENvZGVDb21taXRPcHRpb25zKCk6IFJlcXVpcmVkPFBpY2s8Q29kZUNvbW1pdE9wdGlvbnMsICdyZXBvc2l0b3J5TmFtZScgfCAnYnJhbmNoJyB8ICd0cmlnZ2VyJz4+IHtcbiAgICBjb25zdCBzb3VyY2UgPSB0aGlzLnNvdXJjZTtcbiAgICBpZiAoc291cmNlLnR5cGUgIT09ICdjb2RlY29tbWl0Jykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdTb3VyY2UgdHlwZSBpcyBub3QgQ29kZUNvbW1pdCcpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICAuLi5zb3VyY2Uub3B0aW9ucyxcbiAgICAgIGJyYW5jaDogc291cmNlLm9wdGlvbnMuYnJhbmNoID8/ICdtYWluJyxcbiAgICAgIHRyaWdnZXI6IHNvdXJjZS5vcHRpb25zLnRyaWdnZXIgPz8gVHJpZ2dlclR5cGUuTk9ORSxcbiAgICB9O1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { Plugin } from '@pipeline-builder/pipeline-data';
|
|
2
|
+
import { Duration } from 'aws-cdk-lib';
|
|
3
|
+
import { Runtime } from 'aws-cdk-lib/aws-lambda';
|
|
4
|
+
import { RetentionDays } from 'aws-cdk-lib/aws-logs';
|
|
5
|
+
import { Construct } from 'constructs';
|
|
6
|
+
import type { PluginOptions } from './step-types.js';
|
|
7
|
+
import { UniqueId } from '../core/id-generator.js';
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for PluginLookup construct
|
|
10
|
+
*/
|
|
11
|
+
export interface PluginLookupProps {
|
|
12
|
+
readonly organization: string;
|
|
13
|
+
readonly project: string;
|
|
14
|
+
readonly platformUrl: string;
|
|
15
|
+
readonly uniqueId: UniqueId;
|
|
16
|
+
/** Organization ID for resolving per-org secrets from Secrets Manager */
|
|
17
|
+
readonly orgId?: string;
|
|
18
|
+
readonly runtime?: Runtime;
|
|
19
|
+
/** Lambda timeout (default: 30s) */
|
|
20
|
+
readonly timeout?: Duration;
|
|
21
|
+
/** Lambda memory in MB (default: 512) */
|
|
22
|
+
readonly memorySize?: number;
|
|
23
|
+
/** Log retention (default: ONE_WEEK) */
|
|
24
|
+
readonly logRetention?: RetentionDays;
|
|
25
|
+
/** Reserved concurrent executions for the lookup Lambda (default: 30) */
|
|
26
|
+
readonly reservedConcurrentExecutions?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Plugins pre-resolved by `pipeline-manager pipeline synth` from the platform API.
|
|
29
|
+
* Keyed by `alias || name` (matches the construct's normalize() output).
|
|
30
|
+
* When a lookup hits this map, `plugin()` returns the resolved Plugin
|
|
31
|
+
* directly — no custom resource is created. This is what makes the
|
|
32
|
+
* name, version, commands, env, etc. available at synth time so the resulting
|
|
33
|
+
* CFN template ships with the real values baked in.
|
|
34
|
+
*/
|
|
35
|
+
readonly resolvedPlugins?: Record<string, Plugin>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* CDK Construct responsible for looking up plugin configurations from an external platform
|
|
39
|
+
* using AWS CloudFormation Custom Resources backed by a Lambda function.
|
|
40
|
+
*
|
|
41
|
+
* This construct creates:
|
|
42
|
+
* - A Lambda function (plugin-lookup-handler) that fetches plugin configs
|
|
43
|
+
* - A CloudWatch Log Group for the Lambda
|
|
44
|
+
* - A Custom Resource Provider that invokes the Lambda
|
|
45
|
+
* - An IAM policy granting the Lambda access to the credentials secret
|
|
46
|
+
*
|
|
47
|
+
* ## Prerequisites
|
|
48
|
+
*
|
|
49
|
+
* Before deploying, store a JWT token in Secrets Manager:
|
|
50
|
+
* ```sh
|
|
51
|
+
* pipeline-manager infra store-token --days 30 --region <region>
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* The Lambda resolves the secret by name at runtime:
|
|
55
|
+
* `{SECRETS_PATH_PREFIX}/{orgId}/platform`
|
|
56
|
+
*
|
|
57
|
+
* @see handlers/plugin-lookup-handler.ts for the Lambda implementation
|
|
58
|
+
*/
|
|
59
|
+
export declare class PluginLookup extends Construct {
|
|
60
|
+
private readonly _uniqueId;
|
|
61
|
+
private readonly _provider;
|
|
62
|
+
private readonly _platformUrl;
|
|
63
|
+
private readonly _runtime;
|
|
64
|
+
private readonly _timeout;
|
|
65
|
+
private readonly _memorySize;
|
|
66
|
+
private readonly _reservedConcurrentExecutions?;
|
|
67
|
+
private readonly _orgId?;
|
|
68
|
+
private readonly _resolvedPlugins?;
|
|
69
|
+
constructor(scope: Construct, id: string, props: PluginLookupProps);
|
|
70
|
+
/**
|
|
71
|
+
* Looks up and resolves plugin configuration using either a simple name or full PluginOptions object
|
|
72
|
+
* During synthesis, if the value is unresolved (token), returns fallback plugin
|
|
73
|
+
* During deployment, attempts to parse the actual value returned by the custom resource
|
|
74
|
+
* @param plugin - Plugin name (string) or complete PluginOptions configuration
|
|
75
|
+
* @returns Resolved Plugin object or fallback default configuration
|
|
76
|
+
*/
|
|
77
|
+
plugin(plugin: string | PluginOptions): Plugin;
|
|
78
|
+
/**
|
|
79
|
+
* Creates the Lambda function that serves as the event handler for the custom resource provider.
|
|
80
|
+
*
|
|
81
|
+
* JWT token is stored in a pre-existing Secrets Manager secret at
|
|
82
|
+
* `{SECRETS_PATH_PREFIX}/{orgId}/platform`. The Lambda resolves the
|
|
83
|
+
* secret by name at runtime using `CoreConstants.SECRETS_PATH_PREFIX`.
|
|
84
|
+
*
|
|
85
|
+
* Create the secret before deploying with:
|
|
86
|
+
* pipeline-manager infra store-token --days 30 --region <region>
|
|
87
|
+
*/
|
|
88
|
+
private createLambdaFunction;
|
|
89
|
+
/**
|
|
90
|
+
* Build the default plugin filter.
|
|
91
|
+
* Access control (orgId scoping, public/private visibility) is handled by
|
|
92
|
+
* the platform's access control query builder based on the JWT's organizationId.
|
|
93
|
+
*/
|
|
94
|
+
private defaultFilter;
|
|
95
|
+
private normalize;
|
|
96
|
+
/**
|
|
97
|
+
* Creates a CustomResource instance that triggers plugin lookup during deployment
|
|
98
|
+
*/
|
|
99
|
+
private createCustomResource;
|
|
100
|
+
/** Base plugin shape with no-op defaults for fields CDK doesn't use. */
|
|
101
|
+
private static basePlugin;
|
|
102
|
+
/**
|
|
103
|
+
* Fallback for a plugin whose lookup returned no record (not in the platform
|
|
104
|
+
* catalog for this org) and so could not be pre-resolved at synth.
|
|
105
|
+
*
|
|
106
|
+
* This step FAILS the build (exit 1) on purpose. The previous behaviour —
|
|
107
|
+
* `echo "…" && exit 0` — was a false positive: an unresolved security/quality
|
|
108
|
+
* step (dependency-check, semgrep, spotbugs, …) reported the stage green while
|
|
109
|
+
* running nothing, giving false assurance that scans/builds had passed. A
|
|
110
|
+
* plugin step that can't run its plugin must go red, consistent with
|
|
111
|
+
* `basePlugin().failureBehavior === 'fail'`. The message is actionable so the
|
|
112
|
+
* operator knows the catalog is empty/incomplete, not that the tool crashed.
|
|
113
|
+
*/
|
|
114
|
+
private fallback;
|
|
115
|
+
/**
|
|
116
|
+
* Synth plugin with pipeline-manager commands. Cold-start bootstrap for
|
|
117
|
+
* the synth step when pre-resolution by `pipeline-manager pipeline synth/deploy`
|
|
118
|
+
* didn't populate `resolvedPlugins` for the synth plugin. Runs on the
|
|
119
|
+
* configured `CODEBUILD_DEFAULT_IMAGE` (default `pipeline-bootstrap:1.0`)
|
|
120
|
+
* and self-bootstraps the real synth via
|
|
121
|
+
* `pipeline-manager pipeline synth --id ${PIPELINE_ID}`.
|
|
122
|
+
*
|
|
123
|
+
* No `installCommands`: the default image already has `pipeline-manager`
|
|
124
|
+
* baked in (that's the whole point of `pipeline-bootstrap:1.0`). If the
|
|
125
|
+
* operator points CODEBUILD_DEFAULT_IMAGE at an image lacking it (e.g.
|
|
126
|
+
* vanilla aws/codebuild/standard:7.0), this step exits 127 — fix that
|
|
127
|
+
* by using an image with pipeline-manager rather than papering over it
|
|
128
|
+
* with a per-build `npm install -g`.
|
|
129
|
+
*/
|
|
130
|
+
bootstrap(): Plugin;
|
|
131
|
+
}
|