fix(evals): preserve assignment permission in team fixture request

Use the complete public permissions schema and retain the independently observed same-company CEO assignment capability. Reject foreign or unverified actor metadata before writing, and verify the effective capability remains unchanged.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-11-02 20:18:31 -06:00
1 parent 78d91b0e2f
commit 6e5a430118
2 files changed
+26 -5

No files matched your search

@@ -1,8 +1,9 @@
import type { ChatCatalogContext } from "../chat-catalog-contract.js";
import type { Agent } from "../../../packages/shared/src/types/agent.js";
import { CHAT_OPENCODE_MODEL } from "../chat-runtime-profile.js";
import { updateAgentPermissionsSchema } from "../../../packages/shared/src/validators/agent.js";
import { catalogTeamInstallSchema } from "../../../packages/shared/src/validators/teams-catalog.js";
import { describe, expect, it } from "vitest";
import { describe, expect, it, vi } from "vitest";
import { teamInstallExternalCases, selectedTeamInstallRuntime, teamInstallOverrides, verifyInstalledTeamRuntime } from "./external-team-install.js";
function valid() {
const team = {
@@ -212,3 +213,20 @@ it("real resource counts and actor attribution cannot conceal wrong member provi
(o: ReturnType<typeof valid>) => { o.state.selectedRuntime.model = "openrouter/other/model"; o.state.after.agents.forEach(agent => { agent.adapterConfig.model = "openrouter/other/model"; }); },
]) { const o = valid(); change(o); expect(teamInstallExternalCases[0]!.grade(o).passed).toBe(false); }
});
it.each([true,false])("sends the complete permission schema without changing effective assignment=%s",async canAssignTasks=>{
const actor={id:"ceo",companyId:"company",role:"ceo",access:{canAssignTasks}};
const patch=vi.fn(async(_route:string,body:unknown)=>{expect(updateAgentPermissionsSchema.parse(body)).toEqual({canCreateAgents:true,canAssignTasks});throw new Error("stop-after-validated-permission-request");});
const ctx={input:{fixtures:{company:{id:"company"},agent:{id:"ceo"}},api:{get:async(route:string)=>route==="/api/teams/catalog"?[{slug:"product-engineering",compatibility:"compatible"}]:actor,patch}}} as unknown as ChatCatalogContext;
await expect(teamInstallExternalCases[0]!.setup(ctx)).rejects.toThrow("stop-after-validated-permission-request");
expect(patch).toHaveBeenCalledOnce();
});
it.each(["foreign company","wrong agent","not CEO","missing effective assignment"])("refuses %s identity before permission mutation",async invalid=>{
const actor={id:"ceo",companyId:"company",role:"ceo",access:{canAssignTasks:true}};
if(invalid==="foreign company")actor.companyId="foreign";
if(invalid==="wrong agent")actor.id="other";
if(invalid==="not CEO")actor.role="engineer";
if(invalid==="missing effective assignment")delete(actor as {access?:unknown}).access;
const patch=vi.fn(); const ctx={input:{fixtures:{company:{id:"company"},agent:{id:"ceo"}},api:{get:async(route:string)=>route==="/api/teams/catalog"?[{slug:"product-engineering",compatibility:"compatible"}]:actor,patch}}} as unknown as ChatCatalogContext;
await expect(teamInstallExternalCases[0]!.setup(ctx)).rejects.toThrow("observed installer");expect(patch).not.toHaveBeenCalled();
});
@@ -7,7 +7,7 @@ import {
gradeTeamConditions,
} from "./external-team-conditional.js";
import { expect } from "@playwright/test";
import type { Agent } from "../../../packages/shared/src/types/agent.js";
import type { Agent, AgentDetail } from "../../../packages/shared/src/types/agent.js";
import type {
CatalogTeam,
CatalogTeamImportPreviewResult,
@@ -277,19 +277,22 @@ export const teamInstallExternalCases = [
throw new Error(
"Setup blocker: real compatible Product Engineering team catalog package is unavailable",
);
const beforePermissions = await ctx.input.api.get<AgentDetail>(`/api/agents/${ctx.input.fixtures.agent.id}`);
if (beforePermissions.id !== ctx.input.fixtures.agent.id || beforePermissions.companyId !== ctx.input.fixtures.company.id || beforePermissions.role !== "ceo" || typeof beforePermissions.access?.canAssignTasks !== "boolean") throw new Error("Team fixture requires the independently observed installer identity and assignment authority");
await ctx.input.api.patch(
`/api/agents/${ctx.input.fixtures.agent.id}/permissions`,
{ canCreateAgents: true },
{ canCreateAgents: true, canAssignTasks: beforePermissions.access.canAssignTasks },
);
await ctx.input.api.patch(root(ctx), {
requireBoardApprovalForNewAgents: false,
});
const actor = await ctx.input.api.get<Agent>(
const actor = await ctx.input.api.get<AgentDetail>(
`/api/agents/${ctx.input.fixtures.agent.id}`,
);
if (
actor.lifecycleState !== "ready" ||
actor.permissions?.canCreateAgents !== true
actor.permissions?.canCreateAgents !== true ||
actor.access?.canAssignTasks !== beforePermissions.access.canAssignTasks
)
throw new Error(
"Setup blocker: actual selected installer actor lacks a ready account or creation authority",