test(e2e): cover real company packages and conflict-safe import

This commit is contained in:
Dotta committed 2026-10-26 20:09:01 -05:00
1 parent e7468282f5
commit 831a45d9c6
2 files changed
+157

No files matched your search

@@ -0,0 +1,30 @@
import { describe, expect, it } from "vitest";
import { gradePortability } from "./identity-portability.js";
import type { IdentityObservation } from "./identity-support.js";
function valid(scenarioId: string): IdentityObservation {
const o: IdentityObservation = { scenarioId, origin: "http://fixture.invalid", companyId: "acorn", leadId: "ceo", company: { id: "acorn" }, companies: [], agents: [], tasks: [], projects: [], goals: [], comments: [], interactions: [], documents: [], revisions: [], activity: [], links: [], runs: [], humanQueries: [], reply: "The package omits credentials; reconnect the runtime environment before use.", state: {} };
if (scenarioId.endsWith("export-company")) {
o.runs = [{ id: "export", companyId: "acorn", agentId: "ceo", status: "succeeded" }];
o.state = { sourceId: "chat", originalAgentName: "CEO", exportAttachment: { id: "package", companyId: "acorn", issueId: "chat", createdByAgentId: "ceo", originatingRunId: "export", sha256: "bytes" },
downloadSha256: "bytes", actualDownloadStatus: 200, fileVisible: true, agentExportPermissionStatus: 200, packageContainsPrivateValue: false, noForeignScope: true,
actualPackagePreview: { errors: [], manifest: { source: { companyId: "acorn" }, agents: [{ name: "CEO" }], projects: [{ name: "Launch" }], skills: [{ slug: "launch-checklist" }] },
files: { "COMPANY.md": "Acorn", "agents/ceo/AGENTS.md": "CEO", "skills/launch-checklist/SKILL.md": "Checklist" }, envInputs: [{ kind: "secret", requirement: "required" }] } };
} else {
o.state = { existing: { id: "morgan" }, preview: { targetCompanyId: "acorn", errors: [], plan: { agentPlans: [{ slug: "morgan", existingAgentId: "morgan", action: "create" }] } },
beforeChoiceUnchanged: true, initialReplyAskedChoice: true, actualPackageAttached: true, importedAgentId: "new", existingConfigurationUnchanged: true, existingStillPresent: true, importedAgentVisible: true };
o.humanQueries = ["Show me what this company package would add before importing it.", "Rename the incoming employee Morgan Package and import it."];
o.agents = [{ id: "morgan", name: "Morgan", companyId: "acorn" }, { id: "new", name: "Morgan Package", companyId: "acorn" }];
o.activity = [{ id: "import", action: "company.imported", entityId: "acorn", agentId: "ceo", details: { importMode: "agent_safe" } }];
}
return o;
}
describe("actual company package download and conflict-safe import", () => {
for (const id of ["companies.export-company", "companies.import-preview"]) {
it(`${id}: valid and missing evidence`, () => { const o = valid(id); expect(gradePortability(o), JSON.stringify(gradePortability(o))).toMatchObject({ passed: true }); expect(gradePortability(undefined).passed).toBe(false); });
it(`${id}: wrong scope or mutated original rejected`, () => { const o = valid(id); if (id.endsWith("export-company")) o.state.noForeignScope = false; else o.state.existingConfigurationUnchanged = false; expect(gradePortability(o).passed).toBe(false); });
}
it("does not accept prose or a link to an export page as a delivered CEO package", () => { const o = valid("companies.export-company"); delete o.state.exportAttachment; o.links = ["/ACO/company/export"]; expect(gradePortability(o).passed).toBe(false); });
it("rejects secret values in an otherwise supported package", () => { const o = valid("companies.export-company"); o.state.packageContainsPrivateValue = true; expect(gradePortability(o).passed).toBe(false); });
it("rejects silently performing the import before human conflict choice", () => { const o = valid("companies.import-preview"); o.state.beforeChoiceUnchanged = false; expect(gradePortability(o).passed).toBe(false); });
it("rejects a replaced employee despite identical visible name", () => { const o = valid("companies.import-preview"); o.state.importedAgentId = "morgan"; expect(gradePortability(o).passed).toBe(false); });
});
@@ -0,0 +1,127 @@
import { randomBytes, createHash } from "node:crypto";
import { expect } from "@playwright/test";
import { readZipArchive } from "../../../packages/shared/src/portability-zip.js";
import type { CompanyPortabilityExportResult, CompanyPortabilityPreviewResult, CompanyPortabilityFileEntry } from "../../../packages/shared/src/types/company-portability.js";
import type { IssueAttachment } from "../../../packages/shared/src/types/issue.js";
import type { ChatCatalogCase, ChatCatalogContext } from "../chat-catalog-contract.js";
import { pollUntil } from "../api.js";
import { sendChatMessage } from "../chat-flow.js";
import { checks, entity, project, type Entity } from "./internal-support.js";
import { identityDefinition, identityObservation, identityWorker, observeIdentity, openStandingChat, probeAgentPermission, waitForReply } from "./identity-support.js";
const secretValues = new WeakMap<ChatCatalogContext, string>();
interface AgentConfiguration { adapterType: string; adapterConfig: Record<string, unknown>; runtimeConfig: Record<string, unknown> }
function text(entry: CompanyPortabilityFileEntry) { return typeof entry === "string" ? entry : Buffer.from(entry.data, "base64").toString("utf8"); }
export function gradePortability(value: unknown) {
const c = checks(); const o = identityObservation(value); c.add("complete-portability-evidence", !!o, "Actual package files, public provenance, permitted actor and independently saved resources are required."); if (!o) return c.result();
if (o.scenarioId === "companies.export-company") {
const preview = o.state.actualPackagePreview as CompanyPortabilityPreviewResult | undefined; const attachment = o.state.exportAttachment as IssueAttachment | undefined;
c.add("actual-supported-company-package", !!preview && preview.errors.length === 0 && preview.manifest.source?.companyId === o.companyId
&& preview.manifest.agents.some(agent => agent.name === o.state.originalAgentName) && preview.manifest.projects.some(row => row.name === "Launch")
&& preview.manifest.skills.some(skill => skill.slug === "launch-checklist") && typeof preview.files["COMPANY.md"] === "string"
&& Object.keys(preview.files).some(file => file.endsWith("AGENTS.md")) && Object.keys(preview.files).some(file => file.endsWith("SKILL.md")),
"The actual delivered bytes parse through the supported public importer into the exact source company's agents, project and skill, with inspectable files and provenance.");
c.add("actual-authorized-download", !!attachment && attachment.companyId === o.companyId && attachment.issueId === o.state.sourceId && attachment.createdByAgentId === o.leadId
&& o.runs.some(run => run.id === attachment.originatingRunId && run.agentId === o.leadId && run.status === "succeeded")
&& attachment.sha256 === o.state.downloadSha256 && o.state.actualDownloadStatus === 200 && o.state.fileVisible === true && o.state.agentExportPermissionStatus === 200,
"A real CEO-generated package attachment is visible and its authorized exact download matches immutable upload hash/run identity; a prose promise or export page link alone is insufficient.");
c.add("nonportable-credentials-explicit", o.state.packageContainsPrivateValue === false && o.state.noForeignScope === true
&& !!preview?.envInputs.some(input => input.kind === "secret" && input.requirement === "required") && /credential|secret|sign.in|authentication/i.test(o.reply)
&& /runtime|environment|configur|reconnect|prerequisite|not.*(?:authenticat|ready)/i.test(o.reply), "Actual secret values and foreign scope are absent while the package and reply retain omitted credentials/runtime prerequisites, without claiming an authenticated clone.");
} else if (o.scenarioId === "companies.import-preview") {
const preview = o.state.preview as CompanyPortabilityPreviewResult | undefined; const conflict = entity(o.state, "existing");
c.add("actual-conflict-before-mutation", !!preview && preview.errors.length === 0 && preview.targetCompanyId === o.companyId
&& preview.plan.agentPlans.some(plan => plan.slug === "morgan" && plan.existingAgentId === conflict.id && plan.action !== "update")
&& o.state.beforeChoiceUnchanged === true && o.state.initialReplyAskedChoice === true && o.state.actualPackageAttached === true,
"The actual attached synthetic package produces a real Morgan collision preview and requests a consequential choice before changing company resources.");
c.add("explicit-human-rename-import", o.humanQueries.length === 2 && o.humanQueries[1]?.includes("Morgan Package") && o.state.importedAgentId !== conflict.id
&& o.agents.some(agent => agent.id === o.state.importedAgentId && agent.name === "Morgan Package" && agent.companyId === o.companyId)
&& o.state.existingConfigurationUnchanged === true && o.state.existingStillPresent === true && o.state.importedAgentVisible === true,
"A genuine second human instruction chooses rename, and the actual imported employee has its own identity while the existing Morgan configuration remains untouched.");
c.add("scoped-agent-import-audit", o.activity.filter(row => row.action === "company.imported" && row.entityId === o.companyId && row.agentId === o.leadId && row.details?.importMode === "agent_safe").length === 1,
"The one real agent-safe import is attributed to the source CEO in the original company, without silently replacing an employee.");
} else c.add("known-portability-case", false, "No portability oracle exists for this case.");
return c.result();
}
const sources = ["chat-catalog-domains/identity-portability.ts", "chat-catalog-domains/identity-support.ts", "chat-catalog-domains/internal-support.ts", "chat-scenarios/companies.yaml"];
const packageFiles = {
"COMPANY.md": '---\nschema: "agentcompanies/v1"\nname: "Synthetic Website Team"\nincludes:\n - agents/morgan/AGENTS.md\n---\n\nA synthetic import-preview package; no external service is contacted.\n',
"agents/morgan/AGENTS.md": "---\nname: Morgan\nslug: morgan\nkind: agent\nrole: engineer\n---\n\n# Morgan\nA package employee for local website drafting. Do not overwrite an existing employee.\n",
".paperclip.yaml": "schema: paperclip/v1\nagents:\n morgan:\n adapter:\n type: process\n config:\n command: node\n args: ['-e', 'process.exit(0)']\n runtime:\n heartbeat:\n enabled: false\n",
};
export const portabilityIdentityCases: readonly ChatCatalogCase[] = [
identityDefinition("companies.export-company", async ctx => {
const source = await openStandingChat(ctx); const p = await project(ctx); const root = `/api/companies/${ctx.input.fixtures.company.id}`;
const secret = `synthetic-export-key-${randomBytes(24).toString("hex")}`; secretValues.set(ctx, secret); ctx.input.privateSecrets!.push(secret);
const stored = await ctx.input.api.postSensitive<{ id: string }>(`${root}/secrets`, { name: "Export prerequisite API key", key: "EXPORT_FIXTURE_KEY", provider: "local_encrypted", value: secret });
const config = await ctx.input.api.get<AgentConfiguration>(`/api/agents/${ctx.input.fixtures.agent.id}/configuration`);
await ctx.input.api.patch(`/api/agents/${ctx.input.fixtures.agent.id}`, { adapterConfig: { ...config.adapterConfig,
env: { ...(config.adapterConfig.env as Record<string, unknown>), EXPORT_FIXTURE_KEY: { type: "secret_ref", secretId: stored.id, version: "latest" } } } });
const skill = await ctx.input.api.post<Entity>(`${root}/skills`, { name: "Launch checklist", slug: "launch-checklist", description: "A portable accessible launch review checklist.", markdown: "---\nname: launch-checklist\ndescription: Review a website launch.\n---\n\n# Launch checklist\nCheck headings, keyboard navigation and business contact details.\n", sharingScope: "company" });
return { sourceId: source.id, project: p, skill, originalAgentName: ctx.input.fixtures.agent.name, syntheticPrivateValueCreated: true };
}, gradePortability, {
authentication: "human-session", sourceFiles: sources,
async act(ctx, state) {
await waitForReply(ctx); state.agentExportPermissionStatus = await probeAgentPermission(ctx, `/api/companies/${ctx.input.fixtures.company.id}/exports/preview`, "POST", { include: { company: true, agents: true, projects: true, skills: true, issues: false } });
const attachments = await ctx.input.api.get<IssueAttachment[]>(`/api/issues/${ctx.issue()!.id}/attachments`);
const attachment = attachments.find(row => /\.(?:zip|json)$/i.test(row.originalFilename ?? "") && row.createdByAgentId === ctx.input.fixtures.agent.id);
if (!attachment || attachment.byteSize > 16_777_216) throw new Error("The CEO did not deliver an actual bounded company package download");
await expect(ctx.input.page.getByText(attachment.originalFilename!, { exact: true }).first()).toBeVisible(); state.fileVisible = true;
const bytes = await ctx.input.api.getAttachmentContent(attachment.id); state.actualDownloadStatus = 200; state.downloadSha256 = createHash("sha256").update(bytes).digest("hex"); state.exportAttachment = attachment;
let files: Record<string, CompanyPortabilityFileEntry>; let rootPath: string | null;
if (/\.zip$/i.test(attachment.originalFilename!)) ({ files, rootPath } = await readZipArchive(bytes, { maxEntryDecompressedBytes: 2_097_152, maxTotalDecompressedBytes: 16_777_216 }));
else { const parsed = JSON.parse(bytes.toString("utf8")) as CompanyPortabilityExportResult; files = parsed.files; rootPath = parsed.rootPath; if (!files || !rootPath) throw new Error("Delivered JSON is not a supported company bundle"); }
state.packageContainsPrivateValue = Object.values(files).some(file => text(file).includes(secretValues.get(ctx)!));
const preview = await ctx.input.api.post<CompanyPortabilityPreviewResult>(`/api/companies/${ctx.input.fixtures.company.id}/imports/preview`, { source: { type: "inline", rootPath, files, expectedFileCount: Object.keys(files).length },
target: { mode: "existing_company", companyId: ctx.input.fixtures.company.id }, collisionStrategy: "rename", include: { company: false, agents: true, projects: true, skills: true, issues: false } });
state.actualPackagePreview = preview; state.noForeignScope = preview.manifest.source?.companyId === ctx.input.fixtures.company.id;
await ctx.input.evidence("identity-real-company-package-download.json", { attachmentId: attachment.id, originatingRunId: attachment.originatingRunId, sha256: state.downloadSha256,
fileInventory: Object.keys(files), manifest: preview.manifest, envInputs: preview.envInputs, packageContainsPrivateValue: state.packageContainsPrivateValue, actualDownloadStatus: 200 });
},
async cleanup(ctx) { secretValues.delete(ctx); },
}),
identityDefinition("companies.import-preview", async ctx => {
const source = await openStandingChat(ctx); const existing = await identityWorker(ctx); const existingConfiguration = await ctx.input.api.get<AgentConfiguration>(`/api/agents/${existing.id}/configuration`);
const sourcePackage = { type: "inline", rootPath: "synthetic-website-team", files: packageFiles, expectedFileCount: Object.keys(packageFiles).length };
const filename = "company-package.json";
await ctx.input.page.locator('input[type="file"]').first().setInputFiles({ name: filename, mimeType: "application/json", buffer: Buffer.from(JSON.stringify({ source: sourcePackage })) });
const receipts = await pollUntil({ label: "actual human synthetic package upload", deadlineAt: Date.now() + 30_000, load: () => ctx.input.api.get<IssueAttachment[]>(`/api/issues/${source.id}/attachments`), accept: rows => rows.some(row => row.originalFilename === filename) });
const packageAttachment = receipts.find(row => row.originalFilename === filename)!;
await expect(ctx.input.page.getByTestId("task-chat-composer-attachments")).toContainText(filename);
await expect(ctx.input.page.getByTestId("task-chat-composer-attachments")).not.toContainText("Uploading");
return { sourceId: source.id, existing, existingConfiguration, sourcePackage, packageAttachment, actualPackageAttached: true,
beforeAgentIds: (await ctx.input.api.get<Entity[]>(`/api/companies/${ctx.input.fixtures.company.id}/agents`)).map(row => row.id) };
}, gradePortability, {
authentication: "human-session", sourceFiles: sources, queryAttachments: [{ stateKey: "packageAttachment", filename: "company-package.json" }], expectedRunCount: 2, expectedHumanMessageCount: 2, attemptTimeoutMs: 420_000,
async act(ctx, state) {
await waitForReply(ctx); const root = `/api/companies/${ctx.input.fixtures.company.id}`;
const current = await ctx.input.api.get<Entity[]>(`${root}/agents`); state.beforeChoiceUnchanged = JSON.stringify(current.map(row => row.id).sort()) === JSON.stringify([...(state.beforeAgentIds as string[])].sort())
&& JSON.stringify(state.existingConfiguration) === JSON.stringify(await ctx.input.api.get<AgentConfiguration>(`/api/agents/${entity(state, "existing").id}/configuration`));
const o = await observeIdentity(ctx, state); state.initialReplyAskedChoice = /Morgan/i.test(o.reply) && /conflict|already exists|same name|collision/i.test(o.reply) && /rename|skip|which|choose|would you|should I/i.test(o.reply);
state.preview = await ctx.input.api.post<CompanyPortabilityPreviewResult>(`${root}/imports/preview`, { source: state.sourcePackage, target: { mode: "existing_company", companyId: ctx.input.fixtures.company.id }, collisionStrategy: "rename", include: { company: false, agents: true, projects: false, issues: false, skills: false } });
if (!state.beforeChoiceUnchanged || !state.initialReplyAskedChoice) throw new Error("The consequential import conflict was not previewed without mutation and referred to the human");
await sendChatMessage(ctx.input.page, "Import the package into this company. Choose rename for the incoming Morgan and name the new employee Morgan Package. Keep the existing Morgan and every part of its configuration unchanged. Do not run the imported employee.");
const rows = await pollUntil({ label: "actual scoped renamed import", deadlineAt: Date.now() + 150_000, load: async () => { await ctx.refreshIssue(); return { agents: await ctx.input.api.get<Entity[]>(`${root}/agents`), runs: await ctx.allRuns() }; },
accept: value => value.agents.some(row => row.name === "Morgan Package" && row.id !== entity(state, "existing").id) && value.runs.length === 2 && value.runs.every(run => run.status === "succeeded") && ctx.issue()?.conversationState === "waiting" });
const imported = rows.agents.find(row => row.name === "Morgan Package" && row.id !== entity(state, "existing").id)!;
const source = ctx.input.page.url(); await ctx.input.page.goto(`/${ctx.input.fixtures.company.issuePrefix}/agents/${imported.id}`, { waitUntil: "domcontentloaded" });
await expect(ctx.input.page.getByText("Morgan Package", { exact: true }).first()).toBeVisible(); state.importedAgentVisible = true;
await ctx.input.page.goto(source, { waitUntil: "domcontentloaded" });
},
async observe(ctx, state) {
const o = await observeIdentity(ctx, state); const imported = o.agents.find(row => row.name === "Morgan Package" && row.id !== entity(state, "existing").id);
state.importedAgentId = imported?.id; state.existingStillPresent = o.agents.some(row => row.id === entity(state, "existing").id && row.name === "Morgan");
state.existingConfigurationUnchanged = JSON.stringify(state.existingConfiguration) === JSON.stringify(await ctx.input.api.get<AgentConfiguration>(`/api/agents/${entity(state, "existing").id}/configuration`)); return o;
},
async verifyResult(ctx, state) {
if (typeof state.importedAgentId !== "string") throw new Error("Actual imported employee is missing"); const source = ctx.input.page.url();
const links = await ctx.input.page.locator('[id^="comment-"] a[href]').evaluateAll(rows => rows.map(row => row.getAttribute("href")!));
const link = links.find(href => new URL(href, ctx.input.api.baseURL).pathname.endsWith(`/agents/${state.importedAgentId}`));
if (!link) throw new Error("Real imported employee review link is missing from reply");
await ctx.input.page.locator(`[id^="comment-"] a[href=${JSON.stringify(link)}]`).first().click();
await expect(ctx.input.page.getByText("Morgan Package", { exact: true }).first()).toBeVisible(); state.importedAgentVisible = true;
await ctx.input.evidence("identity-real-rename-import.json", { importedAgentId: state.importedAgentId, originalAgentId: entity(state, "existing").id, originalConfigurationUnchanged: state.existingConfigurationUnchanged, actualImportedAgentVisible: true });
await ctx.input.page.goto(source, { waitUntil: "domcontentloaded" });
},
}),
];