@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,316 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { createLogger, SYSTEM_ORG_ID } from '@pipeline-builder/api-core';
|
|
6
|
+
import { CustomResource, Token, Duration } from 'aws-cdk-lib';
|
|
7
|
+
import { PolicyStatement, Effect } from 'aws-cdk-lib/aws-iam';
|
|
8
|
+
import { Runtime, Architecture } from 'aws-cdk-lib/aws-lambda';
|
|
9
|
+
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
|
|
10
|
+
import { LogGroup, RetentionDays } from 'aws-cdk-lib/aws-logs';
|
|
11
|
+
import { Provider } from 'aws-cdk-lib/custom-resources';
|
|
12
|
+
import { Construct } from 'constructs';
|
|
13
|
+
import { Config, CoreConstants } from '../config/app-config.js';
|
|
14
|
+
import { UniqueId } from '../core/id-generator.js';
|
|
15
|
+
const log = createLogger('plugin-lookup');
|
|
16
|
+
// ESM-safe module directory (the package is `type: module`; `__dirname` is
|
|
17
|
+
// not defined under ES modules).
|
|
18
|
+
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
/**
|
|
20
|
+
* CDK Construct responsible for looking up plugin configurations from an external platform
|
|
21
|
+
* using AWS CloudFormation Custom Resources backed by a Lambda function.
|
|
22
|
+
*
|
|
23
|
+
* This construct creates:
|
|
24
|
+
* - A Lambda function (plugin-lookup-handler) that fetches plugin configs
|
|
25
|
+
* - A CloudWatch Log Group for the Lambda
|
|
26
|
+
* - A Custom Resource Provider that invokes the Lambda
|
|
27
|
+
* - An IAM policy granting the Lambda access to the credentials secret
|
|
28
|
+
*
|
|
29
|
+
* ## Prerequisites
|
|
30
|
+
*
|
|
31
|
+
* Before deploying, store a JWT token in Secrets Manager:
|
|
32
|
+
* ```sh
|
|
33
|
+
* pipeline-manager infra store-token --days 30 --region <region>
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* The Lambda resolves the secret by name at runtime:
|
|
37
|
+
* `{SECRETS_PATH_PREFIX}/{orgId}/platform`
|
|
38
|
+
*
|
|
39
|
+
* @see handlers/plugin-lookup-handler.ts for the Lambda implementation
|
|
40
|
+
*/
|
|
41
|
+
export class PluginLookup extends Construct {
|
|
42
|
+
_uniqueId;
|
|
43
|
+
_provider;
|
|
44
|
+
_platformUrl;
|
|
45
|
+
_runtime;
|
|
46
|
+
_timeout;
|
|
47
|
+
_memorySize;
|
|
48
|
+
_reservedConcurrentExecutions;
|
|
49
|
+
_orgId;
|
|
50
|
+
_resolvedPlugins;
|
|
51
|
+
constructor(scope, id, props) {
|
|
52
|
+
super(scope, id);
|
|
53
|
+
if (!props.organization || !props.project) {
|
|
54
|
+
throw new Error('Both organization and project are required.');
|
|
55
|
+
}
|
|
56
|
+
this._uniqueId = props.uniqueId;
|
|
57
|
+
this._platformUrl = props.platformUrl;
|
|
58
|
+
this._orgId = props.orgId;
|
|
59
|
+
this._runtime = props.runtime ?? Runtime.NODEJS_24_X;
|
|
60
|
+
this._timeout = props.timeout ?? Duration.seconds(30);
|
|
61
|
+
this._memorySize = props.memorySize ?? Config.get('aws').lambda.memorySize;
|
|
62
|
+
this._reservedConcurrentExecutions = props.reservedConcurrentExecutions;
|
|
63
|
+
this._resolvedPlugins = props.resolvedPlugins;
|
|
64
|
+
const onEventHandler = this.createLambdaFunction();
|
|
65
|
+
// Log-group strategy:
|
|
66
|
+
// Previous code created an `AWS::Logs::LogGroup` resource with an
|
|
67
|
+
// EXPLICIT name (`/aws/lambda/plugin-lookup-N`). That breaks every
|
|
68
|
+
// re-deploy after a rolled-back stack: AWS auto-creates the group on
|
|
69
|
+
// first Lambda invocation, the rollback leaves it as an orphan, and
|
|
70
|
+
// the next CDK run fails with "Resource ... already exists" because
|
|
71
|
+
// the explicit name collides with the orphan.
|
|
72
|
+
//
|
|
73
|
+
// Fix: use `LogGroup.fromLogGroupName()` to adopt-or-pass-through.
|
|
74
|
+
// If the group exists, CDK references it without trying to recreate.
|
|
75
|
+
// If it doesn't, AWS Lambda auto-creates it on first invocation.
|
|
76
|
+
// Retention is then set via a separate retention-policy custom
|
|
77
|
+
// resource which is idempotent (safe to apply to existing groups).
|
|
78
|
+
const logGroupName = `/aws/lambda/${this._uniqueId.generate('plugin:lookup').replace(/:/g, '-')}`;
|
|
79
|
+
const logGroup = LogGroup.fromLogGroupName(this, this._uniqueId.generate('log:group'), logGroupName);
|
|
80
|
+
this._provider = new Provider(this, this._uniqueId.generate('resource:provider'), {
|
|
81
|
+
onEventHandler,
|
|
82
|
+
logGroup,
|
|
83
|
+
});
|
|
84
|
+
log.debug(`PluginLookup initialized for ${props.organization}/${props.project}`);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Looks up and resolves plugin configuration using either a simple name or full PluginOptions object
|
|
88
|
+
* During synthesis, if the value is unresolved (token), returns fallback plugin
|
|
89
|
+
* During deployment, attempts to parse the actual value returned by the custom resource
|
|
90
|
+
* @param plugin - Plugin name (string) or complete PluginOptions configuration
|
|
91
|
+
* @returns Resolved Plugin object or fallback default configuration
|
|
92
|
+
*/
|
|
93
|
+
plugin(plugin) {
|
|
94
|
+
const props = this.normalize(plugin);
|
|
95
|
+
// Pre-resolved by `pipeline-manager pipeline synth` from the platform API.
|
|
96
|
+
// Skip the custom resource entirely — we already know the plugin's
|
|
97
|
+
// name, version, commands, env, etc. at synth time, so the resulting CFN
|
|
98
|
+
// template can ship with the real CodeBuild image baked in.
|
|
99
|
+
const cacheKey = props.alias || props.name;
|
|
100
|
+
const preResolved = this._resolvedPlugins?.[cacheKey];
|
|
101
|
+
if (preResolved) {
|
|
102
|
+
log.debug(`Plugin "${props.name}" pre-resolved (alias=${cacheKey}) — skipping custom resource`);
|
|
103
|
+
return preResolved;
|
|
104
|
+
}
|
|
105
|
+
const custom = this.createCustomResource(props);
|
|
106
|
+
const encoded = custom.getAttString('ResultValue');
|
|
107
|
+
if (Token.isUnresolved(encoded)) {
|
|
108
|
+
log.debug(`Plugin "${props.name}" value is unresolved (token) during synthesis — using fallback. The actual plugin will be resolved at deployment time.`);
|
|
109
|
+
return this.fallback();
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const decoded = Buffer.from(encoded, 'base64').toString('utf-8');
|
|
113
|
+
const data = JSON.parse(decoded);
|
|
114
|
+
if (!data || typeof data !== 'object' || !data.name || !Array.isArray(data.commands)) {
|
|
115
|
+
throw new Error('Invalid plugin response: missing required fields (name, commands)');
|
|
116
|
+
}
|
|
117
|
+
return data;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
121
|
+
throw new Error(`Failed to parse plugin "${props.name}" data: ${errorMsg}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Creates the Lambda function that serves as the event handler for the custom resource provider.
|
|
126
|
+
*
|
|
127
|
+
* JWT token is stored in a pre-existing Secrets Manager secret at
|
|
128
|
+
* `{SECRETS_PATH_PREFIX}/{orgId}/platform`. The Lambda resolves the
|
|
129
|
+
* secret by name at runtime using `CoreConstants.SECRETS_PATH_PREFIX`.
|
|
130
|
+
*
|
|
131
|
+
* Create the secret before deploying with:
|
|
132
|
+
* pipeline-manager infra store-token --days 30 --region <region>
|
|
133
|
+
*/
|
|
134
|
+
createLambdaFunction() {
|
|
135
|
+
if (!this._orgId) {
|
|
136
|
+
throw new Error('orgId is required for PluginLookup — needed to resolve the per-org platform secret');
|
|
137
|
+
}
|
|
138
|
+
const secretName = CoreConstants.secretPath(this._orgId, 'platform');
|
|
139
|
+
const fn = new NodejsFunction(this, this._uniqueId.generate('onevent:handler'), {
|
|
140
|
+
runtime: this._runtime,
|
|
141
|
+
timeout: this._timeout,
|
|
142
|
+
memorySize: this._memorySize,
|
|
143
|
+
architecture: Architecture.ARM_64,
|
|
144
|
+
entry: join(MODULE_DIR, '/../handlers/plugin-lookup-handler.js'),
|
|
145
|
+
depsLockFilePath: join(MODULE_DIR, '/../handlers/pnpm-lock.yaml'),
|
|
146
|
+
reservedConcurrentExecutions: this._reservedConcurrentExecutions,
|
|
147
|
+
environment: {
|
|
148
|
+
PLATFORM_SECRET_NAME: secretName,
|
|
149
|
+
// Allow self-signed certs when platform uses HTTPS without a CA-signed certificate
|
|
150
|
+
...(process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0' && {
|
|
151
|
+
NODE_TLS_REJECT_UNAUTHORIZED: '0',
|
|
152
|
+
}),
|
|
153
|
+
},
|
|
154
|
+
bundling: {
|
|
155
|
+
minify: true,
|
|
156
|
+
sourceMap: false,
|
|
157
|
+
target: 'es2022',
|
|
158
|
+
externalModules: [
|
|
159
|
+
// Provided by the Lambda Node.js runtime — never bundle.
|
|
160
|
+
'@aws-sdk/*',
|
|
161
|
+
// Synth-only libraries that must NEVER end up in a Lambda bundle.
|
|
162
|
+
// The handler doesn't use them; this is a guard so a stray transitive
|
|
163
|
+
// import (e.g. via a config module that pulls infrastructure-config →
|
|
164
|
+
// aws-cdk-lib) can't drag the entire ~hundreds-of-MB CDK into the
|
|
165
|
+
// bundle and OOM-kill esbuild during cold-start synth. If one of these
|
|
166
|
+
// is ever genuinely reached at runtime the Lambda will fail loudly at
|
|
167
|
+
// init (module not found) rather than silently OOM at synth — which is
|
|
168
|
+
// the correct signal, since CDK has no business running in this Lambda.
|
|
169
|
+
'aws-cdk-lib',
|
|
170
|
+
'aws-cdk-lib/*',
|
|
171
|
+
'constructs',
|
|
172
|
+
],
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
// Grant the Lambda permission to read the per-org platform secret.
|
|
176
|
+
// The wildcard suffix handles the 6-char random ID that Secrets Manager appends.
|
|
177
|
+
fn.addToRolePolicy(new PolicyStatement({
|
|
178
|
+
effect: Effect.ALLOW,
|
|
179
|
+
actions: ['secretsmanager:GetSecretValue'],
|
|
180
|
+
resources: [`arn:aws:secretsmanager:*:*:secret:${secretName}-*`],
|
|
181
|
+
}));
|
|
182
|
+
return fn;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Build the default plugin filter.
|
|
186
|
+
* Access control (orgId scoping, public/private visibility) is handled by
|
|
187
|
+
* the platform's access control query builder based on the JWT's organizationId.
|
|
188
|
+
*/
|
|
189
|
+
defaultFilter(name) {
|
|
190
|
+
return {
|
|
191
|
+
name,
|
|
192
|
+
isActive: true,
|
|
193
|
+
isDefault: true,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
normalize(plugin) {
|
|
197
|
+
if (typeof plugin === 'string') {
|
|
198
|
+
return {
|
|
199
|
+
name: plugin,
|
|
200
|
+
filter: this.defaultFilter(plugin),
|
|
201
|
+
alias: `${plugin}-alias`,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
name: plugin.name,
|
|
206
|
+
alias: plugin.alias ?? `${plugin.name}-alias`,
|
|
207
|
+
filter: plugin.filter ?? this.defaultFilter(plugin.name),
|
|
208
|
+
metadata: plugin.metadata,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Creates a CustomResource instance that triggers plugin lookup during deployment
|
|
213
|
+
*/
|
|
214
|
+
createCustomResource(props) {
|
|
215
|
+
const resourceId = this._uniqueId.generate(props.alias || props.name);
|
|
216
|
+
return new CustomResource(this, resourceId, {
|
|
217
|
+
serviceToken: this._provider.serviceToken,
|
|
218
|
+
resourceType: 'Custom::PluginLookup',
|
|
219
|
+
properties: {
|
|
220
|
+
baseURL: this._platformUrl,
|
|
221
|
+
pluginFilter: props.filter,
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/** Base plugin shape with no-op defaults for fields CDK doesn't use. */
|
|
226
|
+
static basePlugin() {
|
|
227
|
+
const now = new Date();
|
|
228
|
+
return {
|
|
229
|
+
id: '00000000-0000-0000-0000-000000000000',
|
|
230
|
+
orgId: SYSTEM_ORG_ID,
|
|
231
|
+
createdBy: 'system',
|
|
232
|
+
createdAt: now,
|
|
233
|
+
updatedBy: 'system',
|
|
234
|
+
updatedAt: now,
|
|
235
|
+
name: 'fallback',
|
|
236
|
+
description: null,
|
|
237
|
+
keywords: [],
|
|
238
|
+
category: 'unknown',
|
|
239
|
+
version: '1.0.0',
|
|
240
|
+
metadata: {},
|
|
241
|
+
pluginType: 'CodeBuildStep',
|
|
242
|
+
computeType: 'SMALL',
|
|
243
|
+
timeout: null,
|
|
244
|
+
failureBehavior: 'fail',
|
|
245
|
+
secrets: [],
|
|
246
|
+
primaryOutputDirectory: 'cdk.out',
|
|
247
|
+
env: {},
|
|
248
|
+
buildArgs: {},
|
|
249
|
+
installCommands: [],
|
|
250
|
+
commands: [],
|
|
251
|
+
dockerfile: null,
|
|
252
|
+
buildType: 'metadata_only',
|
|
253
|
+
ownerId: null,
|
|
254
|
+
ownerType: null,
|
|
255
|
+
lifecycle: 'production',
|
|
256
|
+
criticality: null,
|
|
257
|
+
labels: {},
|
|
258
|
+
links: [],
|
|
259
|
+
visibility: 'public',
|
|
260
|
+
isDefault: false,
|
|
261
|
+
isActive: true,
|
|
262
|
+
deletedAt: null,
|
|
263
|
+
deletedBy: null,
|
|
264
|
+
purgeAfter: null,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Fallback for a plugin whose lookup returned no record (not in the platform
|
|
269
|
+
* catalog for this org) and so could not be pre-resolved at synth.
|
|
270
|
+
*
|
|
271
|
+
* This step FAILS the build (exit 1) on purpose. The previous behaviour —
|
|
272
|
+
* `echo "…" && exit 0` — was a false positive: an unresolved security/quality
|
|
273
|
+
* step (dependency-check, semgrep, spotbugs, …) reported the stage green while
|
|
274
|
+
* running nothing, giving false assurance that scans/builds had passed. A
|
|
275
|
+
* plugin step that can't run its plugin must go red, consistent with
|
|
276
|
+
* `basePlugin().failureBehavior === 'fail'`. The message is actionable so the
|
|
277
|
+
* operator knows the catalog is empty/incomplete, not that the tool crashed.
|
|
278
|
+
*/
|
|
279
|
+
fallback() {
|
|
280
|
+
return {
|
|
281
|
+
...PluginLookup.basePlugin(),
|
|
282
|
+
commands: [
|
|
283
|
+
'echo "ERROR: plugin lookup returned no record — this plugin is not in the platform catalog for this org, so the step cannot run." >&2',
|
|
284
|
+
'echo "This step fails instead of passing as a no-op (an unresolved plugin reporting success would be a false-positive green)." >&2',
|
|
285
|
+
'echo "Fix: load the plugin into the platform (deploy/bin/load-plugins.sh), then re-run the pipeline." >&2',
|
|
286
|
+
'exit 1',
|
|
287
|
+
],
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Synth plugin with pipeline-manager commands. Cold-start bootstrap for
|
|
292
|
+
* the synth step when pre-resolution by `pipeline-manager pipeline synth/deploy`
|
|
293
|
+
* didn't populate `resolvedPlugins` for the synth plugin. Runs on the
|
|
294
|
+
* configured `CODEBUILD_DEFAULT_IMAGE` (default `pipeline-bootstrap:1.0`)
|
|
295
|
+
* and self-bootstraps the real synth via
|
|
296
|
+
* `pipeline-manager pipeline synth --id ${PIPELINE_ID}`.
|
|
297
|
+
*
|
|
298
|
+
* No `installCommands`: the default image already has `pipeline-manager`
|
|
299
|
+
* baked in (that's the whole point of `pipeline-bootstrap:1.0`). If the
|
|
300
|
+
* operator points CODEBUILD_DEFAULT_IMAGE at an image lacking it (e.g.
|
|
301
|
+
* vanilla aws/codebuild/standard:7.0), this step exits 127 — fix that
|
|
302
|
+
* by using an image with pipeline-manager rather than papering over it
|
|
303
|
+
* with a per-build `npm install -g`.
|
|
304
|
+
*/
|
|
305
|
+
bootstrap() {
|
|
306
|
+
return {
|
|
307
|
+
...PluginLookup.basePlugin(),
|
|
308
|
+
name: 'cdk-synth',
|
|
309
|
+
primaryOutputDirectory: 'cdk.out',
|
|
310
|
+
commands: [
|
|
311
|
+
'pipeline-manager pipeline synth --id ${PIPELINE_ID} --store-tokens --quiet --no-notices --no-verify-ssl',
|
|
312
|
+
],
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLWxvb2t1cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9waXBlbGluZS9wbHVnaW4tbG9va3VwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDckMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUNwQyxPQUFPLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRXpFLE9BQU8sRUFBRSxjQUFjLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzlELE9BQU8sRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDL0QsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQy9ELE9BQU8sRUFBRSxRQUFRLEVBQUUsYUFBYSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDL0QsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ3hELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFdkMsT0FBTyxFQUFFLE1BQU0sRUFBRSxhQUFhLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFbkQsTUFBTSxHQUFHLEdBQUcsWUFBWSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0FBRTFDLDJFQUEyRTtBQUMzRSxpQ0FBaUM7QUFDakMsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLGFBQWEsQ0FBQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBcUMzRDs7Ozs7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Q1AsU0FBUyxFQUFFLEVBQUU7WUFDYixlQUFlLEVBQUUsRUFBRTtZQUNuQixRQUFRLEVBQUUsRUFBRTtZQUNaLFVBQVUsRUFBRSxJQUFJO1lBQ2hCLFNBQVMsRUFBRSxlQUFlO1lBQzFCLE9BQU8sRUFBRSxJQUFJO1lBQ2IsU0FBUyxFQUFFLElBQUk7WUFDZixTQUFTLEVBQUUsWUFBWTtZQUN2QixXQUFXLEVBQUUsSUFBSTtZQUNqQixNQUFNLEVBQUUsRUFBRTtZQUNWLEtBQUssRUFBRSxFQUFFO1lBQ1QsVUFBVSxFQUFFLFFBQVE7WUFDcEIsU0FBUyxFQUFFLEtBQUs7WUFDaEIsUUFBUSxFQUFFLElBQUk7WUFDZCxTQUFTLEVBQUUsSUFBSTtZQUNmLFNBQVMsRUFBRSxJQUFJO1lBQ2YsVUFBVSxFQUFFLElBQUk7U0FDakIsQ0FBQztJQUNKLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7T0FXRztJQUNLLFFBQVE7UUFDZCxPQUFPO1lBQ0wsR0FBRyxZQUFZLENBQUMsVUFBVSxFQUFFO1lBQzVCLFFBQVEsRUFBRTtnQkFDUix1SUFBdUk7Z0JBQ3ZJLG9JQUFvSTtnQkFDcEksMkdBQTJHO2dCQUMzRyxRQUFRO2FBQ1Q7U0FDRixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7OztPQWNHO0lBQ0ksU0FBUztRQUNkLE9BQU87WUFDTCxHQUFHLFlBQVksQ0FBQyxVQUFVLEVBQUU7WUFDNUIsSUFBSSxFQUFFLFdBQVc7WUFDakIsc0JBQXNCLEVBQUUsU0FBUztZQUNqQyxRQUFRLEVBQUU7Z0JBQ1IseUdBQXlHO2FBQzFHO1NBQ0YsQ0FBQztJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBkaXJuYW1lLCBqb2luIH0gZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciwgU1lTVEVNX09SR19JRCB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB0eXBlIHsgUGx1Z2luRmlsdGVyLCBQbHVnaW4gfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9waXBlbGluZS1kYXRhJztcbmltcG9ydCB7IEN1c3RvbVJlc291cmNlLCBUb2tlbiwgRHVyYXRpb24gfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBQb2xpY3lTdGF0ZW1lbnQsIEVmZmVjdCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0IHsgUnVudGltZSwgQXJjaGl0ZWN0dXJlIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5pbXBvcnQgeyBOb2RlanNGdW5jdGlvbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEtbm9kZWpzJztcbmltcG9ydCB7IExvZ0dyb3VwLCBSZXRlbnRpb25EYXlzIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxvZ3MnO1xuaW1wb3J0IHsgUHJvdmlkZXIgfSBmcm9tICdhd3MtY2RrLWxpYi9jdXN0b20tcmVzb3VyY2VzJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHR5cGUgeyBQbHVnaW5PcHRpb25zIH0gZnJvbSAnLi9zdGVwLXR5cGVzLmpzJztcbmltcG9ydCB7IENvbmZpZywgQ29yZUNvbnN0YW50cyB9IGZyb20gJy4uL2NvbmZpZy9hcHAtY29uZmlnLmpzJztcbmltcG9ydCB7IFVuaXF1ZUlkIH0gZnJvbSAnLi4vY29yZS9pZC1nZW5lcmF0b3IuanMnO1xuXG5jb25zdCBsb2cgPSBjcmVhdGVMb2dnZXIoJ3BsdWdpbi1sb29rdXAnKTtcblxuLy8gRVNNLXNhZmUgbW9kdWxlIGRpcmVjdG9yeSAodGhlIHBhY2thZ2UgaXMgYHR5cGU6IG1vZHVsZWA7IGBfX2Rpcm5hbWVgIGlzXG4vLyBub3QgZGVmaW5lZCB1bmRlciBFUyBtb2R1bGVzKS5cbmNvbnN0IE1PRFVMRV9ESVIgPSBkaXJuYW1lKGZpbGVVUkxUb1BhdGgoaW1wb3J0Lm1ldGEudXJsKSk7XG5cbmludGVyZmFjZSBJbnB1dFByb3BzIHtcbiAgcmVhZG9ubHkgYmFzZVVSTDogc3RyaW5nO1xuICByZWFkb25seSBwbHVnaW5GaWx0ZXI6IFBsdWdpbkZpbHRlcjtcbn1cblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIGZvciBQbHVnaW5Mb29rdXAgY29uc3RydWN0XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGx1Z2luTG9va3VwUHJvcHMge1xuICByZWFkb25seSBvcmdhbml6YXRpb246IHN0cmluZztcbiAgcmVhZG9ubHkgcHJvamVjdDogc3RyaW5nO1xuICByZWFkb25seSBwbGF0Zm9ybVVybDogc3RyaW5nO1xuICByZWFkb25seSB1bmlxdWVJZDogVW5pcXVlSWQ7XG4gIC8qKiBPcmdhbml6YXRpb24gSUQgZm9yIHJlc29sdmluZyBwZXItb3JnIHNlY3JldHMgZnJvbSBTZWNyZXRzIE1hbmFnZXIgKi9cbiAgcmVhZG9ubHkgb3JnSWQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJ1bnRpbWU/OiBSdW50aW1lO1xuICAvKiogTGFtYmRhIHRpbWVvdXQgKGRlZmF1bHQ6IDMwcykgKi9cbiAgcmVhZG9ubHkgdGltZW91dD86IER1cmF0aW9uO1xuICAvKiogTGFtYmRhIG1lbW9yeSBpbiBNQiAoZGVmYXVsdDogNTEyKSAqL1xuICByZWFkb25seSBtZW1vcnlTaXplPzogbnVtYmVyO1xuICAvKiogTG9nIHJldGVudGlvbiAoZGVmYXVsdDogT05FX1dFRUspICovXG4gIHJlYWRvbmx5IGxvZ1JldGVudGlvbj86IFJldGVudGlvbkRheXM7XG4gIC8qKiBSZXNlcnZlZCBjb25jdXJyZW50IGV4ZWN1dGlvbnMgZm9yIHRoZSBsb29rdXAgTGFtYmRhIChkZWZhdWx0OiAzMCkgKi9cbiAgcmVhZG9ubHkgcmVzZXJ2ZWRDb25jdXJyZW50RXhlY3V0aW9ucz86IG51bWJlcjtcbiAgLyoqXG4gICAqIFBsdWdpbnMgcHJlLXJlc29sdmVkIGJ5IGBwaXBlbGluZS1tYW5hZ2VyIHBpcGVsaW5lIHN5bnRoYCBmcm9tIHRoZSBwbGF0Zm9ybSBBUEkuXG4gICAqIEtleWVkIGJ5IGBhbGlhcyB8fCBuYW1lYCAobWF0Y2hlcyB0aGUgY29uc3RydWN0J3Mgbm9ybWFsaXplKCkgb3V0cHV0KS5cbiAgICogV2hlbiBhIGxvb2t1cCBoaXRzIHRoaXMgbWFwLCBgcGx1Z2luKClgIHJldHVybnMgdGhlIHJlc29sdmVkIFBsdWdpblxuICAgKiBkaXJlY3RseSDigJQgbm8gY3VzdG9tIHJlc291cmNlIGlzIGNyZWF0ZWQuIFRoaXMgaXMgd2hhdCBtYWtlcyB0aGVcbiAgICogbmFtZSwgdmVyc2lvbiwgY29tbWFuZHMsIGVudiwgZXRjLiBhdmFpbGFibGUgYXQgc3ludGggdGltZSBzbyB0aGUgcmVzdWx0aW5nXG4gICAqIENGTiB0ZW1wbGF0ZSBzaGlwcyB3aXRoIHRoZSByZWFsIHZhbHVlcyBiYWtlZCBpbi5cbiAgICovXG4gIHJlYWRvbmx5IHJlc29sdmVkUGx1Z2lucz86IFJlY29yZDxzdHJpbmcsIFBsdWdpbj47XG59XG5cbi8qKlxuICogQ0RLIENvbnN0cnVjdCByZXNwb25zaWJsZSBmb3IgbG9va2luZyB1cCBwbHVnaW4gY29uZmlndXJhdGlvbnMgZnJvbSBhbiBleHRlcm5hbCBwbGF0Zm9ybVxuICogdXNpbmcgQVdTIENsb3VkRm9ybWF0aW9uIEN1c3RvbSBSZXNvdXJjZXMgYmFja2VkIGJ5IGEgTGFtYmRhIGZ1bmN0aW9uLlxuICpcbiAqIFRoaXMgY29uc3RydWN0IGNyZWF0ZXM6XG4gKiAtIEEgTGFtYmRhIGZ1bmN0aW9uIChwbHVnaW4tbG9va3VwLWhhbmRsZXIpIHRoYXQgZmV0Y2hlcyBwbHVnaW4gY29uZmlnc1xuICogLSBBIENsb3VkV2F0Y2ggTG9nIEdyb3VwIGZvciB0aGUgTGFtYmRhXG4gKiAtIEEgQ3VzdG9tIFJlc291cmNlIFByb3ZpZGVyIHRoYXQgaW52b2tlcyB0aGUgTGFtYmRhXG4gKiAtIEFuIElBTSBwb2xpY3kgZ3JhbnRpbmcgdGhlIExhbWJkYSBhY2Nlc3MgdG8gdGhlIGNyZWRlbnRpYWxzIHNlY3JldFxuICpcbiAqICMjIFByZXJlcXVpc2l0ZXNcbiAqXG4gKiBCZWZvcmUgZGVwbG95aW5nLCBzdG9yZSBhIEpXVCB0b2tlbiBpbiBTZWNyZXRzIE1hbmFnZXI6XG4gKiBgYGBzaFxuICogcGlwZWxpbmUtbWFuYWdlciBpbmZyYSBzdG9yZS10b2tlbiAtLWRheXMgMzAgLS1yZWdpb24gPHJlZ2lvbj5cbiAqIGBgYFxuICpcbiAqIFRoZSBMYW1iZGEgcmVzb2x2ZXMgdGhlIHNlY3JldCBieSBuYW1lIGF0IHJ1bnRpbWU6XG4gKiBge1NFQ1JFVFNfUEFUSF9QUkVGSVh9L3tvcmdJZH0vcGxhdGZvcm1gXG4gKlxuICogQHNlZSBoYW5kbGVycy9wbHVnaW4tbG9va3VwLWhhbmRsZXIudHMgZm9yIHRoZSBMYW1iZGEgaW1wbGVtZW50YXRpb25cbiAqL1xuZXhwb3J0IGNsYXNzIFBsdWdpbkxvb2t1cCBleHRlbmRzIENvbnN0cnVjdCB7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3VuaXF1ZUlkOiBVbmlxdWVJZDtcbiAgcHJpdmF0ZSByZWFkb25seSBfcHJvdmlkZXI6IFByb3ZpZGVyO1xuICBwcml2YXRlIHJlYWRvbmx5IF9wbGF0Zm9ybVVybDogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IF9ydW50aW1lOiBSdW50aW1lO1xuICBwcml2YXRlIHJlYWRvbmx5IF90aW1lb3V0OiBEdXJhdGlvbjtcbiAgcHJpdmF0ZSByZWFkb25seSBfbWVtb3J5U2l6ZTogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IF9yZXNlcnZlZENvbmN1cnJlbnRFeGVjdXRpb25zPzogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IF9vcmdJZD86IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSBfcmVzb2x2ZWRQbHVnaW5zPzogUmVjb3JkPHN0cmluZywgUGx1Z2luPjtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogUGx1Z2luTG9va3VwUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgaWYgKCFwcm9wcy5vcmdhbml6YXRpb24gfHwgIXByb3BzLnByb2plY3QpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQm90aCBvcmdhbml6YXRpb24gYW5kIHByb2plY3QgYXJlIHJlcXVpcmVkLicpO1xuICAgIH1cblxuICAgIHRoaXMuX3VuaXF1ZUlkID0gcHJvcHMudW5pcXVlSWQ7XG4gICAgdGhpcy5fcGxhdGZvcm1VcmwgPSBwcm9wcy5wbGF0Zm9ybVVybDtcbiAgICB0aGlzLl9vcmdJZCA9IHByb3BzLm9yZ0lkO1xuICAgIHRoaXMuX3J1bnRpbWUgPSBwcm9wcy5ydW50aW1lID8/IFJ1bnRpbWUuTk9ERUpTXzI0X1g7XG4gICAgdGhpcy5fdGltZW91dCA9IHByb3BzLnRpbWVvdXQgPz8gRHVyYXRpb24uc2Vjb25kcygzMCk7XG4gICAgdGhpcy5fbWVtb3J5U2l6ZSA9IHByb3BzLm1lbW9yeVNpemUgPz8gQ29uZmlnLmdldCgnYXdzJykubGFtYmRhLm1lbW9yeVNpemU7XG4gICAgdGhpcy5fcmVzZXJ2ZWRDb25jdXJyZW50RXhlY3V0aW9ucyA9IHByb3BzLnJlc2VydmVkQ29uY3VycmVudEV4ZWN1dGlvbnM7XG4gICAgdGhpcy5fcmVzb2x2ZWRQbHVnaW5zID0gcHJvcHMucmVzb2x2ZWRQbHVnaW5zO1xuXG4gICAgY29uc3Qgb25FdmVudEhhbmRsZXIgPSB0aGlzLmNyZWF0ZUxhbWJkYUZ1bmN0aW9uKCk7XG5cbiAgICAvLyBMb2ctZ3JvdXAgc3RyYXRlZ3k6XG4gICAgLy8gICBQcmV2aW91cyBjb2RlIGNyZWF0ZWQgYW4gYEFXUzo6TG9nczo6TG9nR3JvdXBgIHJlc291cmNlIHdpdGggYW5cbiAgICAvLyAgIEVYUExJQ0lUIG5hbWUgKGAvYXdzL2xhbWJkYS9wbHVnaW4tbG9va3VwLU5gKS4gVGhhdCBicmVha3MgZXZlcnlcbiAgICAvLyAgIHJlLWRlcGxveSBhZnRlciBhIHJvbGxlZC1iYWNrIHN0YWNrOiBBV1MgYXV0by1jcmVhdGVzIHRoZSBncm91cCBvblxuICAgIC8vICAgZmlyc3QgTGFtYmRhIGludm9jYXRpb24sIHRoZSByb2xsYmFjayBsZWF2ZXMgaXQgYXMgYW4gb3JwaGFuLCBhbmRcbiAgICAvLyAgIHRoZSBuZXh0IENESyBydW4gZmFpbHMgd2l0aCBcIlJlc291cmNlIC4uLiBhbHJlYWR5IGV4aXN0c1wiIGJlY2F1c2VcbiAgICAvLyAgIHRoZSBleHBsaWNpdCBuYW1lIGNvbGxpZGVzIHdpdGggdGhlIG9ycGhhbi5cbiAgICAvL1xuICAgIC8vICAgRml4OiB1c2UgYExvZ0dyb3VwLmZyb21Mb2dHcm91cE5hbWUoKWAgdG8gYWRvcHQtb3ItcGFzcy10aHJvdWdoLlxuICAgIC8vICAgSWYgdGhlIGdyb3VwIGV4aXN0cywgQ0RLIHJlZmVyZW5jZXMgaXQgd2l0aG91dCB0cnlpbmcgdG8gcmVjcmVhdGUuXG4gICAgLy8gICBJZiBpdCBkb2Vzbid0LCBBV1MgTGFtYmRhIGF1dG8tY3JlYXRlcyBpdCBvbiBmaXJzdCBpbnZvY2F0aW9uLlxuICAgIC8vICAgUmV0ZW50aW9uIGlzIHRoZW4gc2V0IHZpYSBhIHNlcGFyYXRlIHJldGVudGlvbi1wb2xpY3kgY3VzdG9tXG4gICAgLy8gICByZXNvdXJjZSB3aGljaCBpcyBpZGVtcG90ZW50IChzYWZlIHRvIGFwcGx5IHRvIGV4aXN0aW5nIGdyb3VwcykuXG4gICAgY29uc3QgbG9nR3JvdXBOYW1lID0gYC9hd3MvbGFtYmRhLyR7dGhpcy5fdW5pcXVlSWQuZ2VuZXJhdGUoJ3BsdWdpbjpsb29rdXAnKS5yZXBsYWNlKC86L2csICctJyl9YDtcbiAgICBjb25zdCBsb2dHcm91cCA9IExvZ0dyb3VwLmZyb21Mb2dHcm91cE5hbWUoXG4gICAgICB0aGlzLFxuICAgICAgdGhpcy5fdW5pcXVlSWQuZ2VuZXJhdGUoJ2xvZzpncm91cCcpLFxuICAgICAgbG9nR3JvdXBOYW1lLFxuICAgICk7XG5cbiAgICB0aGlzLl9wcm92aWRlciA9IG5ldyBQcm92aWRlcih0aGlzLCB0aGlzLl91bmlxdWVJZC5nZW5lcmF0ZSgncmVzb3VyY2U6cHJvdmlkZXInKSwge1xuICAgICAgb25FdmVudEhhbmRsZXIsXG4gICAgICBsb2dHcm91cCxcbiAgICB9KTtcblxuICAgIGxvZy5kZWJ1ZyhgUGx1Z2luTG9va3VwIGluaXRpYWxpemVkIGZvciAke3Byb3BzLm9yZ2FuaXphdGlvbn0vJHtwcm9wcy5wcm9qZWN0fWApO1xuICB9XG5cbiAgLyoqXG4gICAqIExvb2tzIHVwIGFuZCByZXNvbHZlcyBwbHVnaW4gY29uZmlndXJhdGlvbiB1c2luZyBlaXRoZXIgYSBzaW1wbGUgbmFtZSBvciBmdWxsIFBsdWdpbk9wdGlvbnMgb2JqZWN0XG4gICAqIER1cmluZyBzeW50aGVzaXMsIGlmIHRoZSB2YWx1ZSBpcyB1bnJlc29sdmVkICh0b2tlbiksIHJldHVybnMgZmFsbGJhY2sgcGx1Z2luXG4gICAqIER1cmluZyBkZXBsb3ltZW50LCBhdHRlbXB0cyB0byBwYXJzZSB0aGUgYWN0dWFsIHZhbHVlIHJldHVybmVkIGJ5IHRoZSBjdXN0b20gcmVzb3VyY2VcbiAgICogQHBhcmFtIHBsdWdpbiAtIFBsdWdpbiBuYW1lIChzdHJpbmcpIG9yIGNvbXBsZXRlIFBsdWdpbk9wdGlvbnMgY29uZmlndXJhdGlvblxuICAgKiBAcmV0dXJucyBSZXNvbHZlZCBQbHVnaW4gb2JqZWN0IG9yIGZhbGxiYWNrIGRlZmF1bHQgY29uZmlndXJhdGlvblxuICAgKi9cbiAgcHVibGljIHBsdWdpbihwbHVnaW46IHN0cmluZyB8IFBsdWdpbk9wdGlvbnMpOiBQbHVnaW4ge1xuICAgIGNvbnN0IHByb3BzID0gdGhpcy5ub3JtYWxpemUocGx1Z2luKTtcblxuICAgIC8vIFByZS1yZXNvbHZlZCBieSBgcGlwZWxpbmUtbWFuYWdlciBwaXBlbGluZSBzeW50aGAgZnJvbSB0aGUgcGxhdGZvcm0gQVBJLlxuICAgIC8vIFNraXAgdGhlIGN1c3RvbSByZXNvdXJjZSBlbnRpcmVseSDigJQgd2UgYWxyZWFkeSBrbm93IHRoZSBwbHVnaW4nc1xuICAgIC8vIG5hbWUsIHZlcnNpb24sIGNvbW1hbmRzLCBlbnYsIGV0Yy4gYXQgc3ludGggdGltZSwgc28gdGhlIHJlc3VsdGluZyBDRk5cbiAgICAvLyB0ZW1wbGF0ZSBjYW4gc2hpcCB3aXRoIHRoZSByZWFsIENvZGVCdWlsZCBpbWFnZSBiYWtlZCBpbi5cbiAgICBjb25zdCBjYWNoZUtleSA9IHByb3BzLmFsaWFzIHx8IHByb3BzLm5hbWU7XG4gICAgY29uc3QgcHJlUmVzb2x2ZWQgPSB0aGlzLl9yZXNvbHZlZFBsdWdpbnM/LltjYWNoZUtleV07XG4gICAgaWYgKHByZVJlc29sdmVkKSB7XG4gICAgICBsb2cuZGVidWcoYFBsdWdpbiBcIiR7cHJvcHMubmFtZX1cIiBwcmUtcmVzb2x2ZWQgKGFsaWFzPSR7Y2FjaGVLZXl9KSDigJQgc2tpcHBpbmcgY3VzdG9tIHJlc291cmNlYCk7XG4gICAgICByZXR1cm4gcHJlUmVzb2x2ZWQ7XG4gICAgfVxuXG4gICAgY29uc3QgY3VzdG9tID0gdGhpcy5jcmVhdGVDdXN0b21SZXNvdXJjZShwcm9wcyk7XG4gICAgY29uc3QgZW5jb2RlZCA9IGN1c3RvbS5nZXRBdHRTdHJpbmcoJ1Jlc3VsdFZhbHVlJyk7XG5cbiAgICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKGVuY29kZWQpKSB7XG4gICAgICBsb2cuZGVidWcoYFBsdWdpbiBcIiR7cHJvcHMubmFtZX1cIiB2YWx1ZSBpcyB1bnJlc29sdmVkICh0b2tlbikgZHVyaW5nIHN5bnRoZXNpcyDigJQgdXNpbmcgZmFsbGJhY2suIFRoZSBhY3R1YWwgcGx1Z2luIHdpbGwgYmUgcmVzb2x2ZWQgYXQgZGVwbG95bWVudCB0aW1lLmApO1xuICAgICAgcmV0dXJuIHRoaXMuZmFsbGJhY2soKTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgZGVjb2RlZCA9IEJ1ZmZlci5mcm9tKGVuY29kZWQsICdiYXNlNjQnKS50b1N0cmluZygndXRmLTgnKTtcbiAgICAgIGNvbnN0IGRhdGEgPSBKU09OLnBhcnNlKGRlY29kZWQpO1xuXG4gICAgICBpZiAoIWRhdGEgfHwgdHlwZW9mIGRhdGEgIT09ICdvYmplY3QnIHx8ICFkYXRhLm5hbWUgfHwgIUFycmF5LmlzQXJyYXkoZGF0YS5jb21tYW5kcykpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHBsdWdpbiByZXNwb25zZTogbWlzc2luZyByZXF1aXJlZCBmaWVsZHMgKG5hbWUsIGNvbW1hbmRzKScpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gZGF0YSBhcyBQbHVnaW47XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnN0IGVycm9yTXNnID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBlcnJvcic7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBwYXJzZSBwbHVnaW4gXCIke3Byb3BzLm5hbWV9XCIgZGF0YTogJHtlcnJvck1zZ31gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyB0aGUgTGFtYmRhIGZ1bmN0aW9uIHRoYXQgc2VydmVzIGFzIHRoZSBldmVudCBoYW5kbGVyIGZvciB0aGUgY3VzdG9tIHJlc291cmNlIHByb3ZpZGVyLlxuICAgKlxuICAgKiBKV1QgdG9rZW4gaXMgc3RvcmVkIGluIGEgcHJlLWV4aXN0aW5nIFNlY3JldHMgTWFuYWdlciBzZWNyZXQgYXRcbiAgICogYHtTRUNSRVRTX1BBVEhfUFJFRklYfS97b3JnSWR9L3BsYXRmb3JtYC4gVGhlIExhbWJkYSByZXNvbHZlcyB0aGVcbiAgICogc2VjcmV0IGJ5IG5hbWUgYXQgcnVudGltZSB1c2luZyBgQ29yZUNvbnN0YW50cy5TRUNSRVRTX1BBVEhfUFJFRklYYC5cbiAgICpcbiAgICogQ3JlYXRlIHRoZSBzZWNyZXQgYmVmb3JlIGRlcGxveWluZyB3aXRoOlxuICAgKiAgIHBpcGVsaW5lLW1hbmFnZXIgaW5mcmEgc3RvcmUtdG9rZW4gLS1kYXlzIDMwIC0tcmVnaW9uIDxyZWdpb24+XG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZUxhbWJkYUZ1bmN0aW9uKCk6IE5vZGVqc0Z1bmN0aW9uIHtcbiAgICBpZiAoIXRoaXMuX29yZ0lkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ29yZ0lkIGlzIHJlcXVpcmVkIGZvciBQbHVnaW5Mb29rdXAg4oCUIG5lZWRlZCB0byByZXNvbHZlIHRoZSBwZXItb3JnIHBsYXRmb3JtIHNlY3JldCcpO1xuICAgIH1cbiAgICBjb25zdCBzZWNyZXROYW1lID0gQ29yZUNvbnN0YW50cy5zZWNyZXRQYXRoKHRoaXMuX29yZ0lkLCAncGxhdGZvcm0nKTtcblxuICAgIGNvbnN0IGZuID0gbmV3IE5vZGVqc0Z1bmN0aW9uKHRoaXMsIHRoaXMuX3VuaXF1ZUlkLmdlbmVyYXRlKCdvbmV2ZW50OmhhbmRsZXInKSwge1xuICAgICAgcnVudGltZTogdGhpcy5fcnVudGltZSxcbiAgICAgIHRpbWVvdXQ6IHRoaXMuX3RpbWVvdXQsXG4gICAgICBtZW1vcnlTaXplOiB0aGlzLl9tZW1vcnlTaXplLFxuICAgICAgYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUuQVJNXzY0LFxuICAgICAgZW50cnk6IGpvaW4oTU9EVUxFX0RJUiwgJy8uLi9oYW5kbGVycy9wbHVnaW4tbG9va3VwLWhhbmRsZXIuanMnKSxcbiAgICAgIGRlcHNMb2NrRmlsZVBhdGg6IGpvaW4oTU9EVUxFX0RJUiwgJy8uLi9oYW5kbGVycy9wbnBtLWxvY2sueWFtbCcpLFxuICAgICAgcmVzZXJ2ZWRDb25jdXJyZW50RXhlY3V0aW9uczogdGhpcy5fcmVzZXJ2ZWRDb25jdXJyZW50RXhlY3V0aW9ucyxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIFBMQVRGT1JNX1NFQ1JFVF9OQU1FOiBzZWNyZXROYW1lLFxuICAgICAgICAvLyBBbGxvdyBzZWxmLXNpZ25lZCBjZXJ0cyB3aGVuIHBsYXRmb3JtIHVzZXMgSFRUUFMgd2l0aG91dCBhIENBLXNpZ25lZCBjZXJ0aWZpY2F0ZVxuICAgICAgICAuLi4ocHJvY2Vzcy5lbnYuTk9ERV9UTFNfUkVKRUNUX1VOQVVUSE9SSVpFRCA9PT0gJzAnICYmIHtcbiAgICAgICAgICBOT0RFX1RMU19SRUpFQ1RfVU5BVVRIT1JJWkVEOiAnMCcsXG4gICAgICAgIH0pLFxuICAgICAgfSxcbiAgICAgIGJ1bmRsaW5nOiB7XG4gICAgICAgIG1pbmlmeTogdHJ1ZSxcbiAgICAgICAgc291cmNlTWFwOiBmYWxzZSxcbiAgICAgICAgdGFyZ2V0OiAnZXMyMDIyJyxcbiAgICAgICAgZXh0ZXJuYWxNb2R1bGVzOiBbXG4gICAgICAgICAgLy8gUHJvdmlkZWQgYnkgdGhlIExhbWJkYSBOb2RlLmpzIHJ1bnRpbWUg4oCUIG5ldmVyIGJ1bmRsZS5cbiAgICAgICAgICAnQGF3cy1zZGsvKicsXG4gICAgICAgICAgLy8gU3ludGgtb25seSBsaWJyYXJpZXMgdGhhdCBtdXN0IE5FVkVSIGVuZCB1cCBpbiBhIExhbWJkYSBidW5kbGUuXG4gICAgICAgICAgLy8gVGhlIGhhbmRsZXIgZG9lc24ndCB1c2UgdGhlbTsgdGhpcyBpcyBhIGd1YXJkIHNvIGEgc3RyYXkgdHJhbnNpdGl2ZVxuICAgICAgICAgIC8vIGltcG9ydCAoZS5nLiB2aWEgYSBjb25maWcgbW9kdWxlIHRoYXQgcHVsbHMgaW5mcmFzdHJ1Y3R1cmUtY29uZmlnIOKGklxuICAgICAgICAgIC8vIGF3cy1jZGstbGliKSBjYW4ndCBkcmFnIHRoZSBlbnRpcmUgfmh1bmRyZWRzLW9mLU1CIENESyBpbnRvIHRoZVxuICAgICAgICAgIC8vIGJ1bmRsZSBhbmQgT09NLWtpbGwgZXNidWlsZCBkdXJpbmcgY29sZC1zdGFydCBzeW50aC4gSWYgb25lIG9mIHRoZXNlXG4gICAgICAgICAgLy8gaXMgZXZlciBnZW51aW5lbHkgcmVhY2hlZCBhdCBydW50aW1lIHRoZSBMYW1iZGEgd2lsbCBmYWlsIGxvdWRseSBhdFxuICAgICAgICAgIC8vIGluaXQgKG1vZHVsZSBub3QgZm91bmQpIHJhdGhlciB0aGFuIHNpbGVudGx5IE9PTSBhdCBzeW50aCDigJQgd2hpY2ggaXNcbiAgICAgICAgICAvLyB0aGUgY29ycmVjdCBzaWduYWwsIHNpbmNlIENESyBoYXMgbm8gYnVzaW5lc3MgcnVubmluZyBpbiB0aGlzIExhbWJkYS5cbiAgICAgICAgICAnYXdzLWNkay1saWInLFxuICAgICAgICAgICdhd3MtY2RrLWxpYi8qJyxcbiAgICAgICAgICAnY29uc3RydWN0cycsXG4gICAgICAgIF0sXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gR3JhbnQgdGhlIExhbWJkYSBwZXJtaXNzaW9uIHRvIHJlYWQgdGhlIHBlci1vcmcgcGxhdGZvcm0gc2VjcmV0LlxuICAgIC8vIFRoZSB3aWxkY2FyZCBzdWZmaXggaGFuZGxlcyB0aGUgNi1jaGFyIHJhbmRvbSBJRCB0aGF0IFNlY3JldHMgTWFuYWdlciBhcHBlbmRzLlxuICAgIGZuLmFkZFRvUm9sZVBvbGljeShuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgYWN0aW9uczogWydzZWNyZXRzbWFuYWdlcjpHZXRTZWNyZXRWYWx1ZSddLFxuICAgICAgcmVzb3VyY2VzOiBbYGFybjphd3M6c2VjcmV0c21hbmFnZXI6KjoqOnNlY3JldDoke3NlY3JldE5hbWV9LSpgXSxcbiAgICB9KSk7XG5cbiAgICByZXR1cm4gZm47XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgdGhlIGRlZmF1bHQgcGx1Z2luIGZpbHRlci5cbiAgICogQWNjZXNzIGNvbnRyb2wgKG9yZ0lkIHNjb3BpbmcsIHB1YmxpYy9wcml2YXRlIHZpc2liaWxpdHkpIGlzIGhhbmRsZWQgYnlcbiAgICogdGhlIHBsYXRmb3JtJ3MgYWNjZXNzIGNvbnRyb2wgcXVlcnkgYnVpbGRlciBiYXNlZCBvbiB0aGUgSldUJ3Mgb3JnYW5pemF0aW9uSWQuXG4gICAqL1xuICBwcml2YXRlIGRlZmF1bHRGaWx0ZXIobmFtZTogc3RyaW5nKTogUGx1Z2luRmlsdGVyIHtcbiAgICByZXR1cm4ge1xuICAgICAgbmFtZSxcbiAgICAgIGlzQWN0aXZlOiB0cnVlLFxuICAgICAgaXNEZWZhdWx0OiB0cnVlLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIG5vcm1hbGl6ZShwbHVnaW46IHN0cmluZyB8IFBsdWdpbk9wdGlvbnMpOiBQbHVnaW5PcHRpb25zIHtcbiAgICBpZiAodHlwZW9mIHBsdWdpbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG5hbWU6IHBsdWdpbixcbiAgICAgICAgZmlsdGVyOiB0aGlzLmRlZmF1bHRGaWx0ZXIocGx1Z2luKSxcbiAgICAgICAgYWxpYXM6IGAke3BsdWdpbn0tYWxpYXNgLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgbmFtZTogcGx1Z2luLm5hbWUsXG4gICAgICBhbGlhczogcGx1Z2luLmFsaWFzID8/IGAke3BsdWdpbi5uYW1lfS1hbGlhc2AsXG4gICAgICBmaWx0ZXI6IHBsdWdpbi5maWx0ZXIgPz8gdGhpcy5kZWZhdWx0RmlsdGVyKHBsdWdpbi5uYW1lKSxcbiAgICAgIG1ldGFkYXRhOiBwbHVnaW4ubWV0YWRhdGEsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgQ3VzdG9tUmVzb3VyY2UgaW5zdGFuY2UgdGhhdCB0cmlnZ2VycyBwbHVnaW4gbG9va3VwIGR1cmluZyBkZXBsb3ltZW50XG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZUN1c3RvbVJlc291cmNlKHByb3BzOiBQbHVnaW5PcHRpb25zKTogQ3VzdG9tUmVzb3VyY2Uge1xuICAgIGNvbnN0IHJlc291cmNlSWQgPSB0aGlzLl91bmlxdWVJZC5nZW5lcmF0ZShwcm9wcy5hbGlhcyB8fCBwcm9wcy5uYW1lKTtcblxuICAgIHJldHVybiBuZXcgQ3VzdG9tUmVzb3VyY2UodGhpcywgcmVzb3VyY2VJZCwge1xuICAgICAgc2VydmljZVRva2VuOiB0aGlzLl9wcm92aWRlci5zZXJ2aWNlVG9rZW4sXG4gICAgICByZXNvdXJjZVR5cGU6ICdDdXN0b206OlBsdWdpbkxvb2t1cCcsXG4gICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgIGJhc2VVUkw6IHRoaXMuX3BsYXRmb3JtVXJsLFxuICAgICAgICBwbHVnaW5GaWx0ZXI6IHByb3BzLmZpbHRlcixcbiAgICAgIH0gYXMgSW5wdXRQcm9wcyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBCYXNlIHBsdWdpbiBzaGFwZSB3aXRoIG5vLW9wIGRlZmF1bHRzIGZvciBmaWVsZHMgQ0RLIGRvZXNuJ3QgdXNlLiAqL1xuICBwcml2YXRlIHN0YXRpYyBiYXNlUGx1Z2luKCk6IFBsdWdpbiB7XG4gICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcbiAgICByZXR1cm4ge1xuICAgICAgaWQ6ICcwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAnLFxuICAgICAgb3JnSWQ6IFNZU1RFTV9PUkdfSUQsXG4gICAgICBjcmVhdGVkQnk6ICdzeXN0ZW0nLFxuICAgICAgY3JlYXRlZEF0OiBub3csXG4gICAgICB1cGRhdGVkQnk6ICdzeXN0ZW0nLFxuICAgICAgdXBkYXRlZEF0OiBub3csXG4gICAgICBuYW1lOiAnZmFsbGJhY2snLFxuICAgICAgZGVzY3JpcHRpb246IG51bGwsXG4gICAgICBrZXl3b3JkczogW10sXG4gICAgICBjYXRlZ29yeTogJ3Vua25vd24nLFxuICAgICAgdmVyc2lvbjogJzEuMC4wJyxcbiAgICAgIG1ldGFkYXRhOiB7fSxcbiAgICAgIHBsdWdpblR5cGU6ICdDb2RlQnVpbGRTdGVwJyxcbiAgICAgIGNvbXB1dGVUeXBlOiAnU01BTEwnLFxuICAgICAgdGltZW91dDogbnVsbCxcbiAgICAgIGZhaWx1cmVCZWhhdmlvcjogJ2ZhaWwnLFxuICAgICAgc2VjcmV0czogW10sXG4gICAgICBwcmltYXJ5T3V0cHV0RGlyZWN0b3J5OiAnY2RrLm91dCcsXG4gICAgICBlbnY6IHt9LFxuICAgICAgYnVpbGRBcmdzOiB7fSxcbiAgICAgIGluc3RhbGxDb21tYW5kczogW10sXG4gICAgICBjb21tYW5kczogW10sXG4gICAgICBkb2NrZXJmaWxlOiBudWxsLFxuICAgICAgYnVpbGRUeXBlOiAnbWV0YWRhdGFfb25seScsXG4gICAgICBvd25lcklkOiBudWxsLFxuICAgICAgb3duZXJUeXBlOiBudWxsLFxuICAgICAgbGlmZWN5Y2xlOiAncHJvZHVjdGlvbicsXG4gICAgICBjcml0aWNhbGl0eTogbnVsbCxcbiAgICAgIGxhYmVsczoge30sXG4gICAgICBsaW5rczogW10sXG4gICAgICB2aXNpYmlsaXR5OiAncHVibGljJyxcbiAgICAgIGlzRGVmYXVsdDogZmFsc2UsXG4gICAgICBpc0FjdGl2ZTogdHJ1ZSxcbiAgICAgIGRlbGV0ZWRBdDogbnVsbCxcbiAgICAgIGRlbGV0ZWRCeTogbnVsbCxcbiAgICAgIHB1cmdlQWZ0ZXI6IG51bGwsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGYWxsYmFjayBmb3IgYSBwbHVnaW4gd2hvc2UgbG9va3VwIHJldHVybmVkIG5vIHJlY29yZCAobm90IGluIHRoZSBwbGF0Zm9ybVxuICAgKiBjYXRhbG9nIGZvciB0aGlzIG9yZykgYW5kIHNvIGNvdWxkIG5vdCBiZSBwcmUtcmVzb2x2ZWQgYXQgc3ludGguXG4gICAqXG4gICAqIFRoaXMgc3RlcCBGQUlMUyB0aGUgYnVpbGQgKGV4aXQgMSkgb24gcHVycG9zZS4gVGhlIHByZXZpb3VzIGJlaGF2aW91ciDigJRcbiAgICogYGVjaG8gXCLigKZcIiAmJiBleGl0IDBgIOKAlCB3YXMgYSBmYWxzZSBwb3NpdGl2ZTogYW4gdW5yZXNvbHZlZCBzZWN1cml0eS9xdWFsaXR5XG4gICAqIHN0ZXAgKGRlcGVuZGVuY3ktY2hlY2ssIHNlbWdyZXAsIHNwb3RidWdzLCDigKYpIHJlcG9ydGVkIHRoZSBzdGFnZSBncmVlbiB3aGlsZVxuICAgKiBydW5uaW5nIG5vdGhpbmcsIGdpdmluZyBmYWxzZSBhc3N1cmFuY2UgdGhhdCBzY2Fucy9idWlsZHMgaGFkIHBhc3NlZC4gQVxuICAgKiBwbHVnaW4gc3RlcCB0aGF0IGNhbid0IHJ1biBpdHMgcGx1Z2luIG11c3QgZ28gcmVkLCBjb25zaXN0ZW50IHdpdGhcbiAgICogYGJhc2VQbHVnaW4oKS5mYWlsdXJlQmVoYXZpb3IgPT09ICdmYWlsJ2AuIFRoZSBtZXNzYWdlIGlzIGFjdGlvbmFibGUgc28gdGhlXG4gICAqIG9wZXJhdG9yIGtub3dzIHRoZSBjYXRhbG9nIGlzIGVtcHR5L2luY29tcGxldGUsIG5vdCB0aGF0IHRoZSB0b29sIGNyYXNoZWQuXG4gICAqL1xuICBwcml2YXRlIGZhbGxiYWNrKCk6IFBsdWdpbiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLlBsdWdpbkxvb2t1cC5iYXNlUGx1Z2luKCksXG4gICAgICBjb21tYW5kczogW1xuICAgICAgICAnZWNobyBcIkVSUk9SOiBwbHVnaW4gbG9va3VwIHJldHVybmVkIG5vIHJlY29yZCDigJQgdGhpcyBwbHVnaW4gaXMgbm90IGluIHRoZSBwbGF0Zm9ybSBjYXRhbG9nIGZvciB0aGlzIG9yZywgc28gdGhlIHN0ZXAgY2Fubm90IHJ1bi5cIiA+JjInLFxuICAgICAgICAnZWNobyBcIlRoaXMgc3RlcCBmYWlscyBpbnN0ZWFkIG9mIHBhc3NpbmcgYXMgYSBuby1vcCAoYW4gdW5yZXNvbHZlZCBwbHVnaW4gcmVwb3J0aW5nIHN1Y2Nlc3Mgd291bGQgYmUgYSBmYWxzZS1wb3NpdGl2ZSBncmVlbikuXCIgPiYyJyxcbiAgICAgICAgJ2VjaG8gXCJGaXg6IGxvYWQgdGhlIHBsdWdpbiBpbnRvIHRoZSBwbGF0Zm9ybSAoZGVwbG95L2Jpbi9sb2FkLXBsdWdpbnMuc2gpLCB0aGVuIHJlLXJ1biB0aGUgcGlwZWxpbmUuXCIgPiYyJyxcbiAgICAgICAgJ2V4aXQgMScsXG4gICAgICBdLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogU3ludGggcGx1Z2luIHdpdGggcGlwZWxpbmUtbWFuYWdlciBjb21tYW5kcy4gQ29sZC1zdGFydCBib290c3RyYXAgZm9yXG4gICAqIHRoZSBzeW50aCBzdGVwIHdoZW4gcHJlLXJlc29sdXRpb24gYnkgYHBpcGVsaW5lLW1hbmFnZXIgcGlwZWxpbmUgc3ludGgvZGVwbG95YFxuICAgKiBkaWRuJ3QgcG9wdWxhdGUgYHJlc29sdmVkUGx1Z2luc2AgZm9yIHRoZSBzeW50aCBwbHVnaW4uIFJ1bnMgb24gdGhlXG4gICAqIGNvbmZpZ3VyZWQgYENPREVCVUlMRF9ERUZBVUxUX0lNQUdFYCAoZGVmYXVsdCBgcGlwZWxpbmUtYm9vdHN0cmFwOjEuMGApXG4gICAqIGFuZCBzZWxmLWJvb3RzdHJhcHMgdGhlIHJlYWwgc3ludGggdmlhXG4gICAqIGBwaXBlbGluZS1tYW5hZ2VyIHBpcGVsaW5lIHN5bnRoIC0taWQgJHtQSVBFTElORV9JRH1gLlxuICAgKlxuICAgKiBObyBgaW5zdGFsbENvbW1hbmRzYDogdGhlIGRlZmF1bHQgaW1hZ2UgYWxyZWFkeSBoYXMgYHBpcGVsaW5lLW1hbmFnZXJgXG4gICAqIGJha2VkIGluICh0aGF0J3MgdGhlIHdob2xlIHBvaW50IG9mIGBwaXBlbGluZS1ib290c3RyYXA6MS4wYCkuIElmIHRoZVxuICAgKiBvcGVyYXRvciBwb2ludHMgQ09ERUJVSUxEX0RFRkFVTFRfSU1BR0UgYXQgYW4gaW1hZ2UgbGFja2luZyBpdCAoZS5nLlxuICAgKiB2YW5pbGxhIGF3cy9jb2RlYnVpbGQvc3RhbmRhcmQ6Ny4wKSwgdGhpcyBzdGVwIGV4aXRzIDEyNyDigJQgZml4IHRoYXRcbiAgICogYnkgdXNpbmcgYW4gaW1hZ2Ugd2l0aCBwaXBlbGluZS1tYW5hZ2VyIHJhdGhlciB0aGFuIHBhcGVyaW5nIG92ZXIgaXRcbiAgICogd2l0aCBhIHBlci1idWlsZCBgbnBtIGluc3RhbGwgLWdgLlxuICAgKi9cbiAgcHVibGljIGJvb3RzdHJhcCgpOiBQbHVnaW4ge1xuICAgIHJldHVybiB7XG4gICAgICAuLi5QbHVnaW5Mb29rdXAuYmFzZVBsdWdpbigpLFxuICAgICAgbmFtZTogJ2Nkay1zeW50aCcsXG4gICAgICBwcmltYXJ5T3V0cHV0RGlyZWN0b3J5OiAnY2RrLm91dCcsXG4gICAgICBjb21tYW5kczogW1xuICAgICAgICAncGlwZWxpbmUtbWFuYWdlciBwaXBlbGluZSBzeW50aCAtLWlkICR7UElQRUxJTkVfSUR9IC0tc3RvcmUtdG9rZW5zIC0tcXVpZXQgLS1uby1ub3RpY2VzIC0tbm8tdmVyaWZ5LXNzbCcsXG4gICAgICBdLFxuICAgIH07XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `PluginSpec` domain type — the shape of a plugin's declared contract as
|
|
3
|
+
* stored in the database and exchanged over the API.
|
|
4
|
+
*
|
|
5
|
+
* Kept in its own module, apart from the synth-time authoring types in
|
|
6
|
+
* `step-types.ts`, because those reference CDK types (`Construct`,
|
|
7
|
+
* `IFileSetProducer`, CodeBuild's `ComputeType`) while this one is pure data.
|
|
8
|
+
* API services consume `PluginSpec`; only the CDK entry point consumes the rest.
|
|
9
|
+
*/
|
|
10
|
+
import type { ComputeType, PluginType } from '../core/pipeline-types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Plugin spec defining plugin behavior and requirements.
|
|
13
|
+
* This is typically loaded from a plugin spec file (plugin-spec.yaml).
|
|
14
|
+
*/
|
|
15
|
+
export interface PluginSpec {
|
|
16
|
+
/**
|
|
17
|
+
* Unique identifier for the plugin
|
|
18
|
+
* @example 'nodejs-build'
|
|
19
|
+
*/
|
|
20
|
+
readonly name: string;
|
|
21
|
+
/**
|
|
22
|
+
* Human-readable description of what the plugin does
|
|
23
|
+
* @example 'Builds and tests Node.js applications'
|
|
24
|
+
*/
|
|
25
|
+
readonly description?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Keywords for plugin discovery and categorization
|
|
28
|
+
* @example ['nodejs', 'typescript', 'build', 'test']
|
|
29
|
+
*/
|
|
30
|
+
readonly keywords?: string[];
|
|
31
|
+
/**
|
|
32
|
+
* Plugin category for AI-assisted selection and organization.
|
|
33
|
+
* One of: language, security, quality, testing, deploy, artifact,
|
|
34
|
+
* infrastructure, monitoring, notification, ai
|
|
35
|
+
*/
|
|
36
|
+
readonly category?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Semantic version of the plugin
|
|
39
|
+
* @example '1.0.0'
|
|
40
|
+
*/
|
|
41
|
+
readonly version?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Type of pipeline step this plugin creates
|
|
44
|
+
* @default PluginType.CODE_BUILD_STEP
|
|
45
|
+
*/
|
|
46
|
+
readonly pluginType?: PluginType;
|
|
47
|
+
/**
|
|
48
|
+
* CodeBuild compute resource size to use
|
|
49
|
+
* @default ComputeType.SMALL
|
|
50
|
+
*/
|
|
51
|
+
readonly computeType?: ComputeType;
|
|
52
|
+
/**
|
|
53
|
+
* Maximum execution time in minutes.
|
|
54
|
+
* Used as fallback when the pipeline step doesn't set timeout.
|
|
55
|
+
* @default 60 (AWS CodeBuild default)
|
|
56
|
+
*/
|
|
57
|
+
readonly timeout?: number;
|
|
58
|
+
/**
|
|
59
|
+
* What happens when this step fails.
|
|
60
|
+
* - 'fail': Stop the pipeline (default)
|
|
61
|
+
* - 'warn': Log a warning and continue
|
|
62
|
+
* - 'ignore': Silently continue
|
|
63
|
+
* @default 'fail'
|
|
64
|
+
*/
|
|
65
|
+
readonly failureBehavior?: 'fail' | 'warn' | 'ignore';
|
|
66
|
+
/**
|
|
67
|
+
* Secret requirements for this plugin.
|
|
68
|
+
* Declares named secrets the plugin expects at build time.
|
|
69
|
+
*/
|
|
70
|
+
readonly secrets?: Array<{
|
|
71
|
+
name: string;
|
|
72
|
+
required: boolean;
|
|
73
|
+
description?: string;
|
|
74
|
+
}>;
|
|
75
|
+
/**
|
|
76
|
+
* Directory containing the primary build output artifacts
|
|
77
|
+
* @example 'dist'
|
|
78
|
+
*/
|
|
79
|
+
readonly primaryOutputDirectory?: string;
|
|
80
|
+
/**
|
|
81
|
+
* Additional metadata that can be accessed during plugin execution
|
|
82
|
+
* Keys should use the format 'aws:cdk:{namespace}:{key}' (all lowercase)
|
|
83
|
+
*/
|
|
84
|
+
readonly metadata?: Record<string, string | number | boolean>;
|
|
85
|
+
/**
|
|
86
|
+
* Path to Dockerfile or Dockerfile content
|
|
87
|
+
* Used to build the container environment for this plugin
|
|
88
|
+
*/
|
|
89
|
+
readonly dockerfile?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Commands to run during the install phase
|
|
92
|
+
* Typically used for installing dependencies
|
|
93
|
+
* @example ['npm ci', 'npm run build']
|
|
94
|
+
*/
|
|
95
|
+
readonly installCommands?: string[];
|
|
96
|
+
/**
|
|
97
|
+
* Commands to run during the build/execution phase
|
|
98
|
+
* These are the main commands that perform the plugin's work
|
|
99
|
+
* @example ['npm test', 'npm run deploy']
|
|
100
|
+
*/
|
|
101
|
+
readonly commands?: string[];
|
|
102
|
+
/**
|
|
103
|
+
* Environment variables to set in the build environment
|
|
104
|
+
* @example { API_URL: 'https://api.example.com', LOG_LEVEL: 'info' }
|
|
105
|
+
*/
|
|
106
|
+
readonly env?: Record<string, string>;
|
|
107
|
+
/**
|
|
108
|
+
* Docker build arguments passed via --build-arg at image build time.
|
|
109
|
+
* Used to parameterize Dockerfile ARG values when building the plugin image.
|
|
110
|
+
* @example { PYTHON_VERSION: '3.12', NODE_ENV: 'production' }
|
|
111
|
+
*/
|
|
112
|
+
readonly buildArgs?: Record<string, string>;
|
|
113
|
+
/**
|
|
114
|
+
* Pipeline metadata keys the plugin references via `{{ pipeline.metadata.X }}`.
|
|
115
|
+
* Declared as a contract — pipelines using this plugin must supply all
|
|
116
|
+
* listed keys unless the template uses `| default: '...'`.
|
|
117
|
+
* @example ['env', 'namespace', 'clusterName']
|
|
118
|
+
*/
|
|
119
|
+
readonly requiredMetadata?: string[];
|
|
120
|
+
/**
|
|
121
|
+
* Pipeline vars keys the plugin references via `{{ pipeline.vars.X }}`.
|
|
122
|
+
* @example ['branch', 'slackChannel']
|
|
123
|
+
*/
|
|
124
|
+
readonly requiredVars?: string[];
|
|
125
|
+
/**
|
|
126
|
+
* Optional type declarations for the metadata keys listed in `requiredMetadata`.
|
|
127
|
+
* Used at upload time to verify that coercion filters (`| number`, `| bool`,
|
|
128
|
+
* `| json`) match the declared type — e.g. `{{ pipeline.metadata.count | number }}`
|
|
129
|
+
* requires `count: 'number'` here, otherwise the plugin is rejected.
|
|
130
|
+
* Keys not declared default to `'string'`.
|
|
131
|
+
* @example { count: 'number', enabled: 'bool' }
|
|
132
|
+
*/
|
|
133
|
+
readonly metadataTypes?: Record<string, 'string' | 'number' | 'bool' | 'json'>;
|
|
134
|
+
/**
|
|
135
|
+
* Optional type declarations for vars keys (same semantics as `metadataTypes`).
|
|
136
|
+
*/
|
|
137
|
+
readonly varsTypes?: Record<string, 'string' | 'number' | 'bool' | 'json'>;
|
|
138
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
export {};
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLXNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcGlwZWxpbmUvcGx1Z2luLXNwZWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIFRoZSBgUGx1Z2luU3BlY2AgZG9tYWluIHR5cGUg4oCUIHRoZSBzaGFwZSBvZiBhIHBsdWdpbidzIGRlY2xhcmVkIGNvbnRyYWN0IGFzXG4gKiBzdG9yZWQgaW4gdGhlIGRhdGFiYXNlIGFuZCBleGNoYW5nZWQgb3ZlciB0aGUgQVBJLlxuICpcbiAqIEtlcHQgaW4gaXRzIG93biBtb2R1bGUsIGFwYXJ0IGZyb20gdGhlIHN5bnRoLXRpbWUgYXV0aG9yaW5nIHR5cGVzIGluXG4gKiBgc3RlcC10eXBlcy50c2AsIGJlY2F1c2UgdGhvc2UgcmVmZXJlbmNlIENESyB0eXBlcyAoYENvbnN0cnVjdGAsXG4gKiBgSUZpbGVTZXRQcm9kdWNlcmAsIENvZGVCdWlsZCdzIGBDb21wdXRlVHlwZWApIHdoaWxlIHRoaXMgb25lIGlzIHB1cmUgZGF0YS5cbiAqIEFQSSBzZXJ2aWNlcyBjb25zdW1lIGBQbHVnaW5TcGVjYDsgb25seSB0aGUgQ0RLIGVudHJ5IHBvaW50IGNvbnN1bWVzIHRoZSByZXN0LlxuICovXG5cbmltcG9ydCB0eXBlIHsgQ29tcHV0ZVR5cGUsIFBsdWdpblR5cGUgfSBmcm9tICcuLi9jb3JlL3BpcGVsaW5lLXR5cGVzLmpzJztcblxuLyoqXG4gKiBQbHVnaW4gc3BlYyBkZWZpbmluZyBwbHVnaW4gYmVoYXZpb3IgYW5kIHJlcXVpcmVtZW50cy5cbiAqIFRoaXMgaXMgdHlwaWNhbGx5IGxvYWRlZCBmcm9tIGEgcGx1Z2luIHNwZWMgZmlsZSAocGx1Z2luLXNwZWMueWFtbCkuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGx1Z2luU3BlYyB7XG4gIC8qKlxuICAgKiBVbmlxdWUgaWRlbnRpZmllciBmb3IgdGhlIHBsdWdpblxuICAgKiBAZXhhbXBsZSAnbm9kZWpzLWJ1aWxkJ1xuICAgKi9cbiAgcmVhZG9ubHkgbmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBIdW1hbi1yZWFkYWJsZSBkZXNjcmlwdGlvbiBvZiB3aGF0IHRoZSBwbHVnaW4gZG9lc1xuICAgKiBAZXhhbXBsZSAnQnVpbGRzIGFuZCB0ZXN0cyBOb2RlLmpzIGFwcGxpY2F0aW9ucydcbiAgICovXG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBLZXl3b3JkcyBmb3IgcGx1Z2luIGRpc2NvdmVyeSBhbmQgY2F0ZWdvcml6YXRpb25cbiAgICogQGV4YW1wbGUgWydub2RlanMnLCAndHlwZXNjcmlwdCcsICdidWlsZCcsICd0ZXN0J11cbiAgICovXG4gIHJlYWRvbmx5IGtleXdvcmRzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIFBsdWdpbiBjYXRlZ29yeSBmb3IgQUktYXNzaXN0ZWQgc2VsZWN0aW9uIGFuZCBvcmdhbml6YXRpb24uXG4gICAqIE9uZSBvZjogbGFuZ3VhZ2UsIHNlY3VyaXR5LCBxdWFsaXR5LCB0ZXN0aW5nLCBkZXBsb3ksIGFydGlmYWN0LFxuICAgKiAgICAgICAgIGluZnJhc3RydWN0dXJlLCBtb25pdG9yaW5nLCBub3RpZmljYXRpb24sIGFpXG4gICAqL1xuICByZWFkb25seSBjYXRlZ29yeT86IHN0cmluZztcblxuICAvKipcbiAgICogU2VtYW50aWMgdmVyc2lvbiBvZiB0aGUgcGx1Z2luXG4gICAqIEBleGFtcGxlICcxLjAuMCdcbiAgICovXG4gIHJlYWRvbmx5IHZlcnNpb24/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFR5cGUgb2YgcGlwZWxpbmUgc3RlcCB0aGlzIHBsdWdpbiBjcmVhdGVzXG4gICAqIEBkZWZhdWx0IFBsdWdpblR5cGUuQ09ERV9CVUlMRF9TVEVQXG4gICAqL1xuICByZWFkb25seSBwbHVnaW5UeXBlPzogUGx1Z2luVHlwZTtcblxuICAvKipcbiAgICogQ29kZUJ1aWxkIGNvbXB1dGUgcmVzb3VyY2Ugc2l6ZSB0byB1c2VcbiAgICogQGRlZmF1bHQgQ29tcHV0ZVR5cGUuU01BTExcbiAgICovXG4gIHJlYWRvbmx5IGNvbXB1dGVUeXBlPzogQ29tcHV0ZVR5cGU7XG5cbiAgLyoqXG4gICAqIE1heGltdW0gZXhlY3V0aW9uIHRpbWUgaW4gbWludXRlcy5cbiAgICogVXNlZCBhcyBmYWxsYmFjayB3aGVuIHRoZSBwaXBlbGluZSBzdGVwIGRvZXNuJ3Qgc2V0IHRpbWVvdXQuXG4gICAqIEBkZWZhdWx0IDYwIChBV1MgQ29kZUJ1aWxkIGRlZmF1bHQpXG4gICAqL1xuICByZWFkb25seSB0aW1lb3V0PzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBXaGF0IGhhcHBlbnMgd2hlbiB0aGlzIHN0ZXAgZmFpbHMuXG4gICAqIC0gJ2ZhaWwnOiBTdG9wIHRoZSBwaXBlbGluZSAoZGVmYXVsdClcbiAgICogLSAnd2Fybic6IExvZyBhIHdhcm5pbmcgYW5kIGNvbnRpbnVlXG4gICAqIC0gJ2lnbm9yZSc6IFNpbGVudGx5IGNvbnRpbnVlXG4gICAqIEBkZWZhdWx0ICdmYWlsJ1xuICAgKi9cbiAgcmVhZG9ubHkgZmFpbHVyZUJlaGF2aW9yPzogJ2ZhaWwnIHwgJ3dhcm4nIHwgJ2lnbm9yZSc7XG5cbiAgLyoqXG4gICAqIFNlY3JldCByZXF1aXJlbWVudHMgZm9yIHRoaXMgcGx1Z2luLlxuICAgKiBEZWNsYXJlcyBuYW1lZCBzZWNyZXRzIHRoZSBwbHVnaW4gZXhwZWN0cyBhdCBidWlsZCB0aW1lLlxuICAgKi9cbiAgcmVhZG9ubHkgc2VjcmV0cz86IEFycmF5PHsgbmFtZTogc3RyaW5nOyByZXF1aXJlZDogYm9vbGVhbjsgZGVzY3JpcHRpb24/OiBzdHJpbmcgfT47XG5cbiAgLyoqXG4gICAqIERpcmVjdG9yeSBjb250YWluaW5nIHRoZSBwcmltYXJ5IGJ1aWxkIG91dHB1dCBhcnRpZmFjdHNcbiAgICogQGV4YW1wbGUgJ2Rpc3QnXG4gICAqL1xuICByZWFkb25seSBwcmltYXJ5T3V0cHV0RGlyZWN0b3J5Pzogc3RyaW5nO1xuICAvKipcbiAgICogQWRkaXRpb25hbCBtZXRhZGF0YSB0aGF0IGNhbiBiZSBhY2Nlc3NlZCBkdXJpbmcgcGx1Z2luIGV4ZWN1dGlvblxuICAgKiBLZXlzIHNob3VsZCB1c2UgdGhlIGZvcm1hdCAnYXdzOmNkazp7bmFtZXNwYWNlfTp7a2V5fScgKGFsbCBsb3dlcmNhc2UpXG4gICAqL1xuICByZWFkb25seSBtZXRhZGF0YT86IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4+O1xuXG4gIC8qKlxuICAgKiBQYXRoIHRvIERvY2tlcmZpbGUgb3IgRG9ja2VyZmlsZSBjb250ZW50XG4gICAqIFVzZWQgdG8gYnVpbGQgdGhlIGNvbnRhaW5lciBlbnZpcm9ubWVudCBmb3IgdGhpcyBwbHVnaW5cbiAgICovXG4gIHJlYWRvbmx5IGRvY2tlcmZpbGU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIENvbW1hbmRzIHRvIHJ1biBkdXJpbmcgdGhlIGluc3RhbGwgcGhhc2VcbiAgICogVHlwaWNhbGx5IHVzZWQgZm9yIGluc3RhbGxpbmcgZGVwZW5kZW5jaWVzXG4gICAqIEBleGFtcGxlIFsnbnBtIGNpJywgJ25wbSBydW4gYnVpbGQnXVxuICAgKi9cbiAgcmVhZG9ubHkgaW5zdGFsbENvbW1hbmRzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIENvbW1hbmRzIHRvIHJ1biBkdXJpbmcgdGhlIGJ1aWxkL2V4ZWN1dGlvbiBwaGFzZVxuICAgKiBUaGVzZSBhcmUgdGhlIG1haW4gY29tbWFuZHMgdGhhdCBwZXJmb3JtIHRoZSBwbHVnaW4ncyB3b3JrXG4gICAqIEBleGFtcGxlIFsnbnBtIHRlc3QnLCAnbnBtIHJ1biBkZXBsb3knXVxuICAgKi9cbiAgcmVhZG9ubHkgY29tbWFuZHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogRW52aXJvbm1lbnQgdmFyaWFibGVzIHRvIHNldCBpbiB0aGUgYnVpbGQgZW52aXJvbm1lbnRcbiAgICogQGV4YW1wbGUgeyBBUElfVVJMOiAnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20nLCBMT0dfTEVWRUw6ICdpbmZvJyB9XG4gICAqL1xuICByZWFkb25seSBlbnY/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuXG4gIC8qKlxuICAgKiBEb2NrZXIgYnVpbGQgYXJndW1lbnRzIHBhc3NlZCB2aWEgLS1idWlsZC1hcmcgYXQgaW1hZ2UgYnVpbGQgdGltZS5cbiAgICogVXNlZCB0byBwYXJhbWV0ZXJpemUgRG9ja2VyZmlsZSBBUkcgdmFsdWVzIHdoZW4gYnVpbGRpbmcgdGhlIHBsdWdpbiBpbWFnZS5cbiAgICogQGV4YW1wbGUgeyBQWVRIT05fVkVSU0lPTjogJzMuMTInLCBOT0RFX0VOVjogJ3Byb2R1Y3Rpb24nIH1cbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkQXJncz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG5cbiAgLyoqXG4gICAqIFBpcGVsaW5lIG1ldGFkYXRhIGtleXMgdGhlIHBsdWdpbiByZWZlcmVuY2VzIHZpYSBge3sgcGlwZWxpbmUubWV0YWRhdGEuWCB9fWAuXG4gICAqIERlY2xhcmVkIGFzIGEgY29udHJhY3Qg4oCUIHBpcGVsaW5lcyB1c2luZyB0aGlzIHBsdWdpbiBtdXN0IHN1cHBseSBhbGxcbiAgICogbGlzdGVkIGtleXMgdW5sZXNzIHRoZSB0ZW1wbGF0ZSB1c2VzIGB8IGRlZmF1bHQ6ICcuLi4nYC5cbiAgICogQGV4YW1wbGUgWydlbnYnLCAnbmFtZXNwYWNlJywgJ2NsdXN0ZXJOYW1lJ11cbiAgICovXG4gIHJlYWRvbmx5IHJlcXVpcmVkTWV0YWRhdGE/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogUGlwZWxpbmUgdmFycyBrZXlzIHRoZSBwbHVnaW4gcmVmZXJlbmNlcyB2aWEgYHt7IHBpcGVsaW5lLnZhcnMuWCB9fWAuXG4gICAqIEBleGFtcGxlIFsnYnJhbmNoJywgJ3NsYWNrQ2hhbm5lbCddXG4gICAqL1xuICByZWFkb25seSByZXF1aXJlZFZhcnM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogT3B0aW9uYWwgdHlwZSBkZWNsYXJhdGlvbnMgZm9yIHRoZSBtZXRhZGF0YSBrZXlzIGxpc3RlZCBpbiBgcmVxdWlyZWRNZXRhZGF0YWAuXG4gICAqIFVzZWQgYXQgdXBsb2FkIHRpbWUgdG8gdmVyaWZ5IHRoYXQgY29lcmNpb24gZmlsdGVycyAoYHwgbnVtYmVyYCwgYHwgYm9vbGAsXG4gICAqIGB8IGpzb25gKSBtYXRjaCB0aGUgZGVjbGFyZWQgdHlwZSDigJQgZS5nLiBge3sgcGlwZWxpbmUubWV0YWRhdGEuY291bnQgfCBudW1iZXIgfX1gXG4gICAqIHJlcXVpcmVzIGBjb3VudDogJ251bWJlcidgIGhlcmUsIG90aGVyd2lzZSB0aGUgcGx1Z2luIGlzIHJlamVjdGVkLlxuICAgKiBLZXlzIG5vdCBkZWNsYXJlZCBkZWZhdWx0IHRvIGAnc3RyaW5nJ2AuXG4gICAqIEBleGFtcGxlIHsgY291bnQ6ICdudW1iZXInLCBlbmFibGVkOiAnYm9vbCcgfVxuICAgKi9cbiAgcmVhZG9ubHkgbWV0YWRhdGFUeXBlcz86IFJlY29yZDxzdHJpbmcsICdzdHJpbmcnIHwgJ251bWJlcicgfCAnYm9vbCcgfCAnanNvbic+O1xuXG4gIC8qKlxuICAgKiBPcHRpb25hbCB0eXBlIGRlY2xhcmF0aW9ucyBmb3IgdmFycyBrZXlzIChzYW1lIHNlbWFudGljcyBhcyBgbWV0YWRhdGFUeXBlc2ApLlxuICAgKi9cbiAgcmVhZG9ubHkgdmFyc1R5cGVzPzogUmVjb3JkPHN0cmluZywgJ3N0cmluZycgfCAnbnVtYmVyJyB8ICdib29sJyB8ICdqc29uJz47XG59XG4iXX0=
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { CodePipelineSource } from 'aws-cdk-lib/pipelines';
|
|
2
|
+
import { Construct } from 'constructs';
|
|
3
|
+
import type { PipelineConfiguration } from './pipeline-configuration.js';
|
|
4
|
+
import { UniqueId } from '../core/id-generator.js';
|
|
5
|
+
/**
|
|
6
|
+
* Creates the appropriate CodePipelineSource based on the pipeline configuration.
|
|
7
|
+
*
|
|
8
|
+
* Supports S3, GitHub, CodeStar connection, and CodeCommit sources.
|
|
9
|
+
*
|
|
10
|
+
* **Note on SCHEDULE triggers:** Scheduled pipelines require an EventBridge rule
|
|
11
|
+
* that starts the pipeline on a cron schedule. The source trigger is set to NONE
|
|
12
|
+
* (no polling/webhook). The EventBridge rule must be created separately as a
|
|
13
|
+
* pipeline-level construct, not at the source level. The `schedule` field on
|
|
14
|
+
* source options captures the cron expression for API/frontend use. The actual
|
|
15
|
+
* EventBridge rule creation is implemented in `PipelineBuilder` (the
|
|
16
|
+
* `ScheduleRule` `events.Rule` targeting the pipeline), not at the source level.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const sourceBuilder = new SourceBuilder(this, config);
|
|
21
|
+
* const source = sourceBuilder.create(uniqueId);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare class SourceBuilder {
|
|
25
|
+
private readonly scope;
|
|
26
|
+
private readonly config;
|
|
27
|
+
constructor(scope: Construct, config: PipelineConfiguration);
|
|
28
|
+
/**
|
|
29
|
+
* Creates the appropriate CodePipelineSource based on source type
|
|
30
|
+
*/
|
|
31
|
+
create(id: UniqueId): CodePipelineSource;
|
|
32
|
+
/**
|
|
33
|
+
* Creates an S3 source for the pipeline
|
|
34
|
+
*/
|
|
35
|
+
private createS3Source;
|
|
36
|
+
/**
|
|
37
|
+
* Creates a GitHub source for the pipeline
|
|
38
|
+
*/
|
|
39
|
+
private createGitHubSource;
|
|
40
|
+
/**
|
|
41
|
+
* Resolve the GitHub authentication token into a {@link SecretValue} without
|
|
42
|
+
* leaking the token value into the synthesized template.
|
|
43
|
+
*
|
|
44
|
+
* - `undefined` token → no authentication (CDK default).
|
|
45
|
+
* - A `SecretValue` → passed through (already a reference, never plaintext).
|
|
46
|
+
* - A Secrets Manager ARN or `secretsmanager:<name>` string → resolved via
|
|
47
|
+
* `SecretValue.secretsManager`, so only the reference lands in the template.
|
|
48
|
+
* - A genuine raw plaintext token → rejected by default (it would be baked as
|
|
49
|
+
* plaintext into CloudFormation/CDK context). Only when
|
|
50
|
+
* `allowPlainTextToken` is explicitly set is it embedded via
|
|
51
|
+
* `SecretValue.unsafePlainText`, and a loud warning is emitted.
|
|
52
|
+
*/
|
|
53
|
+
private resolveGitHubAuthentication;
|
|
54
|
+
/**
|
|
55
|
+
* Creates a CodeStar connection source for the pipeline
|
|
56
|
+
*/
|
|
57
|
+
private createCodeStarSource;
|
|
58
|
+
/**
|
|
59
|
+
* Creates a CodeCommit source for the pipeline
|
|
60
|
+
*/
|
|
61
|
+
private createCodeCommitSource;
|
|
62
|
+
}
|