run402 4.83.0 → 4.84.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.
Files changed (62) hide show
  1. package/gitvault-surface.json +1 -1
  2. package/lib/deploy-v2.mjs +30 -68
  3. package/lib/doctor-source-scan.mjs +2 -547
  4. package/lib/doctor.mjs +28 -8
  5. package/lib/sdk-errors.mjs +7 -0
  6. package/lib/status.mjs +1 -1
  7. package/lib/up.mjs +27 -10
  8. package/lib/update-check.mjs +11 -6
  9. package/lib/update-check.test.mjs +18 -5
  10. package/package.json +1 -1
  11. package/sdk/dist/actions.d.ts +16 -3
  12. package/sdk/dist/actions.d.ts.map +1 -1
  13. package/sdk/dist/config.d.ts +1 -1
  14. package/sdk/dist/config.d.ts.map +1 -1
  15. package/sdk/dist/config.js.map +1 -1
  16. package/sdk/dist/index.d.ts +2 -0
  17. package/sdk/dist/index.d.ts.map +1 -1
  18. package/sdk/dist/index.js +2 -0
  19. package/sdk/dist/index.js.map +1 -1
  20. package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
  21. package/sdk/dist/namespaces/deploy.js +2 -1
  22. package/sdk/dist/namespaces/deploy.js.map +1 -1
  23. package/sdk/dist/namespaces/deploy.types.d.ts +6 -0
  24. package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
  25. package/sdk/dist/namespaces/edge-evidence.d.ts +22 -0
  26. package/sdk/dist/namespaces/edge-evidence.d.ts.map +1 -0
  27. package/sdk/dist/namespaces/edge-evidence.js +38 -0
  28. package/sdk/dist/namespaces/edge-evidence.js.map +1 -0
  29. package/sdk/dist/namespaces/projects.d.ts.map +1 -1
  30. package/sdk/dist/namespaces/projects.js +9 -7
  31. package/sdk/dist/namespaces/projects.js.map +1 -1
  32. package/sdk/dist/node/actions-node.d.ts.map +1 -1
  33. package/sdk/dist/node/actions-node.js +71 -57
  34. package/sdk/dist/node/actions-node.js.map +1 -1
  35. package/sdk/dist/node/app-scope.d.ts +24 -0
  36. package/sdk/dist/node/app-scope.d.ts.map +1 -0
  37. package/sdk/dist/node/app-scope.js +47 -0
  38. package/sdk/dist/node/app-scope.js.map +1 -0
  39. package/sdk/dist/node/deploy-manifest.d.ts +6 -0
  40. package/sdk/dist/node/deploy-manifest.d.ts.map +1 -1
  41. package/sdk/dist/node/deploy-manifest.js +61 -0
  42. package/sdk/dist/node/deploy-manifest.js.map +1 -1
  43. package/sdk/dist/node/index.d.ts +5 -0
  44. package/sdk/dist/node/index.d.ts.map +1 -1
  45. package/sdk/dist/node/index.js +5 -0
  46. package/sdk/dist/node/index.js.map +1 -1
  47. package/sdk/dist/node/manifest-export.d.ts +5 -0
  48. package/sdk/dist/node/manifest-export.d.ts.map +1 -0
  49. package/sdk/dist/node/manifest-export.js +78 -0
  50. package/sdk/dist/node/manifest-export.js.map +1 -0
  51. package/sdk/dist/node/preflight.d.ts +65 -0
  52. package/sdk/dist/node/preflight.d.ts.map +1 -0
  53. package/sdk/dist/node/preflight.js +23 -0
  54. package/sdk/dist/node/preflight.js.map +1 -0
  55. package/sdk/dist/node/source-scan.d.ts +73 -0
  56. package/sdk/dist/node/source-scan.d.ts.map +1 -0
  57. package/sdk/dist/node/source-scan.js +552 -0
  58. package/sdk/dist/node/source-scan.js.map +1 -0
  59. package/sdk/dist/rest-diagnostics.d.ts +15 -0
  60. package/sdk/dist/rest-diagnostics.d.ts.map +1 -0
  61. package/sdk/dist/rest-diagnostics.js +19 -0
  62. package/sdk/dist/rest-diagnostics.js.map +1 -0
