Scope files jobs and plugins to request profile

This commit is contained in:
ekko
2026-05-24 09:25:52 +08:00
committed by ekko
parent 289a958684
commit 9708a6a521
23 changed files with 353 additions and 117 deletions
+39
View File
@@ -13,6 +13,8 @@ vi.mock('@/router', () => ({
}))
import { getApiKey, setApiKey, clearApiKey, hasApiKey, getStoredUserRole, isStoredSuperAdmin, request } from '../../packages/client/src/api/client'
import { getDownloadUrl } from '../../packages/client/src/api/hermes/download'
import { uploadFiles } from '../../packages/client/src/api/hermes/files'
import router from '@/router'
function fakeJwt(payload: Record<string, unknown>) {
@@ -153,4 +155,41 @@ describe('API Client', () => {
expect(result).toEqual(data)
})
})
describe('download URLs', () => {
it('adds the active profile selector to direct download URLs', () => {
setApiKey('secret-key')
localStorage.setItem('hermes_active_profile_name', 'research')
const url = new URL(getDownloadUrl('/tmp/report.txt', 'report.txt'), 'http://localhost')
expect(url.pathname).toBe('/api/hermes/download')
expect(url.searchParams.get('path')).toBe('/tmp/report.txt')
expect(url.searchParams.get('name')).toBe('report.txt')
expect(url.searchParams.get('profile')).toBe('research')
expect(url.searchParams.get('token')).toBe('secret-key')
})
})
describe('file upload', () => {
it('adds auth and active profile headers to multipart uploads', async () => {
setApiKey('secret-key')
localStorage.setItem('hermes_active_profile_name', 'research')
mockFetch.mockResolvedValue({
ok: true,
status: 200,
json: () => Promise.resolve({ files: [] }),
})
await uploadFiles('notes', [new File(['hello'], 'hello.txt', { type: 'text/plain' })])
expect(mockFetch).toHaveBeenCalledOnce()
const [url, options] = mockFetch.mock.calls[0]
expect(url).toBe('/api/hermes/files/upload?path=notes')
expect(options.method).toBe('POST')
expect(options.headers.Authorization).toBe('Bearer secret-key')
expect(options.headers['X-Hermes-Profile']).toBe('research')
expect(options.body).toBeInstanceOf(FormData)
})
})
})
+17
View File
@@ -17,6 +17,7 @@ import {
scheduleToEditableInput,
updateJob,
} from '../../packages/client/src/api/hermes/jobs'
import { listCronRuns } from '../../packages/client/src/api/hermes/cron-history'
import type { Job } from '../../packages/client/src/api/hermes/jobs'
function makeJob(overrides: Partial<Job> = {}): Job {
@@ -118,4 +119,20 @@ describe('Hermes jobs edit payloads', () => {
schedule: 'every 14400m',
})
})
it('sends active profile header when loading job run history', async () => {
localStorage.setItem('hermes_active_profile_name', 'research')
mockFetch.mockResolvedValue({
ok: true,
status: 200,
json: () => Promise.resolve({ runs: [] }),
})
await listCronRuns('job-1')
expect(mockFetch).toHaveBeenCalledOnce()
const [url, options] = mockFetch.mock.calls[0]
expect(url).toBe('/api/cron-history?jobId=job-1')
expect(options.headers['X-Hermes-Profile']).toBe('research')
})
})