Files
nucleic/Tests/NucleicCoreTests/CodexAppServerBackendTests.swift
T

124 lines
5.8 KiB
Swift

import Testing
@testable import NucleicCore
/// Provider approval callbacks remain client-reviewed; Nucleic owns policy and presentation.
@Suite struct CodexAppServerBackendTests {
@Test func autoModeStillRoutesReviewToNucleic() {
#expect(CodexAppServerBackend.approvalsReviewer(autoApprove: true) == "user")
}
@Test func resumePreservesPlatformToolCapabilities() {
let resume = ResumeSpec(
sessionID: SessionID(rawValue: "resume-tools"), backendSessionID: "thread-1",
worktree: "/repo", allowHostExec: true, allowMacVMExec: true,
allowMacVMComputer: true, allowLinuxVMExec: true,
allowLinuxVMComputer: true, allowAgentContainers: true)
let run = CodexAppServerBackend.runSpec(resuming: resume)
#expect(run.allowHostExec)
#expect(run.allowMacVMExec)
#expect(run.allowMacVMComputer)
#expect(run.allowLinuxVMExec)
#expect(run.allowLinuxVMComputer)
#expect(run.allowAgentContainers)
}
@Test func commonAutoPolicyNeverApprovesDestructiveUnknownOrQuestions() {
#expect(NucleicApprovalPolicy.shouldAutoApprove(autoApprove: true, risk: .write))
#expect(!NucleicApprovalPolicy.shouldAutoApprove(autoApprove: true, risk: .destructive))
#expect(!NucleicApprovalPolicy.shouldAutoApprove(autoApprove: true, risk: .unknown))
#expect(!NucleicApprovalPolicy.shouldAutoApprove(
autoApprove: true, risk: .write, requiresExplicitUserDecision: true))
#expect(!NucleicApprovalPolicy.shouldAutoApprove(autoApprove: false, risk: .write))
}
@Test func interactiveModeSelectsUserReviewer() {
#expect(CodexAppServerBackend.approvalsReviewer(autoApprove: false) == "user")
}
@Test func acceptsSupportedMaxAndSolProWireEfforts() {
#expect(CodexAppServerBackend.acceptedReasoningEffort(
"max", model: "gpt-5.6-sol", codexPro: false) == "max")
#expect(CodexAppServerBackend.acceptedReasoningEffort(
"max", model: "gpt-5.6-terra", codexPro: false) == "max")
#expect(CodexAppServerBackend.acceptedReasoningEffort(
"max", model: "gpt-5.5", codexPro: true) == nil)
#expect(CodexAppServerBackend.acceptedReasoningEffort(
"ultra", model: "gpt-5.6-sol", codexPro: true) == "ultra")
#expect(CodexAppServerBackend.acceptedReasoningEffort(
"ultra", model: "gpt-5.6-sol", codexPro: false) == nil)
#expect(CodexAppServerBackend.acceptedReasoningEffort(
"ultra", model: "gpt-5.6-terra", codexPro: true) == nil)
#expect(CodexAppServerBackend.acceptedReasoningEffort(
"pro", model: "gpt-5.6-sol", codexPro: true) == nil)
#expect(CodexAppServerBackend.acceptedReasoningEffort(
"unknown", model: "gpt-5.6-sol", codexPro: true) == nil)
}
// MARK: - Nucleic-MCP auto-allow (CodexGateOwnership)
private func request(_ method: String, _ params: [String: JSONValue])
-> JSONRPCConnection.InboundRequest
{
JSONRPCConnection.InboundRequest(id: .string("1"), method: method, params: .object(params))
}
@Test func topLevelServerAndToolIdentityStillMatch() {
#expect(CodexAppServerBackend.concernsNucleicMCP(
request("item/tool/requestApproval", ["server": .string("nucleic")])))
#expect(CodexAppServerBackend.concernsNucleicMCP(
request("item/tool/requestApproval", ["toolName": .string("mcp__nucleic__mac_vm_exec")])))
}
/// A guardian permission request identifies the call *nested*, under the requested-permission
/// entry rather than at the top level — the shape a top-level-only check missed, which is how
/// Nucleic's own VM tools ended up prompting or failing instead of being auto-allowed.
@Test func nestedGuardianPermissionPayloadMatches() {
let nested = request(
"permissions/requestApproval",
[
"threadId": .string("t1"),
"permissions": .array([
.object([
"mcpToolCall": .object([
"toolName": .string("mcp__nucleic__linux_container"),
"connectorName": .string("nucleic"),
])
])
]),
])
#expect(CodexAppServerBackend.concernsNucleicMCP(nested))
// Same shape in the core's snake_case spelling.
let snake = request(
"permissions/requestApproval",
["permissions": .array([.object(["mcp_tool_call": .object([
"tool_name": .string("mcp__nucleic__mac_vm_computer"),
"connector_name": .string("nucleic"),
])])])])
#expect(CodexAppServerBackend.concernsNucleicMCP(snake))
}
/// The recursive match must not auto-allow an unrelated approval. This project is itself named
/// "nucleic", so a bare `name: "nucleic"` buried in a command approval's payload must NOT count
/// — only a server/connector key, or a `mcp__nucleic__`-qualified tool name, may.
@Test func unrelatedApprovalNamingTheProjectIsNotAutoAllowed() {
let commandApproval = request(
"item/commandExecution/requestApproval",
[
"itemId": .string("c1"),
"command": .string("rm -rf build"),
"workspace": .object(["name": .string("nucleic")]),
])
#expect(!CodexAppServerBackend.concernsNucleicMCP(commandApproval))
let otherServer = request(
"permissions/requestApproval",
["permissions": .array([.object(["mcpToolCall": .object([
"toolName": .string("mcp__github__create_issue"),
"connectorName": .string("github"),
])])])])
#expect(!CodexAppServerBackend.concernsNucleicMCP(otherServer))
}
}