async-confinement-failure.ts 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. /** Snapshot provider whose asynchronous refusal records every attempted underlying spawn. */
  2. import { writeFileSync } from 'node:fs'
  3. import { join } from 'node:path'
  4. import type { Context } from '@deepseek-ai/cordis'
  5. import { SandboxProvider, SandboxUnavailableError } from '@deepseek-ai/dsh-sandbox'
  6. import type { ConfinedArgv, SandboxPolicy } from '@deepseek-ai/dsh-sandbox'
  7. import LocalSubprocessRuntime from '@deepseek-ai/dsh-subprocess-local'
  8. export const name = 'snapshot-async-confinement-failure'
  9. /**
  10. * Mount a refusing sandbox and an underlying-spawn tripwire through normal Cordis services.
  11. * @param ctx - scenario-owned composition context.
  12. */
  13. export async function apply(ctx: Context): Promise<void> {
  14. let confineCalls = 0
  15. let spawnCalls = 0
  16. const audit = (): void => {
  17. writeFileSync(join(process.cwd(), 'confinement-audit.json'), JSON.stringify({ confineCalls, spawnCalls }) + '\n')
  18. }
  19. class GuardedSubprocess extends LocalSubprocessRuntime {
  20. override spawn(): never {
  21. spawnCalls++
  22. audit()
  23. throw new Error('unexpected subprocess allocation after confinement refusal')
  24. }
  25. override async spawnTerminal(): Promise<never> {
  26. spawnCalls++
  27. audit()
  28. throw new Error('unexpected terminal allocation after confinement refusal')
  29. }
  30. }
  31. class RefusingSandbox extends SandboxProvider {
  32. override async confine(_argv: readonly string[], policy: SandboxPolicy, signal?: AbortSignal): Promise<ConfinedArgv> {
  33. await Promise.resolve()
  34. signal?.throwIfAborted()
  35. confineCalls++
  36. audit()
  37. throw new SandboxUnavailableError(policy.mode, 'fixture asynchronous confinement refused')
  38. }
  39. }
  40. await ctx.plugin(GuardedSubprocess)
  41. await ctx.plugin(RefusingSandbox)
  42. }