@tangle-network/agent-bench 0.1.0 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/HARNESS.md +302 -0
- package/README.md +26 -1
- package/fixtures/aec-bench.json +18 -0
- package/fixtures/agentbench-dbbench.json +22 -0
- package/fixtures/bfcl.json +45 -0
- package/fixtures/commit0.json +72 -0
- package/fixtures/crag.json +10 -0
- package/fixtures/dabstep.json +22 -0
- package/fixtures/enterpriseops-gym.json +103 -0
- package/fixtures/finresearchbench.json +21 -0
- package/fixtures/finsearchcomp.json +66 -0
- package/fixtures/frames.json +26 -0
- package/fixtures/hotpotqa.json +182 -0
- package/fixtures/nomiracl.json +26 -0
- package/fixtures/open-rag-bench.json +16 -0
- package/fixtures/pier-agent/no-model-task/environment/Dockerfile +16 -0
- package/fixtures/pier-agent/no-model-task/environment/seed/src/status.txt +1 -0
- package/fixtures/pier-agent/no-model-task/instruction.md +6 -0
- package/fixtures/pier-agent/no-model-task/pre_artifacts.sh +6 -0
- package/fixtures/pier-agent/no-model-task/task.toml +35 -0
- package/fixtures/pier-agent/no-model-task/tests/Dockerfile +17 -0
- package/fixtures/pier-agent/no-model-task/tests/seed/src/status.txt +1 -0
- package/fixtures/pier-agent/no-model-task/tests/test.sh +19 -0
- package/fixtures/programbench.json +17 -0
- package/fixtures/ragbench.json +21 -0
- package/fixtures/simpleqa.json +121 -0
- package/fixtures/t2-ragbench.json +13 -0
- package/fixtures/tau2-bench.json +16 -0
- package/fixtures/tau3-banking.json +16 -0
- package/fixtures/toollm.json +28 -0
- package/fixtures/webarena-verified.json +20 -0
- package/package.json +39 -15
- package/pier_agents/__init__.py +18 -0
- package/pier_agents/candidate_contract.py +755 -0
- package/pier_agents/process_boundary.py +321 -0
- package/pier_agents/tangle_candidate.py +907 -0
- package/pier_agents/workspace_boundary.py +368 -0
- package/scripts/appworld_driver.py +359 -0
- package/scripts/cadbench_prepare.py +22 -0
- package/scripts/cadgenbench_hard_parts.py +48 -0
- package/scripts/clbench_codebase_judge.py +73 -0
- package/scripts/commit0_judge.py +170 -0
- package/scripts/dabstep_judge.py +42 -0
- package/scripts/enterpriseops_gym_judge.py +281 -0
- package/scripts/programbench_judge.py +120 -0
- package/scripts/render-gate-chart.mjs +176 -0
- package/scripts/run-package-tests.mjs +56 -0
- package/scripts/terminate-pier-trial.mts +66 -0
- package/scripts/trata-hedge/README.md +56 -0
- package/scripts/trata-hedge/run.sh +60 -0
- package/scripts/trata-hedge/solve.py +83 -0
- package/scripts/verify-packed-consumer.mjs +224 -0
- package/scripts/verify-pier-agent.mts +715 -0
- package/scripts/verify-pier-pair.mts +74 -0
- package/scripts/verify-pier-recovery.mts +139 -0
- package/src/adapters.ts +26 -0
- package/src/benchmarks/_harness.test.mts +178 -0
- package/src/benchmarks/_harness.ts +239 -16
- package/src/benchmarks/agentbench.ts +163 -0
- package/src/benchmarks/appworld.test.mts +15 -9
- package/src/benchmarks/bfcl.ts +346 -0
- package/src/benchmarks/crag.ts +137 -0
- package/src/benchmarks/dabstep.test.mts +70 -0
- package/src/benchmarks/dabstep.ts +212 -0
- package/src/benchmarks/external-adapters.test.mts +150 -0
- package/src/benchmarks/finresearchbench.ts +269 -0
- package/src/benchmarks/humaneval.ts +20 -8
- package/src/benchmarks/nomiracl.ts +180 -0
- package/src/benchmarks/open-rag-bench.ts +153 -0
- package/src/benchmarks/rag-benchmarks.test.mts +138 -0
- package/src/benchmarks/rag-shared.ts +327 -0
- package/src/benchmarks/ragbench.ts +171 -0
- package/src/benchmarks/swe-bench.test.mts +61 -0
- package/src/benchmarks/swe-bench.ts +201 -19
- package/src/benchmarks/t2-ragbench.ts +166 -0
- package/src/benchmarks/tau-bench-shared.ts +214 -0
- package/src/benchmarks/tau2-bench.ts +30 -0
- package/src/benchmarks/tau3-banking.ts +29 -0
- package/src/benchmarks/terminal-bench.test.mts +33 -0
- package/src/benchmarks/terminal-bench.ts +23 -8
- package/src/benchmarks/toollm.ts +254 -0
- package/src/benchmarks/types.ts +42 -0
- package/src/benchmarks/webarena-verified.ts +200 -0
- package/src/commit0-prereqs.sh +0 -0
- package/src/coordination-mcp-container-reach.mts +181 -0
- package/src/decoder-live.mts +1 -1
- package/src/examples/README.md +103 -39
- package/src/examples/benchmark-matrix.mts +101 -0
- package/src/examples/lean-proof-gate.README.md +77 -0
- package/src/examples/lean-proof-gate.mts +162 -0
- package/src/examples/lean-verify.ts +95 -0
- package/src/examples/lean.Dockerfile +12 -0
- package/src/examples/math-demo.mts +9 -7
- package/src/examples/strategy-demo.mts +10 -12
- package/src/gate.ts +3 -2
- package/src/hev-eval.mts +69 -0
- package/src/hev-improve.mts +169 -0
- package/src/hev-structural.mts +688 -0
- package/src/index.ts +73 -0
- package/src/mbpp-structural.mts +662 -0
- package/src/pier-agent.test-fixtures.mts +19 -0
- package/src/pier-agent.test.mts +363 -0
- package/src/pier-agent.ts +657 -0
- package/src/pier-result-grader.mjs +30 -0
- package/src/pier-result-grader.test.mts +62 -0
- package/src/pier-result-grader.ts +108 -0
- package/src/pier-task-outcome.test.mts +117 -0
- package/src/pier-task-outcome.ts +240 -0
- package/src/pier-trial-controller.test.mts +412 -0
- package/src/pier-trial-controller.ts +858 -0
- package/src/pier-trial-supervisor.mjs +352 -0
- package/src/resolve-client.ts +25 -2
- package/src/run-benchmarks-cli.mts +72 -0
- package/src/run-benchmarks-report.ts +66 -0
- package/src/run-benchmarks.test.mts +231 -0
- package/src/run-benchmarks.ts +589 -0
- package/src/smoke-structural-rollout.mts +393 -0
- package/src/swe-bench-env.test.ts +207 -0
- package/src/swe-bench-env.ts +554 -0
- package/src/swe-jail.ts +293 -0
- package/src/swe-self-improve.mts +84 -0
- package/src/swe-structural-judge-policy.test.ts +117 -0
- package/src/swe-structural-judge-policy.ts +133 -0
- package/src/swe-structural-policy.test.ts +124 -0
- package/src/swe-structural-policy.ts +132 -0
- package/src/swe-structural-provenance.test.ts +93 -0
- package/src/swe-structural-provenance.ts +138 -0
- package/src/swe-structural.mts +1260 -0
- package/src/swe-temp.ts +14 -0
- package/src/tb-container-executor.mts +234 -0
- package/src/tb-container-executor.test.mts +99 -0
- package/src/tb-supervisor-sidecar.mts +222 -0
- package/src/trata-gepa.mts +1 -1
- package/steerers/eops-itsm-population.json +1 -0
- package/tb_agents/opencode_refine_agent.py +117 -0
- package/tb_agents/opencode_router_agent.py +406 -0
- package/tb_agents/opencode_supervisor_agent.py +239 -0
- package/tb_agents/script_agent.py +66 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { createHash } from 'node:crypto'
|
|
3
|
+
import { mkdtemp, readFile, rm } from 'node:fs/promises'
|
|
4
|
+
import { tmpdir } from 'node:os'
|
|
5
|
+
import { join } from 'node:path'
|
|
6
|
+
import test from 'node:test'
|
|
7
|
+
|
|
8
|
+
import { canonicalJson } from '@tangle-network/agent-eval'
|
|
9
|
+
import type {
|
|
10
|
+
AgentCandidateExecutorRequest,
|
|
11
|
+
PreparedAgentCandidateExecution,
|
|
12
|
+
} from '@tangle-network/agent-runtime'
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
awaitAbortableTrial,
|
|
16
|
+
protectedCaptureFromPierResult,
|
|
17
|
+
stagePreparedPierCandidateExecution,
|
|
18
|
+
} from './pier-agent'
|
|
19
|
+
|
|
20
|
+
const digest = (bytes: Uint8Array): `sha256:${string}` =>
|
|
21
|
+
`sha256:${createHash('sha256').update(bytes).digest('hex')}`
|
|
22
|
+
|
|
23
|
+
function prepared(root: string): PreparedAgentCandidateExecution {
|
|
24
|
+
const bundleDigest = `sha256:${'b'.repeat(64)}` as const
|
|
25
|
+
const executionId = 'pier-test-execution'
|
|
26
|
+
const task = {
|
|
27
|
+
outcome: {
|
|
28
|
+
kind: 'workspace',
|
|
29
|
+
repository: {
|
|
30
|
+
identity: 'fixture/repository',
|
|
31
|
+
rootIdentity: 'fixture/repository',
|
|
32
|
+
baseCommit: '1'.repeat(40),
|
|
33
|
+
baseTree: '2'.repeat(40),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
const material = {
|
|
38
|
+
schemaVersion: 1,
|
|
39
|
+
kind: 'agent-candidate-execution-plan-material',
|
|
40
|
+
runCell: { bundleDigest },
|
|
41
|
+
executionId,
|
|
42
|
+
limits: {
|
|
43
|
+
timeoutMs: 60_000,
|
|
44
|
+
maxSteps: 8,
|
|
45
|
+
maxModelCalls: 0,
|
|
46
|
+
maxInputTokens: 0,
|
|
47
|
+
maxOutputTokens: 0,
|
|
48
|
+
maxCostUsd: 0,
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
const planBytes = Buffer.from(canonicalJson(material))
|
|
52
|
+
const planDigest = digest(planBytes)
|
|
53
|
+
const receiptMaterial = {
|
|
54
|
+
schemaVersion: 1,
|
|
55
|
+
kind: 'agent-candidate-materialization',
|
|
56
|
+
digestAlgorithm: 'rfc8785-sha256',
|
|
57
|
+
bundleDigest,
|
|
58
|
+
executionPlan: { digest: planDigest, material },
|
|
59
|
+
}
|
|
60
|
+
const receiptBytes = Buffer.from(canonicalJson(receiptMaterial))
|
|
61
|
+
const receiptDigest = digest(receiptBytes)
|
|
62
|
+
const profileBytes = Buffer.from('fixture profile\n')
|
|
63
|
+
return {
|
|
64
|
+
bundle: { digest: bundleDigest },
|
|
65
|
+
benchmark: { task },
|
|
66
|
+
executionId,
|
|
67
|
+
roots: {
|
|
68
|
+
execution: { taskRoot: '/app' },
|
|
69
|
+
staging: {
|
|
70
|
+
taskRoot: join(root, 'task'),
|
|
71
|
+
profileRoot: join(root, 'profile'),
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
executionPlan: {
|
|
75
|
+
value: { digest: planDigest, material },
|
|
76
|
+
bytes: planBytes,
|
|
77
|
+
},
|
|
78
|
+
profilePlan: {
|
|
79
|
+
value: {
|
|
80
|
+
material: {
|
|
81
|
+
files: [
|
|
82
|
+
{
|
|
83
|
+
relPath: 'AGENTS.md',
|
|
84
|
+
mode: 0o644,
|
|
85
|
+
contentSha256: digest(profileBytes),
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
bytes: Buffer.from('{}'),
|
|
91
|
+
written: ['AGENTS.md'],
|
|
92
|
+
},
|
|
93
|
+
profileActivation: {
|
|
94
|
+
files: [{ path: 'AGENTS.md', mode: 0o644, content: profileBytes.toString('utf8') }],
|
|
95
|
+
},
|
|
96
|
+
materializationReceipt: {
|
|
97
|
+
value: { ...receiptMaterial, digest: receiptDigest },
|
|
98
|
+
bytes: receiptBytes,
|
|
99
|
+
digest: receiptDigest,
|
|
100
|
+
},
|
|
101
|
+
resolvedModel: {
|
|
102
|
+
requested: 'openai/gpt-5.4',
|
|
103
|
+
provider: 'openai',
|
|
104
|
+
model: 'gpt-5.4',
|
|
105
|
+
snapshot: 'gpt-5.4-2026-06-01',
|
|
106
|
+
reasoningEffort: 'xhigh',
|
|
107
|
+
},
|
|
108
|
+
launch: {
|
|
109
|
+
executable: 'python3',
|
|
110
|
+
args: ['/opt/tangle-candidate/runner.py'],
|
|
111
|
+
env: { PUBLIC_MODE: 'fixture' },
|
|
112
|
+
flags: [],
|
|
113
|
+
cwd: '/app',
|
|
114
|
+
},
|
|
115
|
+
memory: { mode: 'disabled' },
|
|
116
|
+
trace: {
|
|
117
|
+
runId: executionId,
|
|
118
|
+
tags: {},
|
|
119
|
+
env: {
|
|
120
|
+
TANGLE_CANDIDATE_EXECUTION_ID: executionId,
|
|
121
|
+
TANGLE_CANDIDATE_BUNDLE_DIGEST: bundleDigest,
|
|
122
|
+
TANGLE_CANDIDATE_EXECUTION_PLAN_DIGEST: planDigest,
|
|
123
|
+
TANGLE_CANDIDATE_MATERIALIZATION_RECEIPT_DIGEST: receiptDigest,
|
|
124
|
+
TANGLE_TRACE_RUN_ID: executionId,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
} as unknown as PreparedAgentCandidateExecution
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function request(execution: PreparedAgentCandidateExecution): AgentCandidateExecutorRequest {
|
|
131
|
+
const taskBytes = Buffer.from('not ready\n')
|
|
132
|
+
const profileBytes = Buffer.from('fixture profile\n')
|
|
133
|
+
return {
|
|
134
|
+
executionId: execution.executionId,
|
|
135
|
+
inputs: {
|
|
136
|
+
task: {
|
|
137
|
+
snapshot: {
|
|
138
|
+
material: {
|
|
139
|
+
files: [
|
|
140
|
+
{
|
|
141
|
+
path: 'src/status.txt',
|
|
142
|
+
mode: 0o644,
|
|
143
|
+
sha256: digest(taskBytes),
|
|
144
|
+
byteLength: taskBytes.byteLength,
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
files: [{ path: 'src/status.txt', mode: 0o644, bytes: taskBytes }],
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
roots: execution.roots.execution,
|
|
153
|
+
profilePlan: execution.profilePlan,
|
|
154
|
+
profileActivation: execution.profileActivation,
|
|
155
|
+
executionPlan: execution.executionPlan,
|
|
156
|
+
materializationReceipt: execution.materializationReceipt,
|
|
157
|
+
launch: {
|
|
158
|
+
...execution.launch,
|
|
159
|
+
env: {
|
|
160
|
+
...execution.launch.env,
|
|
161
|
+
OPENAI_API_KEY: 'evaluator-only',
|
|
162
|
+
...execution.trace.env,
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
instruction: execution.instruction,
|
|
166
|
+
resolvedModel: execution.resolvedModel,
|
|
167
|
+
hardLimits: { timeoutMs: execution.executionPlan.value.material.limits.timeoutMs },
|
|
168
|
+
observedLimits: { maxSteps: execution.executionPlan.value.material.limits.maxSteps },
|
|
169
|
+
trace: execution.trace,
|
|
170
|
+
memory: execution.memory,
|
|
171
|
+
} as unknown as AgentCandidateExecutorRequest
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
test('stages the runtime exact bytes without defining another execution plan', async () => {
|
|
175
|
+
const root = await mkdtemp(join(tmpdir(), 'pier-stage-'))
|
|
176
|
+
try {
|
|
177
|
+
const execution = prepared(root)
|
|
178
|
+
const staged = await stagePreparedPierCandidateExecution(
|
|
179
|
+
{
|
|
180
|
+
prepared: execution,
|
|
181
|
+
directory: join(root, 'sealed'),
|
|
182
|
+
pierVersion: '0.3.0',
|
|
183
|
+
},
|
|
184
|
+
request(execution),
|
|
185
|
+
)
|
|
186
|
+
assert.deepEqual(await readFile(staged.planPath), Buffer.from(execution.executionPlan.bytes))
|
|
187
|
+
assert.deepEqual(
|
|
188
|
+
await readFile(staged.receiptPath),
|
|
189
|
+
Buffer.from(execution.materializationReceipt.bytes),
|
|
190
|
+
)
|
|
191
|
+
assert.equal(
|
|
192
|
+
await readFile(join(staged.taskDirectory, 'src/status.txt'), 'utf8'),
|
|
193
|
+
'not ready\n',
|
|
194
|
+
)
|
|
195
|
+
assert.equal(
|
|
196
|
+
await readFile(join(staged.profileDirectory, 'AGENTS.md'), 'utf8'),
|
|
197
|
+
'fixture profile\n',
|
|
198
|
+
)
|
|
199
|
+
assert.deepEqual(staged.evaluatorEnv, {
|
|
200
|
+
...execution.trace.env,
|
|
201
|
+
OPENAI_API_KEY: 'evaluator-only',
|
|
202
|
+
})
|
|
203
|
+
assert.doesNotMatch(JSON.stringify(execution), /evaluator-only|OPENAI_API_KEY/)
|
|
204
|
+
assert.doesNotMatch(staged.agentArgs.join(' '), /evaluator-only|OPENAI_API_KEY/)
|
|
205
|
+
assert.deepEqual(staged.attemptArgs, ['--n-attempts', '1', '--max-retries', '0'])
|
|
206
|
+
assert.ok(staged.agentArgs.includes('pier_agents.tangle_candidate:TangleCandidateAgent'))
|
|
207
|
+
assert.ok(staged.agentArgs.includes('openai/gpt-5.4'))
|
|
208
|
+
assert.ok(
|
|
209
|
+
staged.agentArgs.includes(
|
|
210
|
+
`expected_receipt_digest=${execution.materializationReceipt.digest}`,
|
|
211
|
+
),
|
|
212
|
+
)
|
|
213
|
+
assert.ok(staged.agentArgs.includes(`task_dir=${staged.taskDirectory}`))
|
|
214
|
+
} finally {
|
|
215
|
+
await rm(root, { recursive: true, force: true })
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
test('reads only identity and termination from Pier, never candidate-authored usage', () => {
|
|
220
|
+
const root = '/tmp/pier-capture-test'
|
|
221
|
+
const execution = prepared(root)
|
|
222
|
+
const metadata = {
|
|
223
|
+
executionId: execution.executionId,
|
|
224
|
+
bundleDigest: execution.bundle.digest,
|
|
225
|
+
executionPlanDigest: execution.executionPlan.value.digest,
|
|
226
|
+
materializationReceiptDigest: execution.materializationReceipt.digest,
|
|
227
|
+
termination: { kind: 'exit', exitCode: 0 },
|
|
228
|
+
}
|
|
229
|
+
const capture = protectedCaptureFromPierResult(request(execution), {
|
|
230
|
+
exception_info: null,
|
|
231
|
+
agent_result: {
|
|
232
|
+
n_input_tokens: 999_999,
|
|
233
|
+
cost_usd: 999_999,
|
|
234
|
+
metadata,
|
|
235
|
+
},
|
|
236
|
+
})
|
|
237
|
+
assert.deepEqual(capture, {
|
|
238
|
+
executionId: execution.executionId,
|
|
239
|
+
termination: { kind: 'exit', exitCode: 0 },
|
|
240
|
+
})
|
|
241
|
+
assert.deepEqual(
|
|
242
|
+
protectedCaptureFromPierResult(request(execution), {
|
|
243
|
+
exception_info: { exception_type: 'AgentTimeoutError' },
|
|
244
|
+
agent_result: { metadata: { ...metadata, termination: { kind: 'cancelled' } } },
|
|
245
|
+
}),
|
|
246
|
+
{
|
|
247
|
+
executionId: execution.executionId,
|
|
248
|
+
termination: { kind: 'timeout', timeoutMs: 60_000 },
|
|
249
|
+
},
|
|
250
|
+
)
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
test('rejects substituted canonical bytes before writing Pier artifacts', async () => {
|
|
254
|
+
const root = await mkdtemp(join(tmpdir(), 'pier-stage-tamper-'))
|
|
255
|
+
try {
|
|
256
|
+
const execution = prepared(root)
|
|
257
|
+
const tampered = {
|
|
258
|
+
...execution,
|
|
259
|
+
executionPlan: { ...execution.executionPlan, bytes: Buffer.from('{}') },
|
|
260
|
+
} as PreparedAgentCandidateExecution
|
|
261
|
+
await assert.rejects(
|
|
262
|
+
stagePreparedPierCandidateExecution(
|
|
263
|
+
{
|
|
264
|
+
prepared: tampered,
|
|
265
|
+
directory: join(root, 'sealed'),
|
|
266
|
+
pierVersion: '0.3.0',
|
|
267
|
+
},
|
|
268
|
+
request(tampered),
|
|
269
|
+
),
|
|
270
|
+
/do not match/,
|
|
271
|
+
)
|
|
272
|
+
} finally {
|
|
273
|
+
await rm(root, { recursive: true, force: true })
|
|
274
|
+
}
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
test('rejects an executor request that changes signed public environment', async () => {
|
|
278
|
+
const root = await mkdtemp(join(tmpdir(), 'pier-stage-env-'))
|
|
279
|
+
try {
|
|
280
|
+
const execution = prepared(root)
|
|
281
|
+
const changed = request(execution)
|
|
282
|
+
;(changed.launch as { env: Record<string, string> }).env.PUBLIC_MODE = 'changed'
|
|
283
|
+
await assert.rejects(
|
|
284
|
+
stagePreparedPierCandidateExecution(
|
|
285
|
+
{
|
|
286
|
+
prepared: execution,
|
|
287
|
+
directory: join(root, 'sealed'),
|
|
288
|
+
pierVersion: '0.3.0',
|
|
289
|
+
},
|
|
290
|
+
changed,
|
|
291
|
+
),
|
|
292
|
+
/changed signed public environment/,
|
|
293
|
+
)
|
|
294
|
+
} finally {
|
|
295
|
+
await rm(root, { recursive: true, force: true })
|
|
296
|
+
}
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
test('rejects changed or escaping executor files before launch', async () => {
|
|
300
|
+
for (const attack of ['bytes', 'path'] as const) {
|
|
301
|
+
const root = await mkdtemp(join(tmpdir(), `pier-stage-${attack}-`))
|
|
302
|
+
try {
|
|
303
|
+
const execution = prepared(root)
|
|
304
|
+
const changed = request(execution)
|
|
305
|
+
const file = changed.inputs.task.files[0] as { path: string; bytes: Uint8Array }
|
|
306
|
+
if (attack === 'bytes') file.bytes = Buffer.from('changed\n')
|
|
307
|
+
else file.path = '../escape'
|
|
308
|
+
await assert.rejects(
|
|
309
|
+
stagePreparedPierCandidateExecution(
|
|
310
|
+
{
|
|
311
|
+
prepared: execution,
|
|
312
|
+
directory: join(root, 'sealed'),
|
|
313
|
+
pierVersion: '0.3.0',
|
|
314
|
+
},
|
|
315
|
+
changed,
|
|
316
|
+
),
|
|
317
|
+
attack === 'bytes' ? /differs from signed evidence/ : /canonical relative POSIX path/,
|
|
318
|
+
)
|
|
319
|
+
} finally {
|
|
320
|
+
await rm(root, { recursive: true, force: true })
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
test('waits for process and container death acknowledgement after abort', async () => {
|
|
326
|
+
const controller = new AbortController()
|
|
327
|
+
let terminated = false
|
|
328
|
+
const waiting = awaitAbortableTrial(
|
|
329
|
+
{
|
|
330
|
+
identity: {
|
|
331
|
+
executionId: 'abort-test',
|
|
332
|
+
executionPlanDigest: `sha256:${'a'.repeat(64)}`,
|
|
333
|
+
},
|
|
334
|
+
result: new Promise(() => undefined),
|
|
335
|
+
terminateAndWait: async () => {
|
|
336
|
+
await new Promise((resolve) => setTimeout(resolve, 5))
|
|
337
|
+
terminated = true
|
|
338
|
+
return { processExited: true, containersRemoved: true }
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
controller.signal,
|
|
342
|
+
)
|
|
343
|
+
controller.abort(new Error('signed deadline elapsed'))
|
|
344
|
+
await assert.rejects(waiting, /signed deadline elapsed/)
|
|
345
|
+
assert.equal(terminated, true)
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
test('fails closed when termination does not acknowledge container removal', async () => {
|
|
349
|
+
const controller = new AbortController()
|
|
350
|
+
const waiting = awaitAbortableTrial(
|
|
351
|
+
{
|
|
352
|
+
identity: {
|
|
353
|
+
executionId: 'bad-ack-test',
|
|
354
|
+
executionPlanDigest: `sha256:${'b'.repeat(64)}`,
|
|
355
|
+
},
|
|
356
|
+
result: new Promise(() => undefined),
|
|
357
|
+
terminateAndWait: async () => ({ processExited: true, containersRemoved: false }) as never,
|
|
358
|
+
},
|
|
359
|
+
controller.signal,
|
|
360
|
+
)
|
|
361
|
+
controller.abort()
|
|
362
|
+
await assert.rejects(waiting, /did not acknowledge/)
|
|
363
|
+
})
|