Fix bridge profile environment isolation (#796)
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { existsSync, readFileSync } from 'fs'
|
||||
import { mkdir, mkdtemp, rm, writeFile } from 'fs/promises'
|
||||
import { tmpdir } from 'os'
|
||||
import { join } from 'path'
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
|
||||
// Mock hermes-cli
|
||||
vi.mock('../../packages/server/src/services/hermes/hermes-cli', () => ({
|
||||
@@ -19,27 +23,17 @@ vi.mock('../../packages/server/src/services/hermes/hermes-cli', () => ({
|
||||
import * as hermesCli from '../../packages/server/src/services/hermes/hermes-cli'
|
||||
|
||||
describe('Profile Routes', () => {
|
||||
const originalHermesHome = process.env.HERMES_HOME
|
||||
const tempHomes: string[] = []
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('ensureApiServerConfig (via active profile switch)', () => {
|
||||
it('should inject api_server config when missing', async () => {
|
||||
// This tests the logic that profiles.ts ensures api_server config exists
|
||||
// We test the ensureApiServerConfig behavior indirectly through the module
|
||||
const { existsSync, readFileSync, writeFileSync } = await import('fs')
|
||||
vi.mock('fs', () => ({
|
||||
existsSync: vi.fn().mockReturnValue(true),
|
||||
readFileSync: vi.fn().mockReturnValue('platforms: {}'),
|
||||
writeFileSync: vi.fn(),
|
||||
createReadStream: vi.fn(),
|
||||
unlinkSync: vi.fn(),
|
||||
mkdirSync: vi.fn(),
|
||||
copyFileSync: vi.fn(),
|
||||
mkdir: vi.fn(),
|
||||
writeFile: vi.fn(),
|
||||
}))
|
||||
})
|
||||
afterEach(async () => {
|
||||
if (originalHermesHome === undefined) delete process.env.HERMES_HOME
|
||||
else process.env.HERMES_HOME = originalHermesHome
|
||||
await Promise.all(tempHomes.splice(0).map(dir => rm(dir, { recursive: true, force: true })))
|
||||
})
|
||||
|
||||
describe('hermes-cli wrapper', () => {
|
||||
@@ -84,4 +78,43 @@ describe('Profile Routes', () => {
|
||||
expect(hermesCli.renameProfile).toHaveBeenCalledWith('old', 'new')
|
||||
})
|
||||
})
|
||||
|
||||
describe('profile deletion fallback', () => {
|
||||
it('removes a reserved profile directory when Hermes CLI refuses to delete it', async () => {
|
||||
const hermesHome = await mkdtemp(join(tmpdir(), 'hermes-profile-delete-'))
|
||||
tempHomes.push(hermesHome)
|
||||
process.env.HERMES_HOME = hermesHome
|
||||
const badProfileDir = join(hermesHome, 'profiles', 'hermes')
|
||||
await mkdir(badProfileDir, { recursive: true })
|
||||
await writeFile(join(badProfileDir, 'config.yaml'), 'model:\n default: bad\n', 'utf-8')
|
||||
await writeFile(join(hermesHome, 'active_profile'), 'hermes\n', 'utf-8')
|
||||
vi.mocked(hermesCli.deleteProfile).mockResolvedValue(false)
|
||||
const { remove } = await import('../../packages/server/src/controllers/hermes/profiles')
|
||||
const ctx: any = { params: { name: 'hermes' }, status: 200, body: undefined }
|
||||
|
||||
await remove(ctx)
|
||||
|
||||
expect(ctx.status).toBe(200)
|
||||
expect(ctx.body).toEqual({ success: true, fallback: 'removed_reserved_profile_from_disk' })
|
||||
expect(existsSync(badProfileDir)).toBe(false)
|
||||
expect(readFileSync(join(hermesHome, 'active_profile'), 'utf-8')).toBe('default\n')
|
||||
})
|
||||
|
||||
it('does not bypass Hermes CLI failures for normal profile names', async () => {
|
||||
const hermesHome = await mkdtemp(join(tmpdir(), 'hermes-profile-delete-'))
|
||||
tempHomes.push(hermesHome)
|
||||
process.env.HERMES_HOME = hermesHome
|
||||
const profileDir = join(hermesHome, 'profiles', 'work')
|
||||
await mkdir(profileDir, { recursive: true })
|
||||
vi.mocked(hermesCli.deleteProfile).mockResolvedValue(false)
|
||||
const { remove } = await import('../../packages/server/src/controllers/hermes/profiles')
|
||||
const ctx: any = { params: { name: 'work' }, status: 200, body: undefined }
|
||||
|
||||
await remove(ctx)
|
||||
|
||||
expect(ctx.status).toBe(500)
|
||||
expect(ctx.body).toEqual({ error: 'Failed to delete profile' })
|
||||
expect(existsSync(profileDir)).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user