@@ -1,5 +1,5 @@
1
1
  {
2
- "surface_version": "4.83.0",
2
+ "surface_version": "4.84.0",
3
3
  "verbs": [
4
4
  "repos create",
5
5
  "repos list",
package/lib/deploy-v2.mjs CHANGED
@@ -33,6 +33,10 @@ import {
33
33
  normalizeDeployManifest,
34
34
  normalizeDeployResolveRequest,
35
35
  resolveDeploymentTarget,
36
+ resolveApplicationScope,
37
+ scanDeploymentSources,
38
+ serializeDeployManifest,
39
+ describeLocalPreflight,
36
40
  } from "#sdk/node";
37
41
  import { getSdk } from "./sdk.mjs";
38
42
  import { reportSdkError, fail } from "./sdk-errors.mjs";
@@ -48,8 +52,8 @@ import { sdkStats, printVerboseStats } from "./stats.mjs";
48
52
  const APPLY_HELP = `run402 deploy apply — Unified deploy primitive (v1.34+)
49
53
 
50
54
  Usage:
51
- run402 deploy apply --manifest <path> [--project <id>] [--check|--print-spec|--plan|--require-plan <id>] [--no-rehearse] [--quiet|--final-only] [--json]
52
- run402 deploy apply --spec '<json>' [--project <id>] [--check|--print-spec|--plan|--require-plan <id>] [--no-rehearse] [--quiet|--final-only] [--json]
55
+ run402 deploy apply --manifest <path> [--project <id>] [--check|--print-spec|--print-manifest|--plan|--require-plan <id>] [--no-rehearse] [--quiet|--final-only] [--json]
56
+ run402 deploy apply --spec '<json>' [--project <id>] [--check|--print-spec|--print-manifest|--plan|--require-plan <id>] [--no-rehearse] [--quiet|--final-only] [--json]
53
57
  run402 deploy apply --dir <build-output> [--manifest <path>] [--project <id>]
54
58
  cat spec.json | run402 deploy apply [--project <id>]
55
59
 
@@ -98,7 +102,9 @@ Options:
98
102
  @run402/astro installed in the project.
99
103
  --project <id> Override project_id from the manifest
100
104
  --check Validate and normalize locally. No gateway calls or uploads.
101
- --print-spec Print the normalized ReleaseSpec JSON. No gateway calls or uploads.
105
+ --print-spec Advanced SDK-native inspection JSON, not authoring input.
106
+ --print-manifest Export snake_case authoring JSON relative to the original manifest
107
+ directory. Unsupported constructs fail; no gateway calls or uploads.
102
108
  --plan Ask the gateway for a reviewed plan. No upload or commit.
103
109
  --no-rehearse Skip the automatic rehearsal. By default a migration-bearing plan
104
110
  against a project with a live release is rehearsed on a contained
@@ -769,7 +775,7 @@ function parseApplyArgs(args) {
769
775
  allowDirty: false,
770
776
  verbose: false,
771
777
  };
772
- const allowedFlags = ["--manifest", "--spec", "--dir", "--project", "--quiet", "--final-only", "--json", "--allow-warning", "--allow-warnings", "--check", "--print-spec", "--plan", "--no-rehearse", "--require-plan", "--plan-fingerprint", "--allow-dirty", "-v", "--verbose", "--help", "-h"];
778
+ const allowedFlags = ["--manifest", "--spec", "--dir", "--project", "--quiet", "--final-only", "--json", "--allow-warning", "--allow-warnings", "--check", "--print-spec", "--print-manifest", "--plan", "--no-rehearse", "--require-plan", "--plan-fingerprint", "--allow-dirty", "-v", "--verbose", "--help", "-h"];
773
779
 
774
780
  for (let i = 0; i < args.length; i++) {
775
781
  const arg = args[i];
@@ -832,6 +838,7 @@ function parseApplyArgs(args) {
832
838
  if (arg === "-v" || arg === "--verbose") { opts.verbose = true; continue; }
833
839
  if (arg === "--check") { setApplyMode(opts, "check", "--check"); continue; }
834
840
  if (arg === "--print-spec") { setApplyMode(opts, "printSpec", "--print-spec"); continue; }
841
+ if (arg === "--print-manifest") { setApplyMode(opts, "printManifest", "--print-manifest"); continue; }
835
842
  if (arg === "--plan") { setApplyMode(opts, "plan", "--plan"); continue; }
836
843
  if (arg === "--no-rehearse") { opts.noRehearse = true; continue; }
837
844
  if (typeof arg === "string" && arg.startsWith("-")) {
@@ -1168,6 +1175,7 @@ async function applyCmd(args) {
1168
1175
  ? await loadDeployManifest(manifestPath, {
1169
1176
 
1170
1177
  ...(defaultProject ? { defaultProject } : {}),
1178
+ validateFiles: true,
1171
1179
  })
1172
1180
  : await normalizeDeployManifest(spec, {
1173
1181
  baseDir: manifestPath ? dirname(manifestPath) : process.cwd(),
@@ -1178,14 +1186,16 @@ async function applyCmd(args) {
1178
1186
  reportSdkError(err);
1179
1187
  }
1180
1188
 
1189
+ const applicationScope = await resolveApplicationScope({ dir: opts.dir, manifest: manifestPath ?? undefined });
1181
1190
  const releaseSpec = normalizedManifest.spec;
1191
+ let target;
1182
1192
  try {
1183
- const target = await resolveDeploymentTarget({
1184
- appRoot: manifestPath ? dirname(manifestPath) : resolve(opts.dir || process.cwd()),
1193
+ target = await resolveDeploymentTarget({
1194
+ appRoot: applicationScope.app_root,
1185
1195
  manifestPath: manifestPath ?? undefined, projectId: opts.project || undefined, environmentProjectId: process.env.RUN402_PROJECT_ID || undefined,
1186
1196
  manifestProjectId: manifestProject || (releaseSpec.project === "prj_up_preflight_placeholder" ? undefined : releaseSpec.project),
1187
1197
  targetKind: isCoreApiTarget() ? "core" : "cloud", apiBase: API,
1188
- allowUnresolved: opts.mode === "check" || opts.mode === "printSpec",
1198
+ allowUnresolved: opts.mode === "check" || opts.mode === "printSpec" || opts.mode === "printManifest",
1189
1199
  });
1190
1200
  if (target.project_id) releaseSpec.project = target.project_id;
1191
1201
  } catch (err) { reportSdkError(err); }
@@ -1203,77 +1213,29 @@ async function applyCmd(args) {
1203
1213
  reportSdkError(err);
1204
1214
  }
1205
1215
 
1216
+ if (process.env.RUN402_DEPLOY_SKIP_SCAN !== "1") {
1217
+ const scan = scanDeploymentSources(releaseSpec, manifestPath ? dirname(manifestPath) : resolve(opts.dir || process.cwd()), opts.dir ? resolve(opts.dir) : undefined);
1218
+ if (scan.errors.length) fail({ code: "R402_AUTH_PREFLIGHT_FAILED", message: "Source scan blocked this application. Fix the reported findings, or explicitly override with RUN402_DEPLOY_SKIP_SCAN=1.", details: scan });
1219
+ }
1220
+
1206
1221
  if (opts.mode === "check") {
1207
1222
  console.log(JSON.stringify({
1208
1223
  ok: true,
1209
1224
  mode: "check",
1210
- project_id: releaseSpec.project,
1211
- manifest_path: manifestPath,
1225
+ project_id: target.project_id,
1226
+ ...describeLocalPreflight({ entryPoint: "deploy apply", appRoot: manifestPath ? dirname(manifestPath) : resolve(opts.dir || process.cwd()), manifestPath, authoring: normalizedManifest.manifest, spec: releaseSpec, target, apiBase: API }),
1212
1227
  }, null, 2));
1213
1228
  return;
1214
1229
  }
1230
+ if (opts.mode === "printManifest") {
1231
+ try { console.log(JSON.stringify(serializeDeployManifest(normalizedManifest, manifestPath ? dirname(manifestPath) : process.cwd(), opts.project || process.env.RUN402_PROJECT_ID), null, 2)); } catch (err) { reportSdkError(err); }
1232
+ return;
1233
+ }
1215
1234
  if (opts.mode === "printSpec") {
1216
- console.log(JSON.stringify(releaseSpec, null, 2));
1235
+ console.log(JSON.stringify({ ...releaseSpec, project: target.project_id ?? undefined }, null, 2));
1217
1236
  return;
1218
1237
  }
1219
1238
 
1220
- // Pre-flight source scan (auth-aware-ssr Section 9). Bypass via
1221
- // RUN402_DEPLOY_SKIP_SCAN=1 — useful for forcing a deploy when
1222
- // the scanner has a false positive that the operator has confirmed
1223
- // is fine. Hits with severity `error` fail the deploy.
1224
- //
1225
- // Scope: a `--dir` (Astro SSR build) deploy walks that dir —
1226
- // it IS the artifact. A manifest/spec/stdin deploy scans ONLY the
1227
- // on-disk source files the manifest actually references, resolved
1228
- // against the manifest's baseDir. We must NOT walk cwd/src for a
1229
- // manifest deploy: running from inside an unrelated source tree (e.g.
1230
- // the gateway monorepo, which legitimately has dozens of `getUser`
1231
- // references) would otherwise block a deploy of one unrelated HTML file.
1232
- if (!isNonApplyingMode(opts.mode) && process.env.RUN402_DEPLOY_SKIP_SCAN !== "1") {
1233
- try {
1234
- const { scanSourceTree, scanSourceFiles, SCAN_SEVERITY } = await import(
1235
- "./doctor-source-scan.mjs"
1236
- );
1237
- const scannableExt = /\.(?:ts|tsx|js|jsx|mjs|cjs|astro)$/;
1238
- let findings;
1239
- if (opts.dir) {
1240
- const scanRoot = isAbsolute(opts.dir)
1241
- ? opts.dir
1242
- : resolve(process.cwd(), opts.dir);
1243
- findings = scanSourceTree(scanRoot, { cwd: process.cwd() });
1244
- } else {
1245
- const baseDir = manifestPath ? dirname(manifestPath) : process.cwd();
1246
- const files = collectManifestSourceFiles(spec ?? normalizedManifest.manifest, baseDir).filter(
1247
- (p) => scannableExt.test(p) && existsSync(p),
1248
- );
1249
- findings = files.length > 0
1250
- ? scanSourceFiles(files, { cwd: process.cwd() })
1251
- : [];
1252
- }
1253
- const errorFindings = findings.filter((f) => f.severity === SCAN_SEVERITY.ERROR);
1254
- if (errorFindings.length > 0) {
1255
- const summary = errorFindings.slice(0, 10).map((f) => {
1256
- const loc = f.line ? `${f.file}:${f.line}` : f.file;
1257
- return ` ${f.code} ${loc}\n ${f.message}${f.canonical_name ? `\n fix: ${f.canonical_name}` : ""}`;
1258
- }).join("\n");
1259
- const more = errorFindings.length > 10 ? `\n ...and ${errorFindings.length - 10} more` : "";
1260
- fail({
1261
- code: "R402_AUTH_PREFLIGHT_FAILED",
1262
- message: `Source scan blocked deploy: ${errorFindings.length} R402_AUTH_* finding(s). Run \`run402 doctor\` for the full list. Bypass with RUN402_DEPLOY_SKIP_SCAN=1 if you're sure.`,
1263
- details: { findings: errorFindings, summary: `${summary}${more}` },
1264
- });
1265
- }
1266
- } catch (err) {
1267
- if (err && typeof err === "object" && err.code === "R402_AUTH_PREFLIGHT_FAILED") {
1268
- throw err;
1269
- }
1270
- // Scanner crashed — warn but don't block. The scanner is a safety
1271
- // net; the deploy should proceed if it can't read the source tree.
1272
- console.warn(
1273
- `[deploy] source scan skipped: ${err instanceof Error ? err.message : String(err)}`,
1274
- );
1275
- }
1276
- }
1277
1239
 
1278
1240
  let sdkOpts;
1279
1241
  const delegateToken = delegateTokenFromEnv();
@@ -1388,7 +1350,7 @@ async function applyCmd(args) {
1388
1350
  }
1389
1351
 
1390
1352
  function isNonApplyingMode(mode) {
1391
- return mode === "check" || mode === "printSpec" || mode === "plan";
1353
+ return mode === "check" || mode === "printSpec" || mode === "printManifest" || mode === "plan";
1392
1354
  }
1393
1355
 
1394
1356
  function hasGithubActionsOidcEnv(env = process.env) {