mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-09 03:39:51 -10:00
feat(slice-05): /install routes declared workflow_specs after successful bootstrap (Item 6 Checkpoint 7.3e step 3) (OPR.0.3.2.5)
Mirror of the 7.3a skills + 7.3d plugins /install integrations for the workflow_specs cross-primitive kind. Closes 7.3e (workflow_specs end- to-end). Per orch ruling Candidate A on Item-6 completeness: 3-of-4 named kinds shipped (skills + plugins HYBRID + workflow_specs); 7.3f context_packs + 7.3g agent_images next, then 7.4 gstack proof case. routeWorkflowSpecsAfterBootstrap (bundles.ts +69): - Resolves targetWorkflowSpecsDir via the CALLER CONTRACT pinned ind43b7729: nodePath.join(ContextPackSettingsStore.resolveConfig() .workspaceSpecsRoot, "workflows") — SettingsStore is sole authority, no hardcoded default. If SettingsStore throws or workspaceSpecsRoot is undefined, returns null (no-op routing; install still succeeds). Mirror of startup.ts:910-916 try/catch posture. - bundlePath-only signature per the5f410eeeB1 decoupling lesson (routing fires on the dual-override path where installMeta is null). - Canonical unpack trust boundary; parses bundle.yaml; filters manifest workflow_specs[] to strings; delegates to routeWorkflowSpecs (which enforces both-sides containment internally). workflowSpecsRouterFsOps (bundles.ts +4): real-fs wrapper — fs.existsSync / fs.readFileSync utf-8 / fs.writeFileSync utf-8 / fs.mkdirSync recursive. /install completed branch integration: third try/catch block alongside skills + plugins routings; workflowSpecsRouting key conditionally merged into the extras object (omitted if null). bundle-routes.test.ts (+214): 3 new tests: 1. POST /install routes declared workflow_specs after successful bootstrap (completed branch) — basic end-to-end. Env-overrides OPENRIG_WORKSPACE_SPECS_ROOT to a tmp specsRoot; bundle tampered with workflow_specs: [packages/test-pkg/workflows/onboarding.yaml] (verbatim package path, same shape as the skills test pattern); asserts workflowSpecsRouting.routedCount=1 + records[0].status= "routed" + file at <specsRoot>/workflows/packages/test-pkg/workflows/ onboarding.yaml with content preserved. 2. POST /install routes declared workflow_specs even when both --skip-version-check and --force are set (B1 mirror) — PROACTIVELY covers the5f410eeedual-override decoupling lesson this time. 3. POST /install does NOT include workflowSpecsRouting when bundle has no workflow_specs[] — null-branch / extras-merge correctness. Discriminator-flip evidence BEFORE this commit (PROACTIVELY this time, per banked commitment): Flip A — insert `return null;` at routeWorkflowSpecsAfterBootstrap entry. Result: 2/44 fail — exactly the basic with-workflow_specs + B1-mirror dual-override tests (both fail at expect(body.workflowSpecsRouting).toBeDefined()). The 42 other tests stay green including the no-workflow_specs null-branch test (because extras-key stays absent in both "function returns null" and "no workflow_specs[] declared" cases). Restored. Flip B — wrap the call site in /install with `if (installMeta) workflowSpecsRouting = ...;` (simulated5f410eeere-coupling). Result: 1/44 fail — ONLY the B1-mirror dual-override test fails; the basic test stays green because its installMeta is non-null when the dual-override flags are absent. PROVES the B1-mirror test specifically catches the dual-override decoupling regression, not the general integration path (which Flip A covered). Restored. Final: 170/170 across the full slice-05 daemon suite (bundle-routes 44 + bundle-workflow-specs-router 8 + bundle-skills- router 8 + bundle-plugins-router 9 + bundle-types 49 + pod-bundle- assembler 51). Mirror of cont.18 ratification: workflow_specs is the 3rd cross-primitive kind; the source primitive (WorkflowSpecCache + scanner) is on main per guard-verified reachability. The integration writes to the live scanner-reachable location so installed specs become operator-visible through the existing Library UI on the next scan. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
1 parent
d43b7729f9
commit
9f9ebe0a51
2 files changed
+287
No files matched your search
@@ -23,6 +23,8 @@ import { BundleAuditReader, BundleAuditWriter, type BundleAuditFsOps, type Bundl
|
||||
import { getDefaultOpenRigPath } from "../openrig-compat.js";
|
||||
import { routeSkills, type SkillsRouterFsOps, type RouteSkillsResult } from "../domain/bundle-skills-router.js";
|
||||
import { routePlugins, type PluginsRouterFsOps, type RoutePluginsResult, type PluginRoutingInput } from "../domain/bundle-plugins-router.js";
|
||||
import { routeWorkflowSpecs, type WorkflowSpecsRouterFsOps, type RouteWorkflowSpecsResult } from "../domain/bundle-workflow-specs-router.js";
|
||||
import { SettingsStore as ContextPackSettingsStore } from "../domain/user-settings/settings-store.js";
|
||||
|
||||
/**
|
||||
* Read the daemon's own package.json version at call time (Item 1 / slice-05).
|
||||
@@ -288,6 +290,70 @@ function pluginsRouterFsOps(): PluginsRouterFsOps {
|
||||
};
|
||||
}
|
||||
|
||||
/** Item 6 / slice-05 Checkpoint 7.3e step 3: real WorkflowSpecsRouterFsOps backed by node:fs. */
|
||||
function workflowSpecsRouterFsOps(): WorkflowSpecsRouterFsOps {
|
||||
return {
|
||||
exists: (p) => fs.existsSync(p),
|
||||
readFile: (p) => fs.readFileSync(p, "utf-8"),
|
||||
writeFile: (p, c) => fs.writeFileSync(p, c, "utf-8"),
|
||||
mkdirp: (p) => fs.mkdirSync(p, { recursive: true }),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Item 6 / slice-05 Checkpoint 7.3e step 3: extract the bundle safely
|
||||
* (banked unpack trust boundary) and route any declared workflow_specs to
|
||||
* the operator workflow-specs library. Returns null when bundle has no
|
||||
* workflow_specs[] (no-op), no manifest, or workspaceSpecsRoot unresolved.
|
||||
*
|
||||
* Target resolution per the CALLER CONTRACT in
|
||||
* bundle-workflow-specs-router.ts: SettingsStore is the sole authority.
|
||||
* Resolved as nodePath.join(workspaceSpecsRoot, "workflows") — the path
|
||||
* that spec-library-workflow-scanner actually reads (startup.ts:903-916).
|
||||
* If SettingsStore cannot resolve workspaceSpecsRoot (settings not yet
|
||||
* initialized / config error), we return null and the install lifecycle
|
||||
* proceeds without workflow_specs routing — mirror of startup.ts:910-916
|
||||
* try/catch posture.
|
||||
*
|
||||
* Mirror of routeSkillsAfterBootstrap / routePluginsAfterBootstrap pattern:
|
||||
* takes bundlePath only (decoupled from installMeta per the 5f410eee B1
|
||||
* lesson; routing must fire on the dual-override path too).
|
||||
*/
|
||||
async function routeWorkflowSpecsAfterBootstrap(bundlePath: string): Promise<RouteWorkflowSpecsResult | null> {
|
||||
let workspaceSpecsRoot: string | undefined;
|
||||
try {
|
||||
const settingsStore = new ContextPackSettingsStore();
|
||||
workspaceSpecsRoot = settingsStore.resolveConfig().workspaceSpecsRoot;
|
||||
} catch {
|
||||
return null; // settings unresolvable; no-op routing
|
||||
}
|
||||
if (!workspaceSpecsRoot) return null;
|
||||
const targetWorkflowSpecsDir = nodePath.join(workspaceSpecsRoot, "workflows");
|
||||
|
||||
const tmpDir = fs.mkdtempSync(nodePath.join(os.tmpdir(), "bundle-workflow-specs-route-"));
|
||||
try {
|
||||
await unpack(bundlePath, tmpDir);
|
||||
const manifestPath = nodePath.join(tmpDir, "bundle.yaml");
|
||||
if (!fs.existsSync(manifestPath)) return null;
|
||||
const manifestYaml = fs.readFileSync(manifestPath, "utf-8");
|
||||
const manifest = parsePodBundleManifest(manifestYaml) as Record<string, unknown>;
|
||||
const rawWorkflowSpecs = manifest["workflow_specs"];
|
||||
if (!Array.isArray(rawWorkflowSpecs) || rawWorkflowSpecs.length === 0) return null;
|
||||
const declaredWorkflowSpecs = rawWorkflowSpecs.filter((s): s is string => typeof s === "string" && s.length > 0);
|
||||
if (declaredWorkflowSpecs.length === 0) return null;
|
||||
return routeWorkflowSpecs(
|
||||
{
|
||||
bundleRoot: tmpDir,
|
||||
declaredWorkflowSpecs,
|
||||
targetWorkflowSpecsDir,
|
||||
},
|
||||
workflowSpecsRouterFsOps(),
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Item 6 / slice-05 Checkpoint 7.3d: extract the bundle safely (banked unpack
|
||||
* trust boundary) and route any declared plugin references to the operator
|
||||
@@ -815,6 +881,7 @@ bundleRoutes.post("/install", async (c) => {
|
||||
// so operators see what landed.
|
||||
let skillsRouting: RouteSkillsResult | null = null;
|
||||
let pluginsRouting: RoutePluginsResult | null = null;
|
||||
let workflowSpecsRouting: RouteWorkflowSpecsResult | null = null;
|
||||
try {
|
||||
skillsRouting = await routeSkillsAfterBootstrap(bundlePath);
|
||||
} catch {
|
||||
@@ -825,9 +892,15 @@ bundleRoutes.post("/install", async (c) => {
|
||||
} catch {
|
||||
// Side-channel failure; install already succeeded
|
||||
}
|
||||
try {
|
||||
workflowSpecsRouting = await routeWorkflowSpecsAfterBootstrap(bundlePath);
|
||||
} catch {
|
||||
// Side-channel failure; install already succeeded
|
||||
}
|
||||
const extras: Record<string, unknown> = {};
|
||||
if (skillsRouting) extras.skillsRouting = skillsRouting;
|
||||
if (pluginsRouting) extras.pluginsRouting = pluginsRouting;
|
||||
if (workflowSpecsRouting) extras.workflowSpecsRouting = workflowSpecsRouting;
|
||||
return c.json(Object.keys(extras).length > 0 ? { ...result, ...extras } : result, 201);
|
||||
}
|
||||
if (result.status === "partial") {
|
||||
|
||||
@@ -1533,6 +1533,220 @@ describe("Bundle API routes", () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Item 6 / Checkpoint 7.3e step 3: /install routes declared workflow_specs
|
||||
// after successful bootstrap. Target = SettingsStore-resolved
|
||||
// <workspaceSpecsRoot>/workflows. Bundle has workflow_specs[] with a path
|
||||
// pointing to a workflow YAML file in the bundle tree. Verifies the file
|
||||
// lands at <env-overridden specs root>/workflows/<basename>.
|
||||
it("POST /api/bundles/install routes declared workflow_specs after successful bootstrap (completed branch)", async () => {
|
||||
const origHome = process.env.OPENRIG_HOME;
|
||||
const origSpecsRoot = process.env.OPENRIG_WORKSPACE_SPECS_ROOT;
|
||||
const auditHome = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-workflow-specs-route-test-"));
|
||||
const specsRoot = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-workflow-specs-route-target-"));
|
||||
process.env.OPENRIG_HOME = auditHome;
|
||||
process.env.OPENRIG_WORKSPACE_SPECS_ROOT = specsRoot;
|
||||
const origBootstrap = setup.bootstrapOrchestrator.bootstrap.bind(setup.bootstrapOrchestrator);
|
||||
try {
|
||||
const { specPath } = seedPackage();
|
||||
const bundlePath = path.join(tmpDir, "with-workflow-specs.rigbundle");
|
||||
const targetRoot = fs.mkdtempSync(path.join(os.tmpdir(), "wflow-target-"));
|
||||
try {
|
||||
// Put a workflow_spec YAML inside the bundle's package source
|
||||
const workflowSrcDir = path.join(tmpDir, "test-pkg", "workflows");
|
||||
fs.mkdirSync(workflowSrcDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(workflowSrcDir, "onboarding.yaml"), "name: onboarding\nversion: '1.0'\nsteps: []\n");
|
||||
|
||||
await app.request("/api/bundles/create", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ specPath, bundleName: "with-workflow-specs", bundleVersion: "0.1.0", outputPath: bundlePath }),
|
||||
});
|
||||
|
||||
const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), "wflow-stage-"));
|
||||
try {
|
||||
const tar = await import("tar");
|
||||
await tar.extract({ file: bundlePath, cwd: stagingDir });
|
||||
const bundleYamlPath = path.join(stagingDir, "bundle.yaml");
|
||||
const original = fs.readFileSync(bundleYamlPath, "utf-8");
|
||||
// Declare the verbatim package path (no leading "workflows/"), mirror of
|
||||
// the skills-test pattern at line 1258. File is already in the bundle via
|
||||
// the test-pkg source; integrity manifest unchanged.
|
||||
const tampered = `${original}\nworkflow_specs:\n - packages/test-pkg/workflows/onboarding.yaml\n`;
|
||||
fs.writeFileSync(bundleYamlPath, tampered);
|
||||
const { pack } = await import("../src/domain/bundle-archive.js");
|
||||
await pack(stagingDir, bundlePath);
|
||||
} finally {
|
||||
fs.rmSync(stagingDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
const stub = vi.fn().mockResolvedValue({
|
||||
status: "completed",
|
||||
runId: "test-run-workflow-specs",
|
||||
rigId: "01H000000000000000WSPEC01",
|
||||
stages: [{ stage: "resolve_spec", status: "ok" }],
|
||||
errors: [],
|
||||
});
|
||||
(setup.bootstrapOrchestrator as unknown as { bootstrap: typeof stub }).bootstrap = stub;
|
||||
|
||||
const installRes = await app.request("/api/bundles/install", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ bundlePath, targetRoot, autoApprove: true }),
|
||||
});
|
||||
const body = await installRes.json();
|
||||
expect(body.workflowSpecsRouting).toBeDefined();
|
||||
expect(body.workflowSpecsRouting.routedCount).toBe(1);
|
||||
expect(body.workflowSpecsRouting.records[0].status).toBe("routed");
|
||||
// Declared path has no leading "workflows/" so routes verbatim;
|
||||
// file lands at <specsRoot>/workflows/<verbatim-path>
|
||||
const expectedTarget = path.join(specsRoot, "workflows", "packages", "test-pkg", "workflows", "onboarding.yaml");
|
||||
expect(fs.existsSync(expectedTarget)).toBe(true);
|
||||
expect(fs.readFileSync(expectedTarget, "utf-8")).toBe("name: onboarding\nversion: '1.0'\nsteps: []\n");
|
||||
} finally {
|
||||
fs.rmSync(targetRoot, { recursive: true, force: true });
|
||||
}
|
||||
} finally {
|
||||
(setup.bootstrapOrchestrator as unknown as { bootstrap: typeof origBootstrap }).bootstrap = origBootstrap;
|
||||
if (origHome === undefined) delete process.env.OPENRIG_HOME;
|
||||
else process.env.OPENRIG_HOME = origHome;
|
||||
if (origSpecsRoot === undefined) delete process.env.OPENRIG_WORKSPACE_SPECS_ROOT;
|
||||
else process.env.OPENRIG_WORKSPACE_SPECS_ROOT = origSpecsRoot;
|
||||
fs.rmSync(auditHome, { recursive: true, force: true });
|
||||
fs.rmSync(specsRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
// Item 6 / Checkpoint 7.3e step 3 / B1-mirror discipline (banked 5f410eee
|
||||
// decoupling lesson): workflow_specs routing must fire even when operator
|
||||
// uses BOTH --skip-version-check and --force pre-check overrides. The
|
||||
// routing is independent of the pre-check extraction gate. Discriminator:
|
||||
// re-coupling routeWorkflowSpecsAfterBootstrap to installMeta would make
|
||||
// this test fail (workflowSpecsRouting undefined when both flags set on a
|
||||
// bundle that declares workflow_specs[]).
|
||||
it("POST /api/bundles/install routes declared workflow_specs even when both --skip-version-check and --force are set (B1 mirror)", async () => {
|
||||
const origHome = process.env.OPENRIG_HOME;
|
||||
const origSpecsRoot = process.env.OPENRIG_WORKSPACE_SPECS_ROOT;
|
||||
const auditHome = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-wflow-dual-override-"));
|
||||
const specsRoot = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-wflow-dual-override-target-"));
|
||||
process.env.OPENRIG_HOME = auditHome;
|
||||
process.env.OPENRIG_WORKSPACE_SPECS_ROOT = specsRoot;
|
||||
const origBootstrap = setup.bootstrapOrchestrator.bootstrap.bind(setup.bootstrapOrchestrator);
|
||||
try {
|
||||
const { specPath } = seedPackage();
|
||||
const bundlePath = path.join(tmpDir, "dual-override-wflow.rigbundle");
|
||||
const targetRoot = fs.mkdtempSync(path.join(os.tmpdir(), "dual-override-wflow-target-"));
|
||||
try {
|
||||
const workflowSrcDir = path.join(tmpDir, "test-pkg", "workflows");
|
||||
fs.mkdirSync(workflowSrcDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(workflowSrcDir, "dualflow.yaml"), "name: dualflow\nversion: '2.0'\nsteps: []\n");
|
||||
|
||||
await app.request("/api/bundles/create", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ specPath, bundleName: "dual-override-wflow", bundleVersion: "0.1.0", outputPath: bundlePath }),
|
||||
});
|
||||
|
||||
const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), "dual-override-wflow-stage-"));
|
||||
try {
|
||||
const tar = await import("tar");
|
||||
await tar.extract({ file: bundlePath, cwd: stagingDir });
|
||||
const bundleYamlPath = path.join(stagingDir, "bundle.yaml");
|
||||
const original = fs.readFileSync(bundleYamlPath, "utf-8");
|
||||
const tampered = `${original}\nworkflow_specs:\n - packages/test-pkg/workflows/dualflow.yaml\n`;
|
||||
fs.writeFileSync(bundleYamlPath, tampered);
|
||||
const { pack } = await import("../src/domain/bundle-archive.js");
|
||||
await pack(stagingDir, bundlePath);
|
||||
} finally {
|
||||
fs.rmSync(stagingDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
const stub = vi.fn().mockResolvedValue({
|
||||
status: "completed",
|
||||
runId: "test-run-wflow-dual",
|
||||
rigId: "01H000000000000000WDUAL01",
|
||||
stages: [{ stage: "resolve_spec", status: "ok" }],
|
||||
errors: [],
|
||||
});
|
||||
(setup.bootstrapOrchestrator as unknown as { bootstrap: typeof stub }).bootstrap = stub;
|
||||
|
||||
// Critical: both override flags set — installMeta is null at the pre-check
|
||||
// site in this path; the workflow_specs-routing wrapper must STILL fire
|
||||
const installRes = await app.request("/api/bundles/install", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
bundlePath, targetRoot, autoApprove: true,
|
||||
skipVersionCheck: true, force: true,
|
||||
}),
|
||||
});
|
||||
const body = await installRes.json();
|
||||
expect(body.workflowSpecsRouting).toBeDefined();
|
||||
expect(body.workflowSpecsRouting.routedCount).toBe(1);
|
||||
expect(body.workflowSpecsRouting.records[0].status).toBe("routed");
|
||||
const expectedTarget = path.join(specsRoot, "workflows", "packages", "test-pkg", "workflows", "dualflow.yaml");
|
||||
expect(fs.existsSync(expectedTarget)).toBe(true);
|
||||
expect(fs.readFileSync(expectedTarget, "utf-8")).toBe("name: dualflow\nversion: '2.0'\nsteps: []\n");
|
||||
} finally {
|
||||
fs.rmSync(targetRoot, { recursive: true, force: true });
|
||||
}
|
||||
} finally {
|
||||
(setup.bootstrapOrchestrator as unknown as { bootstrap: typeof origBootstrap }).bootstrap = origBootstrap;
|
||||
if (origHome === undefined) delete process.env.OPENRIG_HOME;
|
||||
else process.env.OPENRIG_HOME = origHome;
|
||||
if (origSpecsRoot === undefined) delete process.env.OPENRIG_WORKSPACE_SPECS_ROOT;
|
||||
else process.env.OPENRIG_WORKSPACE_SPECS_ROOT = origSpecsRoot;
|
||||
fs.rmSync(auditHome, { recursive: true, force: true });
|
||||
fs.rmSync(specsRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("POST /api/bundles/install does NOT include workflowSpecsRouting when bundle has no workflow_specs[]", async () => {
|
||||
const origHome = process.env.OPENRIG_HOME;
|
||||
const origSpecsRoot = process.env.OPENRIG_WORKSPACE_SPECS_ROOT;
|
||||
const auditHome = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-no-wflow-test-"));
|
||||
const specsRoot = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-no-wflow-target-"));
|
||||
process.env.OPENRIG_HOME = auditHome;
|
||||
process.env.OPENRIG_WORKSPACE_SPECS_ROOT = specsRoot;
|
||||
const origBootstrap = setup.bootstrapOrchestrator.bootstrap.bind(setup.bootstrapOrchestrator);
|
||||
try {
|
||||
const { specPath } = seedPackage();
|
||||
const bundlePath = path.join(tmpDir, "no-wflow.rigbundle");
|
||||
const targetRoot = fs.mkdtempSync(path.join(os.tmpdir(), "no-wflow-target-"));
|
||||
try {
|
||||
await app.request("/api/bundles/create", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ specPath, bundleName: "no-wflow-installer", bundleVersion: "0.1.0", outputPath: bundlePath }),
|
||||
});
|
||||
|
||||
const stub = vi.fn().mockResolvedValue({
|
||||
status: "completed", runId: "test-run-no-wflow",
|
||||
rigId: "01H000000000000000NOWFLW",
|
||||
stages: [], errors: [],
|
||||
});
|
||||
(setup.bootstrapOrchestrator as unknown as { bootstrap: typeof stub }).bootstrap = stub;
|
||||
|
||||
const installRes = await app.request("/api/bundles/install", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ bundlePath, targetRoot, autoApprove: true }),
|
||||
});
|
||||
const body = await installRes.json();
|
||||
expect(body.workflowSpecsRouting).toBeUndefined();
|
||||
} finally {
|
||||
fs.rmSync(targetRoot, { recursive: true, force: true });
|
||||
}
|
||||
} finally {
|
||||
(setup.bootstrapOrchestrator as unknown as { bootstrap: typeof origBootstrap }).bootstrap = origBootstrap;
|
||||
if (origHome === undefined) delete process.env.OPENRIG_HOME;
|
||||
else process.env.OPENRIG_HOME = origHome;
|
||||
if (origSpecsRoot === undefined) delete process.env.OPENRIG_WORKSPACE_SPECS_ROOT;
|
||||
else process.env.OPENRIG_WORKSPACE_SPECS_ROOT = origSpecsRoot;
|
||||
fs.rmSync(auditHome, { recursive: true, force: true });
|
||||
fs.rmSync(specsRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("POST /api/bundles/install does NOT include pluginsRouting when bundle has no plugins[]", async () => {
|
||||
const origHome = process.env.OPENRIG_HOME;
|
||||
const auditHome = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-no-plugins-test-"));
|
||||
|
||||
Reference in new issue
Block a user