anton-bakker-deploy-engine 0.7.13 → 0.9.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 +54 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +7 -2
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/ingest-verify.d.ts +172 -0
- package/dist/ingest-verify.d.ts.map +1 -0
- package/dist/ingest-verify.js +261 -0
- package/dist/ingest-verify.js.map +1 -0
- package/dist/telemetry.d.ts +70 -1
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +90 -0
- package/dist/telemetry.js.map +1 -1
- package/dist/tui.d.ts +34 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +73 -5
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +98 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ingest-verify.ts
|
|
3
|
+
* Location: anton-bakker-deploy-engine/src/ingest-verify.ts
|
|
4
|
+
*
|
|
5
|
+
* Verification gate for the CENTRAL INGEST storage principle (ralph central-ingest-service).
|
|
6
|
+
*
|
|
7
|
+
* The central store is reached ONLY through an authenticated API: a consuming application mints a
|
|
8
|
+
* short-lived JWT from the issuer (OAuth2 client-credentials, M2M) and writes records to the generic
|
|
9
|
+
* `/records/{collection}` ingest API using that token. The application holds no AWS principal; the
|
|
10
|
+
* server attributes every write to the verified token identity (the `client_id` claim) and enforces
|
|
11
|
+
* "own data only" — a token for app A cannot touch app B's records.
|
|
12
|
+
*
|
|
13
|
+
* This module is deploy-engine's FUNCTIONAL verification of that principle for a given app: it proves,
|
|
14
|
+
* end-to-end against the live deployment, that the app can obtain a token, write its own record, and
|
|
15
|
+
* is correctly BLOCKED from another app's partition and from writing without the right scope. It is
|
|
16
|
+
* the gate the central-ingest design calls for ("deploy-engine can provision a new app's credential
|
|
17
|
+
* and verify it end-to-end — mint token → write own record → 403 on another app's partition").
|
|
18
|
+
*
|
|
19
|
+
* Design posture (matches this package):
|
|
20
|
+
* - Zero new runtime deps: token mint + API calls use Node's built-in `fetch` (injectable for tests).
|
|
21
|
+
* - The AWS SDK is used ONLY for the optional SSM client-id discovery helper, and is lazy-imported
|
|
22
|
+
* (dynamic import) so it stays an optional dependency.
|
|
23
|
+
* - Every check returns the shared `CheckResult`, so these compose into the normal gate pipeline.
|
|
24
|
+
* - Nothing is hardcoded: endpoints, token URL, client ids and scopes are all parameters/SSM.
|
|
25
|
+
*
|
|
26
|
+
* @module ingest-verify
|
|
27
|
+
*/
|
|
28
|
+
/** OAuth2 scope that authorises an ingest WRITE (namespaced under the asset resource server). */
|
|
29
|
+
export const INGEST_WRITE_SCOPE = 'assets/write';
|
|
30
|
+
/** OAuth2 scope that authorises an ingest own-data READ. */
|
|
31
|
+
export const INGEST_READ_SCOPE = 'assets/read';
|
|
32
|
+
function assertHttps(url, label) {
|
|
33
|
+
let u;
|
|
34
|
+
try {
|
|
35
|
+
u = new URL(url);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
throw new Error(`ingest-verify: ${label} is not a valid URL: ${url}`);
|
|
39
|
+
}
|
|
40
|
+
if (u.protocol !== 'https:') {
|
|
41
|
+
throw new Error(`ingest-verify: ${label} must be https:// (got ${u.protocol}//) — refusing plaintext`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Mint a short-lived JWT via the OAuth2 client-credentials grant. Pure HTTP (no AWS SDK). Throws on a
|
|
46
|
+
* transport/credential failure so a verification check can surface it as a failed CheckResult.
|
|
47
|
+
*
|
|
48
|
+
* @param cfg endpoint config (tokenUrl)
|
|
49
|
+
* @param cred the app's client id + secret
|
|
50
|
+
* @param scope space-delimited scopes to request (default: write + read)
|
|
51
|
+
* @param deps.fetchImpl injectable fetch (tests)
|
|
52
|
+
*/
|
|
53
|
+
export async function mintClientCredentialsToken(cfg, cred, scope = `${INGEST_WRITE_SCOPE} ${INGEST_READ_SCOPE}`, deps = {}) {
|
|
54
|
+
assertHttps(cfg.tokenUrl, 'tokenUrl');
|
|
55
|
+
const doFetch = deps.fetchImpl ?? globalThis.fetch;
|
|
56
|
+
if (typeof doFetch !== 'function')
|
|
57
|
+
throw new Error('ingest-verify: no fetch implementation available');
|
|
58
|
+
const basic = Buffer.from(`${cred.clientId}:${cred.clientSecret}`).toString('base64');
|
|
59
|
+
const res = await doFetch(cfg.tokenUrl, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
63
|
+
authorization: `Basic ${basic}`,
|
|
64
|
+
},
|
|
65
|
+
body: `grant_type=client_credentials&scope=${encodeURIComponent(scope)}`,
|
|
66
|
+
});
|
|
67
|
+
const data = (await res.json());
|
|
68
|
+
if (!res.ok || !data.access_token) {
|
|
69
|
+
throw new Error(`ingest-verify: token mint failed (${res.status}): ${data.error || ''} ${data.error_description || ''}`.trim());
|
|
70
|
+
}
|
|
71
|
+
return { accessToken: data.access_token, tokenType: data.token_type ?? 'Bearer', expiresIn: data.expires_in ?? 0 };
|
|
72
|
+
}
|
|
73
|
+
/** Internal: make an authenticated ingest API call, returning the raw status + parsed body. */
|
|
74
|
+
async function ingestCall(cfg, token, method, path, body, doFetch) {
|
|
75
|
+
const base = cfg.apiUrl.replace(/\/$/, '');
|
|
76
|
+
const res = await doFetch(`${base}${path}`, {
|
|
77
|
+
method,
|
|
78
|
+
headers: {
|
|
79
|
+
authorization: `Bearer ${token}`,
|
|
80
|
+
...(body !== undefined ? { 'content-type': 'application/json' } : {}),
|
|
81
|
+
accept: 'application/json',
|
|
82
|
+
},
|
|
83
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
84
|
+
});
|
|
85
|
+
let parsed = {};
|
|
86
|
+
try {
|
|
87
|
+
parsed = (await res.json());
|
|
88
|
+
}
|
|
89
|
+
catch { /* non-JSON */ }
|
|
90
|
+
return { status: res.status, body: parsed };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Verify an app can WRITE its own record through the ingest API (functional check).
|
|
94
|
+
* Mints a write-scoped token, POSTs a record to `/records/{collection}`, and asserts 200 + success.
|
|
95
|
+
*
|
|
96
|
+
* @returns CheckResult — passed when the write returns 200 and `{ success: true }`.
|
|
97
|
+
*/
|
|
98
|
+
export async function verifyIngestWrite(opts) {
|
|
99
|
+
const name = `ingest write (${opts.collection})`;
|
|
100
|
+
const doFetch = opts.fetchImpl ?? globalThis.fetch;
|
|
101
|
+
const started = Date.now();
|
|
102
|
+
try {
|
|
103
|
+
assertHttps(opts.endpoint.apiUrl, 'apiUrl');
|
|
104
|
+
const token = await mintClientCredentialsToken(opts.endpoint, opts.credential, INGEST_WRITE_SCOPE, { fetchImpl: doFetch });
|
|
105
|
+
const { status, body } = await ingestCall(opts.endpoint, token.accessToken, 'POST', `/records/${encodeURIComponent(opts.collection)}`, { item: opts.item }, doFetch);
|
|
106
|
+
const passed = status === 200 && body.success === true;
|
|
107
|
+
return {
|
|
108
|
+
name,
|
|
109
|
+
passed,
|
|
110
|
+
expected: '200 { success: true }',
|
|
111
|
+
actual: `${status} ${JSON.stringify(body).slice(0, 120)}`,
|
|
112
|
+
duration: Date.now() - started,
|
|
113
|
+
error: passed ? undefined : `write did not succeed (status ${status})`,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
return { name, passed: false, expected: '200 { success: true }', actual: 'exception', error: err.message, duration: Date.now() - started };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Verify OWN-DATA isolation: a token for `attacker` must NOT be able to mutate a record owned by
|
|
122
|
+
* `victimApp`. Attempts a PATCH on `/records/{collection}/{victimRecordId}` with the attacker token
|
|
123
|
+
* and asserts the server REJECTS it (403 forbidden-cross-app, or 404 because the record is invisible
|
|
124
|
+
* across the partition wall). A 200 here is a critical isolation failure.
|
|
125
|
+
*
|
|
126
|
+
* @returns CheckResult — passed when the cross-app mutation is rejected (403 or 404).
|
|
127
|
+
*/
|
|
128
|
+
export async function verifyOwnDataIsolation(opts) {
|
|
129
|
+
const name = `ingest own-data isolation (${opts.collection})`;
|
|
130
|
+
const doFetch = opts.fetchImpl ?? globalThis.fetch;
|
|
131
|
+
const started = Date.now();
|
|
132
|
+
try {
|
|
133
|
+
assertHttps(opts.endpoint.apiUrl, 'apiUrl');
|
|
134
|
+
const token = await mintClientCredentialsToken(opts.endpoint, opts.attackerCredential, `${INGEST_WRITE_SCOPE} ${INGEST_READ_SCOPE}`, { fetchImpl: doFetch });
|
|
135
|
+
const { status, body } = await ingestCall(opts.endpoint, token.accessToken, 'PATCH', `/records/${encodeURIComponent(opts.collection)}/${encodeURIComponent(opts.victimRecordId)}`, { patch: { status: 'tampered' } }, doFetch);
|
|
136
|
+
// Rejection = isolation holds. 403 (forbidden cross-app) or 404 (invisible across partition).
|
|
137
|
+
const passed = status === 403 || status === 404;
|
|
138
|
+
return {
|
|
139
|
+
name,
|
|
140
|
+
passed,
|
|
141
|
+
expected: '403 or 404 (cross-app rejected)',
|
|
142
|
+
actual: `${status} ${JSON.stringify(body).slice(0, 120)}`,
|
|
143
|
+
duration: Date.now() - started,
|
|
144
|
+
error: passed ? undefined : `CRITICAL: cross-app mutation was NOT rejected (status ${status}) — own-data isolation is broken`,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
return { name, passed: false, expected: '403 or 404 (cross-app rejected)', actual: 'exception', error: err.message, duration: Date.now() - started };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Verify a token WITHOUT the write scope is rejected when it attempts a write (gateway scope
|
|
153
|
+
* enforcement). Mints a read-only token and POSTs; asserts 403.
|
|
154
|
+
*
|
|
155
|
+
* @returns CheckResult — passed when the scopeless write is rejected (403).
|
|
156
|
+
*/
|
|
157
|
+
export async function verifyWriteScopeEnforced(opts) {
|
|
158
|
+
const name = `ingest write-scope enforced (${opts.collection})`;
|
|
159
|
+
const doFetch = opts.fetchImpl ?? globalThis.fetch;
|
|
160
|
+
const started = Date.now();
|
|
161
|
+
try {
|
|
162
|
+
assertHttps(opts.endpoint.apiUrl, 'apiUrl');
|
|
163
|
+
const token = await mintClientCredentialsToken(opts.endpoint, opts.credential, INGEST_READ_SCOPE, { fetchImpl: doFetch });
|
|
164
|
+
const { status } = await ingestCall(opts.endpoint, token.accessToken, 'POST', `/records/${encodeURIComponent(opts.collection)}`, { item: { description: 'scope-check — must be rejected' } }, doFetch);
|
|
165
|
+
const passed = status === 403;
|
|
166
|
+
return {
|
|
167
|
+
name,
|
|
168
|
+
passed,
|
|
169
|
+
expected: '403 (missing assets/write)',
|
|
170
|
+
actual: String(status),
|
|
171
|
+
duration: Date.now() - started,
|
|
172
|
+
error: passed ? undefined : `CRITICAL: a read-only token was allowed to write (status ${status})`,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
return { name, passed: false, expected: '403 (missing assets/write)', actual: 'exception', error: err.message, duration: Date.now() - started };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* End-to-end ingest access verification for a newly-provisioned app (the central-ingest AC-5 gate).
|
|
181
|
+
*
|
|
182
|
+
* Runs, in order:
|
|
183
|
+
* 1. the app writes its OWN record (expect 200);
|
|
184
|
+
* 2. the app's token is BLOCKED from a victim app's record (expect 403/404); [if a victim is given]
|
|
185
|
+
* 3. a read-only token is BLOCKED from writing (expect 403). [optional]
|
|
186
|
+
*
|
|
187
|
+
* Returns the individual CheckResults — compose them into a gate with `summarize` (from verify.ts).
|
|
188
|
+
*
|
|
189
|
+
* @param opts.verifyItem the record the app writes in step 1 (content only). A unique id is
|
|
190
|
+
* recommended so the written record can be cleaned up by the caller.
|
|
191
|
+
*/
|
|
192
|
+
export async function verifyIngestAccess(opts) {
|
|
193
|
+
const results = [];
|
|
194
|
+
results.push(await verifyIngestWrite({
|
|
195
|
+
endpoint: opts.endpoint, credential: opts.credential, collection: opts.collection, item: opts.verifyItem, fetchImpl: opts.fetchImpl,
|
|
196
|
+
}));
|
|
197
|
+
if (opts.isolation) {
|
|
198
|
+
results.push(await verifyOwnDataIsolation({
|
|
199
|
+
endpoint: opts.endpoint, attackerCredential: opts.credential, collection: opts.collection,
|
|
200
|
+
victimRecordId: opts.isolation.victimRecordId, fetchImpl: opts.fetchImpl,
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
if (opts.checkScopeEnforcement !== false) {
|
|
204
|
+
results.push(await verifyWriteScopeEnforced({
|
|
205
|
+
endpoint: opts.endpoint, credential: opts.credential, collection: opts.collection, fetchImpl: opts.fetchImpl,
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
return results;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Discover a provisioned app's ingest client id from SSM (published by the ingest CDK stack at
|
|
212
|
+
* `/ralph/ingest-service/apps/<app>/client-id`). The AWS SDK is lazy-imported so it stays optional —
|
|
213
|
+
* callers that already know the client id (e.g. from stack outputs) need not use this.
|
|
214
|
+
*
|
|
215
|
+
* Note: this returns only the NON-SECRET client id. The client SECRET must be resolved out-of-band
|
|
216
|
+
* (SSM SecureString / password manager) and never logged or committed.
|
|
217
|
+
*
|
|
218
|
+
* @param appName the application name
|
|
219
|
+
* @param opts.region AWS region (default from AWS_REGION)
|
|
220
|
+
* @param opts.ssmPrefix SSM path prefix (default /ralph/ingest-service/apps)
|
|
221
|
+
* @param opts.ssmClient injectable SSM client (tests)
|
|
222
|
+
* @returns the client id, or null if the parameter is absent
|
|
223
|
+
*/
|
|
224
|
+
export async function resolveIngestClientId(appName, opts = {}) {
|
|
225
|
+
const prefix = opts.ssmPrefix ?? '/ralph/ingest-service/apps';
|
|
226
|
+
const paramName = `${prefix}/${appName}/client-id`;
|
|
227
|
+
let client = opts.ssmClient;
|
|
228
|
+
let GetParameterCommand;
|
|
229
|
+
if (!client) {
|
|
230
|
+
// `@aws-sdk/client-ssm` is an OPTIONAL dependency, so there are no compile-time types for it here;
|
|
231
|
+
// the dynamic import is typed as unknown and narrowed at runtime. This is the standard pattern for
|
|
232
|
+
// an optional peer the package does not force on every consumer.
|
|
233
|
+
let sdk;
|
|
234
|
+
try {
|
|
235
|
+
sdk = (await import(/* @vite-ignore */ '@aws-sdk/client-ssm'));
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
// Fail LOUD and actionable — never silent. Consumers without the optional dep can pass the
|
|
239
|
+
// client id directly (it is available from the ingest CDK stack outputs).
|
|
240
|
+
throw new Error('ingest-verify: resolveIngestClientId needs "@aws-sdk/client-ssm" (optional dependency). '
|
|
241
|
+
+ 'Install it, or pass the client id directly (e.g. from the ingest stack output / known value).');
|
|
242
|
+
}
|
|
243
|
+
GetParameterCommand = sdk.GetParameterCommand;
|
|
244
|
+
client = new sdk.SSMClient(opts.region ? { region: opts.region } : {});
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
// Injected client: provide a minimal command shape it will recognise in tests.
|
|
248
|
+
GetParameterCommand = class {
|
|
249
|
+
input;
|
|
250
|
+
constructor(input) { this.input = input; }
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
const out = await client.send(new GetParameterCommand({ Name: paramName }));
|
|
255
|
+
return out.Parameter?.Value ?? null;
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=ingest-verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest-verify.js","sourceRoot":"","sources":["../src/ingest-verify.ts"],"names":[],"mappings":"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"}
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Uses dynamic import for @aws-sdk/client-dynamodb to preserve the
|
|
7
7
|
* zero-hard-dependency contract (consumer must install the SDK).
|
|
8
8
|
*/
|
|
9
|
-
import type { DeployEvent, TelemetryConfig, PipelineState, ExecutionContext, GateSummaryEntry } from './types.js';
|
|
9
|
+
import type { DeployEvent, TelemetryConfig, PipelineState, ExecutionContext, GateSummaryEntry, GroupSummaryEntry } from './types.js';
|
|
10
10
|
/**
|
|
11
11
|
* Build a DeployEvent from a finalised PipelineState and TelemetryConfig.
|
|
12
12
|
* Pure function — no side effects, no I/O.
|
|
@@ -40,4 +40,73 @@ export declare function recordTelemetry(ctx: ExecutionContext, state: PipelineSt
|
|
|
40
40
|
* - Never throws — all errors swallowed
|
|
41
41
|
*/
|
|
42
42
|
export declare function emitGateEvent(ctx: ExecutionContext, state: PipelineState, gate: GateSummaryEntry): void;
|
|
43
|
+
/**
|
|
44
|
+
* Context for a group event — shared fields needed by emitGroupEvent.
|
|
45
|
+
*/
|
|
46
|
+
export interface GroupEventContext {
|
|
47
|
+
/** ISO 8601 start timestamp of the overall deploy run */
|
|
48
|
+
startedAt: string;
|
|
49
|
+
/** Environment name (e.g. 'staging') */
|
|
50
|
+
environment: string;
|
|
51
|
+
/** Full git commit SHA */
|
|
52
|
+
commit: string;
|
|
53
|
+
/** 7-character short commit SHA */
|
|
54
|
+
commitShort: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Payload for a single group telemetry event.
|
|
58
|
+
*/
|
|
59
|
+
export interface GroupEventPayload {
|
|
60
|
+
/** Parent gate ID */
|
|
61
|
+
gateId: string;
|
|
62
|
+
/** Group ID */
|
|
63
|
+
groupId: string;
|
|
64
|
+
/** Human-readable group name */
|
|
65
|
+
name: string;
|
|
66
|
+
/** Failure mode for this group */
|
|
67
|
+
failureMode: 'fail-fast' | 'accumulate';
|
|
68
|
+
/** Group outcome */
|
|
69
|
+
status: 'passed' | 'failed' | 'skipped';
|
|
70
|
+
/** Duration in milliseconds */
|
|
71
|
+
duration: number;
|
|
72
|
+
/** Total number of checks in the group */
|
|
73
|
+
checksCount: number;
|
|
74
|
+
/** Optional group summary for gate event */
|
|
75
|
+
groupSummary?: GroupSummaryEntry[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Payload for a single check telemetry event.
|
|
79
|
+
*/
|
|
80
|
+
export interface CheckEventPayload {
|
|
81
|
+
/** Parent gate ID */
|
|
82
|
+
gateId: string;
|
|
83
|
+
/** Check name */
|
|
84
|
+
checkName: string;
|
|
85
|
+
/** Check outcome */
|
|
86
|
+
status: 'passed' | 'failed';
|
|
87
|
+
/** Duration in milliseconds */
|
|
88
|
+
duration: number;
|
|
89
|
+
/** Error message if status is 'failed' */
|
|
90
|
+
error?: string;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Fire-and-forget: emit a single group completion event to DynamoDB.
|
|
94
|
+
*
|
|
95
|
+
* SK pattern: `group#{startedAt}#{gateId}#{groupId}`
|
|
96
|
+
*
|
|
97
|
+
* Guards:
|
|
98
|
+
* - Returns immediately if ctx.telemetry is absent or ctx.dryRun is true
|
|
99
|
+
* - Never throws — all errors swallowed
|
|
100
|
+
*/
|
|
101
|
+
export declare function emitGroupEvent(ctx: ExecutionContext, deployCtx: GroupEventContext, payload: GroupEventPayload): void;
|
|
102
|
+
/**
|
|
103
|
+
* Fire-and-forget: emit a single check completion event to DynamoDB.
|
|
104
|
+
*
|
|
105
|
+
* SK pattern: `check#{startedAt}#{gateId}#{checkName}`
|
|
106
|
+
*
|
|
107
|
+
* Guards:
|
|
108
|
+
* - Returns immediately if ctx.telemetry is absent or ctx.dryRun is true
|
|
109
|
+
* - Never throws — all errors swallowed
|
|
110
|
+
*/
|
|
111
|
+
export declare function emitCheckEvent(ctx: ExecutionContext, deployCtx: GroupEventContext, payload: CheckEventPayload): void;
|
|
43
112
|
//# sourceMappingURL=telemetry.d.ts.map
|
package/dist/telemetry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAErI;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,GAAG,WAAW,CAmC3F;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BpG;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAkCvG;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,qBAAqB;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,WAAW,EAAE,WAAW,GAAG,YAAY,CAAC;IACxC,oBAAoB;IACpB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxC,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,qBAAqB;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB;IACpB,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,iBAAiB,GACzB,IAAI,CAsCN;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,iBAAiB,GACzB,IAAI,CAuCN"}
|
package/dist/telemetry.js
CHANGED
|
@@ -140,4 +140,94 @@ export function emitGateEvent(ctx, state, gate) {
|
|
|
140
140
|
}
|
|
141
141
|
})();
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Fire-and-forget: emit a single group completion event to DynamoDB.
|
|
145
|
+
*
|
|
146
|
+
* SK pattern: `group#{startedAt}#{gateId}#{groupId}`
|
|
147
|
+
*
|
|
148
|
+
* Guards:
|
|
149
|
+
* - Returns immediately if ctx.telemetry is absent or ctx.dryRun is true
|
|
150
|
+
* - Never throws — all errors swallowed
|
|
151
|
+
*/
|
|
152
|
+
export function emitGroupEvent(ctx, deployCtx, payload) {
|
|
153
|
+
if (!ctx.telemetry || ctx.dryRun)
|
|
154
|
+
return;
|
|
155
|
+
const config = ctx.telemetry;
|
|
156
|
+
void (async () => {
|
|
157
|
+
try {
|
|
158
|
+
const { DynamoDBClient } = await import('@aws-sdk/client-dynamodb');
|
|
159
|
+
const { DynamoDBDocumentClient, PutCommand } = await import('@aws-sdk/lib-dynamodb');
|
|
160
|
+
const client = DynamoDBDocumentClient.from(new DynamoDBClient({ region: config.region }));
|
|
161
|
+
const item = {
|
|
162
|
+
pk: `project#${config.projectId}`,
|
|
163
|
+
sk: `group#${deployCtx.startedAt}#${payload.gateId}#${payload.groupId}`,
|
|
164
|
+
projectId: config.projectId,
|
|
165
|
+
environment: deployCtx.environment,
|
|
166
|
+
commit: deployCtx.commit,
|
|
167
|
+
commitShort: deployCtx.commitShort,
|
|
168
|
+
gateId: payload.gateId,
|
|
169
|
+
id: payload.groupId,
|
|
170
|
+
name: payload.name,
|
|
171
|
+
failureMode: payload.failureMode,
|
|
172
|
+
status: payload.status,
|
|
173
|
+
duration: payload.duration,
|
|
174
|
+
checks: payload.checksCount,
|
|
175
|
+
recordedAt: new Date().toISOString(),
|
|
176
|
+
ttl: Math.floor(Date.now() / 1000) + 7_776_000, // 90 days
|
|
177
|
+
};
|
|
178
|
+
await client.send(new PutCommand({
|
|
179
|
+
TableName: config.tableName,
|
|
180
|
+
Item: item,
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Fire-and-forget — never block the pipeline
|
|
185
|
+
}
|
|
186
|
+
})();
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Fire-and-forget: emit a single check completion event to DynamoDB.
|
|
190
|
+
*
|
|
191
|
+
* SK pattern: `check#{startedAt}#{gateId}#{checkName}`
|
|
192
|
+
*
|
|
193
|
+
* Guards:
|
|
194
|
+
* - Returns immediately if ctx.telemetry is absent or ctx.dryRun is true
|
|
195
|
+
* - Never throws — all errors swallowed
|
|
196
|
+
*/
|
|
197
|
+
export function emitCheckEvent(ctx, deployCtx, payload) {
|
|
198
|
+
if (!ctx.telemetry || ctx.dryRun)
|
|
199
|
+
return;
|
|
200
|
+
const config = ctx.telemetry;
|
|
201
|
+
void (async () => {
|
|
202
|
+
try {
|
|
203
|
+
const { DynamoDBClient } = await import('@aws-sdk/client-dynamodb');
|
|
204
|
+
const { DynamoDBDocumentClient, PutCommand } = await import('@aws-sdk/lib-dynamodb');
|
|
205
|
+
const client = DynamoDBDocumentClient.from(new DynamoDBClient({ region: config.region }));
|
|
206
|
+
const item = {
|
|
207
|
+
pk: `project#${config.projectId}`,
|
|
208
|
+
sk: `check#${deployCtx.startedAt}#${payload.gateId}#${payload.checkName}`,
|
|
209
|
+
projectId: config.projectId,
|
|
210
|
+
environment: deployCtx.environment,
|
|
211
|
+
commit: deployCtx.commit,
|
|
212
|
+
commitShort: deployCtx.commitShort,
|
|
213
|
+
gateId: payload.gateId,
|
|
214
|
+
checkName: payload.checkName,
|
|
215
|
+
status: payload.status,
|
|
216
|
+
duration: payload.duration,
|
|
217
|
+
recordedAt: new Date().toISOString(),
|
|
218
|
+
ttl: Math.floor(Date.now() / 1000) + 7_776_000, // 90 days
|
|
219
|
+
};
|
|
220
|
+
if (payload.error !== undefined) {
|
|
221
|
+
item.error = payload.error;
|
|
222
|
+
}
|
|
223
|
+
await client.send(new PutCommand({
|
|
224
|
+
TableName: config.tableName,
|
|
225
|
+
Item: item,
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
// Fire-and-forget — never block the pipeline
|
|
230
|
+
}
|
|
231
|
+
})();
|
|
232
|
+
}
|
|
143
233
|
//# sourceMappingURL=telemetry.js.map
|
package/dist/telemetry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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"}
|
package/dist/tui.d.ts
CHANGED
|
@@ -10,6 +10,13 @@ export interface Step {
|
|
|
10
10
|
status: StepStatus;
|
|
11
11
|
durationMs?: number;
|
|
12
12
|
error?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Bounded live-progress detail for a long-running step (e.g. GSI convergence,
|
|
15
|
+
* CDK deploy). Rendered as an indented region beneath the step while it is
|
|
16
|
+
* `running`, and collapsed (cleared) once the step reaches a terminal status.
|
|
17
|
+
* Only the most recent {@link MAX_STEP_DETAIL_LINES} lines are retained.
|
|
18
|
+
*/
|
|
19
|
+
detail?: string[];
|
|
13
20
|
}
|
|
14
21
|
export interface Category {
|
|
15
22
|
name: string;
|
|
@@ -25,6 +32,12 @@ export interface TuiState {
|
|
|
25
32
|
errorOutput?: string;
|
|
26
33
|
startedAt: number;
|
|
27
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Maximum number of live-detail lines retained and rendered for a running step.
|
|
37
|
+
* The detail region is height-bounded: appending more lines drops the oldest,
|
|
38
|
+
* so a long-running step never grows the layout or scrolls the panel off-screen.
|
|
39
|
+
*/
|
|
40
|
+
export declare const MAX_STEP_DETAIL_LINES = 8;
|
|
28
41
|
/**
|
|
29
42
|
* Render full-screen frame.
|
|
30
43
|
*/
|
|
@@ -46,10 +59,31 @@ export declare class DeployTui {
|
|
|
46
59
|
stop(): void;
|
|
47
60
|
private render;
|
|
48
61
|
private ciLog;
|
|
62
|
+
/**
|
|
63
|
+
* Emit live-detail lines to the CI log (no alt-screen). Keeps progress of a
|
|
64
|
+
* long-running step visible in CI output, where the interactive panel is not
|
|
65
|
+
* rendered. Each line is prefixed so it is greppable alongside ciLog output.
|
|
66
|
+
*/
|
|
67
|
+
private ciDetail;
|
|
49
68
|
startCategory(index: number): void;
|
|
50
69
|
passCategory(index: number, durationMs: number): void;
|
|
51
70
|
failCategory(index: number, durationMs: number): void;
|
|
52
71
|
startStep(catIndex: number, stepIndex: number): void;
|
|
72
|
+
/**
|
|
73
|
+
* Append bounded live-progress detail to a running step.
|
|
74
|
+
*
|
|
75
|
+
* The step's detail region shows the most recent {@link MAX_STEP_DETAIL_LINES}
|
|
76
|
+
* lines; appending more drops the oldest (no unbounded growth, no layout
|
|
77
|
+
* break). In TUI mode the lines render indented beneath the running step; in
|
|
78
|
+
* CI mode they are logged (no alt-screen) so progress stays visible in CI logs.
|
|
79
|
+
*
|
|
80
|
+
* This is additive: steps that never call stepDetail render exactly as before.
|
|
81
|
+
*
|
|
82
|
+
* @param catIndex Category index
|
|
83
|
+
* @param stepIndex Step index within the category
|
|
84
|
+
* @param lines New detail lines to append (already human-readable)
|
|
85
|
+
*/
|
|
86
|
+
stepDetail(catIndex: number, stepIndex: number, lines: string[]): void;
|
|
53
87
|
passStep(catIndex: number, stepIndex: number, durationMs: number): void;
|
|
54
88
|
failStep(catIndex: number, stepIndex: number, durationMs: number, error: string): void;
|
|
55
89
|
skipStep(catIndex: number, stepIndex: number): void;
|
package/dist/tui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwBH,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEjF,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,QAAQ,EAAE,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,IAAI,CAAC;AA+DvC;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CA4GnD;AAED;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,aAAa,CAA6B;gBAEtC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE;IAe/F,KAAK,IAAI,IAAI;IAyBb,IAAI,IAAI,IAAI;IAeZ,OAAO,CAAC,MAAM;IAOd,OAAO,CAAC,KAAK;IAOb;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAOhB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOlC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAMrD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAMrD,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAMpD;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAYtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAUvE,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAWtF,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAMnD,sEAAsE;IACtE,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;CAa3D"}
|