@hsuite/smart-engines-cli 1.5.1 → 1.6.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/README.md +5 -3
- package/dist/_lib/baas.d.ts +27 -4
- package/dist/_lib/baas.d.ts.map +1 -1
- package/dist/_lib/baas.js +76 -42
- package/dist/_lib/baas.js.map +1 -1
- package/dist/_lib/cluster-convergence.d.ts +214 -0
- package/dist/_lib/cluster-convergence.d.ts.map +1 -0
- package/dist/_lib/cluster-convergence.js +381 -0
- package/dist/_lib/cluster-convergence.js.map +1 -0
- package/dist/_lib/deploy-manifest.d.ts +32 -0
- package/dist/_lib/deploy-manifest.d.ts.map +1 -1
- package/dist/_lib/deploy-manifest.js +71 -0
- package/dist/_lib/deploy-manifest.js.map +1 -1
- package/dist/_lib/docker.d.ts +35 -23
- package/dist/_lib/docker.d.ts.map +1 -1
- package/dist/_lib/docker.js +58 -54
- package/dist/_lib/docker.js.map +1 -1
- package/dist/_lib/frontend-guard.d.ts +59 -0
- package/dist/_lib/frontend-guard.d.ts.map +1 -1
- package/dist/_lib/frontend-guard.js +148 -0
- package/dist/_lib/frontend-guard.js.map +1 -1
- package/dist/_lib/registry-fanout.d.ts +299 -9
- package/dist/_lib/registry-fanout.d.ts.map +1 -1
- package/dist/_lib/registry-fanout.js +557 -27
- package/dist/_lib/registry-fanout.js.map +1 -1
- package/dist/_lib/subscription-client.d.ts +14 -0
- package/dist/_lib/subscription-client.d.ts.map +1 -1
- package/dist/_lib/subscription-client.js +13 -0
- package/dist/_lib/subscription-client.js.map +1 -1
- package/dist/commands/deploy.d.ts +28 -4
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +163 -20
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/redeploy.d.ts +10 -0
- package/dist/commands/redeploy.d.ts.map +1 -1
- package/dist/commands/redeploy.js +146 -15
- package/dist/commands/redeploy.js.map +1 -1
- package/dist/commands/status.d.ts +4 -3
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +15 -3
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/topup.d.ts +55 -0
- package/dist/commands/topup.d.ts.map +1 -0
- package/dist/commands/topup.js +180 -0
- package/dist/commands/topup.js.map +1 -0
- package/dist/commands/update.d.ts +33 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +38 -2
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +24 -1
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../src/_lib/docker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,+EAA+E;AAC/E,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAwCF;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAErE;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,aAAa,EACvB,OAAO,CAAC,EAAE,OAAO,KAAK,GACrB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI7D;AAED
|
|
1
|
+
{"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../src/_lib/docker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,+EAA+E;AAC/E,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAwCF;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAErE;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,aAAa,EACvB,OAAO,CAAC,EAAE,OAAO,KAAK,GACrB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI7D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQnE;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,OAAO,KAAK,GACrB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQxB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,OAAO,KAAK,GACrB,OAAO,CAAC,MAAM,CAAC,CAuBjB"}
|
package/dist/_lib/docker.js
CHANGED
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.imageRef = imageRef;
|
|
4
4
|
exports.dockerLogin = dockerLogin;
|
|
5
5
|
exports.parsePushDigest = parsePushDigest;
|
|
6
|
-
exports.
|
|
7
|
-
exports.
|
|
6
|
+
exports.parseImagetoolsDigest = parseImagetoolsDigest;
|
|
7
|
+
exports.inspectRegistryDigest = inspectRegistryDigest;
|
|
8
8
|
exports.dockerPush = dockerPush;
|
|
9
9
|
/**
|
|
10
10
|
* Thin, testable wrappers around the `docker` CLI for the trusted-deploy flow.
|
|
@@ -87,63 +87,63 @@ function parsePushDigest(output) {
|
|
|
87
87
|
return m ? m[1].toLowerCase() : null;
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
90
|
-
*
|
|
91
|
-
* `
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* in exactly one place.
|
|
90
|
+
* Parse the top-level manifest digest from `docker buildx imagetools inspect
|
|
91
|
+
* <ref>` output. `imagetools inspect` queries the REGISTRY (not the local
|
|
92
|
+
* daemon cache), so this is the authoritative `sha256:<64hex>` the registry
|
|
93
|
+
* serves for the tag — the value the attestation must bind.
|
|
95
94
|
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
95
|
+
* The default (non-`--raw`) report prints a top-level block:
|
|
96
|
+
* `Name: <ref>`
|
|
97
|
+
* `MediaType: application/vnd.docker.distribution.manifest.v2+json`
|
|
98
|
+
* `Digest: sha256:<64hex>`
|
|
99
|
+
* We match the FIRST `Digest:` line — the top-level manifest digest. (Per-arch
|
|
100
|
+
* child digests appear only under a later `Manifests:` block for a multi-arch
|
|
101
|
+
* index, which the single-arch amd64 deploy flow never produces.)
|
|
102
|
+
*
|
|
103
|
+
* @returns the lower-cased `sha256:<64hex>` digest, or `null` if absent.
|
|
100
104
|
*/
|
|
101
|
-
function
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (!Array.isArray(repoDigests))
|
|
110
|
-
return null;
|
|
111
|
-
const repoPrefix = `${registry.server}/${registry.repository}@`;
|
|
112
|
-
for (const rd of repoDigests) {
|
|
113
|
-
if (typeof rd === 'string' && rd.startsWith(repoPrefix)) {
|
|
114
|
-
const at = rd.indexOf('@');
|
|
115
|
-
const digest = rd.slice(at + 1);
|
|
116
|
-
if (/^sha256:[a-f0-9]{64}$/i.test(digest))
|
|
117
|
-
return digest.toLowerCase();
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return null;
|
|
105
|
+
function parseImagetoolsDigest(output) {
|
|
106
|
+
// Scan only the top-level block: truncate at the `Manifests:` section so a
|
|
107
|
+
// per-arch child `Digest:` in a multi-arch index can never be mistaken for
|
|
108
|
+
// the top-level manifest digest. This anchors correctness to structure rather
|
|
109
|
+
// than to buildx's field-emission order (robust across buildx versions).
|
|
110
|
+
const topLevel = output.split(/^\s*Manifests:/m)[0];
|
|
111
|
+
const m = topLevel.match(/^\s*Digest:\s*(sha256:[a-f0-9]{64})/im);
|
|
112
|
+
return m ? m[1].toLowerCase() : null;
|
|
121
113
|
}
|
|
122
114
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
115
|
+
* Resolve the digest the REGISTRY currently serves for `<server>/<repository>:
|
|
116
|
+
* <tag>` via `docker buildx imagetools inspect`. Authoritative: it hits the
|
|
117
|
+
* registry, so — unlike a local `docker inspect ... .RepoDigests` read — a
|
|
118
|
+
* prior push of the same tag or a round-robin retry can never leave a STALE
|
|
119
|
+
* value here (#1679).
|
|
126
120
|
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
121
|
+
* @returns the `sha256:<64hex>` registry digest, or `null` if it could not be
|
|
122
|
+
* resolved (imagetools unavailable / registry unreachable / no digest line).
|
|
129
123
|
*/
|
|
130
|
-
async function
|
|
124
|
+
async function inspectRegistryDigest(registry, tag, spawnFn) {
|
|
131
125
|
const ref = imageRef(registry, tag);
|
|
132
|
-
const { code, stdout } = await runDocker(['
|
|
126
|
+
const { code, stdout, stderr } = await runDocker(['buildx', 'imagetools', 'inspect', ref], { spawnFn });
|
|
133
127
|
if (code !== 0)
|
|
134
128
|
return null;
|
|
135
|
-
return
|
|
129
|
+
return parseImagetoolsDigest(stdout + '\n' + stderr);
|
|
136
130
|
}
|
|
137
131
|
/**
|
|
138
|
-
* Push the backend image and RECORD
|
|
132
|
+
* Push the backend image and RECORD the digest the registry serves for it.
|
|
139
133
|
*
|
|
140
|
-
* Runs `docker push <server>/<repository>:<tag>`,
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
134
|
+
* Runs `docker push <server>/<repository>:<tag>`, then resolves the pushed
|
|
135
|
+
* tag's digest from the REGISTRY via {@link inspectRegistryDigest} (NOT the
|
|
136
|
+
* local daemon cache). The `digest: sha256:...` line from the push summary,
|
|
137
|
+
* when present, is cross-checked against the registry digest and a MISMATCH is
|
|
138
|
+
* a hard error — that is the #1679 failure mode (a DNS-round-robin split /
|
|
139
|
+
* same-tag re-push surfacing a stale local digest that disagrees with what
|
|
140
|
+
* Harbor actually stored). Throws if the push fails, if the registry digest
|
|
141
|
+
* can't be resolved, or on a push/registry mismatch — a deploy must never
|
|
142
|
+
* proceed with an unverifiable or stale artifact reference.
|
|
144
143
|
*
|
|
145
|
-
* @returns the `sha256:<64hex>` manifest digest of the pushed tag.
|
|
146
|
-
* @throws if push exits non-zero,
|
|
144
|
+
* @returns the `sha256:<64hex>` registry manifest digest of the pushed tag.
|
|
145
|
+
* @throws if push exits non-zero, the registry digest is unresolvable, or the
|
|
146
|
+
* push-summary digest disagrees with the registry.
|
|
147
147
|
*/
|
|
148
148
|
async function dockerPush(registry, tag, spawnFn) {
|
|
149
149
|
const ref = imageRef(registry, tag);
|
|
@@ -151,14 +151,18 @@ async function dockerPush(registry, tag, spawnFn) {
|
|
|
151
151
|
if (code !== 0) {
|
|
152
152
|
throw new Error(`docker push failed (exit ${code}): ${stderr.trim()}`);
|
|
153
153
|
}
|
|
154
|
+
const fromRegistry = await inspectRegistryDigest(registry, tag, spawnFn);
|
|
155
|
+
if (!fromRegistry) {
|
|
156
|
+
throw new Error(`pushed ${ref} but could not resolve its registry manifest digest via ` +
|
|
157
|
+
'`docker buildx imagetools inspect` (registry unreachable or buildx unavailable). ' +
|
|
158
|
+
'Refusing to attest an unverifiable artifact reference.');
|
|
159
|
+
}
|
|
154
160
|
const fromPush = parsePushDigest(stdout + '\n' + stderr);
|
|
155
|
-
if (fromPush)
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
'(no `digest: sha256:...` in push output and no matching RepoDigests). ' +
|
|
162
|
-
'Re-run with --image-digest <sha256:...> to supply it explicitly.');
|
|
161
|
+
if (fromPush && fromPush !== fromRegistry) {
|
|
162
|
+
throw new Error(`digest mismatch for ${ref}: push summary reported ${fromPush} but the registry ` +
|
|
163
|
+
`serves ${fromRegistry} (stale local digest / cross-cluster push split, #1679). ` +
|
|
164
|
+
'Refusing to attest a digest the registry does not serve.');
|
|
165
|
+
}
|
|
166
|
+
return fromRegistry;
|
|
163
167
|
}
|
|
164
168
|
//# sourceMappingURL=docker.js.map
|
package/dist/_lib/docker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docker.js","sourceRoot":"","sources":["../../src/_lib/docker.ts"],"names":[],"mappings":";;AAmEA,4BAEC;AAQD,kCAWC;AAaD,0CAIC;
|
|
1
|
+
{"version":3,"file":"docker.js","sourceRoot":"","sources":["../../src/_lib/docker.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RunFn } from './baas';
|
|
1
2
|
/**
|
|
2
3
|
* Fail-closed guard shared by `deploy` and `redeploy`: refuse to ship a
|
|
3
4
|
* frontend build that still carries unfilled `REPLACE_BEFORE_DEPLOY:<key>`
|
|
@@ -10,4 +11,62 @@
|
|
|
10
11
|
* false-positive on the guard's own comparison literal (`REPLACE_BEFORE_DEPLOY:"`).
|
|
11
12
|
*/
|
|
12
13
|
export declare function assertNoDeploySentinels(dir: string): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* #2793: `resolveFrontendBundle` (`deploy.ts` / `redeploy.ts`) `mkdir -p`s the
|
|
16
|
+
* frontend `dir` BEFORE spawning the optional `frontend.build` hook — required
|
|
17
|
+
* (#2790, load-bearing): `execFileSync(..., { cwd: dir })` throws `ENOENT` on a
|
|
18
|
+
* missing cwd, verified empirically. Side effect: the sibling `existsSync(dir)`
|
|
19
|
+
* guard that used to catch a build that never produced its output dir can now
|
|
20
|
+
* NEVER fire once a hook is configured — `dir` always exists post-`mkdir`,
|
|
21
|
+
* whether or not the hook actually wrote into it.
|
|
22
|
+
*
|
|
23
|
+
* Nothing downstream catches an empty dir either: `assertNoDeploySentinels`'s
|
|
24
|
+
* `readdir` walk is a no-op on zero files, `tarFrontend` happily tars nothing
|
|
25
|
+
* into a syntactically valid tar, and the host only logs `size=<n>B` with no
|
|
26
|
+
* minimum. Net effect without this guard: a `frontend.build` hook that exits 0
|
|
27
|
+
* without populating `dir` ships an empty SPA bundle, silently, with no error
|
|
28
|
+
* at any layer.
|
|
29
|
+
*
|
|
30
|
+
* Assert `dir` is plausibly a built SPA: non-empty, and containing
|
|
31
|
+
* `index.html` at its root — the shape the browser-build output this CLI
|
|
32
|
+
* targets always has (`ng build`'s legacy `browser` builder — the one every
|
|
33
|
+
* shipped manifest uses — writes `index.html` directly under `outputPath`,
|
|
34
|
+
* not nested). Call this AFTER the build hook runs, so the hook remains what
|
|
35
|
+
* is allowed to populate `dir` (mirrors the existsSync timing already moved
|
|
36
|
+
* post-hook by #2788) — the failure then names the hook that ran, not the
|
|
37
|
+
* upload step three calls later that would otherwise be blamed.
|
|
38
|
+
*
|
|
39
|
+
* #2795: `frontend.build` is OPTIONAL (`ManifestFrontend.build?`), and a bare
|
|
40
|
+
* `frontend.dir` — "a pre-built/checked-in SPA dir" — is a first-class
|
|
41
|
+
* documented manifest shape. That branch has the SAME empty-bundle failure
|
|
42
|
+
* mode for a different reason: `existsSync(dir)` never checked
|
|
43
|
+
* empty-vs-populated, so an EXISTING but EMPTY dir (wiped, mis-`.gitignore`'d,
|
|
44
|
+
* stale checkout, a typo'd `dir` that resolves to an existing folder) shipped
|
|
45
|
+
* silently too. So `buildHook` is optional: pass `f.build` straight through
|
|
46
|
+
* and the remedy names whatever was actually responsible for populating `dir`
|
|
47
|
+
* on this branch — never a hook that was never configured.
|
|
48
|
+
*/
|
|
49
|
+
export declare function assertPlausibleSpaBundle(dir: string, buildHook?: string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* #2798 / #2791: the `frontend.bundlePath` branch of `resolveFrontendBundle`
|
|
52
|
+
* (deploy.ts / redeploy.ts) — "a pre-built tarball; takes precedence over
|
|
53
|
+
* `dir` when set" (deploy-manifest.ts) — returned BEFORE both dir-shaped
|
|
54
|
+
* guards, so an empty/truncated tarball, or one still carrying unfilled
|
|
55
|
+
* `REPLACE_BEFORE_DEPLOY:*` placeholders, uploaded unvalidated. Same silent
|
|
56
|
+
* broken-bundle symptom #2793/#2795 closed for `dir`, plus the sentinel
|
|
57
|
+
* exposure #2788 exists to prevent.
|
|
58
|
+
*
|
|
59
|
+
* The artifact here is a TAR, not a directory, so `fs.readdir` does not
|
|
60
|
+
* apply. Plausibility is checked from the archive LISTING (`tar -tf`): the
|
|
61
|
+
* bundle the host mounts must contain `index.html` at its root (`tarFrontend
|
|
62
|
+
* `-C <dir> .` puts it there; any pre-built bundle missing it has the same
|
|
63
|
+
* wrong-shape failure `assertPlausibleSpaBundle` rejects) and must be
|
|
64
|
+
* non-empty. A zero-byte file — the "build created the file then died" shape
|
|
65
|
+
* — fails both the size floor and the listing, and is named as such.
|
|
66
|
+
*
|
|
67
|
+
* Sentinels (#2791): `assertNoDeploySentinels` walks a directory tree, so the
|
|
68
|
+
* tarball is unpacked to a throwaway temp dir and the EXISTING guard runs
|
|
69
|
+
* unchanged against it — one sentinel matcher, not two that can drift.
|
|
70
|
+
*/
|
|
71
|
+
export declare function assertPlausibleSpaTarball(tarPath: string, runFn?: RunFn): Promise<void>;
|
|
13
72
|
//# sourceMappingURL=frontend-guard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontend-guard.d.ts","sourceRoot":"","sources":["../../src/_lib/frontend-guard.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBxE"}
|
|
1
|
+
{"version":3,"file":"frontend-guard.d.ts","sourceRoot":"","sources":["../../src/_lib/frontend-guard.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBxE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB7F;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C7F"}
|
|
@@ -1,8 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.assertNoDeploySentinels = assertNoDeploySentinels;
|
|
37
|
+
exports.assertPlausibleSpaBundle = assertPlausibleSpaBundle;
|
|
38
|
+
exports.assertPlausibleSpaTarball = assertPlausibleSpaTarball;
|
|
4
39
|
const fs_1 = require("fs");
|
|
5
40
|
const path_1 = require("path");
|
|
41
|
+
const os_1 = require("os");
|
|
6
42
|
/**
|
|
7
43
|
* Fail-closed guard shared by `deploy` and `redeploy`: refuse to ship a
|
|
8
44
|
* frontend build that still carries unfilled `REPLACE_BEFORE_DEPLOY:<key>`
|
|
@@ -38,4 +74,116 @@ async function assertNoDeploySentinels(dir) {
|
|
|
38
74
|
(hits.length > 5 ? `, +${hits.length - 5} more` : ''));
|
|
39
75
|
}
|
|
40
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* #2793: `resolveFrontendBundle` (`deploy.ts` / `redeploy.ts`) `mkdir -p`s the
|
|
79
|
+
* frontend `dir` BEFORE spawning the optional `frontend.build` hook — required
|
|
80
|
+
* (#2790, load-bearing): `execFileSync(..., { cwd: dir })` throws `ENOENT` on a
|
|
81
|
+
* missing cwd, verified empirically. Side effect: the sibling `existsSync(dir)`
|
|
82
|
+
* guard that used to catch a build that never produced its output dir can now
|
|
83
|
+
* NEVER fire once a hook is configured — `dir` always exists post-`mkdir`,
|
|
84
|
+
* whether or not the hook actually wrote into it.
|
|
85
|
+
*
|
|
86
|
+
* Nothing downstream catches an empty dir either: `assertNoDeploySentinels`'s
|
|
87
|
+
* `readdir` walk is a no-op on zero files, `tarFrontend` happily tars nothing
|
|
88
|
+
* into a syntactically valid tar, and the host only logs `size=<n>B` with no
|
|
89
|
+
* minimum. Net effect without this guard: a `frontend.build` hook that exits 0
|
|
90
|
+
* without populating `dir` ships an empty SPA bundle, silently, with no error
|
|
91
|
+
* at any layer.
|
|
92
|
+
*
|
|
93
|
+
* Assert `dir` is plausibly a built SPA: non-empty, and containing
|
|
94
|
+
* `index.html` at its root — the shape the browser-build output this CLI
|
|
95
|
+
* targets always has (`ng build`'s legacy `browser` builder — the one every
|
|
96
|
+
* shipped manifest uses — writes `index.html` directly under `outputPath`,
|
|
97
|
+
* not nested). Call this AFTER the build hook runs, so the hook remains what
|
|
98
|
+
* is allowed to populate `dir` (mirrors the existsSync timing already moved
|
|
99
|
+
* post-hook by #2788) — the failure then names the hook that ran, not the
|
|
100
|
+
* upload step three calls later that would otherwise be blamed.
|
|
101
|
+
*
|
|
102
|
+
* #2795: `frontend.build` is OPTIONAL (`ManifestFrontend.build?`), and a bare
|
|
103
|
+
* `frontend.dir` — "a pre-built/checked-in SPA dir" — is a first-class
|
|
104
|
+
* documented manifest shape. That branch has the SAME empty-bundle failure
|
|
105
|
+
* mode for a different reason: `existsSync(dir)` never checked
|
|
106
|
+
* empty-vs-populated, so an EXISTING but EMPTY dir (wiped, mis-`.gitignore`'d,
|
|
107
|
+
* stale checkout, a typo'd `dir` that resolves to an existing folder) shipped
|
|
108
|
+
* silently too. So `buildHook` is optional: pass `f.build` straight through
|
|
109
|
+
* and the remedy names whatever was actually responsible for populating `dir`
|
|
110
|
+
* on this branch — never a hook that was never configured.
|
|
111
|
+
*/
|
|
112
|
+
async function assertPlausibleSpaBundle(dir, buildHook) {
|
|
113
|
+
const entries = await fs_1.promises.readdir(dir, { withFileTypes: true });
|
|
114
|
+
const hasIndexHtml = entries.some((e) => e.isFile() && e.name === 'index.html');
|
|
115
|
+
if (entries.length > 0 && hasIndexHtml)
|
|
116
|
+
return;
|
|
117
|
+
const reason = entries.length === 0 ? 'is empty' : 'has no index.html at its root';
|
|
118
|
+
throw new Error(buildHook
|
|
119
|
+
? `frontend build produced no usable SPA bundle: ${dir} ${reason}. The ` +
|
|
120
|
+
`frontend.build hook (\`${buildHook}\`) exited 0 without writing a bundle ` +
|
|
121
|
+
`into its own output dir — verify it actually builds INTO ${dir} ` +
|
|
122
|
+
`(a mismatched --output-path / missing \`cd\` is the usual cause).`
|
|
123
|
+
: `frontend build produced no usable SPA bundle: ${dir} ${reason}, and ` +
|
|
124
|
+
`no \`frontend.build\` hook is configured — a bare frontend.dir must ` +
|
|
125
|
+
`ALREADY contain a built SPA. Build it before deploying (or add a ` +
|
|
126
|
+
`\`frontend.build\` hook to the manifest), and check frontend.dir points ` +
|
|
127
|
+
`at the real build output.`);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* #2798 / #2791: the `frontend.bundlePath` branch of `resolveFrontendBundle`
|
|
131
|
+
* (deploy.ts / redeploy.ts) — "a pre-built tarball; takes precedence over
|
|
132
|
+
* `dir` when set" (deploy-manifest.ts) — returned BEFORE both dir-shaped
|
|
133
|
+
* guards, so an empty/truncated tarball, or one still carrying unfilled
|
|
134
|
+
* `REPLACE_BEFORE_DEPLOY:*` placeholders, uploaded unvalidated. Same silent
|
|
135
|
+
* broken-bundle symptom #2793/#2795 closed for `dir`, plus the sentinel
|
|
136
|
+
* exposure #2788 exists to prevent.
|
|
137
|
+
*
|
|
138
|
+
* The artifact here is a TAR, not a directory, so `fs.readdir` does not
|
|
139
|
+
* apply. Plausibility is checked from the archive LISTING (`tar -tf`): the
|
|
140
|
+
* bundle the host mounts must contain `index.html` at its root (`tarFrontend
|
|
141
|
+
* `-C <dir> .` puts it there; any pre-built bundle missing it has the same
|
|
142
|
+
* wrong-shape failure `assertPlausibleSpaBundle` rejects) and must be
|
|
143
|
+
* non-empty. A zero-byte file — the "build created the file then died" shape
|
|
144
|
+
* — fails both the size floor and the listing, and is named as such.
|
|
145
|
+
*
|
|
146
|
+
* Sentinels (#2791): `assertNoDeploySentinels` walks a directory tree, so the
|
|
147
|
+
* tarball is unpacked to a throwaway temp dir and the EXISTING guard runs
|
|
148
|
+
* unchanged against it — one sentinel matcher, not two that can drift.
|
|
149
|
+
*/
|
|
150
|
+
async function assertPlausibleSpaTarball(tarPath, runFn) {
|
|
151
|
+
const st = await fs_1.promises.stat(tarPath).catch(() => {
|
|
152
|
+
throw new Error(`frontend bundle not found: ${tarPath}`);
|
|
153
|
+
});
|
|
154
|
+
if (st.size === 0) {
|
|
155
|
+
throw new Error(`frontend bundle is a ZERO-BYTE file: ${tarPath}. A build that created ` +
|
|
156
|
+
`the tarball then died before writing it — rebuild it before deploying.`);
|
|
157
|
+
}
|
|
158
|
+
const run = runFn ?? (await Promise.resolve().then(() => __importStar(require('child_process')))).execFileSync;
|
|
159
|
+
let listing;
|
|
160
|
+
try {
|
|
161
|
+
listing = run('tar', ['-tf', tarPath], { encoding: 'utf8' });
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
throw new Error(`frontend bundle is not a readable tar archive: ${tarPath}. Rebuild it ` +
|
|
165
|
+
`before deploying (a truncated or partially-uploaded tar fails here).`);
|
|
166
|
+
}
|
|
167
|
+
const entries = listing
|
|
168
|
+
.split('\n')
|
|
169
|
+
.map((l) => l.trim())
|
|
170
|
+
.filter(Boolean);
|
|
171
|
+
const hasRootIndex = entries.some((e) => e === './index.html' || e === 'index.html');
|
|
172
|
+
if (!hasRootIndex) {
|
|
173
|
+
throw new Error(`frontend bundle has no index.html at its root: ${tarPath} (entries: ` +
|
|
174
|
+
`${entries.slice(0, 5).join(', ')}${entries.length > 5 ? `, +${entries.length - 5} more` : ''}). ` +
|
|
175
|
+
`The bundle root must contain the built SPA — the same shape ` +
|
|
176
|
+
`assertPlausibleSpaBundle enforces for frontend.dir.`);
|
|
177
|
+
}
|
|
178
|
+
// #2791: run the UNCHANGED dir-shaped sentinel walk over the unpacked
|
|
179
|
+
// bundle. Temp dir is under os.tmpdir() and best-effort removed after.
|
|
180
|
+
const probe = await fs_1.promises.mkdtemp((0, path_1.join)((0, os_1.tmpdir)(), 'hsuite-bundlepath-'));
|
|
181
|
+
try {
|
|
182
|
+
run('tar', ['-xf', tarPath, '-C', probe], {});
|
|
183
|
+
await assertNoDeploySentinels(probe);
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
await fs_1.promises.rm(probe, { recursive: true, force: true }).catch(() => undefined);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
41
189
|
//# sourceMappingURL=frontend-guard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontend-guard.js","sourceRoot":"","sources":["../../src/_lib/frontend-guard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"frontend-guard.js","sourceRoot":"","sources":["../../src/_lib/frontend-guard.ts"],"names":[],"mappings":"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"}
|