Files
oh-my-openagent/src/cli/config-manager/auth-plugins.test.ts
YeonGyu-Kim 7027b55c56 fix: remove automatic antigravity plugin installation
Remove the automatic installation of opencode-antigravity-auth plugin
when users have Gemini configured. This change addresses several issues:

1. Antigravity plugin is causing Google account bans for users
2. Users are unaware the plugin was auto-installed
3. Google has built-in OAuth for Gemini that doesn't require third-party plugins

Users who need the antigravity plugin can manually add it to their
plugin configuration if desired.

Fixes issues with unexpected plugin installation and account safety.
2026-02-19 15:30:56 +09:00

231 lines
7.6 KiB
TypeScript

import { describe, expect, it, beforeEach, afterEach, spyOn } from "bun:test"
import { tmpdir } from "node:os"
import { join } from "node:path"
import { writeFileSync, readFileSync, existsSync, rmSync, mkdirSync } from "node:fs"
import { parseJsonc } from "../../shared/jsonc-parser"
import type { InstallConfig } from "../types"
import { resetConfigContext } from "./config-context"
let testConfigPath: string
let testConfigDir: string
let testCounter = 0
let fetchVersionSpy: unknown
beforeEach(async () => {
testCounter++
testConfigDir = join(tmpdir(), `test-opencode-${Date.now()}-${testCounter}`)
testConfigPath = join(testConfigDir, "opencode.jsonc")
mkdirSync(testConfigDir, { recursive: true })
process.env.OPENCODE_CONFIG_DIR = testConfigDir
resetConfigContext()
const module = await import("./auth-plugins")
fetchVersionSpy = spyOn(module, "fetchLatestVersion").mockResolvedValue("1.2.3")
})
afterEach(() => {
try {
rmSync(testConfigDir, { recursive: true, force: true })
} catch {}
})
const testConfig: InstallConfig = {
hasClaude: false,
isMax20: false,
hasOpenAI: false,
hasGemini: true,
hasCopilot: false,
hasOpencodeZen: false,
hasZaiCodingPlan: false,
hasKimiForCoding: false,
}
describe("addAuthPlugins", () => {
describe("Test 1: JSONC with commented plugin line", () => {
it("preserves comment, does NOT add antigravity plugin", async () => {
const content = `{
// "plugin": ["old-plugin"]
"plugin": ["existing-plugin"],
"provider": {}
}`
writeFileSync(testConfigPath, content, "utf-8")
const { addAuthPlugins } = await import("./auth-plugins")
const result = await addAuthPlugins(testConfig)
expect(result.success).toBe(true)
const newContent = readFileSync(result.configPath, "utf-8")
expect(newContent).toContain('// "plugin": ["old-plugin"]')
expect(newContent).toContain('existing-plugin')
// antigravity plugin should NOT be auto-added anymore
expect(newContent).not.toContain('opencode-antigravity-auth')
const parsed = parseJsonc<Record<string, unknown>>(newContent)
const plugins = parsed.plugin as string[]
expect(plugins).toContain('existing-plugin')
expect(plugins.some((p) => p.startsWith('opencode-antigravity-auth'))).toBe(false)
})
})
describe("Test 2: Plugin array already contains antigravity", () => {
it("preserves existing antigravity, does not add another", async () => {
const content = `{
"plugin": ["existing-plugin", "opencode-antigravity-auth"],
"provider": {}
}`
writeFileSync(testConfigPath, content, "utf-8")
const { addAuthPlugins } = await import("./auth-plugins")
const result = await addAuthPlugins(testConfig)
expect(result.success).toBe(true)
const newContent = readFileSync(testConfigPath, "utf-8")
const parsed = parseJsonc<Record<string, unknown>>(newContent)
const plugins = parsed.plugin as string[]
const antigravityCount = plugins.filter((p) => p.startsWith('opencode-antigravity-auth')).length
expect(antigravityCount).toBe(1)
expect(plugins).toContain('existing-plugin')
})
})
describe("Test 3: Backup created before write", () => {
it("creates .bak file", async () => {
const originalContent = `{
"plugin": ["existing-plugin"],
"provider": {}
}`
writeFileSync(testConfigPath, originalContent, "utf-8")
readFileSync(testConfigPath, "utf-8")
const { addAuthPlugins } = await import("./auth-plugins")
const result = await addAuthPlugins(testConfig)
expect(result.success).toBe(true)
expect(existsSync(`${result.configPath}.bak`)).toBe(true)
const backupContent = readFileSync(`${result.configPath}.bak`, "utf-8")
expect(backupContent).toBe(originalContent)
})
})
describe("Test 4: Comment with } character", () => {
it("preserves comments with special characters", async () => {
const content = `{
// This comment has } special characters
"plugin": ["existing-plugin"],
"provider": {}
}`
writeFileSync(testConfigPath, content, "utf-8")
const { addAuthPlugins } = await import("./auth-plugins")
const result = await addAuthPlugins(testConfig)
expect(result.success).toBe(true)
const newContent = readFileSync(testConfigPath, "utf-8")
expect(newContent).toContain('// This comment has } special characters')
expect(() => parseJsonc(newContent)).not.toThrow()
})
})
describe("Test 5: Comment containing 'plugin' string", () => {
it("must NOT match comment location", async () => {
const content = `{
// "plugin": ["fake"]
"plugin": ["existing-plugin"],
"provider": {}
}`
writeFileSync(testConfigPath, content, "utf-8")
const { addAuthPlugins } = await import("./auth-plugins")
const result = await addAuthPlugins(testConfig)
expect(result.success).toBe(true)
const newContent = readFileSync(testConfigPath, "utf-8")
expect(newContent).toContain('// "plugin": ["fake"]')
const parsed = parseJsonc<Record<string, unknown>>(newContent)
const plugins = parsed.plugin as string[]
expect(plugins).toContain('existing-plugin')
expect(plugins).not.toContain('fake')
})
})
describe("Test 6: No existing plugin array", () => {
it("creates empty plugin array when none exists, does NOT add antigravity", async () => {
const content = `{
"provider": {}
}`
writeFileSync(testConfigPath, content, "utf-8")
const { addAuthPlugins } = await import("./auth-plugins")
const result = await addAuthPlugins(testConfig)
expect(result.success).toBe(true)
const newContent = readFileSync(result.configPath, "utf-8")
const parsed = parseJsonc<Record<string, unknown>>(newContent)
expect(parsed).toHaveProperty('plugin')
const plugins = parsed.plugin as string[]
// antigravity plugin should NOT be auto-added anymore
expect(plugins.some((p) => p.startsWith('opencode-antigravity-auth'))).toBe(false)
expect(plugins.length).toBe(0)
})
})
describe("Test 7: Post-write validation ensures valid JSONC", () => {
it("result file must be valid JSONC", async () => {
const content = `{
"plugin": ["existing-plugin"],
"provider": {}
}`
writeFileSync(testConfigPath, content, "utf-8")
const { addAuthPlugins } = await import("./auth-plugins")
const result = await addAuthPlugins(testConfig)
expect(result.success).toBe(true)
const newContent = readFileSync(testConfigPath, "utf-8")
expect(() => parseJsonc(newContent)).not.toThrow()
const parsed = parseJsonc<Record<string, unknown>>(newContent)
expect(parsed).toHaveProperty('plugin')
expect(parsed).toHaveProperty('provider')
})
})
describe("Test 8: Multiple plugins in array", () => {
it("preserves existing plugins, does NOT add antigravity", async () => {
const content = `{
"plugin": ["plugin-1", "plugin-2", "plugin-3"],
"provider": {}
}`
writeFileSync(testConfigPath, content, "utf-8")
const { addAuthPlugins } = await import("./auth-plugins")
const result = await addAuthPlugins(testConfig)
expect(result.success).toBe(true)
const newContent = readFileSync(result.configPath, "utf-8")
const parsed = parseJsonc<Record<string, unknown>>(newContent)
const plugins = parsed.plugin as string[]
expect(plugins).toContain('plugin-1')
expect(plugins).toContain('plugin-2')
expect(plugins).toContain('plugin-3')
// antigravity plugin should NOT be auto-added anymore
expect(plugins.some((p) => p.startsWith('opencode-antigravity-auth'))).toBe(false)
expect(plugins.length).toBe(3)
})
})
})