@infracraft/pulumi 1.22.0 → 1.22.1
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/dist/commands/deploy.cjs +1 -1
- package/dist/commands/deploy.mjs +1 -1
- package/dist/{sandbox-Bh7tQ1Jy.cjs → sandbox-BBnhmyM_.cjs} +7 -6
- package/dist/sandbox-BBnhmyM_.cjs.map +1 -0
- package/dist/{sandbox-8xQPhxw7.mjs → sandbox-BQtqMu-5.mjs} +7 -6
- package/dist/sandbox-BQtqMu-5.mjs.map +1 -0
- package/dist/sandbox.cjs +1 -1
- package/dist/sandbox.d.cts +5 -3
- package/dist/sandbox.d.cts.map +1 -1
- package/dist/sandbox.d.mts +5 -3
- package/dist/sandbox.d.mts.map +1 -1
- package/dist/sandbox.mjs +1 -1
- package/package.json +1 -1
- package/dist/sandbox-8xQPhxw7.mjs.map +0 -1
- package/dist/sandbox-Bh7tQ1Jy.cjs.map +0 -1
package/dist/commands/deploy.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_chunk = require('../chunk-BVYJZCqc.cjs');
|
|
3
3
|
const require_git_guard = require('../git-guard.cjs');
|
|
4
|
-
const require_sandbox = require('../sandbox-
|
|
4
|
+
const require_sandbox = require('../sandbox-BBnhmyM_.cjs');
|
|
5
5
|
let _pulumi_pulumi = require("@pulumi/pulumi");
|
|
6
6
|
_pulumi_pulumi = require_chunk.__toESM(_pulumi_pulumi, 1);
|
|
7
7
|
let _pulumi_command = require("@pulumi/command");
|
package/dist/commands/deploy.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __name } from "../chunk-OPjESj5l.mjs";
|
|
2
2
|
import { isGitGuard } from "../git-guard.mjs";
|
|
3
|
-
import { a as buildSandboxScript, n as isDeploySandbox, r as SandboxMode } from "../sandbox-
|
|
3
|
+
import { a as buildSandboxScript, n as isDeploySandbox, r as SandboxMode } from "../sandbox-BQtqMu-5.mjs";
|
|
4
4
|
import * as pulumi from "@pulumi/pulumi";
|
|
5
5
|
import * as command from "@pulumi/command";
|
|
6
6
|
|
|
@@ -13,17 +13,18 @@ function escapeAwkRegex(path) {
|
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
15
|
* Builds the shell filter applied to the `git ls-files` list before
|
|
16
|
-
* `rsync --files-from`.
|
|
17
|
-
* `
|
|
18
|
-
*
|
|
16
|
+
* `rsync --files-from`. Every excluded entry drops the path and its subtree
|
|
17
|
+
* but keeps the entry's own `package.json`: an excluded directory may be a
|
|
18
|
+
* workspace member, and the package manager fails the whole install when the
|
|
19
|
+
* root manifest names a workspace whose manifest is missing from the copy
|
|
20
|
+
* (a kept manifest for a non-member is inert). Returns `cat` (passthrough)
|
|
19
21
|
* when nothing is excluded. Uses awk so it is portable across macOS and Linux.
|
|
20
22
|
*/
|
|
21
23
|
function buildSandboxFileFilter(excludePaths = []) {
|
|
22
24
|
if (excludePaths.length === 0) return "cat";
|
|
23
25
|
return `awk '${excludePaths.map((entry) => {
|
|
24
26
|
const escaped = escapeAwkRegex(entry);
|
|
25
|
-
|
|
26
|
-
return `!/^${escaped}(\\/|$)/`;
|
|
27
|
+
return `!(/^${escaped}(\\/|$)/ && !/^${escaped}\\/package\\.json$/)`;
|
|
27
28
|
}).join(" && ")}'`;
|
|
28
29
|
}
|
|
29
30
|
/** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */
|
|
@@ -156,4 +157,4 @@ Object.defineProperty(exports, 'isDeploySandbox', {
|
|
|
156
157
|
return isDeploySandbox;
|
|
157
158
|
}
|
|
158
159
|
});
|
|
159
|
-
//# sourceMappingURL=sandbox-
|
|
160
|
+
//# sourceMappingURL=sandbox-BBnhmyM_.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-BBnhmyM_.cjs","names":["fs","path","pulumi"],"sources":["../../sandbox/dist/index.mjs","../src/sandbox.ts"],"sourcesContent":["import { t as __name } from \"./chunk-OPjESj5l.mjs\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n//#region src/index.ts\n/** Escapes a path literal for embedding inside an awk ERE. */\nfunction escapeAwkRegex(path) {\n\treturn path.replace(/[.[\\]{}()*+?^$|\\\\/]/g, \"\\\\$&\");\n}\n/**\n* Builds the shell filter applied to the `git ls-files` list before\n* `rsync --files-from`. Every excluded entry drops the path and its subtree\n* but keeps the entry's own `package.json`: an excluded directory may be a\n* workspace member, and the package manager fails the whole install when the\n* root manifest names a workspace whose manifest is missing from the copy\n* (a kept manifest for a non-member is inert). Returns `cat` (passthrough)\n* when nothing is excluded. Uses awk so it is portable across macOS and Linux.\n*/\nfunction buildSandboxFileFilter(excludePaths = []) {\n\tif (excludePaths.length === 0) return \"cat\";\n\treturn `awk '${excludePaths.map((entry) => {\n\t\tconst escaped = escapeAwkRegex(entry);\n\t\treturn `!(/^${escaped}(\\\\/|$)/ && !/^${escaped}\\\\/package\\\\.json$/)`;\n\t}).join(\" && \")}'`;\n}\n/** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */\nconst SANDBOX_ROOT = \"/tmp/infracraft\";\n/**\n* How a deploy's working copy is isolated. A closed set, so it is an enum rather\n* than a pair of booleans: the seam derives it from `dependsOn` presence\n* (DeploySandbox / GitGuard), which makes the impossible \"git-guard without a\n* sandbox\" state unrepresentable here.\n*/\nlet SandboxMode = /* @__PURE__ */ function(SandboxMode) {\n\t/** No isolation — run the CLI in the live working tree. */\n\tSandboxMode[\"NONE\"] = \"NONE\";\n\t/** Isolated copy carrying the repo's REAL `.git` (real commit/author exposed). */\n\tSandboxMode[\"ORIGINAL\"] = \"ORIGINAL\";\n\t/** Isolated copy with a metadata-free stub `.git` (no commit SHA / author). */\n\tSandboxMode[\"STUB\"] = \"STUB\";\n\treturn SandboxMode;\n}({});\n/**\n* Builds the shell for a deploy's `command.local.Command.create`. See\n* docs/superpowers/specs/2026-06-05-deploy-sandbox-design.md for the modes.\n*\n* Hardening: every script runs under POSIX `set -e` so any failed step aborts\n* instead of silently letting the platform CLI run against partial state.\n* `pipefail` is intentionally NOT used — the command runs under `/bin/sh`, which\n* may be `dash` (pipefail is a bash/ksh/zsh extension). To still catch a failing\n* `git ls-files` (a pipe would mask it, since an `rsync` of an empty list exits\n* 0), the copy is staged through intermediate list files rather than a pipe. The\n* `REPO` and `SANDBOX` command substitutions are explicitly guarded with clear\n* error messages.\n*/\nfunction buildSandboxScript(options) {\n\tconst { mode, appName, env, excludePaths, setup, cli } = options;\n\tconst head = `set -e; REPO=$(git rev-parse --show-toplevel) || { echo \"[infracraft] not inside a git repository\" >&2; exit 1; }`;\n\tconst runSetupAndCli = [setup, cli].filter(Boolean).join(\"; \");\n\tif (mode === \"NONE\") return `${head}; cd \"$REPO\"; ${runSetupAndCli}`;\n\tconst makeSandbox = [\n\t\t`PROJECT=$(basename \"$REPO\")`,\n\t\t`SANDBOX=$(mktemp -d \"${SANDBOX_ROOT}/$PROJECT-${env ? `${env}-${appName}` : appName}.XXXXXX\") || { echo \"[infracraft] mktemp failed\" >&2; exit 1; }`,\n\t\t`trap 'rm -rf \"$SANDBOX\"' EXIT`\n\t].join(\"; \");\n\tconst copy = [\n\t\t`git -C \"$REPO\" ls-files > \"$SANDBOX/.ic-ls\"`,\n\t\t`${mode === \"STUB\" ? buildSandboxFileFilter(excludePaths) : \"cat\"} \"$SANDBOX/.ic-ls\" > \"$SANDBOX/.ic-lsf\"`,\n\t\t`rsync -a --files-from=\"$SANDBOX/.ic-lsf\" \"$REPO\"/ \"$SANDBOX\"/`,\n\t\t`rm -f \"$SANDBOX/.ic-ls\" \"$SANDBOX/.ic-lsf\"`\n\t].join(\"; \");\n\tif (mode === \"STUB\") return `${head}; ${makeSandbox}; ${copy}; cd \"\\$SANDBOX\"; git init -q && git add -A; ${runSetupAndCli}`;\n\treturn `${head}; ${makeSandbox}; ${copy}; cp -c -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\" 2>/dev/null || cp -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\"; cd \"$SANDBOX\"; ${runSetupAndCli}`;\n}\n/** Sweep sandboxes orphaned by a hard-killed run (older than this). Kept well\n* above the worst-case deploy time (~30 min) but low enough that a SIGKILL\n* orphan does not linger for a day accumulating in /tmp. */\nconst STALE_SANDBOX_MS = 10800 * 1e3;\n/** mkdir the workspace root and GC stale sandboxes (best-effort). Sandboxes are\n* flat under the root (`/tmp/infracraft/<project>-<env>-<app>.XXXX`), so this\n* sweeps any entry older than the stale threshold. */\nfunction prepareSandboxWorkspace() {\n\tfs.mkdirSync(SANDBOX_ROOT, { recursive: true });\n\tlet entries = [];\n\ttry {\n\t\tentries = fs.readdirSync(SANDBOX_ROOT);\n\t} catch {\n\t\treturn;\n\t}\n\tconst now = Date.now();\n\tfor (const entry of entries) {\n\t\tconst full = path.join(SANDBOX_ROOT, entry);\n\t\ttry {\n\t\t\tif (now - fs.statSync(full).mtimeMs > STALE_SANDBOX_MS) fs.rmSync(full, {\n\t\t\t\trecursive: true,\n\t\t\t\tforce: true\n\t\t\t});\n\t\t} catch {}\n\t}\n}\n\n//#endregion\nexport { SandboxMode, buildSandboxFileFilter, buildSandboxScript, prepareSandboxWorkspace };\n//# sourceMappingURL=index.mjs.map","import { prepareSandboxWorkspace } from \"@infracraft/sandbox\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nexport type { SandboxScriptOptions } from \"@infracraft/sandbox\";\nexport {\n\tbuildSandboxFileFilter,\n\tbuildSandboxScript,\n\tSandboxMode,\n} from \"@infracraft/sandbox\";\n\n/** Cross-bundle brand: `instanceof` is unreliable when the seam and the resource\n * come from different built entries, so the seam detects sandboxes by this. */\nconst DEPLOY_SANDBOX_BRAND = Symbol.for(\"@infracraft/pulumi/DeploySandbox\");\n\n/**\n * Isolation marker + workspace lifecycle. Listing it in a deploy's `dependsOn`\n * makes that deploy run in an isolated `/tmp/infracraft` copy. Carries no config;\n * the repo root is derived at runtime by the deploy command.\n */\nexport class DeploySandbox extends pulumi.ComponentResource {\n\tconstructor(name: string, opts?: pulumi.ComponentResourceOptions) {\n\t\tsuper(\"infracraft:sandbox:DeploySandbox\", name, {}, opts);\n\n\t\t(this as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] = true;\n\n\t\tif (!pulumi.runtime.isDryRun()) {\n\t\t\tprepareSandboxWorkspace();\n\t\t}\n\n\t\tthis.registerOutputs({});\n\t}\n}\n\n/** Bundle-safe check for a `DeploySandbox` in a `dependsOn` array. */\nexport function isDeploySandbox(value: unknown): value is DeploySandbox {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t(value as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] === true\n\t);\n}\n"],"mappings":";;;;;;;;;;AAMA,SAAS,eAAe,MAAM;CAC7B,OAAO,KAAK,QAAQ,wBAAwB,MAAM;AACnD;;;;;;;;;;AAUA,SAAS,uBAAuB,eAAe,CAAC,GAAG;CAClD,IAAI,aAAa,WAAW,GAAG,OAAO;CACtC,OAAO,QAAQ,aAAa,KAAK,UAAU;EAC1C,MAAM,UAAU,eAAe,KAAK;EACpC,OAAO,OAAO,QAAQ,iBAAiB,QAAQ;CAChD,CAAC,EAAE,KAAK,MAAM,EAAE;AACjB;;AAEA,MAAM,eAAe;;;;;;;AAOrB,IAAI,cAA8B,yBAAS,aAAa;;CAEvD,YAAY,UAAU;;CAEtB,YAAY,cAAc;;CAE1B,YAAY,UAAU;CACtB,OAAO;AACR,EAAE,CAAC,CAAC;;;;;;;;;;;;;;AAcJ,SAAS,mBAAmB,SAAS;CACpC,MAAM,EAAE,MAAM,SAAS,KAAK,cAAc,OAAO,QAAQ;CACzD,MAAM,OAAO;CACb,MAAM,iBAAiB,CAAC,OAAO,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;CAC7D,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,gBAAgB;CACpD,MAAM,cAAc;EACnB;EACA,wBAAwB,aAAa,YAAY,MAAM,GAAG,IAAI,GAAG,YAAY,QAAQ;EACrF;CACD,EAAE,KAAK,IAAI;CACX,MAAM,OAAO;EACZ;EACA,GAAG,SAAS,SAAS,uBAAuB,YAAY,IAAI,MAAM;EAClE;EACA;CACD,EAAE,KAAK,IAAI;CACX,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,+CAA+C;CAC5G,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,gHAAgH;AACzJ;;;;AAIA,MAAM,mBAAmB,QAAQ;;;;AAIjC,SAAS,0BAA0B;CAClC,QAAG,UAAU,cAAc,EAAE,WAAW,KAAK,CAAC;CAC9C,IAAI,UAAU,CAAC;CACf,IAAI;EACH,UAAUA,QAAG,YAAY,YAAY;CACtC,QAAQ;EACP;CACD;CACA,MAAM,MAAM,KAAK,IAAI;CACrB,KAAK,MAAM,SAAS,SAAS;EAC5B,MAAM,OAAOC,UAAK,KAAK,cAAc,KAAK;EAC1C,IAAI;GACH,IAAI,MAAMD,QAAG,SAAS,IAAI,EAAE,UAAU,kBAAkB,QAAG,OAAO,MAAM;IACvE,WAAW;IACX,OAAO;GACR,CAAC;EACF,QAAQ,CAAC;CACV;AACD;;;;;;ACvFA,MAAM,uBAAuB,OAAO,IAAI,kCAAkC;;;;;;AAO1E,IAAa,gBAAb,cAAmCE,eAAO,kBAAkB;CAC3D,YAAY,MAAc,MAAwC;EACjE,MAAM,oCAAoC,MAAM,CAAC,GAAG,IAAI;EAExD,AAAC,KAAiC,wBAAwB;EAE1D,IAAI,CAACA,eAAO,QAAQ,SAAS,GAC5B,wBAAwB;EAGzB,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD;;AAGA,SAAgB,gBAAgB,OAAwC;CACvE,OACC,OAAO,UAAU,YACjB,UAAU,QACT,MAAkC,0BAA0B;AAE/D"}
|
|
@@ -10,17 +10,18 @@ function escapeAwkRegex(path) {
|
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* Builds the shell filter applied to the `git ls-files` list before
|
|
13
|
-
* `rsync --files-from`.
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
13
|
+
* `rsync --files-from`. Every excluded entry drops the path and its subtree
|
|
14
|
+
* but keeps the entry's own `package.json`: an excluded directory may be a
|
|
15
|
+
* workspace member, and the package manager fails the whole install when the
|
|
16
|
+
* root manifest names a workspace whose manifest is missing from the copy
|
|
17
|
+
* (a kept manifest for a non-member is inert). Returns `cat` (passthrough)
|
|
16
18
|
* when nothing is excluded. Uses awk so it is portable across macOS and Linux.
|
|
17
19
|
*/
|
|
18
20
|
function buildSandboxFileFilter(excludePaths = []) {
|
|
19
21
|
if (excludePaths.length === 0) return "cat";
|
|
20
22
|
return `awk '${excludePaths.map((entry) => {
|
|
21
23
|
const escaped = escapeAwkRegex(entry);
|
|
22
|
-
|
|
23
|
-
return `!/^${escaped}(\\/|$)/`;
|
|
24
|
+
return `!(/^${escaped}(\\/|$)/ && !/^${escaped}\\/package\\.json$/)`;
|
|
24
25
|
}).join(" && ")}'`;
|
|
25
26
|
}
|
|
26
27
|
/** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */
|
|
@@ -124,4 +125,4 @@ function isDeploySandbox(value) {
|
|
|
124
125
|
|
|
125
126
|
//#endregion
|
|
126
127
|
export { buildSandboxScript as a, buildSandboxFileFilter as i, isDeploySandbox as n, SandboxMode as r, DeploySandbox as t };
|
|
127
|
-
//# sourceMappingURL=sandbox-
|
|
128
|
+
//# sourceMappingURL=sandbox-BQtqMu-5.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-BQtqMu-5.mjs","names":[],"sources":["../../sandbox/dist/index.mjs","../src/sandbox.ts"],"sourcesContent":["import { t as __name } from \"./chunk-OPjESj5l.mjs\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n//#region src/index.ts\n/** Escapes a path literal for embedding inside an awk ERE. */\nfunction escapeAwkRegex(path) {\n\treturn path.replace(/[.[\\]{}()*+?^$|\\\\/]/g, \"\\\\$&\");\n}\n/**\n* Builds the shell filter applied to the `git ls-files` list before\n* `rsync --files-from`. Every excluded entry drops the path and its subtree\n* but keeps the entry's own `package.json`: an excluded directory may be a\n* workspace member, and the package manager fails the whole install when the\n* root manifest names a workspace whose manifest is missing from the copy\n* (a kept manifest for a non-member is inert). Returns `cat` (passthrough)\n* when nothing is excluded. Uses awk so it is portable across macOS and Linux.\n*/\nfunction buildSandboxFileFilter(excludePaths = []) {\n\tif (excludePaths.length === 0) return \"cat\";\n\treturn `awk '${excludePaths.map((entry) => {\n\t\tconst escaped = escapeAwkRegex(entry);\n\t\treturn `!(/^${escaped}(\\\\/|$)/ && !/^${escaped}\\\\/package\\\\.json$/)`;\n\t}).join(\" && \")}'`;\n}\n/** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */\nconst SANDBOX_ROOT = \"/tmp/infracraft\";\n/**\n* How a deploy's working copy is isolated. A closed set, so it is an enum rather\n* than a pair of booleans: the seam derives it from `dependsOn` presence\n* (DeploySandbox / GitGuard), which makes the impossible \"git-guard without a\n* sandbox\" state unrepresentable here.\n*/\nlet SandboxMode = /* @__PURE__ */ function(SandboxMode) {\n\t/** No isolation — run the CLI in the live working tree. */\n\tSandboxMode[\"NONE\"] = \"NONE\";\n\t/** Isolated copy carrying the repo's REAL `.git` (real commit/author exposed). */\n\tSandboxMode[\"ORIGINAL\"] = \"ORIGINAL\";\n\t/** Isolated copy with a metadata-free stub `.git` (no commit SHA / author). */\n\tSandboxMode[\"STUB\"] = \"STUB\";\n\treturn SandboxMode;\n}({});\n/**\n* Builds the shell for a deploy's `command.local.Command.create`. See\n* docs/superpowers/specs/2026-06-05-deploy-sandbox-design.md for the modes.\n*\n* Hardening: every script runs under POSIX `set -e` so any failed step aborts\n* instead of silently letting the platform CLI run against partial state.\n* `pipefail` is intentionally NOT used — the command runs under `/bin/sh`, which\n* may be `dash` (pipefail is a bash/ksh/zsh extension). To still catch a failing\n* `git ls-files` (a pipe would mask it, since an `rsync` of an empty list exits\n* 0), the copy is staged through intermediate list files rather than a pipe. The\n* `REPO` and `SANDBOX` command substitutions are explicitly guarded with clear\n* error messages.\n*/\nfunction buildSandboxScript(options) {\n\tconst { mode, appName, env, excludePaths, setup, cli } = options;\n\tconst head = `set -e; REPO=$(git rev-parse --show-toplevel) || { echo \"[infracraft] not inside a git repository\" >&2; exit 1; }`;\n\tconst runSetupAndCli = [setup, cli].filter(Boolean).join(\"; \");\n\tif (mode === \"NONE\") return `${head}; cd \"$REPO\"; ${runSetupAndCli}`;\n\tconst makeSandbox = [\n\t\t`PROJECT=$(basename \"$REPO\")`,\n\t\t`SANDBOX=$(mktemp -d \"${SANDBOX_ROOT}/$PROJECT-${env ? `${env}-${appName}` : appName}.XXXXXX\") || { echo \"[infracraft] mktemp failed\" >&2; exit 1; }`,\n\t\t`trap 'rm -rf \"$SANDBOX\"' EXIT`\n\t].join(\"; \");\n\tconst copy = [\n\t\t`git -C \"$REPO\" ls-files > \"$SANDBOX/.ic-ls\"`,\n\t\t`${mode === \"STUB\" ? buildSandboxFileFilter(excludePaths) : \"cat\"} \"$SANDBOX/.ic-ls\" > \"$SANDBOX/.ic-lsf\"`,\n\t\t`rsync -a --files-from=\"$SANDBOX/.ic-lsf\" \"$REPO\"/ \"$SANDBOX\"/`,\n\t\t`rm -f \"$SANDBOX/.ic-ls\" \"$SANDBOX/.ic-lsf\"`\n\t].join(\"; \");\n\tif (mode === \"STUB\") return `${head}; ${makeSandbox}; ${copy}; cd \"\\$SANDBOX\"; git init -q && git add -A; ${runSetupAndCli}`;\n\treturn `${head}; ${makeSandbox}; ${copy}; cp -c -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\" 2>/dev/null || cp -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\"; cd \"$SANDBOX\"; ${runSetupAndCli}`;\n}\n/** Sweep sandboxes orphaned by a hard-killed run (older than this). Kept well\n* above the worst-case deploy time (~30 min) but low enough that a SIGKILL\n* orphan does not linger for a day accumulating in /tmp. */\nconst STALE_SANDBOX_MS = 10800 * 1e3;\n/** mkdir the workspace root and GC stale sandboxes (best-effort). Sandboxes are\n* flat under the root (`/tmp/infracraft/<project>-<env>-<app>.XXXX`), so this\n* sweeps any entry older than the stale threshold. */\nfunction prepareSandboxWorkspace() {\n\tfs.mkdirSync(SANDBOX_ROOT, { recursive: true });\n\tlet entries = [];\n\ttry {\n\t\tentries = fs.readdirSync(SANDBOX_ROOT);\n\t} catch {\n\t\treturn;\n\t}\n\tconst now = Date.now();\n\tfor (const entry of entries) {\n\t\tconst full = path.join(SANDBOX_ROOT, entry);\n\t\ttry {\n\t\t\tif (now - fs.statSync(full).mtimeMs > STALE_SANDBOX_MS) fs.rmSync(full, {\n\t\t\t\trecursive: true,\n\t\t\t\tforce: true\n\t\t\t});\n\t\t} catch {}\n\t}\n}\n\n//#endregion\nexport { SandboxMode, buildSandboxFileFilter, buildSandboxScript, prepareSandboxWorkspace };\n//# sourceMappingURL=index.mjs.map","import { prepareSandboxWorkspace } from \"@infracraft/sandbox\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nexport type { SandboxScriptOptions } from \"@infracraft/sandbox\";\nexport {\n\tbuildSandboxFileFilter,\n\tbuildSandboxScript,\n\tSandboxMode,\n} from \"@infracraft/sandbox\";\n\n/** Cross-bundle brand: `instanceof` is unreliable when the seam and the resource\n * come from different built entries, so the seam detects sandboxes by this. */\nconst DEPLOY_SANDBOX_BRAND = Symbol.for(\"@infracraft/pulumi/DeploySandbox\");\n\n/**\n * Isolation marker + workspace lifecycle. Listing it in a deploy's `dependsOn`\n * makes that deploy run in an isolated `/tmp/infracraft` copy. Carries no config;\n * the repo root is derived at runtime by the deploy command.\n */\nexport class DeploySandbox extends pulumi.ComponentResource {\n\tconstructor(name: string, opts?: pulumi.ComponentResourceOptions) {\n\t\tsuper(\"infracraft:sandbox:DeploySandbox\", name, {}, opts);\n\n\t\t(this as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] = true;\n\n\t\tif (!pulumi.runtime.isDryRun()) {\n\t\t\tprepareSandboxWorkspace();\n\t\t}\n\n\t\tthis.registerOutputs({});\n\t}\n}\n\n/** Bundle-safe check for a `DeploySandbox` in a `dependsOn` array. */\nexport function isDeploySandbox(value: unknown): value is DeploySandbox {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t(value as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] === true\n\t);\n}\n"],"mappings":";;;;;;;AAMA,SAAS,eAAe,MAAM;CAC7B,OAAO,KAAK,QAAQ,wBAAwB,MAAM;AACnD;;;;;;;;;;AAUA,SAAS,uBAAuB,eAAe,CAAC,GAAG;CAClD,IAAI,aAAa,WAAW,GAAG,OAAO;CACtC,OAAO,QAAQ,aAAa,KAAK,UAAU;EAC1C,MAAM,UAAU,eAAe,KAAK;EACpC,OAAO,OAAO,QAAQ,iBAAiB,QAAQ;CAChD,CAAC,EAAE,KAAK,MAAM,EAAE;AACjB;;AAEA,MAAM,eAAe;;;;;;;AAOrB,IAAI,cAA8B,yBAAS,aAAa;;CAEvD,YAAY,UAAU;;CAEtB,YAAY,cAAc;;CAE1B,YAAY,UAAU;CACtB,OAAO;AACR,EAAE,CAAC,CAAC;;;;;;;;;;;;;;AAcJ,SAAS,mBAAmB,SAAS;CACpC,MAAM,EAAE,MAAM,SAAS,KAAK,cAAc,OAAO,QAAQ;CACzD,MAAM,OAAO;CACb,MAAM,iBAAiB,CAAC,OAAO,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;CAC7D,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,gBAAgB;CACpD,MAAM,cAAc;EACnB;EACA,wBAAwB,aAAa,YAAY,MAAM,GAAG,IAAI,GAAG,YAAY,QAAQ;EACrF;CACD,EAAE,KAAK,IAAI;CACX,MAAM,OAAO;EACZ;EACA,GAAG,SAAS,SAAS,uBAAuB,YAAY,IAAI,MAAM;EAClE;EACA;CACD,EAAE,KAAK,IAAI;CACX,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,+CAA+C;CAC5G,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,gHAAgH;AACzJ;;;;AAIA,MAAM,mBAAmB,QAAQ;;;;AAIjC,SAAS,0BAA0B;CAClC,GAAG,UAAU,cAAc,EAAE,WAAW,KAAK,CAAC;CAC9C,IAAI,UAAU,CAAC;CACf,IAAI;EACH,UAAU,GAAG,YAAY,YAAY;CACtC,QAAQ;EACP;CACD;CACA,MAAM,MAAM,KAAK,IAAI;CACrB,KAAK,MAAM,SAAS,SAAS;EAC5B,MAAM,OAAO,KAAK,KAAK,cAAc,KAAK;EAC1C,IAAI;GACH,IAAI,MAAM,GAAG,SAAS,IAAI,EAAE,UAAU,kBAAkB,GAAG,OAAO,MAAM;IACvE,WAAW;IACX,OAAO;GACR,CAAC;EACF,QAAQ,CAAC;CACV;AACD;;;;;;ACvFA,MAAM,uBAAuB,OAAO,IAAI,kCAAkC;;;;;;AAO1E,IAAa,gBAAb,cAAmC,OAAO,kBAAkB;CAC3D,YAAY,MAAc,MAAwC;EACjE,MAAM,oCAAoC,MAAM,CAAC,GAAG,IAAI;EAExD,AAAC,KAAiC,wBAAwB;EAE1D,IAAI,CAAC,OAAO,QAAQ,SAAS,GAC5B,wBAAwB;EAGzB,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD;;AAGA,SAAgB,gBAAgB,OAAwC;CACvE,OACC,OAAO,UAAU,YACjB,UAAU,QACT,MAAkC,0BAA0B;AAE/D"}
|
package/dist/sandbox.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_sandbox = require('./sandbox-
|
|
2
|
+
const require_sandbox = require('./sandbox-BBnhmyM_.cjs');
|
|
3
3
|
|
|
4
4
|
exports.DeploySandbox = require_sandbox.DeploySandbox;
|
|
5
5
|
exports.SandboxMode = require_sandbox.SandboxMode;
|
package/dist/sandbox.d.cts
CHANGED
|
@@ -5,9 +5,11 @@ import * as pulumi from "@pulumi/pulumi";
|
|
|
5
5
|
//#region src/index.d.ts
|
|
6
6
|
/**
|
|
7
7
|
* Builds the shell filter applied to the `git ls-files` list before
|
|
8
|
-
* `rsync --files-from`.
|
|
9
|
-
* `
|
|
10
|
-
*
|
|
8
|
+
* `rsync --files-from`. Every excluded entry drops the path and its subtree
|
|
9
|
+
* but keeps the entry's own `package.json`: an excluded directory may be a
|
|
10
|
+
* workspace member, and the package manager fails the whole install when the
|
|
11
|
+
* root manifest names a workspace whose manifest is missing from the copy
|
|
12
|
+
* (a kept manifest for a non-member is inert). Returns `cat` (passthrough)
|
|
11
13
|
* when nothing is excluded. Uses awk so it is portable across macOS and Linux.
|
|
12
14
|
*/
|
|
13
15
|
declare function buildSandboxFileFilter(excludePaths?: string[]): string;
|
package/dist/sandbox.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.d.cts","names":["t","__name","buildSandboxFileFilter","excludePaths","SandboxMode","NONE","ORIGINAL","STUB","SandboxScriptOptions","mode","appName","env","setup","cli","buildSandboxScript","options","prepareSandboxWorkspace"],"sources":["../../sandbox/dist/index.d.mts","../src/sandbox.ts"],"mappings":";;;;;;AAAmD;;;;
|
|
1
|
+
{"version":3,"file":"sandbox.d.cts","names":["t","__name","buildSandboxFileFilter","excludePaths","SandboxMode","NONE","ORIGINAL","STUB","SandboxScriptOptions","mode","appName","env","setup","cli","buildSandboxScript","options","prepareSandboxWorkspace"],"sources":["../../sandbox/dist/index.d.mts","../src/sandbox.ts"],"mappings":";;;;;;AAAmD;;;;AAYY;AAAA;;;iBAA9CE,sBAAAA,CAAuBC,YAAuB;;;;;AAazD;AAAA;aANOC,WAAAA;;EAEXC,IAAAA;EAQAI;EANAH,QAAAA;EAQAI;EANAH,IAAAA;AAAAA;AAAAA,UAEQC,oBAAAA;EAaRK;EAXAJ,IAAAA,EAAML,WAAW;EAWd;EATHM,OAAAA;EAwBiC;;EArBjCC,GAAAA;EAqB+D;EAnB/DR,YAAAA;;EAEAS,KAAAA;ECnBF;EDqBEC,GAAAA;AAAAA;;;;;;;;;;ACpB+D;AAcjE;;;iBDqBiBC,kBAAAA,CAAmBC,OAA6B,EAApBP,oBAAoB;;;;;;;AAvDd;;;;cCmBtC,aAAA,SAAsB,MAAA,CAAO,iBAAiB;cAC9C,IAAA,UAAc,IAAA,GAAO,MAAA,CAAO,wBAAA;AAAA;;iBAczB,eAAA,CAAgB,KAAA,YAAiB,KAAA,IAAS,aAAa"}
|
package/dist/sandbox.d.mts
CHANGED
|
@@ -5,9 +5,11 @@ import * as pulumi from "@pulumi/pulumi";
|
|
|
5
5
|
//#region src/index.d.ts
|
|
6
6
|
/**
|
|
7
7
|
* Builds the shell filter applied to the `git ls-files` list before
|
|
8
|
-
* `rsync --files-from`.
|
|
9
|
-
* `
|
|
10
|
-
*
|
|
8
|
+
* `rsync --files-from`. Every excluded entry drops the path and its subtree
|
|
9
|
+
* but keeps the entry's own `package.json`: an excluded directory may be a
|
|
10
|
+
* workspace member, and the package manager fails the whole install when the
|
|
11
|
+
* root manifest names a workspace whose manifest is missing from the copy
|
|
12
|
+
* (a kept manifest for a non-member is inert). Returns `cat` (passthrough)
|
|
11
13
|
* when nothing is excluded. Uses awk so it is portable across macOS and Linux.
|
|
12
14
|
*/
|
|
13
15
|
declare function buildSandboxFileFilter(excludePaths?: string[]): string;
|
package/dist/sandbox.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.d.mts","names":["t","__name","buildSandboxFileFilter","excludePaths","SandboxMode","NONE","ORIGINAL","STUB","SandboxScriptOptions","mode","appName","env","setup","cli","buildSandboxScript","options","prepareSandboxWorkspace"],"sources":["../../sandbox/dist/index.d.mts","../src/sandbox.ts"],"mappings":";;;;;;AAAmD;;;;
|
|
1
|
+
{"version":3,"file":"sandbox.d.mts","names":["t","__name","buildSandboxFileFilter","excludePaths","SandboxMode","NONE","ORIGINAL","STUB","SandboxScriptOptions","mode","appName","env","setup","cli","buildSandboxScript","options","prepareSandboxWorkspace"],"sources":["../../sandbox/dist/index.d.mts","../src/sandbox.ts"],"mappings":";;;;;;AAAmD;;;;AAYY;AAAA;;;iBAA9CE,sBAAAA,CAAuBC,YAAuB;;;;;AAazD;AAAA;aANOC,WAAAA;;EAEXC,IAAAA;EAQAI;EANAH,QAAAA;EAQAI;EANAH,IAAAA;AAAAA;AAAAA,UAEQC,oBAAAA;EAaRK;EAXAJ,IAAAA,EAAML,WAAW;EAWd;EATHM,OAAAA;EAwBiC;;EArBjCC,GAAAA;EAqB+D;EAnB/DR,YAAAA;;EAEAS,KAAAA;ECnBF;EDqBEC,GAAAA;AAAAA;;;;;;;;;;ACpB+D;AAcjE;;;iBDqBiBC,kBAAAA,CAAmBC,OAA6B,EAApBP,oBAAoB;;;;;;;AAvDd;;;;cCmBtC,aAAA,SAAsB,MAAA,CAAO,iBAAiB;cAC9C,IAAA,UAAc,IAAA,GAAO,MAAA,CAAO,wBAAA;AAAA;;iBAczB,eAAA,CAAgB,KAAA,YAAiB,KAAA,IAAS,aAAa"}
|
package/dist/sandbox.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as buildSandboxScript, i as buildSandboxFileFilter, n as isDeploySandbox, r as SandboxMode, t as DeploySandbox } from "./sandbox-
|
|
1
|
+
import { a as buildSandboxScript, i as buildSandboxFileFilter, n as isDeploySandbox, r as SandboxMode, t as DeploySandbox } from "./sandbox-BQtqMu-5.mjs";
|
|
2
2
|
|
|
3
3
|
export { DeploySandbox, SandboxMode, buildSandboxFileFilter, buildSandboxScript, isDeploySandbox };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infracraft/pulumi",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Native Pulumi providers for Railway, Neon, Vercel, and Fly.io with adopt-or-create semantics and deploy orchestration. No Terraform bridge.",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox-8xQPhxw7.mjs","names":[],"sources":["../../sandbox/dist/index.mjs","../src/sandbox.ts"],"sourcesContent":["import { t as __name } from \"./chunk-OPjESj5l.mjs\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n//#region src/index.ts\n/** Escapes a path literal for embedding inside an awk ERE. */\nfunction escapeAwkRegex(path) {\n\treturn path.replace(/[.[\\]{}()*+?^$|\\\\/]/g, \"\\\\$&\");\n}\n/**\n* Builds the shell filter applied to the `git ls-files` list before\n* `rsync --files-from`. For `apps/<x>` it drops the app's files but keeps\n* `apps/<x>/package.json` (the monorepo workspace graph needs it during build);\n* any other entry drops the path and its subtree. Returns `cat` (passthrough)\n* when nothing is excluded. Uses awk so it is portable across macOS and Linux.\n*/\nfunction buildSandboxFileFilter(excludePaths = []) {\n\tif (excludePaths.length === 0) return \"cat\";\n\treturn `awk '${excludePaths.map((entry) => {\n\t\tconst escaped = escapeAwkRegex(entry);\n\t\tif (entry.startsWith(\"apps/\")) return `!(/^${escaped}\\\\// && !/^${escaped}\\\\/package\\\\.json$/)`;\n\t\treturn `!/^${escaped}(\\\\/|$)/`;\n\t}).join(\" && \")}'`;\n}\n/** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */\nconst SANDBOX_ROOT = \"/tmp/infracraft\";\n/**\n* How a deploy's working copy is isolated. A closed set, so it is an enum rather\n* than a pair of booleans: the seam derives it from `dependsOn` presence\n* (DeploySandbox / GitGuard), which makes the impossible \"git-guard without a\n* sandbox\" state unrepresentable here.\n*/\nlet SandboxMode = /* @__PURE__ */ function(SandboxMode) {\n\t/** No isolation — run the CLI in the live working tree. */\n\tSandboxMode[\"NONE\"] = \"NONE\";\n\t/** Isolated copy carrying the repo's REAL `.git` (real commit/author exposed). */\n\tSandboxMode[\"ORIGINAL\"] = \"ORIGINAL\";\n\t/** Isolated copy with a metadata-free stub `.git` (no commit SHA / author). */\n\tSandboxMode[\"STUB\"] = \"STUB\";\n\treturn SandboxMode;\n}({});\n/**\n* Builds the shell for a deploy's `command.local.Command.create`. See\n* docs/superpowers/specs/2026-06-05-deploy-sandbox-design.md for the modes.\n*\n* Hardening: every script runs under POSIX `set -e` so any failed step aborts\n* instead of silently letting the platform CLI run against partial state.\n* `pipefail` is intentionally NOT used — the command runs under `/bin/sh`, which\n* may be `dash` (pipefail is a bash/ksh/zsh extension). To still catch a failing\n* `git ls-files` (a pipe would mask it, since an `rsync` of an empty list exits\n* 0), the copy is staged through intermediate list files rather than a pipe. The\n* `REPO` and `SANDBOX` command substitutions are explicitly guarded with clear\n* error messages.\n*/\nfunction buildSandboxScript(options) {\n\tconst { mode, appName, env, excludePaths, setup, cli } = options;\n\tconst head = `set -e; REPO=$(git rev-parse --show-toplevel) || { echo \"[infracraft] not inside a git repository\" >&2; exit 1; }`;\n\tconst runSetupAndCli = [setup, cli].filter(Boolean).join(\"; \");\n\tif (mode === \"NONE\") return `${head}; cd \"$REPO\"; ${runSetupAndCli}`;\n\tconst makeSandbox = [\n\t\t`PROJECT=$(basename \"$REPO\")`,\n\t\t`SANDBOX=$(mktemp -d \"${SANDBOX_ROOT}/$PROJECT-${env ? `${env}-${appName}` : appName}.XXXXXX\") || { echo \"[infracraft] mktemp failed\" >&2; exit 1; }`,\n\t\t`trap 'rm -rf \"$SANDBOX\"' EXIT`\n\t].join(\"; \");\n\tconst copy = [\n\t\t`git -C \"$REPO\" ls-files > \"$SANDBOX/.ic-ls\"`,\n\t\t`${mode === \"STUB\" ? buildSandboxFileFilter(excludePaths) : \"cat\"} \"$SANDBOX/.ic-ls\" > \"$SANDBOX/.ic-lsf\"`,\n\t\t`rsync -a --files-from=\"$SANDBOX/.ic-lsf\" \"$REPO\"/ \"$SANDBOX\"/`,\n\t\t`rm -f \"$SANDBOX/.ic-ls\" \"$SANDBOX/.ic-lsf\"`\n\t].join(\"; \");\n\tif (mode === \"STUB\") return `${head}; ${makeSandbox}; ${copy}; cd \"\\$SANDBOX\"; git init -q && git add -A; ${runSetupAndCli}`;\n\treturn `${head}; ${makeSandbox}; ${copy}; cp -c -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\" 2>/dev/null || cp -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\"; cd \"$SANDBOX\"; ${runSetupAndCli}`;\n}\n/** Sweep sandboxes orphaned by a hard-killed run (older than this). Kept well\n* above the worst-case deploy time (~30 min) but low enough that a SIGKILL\n* orphan does not linger for a day accumulating in /tmp. */\nconst STALE_SANDBOX_MS = 10800 * 1e3;\n/** mkdir the workspace root and GC stale sandboxes (best-effort). Sandboxes are\n* flat under the root (`/tmp/infracraft/<project>-<env>-<app>.XXXX`), so this\n* sweeps any entry older than the stale threshold. */\nfunction prepareSandboxWorkspace() {\n\tfs.mkdirSync(SANDBOX_ROOT, { recursive: true });\n\tlet entries = [];\n\ttry {\n\t\tentries = fs.readdirSync(SANDBOX_ROOT);\n\t} catch {\n\t\treturn;\n\t}\n\tconst now = Date.now();\n\tfor (const entry of entries) {\n\t\tconst full = path.join(SANDBOX_ROOT, entry);\n\t\ttry {\n\t\t\tif (now - fs.statSync(full).mtimeMs > STALE_SANDBOX_MS) fs.rmSync(full, {\n\t\t\t\trecursive: true,\n\t\t\t\tforce: true\n\t\t\t});\n\t\t} catch {}\n\t}\n}\n\n//#endregion\nexport { SandboxMode, buildSandboxFileFilter, buildSandboxScript, prepareSandboxWorkspace };\n//# sourceMappingURL=index.mjs.map","import { prepareSandboxWorkspace } from \"@infracraft/sandbox\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nexport type { SandboxScriptOptions } from \"@infracraft/sandbox\";\nexport {\n\tbuildSandboxFileFilter,\n\tbuildSandboxScript,\n\tSandboxMode,\n} from \"@infracraft/sandbox\";\n\n/** Cross-bundle brand: `instanceof` is unreliable when the seam and the resource\n * come from different built entries, so the seam detects sandboxes by this. */\nconst DEPLOY_SANDBOX_BRAND = Symbol.for(\"@infracraft/pulumi/DeploySandbox\");\n\n/**\n * Isolation marker + workspace lifecycle. Listing it in a deploy's `dependsOn`\n * makes that deploy run in an isolated `/tmp/infracraft` copy. Carries no config;\n * the repo root is derived at runtime by the deploy command.\n */\nexport class DeploySandbox extends pulumi.ComponentResource {\n\tconstructor(name: string, opts?: pulumi.ComponentResourceOptions) {\n\t\tsuper(\"infracraft:sandbox:DeploySandbox\", name, {}, opts);\n\n\t\t(this as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] = true;\n\n\t\tif (!pulumi.runtime.isDryRun()) {\n\t\t\tprepareSandboxWorkspace();\n\t\t}\n\n\t\tthis.registerOutputs({});\n\t}\n}\n\n/** Bundle-safe check for a `DeploySandbox` in a `dependsOn` array. */\nexport function isDeploySandbox(value: unknown): value is DeploySandbox {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t(value as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] === true\n\t);\n}\n"],"mappings":";;;;;;;AAMA,SAAS,eAAe,MAAM;CAC7B,OAAO,KAAK,QAAQ,wBAAwB,MAAM;AACnD;;;;;;;;AAQA,SAAS,uBAAuB,eAAe,CAAC,GAAG;CAClD,IAAI,aAAa,WAAW,GAAG,OAAO;CACtC,OAAO,QAAQ,aAAa,KAAK,UAAU;EAC1C,MAAM,UAAU,eAAe,KAAK;EACpC,IAAI,MAAM,WAAW,OAAO,GAAG,OAAO,OAAO,QAAQ,aAAa,QAAQ;EAC1E,OAAO,MAAM,QAAQ;CACtB,CAAC,EAAE,KAAK,MAAM,EAAE;AACjB;;AAEA,MAAM,eAAe;;;;;;;AAOrB,IAAI,cAA8B,yBAAS,aAAa;;CAEvD,YAAY,UAAU;;CAEtB,YAAY,cAAc;;CAE1B,YAAY,UAAU;CACtB,OAAO;AACR,EAAE,CAAC,CAAC;;;;;;;;;;;;;;AAcJ,SAAS,mBAAmB,SAAS;CACpC,MAAM,EAAE,MAAM,SAAS,KAAK,cAAc,OAAO,QAAQ;CACzD,MAAM,OAAO;CACb,MAAM,iBAAiB,CAAC,OAAO,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;CAC7D,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,gBAAgB;CACpD,MAAM,cAAc;EACnB;EACA,wBAAwB,aAAa,YAAY,MAAM,GAAG,IAAI,GAAG,YAAY,QAAQ;EACrF;CACD,EAAE,KAAK,IAAI;CACX,MAAM,OAAO;EACZ;EACA,GAAG,SAAS,SAAS,uBAAuB,YAAY,IAAI,MAAM;EAClE;EACA;CACD,EAAE,KAAK,IAAI;CACX,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,+CAA+C;CAC5G,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,gHAAgH;AACzJ;;;;AAIA,MAAM,mBAAmB,QAAQ;;;;AAIjC,SAAS,0BAA0B;CAClC,GAAG,UAAU,cAAc,EAAE,WAAW,KAAK,CAAC;CAC9C,IAAI,UAAU,CAAC;CACf,IAAI;EACH,UAAU,GAAG,YAAY,YAAY;CACtC,QAAQ;EACP;CACD;CACA,MAAM,MAAM,KAAK,IAAI;CACrB,KAAK,MAAM,SAAS,SAAS;EAC5B,MAAM,OAAO,KAAK,KAAK,cAAc,KAAK;EAC1C,IAAI;GACH,IAAI,MAAM,GAAG,SAAS,IAAI,EAAE,UAAU,kBAAkB,GAAG,OAAO,MAAM;IACvE,WAAW;IACX,OAAO;GACR,CAAC;EACF,QAAQ,CAAC;CACV;AACD;;;;;;ACtFA,MAAM,uBAAuB,OAAO,IAAI,kCAAkC;;;;;;AAO1E,IAAa,gBAAb,cAAmC,OAAO,kBAAkB;CAC3D,YAAY,MAAc,MAAwC;EACjE,MAAM,oCAAoC,MAAM,CAAC,GAAG,IAAI;EAExD,AAAC,KAAiC,wBAAwB;EAE1D,IAAI,CAAC,OAAO,QAAQ,SAAS,GAC5B,wBAAwB;EAGzB,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD;;AAGA,SAAgB,gBAAgB,OAAwC;CACvE,OACC,OAAO,UAAU,YACjB,UAAU,QACT,MAAkC,0BAA0B;AAE/D"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox-Bh7tQ1Jy.cjs","names":["fs","path","pulumi"],"sources":["../../sandbox/dist/index.mjs","../src/sandbox.ts"],"sourcesContent":["import { t as __name } from \"./chunk-OPjESj5l.mjs\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n//#region src/index.ts\n/** Escapes a path literal for embedding inside an awk ERE. */\nfunction escapeAwkRegex(path) {\n\treturn path.replace(/[.[\\]{}()*+?^$|\\\\/]/g, \"\\\\$&\");\n}\n/**\n* Builds the shell filter applied to the `git ls-files` list before\n* `rsync --files-from`. For `apps/<x>` it drops the app's files but keeps\n* `apps/<x>/package.json` (the monorepo workspace graph needs it during build);\n* any other entry drops the path and its subtree. Returns `cat` (passthrough)\n* when nothing is excluded. Uses awk so it is portable across macOS and Linux.\n*/\nfunction buildSandboxFileFilter(excludePaths = []) {\n\tif (excludePaths.length === 0) return \"cat\";\n\treturn `awk '${excludePaths.map((entry) => {\n\t\tconst escaped = escapeAwkRegex(entry);\n\t\tif (entry.startsWith(\"apps/\")) return `!(/^${escaped}\\\\// && !/^${escaped}\\\\/package\\\\.json$/)`;\n\t\treturn `!/^${escaped}(\\\\/|$)/`;\n\t}).join(\" && \")}'`;\n}\n/** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */\nconst SANDBOX_ROOT = \"/tmp/infracraft\";\n/**\n* How a deploy's working copy is isolated. A closed set, so it is an enum rather\n* than a pair of booleans: the seam derives it from `dependsOn` presence\n* (DeploySandbox / GitGuard), which makes the impossible \"git-guard without a\n* sandbox\" state unrepresentable here.\n*/\nlet SandboxMode = /* @__PURE__ */ function(SandboxMode) {\n\t/** No isolation — run the CLI in the live working tree. */\n\tSandboxMode[\"NONE\"] = \"NONE\";\n\t/** Isolated copy carrying the repo's REAL `.git` (real commit/author exposed). */\n\tSandboxMode[\"ORIGINAL\"] = \"ORIGINAL\";\n\t/** Isolated copy with a metadata-free stub `.git` (no commit SHA / author). */\n\tSandboxMode[\"STUB\"] = \"STUB\";\n\treturn SandboxMode;\n}({});\n/**\n* Builds the shell for a deploy's `command.local.Command.create`. See\n* docs/superpowers/specs/2026-06-05-deploy-sandbox-design.md for the modes.\n*\n* Hardening: every script runs under POSIX `set -e` so any failed step aborts\n* instead of silently letting the platform CLI run against partial state.\n* `pipefail` is intentionally NOT used — the command runs under `/bin/sh`, which\n* may be `dash` (pipefail is a bash/ksh/zsh extension). To still catch a failing\n* `git ls-files` (a pipe would mask it, since an `rsync` of an empty list exits\n* 0), the copy is staged through intermediate list files rather than a pipe. The\n* `REPO` and `SANDBOX` command substitutions are explicitly guarded with clear\n* error messages.\n*/\nfunction buildSandboxScript(options) {\n\tconst { mode, appName, env, excludePaths, setup, cli } = options;\n\tconst head = `set -e; REPO=$(git rev-parse --show-toplevel) || { echo \"[infracraft] not inside a git repository\" >&2; exit 1; }`;\n\tconst runSetupAndCli = [setup, cli].filter(Boolean).join(\"; \");\n\tif (mode === \"NONE\") return `${head}; cd \"$REPO\"; ${runSetupAndCli}`;\n\tconst makeSandbox = [\n\t\t`PROJECT=$(basename \"$REPO\")`,\n\t\t`SANDBOX=$(mktemp -d \"${SANDBOX_ROOT}/$PROJECT-${env ? `${env}-${appName}` : appName}.XXXXXX\") || { echo \"[infracraft] mktemp failed\" >&2; exit 1; }`,\n\t\t`trap 'rm -rf \"$SANDBOX\"' EXIT`\n\t].join(\"; \");\n\tconst copy = [\n\t\t`git -C \"$REPO\" ls-files > \"$SANDBOX/.ic-ls\"`,\n\t\t`${mode === \"STUB\" ? buildSandboxFileFilter(excludePaths) : \"cat\"} \"$SANDBOX/.ic-ls\" > \"$SANDBOX/.ic-lsf\"`,\n\t\t`rsync -a --files-from=\"$SANDBOX/.ic-lsf\" \"$REPO\"/ \"$SANDBOX\"/`,\n\t\t`rm -f \"$SANDBOX/.ic-ls\" \"$SANDBOX/.ic-lsf\"`\n\t].join(\"; \");\n\tif (mode === \"STUB\") return `${head}; ${makeSandbox}; ${copy}; cd \"\\$SANDBOX\"; git init -q && git add -A; ${runSetupAndCli}`;\n\treturn `${head}; ${makeSandbox}; ${copy}; cp -c -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\" 2>/dev/null || cp -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\"; cd \"$SANDBOX\"; ${runSetupAndCli}`;\n}\n/** Sweep sandboxes orphaned by a hard-killed run (older than this). Kept well\n* above the worst-case deploy time (~30 min) but low enough that a SIGKILL\n* orphan does not linger for a day accumulating in /tmp. */\nconst STALE_SANDBOX_MS = 10800 * 1e3;\n/** mkdir the workspace root and GC stale sandboxes (best-effort). Sandboxes are\n* flat under the root (`/tmp/infracraft/<project>-<env>-<app>.XXXX`), so this\n* sweeps any entry older than the stale threshold. */\nfunction prepareSandboxWorkspace() {\n\tfs.mkdirSync(SANDBOX_ROOT, { recursive: true });\n\tlet entries = [];\n\ttry {\n\t\tentries = fs.readdirSync(SANDBOX_ROOT);\n\t} catch {\n\t\treturn;\n\t}\n\tconst now = Date.now();\n\tfor (const entry of entries) {\n\t\tconst full = path.join(SANDBOX_ROOT, entry);\n\t\ttry {\n\t\t\tif (now - fs.statSync(full).mtimeMs > STALE_SANDBOX_MS) fs.rmSync(full, {\n\t\t\t\trecursive: true,\n\t\t\t\tforce: true\n\t\t\t});\n\t\t} catch {}\n\t}\n}\n\n//#endregion\nexport { SandboxMode, buildSandboxFileFilter, buildSandboxScript, prepareSandboxWorkspace };\n//# sourceMappingURL=index.mjs.map","import { prepareSandboxWorkspace } from \"@infracraft/sandbox\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nexport type { SandboxScriptOptions } from \"@infracraft/sandbox\";\nexport {\n\tbuildSandboxFileFilter,\n\tbuildSandboxScript,\n\tSandboxMode,\n} from \"@infracraft/sandbox\";\n\n/** Cross-bundle brand: `instanceof` is unreliable when the seam and the resource\n * come from different built entries, so the seam detects sandboxes by this. */\nconst DEPLOY_SANDBOX_BRAND = Symbol.for(\"@infracraft/pulumi/DeploySandbox\");\n\n/**\n * Isolation marker + workspace lifecycle. Listing it in a deploy's `dependsOn`\n * makes that deploy run in an isolated `/tmp/infracraft` copy. Carries no config;\n * the repo root is derived at runtime by the deploy command.\n */\nexport class DeploySandbox extends pulumi.ComponentResource {\n\tconstructor(name: string, opts?: pulumi.ComponentResourceOptions) {\n\t\tsuper(\"infracraft:sandbox:DeploySandbox\", name, {}, opts);\n\n\t\t(this as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] = true;\n\n\t\tif (!pulumi.runtime.isDryRun()) {\n\t\t\tprepareSandboxWorkspace();\n\t\t}\n\n\t\tthis.registerOutputs({});\n\t}\n}\n\n/** Bundle-safe check for a `DeploySandbox` in a `dependsOn` array. */\nexport function isDeploySandbox(value: unknown): value is DeploySandbox {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t(value as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] === true\n\t);\n}\n"],"mappings":";;;;;;;;;;AAMA,SAAS,eAAe,MAAM;CAC7B,OAAO,KAAK,QAAQ,wBAAwB,MAAM;AACnD;;;;;;;;AAQA,SAAS,uBAAuB,eAAe,CAAC,GAAG;CAClD,IAAI,aAAa,WAAW,GAAG,OAAO;CACtC,OAAO,QAAQ,aAAa,KAAK,UAAU;EAC1C,MAAM,UAAU,eAAe,KAAK;EACpC,IAAI,MAAM,WAAW,OAAO,GAAG,OAAO,OAAO,QAAQ,aAAa,QAAQ;EAC1E,OAAO,MAAM,QAAQ;CACtB,CAAC,EAAE,KAAK,MAAM,EAAE;AACjB;;AAEA,MAAM,eAAe;;;;;;;AAOrB,IAAI,cAA8B,yBAAS,aAAa;;CAEvD,YAAY,UAAU;;CAEtB,YAAY,cAAc;;CAE1B,YAAY,UAAU;CACtB,OAAO;AACR,EAAE,CAAC,CAAC;;;;;;;;;;;;;;AAcJ,SAAS,mBAAmB,SAAS;CACpC,MAAM,EAAE,MAAM,SAAS,KAAK,cAAc,OAAO,QAAQ;CACzD,MAAM,OAAO;CACb,MAAM,iBAAiB,CAAC,OAAO,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;CAC7D,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,gBAAgB;CACpD,MAAM,cAAc;EACnB;EACA,wBAAwB,aAAa,YAAY,MAAM,GAAG,IAAI,GAAG,YAAY,QAAQ;EACrF;CACD,EAAE,KAAK,IAAI;CACX,MAAM,OAAO;EACZ;EACA,GAAG,SAAS,SAAS,uBAAuB,YAAY,IAAI,MAAM;EAClE;EACA;CACD,EAAE,KAAK,IAAI;CACX,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,+CAA+C;CAC5G,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,gHAAgH;AACzJ;;;;AAIA,MAAM,mBAAmB,QAAQ;;;;AAIjC,SAAS,0BAA0B;CAClC,QAAG,UAAU,cAAc,EAAE,WAAW,KAAK,CAAC;CAC9C,IAAI,UAAU,CAAC;CACf,IAAI;EACH,UAAUA,QAAG,YAAY,YAAY;CACtC,QAAQ;EACP;CACD;CACA,MAAM,MAAM,KAAK,IAAI;CACrB,KAAK,MAAM,SAAS,SAAS;EAC5B,MAAM,OAAOC,UAAK,KAAK,cAAc,KAAK;EAC1C,IAAI;GACH,IAAI,MAAMD,QAAG,SAAS,IAAI,EAAE,UAAU,kBAAkB,QAAG,OAAO,MAAM;IACvE,WAAW;IACX,OAAO;GACR,CAAC;EACF,QAAQ,CAAC;CACV;AACD;;;;;;ACtFA,MAAM,uBAAuB,OAAO,IAAI,kCAAkC;;;;;;AAO1E,IAAa,gBAAb,cAAmCE,eAAO,kBAAkB;CAC3D,YAAY,MAAc,MAAwC;EACjE,MAAM,oCAAoC,MAAM,CAAC,GAAG,IAAI;EAExD,AAAC,KAAiC,wBAAwB;EAE1D,IAAI,CAACA,eAAO,QAAQ,SAAS,GAC5B,wBAAwB;EAGzB,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD;;AAGA,SAAgB,gBAAgB,OAAwC;CACvE,OACC,OAAO,UAAU,YACjB,UAAU,QACT,MAAkC,0BAA0B;AAE/D"}
|