pending-confinement.ts 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. /** Snapshot provider that awaits cancellation and records any premature process allocation. */
  2. import { writeFileSync } from 'node:fs'
  3. import { join } from 'node:path'
  4. import type { Context } from '@deepseek-ai/cordis'
  5. import { SandboxProvider } 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-pending-confinement'
  9. /**
  10. * Mount pending confinement and a process-allocation tripwire through normal 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 process allocation after preparation timeout')
  24. }
  25. }
  26. class PendingSandbox extends SandboxProvider {
  27. override async confine(_argv: readonly string[], _policy: SandboxPolicy, signal?: AbortSignal): Promise<ConfinedArgv> {
  28. if (signal === undefined) throw new Error('foreground confinement requires a deadline signal')
  29. signal.throwIfAborted()
  30. confineCalls++
  31. audit()
  32. return new Promise((_resolve, reject) => {
  33. signal.addEventListener('abort', () => { reject(new Error('fixture preparation aborted')) }, { once: true })
  34. })
  35. }
  36. }
  37. await ctx.plugin(GuardedSubprocess)
  38. await ctx.plugin(PendingSandbox)
  39. }