Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
248 changes: 248 additions & 0 deletions packages/opencode/test/altimate/finops-role-access.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
/**
* Tests for finops role-access formatting functions:
* formatGrants, formatHierarchy, formatUserRoles.
*
* These render RBAC data as markdown tables. Incorrect output
* could cause data engineers to miss security issues during audits.
* Tests use Dispatcher.call spying to supply known RBAC data.
*/
import { describe, test, expect, spyOn, afterAll, beforeEach } from "bun:test"
import * as Dispatcher from "../../src/altimate/native/dispatcher"
import {
FinopsRoleGrantsTool,
FinopsRoleHierarchyTool,
FinopsUserRolesTool,
} from "../../src/altimate/tools/finops-role-access"
import { SessionID, MessageID } from "../../src/session/schema"

beforeEach(() => {
process.env.ALTIMATE_TELEMETRY_DISABLED = "true"
})
afterAll(() => {
delete process.env.ALTIMATE_TELEMETRY_DISABLED
})

const ctx = {
sessionID: SessionID.make("ses_test"),
messageID: MessageID.make("msg_test"),
callID: "call_test",
agent: "build",
abort: AbortSignal.any([]),
messages: [],
metadata: () => {},
ask: async () => {},
}

let dispatcherSpy: ReturnType<typeof spyOn>

