@go-to-k/cdkd 0.290.48 → 0.291.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{asg-provider-CTrrSFjd.js → asg-provider-CZ5keDoC.js} +2 -2
- package/dist/{asg-provider-CTrrSFjd.js.map → asg-provider-CZ5keDoC.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-Defy0tTm.js → deploy-engine-9CxYEFh_.js} +519 -39
- package/dist/deploy-engine-9CxYEFh_.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{program-DZoyIJCj.js → program-Cs7N6T4j.js} +9 -7
- package/dist/{program-DZoyIJCj.js.map → program-Cs7N6T4j.js.map} +1 -1
- package/dist/{version-78yzIsS6.js → version-kDWCn_Jq.js} +2 -2
- package/dist/{version-78yzIsS6.js.map → version-kDWCn_Jq.js.map} +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-Defy0tTm.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { C as displayAwsMessage, D as truncateCodePoints, E as isPasteableIdent, S as UNRENDERABLE, T as displaySafe, d as applyDefaultNameForFallback, f as explicitNamePropertyFor, g as looksLikeCdkdGeneratedName, h as getCurrentStackName, m as generateResourceNameWithFallback, n as getLogger, p as generateResourceName, r as isStdoutReservedForPayload, s as getLiveRenderer, v as withStackName, w as displayIdent, x as STACK_REF_MAX_CODE_POINTS, y as withoutGeneratedFallbackName } from "./logger-GASr9bAF.js";
|
|
2
2
|
import { a as setAssumedRoleCredentials, i as getPreAssumeEnvCredentials, n as awsClientDefaults, o as setPreAssumeEnvCredentials, r as getAssumedRoleCredentials, t as SECOND_ROLE_PUBLISH_REFUSAL } from "./aws-client-defaults-BoIxyCir.js";
|
|
3
|
-
import { t as getCdkdVersion } from "./version-
|
|
3
|
+
import { t as getCdkdVersion } from "./version-kDWCn_Jq.js";
|
|
4
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
5
|
import { createHash, randomUUID } from "node:crypto";
|
|
6
6
|
import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetBucketReplicationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -35,6 +35,7 @@ import { GetHostedZoneCommand, ListHostedZonesByNameCommand, Route53Client } fro
|
|
|
35
35
|
import { DescribeListenersCommand, DescribeLoadBalancersCommand, ElasticLoadBalancingV2Client } from "@aws-sdk/client-elastic-load-balancing-v2";
|
|
36
36
|
import { KMSClient, ListAliasesCommand } from "@aws-sdk/client-kms";
|
|
37
37
|
import { readFile } from "fs/promises";
|
|
38
|
+
import { isAbsolute as isAbsolute$1, resolve as resolve$1 } from "path";
|
|
38
39
|
import { CreateRepositoryCommand, DescribeImagesCommand as DescribeImagesCommand$1, DescribeRepositoriesCommand, ECRClient, GetAuthorizationTokenCommand, PutImageTagMutabilityCommand } from "@aws-sdk/client-ecr";
|
|
39
40
|
import { inspect } from "node:util";
|
|
40
41
|
import { hostname } from "os";
|
|
@@ -3031,18 +3032,30 @@ function resolveAssemblyPath(dir, candidate, options) {
|
|
|
3031
3032
|
* empty `path.relative` means "names the directory rather than a file inside
|
|
3032
3033
|
* it". An asset path legitimately names a DIRECTORY, so a value equal to the
|
|
3033
3034
|
* bound is inside it and reporting it as outside would be a false statement.
|
|
3035
|
+
*
|
|
3036
|
+
* **The real-path walk runs on the ACCEPTING side too, not only to find a
|
|
3037
|
+
* symlink escape.** The two paths arrive here INDEPENDENTLY — the bound from
|
|
3038
|
+
* `-a` or the assembly's own `directoryName`, the target from the manifest —
|
|
3039
|
+
* so they can be two spellings of one directory (`/var/…` and `/private/var/…`
|
|
3040
|
+
* on macOS). `resolveAssemblyPath` never meets that, its candidate being built
|
|
3041
|
+
* by joining onto the base. Left alone it warned "outside the assembly" about
|
|
3042
|
+
* an ordinary `cdk synth --no-staging` asset, and a warning that cries wolf is
|
|
3043
|
+
* worse than none.
|
|
3034
3044
|
*/
|
|
3035
3045
|
function absoluteAssemblyPathEscape(bound, absolutePath) {
|
|
3036
3046
|
const resolvedBound = path.resolve(bound);
|
|
3037
3047
|
const target = path.resolve(absolutePath);
|
|
3038
|
-
if (!isInside(resolvedBound, target) && target !== resolvedBound) return {
|
|
3039
|
-
contained: false,
|
|
3040
|
-
escape: "lexical",
|
|
3041
|
-
path: target
|
|
3042
|
-
};
|
|
3043
3048
|
const realBound = resolveThroughLinks(resolvedBound);
|
|
3049
|
+
const realTarget = resolveThroughLinks(target);
|
|
3050
|
+
if (!isInside(resolvedBound, target) && target !== resolvedBound) {
|
|
3051
|
+
if (realBound === void 0 || realTarget === void 0 || !isInside(realBound, realTarget) && realTarget !== realBound) return {
|
|
3052
|
+
contained: false,
|
|
3053
|
+
escape: "lexical",
|
|
3054
|
+
path: target
|
|
3055
|
+
};
|
|
3056
|
+
return;
|
|
3057
|
+
}
|
|
3044
3058
|
if (realBound !== void 0) {
|
|
3045
|
-
const realTarget = resolveThroughLinks(target);
|
|
3046
3059
|
if (realTarget !== void 0 && !isInside(realBound, realTarget) && realTarget !== realBound) return {
|
|
3047
3060
|
contained: false,
|
|
3048
3061
|
escape: "symlink",
|
|
@@ -3052,6 +3065,65 @@ function absoluteAssemblyPathEscape(bound, absolutePath) {
|
|
|
3052
3065
|
}
|
|
3053
3066
|
}
|
|
3054
3067
|
/**
|
|
3068
|
+
* Whether `candidate` names the SAME DIRECTORY as `bound`, by any spelling.
|
|
3069
|
+
*
|
|
3070
|
+
* It lives here, beside {@link absoluteAssemblyPathEscape}, because it asks
|
|
3071
|
+
* that function's question one step further on and must use its machinery to
|
|
3072
|
+
* answer: `path.resolve` equality is a LEXICAL test, and the two paths reach a
|
|
3073
|
+
* caller independently — the bound from `-a` or the assembly's own
|
|
3074
|
+
* `directoryName`, the candidate from the manifest — so one directory has
|
|
3075
|
+
* several spellings. `/tmp/cdk.out` and `/private/tmp/cdk.out` on macOS;
|
|
3076
|
+
* `<cdk.out>/self` where `self` is a symlink to `cdk.out`; both at once.
|
|
3077
|
+
*
|
|
3078
|
+
* **A caller that re-spells this as `resolve(a) === resolve(b)` gets a test
|
|
3079
|
+
* that misses every spelling but one**, which is how
|
|
3080
|
+
* [#3532](https://github.com/go-to-k/cdkd/issues/3532)'s asset resolvers first
|
|
3081
|
+
* shipped their whole-assembly warning: `absoluteAssemblyPathEscape`
|
|
3082
|
+
* exonerates a second spelling of the bound as INSIDE — correctly — and the
|
|
3083
|
+
* lexical equality beside it then said "not the bound", so the one value
|
|
3084
|
+
* meaning "the entire assembly is this asset" passed both tests in silence.
|
|
3085
|
+
* Ask this instead; do not re-derive it.
|
|
3086
|
+
*
|
|
3087
|
+
* Conservative on failure: an unresolvable side answers from the lexical
|
|
3088
|
+
* comparison alone, so it can only ever say "not the same", never wrongly
|
|
3089
|
+
* claim identity.
|
|
3090
|
+
*/
|
|
3091
|
+
function namesTheSameDirectory(bound, candidate) {
|
|
3092
|
+
const resolvedBound = path.resolve(bound);
|
|
3093
|
+
const target = path.resolve(candidate);
|
|
3094
|
+
if (target === resolvedBound) return true;
|
|
3095
|
+
const realBound = resolveThroughLinks(resolvedBound);
|
|
3096
|
+
const realTarget = resolveThroughLinks(target);
|
|
3097
|
+
return realBound !== void 0 && realTarget !== void 0 && realBound === realTarget;
|
|
3098
|
+
}
|
|
3099
|
+
/**
|
|
3100
|
+
* The escape verdict for an assembly-supplied path WITHOUT throwing, taking
|
|
3101
|
+
* whichever arm the value's own shape calls for.
|
|
3102
|
+
*
|
|
3103
|
+
* `resolveAssemblyPath` answers for a RELATIVE value and
|
|
3104
|
+
* {@link absoluteAssemblyPathEscape} for an ABSOLUTE one, and a caller that
|
|
3105
|
+
* only wants to WARN would otherwise branch on `path.isAbsolute` and call
|
|
3106
|
+
* both itself. Three sites already do exactly that
|
|
3107
|
+
* ([#3532](https://github.com/go-to-k/cdkd/issues/3532)'s two asset resolvers,
|
|
3108
|
+
* which must also THROW and so keep their own spelling), and the fourth —
|
|
3109
|
+
* [#3497](https://github.com/go-to-k/cdkd/issues/3497)'s BuildKit
|
|
3110
|
+
* passthroughs — has nothing to throw and a dozen values to judge. This is the
|
|
3111
|
+
* one spelling for that case.
|
|
3112
|
+
*
|
|
3113
|
+
* `base` is what a relative value resolves against; `bound` is what the result
|
|
3114
|
+
* must stay inside. They differ for a Stage. Returns `undefined` when the
|
|
3115
|
+
* value is fine, including when it names `bound` itself, which
|
|
3116
|
+
* {@link namesTheSameDirectory} answers — an asset path legitimately names a
|
|
3117
|
+
* directory and a caller that WARNS has no reason to complain about the
|
|
3118
|
+
* assembly root.
|
|
3119
|
+
*/
|
|
3120
|
+
function assemblyPathEscape(base, bound, candidate) {
|
|
3121
|
+
if (path.isAbsolute(candidate)) return absoluteAssemblyPathEscape(bound, candidate);
|
|
3122
|
+
const resolved = resolveAssemblyPath(base, candidate, { containWithin: bound });
|
|
3123
|
+
if (resolved.contained || namesTheSameDirectory(bound, resolved.path)) return void 0;
|
|
3124
|
+
return resolved;
|
|
3125
|
+
}
|
|
3126
|
+
/**
|
|
3055
3127
|
* The shared tail of every containment refusal: what the value resolved to,
|
|
3056
3128
|
* what it escaped, and why that means the assembly is not CDK-generated. Each
|
|
3057
3129
|
* call site supplies its own subject ("Stack 'X' has templateFile='...' which
|
|
@@ -7020,6 +7092,36 @@ function setsEqual(a, b) {
|
|
|
7020
7092
|
return true;
|
|
7021
7093
|
}
|
|
7022
7094
|
|
|
7095
|
+
//#endregion
|
|
7096
|
+
//#region src/assets/absolute-asset-path-warning.ts
|
|
7097
|
+
/**
|
|
7098
|
+
* The one OTHER thing worth a line: the source resolves to the app's output
|
|
7099
|
+
* directory ITSELF, so the sink gets the whole assembly — every template and
|
|
7100
|
+
* every staged asset — rather than one asset directory.
|
|
7101
|
+
*
|
|
7102
|
+
* It is a WARNING and not a refusal for the same reason its sibling is, and it
|
|
7103
|
+
* must not be silent for a reason the sibling does not share: both resolvers
|
|
7104
|
+
* accept this value (issue
|
|
7105
|
+
* [#3532](https://github.com/go-to-k/cdkd/issues/3532)) because the absolute
|
|
7106
|
+
* arm treats the bound as inside and the two arms must agree, and because the
|
|
7107
|
+
* local twin legitimately bind-mounts a directory. But on THIS layer the sink
|
|
7108
|
+
* is an upload or an image build, so "package the whole output directory and
|
|
7109
|
+
* send it to a bucket this manifest named" is exactly the sentence a user
|
|
7110
|
+
* needs and exactly the one an accept-silently arm withholds. No real `cdk
|
|
7111
|
+
* synth` emits `source.path: "."`, so this costs a legitimate run nothing.
|
|
7112
|
+
*/
|
|
7113
|
+
function warnWholeAssemblyAsSource(w) {
|
|
7114
|
+
getLogger().child("assets").warn(`${w.subject} has ${w.field} naming the output directory ITSELF: '${displaySafe(w.outdir)}'. cdkd will ${w.sink} — that is the WHOLE assembly, every template and every staged asset, not one asset directory. No CDK synth emits this, so treat this assembly as untrusted unless you wrote that path yourself.`);
|
|
7115
|
+
}
|
|
7116
|
+
/**
|
|
7117
|
+
* Emit it. Deliberately `warn`, never `throw`: the one producer of this shape
|
|
7118
|
+
* is a real `cdk synth --no-staging`, and refusing rejects the output of a
|
|
7119
|
+
* documented CDK CLI flag.
|
|
7120
|
+
*/
|
|
7121
|
+
function warnAbsoluteAssetPath(w) {
|
|
7122
|
+
getLogger().child("assets").warn(`${w.subject} has an absolute ${w.field} pointing outside the assembly: '${displaySafe(w.absolute)}'` + (w.escape.escape === "symlink" ? ` (through a symbolic link to '${displaySafe(w.escape.realPath)}')` : "") + `. cdkd will ${w.sink}. This is what cdk synth --no-staging emits, and is expected for it; if you did not synthesize with that flag, treat this assembly as untrusted: an absolute source path is honoured as written, so nothing but this line stands between it and that step.`);
|
|
7123
|
+
}
|
|
7124
|
+
|
|
7023
7125
|
//#endregion
|
|
7024
7126
|
//#region src/assets/asset-manifest-loader.ts
|
|
7025
7127
|
/**
|
|
@@ -7034,9 +7136,80 @@ function setsEqual(a, b) {
|
|
|
7034
7136
|
* primitive with the caller's own credentials, which is the harm the manifest
|
|
7035
7137
|
* FILE's own containment check cites. One function so the loader and the
|
|
7036
7138
|
* publisher cannot disagree about which file is published.
|
|
7037
|
-
|
|
7038
|
-
|
|
7139
|
+
*
|
|
7140
|
+
* **An ABSOLUTE `source.path` is HONOURED, and warned about when it leaves
|
|
7141
|
+
* `assetOutdir`** (issue
|
|
7142
|
+
* [#3532](https://github.com/go-to-k/cdkd/issues/3532)). It used to be neither
|
|
7143
|
+
* honoured nor refused: `resolveAssemblyPath` joins with `path.join`, which
|
|
7144
|
+
* does not honour a leading separator, so an absolute value was folded INTO
|
|
7145
|
+
* the outdir, read as CONTAINED, and died later at `statSync` with an `ENOENT`
|
|
7146
|
+
* naming a path that exists nowhere and that the user never wrote. Three
|
|
7147
|
+
* things decide the arm:
|
|
7148
|
+
*
|
|
7149
|
+
* - `cdk synth --no-staging` emits exactly this shape. Under
|
|
7150
|
+
* `aws:cdk:disable-asset-staging` upstream `AssetStaging.relativeStagedPath`
|
|
7151
|
+
* returns the staged path verbatim, so every `files[*].source.path` is the
|
|
7152
|
+
* asset's absolute SOURCE directory, normally outside the outdir. Refusing it
|
|
7153
|
+
* rejects the output of a documented CDK CLI flag.
|
|
7154
|
+
* - Upstream `cdk deploy` resolves the field with `path.resolve(manifestDir,
|
|
7155
|
+
* p)`, which honours an absolute value and publishes it. Refusing here would
|
|
7156
|
+
* make cdkd diverge from the CLI it is meant to complement.
|
|
7157
|
+
* - So for an ABSOLUTE value the warning is the whole signal, and no
|
|
7158
|
+
* containment boundary is left.
|
|
7159
|
+
*
|
|
7160
|
+
* **State plainly what that gave up, because the first version of this comment
|
|
7161
|
+
* did not and was wrong.** It copied the local twin's line — "the relative arm
|
|
7162
|
+
* buys nothing against an adversary, who would write the absolute spelling" —
|
|
7163
|
+
* which is TRUE there and FALSE here, and the difference is the whole point.
|
|
7164
|
+
* `resolveAssetCodeDirectory` already honoured absolute paths before
|
|
7165
|
+
* [#3494](https://github.com/go-to-k/cdkd/issues/3494), so that change only
|
|
7166
|
+
* added a warning to an open door. HERE the door was SHUT: measured on
|
|
7167
|
+
* `path.resolve(path.join(base, c))`, `/Users/victim/.aws`, `/etc/passwd`,
|
|
7168
|
+
* `//etc/passwd` and `/etc/./passwd` all folded INSIDE the outdir and died at
|
|
7169
|
+
* `statSync`, `/../etc/passwd` was refused lexically, and a planted symlink
|
|
7170
|
+
* was refused by the symlink arm — so NO spelling reached an arbitrary host
|
|
7171
|
+
* file. Accidentally, but completely.
|
|
7172
|
+
*
|
|
7173
|
+
* What this opens, therefore, is real and new: a hand-written manifest can now
|
|
7174
|
+
* have any readable directory zipped to a bucket it names, with the operator's
|
|
7175
|
+
* credentials, gated only by the warning. It is accepted because upstream
|
|
7176
|
+
* `@aws-cdk/cdk-assets-lib` does the same with no containment at all
|
|
7177
|
+
* (`path.resolve(this.workDir, source.path)`, `private/handlers/files.js`), so
|
|
7178
|
+
* cdkd stays strictly MORE protective than the CLI it complements while still
|
|
7179
|
+
* running what `cdk synth --no-staging` emits. The relative arm still catches
|
|
7180
|
+
* an accidental or legacy `..` and costs nothing, which is why it stays — but
|
|
7181
|
+
* it is no longer a boundary against anyone who chose the value. The docs say
|
|
7182
|
+
* this to users in the same words; do not soften either copy.
|
|
7183
|
+
*/
|
|
7184
|
+
function resolveFileAssetSourcePath(manifestDir, asset, assetOutdir, sink) {
|
|
7185
|
+
if (isAbsolute$1(asset.source.path)) {
|
|
7186
|
+
const absolute = resolve$1(asset.source.path);
|
|
7187
|
+
const escape = absoluteAssemblyPathEscape(assetOutdir, absolute);
|
|
7188
|
+
if (escape !== void 0) warnAbsoluteAssetPath({
|
|
7189
|
+
subject: `File asset '${displaySafe(asset.displayName)}'`,
|
|
7190
|
+
field: "source.path",
|
|
7191
|
+
absolute,
|
|
7192
|
+
escape,
|
|
7193
|
+
sink
|
|
7194
|
+
});
|
|
7195
|
+
else if (namesTheSameDirectory(assetOutdir, absolute)) warnWholeAssemblyAsSource({
|
|
7196
|
+
subject: `File asset '${displaySafe(asset.displayName)}'`,
|
|
7197
|
+
field: "source.path",
|
|
7198
|
+
outdir: absolute,
|
|
7199
|
+
sink
|
|
7200
|
+
});
|
|
7201
|
+
return absolute;
|
|
7202
|
+
}
|
|
7039
7203
|
const resolved = resolveAssemblyPath(manifestDir, asset.source.path, { containWithin: assetOutdir });
|
|
7204
|
+
if (!resolved.contained && namesTheSameDirectory(assetOutdir, resolved.path)) {
|
|
7205
|
+
warnWholeAssemblyAsSource({
|
|
7206
|
+
subject: `File asset '${displaySafe(asset.displayName)}'`,
|
|
7207
|
+
field: "source.path",
|
|
7208
|
+
outdir: resolved.path,
|
|
7209
|
+
sink
|
|
7210
|
+
});
|
|
7211
|
+
return resolved.path;
|
|
7212
|
+
}
|
|
7040
7213
|
if (!resolved.contained) throw new Error(`File asset '${displaySafe(asset.displayName)}' has source.path='${displaySafe(asset.source.path)}' which ${renderAssemblyPathEscape(resolved, assetOutdir, "publish it")}`);
|
|
7041
7214
|
return resolved.path;
|
|
7042
7215
|
}
|
|
@@ -7110,18 +7283,26 @@ var AssetManifestLoader = class {
|
|
|
7110
7283
|
/**
|
|
7111
7284
|
* Get asset source path (absolute path)
|
|
7112
7285
|
*
|
|
7113
|
-
* Refuses a `source.path` resolving outside `
|
|
7114
|
-
* [#3489](https://github.com/go-to-k/cdkd/issues/3489))
|
|
7115
|
-
*
|
|
7116
|
-
*
|
|
7117
|
-
*
|
|
7286
|
+
* Refuses a RELATIVE `source.path` resolving outside `assetOutdir` (issue
|
|
7287
|
+
* [#3489](https://github.com/go-to-k/cdkd/issues/3489)); an ABSOLUTE one is
|
|
7288
|
+
* honoured and warned about instead (issue
|
|
7289
|
+
* [#3532](https://github.com/go-to-k/cdkd/issues/3532)) — see
|
|
7290
|
+
* {@link resolveFileAssetSourcePath} for why the two arms differ. The
|
|
7291
|
+
* manifest is assembly-supplied and `cdkd deploy -a <dir>` consumes a
|
|
7292
|
+
* pre-synthesized one, so a `source.path` of `../../../home/<user>/.aws`
|
|
7293
|
+
* would otherwise be packaged and uploaded to a bucket the SAME manifest
|
|
7294
|
+
* names.
|
|
7118
7295
|
*
|
|
7119
7296
|
* @param cdkOutputDir CDK output directory
|
|
7120
7297
|
* @param asset File asset
|
|
7298
|
+
* @param assetOutdir The app's outdir — the containment / warning bound.
|
|
7299
|
+
* REQUIRED for the reason {@link resolveFileAssetSourcePath}'s own
|
|
7300
|
+
* parameter is: a dropped bound narrows to the manifest directory and
|
|
7301
|
+
* silently refuses every Stage asset.
|
|
7121
7302
|
* @returns Absolute path to asset source
|
|
7122
7303
|
*/
|
|
7123
|
-
getAssetSourcePath(cdkOutputDir, asset, assetOutdir) {
|
|
7124
|
-
return resolveFileAssetSourcePath(cdkOutputDir, asset, assetOutdir
|
|
7304
|
+
getAssetSourcePath(cdkOutputDir, asset, assetOutdir, sink) {
|
|
7305
|
+
return resolveFileAssetSourcePath(cdkOutputDir, asset, assetOutdir, sink);
|
|
7125
7306
|
}
|
|
7126
7307
|
/**
|
|
7127
7308
|
* Resolve asset destination values (replace ${AWS::AccountId}, ${AWS::Region}, etc.)
|
|
@@ -7211,10 +7392,16 @@ var FileAssetPublisher = class {
|
|
|
7211
7392
|
* @param cdkOutputDir CDK output directory (cdk.out)
|
|
7212
7393
|
* @param accountId AWS account ID
|
|
7213
7394
|
* @param region AWS region
|
|
7214
|
-
*
|
|
7395
|
+
*
|
|
7396
|
+
* There is deliberately NO `profile` parameter. It was unused, and being
|
|
7397
|
+
* OPTIONAL and last it let a pre-go-to-k/cdkd#3532 call
|
|
7398
|
+
* `(…, accountId, region, profile)` keep compiling with the profile NAME
|
|
7399
|
+
* bound to `assetOutdir` — the required bound catches a DROP, not a SWAP,
|
|
7400
|
+
* so the parameter that made the swap expressible is gone instead.
|
|
7215
7401
|
*/
|
|
7216
|
-
async publish(assetHash, asset, cdkOutputDir, accountId, region,
|
|
7217
|
-
const
|
|
7402
|
+
async publish(assetHash, asset, cdkOutputDir, accountId, region, assetOutdir) {
|
|
7403
|
+
const destinations = Object.values(asset.destinations).map((d) => `s3://${this.resolvePlaceholders(d.bucketName, accountId, region)}/${this.resolvePlaceholders(d.objectKey, accountId, region)}`).map((u) => displaySafe(u));
|
|
7404
|
+
const sourcePath = resolveFileAssetSourcePath(cdkOutputDir, asset, assetOutdir, destinations.length > 0 ? `package that path and upload it to ${destinations.join(", ")}` : "package that path, though this manifest names no destination for it");
|
|
7218
7405
|
for (const [, dest] of Object.entries(asset.destinations)) {
|
|
7219
7406
|
const bucketName = this.resolvePlaceholders(dest.bucketName, accountId, region);
|
|
7220
7407
|
const objectKey = this.resolvePlaceholders(dest.objectKey, accountId, region);
|
|
@@ -8545,12 +8732,260 @@ function describeDockerCapturedOutput(error, args, fallback) {
|
|
|
8545
8732
|
return redactDockerArgvInText(capturedStreamText(error, "stderr") || capturedStreamText(error, "stdout") || fallback, args);
|
|
8546
8733
|
}
|
|
8547
8734
|
|
|
8735
|
+
//#endregion
|
|
8736
|
+
//#region src/assets/docker-cache-option.ts
|
|
8737
|
+
/**
|
|
8738
|
+
* Render a `DockerCacheOption` as the `--cache-from` / `--cache-to` value
|
|
8739
|
+
* BuildKit receives.
|
|
8740
|
+
*
|
|
8741
|
+
* Its own LEAF module, imported by both `docker-build.ts` (which pushes it
|
|
8742
|
+
* into the argv) and `manifest-passthrough-warnings.ts` (which judges it).
|
|
8743
|
+
* Not because those two form a cycle — `docker-build.ts` imports the warnings
|
|
8744
|
+
* module and not the reverse — but because the helper belongs to NEITHER: it
|
|
8745
|
+
* is the shared definition of what BuildKit will be handed, and keeping it in
|
|
8746
|
+
* the builder would make the judge import the thing it judges.
|
|
8747
|
+
*
|
|
8748
|
+
* **It is the one spelling on purpose, and the reason is a defect**
|
|
8749
|
+
* ([#3497](https://github.com/go-to-k/cdkd/issues/3497)): the warning layer
|
|
8750
|
+
* used to walk `option.params` STRUCTURALLY while the argv is this
|
|
8751
|
+
* concatenation, and neither `,` nor `=` is quoted here. A manifest could
|
|
8752
|
+
* therefore inject CSV through a field the walk did not treat as a path —
|
|
8753
|
+
* `type: 'local,dest=/home/victim/.ssh'` with no params at all renders
|
|
8754
|
+
* `--cache-to type=local,dest=/home/victim/.ssh`, a host WRITE that produced
|
|
8755
|
+
* no warning because `params` was empty. Judging the rendered STRING closes
|
|
8756
|
+
* that by construction: whatever BuildKit parses is what cdkd parsed.
|
|
8757
|
+
*/
|
|
8758
|
+
function cacheOptionToFlag(option) {
|
|
8759
|
+
let flag = `type=${option.type}`;
|
|
8760
|
+
if (option.params) for (const [k, v] of Object.entries(option.params)) flag += `,${k}=${v}`;
|
|
8761
|
+
return flag;
|
|
8762
|
+
}
|
|
8763
|
+
|
|
8764
|
+
//#endregion
|
|
8765
|
+
//#region src/assets/manifest-passthrough-warnings.ts
|
|
8766
|
+
/**
|
|
8767
|
+
* Every candidate host path in a buildx option value.
|
|
8768
|
+
*
|
|
8769
|
+
* **Uniform, and over-inclusive on purpose.** Three review rounds found this
|
|
8770
|
+
* parser short in three different ways — `dest=` only (missing the
|
|
8771
|
+
* `--output=<path>` shorthand), case-sensitive `src` (missing `source=` and
|
|
8772
|
+
* `SRC=`), and a per-entry `=` requirement (missing every key after the first
|
|
8773
|
+
* in `--ssh k=./a.key,/home/victim/.ssh/id_rsa`). Each fix was a new special
|
|
8774
|
+
* case, and the next round found the next gap. So the rule is now one rule:
|
|
8775
|
+
* **a part with a key yields its value, a part without one yields itself**,
|
|
8776
|
+
* for every field. An over-inclusive candidate costs at most a warning about
|
|
8777
|
+
* a string that was never a path — and a value that is not a path resolves
|
|
8778
|
+
* inside the build context and is dropped before anything is printed.
|
|
8779
|
+
*
|
|
8780
|
+
* `write` is true only for an explicit `dest=`, or when the caller says the
|
|
8781
|
+
* whole field is a write target (`dockerOutputs`, whose bare-path form IS a
|
|
8782
|
+
* destination). It is NOT inferred from the field name: `cacheFrom` can carry
|
|
8783
|
+
* a `dest=` and `cacheTo` a `src=`.
|
|
8784
|
+
*
|
|
8785
|
+
* KNOWN INCOMPLETE, recorded rather than built, and this list is the whole of
|
|
8786
|
+
* what is left "safe by argument" in this module — four of five review rounds
|
|
8787
|
+
* broke something that lived in that category, so it is written down instead:
|
|
8788
|
+
*
|
|
8789
|
+
* - buildx parses these as CSV, so a quoted value containing a comma
|
|
8790
|
+
* (`dest="/tmp/a,b"`) is split wrongly here and its path is missed.
|
|
8791
|
+
* - the keyed rule takes `src` / `source` / `dest`, the documented spellings
|
|
8792
|
+
* that make BuildKit open a file. An UNDOCUMENTED alias, or a NEW key in a
|
|
8793
|
+
* future buildx, would slip past it, where the earlier take-every-key rule
|
|
8794
|
+
* would have caught it — that rule was given up because it cost live false
|
|
8795
|
+
* positives on `ref=` / `scope=` / `env=` at an ordinary project layout.
|
|
8796
|
+
* What was audited, per backend: `--secret` opens a file only through
|
|
8797
|
+
* `src` / `source` (`env` is a variable NAME); every `--output` exporter
|
|
8798
|
+
* only through `dest` (`name`, `push`, `compression*`, `annotation.*`,
|
|
8799
|
+
* `store`, the docker exporter's `context` are not paths); `--cache-to` and
|
|
8800
|
+
* `--cache-from` only under `type=local` (`registry`, `s3`, `azblob`, `gha`
|
|
8801
|
+
* reach the network or take inline values). For the CACHE flags alone there
|
|
8802
|
+
* is a second enumeration to keep in step: `src/utils/docker-cmd.ts`'s
|
|
8803
|
+
* `ARGV_PARAM_LIST_LOCATOR_PARAMS`, consulted under `ARGV_PARAM_LIST_FLAGS`
|
|
8804
|
+
* (`--cache-from` / `--cache-to`), lists the same backends for the
|
|
8805
|
+
* redaction side and agrees — **update both or neither.** `--secret` and
|
|
8806
|
+
* `--output` have no counterpart there, so a new exporter key is judged
|
|
8807
|
+
* here and nowhere else.
|
|
8808
|
+
* - a leading or trailing SPACE is trimmed here and is NOT trimmed by buildx
|
|
8809
|
+
* or by Go's CSV reader, so ` ../../x` is a directory literally named
|
|
8810
|
+
* `" .."` to the kernel while cdkd judges the trimmed spelling. It can only
|
|
8811
|
+
* OVER-warn, which is why it is recorded rather than removed.
|
|
8812
|
+
*
|
|
8813
|
+
* Both misses cost a WARNING, never a refusal, which is the whole reason
|
|
8814
|
+
* neither is worth a CSV parser or a wider net.
|
|
8815
|
+
*
|
|
8816
|
+
* Tolerant by construction: an unparseable value yields nothing rather than
|
|
8817
|
+
* throwing. This module only ever ADDS a warning and must never be why a
|
|
8818
|
+
* legitimate build fails.
|
|
8819
|
+
*/
|
|
8820
|
+
function candidateHostPaths(value, opts) {
|
|
8821
|
+
const out = [];
|
|
8822
|
+
for (const part of value.split(",")) {
|
|
8823
|
+
const eq = part.indexOf("=");
|
|
8824
|
+
if (eq < 0) {
|
|
8825
|
+
const bare = part.trim();
|
|
8826
|
+
if (bare.length > 0) out.push({
|
|
8827
|
+
path: bare,
|
|
8828
|
+
write: opts.bareIsWrite
|
|
8829
|
+
});
|
|
8830
|
+
continue;
|
|
8831
|
+
}
|
|
8832
|
+
const key = part.slice(0, eq).trim().toLowerCase();
|
|
8833
|
+
const v = part.slice(eq + 1).trim();
|
|
8834
|
+
if (v.length === 0) continue;
|
|
8835
|
+
if (key !== "src" && key !== "source" && key !== "dest") continue;
|
|
8836
|
+
out.push({
|
|
8837
|
+
path: v,
|
|
8838
|
+
write: key === "dest"
|
|
8839
|
+
});
|
|
8840
|
+
}
|
|
8841
|
+
return out;
|
|
8842
|
+
}
|
|
8843
|
+
/** Every host path this source hands to BuildKit, with where it came from. */
|
|
8844
|
+
function hostPathsOf(source) {
|
|
8845
|
+
const refs = [];
|
|
8846
|
+
if (source.dockerFile) refs.push({
|
|
8847
|
+
field: "dockerFile",
|
|
8848
|
+
where: "dockerFile",
|
|
8849
|
+
path: source.dockerFile,
|
|
8850
|
+
write: false
|
|
8851
|
+
});
|
|
8852
|
+
for (const [k, v] of Object.entries(source.dockerBuildContexts ?? {})) {
|
|
8853
|
+
const rendered = `${k}=${v}`;
|
|
8854
|
+
const contextPath = rendered.slice(rendered.indexOf("=") + 1).trim();
|
|
8855
|
+
if (contextPath.length === 0) continue;
|
|
8856
|
+
refs.push({
|
|
8857
|
+
field: "dockerBuildContexts",
|
|
8858
|
+
where: k,
|
|
8859
|
+
path: contextPath,
|
|
8860
|
+
write: false
|
|
8861
|
+
});
|
|
8862
|
+
}
|
|
8863
|
+
const ssh = source.dockerBuildSsh ?? "";
|
|
8864
|
+
const sshEq = ssh.indexOf("=");
|
|
8865
|
+
(sshEq < 0 ? [] : ssh.slice(sshEq + 1).split(",")).forEach((entry, i) => {
|
|
8866
|
+
const p = entry.trim();
|
|
8867
|
+
if (p.length > 0) refs.push({
|
|
8868
|
+
field: "dockerBuildSsh",
|
|
8869
|
+
where: String(i),
|
|
8870
|
+
path: p,
|
|
8871
|
+
write: false
|
|
8872
|
+
});
|
|
8873
|
+
});
|
|
8874
|
+
for (const [k, v] of Object.entries(source.dockerBuildSecrets ?? {})) for (const { path: p, write } of candidateHostPaths(`id=${k},${v}`, { bareIsWrite: false })) refs.push({
|
|
8875
|
+
field: "dockerBuildSecrets",
|
|
8876
|
+
where: k,
|
|
8877
|
+
path: p,
|
|
8878
|
+
write
|
|
8879
|
+
});
|
|
8880
|
+
(source.cacheFrom ?? []).forEach((c, i) => {
|
|
8881
|
+
for (const { path: p, write } of candidateHostPaths(cacheOptionToFlag(c), { bareIsWrite: false })) refs.push({
|
|
8882
|
+
field: "cacheFrom",
|
|
8883
|
+
where: String(i),
|
|
8884
|
+
path: p,
|
|
8885
|
+
write
|
|
8886
|
+
});
|
|
8887
|
+
});
|
|
8888
|
+
if (source.cacheTo) for (const { path: p, write } of candidateHostPaths(cacheOptionToFlag(source.cacheTo), { bareIsWrite: false })) refs.push({
|
|
8889
|
+
field: "cacheTo",
|
|
8890
|
+
where: "cacheTo",
|
|
8891
|
+
path: p,
|
|
8892
|
+
write
|
|
8893
|
+
});
|
|
8894
|
+
(source.dockerOutputs ?? []).forEach((o, i) => {
|
|
8895
|
+
for (const { path: p, write } of candidateHostPaths(o, { bareIsWrite: true })) refs.push({
|
|
8896
|
+
field: "dockerOutputs",
|
|
8897
|
+
where: String(i),
|
|
8898
|
+
path: p,
|
|
8899
|
+
write
|
|
8900
|
+
});
|
|
8901
|
+
});
|
|
8902
|
+
return refs;
|
|
8903
|
+
}
|
|
8904
|
+
/**
|
|
8905
|
+
* Warn for each BuildKit passthrough whose host path leaves the assembly.
|
|
8906
|
+
*
|
|
8907
|
+
* `base` is the build context directory (what a relative value resolves
|
|
8908
|
+
* against); `bound` is the app's outdir.
|
|
8909
|
+
*/
|
|
8910
|
+
function warnEscapingBuildKitPaths(source, base, bound) {
|
|
8911
|
+
const logger = getLogger().child("assets");
|
|
8912
|
+
const contextNarrows = assemblyPathEscape(base, base, resolve$1(bound)) !== void 0;
|
|
8913
|
+
for (const ref of hostPathsOf(source)) {
|
|
8914
|
+
if (!ref.write && contextNarrows && assemblyPathEscape(base, base, ref.path) === void 0) continue;
|
|
8915
|
+
const escape = assemblyPathEscape(base, bound, ref.path);
|
|
8916
|
+
if (escape === void 0) continue;
|
|
8917
|
+
const verb = ref.write ? "WRITE to" : "read";
|
|
8918
|
+
logger.warn(`Docker asset ${ref.field}` + (ref.where === ref.field ? "" : `['${displaySafe(ref.where)}']`) + ` names a host path outside the assembly, which ${renderAssemblyPathEscape(escape, bound, "load", `cdkd will ${verb} it during the image build, matching the CDK CLI — a pre-synthesized assembly is trusted input. If you did not produce this assembly, that is a host path it chose and the CloudFormation template does not show.`)}`);
|
|
8919
|
+
}
|
|
8920
|
+
}
|
|
8921
|
+
/**
|
|
8922
|
+
* Warn that a manifest-chosen command line is about to run on the host.
|
|
8923
|
+
*
|
|
8924
|
+
* **This is the one the decision singles out**, and it is not a containment
|
|
8925
|
+
* question: `source.executable` is an arbitrary argv cdkd spawns, so no path
|
|
8926
|
+
* check applies and no value of it is "safe". It breaks the reasonable
|
|
8927
|
+
* expectation that `-a <dir>` runs no code from the assembly, and nothing said
|
|
8928
|
+
* so before. Rendered through `redactDockerArgvValues`, because a build script
|
|
8929
|
+
* wrapping `docker build` carries the very `--build-arg` pairs the rest of
|
|
8930
|
+
* this layer masks.
|
|
8931
|
+
*/
|
|
8932
|
+
function warnManifestExecutable(executable) {
|
|
8933
|
+
const [cmd, ...rest] = executable;
|
|
8934
|
+
const logger = getLogger().child("assets");
|
|
8935
|
+
logger.debug(`source.executable argv: ${redactDockerArgvValues([...executable]).join(" ")}`);
|
|
8936
|
+
logger.warn(`Docker asset source.executable runs a command this asset manifest chose, on this machine: '${displaySafe(cmd ?? "")}'` + (rest.length > 0 ? ` (with ${rest.length} argument(s); --verbose shows them)` : "") + ". cdkd runs it, matching the CDK CLI — a pre-synthesized assembly is trusted input. Note that this means deploying from a pre-synthesized assembly DOES execute code from it, which the CloudFormation template does not show.");
|
|
8937
|
+
}
|
|
8938
|
+
/**
|
|
8939
|
+
* One set per KIND rather than one set of composite keys. A `${kind}` + NUL +
|
|
8940
|
+
* `${name}` key would be a multi-part NUL-joined string, which this repo
|
|
8941
|
+
* fences as a record-key shape — and it is not one: it never leaves the
|
|
8942
|
+
* process, is never persisted, and a collision would suppress one duplicate
|
|
8943
|
+
* warning line. Two sets carry the same information with nothing to classify.
|
|
8944
|
+
*/
|
|
8945
|
+
const warnedDestinations = {
|
|
8946
|
+
bucket: /* @__PURE__ */ new Set(),
|
|
8947
|
+
repository: /* @__PURE__ */ new Set()
|
|
8948
|
+
};
|
|
8949
|
+
/**
|
|
8950
|
+
* Warn that an asset destination is not bootstrap-shaped.
|
|
8951
|
+
*
|
|
8952
|
+
* `redirectFileAsset` rewrites a destination only when it matches a known
|
|
8953
|
+
* bootstrap shape, so anything else survives verbatim and cdkd uploads there
|
|
8954
|
+
* with the caller's credentials. A CUSTOM BOOTSTRAP IS LEGITIMATE — which is
|
|
8955
|
+
* why this warns and never refuses — but the name is worth printing, because
|
|
8956
|
+
* it is the one field a reader can recognise as not theirs.
|
|
8957
|
+
*
|
|
8958
|
+
* **Shape only, and an adversary can imitate a shape.**
|
|
8959
|
+
* `isDefaultBootstrapBucketName` accepts any qualifier, so
|
|
8960
|
+
* `cdk-<anything>-assets-<victim-account>-<region>` reads as recognized even
|
|
8961
|
+
* when the bucket lives in the attacker's account (S3 names are global and a
|
|
8962
|
+
* bucket policy can admit the victim's principal). This warning narrows what
|
|
8963
|
+
* a careless manifest gets away with; it is not an ownership check, and
|
|
8964
|
+
* nothing here should be read as one.
|
|
8965
|
+
*
|
|
8966
|
+
* `recognized` is whether the name is default-bootstrap-shaped for this
|
|
8967
|
+
* (account, region) or is cdkd's own asset storage. Judged on the FLATTENED
|
|
8968
|
+
* name and on shape, not on whether the redirect table rewrote it: in legacy
|
|
8969
|
+
* mode nothing is rewritten and every ordinary deploy would otherwise warn,
|
|
8970
|
+
* which is the cry-wolf failure this layer already learned once.
|
|
8971
|
+
*/
|
|
8972
|
+
function warnUnrecognizedAssetDestination(opts) {
|
|
8973
|
+
if (opts.recognized) return;
|
|
8974
|
+
const seen = warnedDestinations[opts.kind];
|
|
8975
|
+
if (seen.has(opts.name)) return;
|
|
8976
|
+
seen.add(opts.name);
|
|
8977
|
+
getLogger().child("assets").warn(`Asset destination ${opts.kind} '${displaySafe(opts.name)}' is not a CDK-bootstrap or cdkd-managed name, so cdkd uploads there exactly as this asset manifest wrote it, with your credentials. That is what a custom bootstrap looks like and is expected for one; if you did not configure it, the manifest chose where your assets go.`);
|
|
8978
|
+
}
|
|
8979
|
+
|
|
8548
8980
|
//#endregion
|
|
8549
8981
|
//#region src/assets/docker-build.ts
|
|
8550
8982
|
/**
|
|
8551
|
-
* Where a Docker asset's build context lives, refusing a
|
|
8552
|
-
* that resolves outside `
|
|
8553
|
-
* [#3489](https://github.com/go-to-k/cdkd/issues/3489))
|
|
8983
|
+
* Where a Docker asset's build context lives, refusing a RELATIVE
|
|
8984
|
+
* `source.directory` that resolves outside `assetOutdir` (issue
|
|
8985
|
+
* [#3489](https://github.com/go-to-k/cdkd/issues/3489)) and HONOURING an
|
|
8986
|
+
* ABSOLUTE one with a warning when it leaves that bound (issue
|
|
8987
|
+
* [#3532](https://github.com/go-to-k/cdkd/issues/3532); the reasoning is in
|
|
8988
|
+
* `resolveFileAssetSourcePath`, and the two must not diverge).
|
|
8554
8989
|
*
|
|
8555
8990
|
* The field is assembly-supplied and used BOTH as the executable's cwd and as
|
|
8556
8991
|
* the `docker build` cwd, so an escaping value sends a directory from outside
|
|
@@ -8564,11 +8999,42 @@ function describeDockerCapturedOutput(error, args, fallback) {
|
|
|
8564
8999
|
* Twin of `resolveFileAssetSourcePath` and `resolveVerboseTemplatePath`.
|
|
8565
9000
|
* Exported for unit testing.
|
|
8566
9001
|
*/
|
|
8567
|
-
function resolveDockerContextDirectory(manifestDir, directory, wrapError, assetOutdir
|
|
9002
|
+
function resolveDockerContextDirectory(manifestDir, directory, wrapError, assetOutdir, sink, assetId) {
|
|
9003
|
+
if (isAbsolute$1(directory)) {
|
|
9004
|
+
const absolute = resolve$1(directory);
|
|
9005
|
+
const escape = absoluteAssemblyPathEscape(assetOutdir, absolute);
|
|
9006
|
+
if (escape !== void 0) warnAbsoluteAssetPath({
|
|
9007
|
+
subject: dockerSubject(assetId),
|
|
9008
|
+
field: "source.directory",
|
|
9009
|
+
absolute,
|
|
9010
|
+
escape,
|
|
9011
|
+
sink
|
|
9012
|
+
});
|
|
9013
|
+
else if (namesTheSameDirectory(assetOutdir, absolute)) warnWholeAssemblyAsSource({
|
|
9014
|
+
subject: dockerSubject(assetId),
|
|
9015
|
+
field: "source.directory",
|
|
9016
|
+
outdir: absolute,
|
|
9017
|
+
sink
|
|
9018
|
+
});
|
|
9019
|
+
return absolute;
|
|
9020
|
+
}
|
|
8568
9021
|
const resolved = resolveAssemblyPath(manifestDir, directory, { containWithin: assetOutdir });
|
|
9022
|
+
if (!resolved.contained && namesTheSameDirectory(assetOutdir, resolved.path)) {
|
|
9023
|
+
warnWholeAssemblyAsSource({
|
|
9024
|
+
subject: dockerSubject(assetId),
|
|
9025
|
+
field: "source.directory",
|
|
9026
|
+
outdir: resolved.path,
|
|
9027
|
+
sink
|
|
9028
|
+
});
|
|
9029
|
+
return resolved.path;
|
|
9030
|
+
}
|
|
8569
9031
|
if (!resolved.contained) throw wrapError(`asset source.directory='${displaySafe(directory)}' which ${renderAssemblyPathEscape(resolved, assetOutdir, "build it")}`);
|
|
8570
9032
|
return resolved.path;
|
|
8571
9033
|
}
|
|
9034
|
+
/** One spelling of the warning subject, so the two arms cannot drift. */
|
|
9035
|
+
function dockerSubject(assetId) {
|
|
9036
|
+
return assetId === void 0 ? "A Docker asset" : `Docker asset '${displaySafe(assetId)}'`;
|
|
9037
|
+
}
|
|
8572
9038
|
/**
|
|
8573
9039
|
* Build a Docker image from a CDK asset source. Returns the local image
|
|
8574
9040
|
* tag the caller should use for `docker tag` / `docker push` (publisher)
|
|
@@ -8587,11 +9053,12 @@ function resolveDockerContextDirectory(manifestDir, directory, wrapError, assetO
|
|
|
8587
9053
|
async function buildDockerImage(asset, cdkOutDir, options) {
|
|
8588
9054
|
const source = asset.source;
|
|
8589
9055
|
const logger = getLogger().child("docker-build");
|
|
8590
|
-
const contextDirectory = (directory) => resolveDockerContextDirectory(cdkOutDir, directory, options.wrapError, options.assetOutdir);
|
|
9056
|
+
const contextDirectory = (directory, sink) => resolveDockerContextDirectory(cdkOutDir, directory, options.wrapError, options.assetOutdir ?? cdkOutDir, sink, options.tag);
|
|
8591
9057
|
if (source.executable && source.executable.length > 0) {
|
|
8592
9058
|
const [cmd, ...args] = source.executable;
|
|
8593
9059
|
if (!cmd) throw options.wrapError("asset source.executable[] is empty");
|
|
8594
|
-
|
|
9060
|
+
warnManifestExecutable(source.executable);
|
|
9061
|
+
const cwd = source.directory ? contextDirectory(source.directory, "run this asset's source.executable with that directory as its working directory") : cdkOutDir;
|
|
8595
9062
|
const shownExecutable = redactDockerArgvValues(source.executable).join(" ");
|
|
8596
9063
|
logger.debug(`Building Docker image via executable: ${shownExecutable} (cwd=${cwd})`);
|
|
8597
9064
|
let result;
|
|
@@ -8615,8 +9082,9 @@ async function buildDockerImage(asset, cdkOutDir, options) {
|
|
|
8615
9082
|
}
|
|
8616
9083
|
if (!options.tag) throw options.wrapError("buildDockerImage(directory mode) requires options.tag");
|
|
8617
9084
|
const buildArgs = buildDockerBuildCommand(source, options.tag, options.platform);
|
|
8618
|
-
const contextDir = contextDirectory(source.directory);
|
|
9085
|
+
const contextDir = contextDirectory(source.directory, "send that directory to BuildKit as the build context and bake it into the image pushed to the repository this manifest names");
|
|
8619
9086
|
buildArgs.push(".");
|
|
9087
|
+
warnEscapingBuildKitPaths(source, contextDir, options.assetOutdir ?? cdkOutDir);
|
|
8620
9088
|
logger.debug(`${getDockerCmd()} ${redactDockerArgvValues(buildArgs).join(" ")} (cwd=${displaySafe(contextDir)})`);
|
|
8621
9089
|
try {
|
|
8622
9090
|
await runDockerStreaming(buildArgs, {
|
|
@@ -8655,11 +9123,6 @@ function buildDockerBuildCommand(source, tag, platformOverride) {
|
|
|
8655
9123
|
if (source.cacheDisabled) args.push("--no-cache");
|
|
8656
9124
|
return args;
|
|
8657
9125
|
}
|
|
8658
|
-
function cacheOptionToFlag(option) {
|
|
8659
|
-
let flag = `type=${option.type}`;
|
|
8660
|
-
if (option.params) for (const [k, v] of Object.entries(option.params)) flag += `,${k}=${v}`;
|
|
8661
|
-
return flag;
|
|
8662
|
-
}
|
|
8663
9126
|
|
|
8664
9127
|
//#endregion
|
|
8665
9128
|
//#region src/assets/docker-asset-publisher.ts
|
|
@@ -8730,7 +9193,7 @@ var DockerAssetPublisher = class {
|
|
|
8730
9193
|
continue;
|
|
8731
9194
|
}
|
|
8732
9195
|
const localTag = `cdkd-asset-${assetHash}`;
|
|
8733
|
-
await this.buildImage(asset, cdkOutputDir, localTag);
|
|
9196
|
+
await this.buildImage(asset, cdkOutputDir, localTag, cdkOutputDir);
|
|
8734
9197
|
await this.tagAndPushWithLazyLogin(client, localTag, ecrUri, accountId, destRegion);
|
|
8735
9198
|
this.logger.debug(`✅ Published: ${ecrUri}`);
|
|
8736
9199
|
} finally {
|
|
@@ -8807,7 +9270,7 @@ var DockerAssetPublisher = class {
|
|
|
8807
9270
|
async buildImage(asset, cdkOutputDir, tag, assetOutdir) {
|
|
8808
9271
|
const actualTag = await buildDockerImage(asset, cdkOutputDir, {
|
|
8809
9272
|
tag,
|
|
8810
|
-
|
|
9273
|
+
assetOutdir,
|
|
8811
9274
|
wrapError: (stderr) => new AssetError(`Docker build failed: ${stderr}`)
|
|
8812
9275
|
});
|
|
8813
9276
|
if (actualTag !== tag) {
|
|
@@ -10186,6 +10649,15 @@ var AssetPublisher = class {
|
|
|
10186
10649
|
const nodeIds = [];
|
|
10187
10650
|
const fileAssets = Object.entries(manifest.files || {}).filter(([, asset]) => !isCfnTemplateAssetPath(asset.source.path)).map(([hash, asset]) => [hash, redirect ? redirectFileAsset(asset, redirect) : asset]);
|
|
10188
10651
|
for (const [hash, asset] of fileAssets) {
|
|
10652
|
+
for (const dest of Object.values(asset.destinations)) {
|
|
10653
|
+
const destRegion = dest.region ?? options.region;
|
|
10654
|
+
const name = flattenAssetPlaceholders(dest.bucketName, options.accountId, destRegion);
|
|
10655
|
+
warnUnrecognizedAssetDestination({
|
|
10656
|
+
kind: "bucket",
|
|
10657
|
+
name,
|
|
10658
|
+
recognized: isDefaultBootstrapBucketName(name, options.accountId, destRegion) || redirect !== void 0 && [...redirect.buckets.values()].includes(name)
|
|
10659
|
+
});
|
|
10660
|
+
}
|
|
10189
10661
|
const nodeId = `asset-publish:${prefix}file:${hash}`;
|
|
10190
10662
|
graph.addNode({
|
|
10191
10663
|
id: nodeId,
|
|
@@ -10199,14 +10671,22 @@ var AssetPublisher = class {
|
|
|
10199
10671
|
cdkOutputDir,
|
|
10200
10672
|
assetOutdir,
|
|
10201
10673
|
accountId: options.accountId,
|
|
10202
|
-
region: options.region
|
|
10203
|
-
...options.profile && { profile: options.profile }
|
|
10674
|
+
region: options.region
|
|
10204
10675
|
}
|
|
10205
10676
|
});
|
|
10206
10677
|
nodeIds.push(nodeId);
|
|
10207
10678
|
}
|
|
10208
10679
|
for (const [hash, rawAsset] of Object.entries(manifest.dockerImages || {})) {
|
|
10209
10680
|
const asset = redirect ? redirectDockerAsset(rawAsset, redirect) : rawAsset;
|
|
10681
|
+
for (const dest of Object.values(asset.destinations)) {
|
|
10682
|
+
const destRegion = dest.region ?? options.region;
|
|
10683
|
+
const name = flattenAssetPlaceholders(dest.repositoryName, options.accountId, destRegion);
|
|
10684
|
+
warnUnrecognizedAssetDestination({
|
|
10685
|
+
kind: "repository",
|
|
10686
|
+
name,
|
|
10687
|
+
recognized: isDefaultBootstrapRepoName(name, options.accountId, destRegion) || redirect !== void 0 && [...redirect.repos.values()].includes(name)
|
|
10688
|
+
});
|
|
10689
|
+
}
|
|
10210
10690
|
const localTag = `cdkd-asset-${hash}`;
|
|
10211
10691
|
const buildNodeId = `asset-build:${prefix}docker:${hash}`;
|
|
10212
10692
|
const publishNodeId = `asset-publish:${prefix}docker:${hash}`;
|
|
@@ -10247,7 +10727,7 @@ var AssetPublisher = class {
|
|
|
10247
10727
|
*/
|
|
10248
10728
|
async executeNode(node) {
|
|
10249
10729
|
const data = node.data;
|
|
10250
|
-
if (data.kind === "file") await this.filePublisher.publish(data.hash, data.asset, data.cdkOutputDir, data.accountId, data.region, data.
|
|
10730
|
+
if (data.kind === "file") await this.filePublisher.publish(data.hash, data.asset, data.cdkOutputDir, data.accountId, data.region, data.assetOutdir);
|
|
10251
10731
|
else if (data.kind === "docker-build") await this.dockerPublisher.build(data.asset, data.cdkOutputDir, data.localTag, data.assetOutdir);
|
|
10252
10732
|
else if (data.kind === "docker-publish") await this.dockerPublisher.push(data.asset, data.accountId, data.region, data.localTag);
|
|
10253
10733
|
this.logger.debug(`✅ ${node.id}`);
|
|
@@ -34669,7 +35149,7 @@ var CloudControlProvider = class {
|
|
|
34669
35149
|
const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
|
|
34670
35150
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
34671
35151
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
34672
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
35152
|
+
const { ASGProvider } = await import("./asg-provider-CZ5keDoC.js").then((n) => n.n);
|
|
34673
35153
|
const asgProvider = new ASGProvider();
|
|
34674
35154
|
return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
|
|
34675
35155
|
}
|
|
@@ -48378,5 +48858,5 @@ var DeployEngine = class DeployEngine {
|
|
|
48378
48858
|
};
|
|
48379
48859
|
|
|
48380
48860
|
//#endregion
|
|
48381
|
-
export { yellow as $,
|
|
48382
|
-
//# sourceMappingURL=deploy-engine-
|
|
48861
|
+
export { yellow as $, derivePartitionAndUrlSuffix as $i, safeStackName as $n, assertAssetBucketRegion as $r, requireConfigObject as $t, createPreDeleteFinalSnapshot as A, PartialFailureError as Aa, resolveAutoAssetStorage as Ai, malformedOutputsRefusalMessage as An, formatLockExpiry as Ar, carriesDynamicReference as At, isStatefulRecreateTargetSync as B, normalizeAwsError as Ba, CFN_TEMPLATE_URL_LIMIT as Bi, refuseMalformedOrphansForDestroy as Bn, isReadableBag as Br, isSettledInstanceState as Bt, namesAnyDeclaredParameter as C, DynamicReferenceRegionAmbiguousError as Ca, AssetManifestLoader as Ci, isReadableResourceEntry as Cn, LockManager as Cr, slowCcOperationTimeoutMs as Ct, PRE_DELETE_SNAPSHOT_TYPES as D, LockError as Da, getDefaultStateBucketName as Di, malformedOrphanRecordsWarning as Dn, buildForceUnlockCommand as Dr, disableInstanceApiTermination as Dt, ATOMIC_FINAL_SNAPSHOT_TYPES as E, LocalStartServiceError as Ea, synthesisStatusMessage as Ei, malformedLocalOutputsWarning as En, UNREPRODUCIBLE_LOCK_CLAUSE as Er, deleteSkipReason as Et, extractDeploymentEventError as F, StackTerminationProtectionError as Fa, resolveUseCdkBootstrapAssets as Fi, malformedResourcesWarning as Fn, hasReadableExportSet as Fr, isImpossibleEmptyStoredAttribute as Ft, toCfnInteger as G, isTransientServerError as Ga, injectiveKey as Gi, refuseMalformedResourcesForDestroy as Gn, stringifyValue as Gr, coerceCfnBoolean as Gt, WARM_THROUGHPUT_MEMBERS as H, isMarkedNonRetryable as Ha, findLargeInlineResources as Hi, refuseMalformedOutputsForDestroy as Hn, orphansCarriedFrom as Hr, normalizeAwsTagsToCfn as Ht, makeSiblingClaimReader as I, StateError as Ia, stateBucketExistenceConfirmed as Ii, malformedStateRefusalMessage as In, hasReasonlessBaselineRefusal as Ir, isNamelessDynamicReferenceError as It, bold as J, retryClassificationText as Ja, producerRecordKey as Ji, repairMalformedOutputsForReadOnly as Jn, createAssetRedirectResolver as Jr, configIntegerRefusal as Jt, toFiniteNumber as K, markNonRetryable as Ka, injectiveKeyPrefix as Ki, refuseMalformedState as Kn, WorkGraph as Kr, coerceCfnInteger as Kt, planOrphanAdoption as L, SynthesisError as La, warnDeprecatedNoPrefixCliFlag as Li, refuseDivergentRecordRegionForDestroy as Ln, hasUnverifiableParameterRefusal as Lr, isUnboundTemplateParameter as Lt, refusesFinalSnapshot as M, ResourceTimeoutError as Ma, resolveSkipPrefix as Mi, malformedRenderedContainersWarning as Mn, CUSTOM_RESOURCE_RESPONSE_PREFIX as Mr, cfnRefValueFromPhysicalId as Mt, unsupportedFinalSnapshotError as N, ResourceUpdateNotSupportedError as Na, resolveStateBucketWithDefault as Ni, malformedResourceEntriesWarning as Nn, DEFAULT_STATE_PREFIX as Nr, coerceParameterTypedValue as Nt, buildFinalSnapshotIdentifier as O, MalformedProducerRecordRefusalError as Oa, getLegacyStateBucketName as Oi, malformedOrphansRefusalMessage as On, buildLockContentionMessage as Or, isTerminationProtectionPropagationError as Ot, makeCanonicalizePropertiesFn as P, StackHasActiveImportsError as Pa, resolveStateBucketWithDefaultAndSource as Pi, malformedResourcePropertiesWarning as Pn, exportNamesCarriedFrom as Pr, getAccountInfo as Pt, red as Q, canonicalizeRegion as Qi, safeRegion as Qn, BOOTSTRAP_MARKER_PREFIX as Qr, requireConfigArray as Qt, MULTI_REGION_RECREATE_BLOCKED_TYPES as R, formatError as Ra, ssmResolvedValueType as Ri, refuseMalformedNestedChildOutputs as Rn, importableOutputKeys as Rr, parameterTypeMayLoseSecretIdentity as Rt, computeParameterTaint as S, DeployCancelledError as Sa, stripControlChars as Si, hasReadableResources as Sn, scrubResourceRecord as Sr, isWaitAbandonedError as St, resourcesNamingDeclaredParameter as T, LocalInvokeBuildError as Ta, Synthesizer as Ti, malformedExportSourceWarning as Tn, rebuildClientForBucketRegion as Tr, deleteIndeterminateGuards as Tt, coerceWarmThroughput as U, isRetryableTransientError as Ua, uploadCfnTemplate as Ui, refuseMalformedResourceEntries as Un, shouldRetainResource as Ur, resolveExplicitPhysicalId as Ut, renderStatefulReason as V, withErrorHandling as Va, MIGRATE_TMP_PREFIX as Vi, refuseMalformedOutputs as Vn, orphansAfterRollback as Vr, WAFv2WebACLProvider as Vt, isWarmThroughputDecrease as W, isThrottlingError as Wa, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Wi, refuseMalformedResourcePropertiesForOrphan as Wn, AssetPublisher as Wr, assertRegionMatch as Wt, gray as X, safeStringify$1 as Xa, expectedOwnerParam as Xi, repairMalformedResourcePropertiesForReadOnly as Xn, rewriteTemplateAssetReferences as Xr, readConfigString as Xt, cyan as Y, describeAwsFailure as Ya, decodeListingKey as Yi, repairMalformedResourceEntriesForReadOnly as Yn, loadPublishableAssetManifest as Yr, configStringRefusal as Yt, green as Z, __exportAll as Za, PARTITION_TABLE as Zi, repairMalformedResourcesForReadOnly as Zn, AssetModeResolver as Zr, replayWarn as Zt, bagHoldsSecretExpression as _, AssetError as _a, partitionSensitiveEnv as _i, UNREADABLE_ORPHANS_CONTAINER_ROW as _n, maskSecretsInError as _r, endCommandInterruptScope as _t, DeploymentEventsStore as a, hasPlainPrototype$1 as aa, validateAssetBucketName as ai, s3BucketDomainName as an, TemplateParser as ar, secretBearingStateKeyWarning as at, mergeNoChangeOutputs as b, CrossAccountSecretRefusalError as ba, runDockerStreaming as bi, hasReadableOrphans as bn, recoverMaskedOutput as br, startInterruptWatch as bt, replayFailedOperations as c, absoluteAssemblyPathEscape as ca, buildDockerImage as ci, s3BucketWebsiteUrl as cn, STATE_SOURCED_READBACK_RULES as cr, IAMRoleProvider as ct, updatePartialMessage as d, clearBucketRegionCache as da, describeDockerCapturedOutput as di, applyCallerIdentityCredentials as dn, createSecretMasker as dr, ProviderRegistry as dt, AssemblyReader as ea, ensureAssetStorage as ei, requireConfigString as en, findActionableSilentDrops as er, collectDeclaredOutputNames as et, updatePartialReason as f, resolveBucketRegion as fa, describeDockerExecFailure as fi, callerEnvCredentials as fn, dynamicReferenceTokens as fr, wouldReturnToSdkProvider as ft, computeImplicitDeleteEdges as g, setAwsClients as ga, getDockerCmd as gi, STATE_RESOURCES_MALFORMED as gn, markSameGenerationBag as gr, beginCommandInterruptScope as gt, IMPLICIT_DELETE_DEPENDENCIES as h, resetAwsClients as ha, formatDockerLoginError as hi, INTRINSIC_KEYS as hn, isSingleDynamicReferenceToken as hr, maskerOrIdentity as ht, DeploymentEventsReader as i, hasOwnKey as ia, readBootstrapMarkerBody as ii, s3BucketArn as in, DagBuilder as ir, secretBearing as it, isFinalSnapshotError as j, ProvisioningError as ja, resolveCaptureObservedState as ji, malformedOutputsWarning as jn, shellQuote as jr, carriesFetchableDynamicReference as jt, ccRoutedFinalSnapshotError as k, NestedStackChildDirectDestroyError as ka, resolveApp as ki, malformedOrphansWarning as kn, forceQuitRecoveryClause as kr, IntrinsicFunctionResolver as kt, replayRollback as l, renderAssemblyPathEscape as la, resolveDockerContextDirectory as li, applyRoleArnIfSet as ln, TEMPLATE_SOURCED_RULES as lr, collectInlinePolicyNamesManagedBySiblings as lt, maskingRetryLogger as m, getAwsClients as ma, dockerSpawnEnvWithSensitive as mi, DiffCalculator as mn, identityKeyFor as mr, maskDeep as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, processStackMessages as na, isCrossRegionRedirect as ni, producerRegionsFromState as nn, describeTypeWithThrottleRetry as nr, exportAliasCollisionScrubWarning as nt, planFailedOps as o, nullPrototypeRecord as oa, validateContainerRepoName as oi, s3BucketDualStackDomainName as on, STATE_SOURCED_BASELINE_RULES as or, secretSafeKeyDisplay as ot, withResourceDeadline as p, AwsClients as pa, describeDockerFailure as pi, envCredentialsAreAssumedRole as pn, errorCauseChain as pr, createMaskedRetryLogger as pt, formatResourceLine as q, markRedactedCause as qa, producerCoordinateKey as qi, repairMalformedOrphansForReadOnly as qn, buildAssetRedirectMap as qr, configBooleanRefusal as qt, DeployEngine as r, defineOwnKey as ra, parseBootstrapMarker as ri, withSharedDrainBudget as rn, withRetry as rr, isExportAliasCollision as rt, planRollback as s, ownValue as sa, buildDenyExternalAccessPolicy as si, s3BucketRegionalDomainName as sn, STATE_SOURCED_CROSS_GENERATION_RULES as sr, getCurrentResourceSecrets as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, failedStageNote as ta, getBootstrapMarkerKey as ti, classifyReplaySecretRegion as tn, findSilentDropProperties as tr, collectPublishedOutputNames as tt, resolveReplacementOldType as u, resolveAssemblyPath as ua, warnManifestExecutable as ui, AWS_CREDENTIAL_ENV_KEYS as un, carriesSecretMask as ur, clearOnUpdateRemoval as ut, isSecretBearingReferenceString as v, CdkdError as va, redactDockerArgvValues as vi, UNREADABLE_RESOURCES_MAP_ROW as vn, maskSecretsInText as vr, interruptWatchListenerCount as vt, reachableDivergentParameters as w, IntrinsicResolutionRefusalError as wa, getDockerImageBySourceHash as wi, malformedExportNamesWarning as wn, S3StateBackend as wr, UNSPECIFIED_SKIP_REASON as wt, bindingSkippedOutputs as x, DependencyError as xa, escapeRegExp$1 as xi, hasReadableOutputs as xn, redactSecretsForState as xr, CloudControlProvider as xt, keptWholeReasonText as y, ConfigError as ya, runDockerForeground as yi, displayLogicalId as yn, recordMaskOnlyValue as yr, isInterruptedWaitError as yt, isStatefulRecreateTargetForReplace as z, isCdkdError as za, CFN_TEMPLATE_BODY_LIMIT as zi, refuseMalformedOrphans as zn, importableOutputs as zr, refStateLookupFromResource as zt };
|
|
48862
|
+
//# sourceMappingURL=deploy-engine-9CxYEFh_.js.map
|