Merge branch 'codex/invariant-package-registration-gate' into codex/package-invariant-checks
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import type { Session, SessionEvent } from '@deepseek-ai/dsh-session'
|
||||
import InvariantService, { InvariantError } from '@deepseek-ai/dsh-invariants'
|
||||
import * as SandboxPolicyInvariant from '@deepseek-ai/dsh-sandbox-policy/invariant'
|
||||
|
||||
async function setup(): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(InvariantService)
|
||||
await ctx.plugin(SandboxPolicyInvariant)
|
||||
return ctx
|
||||
}
|
||||
|
||||
function modeEvent(mode: string): SessionEvent {
|
||||
return { type: 'sandbox/mode', seq: 0, time: 0, data: { mode } } as SessionEvent
|
||||
}
|
||||
|
||||
describe('sandbox-policy invariants', () => {
|
||||
it.each(['read-only', 'workspace-write', 'danger-full-access'])(
|
||||
'accepts the durable %s mode',
|
||||
async (mode) => {
|
||||
const ctx = await setup()
|
||||
expect(() => { ctx.emit('session/event', {} as Session, modeEvent(mode)) }).not.toThrow()
|
||||
},
|
||||
)
|
||||
|
||||
it('ignores unrelated event streams', async () => {
|
||||
const ctx = await setup()
|
||||
expect(() => { ctx.emit('session/event', {} as Session, {
|
||||
type: 'turn/start', seq: 0, time: 0, data: {},
|
||||
} as SessionEvent) }).not.toThrow()
|
||||
expect(() => { ctx.emit('tools/change') }).not.toThrow()
|
||||
})
|
||||
|
||||
it('rejects and attributes an unknown durable sandbox mode', async () => {
|
||||
const ctx = await setup()
|
||||
expect(() => { ctx.emit('session/event', {} as Session, modeEvent('host-root')) })
|
||||
.toThrow(new InvariantError('@deepseek-ai/dsh-sandbox-policy', 'sandbox/mode carries unknown mode "host-root"'))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Tests for the sandbox-policy home: the deployment default (mode +
|
||||
* workspaceRoot) the service exposes, and the per-session `sandbox/mode`
|
||||
* override kit (fold + write path) both enforcing families read.
|
||||
*/
|
||||
|
||||
import { resolve } from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import { Session, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import SandboxPolicyService, { SANDBOX_MODES, effectiveSandboxMode, setSandboxMode } from '@deepseek-ai/dsh-sandbox-policy'
|
||||
|
||||
async function mounted(config: { mode?: 'read-only' | 'workspace-write' | 'danger-full-access'; workspaceRoot?: string } = {}) {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SandboxPolicyService, config)
|
||||
return ctx
|
||||
}
|
||||
|
||||
describe('SandboxPolicyService', () => {
|
||||
it('defaults to read-only under the process cwd', async () => {
|
||||
const ctx = await mounted()
|
||||
expect(ctx.sandboxPolicy.defaultMode).toBe('read-only')
|
||||
expect(ctx.sandboxPolicy.workspaceRoot).toBe(resolve(process.cwd()))
|
||||
})
|
||||
|
||||
it('carries a configured mode and resolves the workspace root absolute', async () => {
|
||||
const ctx = await mounted({ mode: 'workspace-write', workspaceRoot: '/ws/../ws/./sub' })
|
||||
expect(ctx.sandboxPolicy.defaultMode).toBe('workspace-write')
|
||||
expect(ctx.sandboxPolicy.workspaceRoot).toBe(resolve('/ws/../ws/./sub'))
|
||||
})
|
||||
|
||||
it('rejects a mode outside the closed vocabulary at load', async () => {
|
||||
const ctx = new Context()
|
||||
// schemastery rejects the union violation when the plugin loads.
|
||||
await expect(ctx.plugin(SandboxPolicyService, { mode: 'yolo' as never })).rejects.toThrow()
|
||||
})
|
||||
|
||||
it('unregisters cleanly from a child fiber (HMR safety)', async () => {
|
||||
const ctx = new Context()
|
||||
const fiber = await ctx.plugin(SandboxPolicyService, {})
|
||||
expect(ctx.sandboxPolicy).toBeDefined()
|
||||
await fiber.dispose()
|
||||
expect(ctx.get('sandboxPolicy')).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('the sandbox/mode session kit', () => {
|
||||
it('SANDBOX_MODES lists every mode for advertisement and validation', () => {
|
||||
expect(SANDBOX_MODES).toEqual(['read-only', 'workspace-write', 'danger-full-access'])
|
||||
})
|
||||
|
||||
it('effectiveSandboxMode folds to the last switch, or undefined without one', () => {
|
||||
const session = new Session(SessionId('sess-fold'))
|
||||
expect(effectiveSandboxMode(session.events)).toBeUndefined()
|
||||
setSandboxMode(session, 'workspace-write')
|
||||
setSandboxMode(session, 'read-only')
|
||||
expect(effectiveSandboxMode(session.events)).toBe('read-only')
|
||||
})
|
||||
|
||||
it('setSandboxMode appends exactly one sandbox/mode event per switch', () => {
|
||||
const session = new Session(SessionId('sess-write'))
|
||||
setSandboxMode(session, 'danger-full-access')
|
||||
const modeEvents = session.events.filter(e => e.type === 'sandbox/mode')
|
||||
expect(modeEvents).toHaveLength(1)
|
||||
expect(modeEvents[0]?.data).toEqual({ mode: 'danger-full-access' })
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user