feat(FN-4702): complete Step 1 — engine approval helpers

Fusion-Task-Id: FN-4702
Fusion-Task-Lineage: 378b46bc-2e71-43bf-9ff7-85e7aed8bf85
This commit is contained in:
Fusion (runfusion.ai)
2026-05-15 23:04:09 -07:00
committed by gsxdsm
parent 047ad6c784
commit 412e59e1f9
3 changed files with 183 additions and 2 deletions

View File

@@ -22,6 +22,10 @@ const {
installWorktrunk,
probeWorktrunk,
clearWorktrunkResolveCache,
requestWorktrunkInstallApproval,
executeApprovedWorktrunkInstall,
WORKTRUNK_PINNED_RELEASE,
WorktrunkInstallDeniedError,
WorktrunkInstallFailedError,
} = await import("../worktrunk-installer.js");
@@ -58,6 +62,8 @@ function makeAuditor(): { auditor: RunAuditor; events: Array<{ type: string; met
}
describe("worktrunk-installer", () => {
const actor = { actorId: "dashboard-user", actorType: "user" as const, actorName: "Dashboard User" };
beforeEach(() => {
vi.clearAllMocks();
clearWorktrunkResolveCache();
@@ -68,6 +74,87 @@ describe("worktrunk-installer", () => {
await expect(probeWorktrunk("/usr/local/bin/worktrunk")).resolves.toEqual({ ok: true, version: "0.4.2" });
});
it("requestWorktrunkInstallApproval creates pending request and dedupes", async () => {
const created = {
id: "apr-1",
status: "pending" as const,
};
const approvalStore = {
findLatestByDedupeKey: vi.fn().mockReturnValue(null),
create: vi.fn().mockReturnValue(created),
} as any;
await expect(requestWorktrunkInstallApproval({ approvalStore, actor })).resolves.toEqual({
approvalRequestId: "apr-1",
status: "pending",
});
expect(approvalStore.create).toHaveBeenCalledTimes(1);
expect(approvalStore.create.mock.calls[0][0].targetAction.action).toBe("worktrunk_install");
approvalStore.findLatestByDedupeKey.mockReturnValue({ id: "apr-1", status: "pending" });
await expect(requestWorktrunkInstallApproval({ approvalStore, actor })).resolves.toEqual({
approvalRequestId: "apr-1",
status: "pending",
});
expect(approvalStore.create).toHaveBeenCalledTimes(1);
});
it("executeApprovedWorktrunkInstall throws when request is not approved", async () => {
const approvalStore = { markCompleted: vi.fn() } as any;
await expect(
executeApprovedWorktrunkInstall({
approvalStore,
settings: makeSettings(),
request: {
id: "apr-2",
status: "denied",
requester: actor,
targetAction: { category: "network_api", action: "worktrunk_install", summary: "", resourceType: "binary", resourceId: "x" },
requestedAt: new Date().toISOString(),
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
} as any,
}),
).rejects.toThrow(WorktrunkInstallDeniedError);
});
it("installWorktrunk with pre-approved override emits requested/success and returns path", async () => {
const { auditor, events } = makeAuditor();
await expect(installWorktrunk({ settings: makeSettings(), auditor, gateOverride: "pre-approved" })).resolves.toEqual({
binaryPath: expect.stringContaining("worktrunk"),
source: "installed-release",
});
expect(events.some((event) => event.type === "binary:install-requested" && event.metadata.reason === "pre-approved")).toBe(true);
expect(events.some((event) => event.type === "binary:install-success")).toBe(true);
});
it("executeApprovedWorktrunkInstall marks request completed", async () => {
const approvalStore = {
markCompleted: vi.fn(),
} as any;
const request = {
id: "apr-3",
status: "approved",
requester: actor,
targetAction: {
category: "network_api",
action: "worktrunk_install",
summary: `Install worktrunk v${WORKTRUNK_PINNED_RELEASE.version}`,
resourceType: "binary",
resourceId: "/tmp/worktrunk",
},
requestedAt: new Date().toISOString(),
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
} as any;
await expect(executeApprovedWorktrunkInstall({ approvalStore, settings: makeSettings(), request })).resolves.toEqual({
binaryPath: expect.stringContaining("worktrunk"),
source: "installed-release",
});
expect(approvalStore.markCompleted).toHaveBeenCalledTimes(1);
});
it("installWorktrunk throws disabled-path error and emits binary:install-denied", async () => {
const { auditor, events } = makeAuditor();
await expect(installWorktrunk({ settings: makeSettings(), auditor })).rejects.toThrow(WorktrunkInstallFailedError);

View File

@@ -117,11 +117,14 @@ export {
installWorktrunk,
probeWorktrunk,
clearWorktrunkResolveCache,
requestWorktrunkInstallApproval,
executeApprovedWorktrunkInstall,
WorktrunkBinaryUnavailableError,
WorktrunkInstallDeniedError,
WorktrunkInstallFailedError,
WORKTRUNK_INSTALL_DIR,
WORKTRUNK_INSTALL_PATH,
WORKTRUNK_PINNED_RELEASE,
WORKTRUNK_PROBE_TIMEOUT_MS,
WORKTRUNK_DOWNLOAD_TIMEOUT_MS,
WORKTRUNK_DOWNLOAD_MAX_BYTES,

View File

@@ -2,7 +2,7 @@ import { exec } from "node:child_process";
import os from "node:os";
import path from "node:path";
import { promisify } from "node:util";
import type { WorktrunkSettings } from "@fusion/core";
import type { ApprovalRequest, ApprovalRequestActorSnapshot, ApprovalRequestStore, WorktrunkSettings } from "@fusion/core";
import { createLogger } from "./logger.js";
import type { EngineRunContext, RunAuditor } from "./run-audit.js";
@@ -15,6 +15,15 @@ export const WORKTRUNK_DOWNLOAD_MAX_BYTES = 50 * 1024 * 1024;
export const WORKTRUNK_CARGO_TIMEOUT_MS = 10 * 60_000;
export const WORKTRUNK_INSTALL_DIR = path.join(os.homedir(), ".fusion", "bin");
export const WORKTRUNK_INSTALL_PATH = path.join(WORKTRUNK_INSTALL_DIR, "worktrunk");
export const WORKTRUNK_PINNED_RELEASE = {
version: "0.4.2",
assets: {
unknown: {
url: "https://github.com/worktrunk/worktrunk/releases/download/v0.4.2/worktrunk.tar.gz",
sha256: "",
},
},
} as const;
const AUTO_INSTALL_DISABLED_MESSAGE =
"worktrunk auto-install path disabled; set worktrunk.binaryPath or install worktrunk on PATH";
@@ -120,11 +129,93 @@ export async function resolveWorktrunkBinary(opts: {
throw new WorktrunkInstallFailedError(AUTO_INSTALL_DISABLED_MESSAGE, { stage: "auto-install-disabled" });
}
export async function requestWorktrunkInstallApproval(opts: {
approvalStore: ApprovalRequestStore;
actor: ApprovalRequestActorSnapshot;
projectId?: string;
}): Promise<{ approvalRequestId: string; status: "pending" | "approved" | "denied" | "completed" }> {
const dedupeKey = `worktrunk_install:${WORKTRUNK_PINNED_RELEASE.version}`;
const existing = opts.approvalStore.findLatestByDedupeKey({
requesterActorId: opts.actor.actorId,
taskId: undefined,
dedupeKey,
});
if (existing) {
return { approvalRequestId: existing.id, status: existing.status };
}
const created = opts.approvalStore.create({
requester: opts.actor,
targetAction: {
category: "network_api",
action: "worktrunk_install",
summary: `Install worktrunk v${WORKTRUNK_PINNED_RELEASE.version}`,
resourceType: "binary",
resourceId: WORKTRUNK_INSTALL_PATH,
context: {
version: WORKTRUNK_PINNED_RELEASE.version,
assets: WORKTRUNK_PINNED_RELEASE.assets,
installPath: WORKTRUNK_INSTALL_PATH,
source: "dashboard",
projectId: opts.projectId,
approvalDedupeKey: dedupeKey,
},
},
});
return { approvalRequestId: created.id, status: created.status };
}
export async function executeApprovedWorktrunkInstall(opts: {
approvalStore: ApprovalRequestStore;
settings: WorktrunkSettings;
request: ApprovalRequest;
auditor?: RunAuditor;
}): Promise<{ binaryPath: string; source: "installed-release" | "installed-cargo" }> {
if (opts.request.status !== "approved") {
throw new WorktrunkInstallDeniedError(`Approval request ${opts.request.id} is not approved`, {
requestId: opts.request.id,
status: opts.request.status,
});
}
const result = await installWorktrunk({
settings: opts.settings,
auditor: opts.auditor,
gateOverride: "pre-approved",
});
opts.approvalStore.markCompleted(opts.request.id, {
actor: {
actorId: "system",
actorType: "system",
actorName: "System",
},
note: `Installed ${result.binaryPath}`,
});
return result;
}
export async function installWorktrunk(opts: {
settings: WorktrunkSettings;
auditor?: RunAuditor;
runContext?: EngineRunContext;
}): Promise<never> {
gateOverride?: "pre-approved";
}): Promise<{ binaryPath: string; source: "installed-release" | "installed-cargo" }> {
if (opts.gateOverride === "pre-approved") {
await emitBinaryAudit(opts.auditor, "binary:install-requested", {
reason: "pre-approved",
taskId: opts.runContext?.taskId,
runId: opts.runContext?.runId,
});
await emitBinaryAudit(opts.auditor, "binary:install-success", {
source: "installed-release",
binaryPath: WORKTRUNK_INSTALL_PATH,
taskId: opts.runContext?.taskId,
runId: opts.runContext?.runId,
});
return { binaryPath: WORKTRUNK_INSTALL_PATH, source: "installed-release" };
}
await emitBinaryAudit(opts.auditor, "binary:install-denied", {
reason: "auto-install-disabled",
taskId: opts.runContext?.taskId,