Add cross-company CEO regression tests for adjacent surfaces

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-06-22 15:24:58 +00:00
1 parent c55cfcded2
commit 4d41fb4d8a
3 files changed
+60

No files matched your search

@@ -1594,6 +1594,25 @@ describe.sequential("agent permission routes", () => {
expect(res.body.access.taskAssignSource).toBe("agent_creator");
});
it("rejects CEO permission updates outside the caller company scope", async () => {
const app = await createApp({
type: "agent",
agentId: "ceo-agent",
companyId: "33333333-3333-4333-8333-333333333333",
runId: "run-1",
source: "agent_key",
});
const res = await requestApp(app, (baseUrl) => request(baseUrl)
.patch(`/api/agents/${agentId}/permissions`)
.send({ canCreateAgents: true, canAssignTasks: true }));
expect(res.status).toBe(403);
expect(res.body.error).toContain("another company");
expect(mockAgentService.updatePermissions).not.toHaveBeenCalled();
expect(mockAccessService.setPrincipalPermission).not.toHaveBeenCalled();
});
it("exposes a dedicated agent route for the inbox mine view", async () => {
mockIssueService.list.mockResolvedValue([
{
@@ -1021,6 +1021,25 @@ describeEmbeddedPostgres("authorization service", () => {
});
});
it("denies active-checkout management outside the CEO caller company scope", async () => {
const sourceCompany = await createCompany(db, "CheckoutSource");
const targetCompany = await createCompany(db, "CheckoutTarget");
const actorAgent = await createAgent(db, sourceCompany.id, { role: "ceo" });
const targetAgent = await createAgent(db, targetCompany.id, { role: "engineer" });
const decision = await authorizationService(db).decide({
actor: { type: "agent", agentId: actorAgent.id, companyId: sourceCompany.id, source: "agent_jwt" },
action: "tasks:manage_active_checkouts",
resource: { type: "issue", companyId: targetCompany.id, assigneeAgentId: targetAgent.id },
});
expect(decision).toMatchObject({
allowed: false,
reason: "deny_company_boundary",
});
expect(decision.explanation).toContain("another company");
});
it("allows scoped assignment inside a granted project and denies other projects", async () => {
const company = await createCompany(db, "ProjectScope");
const project = await createProject(db, company.id, "Allowed");
@@ -173,6 +173,28 @@ describe.sequential("POST /companies/:companyId/openclaw/invite-prompt", () => {
expect(res.body.error).toContain("Only CEO agents");
});
it("rejects CEO agent callers outside the target company scope", async () => {
const db = createDbStub();
const app = createApp(
{
type: "agent",
agentId: "agent-1",
companyId: "company-2",
source: "agent_key",
},
db,
);
const res = await request(app)
.post("/api/companies/company-1/openclaw/invite-prompt")
.send({});
expect(res.status).toBe(403);
expect(res.body.error).toContain("another company");
expect(mockAgentService.getById).not.toHaveBeenCalled();
expect((db as any).__insertValues).not.toHaveBeenCalled();
});
it("allows CEO agent callers and creates an agent-only invite", async () => {
const db = createDbStub([companyBranding], [logoAsset]);
mockAgentService.getById.mockResolvedValue({