@empire-builder-kit/nx 1.0.0-rc.40 → 1.0.0-rc.41
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 +26 -10
- package/package.json +3 -3
- package/src/blueprints/external-sandbox.d.ts +1 -1
- package/src/cli/deploy-runtime.d.ts +25 -1
- package/src/cli/deploy-runtime.js +120 -4
- package/src/cli/dev-command.d.ts +2 -0
- package/src/cli/dev-command.js +8 -0
- package/src/cli/main.js +20 -6
- package/src/cli/personal-secret-runtime.d.ts +12 -0
- package/src/cli/personal-secret-runtime.js +18 -3
- package/src/cli/secret-terminal.js +1 -1
- package/src/container-images.d.ts +1 -1
- package/src/container-images.js +1 -1
- package/src/developer-agent/operation-registry.d.ts +10 -0
- package/src/developer-agent/operation-registry.js +60 -13
- package/src/developer-agent/planning.d.ts +8 -1
- package/src/developer-agent/planning.js +23 -3
- package/src/executors/local-deploy/local-approval.js +1 -1
- package/src/executors/sst-lifecycle/governed-native-operation.js +3 -2
- package/src/executors/sst-lifecycle/run-sst-command.d.ts +6 -0
- package/src/executors/sst-lifecycle/run-sst-command.js +3 -33
- package/src/foundation/cost-estimate.d.ts +170 -0
- package/src/foundation/cost-estimate.js +683 -0
- package/src/generators/preset/tool-versions.d.ts +0 -2
- package/src/generators/preset/tool-versions.js +1 -3
- package/src/generators/preset/workspace-files-adopter-skills.js +39 -18
- package/src/generators/preset/workspace-files-developer-agent.js +83 -27
- package/src/generators/preset/workspace-files-shared-operation-claims.d.ts +10 -0
- package/src/generators/preset/workspace-files-shared-operation-claims.js +59 -0
- package/src/generators/preset/workspace-files-stage-authority.js +13 -2
- package/src/generators/preset/workspace-files-thin-deploy.d.ts +10 -0
- package/src/generators/preset/workspace-files-thin-deploy.js +54 -20
- package/src/generators/preset/workspace-files-thin-docs.js +32 -14
- package/src/generators/preset/workspace-files.js +28 -8
- package/src/generators/slice/built-in-plan-api-contract-files.js +7 -4
- package/src/generators/slice/built-in-plan-authorization-files.js +10 -5
- package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +933 -249
- package/src/generators/slice/built-in-plan-data-files.js +17 -8
- package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js +5 -1
- package/src/generators/slice/built-in-plan-frontend-files.js +7 -0
- package/src/generators/slice/built-in-plan-infrastructure-files.js +0 -1
- package/src/generators/slice/built-in-plan-infrastructure-safety-files.js +8 -3
- package/src/generators/slice/built-in-plan-metadata-files.js +2 -1
- package/src/generators/slice/built-in-plan-reliability-files.js +4 -1
- package/src/generators/slice/built-in-plan-testing-persistence-event-files.d.ts +7 -0
- package/src/generators/slice/built-in-plan-testing-persistence-event-files.js +487 -0
- package/src/generators/slice/built-in-plan-testing-persistence-files.js +2 -0
- package/src/generators/slice/built-in-plan.js +3 -1
- package/src/generators/workload/frozen-container.d.ts +1 -1
- package/src/git-policy/github-bootstrap.d.ts +9 -0
- package/src/git-policy/github-bootstrap.js +16 -2
- package/src/local-dev/fleet-inventory.js +18 -10
- package/src/local-dev/fleet-launcher.js +2 -2
- package/src/secrets/personal-command.d.ts +18 -2
- package/src/secrets/personal-command.js +66 -12
- package/src/secrets/verification.js +6 -1
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ Consumers should never invoke SST lifecycle commands directly.
|
|
|
39
39
|
|
|
40
40
|
The workspace-pinned `ebk` binary is the single framework CLI. It owns local
|
|
41
41
|
development, bounded Developer-Agent inspection/planning, external Blueprint
|
|
42
|
-
receipt review, and the
|
|
42
|
+
receipt review, and the personal secret commands. Nx remains the
|
|
43
43
|
workspace graph and owning-target authority behind generated work.
|
|
44
44
|
|
|
45
45
|
`ebk agent context --json` is the sole full structured context transport. The
|
|
@@ -77,7 +77,10 @@ recurring target only after retention and after recomputing its portable
|
|
|
77
77
|
package authority from the protected target, manifests, and lockfile. Exact
|
|
78
78
|
Node declarations and the full lockfile digest are receipt-bound as well. A
|
|
79
79
|
human may invoke the structured Nx target without a receipt. Neither path is
|
|
80
|
-
cryptographic or hosted attestation.
|
|
80
|
+
cryptographic or hosted attestation. Until the receipt is retained, an agent
|
|
81
|
+
prepares the change, asks the human to run `ebk blueprint verification-review`
|
|
82
|
+
on the protected tip and land the retaining commit, and verifies its own edits
|
|
83
|
+
through built-in targets.
|
|
81
84
|
|
|
82
85
|
The external manifest's sole recurring root is named exactly `verify`.
|
|
83
86
|
Generated project configurations are whole-file managed, canonically rooted
|
|
@@ -86,8 +89,11 @@ result. Agent inspection classifies every graph project beneath a current or
|
|
|
86
89
|
historically external Slice ownership root as external without trusting tags
|
|
87
90
|
or that publisher-authored inventory; historical roots and identities remain
|
|
88
91
|
external after deletion or relabeling. Only the protected-reviewed chain is
|
|
89
|
-
exposed. Read-only fleet status and logs remain available,
|
|
90
|
-
withholds
|
|
92
|
+
exposed. Read-only fleet status and logs remain available. In v1, agent
|
|
93
|
+
planning withholds `ebk dev up`, `restart`, and `down` for external Slices
|
|
94
|
+
because their code is not bound by a protected receipt; an agent asks the human
|
|
95
|
+
to run the lifecycle command directly, then continues with status, logs, and
|
|
96
|
+
the reviewed verification chain.
|
|
91
97
|
|
|
92
98
|
Independently of Blueprint provenance, Developer-Agent inspection performs a
|
|
93
99
|
bounded repository-wide Nx-configuration preflight before graph loading. Each
|
|
@@ -109,8 +115,11 @@ external ownership appears currently or anywhere in the bounded first-parent
|
|
|
109
115
|
histories of HEAD, protected develop, or protected main; mutable
|
|
110
116
|
`nx.json.defaultBase` cannot redirect the inventory. A missing protected ref
|
|
111
117
|
makes the inventory incomplete and activates the same strict boundary; a
|
|
112
|
-
shallow clone does likewise because hidden history cannot prove absence.
|
|
113
|
-
|
|
118
|
+
shallow clone does likewise because hidden history cannot prove absence. This
|
|
119
|
+
is a recoverable state: complete the history with `git fetch --unshallow origin`
|
|
120
|
+
(or a full-depth `git fetch origin develop main`) so that
|
|
121
|
+
`refs/remotes/origin/develop` and `refs/remotes/origin/main` exist, then rerun
|
|
122
|
+
inspection. While that inventory is incomplete, every graph project under `packages/` except the
|
|
114
123
|
sole canonical `foundation` project at `packages/foundation` is treated as
|
|
115
124
|
externally owned. The Foundation tag cannot create that exception: its project
|
|
116
125
|
name, declared root, and canonical directory are checked together. Read-only
|
|
@@ -124,16 +133,23 @@ outside the local-evidence claim. That includes mutation between the
|
|
|
124
133
|
repository-wide configuration inventory and Nx graph loading; the preflight is
|
|
125
134
|
not an immutable repository snapshot.
|
|
126
135
|
|
|
127
|
-
The
|
|
136
|
+
The personal secret commands are:
|
|
128
137
|
|
|
129
138
|
```bash
|
|
130
139
|
ebk secret set <slice> <logical-name>
|
|
131
140
|
ebk secret remove <slice> <logical-name>
|
|
132
141
|
```
|
|
133
142
|
|
|
134
|
-
|
|
135
|
-
`ebk dev configure`, verify the development Foundation account, and
|
|
136
|
-
|
|
143
|
+
Both commands derive the personal stage, use the profile and Region saved by
|
|
144
|
+
`ebk dev configure`, verify the development Foundation account, and refuse
|
|
145
|
+
canonical stages. `set` accepts the value only from a hidden local TTY, never
|
|
146
|
+
from argv, environment, or files, and refuses agent and CI environments,
|
|
147
|
+
because a hidden prompt does not hide the value from the process that owns the
|
|
148
|
+
terminal: a human runs it in a terminal no agent spawned, and the agent
|
|
149
|
+
verifies afterwards with the value-blind `secret-metadata` and status targets.
|
|
150
|
+
`remove` carries no value. An agent may start it; it still needs a local
|
|
151
|
+
interactive terminal where the human types the hidden `REMOVE <logical-name>`
|
|
152
|
+
confirmation.
|
|
137
153
|
|
|
138
154
|
Generated workspaces expose `work-markers` as both a direct target and part of
|
|
139
155
|
workspace health. The generated `AGENTS.md`, `CLAUDE.md`, and runbook define how
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empire-builder-kit/nx",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.41",
|
|
4
4
|
"description": "Nx generators, executors, and Blueprint contracts for Empire Builder Kit",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aws",
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
"provenance": false
|
|
146
146
|
},
|
|
147
147
|
"dependencies": {
|
|
148
|
-
"@empire-builder-kit/runtime": "1.0.0-rc.
|
|
148
|
+
"@empire-builder-kit/runtime": "1.0.0-rc.41",
|
|
149
149
|
"@aws-sdk/client-cloudfront": "^3.700.0",
|
|
150
150
|
"@aws-sdk/client-cloudwatch": "^3.700.0",
|
|
151
151
|
"@aws-sdk/client-cloudwatch-logs": "^3.700.0",
|
|
@@ -178,5 +178,5 @@
|
|
|
178
178
|
"engines": {
|
|
179
179
|
"node": ">=22.13.0"
|
|
180
180
|
},
|
|
181
|
-
"gitHead": "
|
|
181
|
+
"gitHead": "6c8e932ac3acf0a1e124f7687cd7b8582b864c49"
|
|
182
182
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ChildProcessWithoutNullStreams } from 'node:child_process';
|
|
2
|
-
export declare const EXTERNAL_BLUEPRINT_SANDBOX_IMAGE: "node:22-alpine@sha256:
|
|
2
|
+
export declare const EXTERNAL_BLUEPRINT_SANDBOX_IMAGE: "node:22-alpine@sha256:0a7108bf6c7bf5de370ffb1a3ed6be93d405b43ff159f681a8d18c0e2bc2e402";
|
|
3
3
|
export declare const EXTERNAL_BLUEPRINT_CONTAINER_AUTO_REMOVE: "--rm";
|
|
4
4
|
export declare const EXTERNAL_BLUEPRINT_SANDBOX_FLAGS: readonly ["--network=none", "--read-only", "--cap-drop=ALL", "--security-opt=no-new-privileges", "--pids-limit=64", "--memory=256m", "--memory-swap=256m", "--cpus=1", "--ulimit=nofile=256:256", "--tmpfs=/tmp:rw,noexec,nosuid,nodev,size=16m,mode=1777"];
|
|
5
5
|
export type ExternalBlueprintSource = 'installed' | 'local';
|
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
import { runGovernedChildProcess } from '../executors/sst-lifecycle/run-sst-command.js';
|
|
2
2
|
import type { DeployCliCommand } from './dev-command.js';
|
|
3
|
+
export declare const DEPLOY_RESULT_KIND = "ebk-deploy-result";
|
|
4
|
+
export declare const DEPLOY_RECEIPT_PATH = ".ebk/evidence/deployment/latest.json";
|
|
5
|
+
export interface DeployResultProject {
|
|
6
|
+
outcome: string;
|
|
7
|
+
project: string;
|
|
8
|
+
target: string;
|
|
9
|
+
}
|
|
10
|
+
/** The development-only `--json` result: the executor's own written receipt
|
|
11
|
+
* (already secret-free evidence) and per-project status. It is printed after
|
|
12
|
+
* the run and carries no authority; protected stages never produce it. */
|
|
13
|
+
export interface DeployJsonResult {
|
|
14
|
+
exitCode: number;
|
|
15
|
+
kind: typeof DEPLOY_RESULT_KIND;
|
|
16
|
+
outcome: 'failed' | 'receipt-unavailable' | 'review-required' | 'succeeded';
|
|
17
|
+
projects: DeployResultProject[];
|
|
18
|
+
receipt: Record<string, unknown> | null;
|
|
19
|
+
receiptPath: typeof DEPLOY_RECEIPT_PATH;
|
|
20
|
+
schemaVersion: 1;
|
|
21
|
+
stage: 'development';
|
|
22
|
+
}
|
|
23
|
+
export interface DeployCommandOutput {
|
|
24
|
+
now?: () => number;
|
|
25
|
+
stdout: (value: string) => void;
|
|
26
|
+
}
|
|
3
27
|
/** The CLI selects the existing workspace lifecycle, never an individual SST
|
|
4
28
|
* child. All policy, identity, TTY, migration, smoke and receipt decisions
|
|
5
29
|
* remain in the generated Nx target and its executor. */
|
|
6
|
-
export declare function executeDeployCommand(command: DeployCliCommand, workspaceRoot: string, environment: NodeJS.ProcessEnv, run?: typeof runGovernedChildProcess): Promise<number>;
|
|
30
|
+
export declare function executeDeployCommand(command: DeployCliCommand, workspaceRoot: string, environment: NodeJS.ProcessEnv, run?: typeof runGovernedChildProcess, output?: DeployCommandOutput): Promise<number>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEPLOY_RECEIPT_PATH = exports.DEPLOY_RESULT_KIND = void 0;
|
|
3
4
|
exports.executeDeployCommand = executeDeployCommand;
|
|
4
5
|
const node_fs_1 = require("node:fs");
|
|
5
6
|
const node_os_1 = require("node:os");
|
|
@@ -7,10 +8,104 @@ const node_path_1 = require("node:path");
|
|
|
7
8
|
const run_sst_command_js_1 = require("../executors/sst-lifecycle/run-sst-command.js");
|
|
8
9
|
const errors_js_1 = require("../local-dev/errors.js");
|
|
9
10
|
const nx_workspace_js_1 = require("../local-dev/nx-workspace.js");
|
|
11
|
+
exports.DEPLOY_RESULT_KIND = 'ebk-deploy-result';
|
|
12
|
+
exports.DEPLOY_RECEIPT_PATH = '.ebk/evidence/deployment/latest.json';
|
|
13
|
+
const MAX_DEPLOY_RECEIPT_BYTES = 1024 * 1024;
|
|
14
|
+
const MAX_DEPLOY_RECEIPT_CHILDREN = 4096;
|
|
15
|
+
function isRecord(value) {
|
|
16
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
function boundedText(value) {
|
|
19
|
+
return typeof value === 'string' && value.length > 0 && value.length <= 256;
|
|
20
|
+
}
|
|
21
|
+
/** Reads only a fresh, regular, bounded development receipt written by this
|
|
22
|
+
* run. A stale receipt left by an earlier run (for example when the
|
|
23
|
+
* workspace-health dependency fails before the executor invalidates it) is
|
|
24
|
+
* reported as unavailable, never as this run's result. */
|
|
25
|
+
function readFreshDevelopmentReceipt(workspaceRoot, startedAtMs) {
|
|
26
|
+
let descriptor;
|
|
27
|
+
let source;
|
|
28
|
+
try {
|
|
29
|
+
const receiptPath = (0, node_path_1.join)(workspaceRoot, exports.DEPLOY_RECEIPT_PATH);
|
|
30
|
+
// Windows has no O_NOFOLLOW, so the receipt file itself must not be a
|
|
31
|
+
// symbolic link, and the opened file must be the one lstat saw (exact
|
|
32
|
+
// 64-bit identity). A filesystem whose fstat identity differs from lstat
|
|
33
|
+
// reports the receipt as unavailable.
|
|
34
|
+
const entry = (0, node_fs_1.lstatSync)(receiptPath, { bigint: true });
|
|
35
|
+
if (entry.isSymbolicLink() || !entry.isFile())
|
|
36
|
+
return undefined;
|
|
37
|
+
descriptor = (0, node_fs_1.openSync)(receiptPath,
|
|
38
|
+
// O_NOFOLLOW refuses a symbolic link at the receipt path itself.
|
|
39
|
+
node_fs_1.constants.O_RDONLY | (node_fs_1.constants.O_NOFOLLOW ?? 0));
|
|
40
|
+
const stat = (0, node_fs_1.fstatSync)(descriptor, { bigint: true });
|
|
41
|
+
if (!stat.isFile() ||
|
|
42
|
+
stat.dev !== entry.dev ||
|
|
43
|
+
stat.ino !== entry.ino ||
|
|
44
|
+
stat.size > BigInt(MAX_DEPLOY_RECEIPT_BYTES)) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const size = Number(stat.size);
|
|
48
|
+
const buffer = Buffer.alloc(size);
|
|
49
|
+
let offset = 0;
|
|
50
|
+
while (offset < size) {
|
|
51
|
+
const read = (0, node_fs_1.readSync)(descriptor, buffer, offset, size - offset, null);
|
|
52
|
+
if (read === 0)
|
|
53
|
+
break;
|
|
54
|
+
offset += read;
|
|
55
|
+
}
|
|
56
|
+
source = buffer.subarray(0, offset).toString('utf8');
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
if (descriptor !== undefined)
|
|
63
|
+
(0, node_fs_1.closeSync)(descriptor);
|
|
64
|
+
}
|
|
65
|
+
let receipt;
|
|
66
|
+
try {
|
|
67
|
+
receipt = JSON.parse(source);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
if (!isRecord(receipt) ||
|
|
73
|
+
receipt.kind !== 'ebk-deployment-receipt' ||
|
|
74
|
+
receipt.schemaVersion !== 1 ||
|
|
75
|
+
receipt.stage !== 'development' ||
|
|
76
|
+
typeof receipt.startedAt !== 'string' ||
|
|
77
|
+
!Number.isFinite(Date.parse(receipt.startedAt)) ||
|
|
78
|
+
Date.parse(receipt.startedAt) < startedAtMs ||
|
|
79
|
+
!['failed', 'review-required', 'succeeded'].includes(String(receipt.outcome)) ||
|
|
80
|
+
!Array.isArray(receipt.children) ||
|
|
81
|
+
receipt.children.length > MAX_DEPLOY_RECEIPT_CHILDREN) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
const projects = [];
|
|
85
|
+
for (const child of receipt.children) {
|
|
86
|
+
if (!isRecord(child) ||
|
|
87
|
+
!boundedText(child.project) ||
|
|
88
|
+
!boundedText(child.target) ||
|
|
89
|
+
!boundedText(child.outcome)) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
projects.push({
|
|
93
|
+
outcome: child.outcome,
|
|
94
|
+
project: child.project,
|
|
95
|
+
target: child.target,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return { projects, receipt };
|
|
99
|
+
}
|
|
10
100
|
/** The CLI selects the existing workspace lifecycle, never an individual SST
|
|
11
101
|
* child. All policy, identity, TTY, migration, smoke and receipt decisions
|
|
12
102
|
* remain in the generated Nx target and its executor. */
|
|
13
|
-
async function executeDeployCommand(command, workspaceRoot, environment, run = run_sst_command_js_1.runGovernedChildProcess) {
|
|
103
|
+
async function executeDeployCommand(command, workspaceRoot, environment, run = run_sst_command_js_1.runGovernedChildProcess, output) {
|
|
104
|
+
const structured = command.json === true;
|
|
105
|
+
if (structured && (command.stage !== 'development' || !output)) {
|
|
106
|
+
// Parsing already refuses this; fail closed if a caller bypasses it.
|
|
107
|
+
throw new errors_js_1.LocalDevContractError('invalid-input', 'ebk deploy --json is available only for development; staging and production keep native output and the interactive acknowledgement.');
|
|
108
|
+
}
|
|
14
109
|
let project;
|
|
15
110
|
try {
|
|
16
111
|
project = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(workspaceRoot, 'project.json'), 'utf8'));
|
|
@@ -28,6 +123,7 @@ async function executeDeployCommand(command, workspaceRoot, environment, run = r
|
|
|
28
123
|
throw new errors_js_1.LocalDevContractError('prerequisite-unavailable', 'ebk deploy requires the generated, non-cacheable workspace deploy-local target. Run the supported workspace upgrade and workspace-health check.');
|
|
29
124
|
}
|
|
30
125
|
const nx = (0, nx_workspace_js_1.resolveWorkspaceNxRuntime)(workspaceRoot);
|
|
126
|
+
const startedAtMs = (output?.now ?? Date.now)();
|
|
31
127
|
const result = await run({
|
|
32
128
|
executable: process.execPath,
|
|
33
129
|
args: [
|
|
@@ -48,11 +144,31 @@ async function executeDeployCommand(command, workspaceRoot, environment, run = r
|
|
|
48
144
|
NX_TUI: 'false',
|
|
49
145
|
NX_TASKS_RUNNER_DYNAMIC_OUTPUT: 'false',
|
|
50
146
|
},
|
|
147
|
+
// With --json, native output moves to stderr so stdout carries only the
|
|
148
|
+
// structured result; stdin stays inherited.
|
|
149
|
+
...(structured ? { stdio: ['inherit', 2, 'inherit'] } : {}),
|
|
51
150
|
});
|
|
52
151
|
if (result.error)
|
|
53
152
|
throw result.error;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
153
|
+
const exitCode = result.signal
|
|
154
|
+
? 128 + (node_os_1.constants.signals[result.signal] ?? 1)
|
|
155
|
+
: (result.status ?? 1);
|
|
156
|
+
if (structured && output) {
|
|
157
|
+
const fresh = readFreshDevelopmentReceipt(workspaceRoot, startedAtMs);
|
|
158
|
+
const payload = {
|
|
159
|
+
exitCode,
|
|
160
|
+
kind: exports.DEPLOY_RESULT_KIND,
|
|
161
|
+
outcome: fresh
|
|
162
|
+
? fresh.receipt.outcome
|
|
163
|
+
: 'receipt-unavailable',
|
|
164
|
+
projects: fresh?.projects ?? [],
|
|
165
|
+
receipt: fresh?.receipt ?? null,
|
|
166
|
+
receiptPath: exports.DEPLOY_RECEIPT_PATH,
|
|
167
|
+
schemaVersion: 1,
|
|
168
|
+
stage: 'development',
|
|
169
|
+
};
|
|
170
|
+
output.stdout(`${JSON.stringify(payload, null, 2)}\n`);
|
|
171
|
+
}
|
|
172
|
+
return exitCode;
|
|
57
173
|
}
|
|
58
174
|
//# sourceMappingURL=deploy-runtime.js.map
|
package/src/cli/dev-command.d.ts
CHANGED
|
@@ -97,6 +97,8 @@ export interface DeployCliCommand {
|
|
|
97
97
|
stage: 'development' | 'staging' | 'production';
|
|
98
98
|
profile?: string;
|
|
99
99
|
expectedRoleArn: string;
|
|
100
|
+
/** Development only: print one bounded receipt result on stdout. */
|
|
101
|
+
json?: true;
|
|
100
102
|
slices?: string[];
|
|
101
103
|
}
|
|
102
104
|
export type ParsedEbkCommand = AgentCliCommand | CliHelpCommand | CliVersionCommand | DeployCliCommand | DevCliCommand | SecretCliCommand;
|
package/src/cli/dev-command.js
CHANGED
|
@@ -501,6 +501,7 @@ function parseEbkArguments(arguments_) {
|
|
|
501
501
|
},
|
|
502
502
|
profile: { kind: 'string' },
|
|
503
503
|
expectedRoleArn: { kind: 'string' },
|
|
504
|
+
json: { kind: 'flag' },
|
|
504
505
|
});
|
|
505
506
|
const stages = ['development', 'staging', 'production'];
|
|
506
507
|
const positionalStage = stages.includes(tokens.positionals[0])
|
|
@@ -515,6 +516,12 @@ function parseEbkArguments(arguments_) {
|
|
|
515
516
|
stage !== 'production') {
|
|
516
517
|
return usageError('ebk deploy stage must be development, staging, or production.');
|
|
517
518
|
}
|
|
519
|
+
const json = booleanOption(tokens, 'json');
|
|
520
|
+
if (json && stage !== 'development') {
|
|
521
|
+
// Protected stages keep native output and the human-typed TTY
|
|
522
|
+
// acknowledgement; a structured mode must never stand in for either.
|
|
523
|
+
return usageError('ebk deploy --json is available only for development; staging and production keep native output and the interactive acknowledgement.');
|
|
524
|
+
}
|
|
518
525
|
const expectedRoleArn = stringOption(tokens, 'expectedRoleArn');
|
|
519
526
|
if (!expectedRoleArn ||
|
|
520
527
|
!/^arn:(aws|aws-us-gov|aws-cn):iam::[0-9]{12}:role\/[A-Za-z0-9+=,.@_/-]{1,512}$/.test(expectedRoleArn)) {
|
|
@@ -535,6 +542,7 @@ function parseEbkArguments(arguments_) {
|
|
|
535
542
|
...(profile === undefined
|
|
536
543
|
? {}
|
|
537
544
|
: { profile: (0, local_context_js_1.normalizeLocalDevProfile)(profile) }),
|
|
545
|
+
...(json ? { json: true } : {}),
|
|
538
546
|
...(slices.length === 0 ? {} : { slices }),
|
|
539
547
|
};
|
|
540
548
|
}
|
package/src/cli/main.js
CHANGED
|
@@ -57,6 +57,7 @@ const DEPLOY_HELP = `Empire Builder Kit local deployment
|
|
|
57
57
|
|
|
58
58
|
Usage:
|
|
59
59
|
ebk deploy [development|staging|production] [slice...] --expectedRoleArn=<role-arn> [--profile=<aws-profile>]
|
|
60
|
+
ebk deploy development [slice...] --expectedRoleArn=<role-arn> [--profile=<aws-profile>] --json
|
|
60
61
|
|
|
61
62
|
The stage defaults to development; --stage=<stage> is also supported instead
|
|
62
63
|
of a positional stage. Account and Region come from committed repository policy.
|
|
@@ -65,9 +66,15 @@ Slices, declared migrations and deployed smoke. Supply billing to deploy only
|
|
|
65
66
|
that Slice after Foundation; omit Slice names for the complete stage. Other
|
|
66
67
|
Slices are not redeployed and must already exist if the feature needs them.
|
|
67
68
|
Native output and terminal
|
|
68
|
-
interaction are inherited;
|
|
69
|
+
interaction are inherited; arbitrary Nx/SST options are not accepted.
|
|
69
70
|
The existing deployment receipt is the structured result, not a CLI success seal.
|
|
70
71
|
|
|
72
|
+
--json is accepted for development only. Native output then moves to stderr,
|
|
73
|
+
and stdout carries one bounded, secret-free result after the run: the
|
|
74
|
+
deployment receipt this run wrote and each project's target outcome (receipt
|
|
75
|
+
null when none was written). The exit code is the lifecycle's own. --json is
|
|
76
|
+
refused for staging and production and never replaces their acknowledgement.
|
|
77
|
+
|
|
71
78
|
Development allows dirty source without a prompt. Local staging requires a
|
|
72
79
|
clean commit and its TTY acknowledgement. Starter production requires a clean
|
|
73
80
|
commit and the exact deploy:production:<account>:<region>:<source-commit> TTY
|
|
@@ -132,9 +139,12 @@ Usage:
|
|
|
132
139
|
ebk secret set <slice> <logical-name>
|
|
133
140
|
ebk secret remove <slice> <logical-name>
|
|
134
141
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
142
|
+
Both commands derive the personal stage and read the saved development
|
|
143
|
+
profile and Region. set accepts the value only through a hidden local TTY,
|
|
144
|
+
never through argv, environment, or files, and refuses agent and CI
|
|
145
|
+
environments: a human runs it in a terminal no agent spawned. remove carries
|
|
146
|
+
no value; an agent may start it, and the human types the hidden
|
|
147
|
+
REMOVE <logical-name> confirmation in that interactive terminal.`;
|
|
138
148
|
function inspectWorkspaceFilesystemIdentity(path) {
|
|
139
149
|
const status = (0, node_fs_1.statSync)(path, { bigint: true });
|
|
140
150
|
return {
|
|
@@ -450,7 +460,7 @@ function secretCommandFailure(error) {
|
|
|
450
460
|
async function executeSecretCommand(command, dispatch) {
|
|
451
461
|
try {
|
|
452
462
|
const ceremony = dispatch.dependencies.secretCeremony(dispatch.environment);
|
|
453
|
-
(0, personal_command_js_1.assertHumanSecretCeremony)(ceremony);
|
|
463
|
+
(0, personal_command_js_1.assertHumanSecretCeremony)(ceremony, command.command);
|
|
454
464
|
const common = dispatch.dependencies.gitCommonDirectory(dispatch.workspaceRoot);
|
|
455
465
|
const saved = dispatch.dependencies.readContext(common);
|
|
456
466
|
if (saved.kind !== 'ready') {
|
|
@@ -1159,6 +1169,8 @@ function processAbortSignal() {
|
|
|
1159
1169
|
};
|
|
1160
1170
|
}
|
|
1161
1171
|
function commandJson(command) {
|
|
1172
|
+
if (command?.kind === 'deploy')
|
|
1173
|
+
return command.json === true;
|
|
1162
1174
|
return (command?.kind === 'agent' || command?.kind === 'dev') && command.json;
|
|
1163
1175
|
}
|
|
1164
1176
|
function commandName(command) {
|
|
@@ -1280,7 +1292,9 @@ async function runEbkCli(arguments_, io = {}, overrides = {}) {
|
|
|
1280
1292
|
const dependencies = defaultDependencies(overrides);
|
|
1281
1293
|
const root = dependencies.resolveWorkspaceRoot(io.cwd ?? process.cwd());
|
|
1282
1294
|
if (parsed.kind === 'deploy') {
|
|
1283
|
-
return
|
|
1295
|
+
return parsed.json
|
|
1296
|
+
? await dependencies.executeDeploy(parsed, root, io.environment ?? process.env, undefined, { stdout: output.stdout })
|
|
1297
|
+
: await dependencies.executeDeploy(parsed, root, io.environment ?? process.env);
|
|
1284
1298
|
}
|
|
1285
1299
|
dependencies.changeDirectory(root);
|
|
1286
1300
|
if (!io.abortSignal)
|
|
@@ -29,6 +29,15 @@ export interface WorkspaceSstSecretInvocation {
|
|
|
29
29
|
operation: 'remove' | 'set';
|
|
30
30
|
}
|
|
31
31
|
export type PersonalSecretProcessSpawner = typeof spawn;
|
|
32
|
+
/**
|
|
33
|
+
* Markers that identify an agent- or CI-owned process. `ebk secret set`
|
|
34
|
+
* refuses them because a hidden TTY prompt does not hide the value from the
|
|
35
|
+
* process that owns the terminal; the human runs set in a terminal no agent
|
|
36
|
+
* spawned. `ebk secret remove` carries no value and is not gated by this
|
|
37
|
+
* list; it still requires an interactive terminal and the hidden typed
|
|
38
|
+
* confirmation. Only the variable name is ever reported, never its value.
|
|
39
|
+
*/
|
|
40
|
+
declare const agentEnvironmentNames: readonly ["BUILDKITE", "CI", "CLAUDECODE", "CLAUDE_CODE_ENTRYPOINT", "CODEBUILD_BUILD_ID", "CODEX_SANDBOX", "CODEX_THREAD_ID", "CURSOR_AGENT", "EBK_AGENT_DELEGATED", "GITHUB_ACTIONS", "JENKINS_URL", "TF_BUILD"];
|
|
32
41
|
/**
|
|
33
42
|
* Binds the stored SST value to one personal stage, declaration, and value
|
|
34
43
|
* shape. Raw SST values and values inherited from another stage cannot satisfy
|
|
@@ -40,6 +49,8 @@ export declare function encodePersonalSstSecretEnvelope(input: {
|
|
|
40
49
|
stage: string;
|
|
41
50
|
valueKind: SecretMetadataDeclaration['valueKind'];
|
|
42
51
|
}): Uint8Array;
|
|
52
|
+
/** Returns the first detected marker variable name, never its value. */
|
|
53
|
+
export declare function detectedAgentOrCiMarker(environment: NodeJS.ProcessEnv): (typeof agentEnvironmentNames)[number] | undefined;
|
|
43
54
|
export declare function detectDelegatedAgentOrCi(environment: NodeJS.ProcessEnv): boolean;
|
|
44
55
|
export declare function createHumanSecretCeremony(environment: NodeJS.ProcessEnv, stdinIsTty: boolean, outputIsTty: boolean): HumanSecretCeremony;
|
|
45
56
|
export declare function loadPersonalOperatorSecret(input: {
|
|
@@ -79,3 +90,4 @@ export declare function createWorkspacePinnedSstSecretStore(input: {
|
|
|
79
90
|
signal?: AbortSignal;
|
|
80
91
|
spawnProcess?: PersonalSecretProcessSpawner;
|
|
81
92
|
}): PersonalSstSecretStore;
|
|
93
|
+
export {};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PersonalSecretRuntimeError = void 0;
|
|
4
4
|
exports.encodePersonalSstSecretEnvelope = encodePersonalSstSecretEnvelope;
|
|
5
|
+
exports.detectedAgentOrCiMarker = detectedAgentOrCiMarker;
|
|
5
6
|
exports.detectDelegatedAgentOrCi = detectDelegatedAgentOrCi;
|
|
6
7
|
exports.createHumanSecretCeremony = createHumanSecretCeremony;
|
|
7
8
|
exports.loadPersonalOperatorSecret = loadPersonalOperatorSecret;
|
|
@@ -44,6 +45,14 @@ class PersonalSecretRuntimeError extends Error {
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
exports.PersonalSecretRuntimeError = PersonalSecretRuntimeError;
|
|
48
|
+
/**
|
|
49
|
+
* Markers that identify an agent- or CI-owned process. `ebk secret set`
|
|
50
|
+
* refuses them because a hidden TTY prompt does not hide the value from the
|
|
51
|
+
* process that owns the terminal; the human runs set in a terminal no agent
|
|
52
|
+
* spawned. `ebk secret remove` carries no value and is not gated by this
|
|
53
|
+
* list; it still requires an interactive terminal and the hidden typed
|
|
54
|
+
* confirmation. Only the variable name is ever reported, never its value.
|
|
55
|
+
*/
|
|
47
56
|
const agentEnvironmentNames = [
|
|
48
57
|
'BUILDKITE',
|
|
49
58
|
'CI',
|
|
@@ -124,13 +133,19 @@ function encodePersonalSstSecretEnvelope(input) {
|
|
|
124
133
|
envelope.fill(0);
|
|
125
134
|
}
|
|
126
135
|
}
|
|
127
|
-
|
|
128
|
-
|
|
136
|
+
/** Returns the first detected marker variable name, never its value. */
|
|
137
|
+
function detectedAgentOrCiMarker(environment) {
|
|
138
|
+
return agentEnvironmentNames.find((name) => environment[name] !== undefined &&
|
|
129
139
|
(name !== 'CI' || enabledEnvironmentFlag(environment[name])));
|
|
130
140
|
}
|
|
141
|
+
function detectDelegatedAgentOrCi(environment) {
|
|
142
|
+
return detectedAgentOrCiMarker(environment) !== undefined;
|
|
143
|
+
}
|
|
131
144
|
function createHumanSecretCeremony(environment, stdinIsTty, outputIsTty) {
|
|
145
|
+
const detectedMarker = detectedAgentOrCiMarker(environment);
|
|
132
146
|
return (0, personal_command_js_1.issueHumanSecretCeremony)({
|
|
133
|
-
agentDelegated:
|
|
147
|
+
agentDelegated: detectedMarker !== undefined,
|
|
148
|
+
...(detectedMarker === undefined ? {} : { detectedMarker }),
|
|
134
149
|
interactive: stdinIsTty && outputIsTty,
|
|
135
150
|
stdinIsTty,
|
|
136
151
|
});
|
|
@@ -6,7 +6,7 @@ exports.createTtySecretConfirmation = createTtySecretConfirmation;
|
|
|
6
6
|
const MAX_HIDDEN_INPUT_BYTES = 256 * 1024;
|
|
7
7
|
class SecretTerminalError extends Error {
|
|
8
8
|
constructor() {
|
|
9
|
-
super('The personal secret
|
|
9
|
+
super('The personal secret prompt needs a local interactive TTY that a human types into, and stops on Ctrl-C or end of input. Run ebk secret set in a terminal no agent spawned; an agent may start ebk secret remove only where the human can type the hidden confirmation.');
|
|
10
10
|
this.name = 'SecretTerminalError';
|
|
11
11
|
}
|
|
12
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const EBK_NODE_22_ALPINE_IMAGE: "node:22-alpine@sha256:
|
|
1
|
+
export declare const EBK_NODE_22_ALPINE_IMAGE: "node:22-alpine@sha256:0a7108bf6c7bf5de370ffb1a3ed6be93d405b43ff159f681a8d18c0e2bc2e402";
|
package/src/container-images.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EBK_NODE_22_ALPINE_IMAGE = void 0;
|
|
4
|
-
exports.EBK_NODE_22_ALPINE_IMAGE = 'node:22-alpine@sha256:
|
|
4
|
+
exports.EBK_NODE_22_ALPINE_IMAGE = 'node:22-alpine@sha256:0a7108bf6c7bf5de370ffb1a3ed6be93d405b43ff159f681a8d18c0e2bc2e402';
|
|
5
5
|
//# sourceMappingURL=container-images.js.map
|
|
@@ -34,6 +34,16 @@ export declare class DeveloperAgentOperationRegistryError extends Error {
|
|
|
34
34
|
readonly classification: "unsupported-operation";
|
|
35
35
|
constructor();
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Non-plannable local targets name their real owner. Each string states only
|
|
39
|
+
* behaviour that exists: none of them promises a Developer-Agent plan entry.
|
|
40
|
+
*/
|
|
41
|
+
export declare const DEPLOY_LOCAL_OWNER_RATIONALE = "Development deployment is owned by ebk deploy development [slice]: run that command directly with the saved development --profile and the policy-derived --expectedRoleArn. This root target is its Nx implementation, not a separate entry point.";
|
|
42
|
+
export declare const DOCKER_BUILD_OWNER_RATIONALE = "Local workload image builds use the host Docker daemon outside any bounded owner. Verify workload source with its build, test and typecheck targets; ebk deploy development <slice> builds the deployable image.";
|
|
43
|
+
export declare const WORKLOAD_DEV_OWNER_RATIONALE = "A hot workload process started outside the ebk dev Fleet has no owned port, lifecycle or cleanup. Verify Service and Job source with its test, typecheck and build targets and exercise it through ebk deploy development <slice>.";
|
|
44
|
+
export declare const FORMAT_WRITE_OWNER_RATIONALE = "Formatting rewrites source files only: run pnpm nx format:write directly as part of a source edit, then rerun the required verification.";
|
|
45
|
+
export declare const GRAPH_INTERACTIVE_RATIONALE = "nx graph starts an interactive browser server and is not a bounded operation; use ebk agent context for the read-only project inventory.";
|
|
46
|
+
export declare const ROUTER_WAF_REHEARSAL_OWNER_RATIONALE = "The Router WAF rehearsal requires an exact --probeUrl that planning cannot derive: run it directly through its Nx target with that option after a development deployment.";
|
|
37
47
|
/**
|
|
38
48
|
* Authority classes are not a severity list. In particular, development
|
|
39
49
|
* mutation plus protected proposal crosses authority domains and therefore
|