function mockDispatcher(responses: Record<string, any>) {
dispatcherSpy?.mockRestore()
dispatcherSpy = spyOn(Dispatcher, "call").mockImplementation(async (method: string) => {
if (responses[method]) return responses[method]
throw new Error(`No mock for ${method}`)
})
Comment on lines +38 to +43
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use key existence check in mockDispatcher, not truthiness.

if (responses[method]) fails for valid mocked values that are falsy. Check property existence to avoid false “No mock” failures.

🐛 Proposed fix
 function mockDispatcher(responses: Record<string, any>) {
   dispatcherSpy?.mockRestore()
   dispatcherSpy = spyOn(Dispatcher, "call").mockImplementation(async (method: string) => {
-    if (responses[method]) return responses[method]
+    if (Object.prototype.hasOwnProperty.call(responses, method)) return responses[method]
     throw new Error(`No mock for ${method}`)
   })
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function mockDispatcher(responses: Record<string, any>) {
dispatcherSpy?.mockRestore()
dispatcherSpy = spyOn(Dispatcher, "call").mockImplementation(async (method: string) => {
if (responses[method]) return responses[method]
throw new Error(`No mock for ${method}`)
})
function mockDispatcher(responses: Record<string, any>) {
dispatcherSpy?.mockRestore()
dispatcherSpy = spyOn(Dispatcher, "call").mockImplementation(async (method: string) => {
if (Object.prototype.hasOwnProperty.call(responses, method)) return responses[method]
throw new Error(`No mock for ${method}`)
})
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/altimate/finops-role-access.test.ts` around lines 38 -
43, The mockDispatcher implementation incorrectly treats falsy mocked values as
missing; replace the truthiness check in mockDispatcher (currently `if
(responses[method])`) with a property-existence check such as using
Object.prototype.hasOwnProperty.call(responses, method) or the `in` operator so
Dispatcher.call mock returns falsy-but-valid responses instead of throwing "No
mock for ...".

}

afterAll(() => {
dispatcherSpy?.mockRestore()
})

describe("formatGrants: privilege summary and grant rows", () => {
test("renders privilege summary and grant table with standard Snowflake fields", async () => {
mockDispatcher({
"finops.role_grants": {
success: true,
grant_count: 2,
privilege_summary: { SELECT: 2, INSERT: 1 },
grants: [
{ grantee_name: "ANALYST", privilege: "SELECT", object_type: "TABLE", object_name: "orders" },
{ grantee_name: "ADMIN", privilege: "INSERT", object_type: "TABLE", object_name: "users" },
],
},
})

const tool = await FinopsRoleGrantsTool.init()
const result = await tool.execute({ warehouse: "test_wh", limit: 100 }, ctx as any)

expect(result.title).toContain("2 found")
expect(result.output).toContain("Privilege Summary")
expect(result.output).toContain("SELECT: 2")
expect(result.output).toContain("INSERT: 1")
expect(result.output).toContain("ANALYST | SELECT | TABLE | orders")
expect(result.output).toContain("ADMIN | INSERT | TABLE | users")
})

test("uses fallback field aliases (role, granted_on, name)", async () => {
mockDispatcher({
"finops.role_grants": {
success: true,
grant_count: 1,
privilege_summary: {},
grants: [
{ role: "DBA", privilege: "USAGE", granted_on: "WAREHOUSE", name: "compute_wh" },
],
},
})

const tool = await FinopsRoleGrantsTool.init()
const result = await tool.execute({ warehouse: "test_wh", limit: 100 }, ctx as any)

// formatGrants should fall back to r.role, r.granted_on, r.name
expect(result.output).toContain("DBA | USAGE | WAREHOUSE | compute_wh")
})

test("handles empty grants array", async () => {
mockDispatcher({
"finops.role_grants": {
success: true,
grant_count: 0,
privilege_summary: {},
grants: [],
},
})

const tool = await FinopsRoleGrantsTool.init()
const result = await tool.execute({ warehouse: "test_wh", limit: 100 }, ctx as any)

expect(result.output).toContain("No grants found")
})

test("returns error message on Dispatcher failure", async () => {
mockDispatcher({
"finops.role_grants": {
success: false,
error: "Connection refused",
},
})

const tool = await FinopsRoleGrantsTool.init()
const result = await tool.execute({ warehouse: "test_wh", limit: 100 }, ctx as any)

expect(result.title).toContain("FAILED")
expect(result.output).toContain("Connection refused")
})
})

describe("formatHierarchy: recursive role tree rendering", () => {
test("renders two-level nested hierarchy with children key", async () => {
mockDispatcher({
"finops.role_hierarchy": {
success: true,
role_count: 3,
hierarchy: [
{
name: "SYSADMIN",
children: [
{ name: "DBA", children: [] },
{ name: "ANALYST", children: [] },
],
},
],
},
})

const tool = await FinopsRoleHierarchyTool.init()
const result = await tool.execute({ warehouse: "test_wh" }, ctx as any)

expect(result.title).toContain("3 roles")
expect(result.output).toContain("Role Hierarchy")
expect(result.output).toContain("SYSADMIN")
expect(result.output).toContain("-> DBA")
expect(result.output).toContain("-> ANALYST")
})

test("uses granted_roles fallback alias for children", async () => {
mockDispatcher({
"finops.role_hierarchy": {
success: true,
role_count: 2,
hierarchy: [
{
role: "ACCOUNTADMIN",
granted_roles: [{ role: "SECURITYADMIN" }],
},
],
},
})

const tool = await FinopsRoleHierarchyTool.init()
const result = await tool.execute({ warehouse: "test_wh" }, ctx as any)

// Should use r.role as name and r.granted_roles as children
expect(result.output).toContain("ACCOUNTADMIN")
expect(result.output).toContain("-> SECURITYADMIN")
})

test("handles empty hierarchy", async () => {
mockDispatcher({
"finops.role_hierarchy": {
success: true,
role_count: 0,
hierarchy: [],
},
})

const tool = await FinopsRoleHierarchyTool.init()
const result = await tool.execute({ warehouse: "test_wh" }, ctx as any)

expect(result.output).toContain("Role Hierarchy")
// No roles rendered but header is present
expect(result.output).not.toContain("->")
})
})

describe("formatUserRoles: user-role assignment table", () => {
test("renders user assignments with standard fields", async () => {
mockDispatcher({
"finops.user_roles": {
success: true,
assignment_count: 2,
assignments: [
{ grantee_name: "alice@corp.com", role: "ANALYST", granted_by: "SECURITYADMIN" },
{ grantee_name: "bob@corp.com", role: "DBA", granted_by: "ACCOUNTADMIN" },
],
},
})

const tool = await FinopsUserRolesTool.init()
const result = await tool.execute({ warehouse: "test_wh", limit: 100 }, ctx as any)

expect(result.title).toContain("2 assignments")
expect(result.output).toContain("User Role Assignments")
expect(result.output).toContain("alice@corp.com | ANALYST | SECURITYADMIN")
expect(result.output).toContain("bob@corp.com | DBA | ACCOUNTADMIN")
})

test("uses fallback aliases (user_name, role_name, grantor)", async () => {
mockDispatcher({
"finops.user_roles": {
success: true,
assignment_count: 1,
assignments: [
{ user_name: "charlie", role_name: "READER", grantor: "ADMIN" },
],
},
})

const tool = await FinopsUserRolesTool.init()
const result = await tool.execute({ warehouse: "test_wh", limit: 100 }, ctx as any)

// Falls back to r.user_name (via user fallback chain), r.role_name, r.grantor
expect(result.output).toContain("charlie | READER | ADMIN")
})

test("handles empty assignments", async () => {
mockDispatcher({
"finops.user_roles": {
success: true,
assignment_count: 0,
assignments: [],
},
})

const tool = await FinopsUserRolesTool.init()
const result = await tool.execute({ warehouse: "test_wh", limit: 100 }, ctx as any)

expect(result.output).toContain("No user role assignments found")
})
})
149 changes: 149 additions & 0 deletions packages/opencode/test/altimate/tool-lookup.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/**
* Tests for the tool_lookup tool — Zod schema introspection
* (describeZodSchema, inferZodType, unwrap, getShape).
*
* The agent uses tool_lookup to discover other tools' parameter contracts.
* Incorrect introspection leads to wrong tool calls.
*/
import { describe, test, expect, beforeEach, afterAll } from "bun:test"
import z from "zod"
import { ToolLookupTool } from "../../src/altimate/tools/tool-lookup"
import { ToolRegistry } from "../../src/tool/registry"
import { Instance } from "../../src/project/instance"
import { tmpdir } from "../fixture/fixture"
import { SessionID, MessageID } from "../../src/session/schema"

beforeEach(() => {
process.env.ALTIMATE_TELEMETRY_DISABLED = "true"
})
afterAll(() => {
delete process.env.ALTIMATE_TELEMETRY_DISABLED
})

const ctx = {
sessionID: SessionID.make("ses_test"),
messageID: MessageID.make("msg_test"),
callID: "call_test",
agent: "build",
abort: AbortSignal.any([]),
messages: [],
metadata: () => {},
ask: async () => {},
}

describe("ToolLookupTool: Zod schema introspection", () => {
test("returns parameter info for tool with mixed types", async () => {
await using tmp = await tmpdir()
await Instance.provide({
directory: tmp.path,
fn: async () => {
const testTool = {
id: "__test_lookup_mixed",
init: async () => ({
description: "Test tool with mixed params",
parameters: z.object({
name: z.string().describe("The name"),
count: z.number().describe("How many"),
verbose: z.boolean().optional().describe("Enable verbosity"),
tags: z.array(z.string()).describe("Tags list"),
mode: z.enum(["fast", "slow"]).default("fast").describe("Execution mode"),
}),
execute: async () => ({ title: "", output: "", metadata: {} }),
}),
}
await ToolRegistry.register(testTool)

const tool = await ToolLookupTool.init()
const result = await tool.execute({ tool_name: "__test_lookup_mixed" }, ctx as any)

// Required string param
expect(result.output).toContain("name")
expect(result.output).toContain("string")
expect(result.output).toContain("required")
expect(result.output).toContain("The name")

// Number param
expect(result.output).toContain("count")
expect(result.output).toContain("number")

// Optional boolean
expect(result.output).toContain("verbose")
expect(result.output).toContain("optional")

// Array param
expect(result.output).toContain("tags")
expect(result.output).toContain("array")

// Enum with default — inferZodType unwraps default then hits enum
expect(result.output).toContain("mode")
expect(result.output).toContain("enum")
},
})
})

test("returns 'Tool not found' with available tools list", async () => {
await using tmp = await tmpdir()
await Instance.provide({
directory: tmp.path,
fn: async () => {
const tool = await ToolLookupTool.init()
const result = await tool.execute({ tool_name: "nonexistent_tool_xyz" }, ctx as any)
expect(result.title).toBe("Tool not found")
expect(result.output).toContain('No tool named "nonexistent_tool_xyz"')
expect(result.output).toContain("Available tools:")
},
})
})

test("handles tool with empty parameters object", async () => {
await using tmp = await tmpdir()
await Instance.provide({
directory: tmp.path,
fn: async () => {
const testTool = {
id: "__test_lookup_empty",
init: async () => ({
description: "Tool with empty params",
parameters: z.object({}),
execute: async () => ({ title: "", output: "", metadata: {} }),
}),
}
await ToolRegistry.register(testTool)

const tool = await ToolLookupTool.init()
const result = await tool.execute({ tool_name: "__test_lookup_empty" }, ctx as any)
expect(result.output).toContain("No parameters")
},
})
})

test("unwraps nested optional/default wrappers correctly", async () => {
await using tmp = await tmpdir()
await Instance.provide({
directory: tmp.path,
fn: async () => {
const testTool = {
id: "__test_lookup_nested",
init: async () => ({
description: "Tool with nested wrappers",
parameters: z.object({
// default wrapping optional wrapping string
deep: z.string().optional().default("hello").describe("Deeply wrapped"),
}),
execute: async () => ({ title: "", output: "", metadata: {} }),
}),
}
await ToolRegistry.register(testTool)

const tool = await ToolLookupTool.init()
const result = await tool.execute({ tool_name: "__test_lookup_nested" }, ctx as any)

// Should unwrap to the inner string type
expect(result.output).toContain("deep")
expect(result.output).toContain("Deeply wrapped")
// The outer wrapper is default, so it should show as optional
expect(result.output).toContain("optional")
},
})
})
})
Loading