mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-28 04:02:18 +01:00
Add cross-company CEO regression tests for adjacent surfaces
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
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({
|
||||
|
||||
Reference in new issue
Block a user