@assemblyline-agents/cli 2.0.0 → 3.1.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/LICENSE +1 -1
- package/README.md +19 -0
- package/authoring/skills/assembly-line-authoring/SKILL.md +61 -10
- package/dist/add.d.ts +4 -0
- package/dist/add.d.ts.map +1 -1
- package/dist/add.js +191 -48
- package/dist/add.js.map +1 -1
- package/dist/args.js +1 -1
- package/dist/args.js.map +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +40 -8
- package/dist/auth.js.map +1 -1
- package/dist/authoring.d.ts +2 -2
- package/dist/authoring.d.ts.map +1 -1
- package/dist/authoring.js +7 -4
- package/dist/authoring.js.map +1 -1
- package/dist/channels.d.ts +21 -0
- package/dist/channels.d.ts.map +1 -1
- package/dist/channels.js +104 -0
- package/dist/channels.js.map +1 -1
- package/dist/checkpoints.js +2 -2
- package/dist/checkpoints.js.map +1 -1
- package/dist/connections.d.ts +12 -0
- package/dist/connections.d.ts.map +1 -0
- package/dist/connections.js +55 -0
- package/dist/connections.js.map +1 -0
- package/dist/deploy-definition.js +3 -3
- package/dist/deploy-definition.js.map +1 -1
- package/dist/deploy-lifecycle.d.ts +11 -1
- package/dist/deploy-lifecycle.d.ts.map +1 -1
- package/dist/deploy-lifecycle.js +65 -16
- package/dist/deploy-lifecycle.js.map +1 -1
- package/dist/deploy.d.ts +9 -1
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +234 -29
- package/dist/deploy.js.map +1 -1
- package/dist/dev.d.ts +0 -2
- package/dist/dev.d.ts.map +1 -1
- package/dist/dev.js +9 -10
- package/dist/dev.js.map +1 -1
- package/dist/eval-case-runner.js +4 -2
- package/dist/eval-case-runner.js.map +1 -1
- package/dist/eval-fixtures.d.ts +5 -5
- package/dist/eval-fixtures.d.ts.map +1 -1
- package/dist/eval-fixtures.js +48 -22
- package/dist/eval-fixtures.js.map +1 -1
- package/dist/eval-judge.js +1 -1
- package/dist/eval-judge.js.map +1 -1
- package/dist/eval.d.ts.map +1 -1
- package/dist/eval.js +3 -3
- package/dist/eval.js.map +1 -1
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +57 -7
- package/dist/help.js.map +1 -1
- package/dist/hosts.js +1 -1
- package/dist/hosts.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +98 -19
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +4 -25
- package/dist/init.js.map +1 -1
- package/dist/models.d.ts +0 -3
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +1 -9
- package/dist/models.js.map +1 -1
- package/dist/operator-client.d.ts +1 -0
- package/dist/operator-client.d.ts.map +1 -1
- package/dist/operator-client.js +158 -3
- package/dist/operator-client.js.map +1 -1
- package/dist/project-env.d.ts.map +1 -1
- package/dist/project-env.js +2 -7
- package/dist/project-env.js.map +1 -1
- package/dist/release-history.d.ts +20 -0
- package/dist/release-history.d.ts.map +1 -0
- package/dist/release-history.js +232 -0
- package/dist/release-history.js.map +1 -0
- package/dist/secrets.d.ts +11 -0
- package/dist/secrets.d.ts.map +1 -1
- package/dist/secrets.js +66 -13
- package/dist/secrets.js.map +1 -1
- package/dist/setup.d.ts +38 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +107 -0
- package/dist/setup.js.map +1 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js.map +1 -1
- package/package.json +11 -11
package/dist/deploy-lifecycle.js
CHANGED
|
@@ -1,25 +1,74 @@
|
|
|
1
|
+
/** Run provider cleanup without hiding a completed or failed deploy outcome. */
|
|
2
|
+
export async function executeDeployCleanup(input) {
|
|
3
|
+
if (!input.publisher.cleanup)
|
|
4
|
+
return undefined;
|
|
5
|
+
try {
|
|
6
|
+
return await input.publisher.cleanup(input.artifact, input.plan) ?? undefined;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return {
|
|
10
|
+
target: input.publisher.target,
|
|
11
|
+
status: "degraded",
|
|
12
|
+
warning: "Provider cleanup did not complete. The deployment outcome is unchanged; rerun deploy cleanup through the next deployment attempt."
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
1
16
|
/** Execute the provider lifecycle in the one supported hosted-deploy order. */
|
|
2
17
|
export async function executeDeployLifecycle(input) {
|
|
3
18
|
const lifecycle = {};
|
|
19
|
+
input.onProgress?.("preflight");
|
|
4
20
|
const preflight = await input.publisher.preflight?.(input.artifact, input.plan);
|
|
5
21
|
if (preflight)
|
|
6
22
|
lifecycle.preflight = preflight;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
let sandboxEnvironment;
|
|
24
|
+
let preparation;
|
|
25
|
+
let migrationStatus = "none";
|
|
26
|
+
let providerReceipt;
|
|
27
|
+
try {
|
|
28
|
+
if (input.reconcileSandboxEnvironment) {
|
|
29
|
+
input.onProgress?.("sandbox-environment");
|
|
30
|
+
sandboxEnvironment = await input.reconcileSandboxEnvironment();
|
|
31
|
+
}
|
|
32
|
+
input.onProgress?.("prepare");
|
|
33
|
+
preparation = await input.publisher.prepare?.(input.artifact, input.plan);
|
|
34
|
+
if (preparation)
|
|
35
|
+
lifecycle.preparation = preparation;
|
|
36
|
+
input.onProgress?.("secrets");
|
|
37
|
+
await input.syncSecrets();
|
|
38
|
+
input.onProgress?.("migrations");
|
|
39
|
+
migrationStatus = input.publisher.runMigrations
|
|
40
|
+
? await input.publisher.runMigrations(input.artifact, input.plan, input.migrationRequest)
|
|
41
|
+
: await input.runFallbackMigrations();
|
|
42
|
+
if (input.activate !== false)
|
|
43
|
+
input.onProgress?.("activate");
|
|
44
|
+
providerReceipt = input.activate === false
|
|
45
|
+
? {
|
|
46
|
+
...(preparation ?? {}),
|
|
47
|
+
target: input.publisher.target,
|
|
48
|
+
status: "prepared",
|
|
49
|
+
environment: input.plan.environment,
|
|
50
|
+
agentRevision: input.plan.agentRevision
|
|
51
|
+
}
|
|
52
|
+
: await (input.publisher.activate ?? input.publisher.publish).call(input.publisher, input.artifact, input.plan);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (input.publisher.cleanup) {
|
|
56
|
+
input.onProgress?.("cleanup");
|
|
57
|
+
await executeDeployCleanup(input);
|
|
21
58
|
}
|
|
22
|
-
|
|
23
|
-
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
if (input.publisher.cleanup) {
|
|
62
|
+
input.onProgress?.("cleanup");
|
|
63
|
+
const cleanup = await executeDeployCleanup(input);
|
|
64
|
+
if (cleanup)
|
|
65
|
+
lifecycle.cleanup = cleanup;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
providerReceipt,
|
|
69
|
+
migrationStatus,
|
|
70
|
+
lifecycle,
|
|
71
|
+
...(sandboxEnvironment ? { sandboxEnvironment } : {})
|
|
72
|
+
};
|
|
24
73
|
}
|
|
25
74
|
//# sourceMappingURL=deploy-lifecycle.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy-lifecycle.js","sourceRoot":"","sources":["../src/deploy-lifecycle.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deploy-lifecycle.js","sourceRoot":"","sources":["../src/deploy-lifecycle.ts"],"names":[],"mappings":"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"}
|
package/dist/deploy.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type DeploymentPlan } from "@assemblyline-agents/compiler";
|
|
1
|
+
import { type BuildArtifact, type DeploymentPlan } from "@assemblyline-agents/compiler";
|
|
2
|
+
import type { SandboxEnvironmentResolution } from "@assemblyline-agents/core";
|
|
2
3
|
import { type ParsedArgs } from "./args.js";
|
|
3
4
|
export { parseEnvSecrets } from "./project-env.js";
|
|
4
5
|
export declare function runDeployCommand(agentRoot: string, parsed: ParsedArgs): Promise<void>;
|
|
@@ -7,6 +8,13 @@ export declare function splitDeploySecrets(secrets: Record<string, string>, plan
|
|
|
7
8
|
runtimeSecrets: Record<string, string>;
|
|
8
9
|
localDeployKeys: string[];
|
|
9
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* Reuse a sandbox artifact proven by a successful receipt when its provider and
|
|
13
|
+
* content fingerprint are unchanged. Runtime credentials stay on the host;
|
|
14
|
+
* only the provider-safe artifact reference crosses deploys.
|
|
15
|
+
*/
|
|
16
|
+
export declare function reusableSandboxEnvironmentResolution(artifact: Pick<BuildArtifact, "root" | "manifest">, environmentName: string): SandboxEnvironmentResolution | undefined;
|
|
17
|
+
export declare function sandboxPassthroughEnv(env: NodeJS.ProcessEnv, names: string[]): Record<string, string>;
|
|
10
18
|
export declare function runCommand(commandName: string, args: string[], options?: {
|
|
11
19
|
cwd?: string;
|
|
12
20
|
env?: NodeJS.ProcessEnv;
|
package/dist/deploy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"AAIA,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAQV,4BAA4B,EAC7B,MAAM,2BAA2B,CAAC;AAUnC,OAAO,EAAqD,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAmB/F,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkG3F;AAwKD,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACtC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxB;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,IAAI,EAAE,cAAc,GACnB;IAAE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,eAAe,EAAE,MAAM,EAAE,CAAA;CAAE,CAqBvE;AAqPD;;;;GAIG;AACH,wBAAgB,oCAAoC,CAClD,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,UAAU,CAAC,EAClD,eAAe,EAAE,MAAM,GACtB,4BAA4B,GAAG,SAAS,CA0B1C;AAUD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWrG;AA4DD,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACxE,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA8B/D;AAeD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAG5D"}
|
package/dist/deploy.js
CHANGED
|
@@ -3,15 +3,18 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync
|
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { buildAgent, compileAgent, planDeployment } from "@assemblyline-agents/compiler";
|
|
6
|
-
import { sanitizeDeployName } from "@assemblyline-agents/core";
|
|
7
|
-
import { installSignalHandlers, listenNodeRuntime, resolveProvider } from "@assemblyline-agents/node";
|
|
6
|
+
import { adapterProviderMetadata, isSensitiveSandboxEnvName, sanitizeDeployName } from "@assemblyline-agents/core";
|
|
7
|
+
import { installSignalHandlers, listenNodeRuntime, resolveProvider, resolveSecretsEnv } from "@assemblyline-agents/node";
|
|
8
8
|
import { FileStateAdapter, LocalBlobAdapter, LocalSandboxAdapter, AssemblyLineRuntime, loadRuntimeBundle } from "@assemblyline-agents/runtime";
|
|
9
9
|
import { booleanFlag, buildOptions, numberFlag, stringFlag } from "./args.js";
|
|
10
10
|
import { printIssues } from "./help.js";
|
|
11
11
|
import { missingPackageFixLines } from "./init.js";
|
|
12
|
+
import { checkChannelInstallations } from "./channels.js";
|
|
13
|
+
import { wireConnectionEvents } from "./connections.js";
|
|
12
14
|
import { resolveDeployDefinition, resolveDeployEnvironment } from "./deploy-definition.js";
|
|
13
|
-
import { executeDeployLifecycle } from "./deploy-lifecycle.js";
|
|
15
|
+
import { executeDeployCleanup, executeDeployLifecycle } from "./deploy-lifecycle.js";
|
|
14
16
|
import { loadProjectEnv, readEnvSecretsFile } from "./project-env.js";
|
|
17
|
+
import { prepareReleaseSnapshot, releaseSnapshotForReceipt, withReleaseSnapshot, } from "./release-history.js";
|
|
15
18
|
export { parseEnvSecrets } from "./project-env.js";
|
|
16
19
|
export async function runDeployCommand(agentRoot, parsed) {
|
|
17
20
|
loadProjectEnv(agentRoot);
|
|
@@ -26,20 +29,25 @@ export async function runDeployCommand(agentRoot, parsed) {
|
|
|
26
29
|
const manifest = compileAgent({ root: agentRoot });
|
|
27
30
|
deployOptions.environment = resolveDeployEnvironment(manifest, parsed);
|
|
28
31
|
printIssues(manifest.validation.issues.filter((issue) => issue.code === "provider-package-unresolved"), { agentRoot });
|
|
29
|
-
const plan = planDeployment(manifest, deployOptions);
|
|
32
|
+
const plan = planDeployment(manifest, { ...deployOptions, env: await resolveDeploySecretsEnv(manifest, agentRoot) });
|
|
30
33
|
const definition = resolveDeployDefinition(manifest, plan.target, parsed);
|
|
31
|
-
plan.missingRequirements = await effectiveMissingRequirements(plan, definition);
|
|
34
|
+
plan.missingRequirements = await effectiveMissingRequirements(plan, definition, manifest);
|
|
32
35
|
printDeployWarnings(plan);
|
|
33
36
|
console.log(JSON.stringify(plan, null, 2));
|
|
34
37
|
return;
|
|
35
38
|
}
|
|
36
|
-
const artifact = buildAgent(buildOptions(parsed, agentRoot));
|
|
39
|
+
const artifact = await buildAgent(buildOptions(parsed, agentRoot));
|
|
37
40
|
deployOptions.environment = resolveDeployEnvironment(artifact.manifest, parsed);
|
|
38
|
-
const
|
|
41
|
+
const deployEnv = await resolveDeploySecretsEnv(artifact.manifest, agentRoot);
|
|
42
|
+
const plan = planDeployment(artifact.manifest, { ...deployOptions, env: deployEnv });
|
|
43
|
+
const controlOnlyOperation = ["activate", "rollback", "ingress-only", "destroy"]
|
|
44
|
+
.some((flag) => booleanFlag(parsed, flag));
|
|
45
|
+
if (!controlOnlyOperation)
|
|
46
|
+
await preflightChannelInstallations(artifact);
|
|
39
47
|
const definition = resolveDeployDefinition(artifact.manifest, plan.target, parsed);
|
|
40
48
|
const effectivePlan = {
|
|
41
49
|
...plan,
|
|
42
|
-
missingRequirements: await effectiveMissingRequirements(plan, definition),
|
|
50
|
+
missingRequirements: await effectiveMissingRequirements(plan, definition, artifact.manifest, reusableSandboxEnvironmentResolution(artifact, plan.environment)),
|
|
43
51
|
canPublish: false
|
|
44
52
|
};
|
|
45
53
|
effectivePlan.canPublish = !effectivePlan.dryRun && effectivePlan.missingRequirements.length === 0;
|
|
@@ -82,6 +90,7 @@ export async function runDeployCommand(agentRoot, parsed) {
|
|
|
82
90
|
state: new FileStateAdapter(resolve(artifact.root, "deploy-state.json")),
|
|
83
91
|
blob: new LocalBlobAdapter(resolve(artifact.root, "blobs")),
|
|
84
92
|
sandbox: new LocalSandboxAdapter(resolve(artifact.root, "sandbox")),
|
|
93
|
+
env: deployEnv,
|
|
85
94
|
devMode: true,
|
|
86
95
|
port: numberFlag(parsed, "port") ?? 0
|
|
87
96
|
});
|
|
@@ -97,7 +106,41 @@ export async function runDeployCommand(agentRoot, parsed) {
|
|
|
97
106
|
console.log(`Local deploy prepared for revision ${effectivePlan.agentRevision}. Run assembly-line serve to keep it online.`);
|
|
98
107
|
return;
|
|
99
108
|
}
|
|
100
|
-
|
|
109
|
+
const release = !booleanFlag(parsed, "destroy") && !booleanFlag(parsed, "ingress-only")
|
|
110
|
+
? prepareReleaseSnapshot(agentRoot, artifact.manifest)
|
|
111
|
+
: undefined;
|
|
112
|
+
await runProviderDeploy(artifact, effectivePlan, definition, parsed, agentRoot, release, deployEnv);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* The env view deploy planning and secret sync work from: the process
|
|
116
|
+
* environment overlaid with the gateway's secrets store when one is
|
|
117
|
+
* configured, so declared secrets held only in the store still satisfy
|
|
118
|
+
* preflight and reach `--sync-secrets` without per-agent `.env` copies.
|
|
119
|
+
*/
|
|
120
|
+
async function resolveDeploySecretsEnv(manifest, agentRoot) {
|
|
121
|
+
return resolveSecretsEnv({
|
|
122
|
+
manifest,
|
|
123
|
+
env: process.env,
|
|
124
|
+
artifactRoot: agentRoot,
|
|
125
|
+
providerRoot: fileURLToPath(new URL("..", import.meta.url)),
|
|
126
|
+
devMode: false
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async function preflightChannelInstallations(artifact) {
|
|
130
|
+
const checks = await checkChannelInstallations(artifact.manifest, process.env, fetch);
|
|
131
|
+
for (const check of checks) {
|
|
132
|
+
const workspace = check.workspace ? ` (${check.workspace})` : "";
|
|
133
|
+
if (check.skipped) {
|
|
134
|
+
console.warn(`Channel preflight skipped for ${check.provider}${workspace}: ${check.detail}`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (!check.ok)
|
|
138
|
+
throw new Error(`Channel preflight failed for ${check.provider}${workspace}: ${check.detail}`);
|
|
139
|
+
console.log(`Channel preflight passed for ${check.provider}${workspace}.`);
|
|
140
|
+
if (check.missingOptionalScopes.length > 0) {
|
|
141
|
+
console.warn(`Optional ${check.provider} scopes not granted: ${check.missingOptionalScopes.join(", ")}.`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
101
144
|
}
|
|
102
145
|
/**
|
|
103
146
|
* The canonical receipt is per environment (`deployments/<environment>.json`).
|
|
@@ -131,13 +174,16 @@ function assertDestroyAllowed(plan, parsed) {
|
|
|
131
174
|
throw new Error(`Refusing to destroy the default environment "${plan.environment}" without --force. Alternate environments (--env <name>) are presumed disposable; the default one is not.`);
|
|
132
175
|
}
|
|
133
176
|
}
|
|
134
|
-
async function effectiveMissingRequirements(plan, definition) {
|
|
177
|
+
async function effectiveMissingRequirements(plan, definition, manifest, reusableSandboxEnvironment) {
|
|
135
178
|
let missing = plan.missingRequirements;
|
|
136
179
|
// VPS runtime credentials are validated from the remote 0600 secret file
|
|
137
180
|
// after optional sync. This allows repeat deploys without copying secrets
|
|
138
181
|
// from the VPS back onto the operator machine.
|
|
139
182
|
if (plan.target === "vps" && !plan.dryRun) {
|
|
140
|
-
|
|
183
|
+
const sandboxKind = manifest.gateway.sandbox?.kind ?? "local";
|
|
184
|
+
const provisioningEnv = new Set(adapterProviderMetadata(sandboxKind, "sandbox")?.sandboxEnvironment?.provisioningEnv ?? []);
|
|
185
|
+
missing = missing.filter((requirement) => requirement.kind !== "env"
|
|
186
|
+
|| (provisioningEnv.has(requirement.name) && !reusableSandboxEnvironment));
|
|
141
187
|
}
|
|
142
188
|
if (plan.target === "railway" && missing.some((requirement) => requirement.name === "RAILWAY_TOKEN")) {
|
|
143
189
|
const railwayBin = stringOption(definition, "railwayBin") ?? "railway";
|
|
@@ -185,7 +231,7 @@ function printDeployWarnings(plan) {
|
|
|
185
231
|
* is set and the publisher supports it. Reads `--secrets-from <path>` or the
|
|
186
232
|
* project `.env`. Logs key names only — never values.
|
|
187
233
|
*/
|
|
188
|
-
async function syncDeploySecretsIfRequested(publisher, plan, parsed, agentRoot) {
|
|
234
|
+
async function syncDeploySecretsIfRequested(publisher, plan, parsed, agentRoot, deployEnv) {
|
|
189
235
|
if (!booleanFlag(parsed, "sync-secrets"))
|
|
190
236
|
return;
|
|
191
237
|
if (!publisher.syncSecrets) {
|
|
@@ -200,7 +246,7 @@ async function syncDeploySecretsIfRequested(publisher, plan, parsed, agentRoot)
|
|
|
200
246
|
const fileSecrets = existsSync(secretsPath)
|
|
201
247
|
? readEnvSecretsFile(secretsPath)
|
|
202
248
|
: {};
|
|
203
|
-
const secrets = withDeclaredRuntimeEnv(fileSecrets, plan,
|
|
249
|
+
const secrets = withDeclaredRuntimeEnv(fileSecrets, plan, deployEnv);
|
|
204
250
|
const { runtimeSecrets, localDeployKeys } = splitDeploySecrets(secrets, plan);
|
|
205
251
|
if (localDeployKeys.length > 0) {
|
|
206
252
|
console.log(`Kept ${localDeployKeys.length} deploy credential(s) local: ${localDeployKeys.join(", ")}`);
|
|
@@ -259,7 +305,7 @@ async function railwayCliAuthenticated(railwayBin) {
|
|
|
259
305
|
* Every non-local target resolves through the open provider registry. Built-in
|
|
260
306
|
* flags only normalize provider options; publishing follows this single path.
|
|
261
307
|
*/
|
|
262
|
-
async function runProviderDeploy(artifact, plan, definition, parsed, agentRoot) {
|
|
308
|
+
async function runProviderDeploy(artifact, plan, definition, parsed, agentRoot, release, deployEnv) {
|
|
263
309
|
if (parsed.flags["domains-only"] !== undefined) {
|
|
264
310
|
throw new Error("--domains-only was removed. Use --ingress-only.");
|
|
265
311
|
}
|
|
@@ -290,9 +336,12 @@ async function runProviderDeploy(artifact, plan, definition, parsed, agentRoot)
|
|
|
290
336
|
if (booleanFlag(parsed, "activate")) {
|
|
291
337
|
if (!publisher.activate)
|
|
292
338
|
throw new Error(`Deploy target ${plan.target} does not support separate activation.`);
|
|
339
|
+
const activate = publisher.activate;
|
|
293
340
|
await publisher.preflight?.(artifact, plan);
|
|
294
|
-
const
|
|
341
|
+
const providerReceipt = await deployActionWithCleanup(publisher, artifact, plan, () => activate.call(publisher, artifact, plan));
|
|
342
|
+
const receipt = withReleaseSnapshot(providerReceipt, releaseSnapshotForReceipt(release, providerReceipt, true));
|
|
295
343
|
writeDeployReceipt(artifact.root, plan, receipt);
|
|
344
|
+
await wireDeployedConnectionEvents(artifact.manifest, receipt);
|
|
296
345
|
console.log(`${deployTargetLabel(plan.target)} prepared release activated.`);
|
|
297
346
|
console.log(JSON.stringify(receipt, null, 2));
|
|
298
347
|
return;
|
|
@@ -300,9 +349,12 @@ async function runProviderDeploy(artifact, plan, definition, parsed, agentRoot)
|
|
|
300
349
|
if (booleanFlag(parsed, "rollback")) {
|
|
301
350
|
if (!publisher.rollback)
|
|
302
351
|
throw new Error(`Deploy target ${plan.target} does not support rollback.`);
|
|
352
|
+
const rollback = publisher.rollback;
|
|
303
353
|
await publisher.preflight?.(artifact, plan);
|
|
304
|
-
const
|
|
354
|
+
const providerReceipt = await deployActionWithCleanup(publisher, artifact, plan, () => rollback.call(publisher, artifact, plan));
|
|
355
|
+
const receipt = withReleaseSnapshot(providerReceipt, releaseSnapshotForReceipt(release, providerReceipt, true));
|
|
305
356
|
writeDeployReceipt(artifact.root, plan, receipt);
|
|
357
|
+
await wireDeployedConnectionEvents(artifact.manifest, receipt);
|
|
306
358
|
console.log(`${deployTargetLabel(plan.target)} release rolled back.`);
|
|
307
359
|
console.log(JSON.stringify(receipt, null, 2));
|
|
308
360
|
return;
|
|
@@ -310,37 +362,195 @@ async function runProviderDeploy(artifact, plan, definition, parsed, agentRoot)
|
|
|
310
362
|
if (booleanFlag(parsed, "ingress-only")) {
|
|
311
363
|
if (!publisher.reconcileIngress)
|
|
312
364
|
throw new Error(`Deploy target ${plan.target} does not support ingress reconciliation.`);
|
|
365
|
+
const reconcileIngress = publisher.reconcileIngress;
|
|
313
366
|
await publisher.preflight?.(artifact, plan);
|
|
314
|
-
const receipt = await publisher.
|
|
367
|
+
const receipt = await deployActionWithCleanup(publisher, artifact, plan, () => reconcileIngress.call(publisher, artifact, plan));
|
|
315
368
|
writeDeployReceipt(artifact.root, plan, receipt);
|
|
316
369
|
console.log(`${deployTargetLabel(plan.target)} ingress reconciled.`);
|
|
317
370
|
console.log(JSON.stringify(receipt, null, 2));
|
|
318
371
|
return;
|
|
319
372
|
}
|
|
320
373
|
const prepareOnly = booleanFlag(parsed, "prepare-only");
|
|
374
|
+
const reconcileSandboxEnvironment = sandboxEnvironmentReconciler(artifact, reusableSandboxEnvironmentResolution(artifact, plan.environment));
|
|
321
375
|
console.log(`${prepareOnly ? "Preparing" : "Publishing"} Assembly Line revision ${plan.agentRevision} with ${plan.target}.`);
|
|
322
376
|
const migrationRequest = configuredMigrationRequest(artifact, parsed);
|
|
323
|
-
const
|
|
377
|
+
const progressStages = [
|
|
378
|
+
"preflight",
|
|
379
|
+
...(reconcileSandboxEnvironment ? ["sandbox-environment"] : []),
|
|
380
|
+
"prepare",
|
|
381
|
+
"secrets",
|
|
382
|
+
"migrations",
|
|
383
|
+
...(!prepareOnly ? ["activate"] : []),
|
|
384
|
+
...(publisher.cleanup ? ["cleanup"] : [])
|
|
385
|
+
];
|
|
386
|
+
const progressLabels = {
|
|
387
|
+
preflight: "Checking provider and host",
|
|
388
|
+
"sandbox-environment": "Reconciling sandbox environment",
|
|
389
|
+
prepare: "Uploading artifact and preparing runtime image",
|
|
390
|
+
secrets: "Reconciling runtime secrets",
|
|
391
|
+
migrations: "Running migrations",
|
|
392
|
+
activate: "Activating and health-checking the release",
|
|
393
|
+
cleanup: "Cleaning managed deployment artifacts"
|
|
394
|
+
};
|
|
395
|
+
const { providerReceipt, migrationStatus, lifecycle, sandboxEnvironment } = await executeDeployLifecycle({
|
|
324
396
|
publisher,
|
|
325
397
|
artifact,
|
|
326
398
|
plan,
|
|
327
399
|
migrationRequest,
|
|
328
400
|
activate: !prepareOnly,
|
|
329
|
-
|
|
330
|
-
|
|
401
|
+
...(reconcileSandboxEnvironment ? { reconcileSandboxEnvironment } : {}),
|
|
402
|
+
syncSecrets: () => syncDeploySecretsIfRequested(publisher, plan, parsed, agentRoot, deployEnv),
|
|
403
|
+
runFallbackMigrations: () => runConfiguredMigrations(artifact, plan, migrationRequest),
|
|
404
|
+
onProgress: (stage) => {
|
|
405
|
+
const index = progressStages.indexOf(stage);
|
|
406
|
+
if (index >= 0)
|
|
407
|
+
console.log(`[${index + 1}/${progressStages.length}] ${progressLabels[stage]}`);
|
|
408
|
+
}
|
|
331
409
|
});
|
|
332
|
-
const
|
|
410
|
+
const providerLifecycleReceipt = {
|
|
333
411
|
...providerReceipt,
|
|
334
412
|
migrationStatus,
|
|
413
|
+
...(sandboxEnvironment ? { sandboxEnvironment } : {}),
|
|
335
414
|
...(Object.keys(lifecycle).length > 0 ? { lifecycle } : {})
|
|
336
415
|
};
|
|
416
|
+
const receipt = withReleaseSnapshot(providerLifecycleReceipt, releaseSnapshotForReceipt(release, providerLifecycleReceipt, !prepareOnly));
|
|
337
417
|
writeDeployReceipt(artifact.root, plan, receipt);
|
|
418
|
+
if (!prepareOnly)
|
|
419
|
+
await wireDeployedConnectionEvents(artifact.manifest, receipt);
|
|
338
420
|
console.log(`${deployTargetLabel(plan.target)} deploy ${prepareOnly ? "prepared" : "completed"}.`);
|
|
339
421
|
if (artifact.manifest.deploymentRequirements?.remoteExecution) {
|
|
340
422
|
console.log(`Codex CLI and persistent credential storage are provisioned. Run \`assembly-line auth codex <agentRoot> --target ${plan.target} --env ${plan.environment}${prepareOnly ? " --prepared" : ""}\` to complete device authentication; OAuth tokens are not deployment secrets.`);
|
|
341
423
|
}
|
|
342
424
|
console.log(JSON.stringify(receipt, null, 2));
|
|
343
425
|
}
|
|
426
|
+
async function deployActionWithCleanup(publisher, artifact, plan, action) {
|
|
427
|
+
try {
|
|
428
|
+
const receipt = await action();
|
|
429
|
+
const cleanup = await executeDeployCleanup({ publisher, artifact, plan });
|
|
430
|
+
return cleanup ? { ...receipt, cleanup } : receipt;
|
|
431
|
+
}
|
|
432
|
+
catch (error) {
|
|
433
|
+
await executeDeployCleanup({ publisher, artifact, plan });
|
|
434
|
+
throw error;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
async function wireDeployedConnectionEvents(manifest, receipt) {
|
|
438
|
+
if (!manifest.connections.some((connection) => connection.events?.enabled))
|
|
439
|
+
return;
|
|
440
|
+
const deploymentUrl = receiptField(receipt, "deploymentUrl");
|
|
441
|
+
if (!deploymentUrl) {
|
|
442
|
+
console.warn("Connection events were not wired because the deploy target did not return a public deployment URL. Run `assembly-line connections wire <agentRoot> --url <publicUrl>` after ingress is available.");
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
const result = await wireConnectionEvents({
|
|
446
|
+
baseUrl: deploymentUrl,
|
|
447
|
+
...(process.env.ASSEMBLY_LINE_ADMIN_TOKEN ? { token: process.env.ASSEMBLY_LINE_ADMIN_TOKEN } : {}),
|
|
448
|
+
force: false
|
|
449
|
+
});
|
|
450
|
+
console.log("Connection event subscriptions reconciled.");
|
|
451
|
+
console.log(JSON.stringify(result, null, 2));
|
|
452
|
+
}
|
|
453
|
+
function receiptField(receipt, name) {
|
|
454
|
+
if (!receipt || typeof receipt !== "object" || Array.isArray(receipt))
|
|
455
|
+
return undefined;
|
|
456
|
+
const value = receipt[name];
|
|
457
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
458
|
+
}
|
|
459
|
+
function sandboxEnvironmentReconciler(artifact, reusableResolution) {
|
|
460
|
+
const definition = artifact.manifest.gateway.sandbox;
|
|
461
|
+
if (!definition || definition.kind === "local")
|
|
462
|
+
return undefined;
|
|
463
|
+
const sandbox = artifact.manifest.sandboxes.find((candidate) => candidate.adapter === definition.kind && candidate.environment);
|
|
464
|
+
const environment = sandbox?.environment;
|
|
465
|
+
if (!sandbox || !environment)
|
|
466
|
+
return undefined;
|
|
467
|
+
if (reusableResolution)
|
|
468
|
+
return async () => reusableResolution;
|
|
469
|
+
return async () => {
|
|
470
|
+
const passthroughEnv = sandboxPassthroughEnv(process.env, sandbox.env);
|
|
471
|
+
const provider = await resolveProvider("sandbox", definition, {
|
|
472
|
+
env: process.env,
|
|
473
|
+
fetch,
|
|
474
|
+
manifest: artifact.manifest,
|
|
475
|
+
artifactRoot: artifact.root,
|
|
476
|
+
providerRoot: fileURLToPath(new URL("..", import.meta.url)),
|
|
477
|
+
devMode: false
|
|
478
|
+
}, {
|
|
479
|
+
...(sandbox.image ? { image: sandbox.image } : {}),
|
|
480
|
+
environment,
|
|
481
|
+
...(Object.keys(passthroughEnv).length > 0 ? { env: passthroughEnv } : {}),
|
|
482
|
+
...(sandbox.workingDirectory ? { workingDirectory: sandbox.workingDirectory } : {}),
|
|
483
|
+
agentId: artifact.manifest.agent.id ?? artifact.manifest.agent.name ?? "agent",
|
|
484
|
+
sandboxName: sandbox.name
|
|
485
|
+
});
|
|
486
|
+
if (!provider.ensureEnvironment) {
|
|
487
|
+
throw new Error(`Sandbox provider ${definition.kind} cannot reconcile the compiled environment for ${sandbox.name}.`);
|
|
488
|
+
}
|
|
489
|
+
return provider.ensureEnvironment({
|
|
490
|
+
agentId: artifact.manifest.agent.id ?? artifact.manifest.agent.name ?? "agent",
|
|
491
|
+
sandboxName: sandbox.name,
|
|
492
|
+
adapter: definition.kind,
|
|
493
|
+
artifactRoot: artifact.root,
|
|
494
|
+
environment
|
|
495
|
+
});
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Reuse a sandbox artifact proven by a successful receipt when its provider and
|
|
500
|
+
* content fingerprint are unchanged. Runtime credentials stay on the host;
|
|
501
|
+
* only the provider-safe artifact reference crosses deploys.
|
|
502
|
+
*/
|
|
503
|
+
export function reusableSandboxEnvironmentResolution(artifact, environmentName) {
|
|
504
|
+
const definition = artifact.manifest.gateway.sandbox;
|
|
505
|
+
if (!definition || definition.kind === "local")
|
|
506
|
+
return undefined;
|
|
507
|
+
const sandbox = artifact.manifest.sandboxes.find((candidate) => candidate.adapter === definition.kind && candidate.environment);
|
|
508
|
+
const fingerprint = sandbox?.environment?.fingerprint;
|
|
509
|
+
if (!fingerprint)
|
|
510
|
+
return undefined;
|
|
511
|
+
const candidates = [
|
|
512
|
+
environmentReceiptPath(artifact.root, environmentName),
|
|
513
|
+
resolve(artifact.root, "deployment.json")
|
|
514
|
+
];
|
|
515
|
+
for (const path of candidates) {
|
|
516
|
+
try {
|
|
517
|
+
const receipt = JSON.parse(readFileSync(path, "utf8"));
|
|
518
|
+
if (receipt.status !== "published" || receipt.environment !== environmentName)
|
|
519
|
+
continue;
|
|
520
|
+
const resolution = receipt.sandboxEnvironment;
|
|
521
|
+
if (!isSandboxEnvironmentResolution(resolution))
|
|
522
|
+
continue;
|
|
523
|
+
if (resolution.provider !== definition.kind || resolution.fingerprint !== fingerprint)
|
|
524
|
+
continue;
|
|
525
|
+
return { ...resolution, action: "reused" };
|
|
526
|
+
}
|
|
527
|
+
catch {
|
|
528
|
+
// Missing, stale, or malformed receipts are not reuse evidence.
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return undefined;
|
|
532
|
+
}
|
|
533
|
+
function isSandboxEnvironmentResolution(value) {
|
|
534
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
535
|
+
return false;
|
|
536
|
+
const record = value;
|
|
537
|
+
return ["provider", "artifactKind", "fingerprint", "artifactId", "runtimeReference"]
|
|
538
|
+
.every((key) => typeof record[key] === "string" && record[key].length > 0)
|
|
539
|
+
&& ["reused", "built", "external"].includes(String(record.action));
|
|
540
|
+
}
|
|
541
|
+
export function sandboxPassthroughEnv(env, names) {
|
|
542
|
+
const values = {};
|
|
543
|
+
for (const name of names) {
|
|
544
|
+
const value = env[name];
|
|
545
|
+
if (value !== undefined)
|
|
546
|
+
values[name] = value;
|
|
547
|
+
}
|
|
548
|
+
const sensitive = Object.keys(values).filter(isSensitiveSandboxEnvName);
|
|
549
|
+
if (sensitive.length > 0) {
|
|
550
|
+
throw new Error(`Refusing host/control-plane secrets in global sandbox env: ${sensitive.join(", ")}.`);
|
|
551
|
+
}
|
|
552
|
+
return values;
|
|
553
|
+
}
|
|
344
554
|
function deployTargetLabel(target) {
|
|
345
555
|
if (target === "railway")
|
|
346
556
|
return "Railway";
|
|
@@ -358,7 +568,7 @@ function stringOption(definition, name) {
|
|
|
358
568
|
}
|
|
359
569
|
function configuredMigrationRequest(artifact, parsed) {
|
|
360
570
|
const entries = migrationEntriesForArtifact(artifact);
|
|
361
|
-
const command = stringFlag(parsed, "migration-command") ?? process.env.
|
|
571
|
+
const command = stringFlag(parsed, "migration-command") ?? process.env.ASSEMBLY_LINE_MIGRATION_COMMAND;
|
|
362
572
|
if (entries.length > 0 && !command) {
|
|
363
573
|
throw new Error("Migration files are present, but no migration runner was configured. Pass --migration-command or set ASSEMBLY_LINE_MIGRATION_COMMAND.");
|
|
364
574
|
}
|
|
@@ -375,18 +585,12 @@ async function runConfiguredMigrations(artifact, plan, request) {
|
|
|
375
585
|
console.log(`Running ${entries.length} migration file(s) with ${commandName}.`);
|
|
376
586
|
const result = await runCommand(commandName, [], {
|
|
377
587
|
cwd: artifact.root,
|
|
378
|
-
// Both spellings, permanently (the env-alias mirror never soaks out) so
|
|
379
|
-
// migration runners written against either prefix keep working.
|
|
380
588
|
env: {
|
|
381
589
|
...process.env,
|
|
382
590
|
ASSEMBLY_LINE_ARTIFACT_ROOT: artifact.root,
|
|
383
591
|
ASSEMBLY_LINE_AGENT_REVISION: plan.agentRevision,
|
|
384
592
|
ASSEMBLY_LINE_DEPLOY_ENV: plan.environment,
|
|
385
|
-
ASSEMBLY_LINE_MIGRATION_FILES: JSON.stringify(entries)
|
|
386
|
-
OPENEVE_ARTIFACT_ROOT: artifact.root,
|
|
387
|
-
OPENEVE_AGENT_REVISION: plan.agentRevision,
|
|
388
|
-
OPENEVE_DEPLOY_ENV: plan.environment,
|
|
389
|
-
OPENEVE_MIGRATION_FILES: JSON.stringify(entries)
|
|
593
|
+
ASSEMBLY_LINE_MIGRATION_FILES: JSON.stringify(entries)
|
|
390
594
|
}
|
|
391
595
|
});
|
|
392
596
|
if (result.exitCode !== 0) {
|
|
@@ -441,6 +645,7 @@ function localDeployReceipt(artifact, plan, status, deploymentUrl) {
|
|
|
441
645
|
status,
|
|
442
646
|
environment: plan.environment,
|
|
443
647
|
agentRevision: plan.agentRevision,
|
|
648
|
+
buildRevision: plan.buildRevision ?? plan.agentRevision,
|
|
444
649
|
artifactRoot: artifact.root,
|
|
445
650
|
deploymentUrl,
|
|
446
651
|
completedAt: new Date().toISOString()
|