reeval 0.9.0 → 0.10.0
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/README.md +42 -30
- package/THIRD_PARTY_NOTICES.md +218 -11
- package/assets/package.json +1 -1
- package/assets/pnpm-lock.yaml +30 -30
- package/dist/adapter-DWlpOtRn.js +279 -0
- package/dist/adapter-DWlpOtRn.js.map +1 -0
- package/dist/{agent-6FefIhX7.js → agent-CURAwx_q.js} +6 -6
- package/dist/{agent-6FefIhX7.js.map → agent-CURAwx_q.js.map} +1 -1
- package/dist/{agent-WSmTaesf.js → agent-CaS_2Sce.js} +46 -15
- package/dist/agent-CaS_2Sce.js.map +1 -0
- package/dist/{analysis-DlGBDjTj.js → analysis-Bxub9LMT.js} +4 -4
- package/dist/{analysis-DlGBDjTj.js.map → analysis-Bxub9LMT.js.map} +1 -1
- package/dist/{assemble-BCZzTyR7.js → assemble-B9Alds-z.js} +69 -41
- package/dist/assemble-B9Alds-z.js.map +1 -0
- package/dist/assemble-J5MukZFY.js +1 -0
- package/dist/{client-Bbo9SPlK.js → assert-EUIoRdIt.js} +10 -113
- package/dist/assert-EUIoRdIt.js.map +1 -0
- package/dist/bridge/index.mjs +248 -55
- package/dist/{capture-Bp74Z6Fr.js → capture-CNb9SuU5.js} +145 -31
- package/dist/capture-CNb9SuU5.js.map +1 -0
- package/dist/capture-jquXZBKK.js +1 -0
- package/dist/{cli-CVrMh_qz.js → cli-D303Vj5N.js} +133 -115
- package/dist/cli-D303Vj5N.js.map +1 -0
- package/dist/{cli-spec-CKEYa8V2.js → cli-spec-BPZbQG2p.js} +36 -17
- package/dist/cli-spec-BPZbQG2p.js.map +1 -0
- package/dist/cli.js +4 -2
- package/dist/cli.js.map +1 -1
- package/dist/client-fcwgwOAD.js +106 -0
- package/dist/client-fcwgwOAD.js.map +1 -0
- package/dist/{command-CzIFp1JQ.js → command-BLfT7vnQ.js} +18 -17
- package/dist/command-BLfT7vnQ.js.map +1 -0
- package/dist/{command-C5xFPKHM.js → command-BT9a37ZR.js} +374 -72
- package/dist/command-BT9a37ZR.js.map +1 -0
- package/dist/{command-DUT5l13I.js → command-Bge8F7Ko.js} +316 -83
- package/dist/command-Bge8F7Ko.js.map +1 -0
- package/dist/command-BkFjijN2.js +1 -0
- package/dist/{command-BFP0hKEb.js → command-CMJtHKRa.js} +14 -14
- package/dist/{command-BFP0hKEb.js.map → command-CMJtHKRa.js.map} +1 -1
- package/dist/commands-1p-bIWhN.js +1 -0
- package/dist/{commands-CLmPBrTS.js → commands-BFx16WB8.js} +7 -7
- package/dist/commands-BFx16WB8.js.map +1 -0
- package/dist/config-DEgnUiU-.js +756 -0
- package/dist/config-DEgnUiU-.js.map +1 -0
- package/dist/{context-DbSMEVKs.js → context-C1mxXh80.js} +11 -3
- package/dist/context-C1mxXh80.js.map +1 -0
- package/dist/{db-CfQFwJtq.js → db-CdHizc4_.js} +455 -36
- package/dist/db-CdHizc4_.js.map +1 -0
- package/dist/db-Dm1cRJJP.js +2 -0
- package/dist/debug-D7bEv_UV.js +1 -0
- package/dist/{dist-CTzThfu_.js → dist-B8hJImYt.js} +17 -4
- package/dist/dist-B8hJImYt.js.map +1 -0
- package/dist/{docker-CRQGQbIt.js → docker-7b_2SaH7.js} +22 -21
- package/dist/docker-7b_2SaH7.js.map +1 -0
- package/dist/{docker-DV2GNgle.js → docker-sZrNrr82.js} +3 -3
- package/dist/docker-sZrNrr82.js.map +1 -0
- package/dist/docker-yauK-9X8.js +1 -0
- package/dist/{doctor-DlKycx5H.js → doctor-BYNok4UO.js} +262 -83
- package/dist/doctor-BYNok4UO.js.map +1 -0
- package/dist/{duration-JsJrIWXq.js → duration-CEOQww97.js} +2 -2
- package/dist/{duration-JsJrIWXq.js.map → duration-CEOQww97.js.map} +1 -1
- package/dist/{egress-BhzNh7Yi.js → egress-C4PZTSSe.js} +146 -14
- package/dist/egress-C4PZTSSe.js.map +1 -0
- package/dist/environment-DNjRk0nU.js +1133 -0
- package/dist/environment-DNjRk0nU.js.map +1 -0
- package/dist/{errors-yDAEwmZo.js → errors-B6BSMs03.js} +2 -2
- package/dist/errors-B6BSMs03.js.map +1 -0
- package/dist/{errors-C9w_ud7g.js → errors-r025B0Zb.js} +4 -4
- package/dist/errors-r025B0Zb.js.map +1 -0
- package/dist/evaluate-C1UVL21l.d.ts +92 -0
- package/dist/evaluate-D4zeRGBF.js +2351 -0
- package/dist/evaluate-D4zeRGBF.js.map +1 -0
- package/dist/files-BAt0i00X.js +1 -0
- package/dist/{files-CSzVADHn.js → files-BXUdY8tr.js} +9 -8
- package/dist/{files-CSzVADHn.js.map → files-BXUdY8tr.js.map} +1 -1
- package/dist/files-BhyltlDB.js +1 -0
- package/dist/files-Bk1mC3AN.js +43 -0
- package/dist/files-Bk1mC3AN.js.map +1 -0
- package/dist/{files-DJUFg-4e.js → files-DQmHE7pb.js} +5 -5
- package/dist/{files-DJUFg-4e.js.map → files-DQmHE7pb.js.map} +1 -1
- package/dist/files-ZZPqfAo6.js +1 -0
- package/dist/harness-B8QC9u0O.js +323 -0
- package/dist/harness-B8QC9u0O.js.map +1 -0
- package/dist/harness.d.ts +16 -30
- package/dist/harness.js +1 -2
- package/dist/{header-CALhmafp.js → header-hK-Z_Po9.js} +2 -2
- package/dist/{header-CALhmafp.js.map → header-hK-Z_Po9.js.map} +1 -1
- package/dist/{images-BMgdpMAX.js → images-0On0cztu.js} +114 -45
- package/dist/images-0On0cztu.js.map +1 -0
- package/dist/index.d.ts +9 -37
- package/dist/index.js +6 -2138
- package/dist/{init-BIdLF0F9.js → init-B77Rpcqc.js} +26 -8
- package/dist/init-B77Rpcqc.js.map +1 -0
- package/dist/init-BrOWin3W.js +1 -0
- package/dist/{invocations-CLaL8AuW.js → invocations-DbGfBAA_.js} +4 -4
- package/dist/{invocations-CLaL8AuW.js.map → invocations-DbGfBAA_.js.map} +1 -1
- package/dist/{judge-CeYPN8P_.js → judge-DW_GDOmB.js} +11 -19
- package/dist/{judge-CeYPN8P_.js.map → judge-DW_GDOmB.js.map} +1 -1
- package/dist/judge.d.ts +2 -2
- package/dist/judge.js +1 -1
- package/dist/{live-S0qODb6o.js → live-jlfszAbb.js} +9 -20
- package/dist/live-jlfszAbb.js.map +1 -0
- package/dist/matchers-Ddmc2z7H.js +118 -0
- package/dist/matchers-Ddmc2z7H.js.map +1 -0
- package/dist/{model-DEQo3FkZ.js → model-DaVCY3rb.js} +2 -2
- package/dist/{model-DEQo3FkZ.js.map → model-DaVCY3rb.js.map} +1 -1
- package/dist/model-NM3ID0uR.js +1 -0
- package/dist/{model-B1BZoZ9b.js → model-h_cDtcRr.js} +18 -17
- package/dist/model-h_cDtcRr.js.map +1 -0
- package/dist/model-nwWJvaUR.js +1 -0
- package/dist/{model-BOnlAPzs.js → model-oqcDplJG.js} +111 -19
- package/dist/model-oqcDplJG.js.map +1 -0
- package/dist/{node-Co7EXge0.js → node-B3ydHo6t.js} +10 -47
- package/dist/node-B3ydHo6t.js.map +1 -0
- package/dist/object-CLf2-tNq.js +9 -0
- package/dist/object-CLf2-tNq.js.map +1 -0
- package/dist/{opencode-providers-ByD85Q0l.js → opencode-providers-J9colP0-.js} +96 -21
- package/dist/opencode-providers-J9colP0-.js.map +1 -0
- package/dist/options-Bh2W63dK.js +1119 -0
- package/dist/options-Bh2W63dK.js.map +1 -0
- package/dist/{pairs-DDsjgm5F.js → pairs-CnInRu-G.js} +76 -2
- package/dist/{pairs-DDsjgm5F.js.map → pairs-CnInRu-G.js.map} +1 -1
- package/dist/{patch-bDV8YFW0.js → patch-Zac5aIRM.js} +6 -6
- package/dist/{patch-bDV8YFW0.js.map → patch-Zac5aIRM.js.map} +1 -1
- package/dist/{plan-DUydFc_1.js → plan-C9Cy27Ay.js} +24 -9
- package/dist/plan-C9Cy27Ay.js.map +1 -0
- package/dist/preflight-CPWpQeBI.js +1 -0
- package/dist/{preflight-BkoSxf4C.js → preflight-D7iFPKeK.js} +8 -7
- package/dist/preflight-D7iFPKeK.js.map +1 -0
- package/dist/prepare-BGjePFQl.js +2 -0
- package/dist/{prepare-CUAWHebF.js → prepare-doGxaAGR.js} +38 -30
- package/dist/prepare-doGxaAGR.js.map +1 -0
- package/dist/{provenance-D7HK3vzt.js → provenance-DmE9uPVt.js} +3 -3
- package/dist/{provenance-D7HK3vzt.js.map → provenance-DmE9uPVt.js.map} +1 -1
- package/dist/provider-DehR4CMN.js +1 -0
- package/dist/providers-gDMko8fl.js +1 -0
- package/dist/providers-tAOD1NQN.js +165 -0
- package/dist/providers-tAOD1NQN.js.map +1 -0
- package/dist/{query-BjBMLa-C.js → query-Bes9Kh6Y.js} +3 -3
- package/dist/{query-BjBMLa-C.js.map → query-Bes9Kh6Y.js.map} +1 -1
- package/dist/query-C_G_svLU.js +1 -0
- package/dist/questions-DjAwMxZ3.js +524 -0
- package/dist/questions-DjAwMxZ3.js.map +1 -0
- package/dist/{record-BRP9vZrj.js → record-BKmMvZ6O.js} +9 -1
- package/dist/{record-BRP9vZrj.js.map → record-BKmMvZ6O.js.map} +1 -1
- package/dist/remote-HDRt16ew.js +378 -0
- package/dist/remote-HDRt16ew.js.map +1 -0
- package/dist/{results-Di7m8dQ3.js → results-DuauQI3Z.js} +4 -4
- package/dist/{results-Di7m8dQ3.js.map → results-DuauQI3Z.js.map} +1 -1
- package/dist/{resume-SUz1GskV.js → resume-BRfa8E_s.js} +10 -10
- package/dist/{resume-SUz1GskV.js.map → resume-BRfa8E_s.js.map} +1 -1
- package/dist/{root-CvdRlRZX.js → root-DICDHCtp.js} +4 -4
- package/dist/{root-CvdRlRZX.js.map → root-DICDHCtp.js.map} +1 -1
- package/dist/{runtime-DdsfnRz_.js → runtime-PX_oXiCS.js} +23 -71
- package/dist/runtime-PX_oXiCS.js.map +1 -0
- package/dist/sandbox-D3A8oUb7.js +70 -0
- package/dist/sandbox-D3A8oUb7.js.map +1 -0
- package/dist/sandbox.d.ts +19 -6
- package/dist/sandbox.js +1 -2
- package/dist/server-C7sg1ndo.js +1 -0
- package/dist/{server-BNnXtmS8.js → server-XDleKaF_.js} +11 -11
- package/dist/server-XDleKaF_.js.map +1 -0
- package/dist/shared-DYpIb1BI.js +166 -0
- package/dist/shared-DYpIb1BI.js.map +1 -0
- package/dist/{source-Dof0NQBm.js → source-C8xumIWj.js} +2 -2
- package/dist/{source-Dof0NQBm.js.map → source-C8xumIWj.js.map} +1 -1
- package/dist/source-fGd0SaKP.js +1 -0
- package/dist/{src-8rRXy4u9.js → src-B7treWa8.js} +1538 -180
- package/dist/src-B7treWa8.js.map +1 -0
- package/dist/{src-C1E9HDWO.js → src-C7_1SqDP.js} +3 -3
- package/dist/{src-C1E9HDWO.js.map → src-C7_1SqDP.js.map} +1 -1
- package/dist/{src-DDNXsD9H.js → src-CF17Ug08.js} +5 -4
- package/dist/src-CF17Ug08.js.map +1 -0
- package/dist/{src-C_4Umgh2.js → src-CFp86GtV.js} +52 -51
- package/dist/src-CFp86GtV.js.map +1 -0
- package/dist/src-C_lPtowT.js +2 -0
- package/dist/src-DIL0jST0.js +368 -0
- package/dist/src-DIL0jST0.js.map +1 -0
- package/dist/src-DNnG4e4R.js +2 -0
- package/dist/src-DTbrY1hi.js +2 -0
- package/dist/src-DdyJEh2v.js +2 -0
- package/dist/src-Dj9PAroc.js +2 -0
- package/dist/src-Du8H85Qq.js +2 -0
- package/dist/src-DvCg0NBs.js +324 -0
- package/dist/src-DvCg0NBs.js.map +1 -0
- package/dist/{src-COgE7991.js → src-DvK0EIZx.js} +5 -5
- package/dist/{src-COgE7991.js.map → src-DvK0EIZx.js.map} +1 -1
- package/dist/{src-DVy58-zZ.js → src-FGXhkEkH.js} +5 -5
- package/dist/{src-DVy58-zZ.js.map → src-FGXhkEkH.js.map} +1 -1
- package/dist/src-jzagbuqH.js +2 -0
- package/dist/src-ofUaYbuY.js +3 -0
- package/dist/src-pJZOrYR9.js +1 -0
- package/dist/{src-D95O-Smv.js → src-u8_ixn_F.js} +15 -11
- package/dist/src-u8_ixn_F.js.map +1 -0
- package/dist/{state-CiXyLqg0.js → state-C__9swoG.js} +35 -23
- package/dist/state-C__9swoG.js.map +1 -0
- package/dist/state-CeR6oz0k.js +66 -0
- package/dist/state-CeR6oz0k.js.map +1 -0
- package/dist/state-CgjQo29K.js +1 -0
- package/dist/studio-app/assets/index-CwQN3f_h.css +2 -0
- package/dist/studio-app/assets/{index-CROH2NB3.js → index-DrQc2Yxd.js} +11 -11
- package/dist/studio-app/index.html +2 -2
- package/dist/{summary-BTksrIxn.js → summary-BLAVLySU.js} +150 -19
- package/dist/summary-BLAVLySU.js.map +1 -0
- package/dist/{summary-2OAWF2N7.js → summary-DgyjUh_l.js} +7 -7
- package/dist/{summary-2OAWF2N7.js.map → summary-DgyjUh_l.js.map} +1 -1
- package/dist/testing.d.ts +3 -2
- package/dist/testing.js +3 -2
- package/dist/{tool-target-BU1JnSE9.js → tool-target-D2mcYlSQ.js} +14 -7
- package/dist/tool-target-D2mcYlSQ.js.map +1 -0
- package/dist/{tools-B10Uj7OI.js → tools-GCyNYSc1.js} +6 -6
- package/dist/tools-GCyNYSc1.js.map +1 -0
- package/dist/transcript-BNNANU8A.js +64 -0
- package/dist/transcript-BNNANU8A.js.map +1 -0
- package/dist/{types-D8RLfkFP.d.ts → types-g17bRAzt.d.ts} +389 -42
- package/dist/{usage-DDF_6tkV.js → usage-CleNKkly.js} +4 -2
- package/dist/{usage-DDF_6tkV.js.map → usage-CleNKkly.js.map} +1 -1
- package/dist/view/index.d.ts +42 -8
- package/dist/view/index.js +6 -6
- package/dist/views-BW6oCDUQ.js +2 -0
- package/dist/{views-Dqa5ojfZ.js → views-BmQF4UCI.js} +13 -8
- package/dist/views-BmQF4UCI.js.map +1 -0
- package/dist/{worker-entry-BAikHl9F.js → worker-entry-yOchGYYv.js} +16 -229
- package/dist/worker-entry-yOchGYYv.js.map +1 -0
- package/dist/{workspace-C-TrNIUc.js → workspace-CgyHEM0l.js} +6 -6
- package/dist/{workspace-C-TrNIUc.js.map → workspace-CgyHEM0l.js.map} +1 -1
- package/dist/workspace-D8sSgpiy.js +1 -0
- package/package.json +12 -12
- package/dist/agent-WSmTaesf.js.map +0 -1
- package/dist/assemble-BCZzTyR7.js.map +0 -1
- package/dist/assemble-C5qq5yT2.js +0 -2
- package/dist/capture-Bp74Z6Fr.js.map +0 -1
- package/dist/capture-DS-cPyuE.js +0 -2
- package/dist/cli-CVrMh_qz.js.map +0 -1
- package/dist/cli-spec-CKEYa8V2.js.map +0 -1
- package/dist/client-Bbo9SPlK.js.map +0 -1
- package/dist/command-BrmXUC-W.js +0 -2
- package/dist/command-C5xFPKHM.js.map +0 -1
- package/dist/command-CzIFp1JQ.js.map +0 -1
- package/dist/command-DUT5l13I.js.map +0 -1
- package/dist/commands-CLmPBrTS.js.map +0 -1
- package/dist/commands-fI3G2Wnh.js +0 -2
- package/dist/config-CGvBeewH.js +0 -457
- package/dist/config-CGvBeewH.js.map +0 -1
- package/dist/context-DbSMEVKs.js.map +0 -1
- package/dist/db-CSSFtGcN.js +0 -3
- package/dist/db-CfQFwJtq.js.map +0 -1
- package/dist/debug-SEmW4w8f.js +0 -2
- package/dist/dist-CTzThfu_.js.map +0 -1
- package/dist/docker-CRQGQbIt.js.map +0 -1
- package/dist/docker-DV2GNgle.js.map +0 -1
- package/dist/docker-Df_YOxxB.js +0 -2
- package/dist/doctor-DlKycx5H.js.map +0 -1
- package/dist/egress-BhzNh7Yi.js.map +0 -1
- package/dist/environment-1jE-HhO-.js +0 -657
- package/dist/environment-1jE-HhO-.js.map +0 -1
- package/dist/errors-C9w_ud7g.js.map +0 -1
- package/dist/errors-yDAEwmZo.js.map +0 -1
- package/dist/fake-instructions-CUI33I_F.js +0 -32
- package/dist/fake-instructions-CUI33I_F.js.map +0 -1
- package/dist/files-AiEKuEZe.js +0 -2
- package/dist/files-BM78_nnF.js +0 -2
- package/dist/files-BMCvfB4X.js +0 -2
- package/dist/harness-CeCp2GSW.js +0 -171
- package/dist/harness-CeCp2GSW.js.map +0 -1
- package/dist/images-BMgdpMAX.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/init-B6vegaP_.js +0 -2
- package/dist/init-BIdLF0F9.js.map +0 -1
- package/dist/jiti-BcJHCtrb.js +0 -46
- package/dist/jiti-BcJHCtrb.js.map +0 -1
- package/dist/live-S0qODb6o.js.map +0 -1
- package/dist/model-B1BZoZ9b.js.map +0 -1
- package/dist/model-BOnlAPzs.js.map +0 -1
- package/dist/model-DWeg5J7z.js +0 -2
- package/dist/model-FXko2kl7.js +0 -2
- package/dist/node-Co7EXge0.js.map +0 -1
- package/dist/opencode-providers-ByD85Q0l.js.map +0 -1
- package/dist/options-CKqyPGxX.js +0 -739
- package/dist/options-CKqyPGxX.js.map +0 -1
- package/dist/plan-DUydFc_1.js.map +0 -1
- package/dist/preflight-BkoSxf4C.js.map +0 -1
- package/dist/preflight-D5LW7Oqi.js +0 -2
- package/dist/prepare-CUAWHebF.js.map +0 -1
- package/dist/prepare-oji2oO8W.js +0 -3
- package/dist/provider-BDbNOQhQ.js +0 -2
- package/dist/providers-B1DzMvmH.js +0 -107
- package/dist/providers-B1DzMvmH.js.map +0 -1
- package/dist/providers-CpEfNU1F.js +0 -2
- package/dist/query-oPO_XrTy.js +0 -2
- package/dist/questions-B8by4Bbt.js +0 -234
- package/dist/questions-B8by4Bbt.js.map +0 -1
- package/dist/runtime-DdsfnRz_.js.map +0 -1
- package/dist/sandbox-D5v-of6d.js +0 -139
- package/dist/sandbox-D5v-of6d.js.map +0 -1
- package/dist/server-BNnXtmS8.js.map +0 -1
- package/dist/server-BNwoKzlm.js +0 -2
- package/dist/source-Bk_0ZaEY.js +0 -2
- package/dist/src-8rRXy4u9.js.map +0 -1
- package/dist/src-BGWuWp6I.js +0 -3
- package/dist/src-BRt0O02i.js +0 -3
- package/dist/src-Bx2x1ekD.js +0 -3
- package/dist/src-C_4Umgh2.js.map +0 -1
- package/dist/src-D95O-Smv.js.map +0 -1
- package/dist/src-DDNXsD9H.js.map +0 -1
- package/dist/src-DLa-ESW0.js +0 -4
- package/dist/src-cN0aB-WR.js +0 -3
- package/dist/src-cdIVjC5b.js +0 -2
- package/dist/src-sIsDHWYq.js +0 -3
- package/dist/state-Bo5zg4da.js +0 -2
- package/dist/state-CiXyLqg0.js.map +0 -1
- package/dist/studio-app/assets/index-B9MCTfuu.css +0 -2
- package/dist/summary-BTksrIxn.js.map +0 -1
- package/dist/tool-target-BU1JnSE9.js.map +0 -1
- package/dist/tools-B10Uj7OI.js.map +0 -1
- package/dist/views-Cs2Oqayd.js +0 -3
- package/dist/views-Dqa5ojfZ.js.map +0 -1
- package/dist/worker-entry-BAikHl9F.js.map +0 -1
- package/dist/workspace-Do_SiWBs.js +0 -2
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { u as ownFileURL } from "./root-
|
|
1
|
+
import { u as ownFileURL } from "./root-DICDHCtp.js";
|
|
2
2
|
import { n as shellQuote, t as run } from "./process-CSVO_jsc.js";
|
|
3
|
-
import { existsSync, lstatSync, readFileSync, readdirSync, readlinkSync } from "node:fs";
|
|
3
|
+
import { existsSync, lstatSync, readFileSync, readdirSync, readlinkSync, renameSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
4
5
|
import { basename, dirname, join, posix, relative } from "node:path";
|
|
5
6
|
import net, { BlockList, isIP } from "node:net";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { createHash, generateKeyPairSync, randomBytes, randomInt, sign } from "node:crypto";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
8
10
|
import { createHarnessSandboxTemplate } from "@ai-sdk/harness/agent";
|
|
9
|
-
import { spawn } from "node:child_process";
|
|
10
11
|
import { isUtf8 } from "node:buffer";
|
|
11
12
|
import { Duplex, Readable, Transform } from "node:stream";
|
|
12
13
|
import http from "node:http";
|
|
@@ -14,6 +15,1073 @@ import http2 from "node:http2";
|
|
|
14
15
|
import https from "node:https";
|
|
15
16
|
import tls from "node:tls";
|
|
16
17
|
import { lookup } from "node:dns/promises";
|
|
18
|
+
//#region ../sandbox-docker/src/seccomp-profile.ts
|
|
19
|
+
const DOCKER_SECCOMP_PROFILE = {
|
|
20
|
+
defaultAction: "SCMP_ACT_ERRNO",
|
|
21
|
+
defaultErrnoRet: 1,
|
|
22
|
+
archMap: [
|
|
23
|
+
{
|
|
24
|
+
architecture: "SCMP_ARCH_X86_64",
|
|
25
|
+
subArchitectures: ["SCMP_ARCH_X86", "SCMP_ARCH_X32"]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
architecture: "SCMP_ARCH_AARCH64",
|
|
29
|
+
subArchitectures: ["SCMP_ARCH_ARM"]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
architecture: "SCMP_ARCH_MIPS64",
|
|
33
|
+
subArchitectures: ["SCMP_ARCH_MIPS", "SCMP_ARCH_MIPS64N32"]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
architecture: "SCMP_ARCH_MIPS64N32",
|
|
37
|
+
subArchitectures: ["SCMP_ARCH_MIPS", "SCMP_ARCH_MIPS64"]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
architecture: "SCMP_ARCH_MIPSEL64",
|
|
41
|
+
subArchitectures: ["SCMP_ARCH_MIPSEL", "SCMP_ARCH_MIPSEL64N32"]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
architecture: "SCMP_ARCH_MIPSEL64N32",
|
|
45
|
+
subArchitectures: ["SCMP_ARCH_MIPSEL", "SCMP_ARCH_MIPSEL64"]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
architecture: "SCMP_ARCH_S390X",
|
|
49
|
+
subArchitectures: ["SCMP_ARCH_S390"]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
architecture: "SCMP_ARCH_RISCV64",
|
|
53
|
+
subArchitectures: null
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
architecture: "SCMP_ARCH_LOONGARCH64",
|
|
57
|
+
subArchitectures: null
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
syscalls: [
|
|
61
|
+
{
|
|
62
|
+
names: [
|
|
63
|
+
"accept",
|
|
64
|
+
"accept4",
|
|
65
|
+
"access",
|
|
66
|
+
"adjtimex",
|
|
67
|
+
"alarm",
|
|
68
|
+
"bind",
|
|
69
|
+
"brk",
|
|
70
|
+
"cachestat",
|
|
71
|
+
"capget",
|
|
72
|
+
"capset",
|
|
73
|
+
"chdir",
|
|
74
|
+
"chmod",
|
|
75
|
+
"chown",
|
|
76
|
+
"chown32",
|
|
77
|
+
"clock_adjtime",
|
|
78
|
+
"clock_adjtime64",
|
|
79
|
+
"clock_getres",
|
|
80
|
+
"clock_getres_time64",
|
|
81
|
+
"clock_gettime",
|
|
82
|
+
"clock_gettime64",
|
|
83
|
+
"clock_nanosleep",
|
|
84
|
+
"clock_nanosleep_time64",
|
|
85
|
+
"close",
|
|
86
|
+
"close_range",
|
|
87
|
+
"connect",
|
|
88
|
+
"copy_file_range",
|
|
89
|
+
"creat",
|
|
90
|
+
"dup",
|
|
91
|
+
"dup2",
|
|
92
|
+
"dup3",
|
|
93
|
+
"epoll_create",
|
|
94
|
+
"epoll_create1",
|
|
95
|
+
"epoll_ctl",
|
|
96
|
+
"epoll_ctl_old",
|
|
97
|
+
"epoll_pwait",
|
|
98
|
+
"epoll_pwait2",
|
|
99
|
+
"epoll_wait",
|
|
100
|
+
"epoll_wait_old",
|
|
101
|
+
"eventfd",
|
|
102
|
+
"eventfd2",
|
|
103
|
+
"execve",
|
|
104
|
+
"execveat",
|
|
105
|
+
"exit",
|
|
106
|
+
"exit_group",
|
|
107
|
+
"faccessat",
|
|
108
|
+
"faccessat2",
|
|
109
|
+
"fadvise64",
|
|
110
|
+
"fadvise64_64",
|
|
111
|
+
"fallocate",
|
|
112
|
+
"fanotify_mark",
|
|
113
|
+
"fchdir",
|
|
114
|
+
"fchmod",
|
|
115
|
+
"fchmodat",
|
|
116
|
+
"fchmodat2",
|
|
117
|
+
"fchown",
|
|
118
|
+
"fchown32",
|
|
119
|
+
"fchownat",
|
|
120
|
+
"fcntl",
|
|
121
|
+
"fcntl64",
|
|
122
|
+
"fdatasync",
|
|
123
|
+
"fgetxattr",
|
|
124
|
+
"flistxattr",
|
|
125
|
+
"flock",
|
|
126
|
+
"fork",
|
|
127
|
+
"fremovexattr",
|
|
128
|
+
"fsetxattr",
|
|
129
|
+
"fstat",
|
|
130
|
+
"fstat64",
|
|
131
|
+
"fstatat64",
|
|
132
|
+
"fstatfs",
|
|
133
|
+
"fstatfs64",
|
|
134
|
+
"fsync",
|
|
135
|
+
"ftruncate",
|
|
136
|
+
"ftruncate64",
|
|
137
|
+
"futex",
|
|
138
|
+
"futex_requeue",
|
|
139
|
+
"futex_time64",
|
|
140
|
+
"futex_wait",
|
|
141
|
+
"futex_waitv",
|
|
142
|
+
"futex_wake",
|
|
143
|
+
"futimesat",
|
|
144
|
+
"getcpu",
|
|
145
|
+
"getcwd",
|
|
146
|
+
"getdents",
|
|
147
|
+
"getdents64",
|
|
148
|
+
"getegid",
|
|
149
|
+
"getegid32",
|
|
150
|
+
"geteuid",
|
|
151
|
+
"geteuid32",
|
|
152
|
+
"getgid",
|
|
153
|
+
"getgid32",
|
|
154
|
+
"getgroups",
|
|
155
|
+
"getgroups32",
|
|
156
|
+
"getitimer",
|
|
157
|
+
"getpeername",
|
|
158
|
+
"getpgid",
|
|
159
|
+
"getpgrp",
|
|
160
|
+
"getpid",
|
|
161
|
+
"getppid",
|
|
162
|
+
"getpriority",
|
|
163
|
+
"getrandom",
|
|
164
|
+
"getresgid",
|
|
165
|
+
"getresgid32",
|
|
166
|
+
"getresuid",
|
|
167
|
+
"getresuid32",
|
|
168
|
+
"getrlimit",
|
|
169
|
+
"get_robust_list",
|
|
170
|
+
"getrusage",
|
|
171
|
+
"getsid",
|
|
172
|
+
"getsockname",
|
|
173
|
+
"getsockopt",
|
|
174
|
+
"get_thread_area",
|
|
175
|
+
"gettid",
|
|
176
|
+
"gettimeofday",
|
|
177
|
+
"getuid",
|
|
178
|
+
"getuid32",
|
|
179
|
+
"getxattr",
|
|
180
|
+
"getxattrat",
|
|
181
|
+
"inotify_add_watch",
|
|
182
|
+
"inotify_init",
|
|
183
|
+
"inotify_init1",
|
|
184
|
+
"inotify_rm_watch",
|
|
185
|
+
"io_cancel",
|
|
186
|
+
"ioctl",
|
|
187
|
+
"io_destroy",
|
|
188
|
+
"io_getevents",
|
|
189
|
+
"io_pgetevents",
|
|
190
|
+
"io_pgetevents_time64",
|
|
191
|
+
"ioprio_get",
|
|
192
|
+
"ioprio_set",
|
|
193
|
+
"io_setup",
|
|
194
|
+
"io_submit",
|
|
195
|
+
"ipc",
|
|
196
|
+
"kill",
|
|
197
|
+
"landlock_add_rule",
|
|
198
|
+
"landlock_create_ruleset",
|
|
199
|
+
"landlock_restrict_self",
|
|
200
|
+
"lchown",
|
|
201
|
+
"lchown32",
|
|
202
|
+
"lgetxattr",
|
|
203
|
+
"link",
|
|
204
|
+
"linkat",
|
|
205
|
+
"listen",
|
|
206
|
+
"listmount",
|
|
207
|
+
"listxattr",
|
|
208
|
+
"listxattrat",
|
|
209
|
+
"llistxattr",
|
|
210
|
+
"_llseek",
|
|
211
|
+
"lremovexattr",
|
|
212
|
+
"lseek",
|
|
213
|
+
"lsetxattr",
|
|
214
|
+
"lstat",
|
|
215
|
+
"lstat64",
|
|
216
|
+
"madvise",
|
|
217
|
+
"map_shadow_stack",
|
|
218
|
+
"membarrier",
|
|
219
|
+
"memfd_create",
|
|
220
|
+
"memfd_secret",
|
|
221
|
+
"mincore",
|
|
222
|
+
"mkdir",
|
|
223
|
+
"mkdirat",
|
|
224
|
+
"mknod",
|
|
225
|
+
"mknodat",
|
|
226
|
+
"mlock",
|
|
227
|
+
"mlock2",
|
|
228
|
+
"mlockall",
|
|
229
|
+
"mmap",
|
|
230
|
+
"mmap2",
|
|
231
|
+
"mprotect",
|
|
232
|
+
"mq_getsetattr",
|
|
233
|
+
"mq_notify",
|
|
234
|
+
"mq_open",
|
|
235
|
+
"mq_timedreceive",
|
|
236
|
+
"mq_timedreceive_time64",
|
|
237
|
+
"mq_timedsend",
|
|
238
|
+
"mq_timedsend_time64",
|
|
239
|
+
"mq_unlink",
|
|
240
|
+
"mremap",
|
|
241
|
+
"mseal",
|
|
242
|
+
"msgctl",
|
|
243
|
+
"msgget",
|
|
244
|
+
"msgrcv",
|
|
245
|
+
"msgsnd",
|
|
246
|
+
"msync",
|
|
247
|
+
"munlock",
|
|
248
|
+
"munlockall",
|
|
249
|
+
"munmap",
|
|
250
|
+
"name_to_handle_at",
|
|
251
|
+
"nanosleep",
|
|
252
|
+
"newfstatat",
|
|
253
|
+
"_newselect",
|
|
254
|
+
"open",
|
|
255
|
+
"openat",
|
|
256
|
+
"openat2",
|
|
257
|
+
"pause",
|
|
258
|
+
"pidfd_open",
|
|
259
|
+
"pidfd_send_signal",
|
|
260
|
+
"pipe",
|
|
261
|
+
"pipe2",
|
|
262
|
+
"pkey_alloc",
|
|
263
|
+
"pkey_free",
|
|
264
|
+
"pkey_mprotect",
|
|
265
|
+
"poll",
|
|
266
|
+
"ppoll",
|
|
267
|
+
"ppoll_time64",
|
|
268
|
+
"prctl",
|
|
269
|
+
"pread64",
|
|
270
|
+
"preadv",
|
|
271
|
+
"preadv2",
|
|
272
|
+
"prlimit64",
|
|
273
|
+
"process_mrelease",
|
|
274
|
+
"pselect6",
|
|
275
|
+
"pselect6_time64",
|
|
276
|
+
"pwrite64",
|
|
277
|
+
"pwritev",
|
|
278
|
+
"pwritev2",
|
|
279
|
+
"read",
|
|
280
|
+
"readahead",
|
|
281
|
+
"readlink",
|
|
282
|
+
"readlinkat",
|
|
283
|
+
"readv",
|
|
284
|
+
"recv",
|
|
285
|
+
"recvfrom",
|
|
286
|
+
"recvmmsg",
|
|
287
|
+
"recvmmsg_time64",
|
|
288
|
+
"recvmsg",
|
|
289
|
+
"remap_file_pages",
|
|
290
|
+
"removexattr",
|
|
291
|
+
"removexattrat",
|
|
292
|
+
"rename",
|
|
293
|
+
"renameat",
|
|
294
|
+
"renameat2",
|
|
295
|
+
"restart_syscall",
|
|
296
|
+
"riscv_hwprobe",
|
|
297
|
+
"rmdir",
|
|
298
|
+
"rseq",
|
|
299
|
+
"rt_sigaction",
|
|
300
|
+
"rt_sigpending",
|
|
301
|
+
"rt_sigprocmask",
|
|
302
|
+
"rt_sigqueueinfo",
|
|
303
|
+
"rt_sigreturn",
|
|
304
|
+
"rt_sigsuspend",
|
|
305
|
+
"rt_sigtimedwait",
|
|
306
|
+
"rt_sigtimedwait_time64",
|
|
307
|
+
"rt_tgsigqueueinfo",
|
|
308
|
+
"sched_getaffinity",
|
|
309
|
+
"sched_getattr",
|
|
310
|
+
"sched_getparam",
|
|
311
|
+
"sched_get_priority_max",
|
|
312
|
+
"sched_get_priority_min",
|
|
313
|
+
"sched_getscheduler",
|
|
314
|
+
"sched_rr_get_interval",
|
|
315
|
+
"sched_rr_get_interval_time64",
|
|
316
|
+
"sched_setaffinity",
|
|
317
|
+
"sched_setattr",
|
|
318
|
+
"sched_setparam",
|
|
319
|
+
"sched_setscheduler",
|
|
320
|
+
"sched_yield",
|
|
321
|
+
"seccomp",
|
|
322
|
+
"select",
|
|
323
|
+
"semctl",
|
|
324
|
+
"semget",
|
|
325
|
+
"semop",
|
|
326
|
+
"semtimedop",
|
|
327
|
+
"semtimedop_time64",
|
|
328
|
+
"send",
|
|
329
|
+
"sendfile",
|
|
330
|
+
"sendfile64",
|
|
331
|
+
"sendmmsg",
|
|
332
|
+
"sendmsg",
|
|
333
|
+
"sendto",
|
|
334
|
+
"setfsgid",
|
|
335
|
+
"setfsgid32",
|
|
336
|
+
"setfsuid",
|
|
337
|
+
"setfsuid32",
|
|
338
|
+
"setgid",
|
|
339
|
+
"setgid32",
|
|
340
|
+
"setgroups",
|
|
341
|
+
"setgroups32",
|
|
342
|
+
"setitimer",
|
|
343
|
+
"setpgid",
|
|
344
|
+
"setpriority",
|
|
345
|
+
"setregid",
|
|
346
|
+
"setregid32",
|
|
347
|
+
"setresgid",
|
|
348
|
+
"setresgid32",
|
|
349
|
+
"setresuid",
|
|
350
|
+
"setresuid32",
|
|
351
|
+
"setreuid",
|
|
352
|
+
"setreuid32",
|
|
353
|
+
"setrlimit",
|
|
354
|
+
"set_robust_list",
|
|
355
|
+
"setsid",
|
|
356
|
+
"setsockopt",
|
|
357
|
+
"set_thread_area",
|
|
358
|
+
"set_tid_address",
|
|
359
|
+
"setuid",
|
|
360
|
+
"setuid32",
|
|
361
|
+
"setxattr",
|
|
362
|
+
"setxattrat",
|
|
363
|
+
"shmat",
|
|
364
|
+
"shmctl",
|
|
365
|
+
"shmdt",
|
|
366
|
+
"shmget",
|
|
367
|
+
"shutdown",
|
|
368
|
+
"sigaltstack",
|
|
369
|
+
"signalfd",
|
|
370
|
+
"signalfd4",
|
|
371
|
+
"sigprocmask",
|
|
372
|
+
"sigreturn",
|
|
373
|
+
"socketcall",
|
|
374
|
+
"socketpair",
|
|
375
|
+
"splice",
|
|
376
|
+
"stat",
|
|
377
|
+
"stat64",
|
|
378
|
+
"statfs",
|
|
379
|
+
"statfs64",
|
|
380
|
+
"statmount",
|
|
381
|
+
"statx",
|
|
382
|
+
"symlink",
|
|
383
|
+
"symlinkat",
|
|
384
|
+
"sync",
|
|
385
|
+
"sync_file_range",
|
|
386
|
+
"syncfs",
|
|
387
|
+
"sysinfo",
|
|
388
|
+
"tee",
|
|
389
|
+
"tgkill",
|
|
390
|
+
"time",
|
|
391
|
+
"timer_create",
|
|
392
|
+
"timer_delete",
|
|
393
|
+
"timer_getoverrun",
|
|
394
|
+
"timer_gettime",
|
|
395
|
+
"timer_gettime64",
|
|
396
|
+
"timer_settime",
|
|
397
|
+
"timer_settime64",
|
|
398
|
+
"timerfd_create",
|
|
399
|
+
"timerfd_gettime",
|
|
400
|
+
"timerfd_gettime64",
|
|
401
|
+
"timerfd_settime",
|
|
402
|
+
"timerfd_settime64",
|
|
403
|
+
"times",
|
|
404
|
+
"tkill",
|
|
405
|
+
"truncate",
|
|
406
|
+
"truncate64",
|
|
407
|
+
"ugetrlimit",
|
|
408
|
+
"umask",
|
|
409
|
+
"uname",
|
|
410
|
+
"unlink",
|
|
411
|
+
"unlinkat",
|
|
412
|
+
"uretprobe",
|
|
413
|
+
"utime",
|
|
414
|
+
"utimensat",
|
|
415
|
+
"utimensat_time64",
|
|
416
|
+
"utimes",
|
|
417
|
+
"vfork",
|
|
418
|
+
"vmsplice",
|
|
419
|
+
"wait4",
|
|
420
|
+
"waitid",
|
|
421
|
+
"waitpid",
|
|
422
|
+
"write",
|
|
423
|
+
"writev"
|
|
424
|
+
],
|
|
425
|
+
action: "SCMP_ACT_ALLOW"
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
names: [
|
|
429
|
+
"process_vm_readv",
|
|
430
|
+
"process_vm_writev",
|
|
431
|
+
"ptrace"
|
|
432
|
+
],
|
|
433
|
+
action: "SCMP_ACT_ALLOW",
|
|
434
|
+
includes: { minKernel: "4.8" }
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
names: ["socket"],
|
|
438
|
+
action: "SCMP_ACT_ALLOW",
|
|
439
|
+
args: [{
|
|
440
|
+
index: 0,
|
|
441
|
+
value: 3,
|
|
442
|
+
op: "SCMP_CMP_LT"
|
|
443
|
+
}]
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
names: ["socket"],
|
|
447
|
+
action: "SCMP_ACT_ALLOW",
|
|
448
|
+
args: [{
|
|
449
|
+
index: 0,
|
|
450
|
+
value: 7,
|
|
451
|
+
op: "SCMP_CMP_EQ"
|
|
452
|
+
}]
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
names: ["socket"],
|
|
456
|
+
action: "SCMP_ACT_ALLOW",
|
|
457
|
+
args: [{
|
|
458
|
+
index: 0,
|
|
459
|
+
value: 8,
|
|
460
|
+
op: "SCMP_CMP_EQ"
|
|
461
|
+
}]
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
names: ["socket"],
|
|
465
|
+
action: "SCMP_ACT_ALLOW",
|
|
466
|
+
args: [{
|
|
467
|
+
index: 0,
|
|
468
|
+
value: 9,
|
|
469
|
+
op: "SCMP_CMP_EQ"
|
|
470
|
+
}]
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
names: ["socket"],
|
|
474
|
+
action: "SCMP_ACT_ALLOW",
|
|
475
|
+
args: [{
|
|
476
|
+
index: 0,
|
|
477
|
+
value: 10,
|
|
478
|
+
op: "SCMP_CMP_EQ"
|
|
479
|
+
}]
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
names: ["socket"],
|
|
483
|
+
action: "SCMP_ACT_ALLOW",
|
|
484
|
+
args: [{
|
|
485
|
+
index: 0,
|
|
486
|
+
value: 13,
|
|
487
|
+
op: "SCMP_CMP_EQ"
|
|
488
|
+
}]
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
names: ["socket"],
|
|
492
|
+
action: "SCMP_ACT_ALLOW",
|
|
493
|
+
args: [{
|
|
494
|
+
index: 0,
|
|
495
|
+
value: 14,
|
|
496
|
+
op: "SCMP_CMP_EQ"
|
|
497
|
+
}]
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
names: ["socket"],
|
|
501
|
+
action: "SCMP_ACT_ALLOW",
|
|
502
|
+
args: [{
|
|
503
|
+
index: 0,
|
|
504
|
+
value: 15,
|
|
505
|
+
op: "SCMP_CMP_EQ"
|
|
506
|
+
}]
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
names: ["socket"],
|
|
510
|
+
action: "SCMP_ACT_ALLOW",
|
|
511
|
+
args: [{
|
|
512
|
+
index: 0,
|
|
513
|
+
value: 16,
|
|
514
|
+
op: "SCMP_CMP_EQ"
|
|
515
|
+
}]
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
names: ["socket"],
|
|
519
|
+
action: "SCMP_ACT_ALLOW",
|
|
520
|
+
args: [{
|
|
521
|
+
index: 0,
|
|
522
|
+
value: 17,
|
|
523
|
+
op: "SCMP_CMP_EQ"
|
|
524
|
+
}]
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
names: ["socket"],
|
|
528
|
+
action: "SCMP_ACT_ALLOW",
|
|
529
|
+
args: [{
|
|
530
|
+
index: 0,
|
|
531
|
+
value: 18,
|
|
532
|
+
op: "SCMP_CMP_EQ"
|
|
533
|
+
}]
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
names: ["socket"],
|
|
537
|
+
action: "SCMP_ACT_ALLOW",
|
|
538
|
+
args: [{
|
|
539
|
+
index: 0,
|
|
540
|
+
value: 21,
|
|
541
|
+
op: "SCMP_CMP_EQ"
|
|
542
|
+
}]
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
names: ["socket"],
|
|
546
|
+
action: "SCMP_ACT_ALLOW",
|
|
547
|
+
args: [{
|
|
548
|
+
index: 0,
|
|
549
|
+
value: 22,
|
|
550
|
+
op: "SCMP_CMP_EQ"
|
|
551
|
+
}]
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
names: ["socket"],
|
|
555
|
+
action: "SCMP_ACT_ALLOW",
|
|
556
|
+
args: [{
|
|
557
|
+
index: 0,
|
|
558
|
+
value: 24,
|
|
559
|
+
op: "SCMP_CMP_EQ"
|
|
560
|
+
}]
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
names: ["socket"],
|
|
564
|
+
action: "SCMP_ACT_ALLOW",
|
|
565
|
+
args: [{
|
|
566
|
+
index: 0,
|
|
567
|
+
value: 26,
|
|
568
|
+
op: "SCMP_CMP_EQ"
|
|
569
|
+
}]
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
names: ["socket"],
|
|
573
|
+
action: "SCMP_ACT_ALLOW",
|
|
574
|
+
args: [{
|
|
575
|
+
index: 0,
|
|
576
|
+
value: 27,
|
|
577
|
+
op: "SCMP_CMP_EQ"
|
|
578
|
+
}]
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
names: ["socket"],
|
|
582
|
+
action: "SCMP_ACT_ALLOW",
|
|
583
|
+
args: [{
|
|
584
|
+
index: 0,
|
|
585
|
+
value: 28,
|
|
586
|
+
op: "SCMP_CMP_EQ"
|
|
587
|
+
}]
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
names: ["socket"],
|
|
591
|
+
action: "SCMP_ACT_ALLOW",
|
|
592
|
+
args: [{
|
|
593
|
+
index: 0,
|
|
594
|
+
value: 29,
|
|
595
|
+
op: "SCMP_CMP_EQ"
|
|
596
|
+
}]
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
names: ["socket"],
|
|
600
|
+
action: "SCMP_ACT_ALLOW",
|
|
601
|
+
args: [{
|
|
602
|
+
index: 0,
|
|
603
|
+
value: 30,
|
|
604
|
+
op: "SCMP_CMP_EQ"
|
|
605
|
+
}]
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
names: ["socket"],
|
|
609
|
+
action: "SCMP_ACT_ALLOW",
|
|
610
|
+
args: [{
|
|
611
|
+
index: 0,
|
|
612
|
+
value: 31,
|
|
613
|
+
op: "SCMP_CMP_EQ"
|
|
614
|
+
}]
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
names: ["socket"],
|
|
618
|
+
action: "SCMP_ACT_ALLOW",
|
|
619
|
+
args: [{
|
|
620
|
+
index: 0,
|
|
621
|
+
value: 32,
|
|
622
|
+
op: "SCMP_CMP_EQ"
|
|
623
|
+
}]
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
names: ["socket"],
|
|
627
|
+
action: "SCMP_ACT_ALLOW",
|
|
628
|
+
args: [{
|
|
629
|
+
index: 0,
|
|
630
|
+
value: 33,
|
|
631
|
+
op: "SCMP_CMP_EQ"
|
|
632
|
+
}]
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
names: ["socket"],
|
|
636
|
+
action: "SCMP_ACT_ALLOW",
|
|
637
|
+
args: [{
|
|
638
|
+
index: 0,
|
|
639
|
+
value: 35,
|
|
640
|
+
op: "SCMP_CMP_EQ"
|
|
641
|
+
}]
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
names: ["socket"],
|
|
645
|
+
action: "SCMP_ACT_ALLOW",
|
|
646
|
+
args: [{
|
|
647
|
+
index: 0,
|
|
648
|
+
value: 36,
|
|
649
|
+
op: "SCMP_CMP_EQ"
|
|
650
|
+
}]
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
names: ["socket"],
|
|
654
|
+
action: "SCMP_ACT_ALLOW",
|
|
655
|
+
args: [{
|
|
656
|
+
index: 0,
|
|
657
|
+
value: 39,
|
|
658
|
+
op: "SCMP_CMP_EQ"
|
|
659
|
+
}]
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
names: ["socket"],
|
|
663
|
+
action: "SCMP_ACT_ALLOW",
|
|
664
|
+
args: [{
|
|
665
|
+
index: 0,
|
|
666
|
+
value: 41,
|
|
667
|
+
op: "SCMP_CMP_EQ"
|
|
668
|
+
}]
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
names: ["socket"],
|
|
672
|
+
action: "SCMP_ACT_ALLOW",
|
|
673
|
+
args: [{
|
|
674
|
+
index: 0,
|
|
675
|
+
value: 42,
|
|
676
|
+
op: "SCMP_CMP_EQ"
|
|
677
|
+
}]
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
names: ["socket"],
|
|
681
|
+
action: "SCMP_ACT_ALLOW",
|
|
682
|
+
args: [{
|
|
683
|
+
index: 0,
|
|
684
|
+
value: 43,
|
|
685
|
+
op: "SCMP_CMP_EQ"
|
|
686
|
+
}]
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
names: ["socket"],
|
|
690
|
+
action: "SCMP_ACT_ALLOW",
|
|
691
|
+
args: [{
|
|
692
|
+
index: 0,
|
|
693
|
+
value: 44,
|
|
694
|
+
op: "SCMP_CMP_EQ"
|
|
695
|
+
}]
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
names: ["socket"],
|
|
699
|
+
action: "SCMP_ACT_ALLOW",
|
|
700
|
+
args: [{
|
|
701
|
+
index: 0,
|
|
702
|
+
value: 45,
|
|
703
|
+
op: "SCMP_CMP_EQ"
|
|
704
|
+
}]
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
names: ["personality"],
|
|
708
|
+
action: "SCMP_ACT_ALLOW",
|
|
709
|
+
args: [{
|
|
710
|
+
index: 0,
|
|
711
|
+
value: 0,
|
|
712
|
+
op: "SCMP_CMP_EQ"
|
|
713
|
+
}]
|
|
714
|
+
},
|
|
715
|
+
{
|
|
716
|
+
names: ["personality"],
|
|
717
|
+
action: "SCMP_ACT_ALLOW",
|
|
718
|
+
args: [{
|
|
719
|
+
index: 0,
|
|
720
|
+
value: 8,
|
|
721
|
+
op: "SCMP_CMP_EQ"
|
|
722
|
+
}]
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
names: ["personality"],
|
|
726
|
+
action: "SCMP_ACT_ALLOW",
|
|
727
|
+
args: [{
|
|
728
|
+
index: 0,
|
|
729
|
+
value: 131072,
|
|
730
|
+
op: "SCMP_CMP_EQ"
|
|
731
|
+
}]
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
names: ["personality"],
|
|
735
|
+
action: "SCMP_ACT_ALLOW",
|
|
736
|
+
args: [{
|
|
737
|
+
index: 0,
|
|
738
|
+
value: 131080,
|
|
739
|
+
op: "SCMP_CMP_EQ"
|
|
740
|
+
}]
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
names: ["personality"],
|
|
744
|
+
action: "SCMP_ACT_ALLOW",
|
|
745
|
+
args: [{
|
|
746
|
+
index: 0,
|
|
747
|
+
value: 4294967295,
|
|
748
|
+
op: "SCMP_CMP_EQ"
|
|
749
|
+
}]
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
names: ["sync_file_range2", "swapcontext"],
|
|
753
|
+
action: "SCMP_ACT_ALLOW",
|
|
754
|
+
includes: { arches: ["ppc64le"] }
|
|
755
|
+
},
|
|
756
|
+
{
|
|
757
|
+
names: [
|
|
758
|
+
"arm_fadvise64_64",
|
|
759
|
+
"arm_sync_file_range",
|
|
760
|
+
"sync_file_range2",
|
|
761
|
+
"breakpoint",
|
|
762
|
+
"cacheflush",
|
|
763
|
+
"set_tls"
|
|
764
|
+
],
|
|
765
|
+
action: "SCMP_ACT_ALLOW",
|
|
766
|
+
includes: { arches: ["arm", "arm64"] }
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
names: ["arch_prctl"],
|
|
770
|
+
action: "SCMP_ACT_ALLOW",
|
|
771
|
+
includes: { arches: ["amd64", "x32"] }
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
names: ["modify_ldt"],
|
|
775
|
+
action: "SCMP_ACT_ALLOW",
|
|
776
|
+
includes: { arches: [
|
|
777
|
+
"amd64",
|
|
778
|
+
"x32",
|
|
779
|
+
"x86"
|
|
780
|
+
] }
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
names: [
|
|
784
|
+
"s390_pci_mmio_read",
|
|
785
|
+
"s390_pci_mmio_write",
|
|
786
|
+
"s390_runtime_instr"
|
|
787
|
+
],
|
|
788
|
+
action: "SCMP_ACT_ALLOW",
|
|
789
|
+
includes: { arches: ["s390", "s390x"] }
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
names: ["riscv_flush_icache"],
|
|
793
|
+
action: "SCMP_ACT_ALLOW",
|
|
794
|
+
includes: { arches: ["riscv64"] }
|
|
795
|
+
},
|
|
796
|
+
{
|
|
797
|
+
names: ["open_by_handle_at"],
|
|
798
|
+
action: "SCMP_ACT_ALLOW",
|
|
799
|
+
includes: { caps: ["CAP_DAC_READ_SEARCH"] }
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
names: [
|
|
803
|
+
"bpf",
|
|
804
|
+
"clone",
|
|
805
|
+
"clone3",
|
|
806
|
+
"fanotify_init",
|
|
807
|
+
"fsconfig",
|
|
808
|
+
"fsmount",
|
|
809
|
+
"fsopen",
|
|
810
|
+
"fspick",
|
|
811
|
+
"lookup_dcookie",
|
|
812
|
+
"lsm_get_self_attr",
|
|
813
|
+
"lsm_list_modules",
|
|
814
|
+
"lsm_set_self_attr",
|
|
815
|
+
"mount",
|
|
816
|
+
"mount_setattr",
|
|
817
|
+
"move_mount",
|
|
818
|
+
"open_tree",
|
|
819
|
+
"perf_event_open",
|
|
820
|
+
"quotactl",
|
|
821
|
+
"quotactl_fd",
|
|
822
|
+
"setdomainname",
|
|
823
|
+
"sethostname",
|
|
824
|
+
"setns",
|
|
825
|
+
"syslog",
|
|
826
|
+
"umount",
|
|
827
|
+
"umount2",
|
|
828
|
+
"unshare"
|
|
829
|
+
],
|
|
830
|
+
action: "SCMP_ACT_ALLOW",
|
|
831
|
+
includes: { caps: ["CAP_SYS_ADMIN"] }
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
names: ["clone"],
|
|
835
|
+
action: "SCMP_ACT_ALLOW",
|
|
836
|
+
args: [{
|
|
837
|
+
index: 0,
|
|
838
|
+
value: 2114060288,
|
|
839
|
+
op: "SCMP_CMP_MASKED_EQ"
|
|
840
|
+
}],
|
|
841
|
+
excludes: {
|
|
842
|
+
caps: ["CAP_SYS_ADMIN"],
|
|
843
|
+
arches: ["s390", "s390x"]
|
|
844
|
+
}
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
names: ["clone"],
|
|
848
|
+
action: "SCMP_ACT_ALLOW",
|
|
849
|
+
args: [{
|
|
850
|
+
index: 1,
|
|
851
|
+
value: 2114060288,
|
|
852
|
+
op: "SCMP_CMP_MASKED_EQ"
|
|
853
|
+
}],
|
|
854
|
+
comment: "s390 parameter ordering for clone is different",
|
|
855
|
+
includes: { arches: ["s390", "s390x"] },
|
|
856
|
+
excludes: { caps: ["CAP_SYS_ADMIN"] }
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
names: ["clone3"],
|
|
860
|
+
action: "SCMP_ACT_ERRNO",
|
|
861
|
+
errnoRet: 38,
|
|
862
|
+
excludes: { caps: ["CAP_SYS_ADMIN"] }
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
names: ["reboot"],
|
|
866
|
+
action: "SCMP_ACT_ALLOW",
|
|
867
|
+
includes: { caps: ["CAP_SYS_BOOT"] }
|
|
868
|
+
},
|
|
869
|
+
{
|
|
870
|
+
names: ["chroot"],
|
|
871
|
+
action: "SCMP_ACT_ALLOW",
|
|
872
|
+
includes: { caps: ["CAP_SYS_CHROOT"] }
|
|
873
|
+
},
|
|
874
|
+
{
|
|
875
|
+
names: [
|
|
876
|
+
"delete_module",
|
|
877
|
+
"init_module",
|
|
878
|
+
"finit_module"
|
|
879
|
+
],
|
|
880
|
+
action: "SCMP_ACT_ALLOW",
|
|
881
|
+
includes: { caps: ["CAP_SYS_MODULE"] }
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
names: ["acct"],
|
|
885
|
+
action: "SCMP_ACT_ALLOW",
|
|
886
|
+
includes: { caps: ["CAP_SYS_PACCT"] }
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
names: [
|
|
890
|
+
"kcmp",
|
|
891
|
+
"pidfd_getfd",
|
|
892
|
+
"process_madvise",
|
|
893
|
+
"process_vm_readv",
|
|
894
|
+
"process_vm_writev",
|
|
895
|
+
"ptrace"
|
|
896
|
+
],
|
|
897
|
+
action: "SCMP_ACT_ALLOW",
|
|
898
|
+
includes: { caps: ["CAP_SYS_PTRACE"] }
|
|
899
|
+
},
|
|
900
|
+
{
|
|
901
|
+
names: ["iopl", "ioperm"],
|
|
902
|
+
action: "SCMP_ACT_ALLOW",
|
|
903
|
+
includes: { caps: ["CAP_SYS_RAWIO"] }
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
names: [
|
|
907
|
+
"settimeofday",
|
|
908
|
+
"stime",
|
|
909
|
+
"clock_settime",
|
|
910
|
+
"clock_settime64"
|
|
911
|
+
],
|
|
912
|
+
action: "SCMP_ACT_ALLOW",
|
|
913
|
+
includes: { caps: ["CAP_SYS_TIME"] }
|
|
914
|
+
},
|
|
915
|
+
{
|
|
916
|
+
names: ["vhangup"],
|
|
917
|
+
action: "SCMP_ACT_ALLOW",
|
|
918
|
+
includes: { caps: ["CAP_SYS_TTY_CONFIG"] }
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
names: [
|
|
922
|
+
"get_mempolicy",
|
|
923
|
+
"mbind",
|
|
924
|
+
"set_mempolicy",
|
|
925
|
+
"set_mempolicy_home_node"
|
|
926
|
+
],
|
|
927
|
+
action: "SCMP_ACT_ALLOW",
|
|
928
|
+
includes: { caps: ["CAP_SYS_NICE"] }
|
|
929
|
+
},
|
|
930
|
+
{
|
|
931
|
+
names: ["syslog"],
|
|
932
|
+
action: "SCMP_ACT_ALLOW",
|
|
933
|
+
includes: { caps: ["CAP_SYSLOG"] }
|
|
934
|
+
},
|
|
935
|
+
{
|
|
936
|
+
names: ["bpf"],
|
|
937
|
+
action: "SCMP_ACT_ALLOW",
|
|
938
|
+
includes: { caps: ["CAP_BPF"] }
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
names: ["perf_event_open"],
|
|
942
|
+
action: "SCMP_ACT_ALLOW",
|
|
943
|
+
includes: { caps: ["CAP_PERFMON"] }
|
|
944
|
+
}
|
|
945
|
+
]
|
|
946
|
+
};
|
|
947
|
+
//#endregion
|
|
948
|
+
//#region ../sandbox-docker/src/engine.ts
|
|
949
|
+
let seccompFile;
|
|
950
|
+
/**
|
|
951
|
+
* Docker's default seccomp profile as a file Podman can read, written once per content under the
|
|
952
|
+
* temp directory (a compiled reeval has no real file of its own to point at).
|
|
953
|
+
*/
|
|
954
|
+
function dockerSeccompFile() {
|
|
955
|
+
if (seccompFile && existsSync(seccompFile)) return seccompFile;
|
|
956
|
+
const json = JSON.stringify(DOCKER_SECCOMP_PROFILE);
|
|
957
|
+
const hash = createHash("sha256").update(json).digest("hex").slice(0, 16);
|
|
958
|
+
const path = join(tmpdir(), `reeval-seccomp-${hash}.json`);
|
|
959
|
+
if (!existsSync(path)) {
|
|
960
|
+
const partial = `${path}.${process.pid}.tmp`;
|
|
961
|
+
writeFileSync(partial, json);
|
|
962
|
+
renameSync(partial, path);
|
|
963
|
+
}
|
|
964
|
+
seccompFile = path;
|
|
965
|
+
return path;
|
|
966
|
+
}
|
|
967
|
+
const ENGINES = {
|
|
968
|
+
docker: {
|
|
969
|
+
bin: "docker",
|
|
970
|
+
name: "Docker",
|
|
971
|
+
fn: "docker",
|
|
972
|
+
stateFormat: "{{.ServerVersion}} {{.OSType}}",
|
|
973
|
+
capacityFormat: "{{.NCPU}} {{.MemTotal}}",
|
|
974
|
+
imageId: ".Id",
|
|
975
|
+
rmForce: ["rm", "-f"],
|
|
976
|
+
runArgs: () => [],
|
|
977
|
+
createsWorkdir: true
|
|
978
|
+
},
|
|
979
|
+
podman: {
|
|
980
|
+
bin: "podman",
|
|
981
|
+
name: "Podman",
|
|
982
|
+
fn: "podman",
|
|
983
|
+
stateFormat: "{{.Version.Version}} {{.Host.OS}}",
|
|
984
|
+
capacityFormat: "{{.Host.CPUs}} {{.Host.MemTotal}}",
|
|
985
|
+
imageId: ".ID",
|
|
986
|
+
rmForce: [
|
|
987
|
+
"rm",
|
|
988
|
+
"-f",
|
|
989
|
+
"--time",
|
|
990
|
+
"0"
|
|
991
|
+
],
|
|
992
|
+
runArgs: () => [
|
|
993
|
+
"--network",
|
|
994
|
+
"bridge",
|
|
995
|
+
"--security-opt",
|
|
996
|
+
`seccomp=${dockerSeccompFile()}`
|
|
997
|
+
],
|
|
998
|
+
createsWorkdir: false
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
const engineSpec = (engine = "docker") => ENGINES[engine];
|
|
1002
|
+
/**
|
|
1003
|
+
* The `CONTAINER_HOST` that reaches a `podman machine` straight through its API socket (macOS) or
|
|
1004
|
+
* named pipe (Windows), from `podman machine inspect`'s JSON.
|
|
1005
|
+
*/
|
|
1006
|
+
function machineHost(inspect, platform) {
|
|
1007
|
+
const machine = Array.isArray(inspect) ? inspect[0] : void 0;
|
|
1008
|
+
const info = machine?.ConnectionInfo;
|
|
1009
|
+
const name = machine?.Name ?? "podman-machine-default";
|
|
1010
|
+
if (platform === "darwin" && info?.PodmanSocket?.Path) {
|
|
1011
|
+
const path = info.PodmanSocket.Path;
|
|
1012
|
+
return {
|
|
1013
|
+
host: `unix://${path}`,
|
|
1014
|
+
path,
|
|
1015
|
+
name
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
if (platform === "win32" && info?.PodmanPipe?.Path) {
|
|
1019
|
+
const path = info.PodmanPipe.Path;
|
|
1020
|
+
return {
|
|
1021
|
+
host: `npipe://${path.replaceAll("\\", "/")}`,
|
|
1022
|
+
path,
|
|
1023
|
+
name
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
return null;
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* The environment every podman command gets. On macOS and Windows the client talks to the
|
|
1030
|
+
* machine's VM over SSH, a connection per command, and sshd's `MaxStartups` drops some of a burst
|
|
1031
|
+
* (exit 125, `ssh: handshake failed`), so commands go through the machine's API socket instead.
|
|
1032
|
+
* Not when the user picked a host (`CONTAINER_HOST`, `CONTAINER_CONNECTION`, or a default
|
|
1033
|
+
* connection that isn't the machine's), or the socket isn't there.
|
|
1034
|
+
*/
|
|
1035
|
+
function podmanHostEnv(inputs) {
|
|
1036
|
+
const { platform, env } = inputs;
|
|
1037
|
+
if (platform !== "darwin" && platform !== "win32") return {};
|
|
1038
|
+
if (env.CONTAINER_HOST || env.CONTAINER_CONNECTION) return {};
|
|
1039
|
+
const machine = machineHost(inputs.inspect(), platform);
|
|
1040
|
+
if (!machine || !inputs.exists(machine.path)) return {};
|
|
1041
|
+
const connections = inputs.connections();
|
|
1042
|
+
const chosen = Array.isArray(connections) ? connections.find((c) => c.Default)?.Name : void 0;
|
|
1043
|
+
if (chosen && chosen !== machine.name && chosen !== `${machine.name}-root`) return {};
|
|
1044
|
+
return { CONTAINER_HOST: machine.host };
|
|
1045
|
+
}
|
|
1046
|
+
const readJson = (bin, args) => {
|
|
1047
|
+
try {
|
|
1048
|
+
const out = execFileSync(bin, args, {
|
|
1049
|
+
encoding: "utf8",
|
|
1050
|
+
stdio: [
|
|
1051
|
+
"ignore",
|
|
1052
|
+
"pipe",
|
|
1053
|
+
"ignore"
|
|
1054
|
+
],
|
|
1055
|
+
timeout: 1e4,
|
|
1056
|
+
windowsHide: true
|
|
1057
|
+
});
|
|
1058
|
+
return JSON.parse(out);
|
|
1059
|
+
} catch {
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
1063
|
+
let podmanEnv;
|
|
1064
|
+
/** What every command on `engine` adds to its environment; read once per process. */
|
|
1065
|
+
function engineEnv(engine = "docker") {
|
|
1066
|
+
if (engine !== "podman") return {};
|
|
1067
|
+
podmanEnv ??= podmanHostEnv({
|
|
1068
|
+
platform: process.platform,
|
|
1069
|
+
env: process.env,
|
|
1070
|
+
inspect: () => readJson("podman", ["machine", "inspect"]),
|
|
1071
|
+
connections: () => readJson("podman", [
|
|
1072
|
+
"system",
|
|
1073
|
+
"connection",
|
|
1074
|
+
"list",
|
|
1075
|
+
"--format",
|
|
1076
|
+
"json"
|
|
1077
|
+
]),
|
|
1078
|
+
exists: existsSync
|
|
1079
|
+
});
|
|
1080
|
+
return podmanEnv;
|
|
1081
|
+
}
|
|
1082
|
+
/** Docker's ids are `sha256:…`; Podman's are the bare hex. */
|
|
1083
|
+
const normalizeImageId = (id) => id.includes(":") ? id : `sha256:${id}`;
|
|
1084
|
+
//#endregion
|
|
17
1085
|
//#region ../sandbox-docker/src/build-failure.ts
|
|
18
1086
|
var ImageBuildError = class extends Error {
|
|
19
1087
|
name = "ImageBuildError";
|
|
@@ -27,6 +1095,7 @@ const stripAnsi = (text) => text.replace(/\x1b\[[0-9;]*[A-Za-z]/g, "");
|
|
|
27
1095
|
/** The failing step and its output from `--progress plain` build output. */
|
|
28
1096
|
function parseBuildOutput(text) {
|
|
29
1097
|
const lines = stripAnsi(text).split(/\r?\n/);
|
|
1098
|
+
if (!lines.some((l) => /^(?:#\d+ )?ERROR: /.test(l)) && lines.some((l) => l.startsWith("Error: "))) return parseBuildahOutput(lines);
|
|
30
1099
|
let step = null;
|
|
31
1100
|
let error = null;
|
|
32
1101
|
for (const line of lines) {
|
|
@@ -47,14 +1116,35 @@ function parseBuildOutput(text) {
|
|
|
47
1116
|
exitCode: code ? Number(code) : null
|
|
48
1117
|
};
|
|
49
1118
|
}
|
|
1119
|
+
/**
|
|
1120
|
+
* buildah's output (`podman build`): `STEP n/m: …` headers, each step's output as is, then
|
|
1121
|
+
* `Error: building at STEP "…": …`. Its own warnings are `time="…" level=…` lines.
|
|
1122
|
+
*/
|
|
1123
|
+
function parseBuildahOutput(lines) {
|
|
1124
|
+
let error = null;
|
|
1125
|
+
let output = [];
|
|
1126
|
+
for (const line of lines) if (/^STEP \d+\/\d+: /.test(line)) output = [];
|
|
1127
|
+
else if (line.startsWith("Error: ")) error = line.slice(7);
|
|
1128
|
+
else if (!error && line.trim() && !/^time="[^"]*" level=|^--> /.test(line)) output.push(line);
|
|
1129
|
+
error = (error ?? "").replace(/^building at STEP "(?:[^"\\]|\\.)*": /, "").replace(/ &imagebuilder\.Step\{.*$/, "").trim() || null;
|
|
1130
|
+
const code = /exit status (\d+)$/.exec(error ?? "")?.[1];
|
|
1131
|
+
return {
|
|
1132
|
+
error,
|
|
1133
|
+
output: output.slice(-8),
|
|
1134
|
+
exitCode: code ? Number(code) : null
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
50
1137
|
/** ENOSPC or a SIGKILL (137, usually the out-of-memory killer), from anything the build printed. */
|
|
51
1138
|
function failureCause(text, exitCode) {
|
|
52
1139
|
if (/no space left on device|ENOSPC/i.test(text)) return "enospc";
|
|
53
|
-
if (exitCode === 137 || /exit(?:ed| code
|
|
1140
|
+
if (exitCode === 137 || /exit(?:ed| code:?| status) 137\b|signal: killed|OOMKilled/i.test(text)) return "oom";
|
|
54
1141
|
return null;
|
|
55
1142
|
}
|
|
56
|
-
const causeLine = (cause
|
|
57
|
-
const
|
|
1143
|
+
const causeLine = (cause, engine) => {
|
|
1144
|
+
const { name, bin } = engineSpec(engine);
|
|
1145
|
+
return cause === "enospc" ? `out of disk space (ENOSPC): free space for ${name} (${bin} system df, reeval clean --images) and rerun` : `killed (exit 137): usually out of memory; give ${name} more memory or lower the concurrency`;
|
|
1146
|
+
};
|
|
1147
|
+
const DETERMINISTIC = /did not complete successfully|while running runtime: exit status|did not resolve to an alias|requested access to the resource is denied|dockerfile parse error|unknown instruction|should not be blank|pull access denied|repository does not exist|manifest unknown|not found: manifest|: not found\b|unauthorized|denied:|reeval needs a Debian or Ubuntu based image/i;
|
|
58
1148
|
const TRANSIENT = /EAI_AGAIN|ECONNRESET|ETIMEDOUT|ECONNREFUSED|i\/o timeout|TLS handshake timeout|no such host|temporary failure in name resolution|connection reset by peer|dial tcp|net\/http: request canceled|unexpected EOF|\b(?:500|502|503|504) |429 Too Many Requests|toomanyrequests|Service Unavailable|Bad Gateway|Gateway Timeout|ENOTFOUND/i;
|
|
59
1149
|
/** A registry or network error: a pull, a metadata lookup, or a download in the harness bootstrap. */
|
|
60
1150
|
const isTransient = (text) => !DETERMINISTIC.test(text) && TRANSIENT.test(text);
|
|
@@ -77,7 +1167,7 @@ const RETRY_DELAYS = [2e3, 8e3];
|
|
|
77
1167
|
*/
|
|
78
1168
|
function failureMessage(parts) {
|
|
79
1169
|
const lines = [parts.headline];
|
|
80
|
-
if (parts.cause) lines.push(causeLine(parts.cause));
|
|
1170
|
+
if (parts.cause) lines.push(causeLine(parts.cause, parts.engine));
|
|
81
1171
|
if (parts.output.length) lines.push(...parts.output.map((l) => ` | ${l}`));
|
|
82
1172
|
if (parts.log) lines.push(`(full log: ${parts.log})`);
|
|
83
1173
|
return lines.join("\n");
|
|
@@ -104,9 +1194,10 @@ function streamPreview(data) {
|
|
|
104
1194
|
if (data.includes(0) || !isUtf8(data)) return `<${data.length} bytes>`;
|
|
105
1195
|
return clip(data.toString("utf8"), MAX_STREAM);
|
|
106
1196
|
}
|
|
107
|
-
function traceDocker(args, startedAt, result) {
|
|
1197
|
+
function traceDocker(args, startedAt, result, bin = "docker") {
|
|
108
1198
|
if (!listener) return;
|
|
109
1199
|
const base = {
|
|
1200
|
+
bin,
|
|
110
1201
|
args: args.map((a) => clip(a, MAX_ARG)),
|
|
111
1202
|
ms: Date.now() - startedAt
|
|
112
1203
|
};
|
|
@@ -133,107 +1224,199 @@ function traceDocker(args, startedAt, result) {
|
|
|
133
1224
|
}
|
|
134
1225
|
//#endregion
|
|
135
1226
|
//#region ../sandbox-docker/src/docker-cli.ts
|
|
136
|
-
/**
|
|
1227
|
+
/** How long to wait before each retry of a command that never reached Podman. */
|
|
1228
|
+
const CONNECTION_RETRY_MS = [
|
|
1229
|
+
100,
|
|
1230
|
+
250,
|
|
1231
|
+
500,
|
|
1232
|
+
1e3,
|
|
1233
|
+
2e3
|
|
1234
|
+
];
|
|
1235
|
+
/**
|
|
1236
|
+
* Whether a podman command failed before reaching the engine: the remote client's SSH handshake
|
|
1237
|
+
* or socket connection to `podman machine`, so running it again is safe.
|
|
1238
|
+
*/
|
|
1239
|
+
const isConnectionFailure = (r) => r.exitCode === 125 && /ssh: handshake failed|unable to connect to Podman socket/.test(r.stderr);
|
|
1240
|
+
const sleep = (ms, signal) => new Promise((resolve) => {
|
|
1241
|
+
const timer = setTimeout(done, ms);
|
|
1242
|
+
function done() {
|
|
1243
|
+
clearTimeout(timer);
|
|
1244
|
+
signal?.removeEventListener("abort", done);
|
|
1245
|
+
resolve();
|
|
1246
|
+
}
|
|
1247
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
1248
|
+
});
|
|
1249
|
+
/**
|
|
1250
|
+
* Runs `attempt` again, after each of `delays`, while its result is a connection failure (see
|
|
1251
|
+
* {@link isConnectionFailure}), and returns the last result.
|
|
1252
|
+
*/
|
|
1253
|
+
async function retryConnection(attempt, options = {}) {
|
|
1254
|
+
const { delays = CONNECTION_RETRY_MS, signal, wait = sleep } = options;
|
|
1255
|
+
let r = await attempt();
|
|
1256
|
+
for (const ms of delays) {
|
|
1257
|
+
if (!isConnectionFailure(r) || signal?.aborted) break;
|
|
1258
|
+
await wait(ms, signal);
|
|
1259
|
+
r = await attempt();
|
|
1260
|
+
}
|
|
1261
|
+
return r;
|
|
1262
|
+
}
|
|
1263
|
+
/** Runs the docker (or podman) CLI. `env` values are passed via the CLI's environment, never argv. */
|
|
137
1264
|
async function docker(args, options = {}) {
|
|
138
|
-
const
|
|
1265
|
+
const { engine, ...rest } = options;
|
|
1266
|
+
const { bin } = engineSpec(engine);
|
|
139
1267
|
const stdin = options.input?.length ?? 0;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
1268
|
+
const env = {
|
|
1269
|
+
...engineEnv(engine),
|
|
1270
|
+
...rest.env
|
|
1271
|
+
};
|
|
1272
|
+
const once = async () => {
|
|
1273
|
+
const startedAt = Date.now();
|
|
1274
|
+
try {
|
|
1275
|
+
const r = await run(bin, args, {
|
|
1276
|
+
...rest,
|
|
1277
|
+
env,
|
|
1278
|
+
binary: true
|
|
1279
|
+
});
|
|
1280
|
+
traceDocker(args, startedAt, {
|
|
1281
|
+
...r,
|
|
1282
|
+
stdin
|
|
1283
|
+
}, bin);
|
|
1284
|
+
return r;
|
|
1285
|
+
} catch (error) {
|
|
1286
|
+
traceDocker(args, startedAt, { error }, bin);
|
|
1287
|
+
throw error;
|
|
1288
|
+
}
|
|
1289
|
+
};
|
|
1290
|
+
return engine === "podman" ? retryConnection(once, { signal: options.signal }) : once();
|
|
154
1291
|
}
|
|
155
1292
|
async function dockerOk(args, opts) {
|
|
156
1293
|
const r = await docker(args, opts);
|
|
157
|
-
if (r.exitCode !== 0) throw new Error(
|
|
1294
|
+
if (r.exitCode !== 0) throw new Error(`${engineSpec(opts?.engine).bin} ${args[0]} failed: ${r.stderr.trim()}`);
|
|
158
1295
|
return r.stdout.toString("utf8").trim();
|
|
159
1296
|
}
|
|
160
|
-
/**
|
|
161
|
-
|
|
162
|
-
|
|
1297
|
+
/** Whether `rm -f` left the container gone: it removed it, or it was already gone. */
|
|
1298
|
+
const removalDone = (r) => r.exitCode === 0 || /no such container/i.test(r.stderr);
|
|
1299
|
+
/** How long to wait before each retry of a removal that failed. */
|
|
1300
|
+
const REMOVAL_RETRY_MS = [
|
|
1301
|
+
250,
|
|
1302
|
+
500,
|
|
1303
|
+
1e3,
|
|
1304
|
+
2e3,
|
|
1305
|
+
4e3
|
|
1306
|
+
];
|
|
1307
|
+
/**
|
|
1308
|
+
* Removes a container in its own process group, so removal survives this process being killed,
|
|
1309
|
+
* and tries again while it fails. Resolves either way.
|
|
1310
|
+
*/
|
|
1311
|
+
async function removeContainerDetached(id, engine, options = {}) {
|
|
1312
|
+
const { bin, rmForce } = engineSpec(engine);
|
|
1313
|
+
const { delays = REMOVAL_RETRY_MS, wait = sleep } = options;
|
|
1314
|
+
const args = [...rmForce, id];
|
|
1315
|
+
const env = {
|
|
1316
|
+
...process.env,
|
|
1317
|
+
...engineEnv(engine)
|
|
1318
|
+
};
|
|
1319
|
+
const once = () => new Promise((resolve) => {
|
|
163
1320
|
const keepAlive = setInterval(() => {}, 1e3);
|
|
164
1321
|
const startedAt = Date.now();
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
"-f",
|
|
168
|
-
id
|
|
169
|
-
];
|
|
1322
|
+
let stderr = "";
|
|
1323
|
+
let settled = false;
|
|
170
1324
|
const done = (exitCode) => {
|
|
1325
|
+
if (settled) return;
|
|
1326
|
+
settled = true;
|
|
171
1327
|
clearInterval(keepAlive);
|
|
172
|
-
traceDocker(args, startedAt, {
|
|
173
|
-
|
|
1328
|
+
traceDocker(args, startedAt, {
|
|
1329
|
+
exitCode,
|
|
1330
|
+
stderr
|
|
1331
|
+
}, bin);
|
|
1332
|
+
resolve({
|
|
1333
|
+
exitCode,
|
|
1334
|
+
stderr
|
|
1335
|
+
});
|
|
174
1336
|
};
|
|
175
|
-
const child = spawn(
|
|
1337
|
+
const child = spawn(bin, args, {
|
|
176
1338
|
detached: true,
|
|
177
|
-
stdio:
|
|
178
|
-
|
|
1339
|
+
stdio: [
|
|
1340
|
+
"ignore",
|
|
1341
|
+
"ignore",
|
|
1342
|
+
"pipe"
|
|
1343
|
+
],
|
|
1344
|
+
windowsHide: true,
|
|
1345
|
+
env
|
|
1346
|
+
});
|
|
1347
|
+
child.stderr.on("data", (d) => {
|
|
1348
|
+
stderr += d;
|
|
1349
|
+
});
|
|
1350
|
+
child.on("error", (error) => {
|
|
1351
|
+
stderr += String(error);
|
|
1352
|
+
done(null);
|
|
179
1353
|
});
|
|
180
|
-
child.on("error", () => done(null));
|
|
181
1354
|
child.on("close", done);
|
|
182
1355
|
});
|
|
1356
|
+
let r = await once();
|
|
1357
|
+
for (const ms of delays) {
|
|
1358
|
+
if (removalDone(r) || r.exitCode === null) return;
|
|
1359
|
+
await wait(ms);
|
|
1360
|
+
r = await once();
|
|
1361
|
+
}
|
|
183
1362
|
}
|
|
184
1363
|
/**
|
|
185
1364
|
* Removes every container with `label` (`key=value`) for the next few seconds, in its own process
|
|
186
1365
|
* group so it outlives this process. For a `docker run` killed mid-way: the daemon may create the
|
|
187
1366
|
* container after the CLI dies, and its id never came back.
|
|
188
1367
|
*/
|
|
189
|
-
function sweepLabelDetached(label, seconds = 15) {
|
|
1368
|
+
function sweepLabelDetached(label, seconds = 15, engine) {
|
|
1369
|
+
const { bin, rmForce } = engineSpec(engine);
|
|
190
1370
|
const child = spawn(process.execPath, [
|
|
191
1371
|
"-e",
|
|
192
1372
|
`const { execFileSync } = require('node:child_process')
|
|
193
|
-
const [filter, seconds] = process.argv.slice(1)
|
|
1373
|
+
const [filter, seconds, bin, ...rm] = process.argv.slice(1)
|
|
194
1374
|
const o = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true }
|
|
195
1375
|
for (let i = 0; i < Number(seconds); i++) {
|
|
196
1376
|
try {
|
|
197
|
-
const ids = execFileSync(
|
|
198
|
-
if (ids.length) execFileSync(
|
|
1377
|
+
const ids = execFileSync(bin, ['ps', '-aq', '--filter', filter], o).split(/\\s+/).filter(Boolean)
|
|
1378
|
+
if (ids.length) execFileSync(bin, [...rm, ...ids], o)
|
|
199
1379
|
} catch {}
|
|
200
1380
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 1000)
|
|
201
1381
|
}`,
|
|
202
1382
|
`label=${label}`,
|
|
203
|
-
String(seconds)
|
|
1383
|
+
String(seconds),
|
|
1384
|
+
bin,
|
|
1385
|
+
...rmForce
|
|
204
1386
|
], {
|
|
205
1387
|
detached: true,
|
|
206
1388
|
stdio: "ignore",
|
|
207
1389
|
windowsHide: true,
|
|
208
1390
|
env: {
|
|
209
1391
|
...process.env,
|
|
1392
|
+
...engineEnv(engine),
|
|
210
1393
|
BUN_BE_BUN: "1"
|
|
211
1394
|
}
|
|
212
1395
|
});
|
|
213
1396
|
child.on("error", () => {});
|
|
214
1397
|
child.unref();
|
|
215
1398
|
}
|
|
216
|
-
async function dockerState() {
|
|
1399
|
+
async function dockerState(engine) {
|
|
217
1400
|
const r = await docker([
|
|
218
1401
|
"info",
|
|
219
1402
|
"--format",
|
|
220
|
-
|
|
221
|
-
]).catch(() => null);
|
|
1403
|
+
engineSpec(engine).stateFormat
|
|
1404
|
+
], { engine }).catch(() => null);
|
|
222
1405
|
const [version, os] = r?.exitCode === 0 ? r.stdout.toString("utf8").trim().split(/\s+/) : [];
|
|
223
1406
|
if (!version) return "down";
|
|
224
1407
|
return os === "windows" ? "windows-containers" : "running";
|
|
225
1408
|
}
|
|
226
|
-
/** Whether Docker is running Linux containers, as every sandbox needs. */
|
|
227
|
-
async function dockerAvailable() {
|
|
228
|
-
return await dockerState() === "running";
|
|
1409
|
+
/** Whether Docker (or Podman) is running Linux containers, as every sandbox needs. */
|
|
1410
|
+
async function dockerAvailable(engine) {
|
|
1411
|
+
return await dockerState(engine) === "running";
|
|
229
1412
|
}
|
|
230
|
-
/** CPUs and memory of the machine containers run on (the VM, under Docker Desktop). */
|
|
231
|
-
async function dockerCapacity() {
|
|
1413
|
+
/** CPUs and memory of the machine containers run on (the VM, under Docker Desktop or `podman machine`). */
|
|
1414
|
+
async function dockerCapacity(engine) {
|
|
232
1415
|
const r = await docker([
|
|
233
1416
|
"info",
|
|
234
1417
|
"--format",
|
|
235
|
-
|
|
236
|
-
]).catch(() => null);
|
|
1418
|
+
engineSpec(engine).capacityFormat
|
|
1419
|
+
], { engine }).catch(() => null);
|
|
237
1420
|
if (r?.exitCode !== 0) return null;
|
|
238
1421
|
const [cpus, memoryBytes] = r.stdout.toString("utf8").trim().split(/\s+/).map(Number);
|
|
239
1422
|
return cpus && memoryBytes ? {
|
|
@@ -247,23 +1430,51 @@ async function dockerCapacity() {
|
|
|
247
1430
|
* their bare local name (`reeval-sandbox@sha256:…`). A bare name is Docker Hub's `library/`
|
|
248
1431
|
* namespace, which only official images can push to, so only a digest whose name has a registry
|
|
249
1432
|
* host or a namespace counts. Official images such as `busybox` count as local; no image with
|
|
250
|
-
* the harness baked in is one.
|
|
1433
|
+
* the harness baked in is one. Podman names local images `localhost/…`, which no one pulls from.
|
|
1434
|
+
*/
|
|
1435
|
+
const isRegistryDigest = (digest) => {
|
|
1436
|
+
const name = digest.split("@")[0] ?? "";
|
|
1437
|
+
return name.includes("/") && !name.startsWith("localhost/");
|
|
1438
|
+
};
|
|
1439
|
+
/** `repository:tag` of every local image in `repository`; none when the CLI fails. */
|
|
1440
|
+
async function imageTags(repository, engine) {
|
|
1441
|
+
const r = await docker([
|
|
1442
|
+
"image",
|
|
1443
|
+
"ls",
|
|
1444
|
+
"--format",
|
|
1445
|
+
"{{.Repository}}:{{.Tag}}",
|
|
1446
|
+
repository
|
|
1447
|
+
], { engine }).catch(() => null);
|
|
1448
|
+
if (r?.exitCode !== 0) return [];
|
|
1449
|
+
return r.stdout.toString("utf8").split(/\r?\n/).filter(Boolean).map((t) => t.replace(/^localhost\//, ""));
|
|
1450
|
+
}
|
|
1451
|
+
/** `image inspect`'s answer when the engine has no such image (Docker's wording, then Podman's). */
|
|
1452
|
+
const isNoSuchImage = (stderr) => /no such image|image not known/i.test(stderr);
|
|
1453
|
+
/**
|
|
1454
|
+
* The image, or null when the engine says it has no such image. A CLI that can't start or a daemon
|
|
1455
|
+
* that doesn't answer throws instead, naming the error: that's not knowing, not a missing image.
|
|
251
1456
|
*/
|
|
252
|
-
|
|
253
|
-
|
|
1457
|
+
async function imageInfo(image, engine) {
|
|
1458
|
+
const { bin, imageId } = engineSpec(engine);
|
|
254
1459
|
const r = await docker([
|
|
255
1460
|
"image",
|
|
256
1461
|
"inspect",
|
|
257
1462
|
"--format",
|
|
258
|
-
|
|
1463
|
+
`{"config":{{json .Config}},"id":{{json ${imageId}}},"repoDigests":{{json .RepoDigests}}}`,
|
|
259
1464
|
image
|
|
260
|
-
]).catch(() =>
|
|
261
|
-
|
|
1465
|
+
], { engine }).catch((error) => {
|
|
1466
|
+
throw new Error(`${bin} image inspect ${image} couldn't run: ${error.message}`);
|
|
1467
|
+
});
|
|
1468
|
+
if (r.exitCode !== 0) {
|
|
1469
|
+
const stderr = r.stderr.trim();
|
|
1470
|
+
if (isNoSuchImage(stderr)) return null;
|
|
1471
|
+
throw new Error(`${bin} image inspect ${image} failed: ${stderr || `exit ${r.exitCode}`}`);
|
|
1472
|
+
}
|
|
262
1473
|
const info = JSON.parse(r.stdout.toString("utf8"));
|
|
263
1474
|
const repoDigests = (info.repoDigests ?? []).filter(isRegistryDigest);
|
|
264
1475
|
return {
|
|
265
1476
|
labels: info.config?.Labels ?? {},
|
|
266
|
-
id: info.id,
|
|
1477
|
+
id: normalizeImageId(info.id),
|
|
267
1478
|
repoDigests
|
|
268
1479
|
};
|
|
269
1480
|
}
|
|
@@ -278,32 +1489,40 @@ async function imageInfo(image) {
|
|
|
278
1489
|
const HARNESS_PACKAGES = {
|
|
279
1490
|
cursor: {
|
|
280
1491
|
name: "@reeval/harness-cursor-sdk",
|
|
281
|
-
version: "0.1.
|
|
1492
|
+
version: "0.1.5"
|
|
282
1493
|
},
|
|
283
1494
|
"claude-code": {
|
|
284
1495
|
name: "@ai-sdk/harness-claude-code",
|
|
285
|
-
version: "1.0.
|
|
286
|
-
patch: "
|
|
1496
|
+
version: "1.0.158",
|
|
1497
|
+
patch: "6c1cff12"
|
|
287
1498
|
},
|
|
288
1499
|
antigravity: {
|
|
289
1500
|
name: "@reeval/harness-antigravity",
|
|
290
|
-
version: "0.1.
|
|
1501
|
+
version: "0.1.8"
|
|
291
1502
|
},
|
|
292
1503
|
opencode: {
|
|
293
1504
|
name: "@reeval/harness-opencode",
|
|
294
|
-
version: "0.2.
|
|
1505
|
+
version: "0.2.8"
|
|
295
1506
|
},
|
|
296
1507
|
goose: {
|
|
297
1508
|
name: "@reeval/harness-goose",
|
|
298
|
-
version: "0.1.
|
|
1509
|
+
version: "0.1.3"
|
|
299
1510
|
},
|
|
300
1511
|
pi: {
|
|
301
1512
|
name: "@reeval/harness-pi",
|
|
302
|
-
version: "0.2.
|
|
1513
|
+
version: "0.2.7"
|
|
303
1514
|
},
|
|
304
1515
|
codex: {
|
|
305
1516
|
name: "@reeval/harness-codex",
|
|
306
|
-
version: "0.1.
|
|
1517
|
+
version: "0.1.7"
|
|
1518
|
+
},
|
|
1519
|
+
fx: {
|
|
1520
|
+
name: "@reeval/harness-fx",
|
|
1521
|
+
version: "0.1.0"
|
|
1522
|
+
},
|
|
1523
|
+
"grok-build": {
|
|
1524
|
+
name: "@reeval/harness-grok-build",
|
|
1525
|
+
version: "0.1.0"
|
|
307
1526
|
}
|
|
308
1527
|
};
|
|
309
1528
|
/** Every harness with an image, in {@link HARNESS_PACKAGES} order. */
|
|
@@ -668,7 +1887,9 @@ const HARNESS_HOSTS = {
|
|
|
668
1887
|
opencode: ["generativelanguage.googleapis.com", "mcp.exa.ai"],
|
|
669
1888
|
goose: ["generativelanguage.googleapis.com"],
|
|
670
1889
|
pi: ["generativelanguage.googleapis.com"],
|
|
671
|
-
codex: ["api.openai.com"]
|
|
1890
|
+
codex: ["api.openai.com"],
|
|
1891
|
+
fx: ["ai-gateway.vercel.sh"],
|
|
1892
|
+
"grok-build": ["api.x.ai"]
|
|
672
1893
|
};
|
|
673
1894
|
/** The package registries and GitHub, for a restricted policy that still installs. */
|
|
674
1895
|
const PACKAGE_HOSTS = Object.freeze([
|
|
@@ -1782,14 +3003,14 @@ const PROXY_PORT = 43128;
|
|
|
1782
3003
|
const CA_PATH = "/usr/local/share/ca-certificates/reeval-egress.crt";
|
|
1783
3004
|
/** Debian's system bundle, which `update-ca-certificates` rebuilds with the gateway's CA in it. */
|
|
1784
3005
|
const CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt";
|
|
1785
|
-
const BUNDLED = "
|
|
3006
|
+
const BUNDLED = "reeval:ca-bundle";
|
|
1786
3007
|
const READY_TIMEOUT_MS = 15e3;
|
|
1787
3008
|
/**
|
|
1788
3009
|
* The gateway's side of the container runs as root, whoever the sandbox runs as: the sandbox user
|
|
1789
3010
|
* can't signal, trace or replace the forwarder, or change the CA it installed.
|
|
1790
3011
|
*/
|
|
1791
3012
|
const AS_ROOT = ["--user", "0:0"];
|
|
1792
|
-
const installCa = (containerId, cert, signal) => docker([
|
|
3013
|
+
const installCa = (containerId, cert, signal, engine) => docker([
|
|
1793
3014
|
"exec",
|
|
1794
3015
|
"--interactive",
|
|
1795
3016
|
...AS_ROOT,
|
|
@@ -1799,15 +3020,16 @@ const installCa = (containerId, cert, signal) => docker([
|
|
|
1799
3020
|
`umask 022 && mkdir -p "$(dirname ${CA_PATH})" && cat > ${CA_PATH} && { command -v update-ca-certificates >/dev/null && update-ca-certificates >/dev/null 2>&1 && grep -q "$(sed -n 2p ${CA_PATH})" ${CA_BUNDLE} && echo ${BUNDLED}; true; }`
|
|
1800
3021
|
], {
|
|
1801
3022
|
input: cert,
|
|
1802
|
-
signal
|
|
3023
|
+
signal,
|
|
3024
|
+
engine
|
|
1803
3025
|
});
|
|
1804
3026
|
/**
|
|
1805
3027
|
* Starts the egress gateway for one container: a forwarder inside it, tunnelled over one
|
|
1806
3028
|
* `docker exec -i`, and the proxy in this process, which holds the real credentials.
|
|
1807
3029
|
*/
|
|
1808
|
-
async function startGateway(containerId, options, signal) {
|
|
3030
|
+
async function startGateway(containerId, options, signal, engine) {
|
|
1809
3031
|
const ca = createCertificateAuthority();
|
|
1810
|
-
const installed = await installCa(containerId, ca.cert, signal);
|
|
3032
|
+
const installed = await installCa(containerId, ca.cert, signal, engine);
|
|
1811
3033
|
if (installed.exitCode !== 0) throw new Error(`couldn't install the gateway CA: ${installed.stderr.trim()}`);
|
|
1812
3034
|
const bundled = installed.stdout.toString("utf8").includes(BUNDLED);
|
|
1813
3035
|
const proxy = createEgressProxy({
|
|
@@ -1824,14 +3046,19 @@ async function startGateway(containerId, options, signal) {
|
|
|
1824
3046
|
forwarderScript(PROXY_PORT)
|
|
1825
3047
|
];
|
|
1826
3048
|
const startedAt = Date.now();
|
|
1827
|
-
const
|
|
3049
|
+
const { bin } = engineSpec(engine);
|
|
3050
|
+
const child = spawn(bin, args, {
|
|
1828
3051
|
stdio: "pipe",
|
|
1829
|
-
detached: true
|
|
3052
|
+
detached: true,
|
|
3053
|
+
env: {
|
|
3054
|
+
...process.env,
|
|
3055
|
+
...engineEnv(engine)
|
|
3056
|
+
}
|
|
1830
3057
|
});
|
|
1831
3058
|
child.once("close", (code) => traceDocker(args, startedAt, {
|
|
1832
3059
|
exitCode: code,
|
|
1833
3060
|
stderr
|
|
1834
|
-
}));
|
|
3061
|
+
}, bin));
|
|
1835
3062
|
let stderr = "";
|
|
1836
3063
|
child.stderr.on("data", (d) => {
|
|
1837
3064
|
stderr += d;
|
|
@@ -1982,14 +3209,21 @@ const ROOT_CAPABILITIES = [
|
|
|
1982
3209
|
"SETUID",
|
|
1983
3210
|
"SETGID"
|
|
1984
3211
|
];
|
|
1985
|
-
|
|
3212
|
+
const hostCpus = /* @__PURE__ */ new Map();
|
|
1986
3213
|
/** Docker refuses `--cpus` above the host's count, so cap it there. */
|
|
1987
|
-
async function cpuLimit(cpus) {
|
|
1988
|
-
|
|
1989
|
-
|
|
3214
|
+
async function cpuLimit(cpus, engine = "docker") {
|
|
3215
|
+
let known = hostCpus.get(engine);
|
|
3216
|
+
if (!known) {
|
|
3217
|
+
known = dockerCapacity(engine).then((c) => c?.cpus, () => void 0);
|
|
3218
|
+
hostCpus.set(engine, known);
|
|
3219
|
+
}
|
|
3220
|
+
const available = await known;
|
|
1990
3221
|
return String(available ? Math.min(cpus, available) : cpus);
|
|
1991
3222
|
}
|
|
1992
|
-
/**
|
|
3223
|
+
/**
|
|
3224
|
+
* The `docker run` flags that confine the container: its user, capabilities and limits, and on
|
|
3225
|
+
* Podman the bridge network and Docker's seccomp profile.
|
|
3226
|
+
*/
|
|
1993
3227
|
async function confinementArgs(options) {
|
|
1994
3228
|
const limits = {
|
|
1995
3229
|
...DEFAULT_LIMITS,
|
|
@@ -2011,7 +3245,8 @@ async function confinementArgs(options) {
|
|
|
2011
3245
|
"--pids-limit",
|
|
2012
3246
|
String(limits.pids),
|
|
2013
3247
|
"--cpus",
|
|
2014
|
-
await cpuLimit(limits.cpus)
|
|
3248
|
+
await cpuLimit(limits.cpus, options.engine),
|
|
3249
|
+
...engineSpec(options.engine).runArgs()
|
|
2015
3250
|
];
|
|
2016
3251
|
}
|
|
2017
3252
|
/** Runtime `npm i -g` goes to the sandbox user's own prefix, whose `bin` the images put on PATH. */
|
|
@@ -2023,14 +3258,14 @@ const EXEC_MARKER = "REEVAL_EXEC_ID";
|
|
|
2023
3258
|
* `memory.events` and v1's `memory.oom_control` both have an `oom_kill` line. Without either,
|
|
2024
3259
|
* Docker's `OOMKilled` says only whether there was one.
|
|
2025
3260
|
*/
|
|
2026
|
-
async function oomKills(id) {
|
|
3261
|
+
async function oomKills(id, engine) {
|
|
2027
3262
|
const events = await docker([
|
|
2028
3263
|
"exec",
|
|
2029
3264
|
id,
|
|
2030
3265
|
"sh",
|
|
2031
3266
|
"-c",
|
|
2032
3267
|
"cat /sys/fs/cgroup/memory.events 2>/dev/null || cat /sys/fs/cgroup/memory/memory.oom_control"
|
|
2033
|
-
]).catch(() => null);
|
|
3268
|
+
], { engine }).catch(() => null);
|
|
2034
3269
|
const count = events?.stdout.toString("utf8").match(/^oom_kill (\d+)$/m)?.[1];
|
|
2035
3270
|
if (events?.exitCode === 0 && count !== void 0) return Number(count);
|
|
2036
3271
|
const inspected = await docker([
|
|
@@ -2038,21 +3273,31 @@ async function oomKills(id) {
|
|
|
2038
3273
|
"--format",
|
|
2039
3274
|
"{{.State.OOMKilled}}",
|
|
2040
3275
|
id
|
|
2041
|
-
]).catch(() => null);
|
|
3276
|
+
], { engine }).catch(() => null);
|
|
2042
3277
|
if (inspected?.exitCode !== 0) return null;
|
|
2043
3278
|
const killed = inspected.stdout.toString("utf8").trim();
|
|
2044
3279
|
return killed === "true" ? 1 : killed === "false" ? 0 : null;
|
|
2045
3280
|
}
|
|
2046
3281
|
/** The Docker networks a container is attached to. */
|
|
2047
|
-
async function networksOf(id) {
|
|
3282
|
+
async function networksOf(id, engine) {
|
|
2048
3283
|
const out = await dockerOk([
|
|
2049
3284
|
"inspect",
|
|
2050
3285
|
"--format",
|
|
2051
3286
|
"{{json .NetworkSettings.Networks}}",
|
|
2052
3287
|
id
|
|
2053
|
-
]);
|
|
3288
|
+
], { engine });
|
|
2054
3289
|
return Object.keys(JSON.parse(out) ?? {});
|
|
2055
3290
|
}
|
|
3291
|
+
/** How the container is networked when it's on no network: `host`, `slirp4netns`, `pasta`… */
|
|
3292
|
+
async function networkMode(id, engine) {
|
|
3293
|
+
const r = await docker([
|
|
3294
|
+
"inspect",
|
|
3295
|
+
"--format",
|
|
3296
|
+
"{{.HostConfig.NetworkMode}}",
|
|
3297
|
+
id
|
|
3298
|
+
], { engine }).catch(() => null);
|
|
3299
|
+
return r?.exitCode === 0 ? r.stdout.toString("utf8").trim() || "unknown" : "unknown";
|
|
3300
|
+
}
|
|
2056
3301
|
/**
|
|
2057
3302
|
* A harness sandbox session backed by one local Docker container. Commands and file I/O go
|
|
2058
3303
|
* through `docker exec`. With the egress gateway, ports are reached through its tunnel whatever
|
|
@@ -2067,6 +3312,8 @@ async function createDockerSession(options) {
|
|
|
2067
3312
|
};
|
|
2068
3313
|
const lifetime = Math.ceil((options.lifetimeMs ?? 864e5) / 1e3);
|
|
2069
3314
|
const signal = options.abortSignal;
|
|
3315
|
+
const { engine } = options;
|
|
3316
|
+
const spec = engineSpec(engine);
|
|
2070
3317
|
const env = {
|
|
2071
3318
|
...userEnv(options),
|
|
2072
3319
|
...options.env
|
|
@@ -2081,20 +3328,21 @@ async function createDockerSession(options) {
|
|
|
2081
3328
|
...Object.keys(env).flatMap((k) => ["--env", k]),
|
|
2082
3329
|
"--publish",
|
|
2083
3330
|
`127.0.0.1::${BRIDGE_PORT}`,
|
|
2084
|
-
"--workdir",
|
|
2085
|
-
SANDBOX_ROOT,
|
|
3331
|
+
...spec.createsWorkdir ? ["--workdir", SANDBOX_ROOT] : [],
|
|
2086
3332
|
"--entrypoint",
|
|
2087
3333
|
"sleep",
|
|
2088
3334
|
options.image,
|
|
2089
3335
|
String(lifetime)
|
|
2090
3336
|
], {
|
|
2091
3337
|
signal,
|
|
2092
|
-
env
|
|
3338
|
+
env,
|
|
3339
|
+
engine
|
|
2093
3340
|
}).catch((error) => {
|
|
2094
|
-
|
|
2095
|
-
if (
|
|
2096
|
-
|
|
2097
|
-
|
|
3341
|
+
const sweep = () => sweepLabelDetached(`${LABEL.session}=${nonce}`, void 0, engine);
|
|
3342
|
+
if (signal?.aborted) sweep();
|
|
3343
|
+
if (/unable to find user|no matching entries in passwd/i.test(error.message)) {
|
|
3344
|
+
sweep();
|
|
3345
|
+
throw new Error(`${options.image} has no ${SANDBOX_USER} user to run the sandbox as. Images reeval builds have one: rebuild it (reeval image build), or start from reeval's image or ${spec.fn}({ from }). An eval that needs root at run time can opt in with ${spec.fn}({ root: true }).`);
|
|
2098
3346
|
}
|
|
2099
3347
|
throw error;
|
|
2100
3348
|
});
|
|
@@ -2102,33 +3350,57 @@ async function createDockerSession(options) {
|
|
|
2102
3350
|
let removed;
|
|
2103
3351
|
const remove = () => {
|
|
2104
3352
|
gateway?.close();
|
|
2105
|
-
removed ??= removeContainerDetached(id);
|
|
3353
|
+
removed ??= removeContainerDetached(id, engine);
|
|
2106
3354
|
return removed;
|
|
2107
3355
|
};
|
|
2108
3356
|
if (signal?.aborted) {
|
|
2109
3357
|
await remove();
|
|
2110
3358
|
throw signal.reason;
|
|
2111
3359
|
}
|
|
3360
|
+
if (!spec.createsWorkdir) {
|
|
3361
|
+
const made = await docker([
|
|
3362
|
+
"exec",
|
|
3363
|
+
"--user",
|
|
3364
|
+
"0:0",
|
|
3365
|
+
id,
|
|
3366
|
+
"mkdir",
|
|
3367
|
+
"-p",
|
|
3368
|
+
SANDBOX_ROOT
|
|
3369
|
+
], {
|
|
3370
|
+
engine,
|
|
3371
|
+
signal
|
|
3372
|
+
}).catch((error) => ({
|
|
3373
|
+
exitCode: 1,
|
|
3374
|
+
stderr: error.message
|
|
3375
|
+
}));
|
|
3376
|
+
if (made.exitCode !== 0) {
|
|
3377
|
+
await remove();
|
|
3378
|
+
if (signal?.aborted) throw signal.reason;
|
|
3379
|
+
throw new Error(`Couldn't create ${SANDBOX_ROOT} in the container: ${made.stderr.trim()}`);
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
2112
3382
|
const egressOptions = options.egress === true ? {} : options.egress || void 0;
|
|
2113
3383
|
let egress;
|
|
2114
3384
|
let detached = [];
|
|
2115
3385
|
const attach = async (policy) => {
|
|
2116
3386
|
if (isRestricted(policy) && detached.length === 0) {
|
|
2117
|
-
detached = await networksOf(id);
|
|
3387
|
+
detached = await networksOf(id, engine);
|
|
3388
|
+
const mode = detached.length === 0 ? await networkMode(id, engine) : "none";
|
|
3389
|
+
if (detached.length === 0 && mode !== "none") throw new Error(`the container's network is ${mode}, which ${spec.name} can't detach it from, so a restricted policy would still have a route out`);
|
|
2118
3390
|
for (const n of detached) await dockerOk([
|
|
2119
3391
|
"network",
|
|
2120
3392
|
"disconnect",
|
|
2121
3393
|
"--force",
|
|
2122
3394
|
n,
|
|
2123
3395
|
id
|
|
2124
|
-
]);
|
|
3396
|
+
], { engine });
|
|
2125
3397
|
} else if (!isRestricted(policy) && detached.length > 0) {
|
|
2126
3398
|
for (const n of detached) await dockerOk([
|
|
2127
3399
|
"network",
|
|
2128
3400
|
"connect",
|
|
2129
3401
|
n,
|
|
2130
3402
|
id
|
|
2131
|
-
]);
|
|
3403
|
+
], { engine });
|
|
2132
3404
|
detached = [];
|
|
2133
3405
|
}
|
|
2134
3406
|
};
|
|
@@ -2139,7 +3411,7 @@ async function createDockerSession(options) {
|
|
|
2139
3411
|
gateway = await startGateway(id, {
|
|
2140
3412
|
...rest,
|
|
2141
3413
|
policy
|
|
2142
|
-
}, signal);
|
|
3414
|
+
}, signal, engine);
|
|
2143
3415
|
egress = { active: true };
|
|
2144
3416
|
} catch (error) {
|
|
2145
3417
|
if (signal?.aborted || isRestricted(policy)) {
|
|
@@ -2182,14 +3454,15 @@ async function createDockerSession(options) {
|
|
|
2182
3454
|
"sh",
|
|
2183
3455
|
"-c",
|
|
2184
3456
|
`for e in /proc/[0-9]*/environ; do grep -qsxzF ${shellQuote(`${EXEC_MARKER}=${marker}`)} "$e" && kill -9 "$(basename "$(dirname "$e")")" 2>/dev/null; done; true`
|
|
2185
|
-
]).then(() => {}, () => {});
|
|
3457
|
+
], { engine }).then(() => {}, () => {});
|
|
2186
3458
|
const run = async (o) => {
|
|
2187
3459
|
const env = envFor(o.env);
|
|
2188
3460
|
const marker = nextMarker();
|
|
2189
3461
|
try {
|
|
2190
3462
|
const r = await docker(execArgs(o.command, marker, o.workingDirectory, env), {
|
|
2191
3463
|
env,
|
|
2192
|
-
signal: o.abortSignal
|
|
3464
|
+
signal: o.abortSignal,
|
|
3465
|
+
engine
|
|
2193
3466
|
});
|
|
2194
3467
|
return {
|
|
2195
3468
|
exitCode: r.exitCode,
|
|
@@ -2208,7 +3481,10 @@ async function createDockerSession(options) {
|
|
|
2208
3481
|
"cat",
|
|
2209
3482
|
"--",
|
|
2210
3483
|
posix.resolve(SANDBOX_ROOT, o.path)
|
|
2211
|
-
], {
|
|
3484
|
+
], {
|
|
3485
|
+
signal: o.abortSignal,
|
|
3486
|
+
engine
|
|
3487
|
+
});
|
|
2212
3488
|
return r.exitCode === 0 ? new Uint8Array(r.stdout) : null;
|
|
2213
3489
|
};
|
|
2214
3490
|
const writeBinaryFile = async (o) => {
|
|
@@ -2222,7 +3498,8 @@ async function createDockerSession(options) {
|
|
|
2222
3498
|
`mkdir -p ${shellQuote(posix.dirname(path))} && cat > ${shellQuote(path)}`
|
|
2223
3499
|
], {
|
|
2224
3500
|
input: Buffer.from(o.content),
|
|
2225
|
-
signal: o.abortSignal
|
|
3501
|
+
signal: o.abortSignal,
|
|
3502
|
+
engine
|
|
2226
3503
|
});
|
|
2227
3504
|
};
|
|
2228
3505
|
const brokering = gateway ? {
|
|
@@ -2245,7 +3522,7 @@ async function createDockerSession(options) {
|
|
|
2245
3522
|
} : {};
|
|
2246
3523
|
const session = {
|
|
2247
3524
|
id,
|
|
2248
|
-
description:
|
|
3525
|
+
description: `${spec.name} container ${id.slice(0, 12)} (${options.image})`,
|
|
2249
3526
|
defaultWorkingDirectory: SANDBOX_ROOT,
|
|
2250
3527
|
ports: [BRIDGE_PORT],
|
|
2251
3528
|
get egress() {
|
|
@@ -2257,30 +3534,31 @@ async function createDockerSession(options) {
|
|
|
2257
3534
|
},
|
|
2258
3535
|
...brokering,
|
|
2259
3536
|
...substituting,
|
|
2260
|
-
oomKills: () => oomKills(id),
|
|
3537
|
+
oomKills: () => oomKills(id, engine),
|
|
2261
3538
|
run,
|
|
2262
3539
|
async spawn(o) {
|
|
2263
3540
|
const env = envFor(o.env);
|
|
2264
3541
|
const marker = nextMarker();
|
|
2265
3542
|
const args = execArgs(o.command, marker, o.workingDirectory, env);
|
|
2266
3543
|
const startedAt = Date.now();
|
|
2267
|
-
const child = spawn(
|
|
3544
|
+
const child = spawn(spec.bin, args, {
|
|
2268
3545
|
stdio: [
|
|
2269
3546
|
"ignore",
|
|
2270
3547
|
"pipe",
|
|
2271
3548
|
"pipe"
|
|
2272
3549
|
],
|
|
2273
3550
|
detached: true,
|
|
2274
|
-
env:
|
|
3551
|
+
env: {
|
|
2275
3552
|
...process.env,
|
|
3553
|
+
...engineEnv(engine),
|
|
2276
3554
|
...env
|
|
2277
|
-
}
|
|
3555
|
+
}
|
|
2278
3556
|
});
|
|
2279
3557
|
const exited = new Promise((resolve) => child.on("close", (code) => {
|
|
2280
3558
|
traceDocker(args, startedAt, {
|
|
2281
3559
|
exitCode: code,
|
|
2282
3560
|
stdout: "<streamed>"
|
|
2283
|
-
});
|
|
3561
|
+
}, spec.bin);
|
|
2284
3562
|
resolve({ exitCode: code ?? 1 });
|
|
2285
3563
|
}));
|
|
2286
3564
|
const kill = async () => {
|
|
@@ -2329,10 +3607,10 @@ async function createDockerSession(options) {
|
|
|
2329
3607
|
"port",
|
|
2330
3608
|
id,
|
|
2331
3609
|
`${port}/tcp`
|
|
2332
|
-
]);
|
|
3610
|
+
], { engine });
|
|
2333
3611
|
const hostPort = mapped.stdout.toString("utf8").split("\n")[0]?.split(":").at(-1);
|
|
2334
3612
|
if (mapped.exitCode !== 0 || !hostPort) {
|
|
2335
|
-
const reason = mapped.stderr.trim() ||
|
|
3613
|
+
const reason = mapped.stderr.trim() || `${spec.name} reports no host port for it`;
|
|
2336
3614
|
throw new Error(`Port ${port} of ${id.slice(0, 12)} isn't reachable: ${reason}`);
|
|
2337
3615
|
}
|
|
2338
3616
|
return { url: `${scheme}://127.0.0.1:${hostPort}` };
|
|
@@ -2363,7 +3641,7 @@ async function createDockerSession(options) {
|
|
|
2363
3641
|
/** The session as an AI SDK harness sandbox provider. */
|
|
2364
3642
|
const dockerSandboxProvider = (options) => ({
|
|
2365
3643
|
specificationVersion: "harness-sandbox-v1",
|
|
2366
|
-
providerId: "reeval-docker",
|
|
3644
|
+
providerId: options.engine === "podman" ? "reeval-podman" : "reeval-docker",
|
|
2367
3645
|
async createSession(o) {
|
|
2368
3646
|
const session = await createDockerSession({
|
|
2369
3647
|
...options,
|
|
@@ -2396,22 +3674,22 @@ const BOOTSTRAPS = {
|
|
|
2396
3674
|
name: "Cursor",
|
|
2397
3675
|
cli: "@cursor/sdk",
|
|
2398
3676
|
version: `node -p "'@cursor/sdk ' + require(process.env.HOME + '/.ai-sdk-harness/.harness-bootstrap/cursor-sdk/node_modules/@cursor/sdk/package.json').version"`,
|
|
2399
|
-
adapter: async () => (await import("./src-
|
|
3677
|
+
adapter: async () => (await import("./src-DTbrY1hi.js")).createCursorSdk()
|
|
2400
3678
|
},
|
|
2401
3679
|
"claude-code": {
|
|
2402
3680
|
name: "Claude Code",
|
|
2403
3681
|
cli: "claude",
|
|
2404
|
-
adapter: async () => (await import("./dist-
|
|
3682
|
+
adapter: async () => (await import("./dist-B8hJImYt.js")).createClaudeCode()
|
|
2405
3683
|
},
|
|
2406
3684
|
antigravity: {
|
|
2407
3685
|
name: "Antigravity",
|
|
2408
3686
|
cli: "agy",
|
|
2409
|
-
adapter: async () => (await import("./src-
|
|
3687
|
+
adapter: async () => (await import("./src-DNnG4e4R.js")).createAntigravity()
|
|
2410
3688
|
},
|
|
2411
3689
|
opencode: {
|
|
2412
3690
|
name: "OpenCode",
|
|
2413
3691
|
cli: "opencode",
|
|
2414
|
-
adapter: async () => (await import("./src-
|
|
3692
|
+
adapter: async () => (await import("./src-ofUaYbuY.js")).createOpenCode({
|
|
2415
3693
|
auth: { GOOGLE_GENERATIVE_AI_API_KEY: "unused" },
|
|
2416
3694
|
model: "google/unused"
|
|
2417
3695
|
})
|
|
@@ -2419,7 +3697,7 @@ const BOOTSTRAPS = {
|
|
|
2419
3697
|
goose: {
|
|
2420
3698
|
name: "Goose",
|
|
2421
3699
|
cli: "goose",
|
|
2422
|
-
adapter: async () => (await import("./src-
|
|
3700
|
+
adapter: async () => (await import("./src-DdyJEh2v.js")).createGoose({
|
|
2423
3701
|
auth: { GOOGLE_API_KEY: "unused" },
|
|
2424
3702
|
model: "unused"
|
|
2425
3703
|
})
|
|
@@ -2427,12 +3705,28 @@ const BOOTSTRAPS = {
|
|
|
2427
3705
|
pi: {
|
|
2428
3706
|
name: "pi",
|
|
2429
3707
|
cli: "pi",
|
|
2430
|
-
adapter: async () => (await import("./src-
|
|
3708
|
+
adapter: async () => (await import("./src-jzagbuqH.js")).createPi({ auth: { GEMINI_API_KEY: "unused" } })
|
|
2431
3709
|
},
|
|
2432
3710
|
codex: {
|
|
2433
3711
|
name: "Codex",
|
|
2434
3712
|
cli: "codex",
|
|
2435
|
-
adapter: async () => (await import("./src-
|
|
3713
|
+
adapter: async () => (await import("./src-Dj9PAroc.js")).createCodex({ auth: { OPENAI_API_KEY: "unused" } })
|
|
3714
|
+
},
|
|
3715
|
+
fx: {
|
|
3716
|
+
name: "fx",
|
|
3717
|
+
cli: "fx",
|
|
3718
|
+
adapter: async () => (await import("./src-C_lPtowT.js")).createFx({
|
|
3719
|
+
auth: { AI_GATEWAY_API_KEY: "unused" },
|
|
3720
|
+
model: "unused/unused"
|
|
3721
|
+
})
|
|
3722
|
+
},
|
|
3723
|
+
"grok-build": {
|
|
3724
|
+
name: "Grok Build",
|
|
3725
|
+
cli: "grok",
|
|
3726
|
+
adapter: async () => (await import("./src-Du8H85Qq.js")).createGrokBuild({
|
|
3727
|
+
auth: { XAI_API_KEY: "unused" },
|
|
3728
|
+
model: "unused"
|
|
3729
|
+
})
|
|
2436
3730
|
}
|
|
2437
3731
|
};
|
|
2438
3732
|
/** Keeps the image's `PATH` in login shells, which Debian's `/etc/profile` resets. */
|
|
@@ -2464,10 +3758,10 @@ WORKDIR ${SANDBOX_ROOT}/${WORKSPACE_DIR}
|
|
|
2464
3758
|
`;
|
|
2465
3759
|
const tail = (text) => text.trim().split("\n").slice(-15).join("\n");
|
|
2466
3760
|
const clipLine = (text, max = 300) => text.length > max ? `${text.slice(0, max - 1)}…` : text;
|
|
2467
|
-
/** Why a `docker build` failed, in a line: the failing step's exit, or BuildKit's own error. */
|
|
2468
|
-
function buildReason(error) {
|
|
2469
|
-
if (!error) return
|
|
2470
|
-
const exit = /^process ".*" did not complete successfully: exit code: (\d+)$/s.exec(error);
|
|
3761
|
+
/** Why a `docker build` failed, in a line: the failing step's exit, or BuildKit's (or buildah's) own error. */
|
|
3762
|
+
function buildReason(error, engine) {
|
|
3763
|
+
if (!error) return `${engineSpec(engine).bin} build failed`;
|
|
3764
|
+
const exit = /^process ".*" did not complete successfully: exit code: (\d+)$/s.exec(error) ?? /^while running runtime: exit status (\d+)$/.exec(error);
|
|
2471
3765
|
return exit ? `a RUN step exited ${exit[1]}` : clipLine(error.replace(/\s+/g, " "));
|
|
2472
3766
|
}
|
|
2473
3767
|
/**
|
|
@@ -2479,12 +3773,13 @@ function buildError(output, what, reason, keep = () => true) {
|
|
|
2479
3773
|
const text = [parsed.error ?? "", ...parsed.output].join("\n");
|
|
2480
3774
|
const cause = failureCause(text, parsed.exitCode);
|
|
2481
3775
|
parsed.output = parsed.output.filter(keep);
|
|
2482
|
-
const why = reason?.(parsed) ?? buildReason(parsed.error);
|
|
3776
|
+
const why = reason?.(parsed) ?? buildReason(parsed.error, what.engine);
|
|
2483
3777
|
return new ImageBuildError(failureMessage({
|
|
2484
3778
|
headline: `${what.headline} failed: ${why}`,
|
|
2485
3779
|
cause,
|
|
2486
3780
|
output: parsed.output,
|
|
2487
|
-
log: what.log ?? null
|
|
3781
|
+
log: what.log ?? null,
|
|
3782
|
+
...what.engine ? { engine: what.engine } : {}
|
|
2488
3783
|
}), {
|
|
2489
3784
|
stage: what.stage,
|
|
2490
3785
|
ref: what.ref,
|
|
@@ -2499,12 +3794,12 @@ const BUILT_BY = ["--label", `${LABEL.managed}=image`];
|
|
|
2499
3794
|
* Removes the images reeval built that nothing tags any more (a rebuild's old image) and the
|
|
2500
3795
|
* intermediate `-base` tags of `from` builds. Returns how many it removed.
|
|
2501
3796
|
*/
|
|
2502
|
-
async function pruneImages() {
|
|
3797
|
+
async function pruneImages(engine) {
|
|
2503
3798
|
const list = async (args) => (await docker([
|
|
2504
3799
|
"image",
|
|
2505
3800
|
"ls",
|
|
2506
3801
|
...args
|
|
2507
|
-
])).stdout.toString("utf8").split("\n").map((l) => l.trim()).filter(Boolean);
|
|
3802
|
+
], { engine })).stdout.toString("utf8").split("\n").map((l) => l.trim()).filter(Boolean);
|
|
2508
3803
|
const dangling = [...await list([
|
|
2509
3804
|
"-q",
|
|
2510
3805
|
"--filter",
|
|
@@ -2528,46 +3823,93 @@ async function pruneImages() {
|
|
|
2528
3823
|
"image",
|
|
2529
3824
|
"rm",
|
|
2530
3825
|
ref
|
|
2531
|
-
]).catch(() => null))?.exitCode === 0) removed++;
|
|
3826
|
+
], { engine }).catch(() => null))?.exitCode === 0) removed++;
|
|
2532
3827
|
return removed;
|
|
2533
3828
|
}
|
|
3829
|
+
/** Docker's names for Node's architectures, as image indexes list platforms. */
|
|
3830
|
+
const OCI_ARCH = {
|
|
3831
|
+
x64: "amd64",
|
|
3832
|
+
arm64: "arm64",
|
|
3833
|
+
arm: "arm",
|
|
3834
|
+
ppc64: "ppc64le"
|
|
3835
|
+
};
|
|
3836
|
+
/**
|
|
3837
|
+
* A registry digest for `from` without Docker's buildx: skopeo's, which is the same digest
|
|
3838
|
+
* buildx gives, or else this platform's manifest from `podman manifest inspect`.
|
|
3839
|
+
*/
|
|
3840
|
+
async function podmanRemoteDigest(from, signal) {
|
|
3841
|
+
const skopeo = await run("skopeo", [
|
|
3842
|
+
"inspect",
|
|
3843
|
+
"--format",
|
|
3844
|
+
"{{.Digest}}",
|
|
3845
|
+
`docker://${from}`
|
|
3846
|
+
], { ...signal ? { signal } : {} }).catch(() => null);
|
|
3847
|
+
const digest = skopeo?.exitCode === 0 ? skopeo.stdout.trim() : "";
|
|
3848
|
+
if (digest.startsWith("sha256:")) return { digest };
|
|
3849
|
+
const r = await docker([
|
|
3850
|
+
"manifest",
|
|
3851
|
+
"inspect",
|
|
3852
|
+
from
|
|
3853
|
+
], {
|
|
3854
|
+
signal,
|
|
3855
|
+
engine: "podman"
|
|
3856
|
+
}).catch(() => null);
|
|
3857
|
+
if (r?.exitCode === 0) {
|
|
3858
|
+
const manifest = JSON.parse(r.stdout.toString("utf8"));
|
|
3859
|
+
const arch = OCI_ARCH[process.arch] ?? process.arch;
|
|
3860
|
+
const own = manifest.manifests?.find((m) => m.platform?.os === "linux" && m.platform.architecture === arch)?.digest;
|
|
3861
|
+
if (own?.startsWith("sha256:")) return { digest: own };
|
|
3862
|
+
}
|
|
3863
|
+
return { error: (r?.stderr.trim() || skopeo?.stderr.trim() || "").replace(/^(?:Error|time="[^"]*" level=fatal msg=): ?/, "").replace(/\s+/g, " ") || `${from} doesn't resolve` };
|
|
3864
|
+
}
|
|
2534
3865
|
/**
|
|
2535
3866
|
* What a `from` names now, without pulling: its registry digest, or for an image that's only
|
|
2536
3867
|
* local, its id (`local`). `error` when neither resolves, e.g. a typo or no network.
|
|
2537
3868
|
*/
|
|
2538
|
-
async function resolveFrom(from, signal) {
|
|
3869
|
+
async function resolveFrom(from, signal, engine) {
|
|
2539
3870
|
const pinned = /@(sha256:[0-9a-f]{64})$/.exec(from)?.[1];
|
|
2540
3871
|
if (pinned) return {
|
|
2541
3872
|
digest: pinned,
|
|
2542
3873
|
local: false
|
|
2543
3874
|
};
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
"
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
3875
|
+
let error = null;
|
|
3876
|
+
if (engine === "podman") {
|
|
3877
|
+
const remote = await podmanRemoteDigest(from, signal);
|
|
3878
|
+
if ("digest" in remote) return {
|
|
3879
|
+
digest: remote.digest,
|
|
3880
|
+
local: false
|
|
3881
|
+
};
|
|
3882
|
+
error = remote.error;
|
|
3883
|
+
} else {
|
|
3884
|
+
const remote = await docker([
|
|
3885
|
+
"buildx",
|
|
3886
|
+
"imagetools",
|
|
3887
|
+
"inspect",
|
|
3888
|
+
"--format",
|
|
3889
|
+
"{{json .Manifest.Digest}}",
|
|
3890
|
+
from
|
|
3891
|
+
], { signal }).catch(() => null);
|
|
3892
|
+
const digest = remote?.exitCode === 0 ? JSON.parse(remote.stdout.toString("utf8").trim()) : null;
|
|
3893
|
+
if (typeof digest === "string" && digest.startsWith("sha256:")) return {
|
|
3894
|
+
digest,
|
|
3895
|
+
local: false
|
|
3896
|
+
};
|
|
3897
|
+
error = remote?.stderr.trim().replace(/^ERROR: /, "").replace(/\s+/g, " ") || null;
|
|
3898
|
+
}
|
|
3899
|
+
const local = await imageInfo(from, engine).catch(() => null);
|
|
2558
3900
|
if (local) return {
|
|
2559
3901
|
digest: local.id,
|
|
2560
3902
|
local: true
|
|
2561
3903
|
};
|
|
2562
|
-
return { error:
|
|
3904
|
+
return { error: error || `${from} doesn't resolve` };
|
|
2563
3905
|
}
|
|
2564
3906
|
/** Removes a tag or an image reeval replaced, unless something still uses it. */
|
|
2565
|
-
const removeQuietly = async (ref) => {
|
|
3907
|
+
const removeQuietly = async (ref, engine) => {
|
|
2566
3908
|
await docker([
|
|
2567
3909
|
"image",
|
|
2568
3910
|
"rm",
|
|
2569
3911
|
ref
|
|
2570
|
-
]).catch(() => {});
|
|
3912
|
+
], { engine }).catch(() => {});
|
|
2571
3913
|
};
|
|
2572
3914
|
/** The hash of reeval's base image build context, which its images carry as a label. */
|
|
2573
3915
|
function contextHash() {
|
|
@@ -2587,14 +3929,14 @@ function contextHash() {
|
|
|
2587
3929
|
* intermediate `-base` tag of a `from` build, are removed once the new one is committed.
|
|
2588
3930
|
*/
|
|
2589
3931
|
async function buildImage(log, options) {
|
|
2590
|
-
const { harness, from, signal } = options;
|
|
2591
|
-
const resolved = from ? await resolveFrom(from, signal) : null;
|
|
3932
|
+
const { harness, from, signal, engine } = options;
|
|
3933
|
+
const resolved = from ? await resolveFrom(from, signal, engine) : null;
|
|
2592
3934
|
const digest = resolved && "digest" in resolved ? resolved.digest : null;
|
|
2593
3935
|
const pinned = from && digest && resolved && "local" in resolved && !resolved.local && !from.includes("@") ? `${from}@${digest}` : from;
|
|
2594
3936
|
const bootstrap = BOOTSTRAPS[harness];
|
|
2595
3937
|
const base = from ? `${harnessImageFor(harness, from)}-base` : BASE_IMAGE;
|
|
2596
3938
|
const target = from ? harnessImageFor(harness, from) : imageFor(harness);
|
|
2597
|
-
const previous = [(await imageInfo(target))?.id, from ? null : (await imageInfo(base))?.id];
|
|
3939
|
+
const previous = [(await imageInfo(target, engine))?.id, from ? null : (await imageInfo(base, engine))?.id];
|
|
2598
3940
|
log(`Building ${base}${from ? ` from ${from}` : ""}`);
|
|
2599
3941
|
const build = from ? await docker([
|
|
2600
3942
|
"build",
|
|
@@ -2607,7 +3949,8 @@ async function buildImage(log, options) {
|
|
|
2607
3949
|
"-"
|
|
2608
3950
|
], {
|
|
2609
3951
|
input: toolchainDockerfile(pinned ?? from),
|
|
2610
|
-
signal
|
|
3952
|
+
signal,
|
|
3953
|
+
engine
|
|
2611
3954
|
}) : await docker([
|
|
2612
3955
|
"build",
|
|
2613
3956
|
"--progress",
|
|
@@ -2620,20 +3963,25 @@ async function buildImage(log, options) {
|
|
|
2620
3963
|
"--tag",
|
|
2621
3964
|
base,
|
|
2622
3965
|
DOCKER_CONTEXT
|
|
2623
|
-
], {
|
|
3966
|
+
], {
|
|
3967
|
+
signal,
|
|
3968
|
+
engine
|
|
3969
|
+
});
|
|
2624
3970
|
const output = `${build.stdout.toString("utf8")}${build.stderr}`;
|
|
2625
3971
|
options.output?.write(output);
|
|
2626
3972
|
if (build.exitCode !== 0) throw buildError(output, {
|
|
2627
3973
|
stage: from ? "from" : "harness",
|
|
2628
3974
|
ref: target,
|
|
2629
3975
|
headline: from ? `Building the toolchain layer FROM ${from}` : "Building reeval's base image",
|
|
2630
|
-
log: options.output?.path ?? null
|
|
3976
|
+
log: options.output?.path ?? null,
|
|
3977
|
+
engine
|
|
2631
3978
|
}, (parsed) => parsed.output.find((l) => l.startsWith("reeval needs a Debian")) ?? null);
|
|
2632
3979
|
log(`Installing the ${bootstrap.name} harness bootstrap`);
|
|
2633
3980
|
const session = await createDockerSession({
|
|
2634
3981
|
image: base,
|
|
2635
3982
|
lifetimeMs: 18e5,
|
|
2636
|
-
...signal ? { abortSignal: signal } : {}
|
|
3983
|
+
...signal ? { abortSignal: signal } : {},
|
|
3984
|
+
...engine ? { engine } : {}
|
|
2637
3985
|
});
|
|
2638
3986
|
let agentVersion;
|
|
2639
3987
|
try {
|
|
@@ -2653,7 +4001,7 @@ async function buildImage(log, options) {
|
|
|
2653
4001
|
"CMD [\"bash\"]",
|
|
2654
4002
|
session.id,
|
|
2655
4003
|
target
|
|
2656
|
-
]);
|
|
4004
|
+
], { engine });
|
|
2657
4005
|
} catch (error) {
|
|
2658
4006
|
if (signal?.aborted || error instanceof ImageBuildError) throw error;
|
|
2659
4007
|
const [first = "", ...rest] = error.message.split("\n");
|
|
@@ -2663,7 +4011,8 @@ async function buildImage(log, options) {
|
|
|
2663
4011
|
headline: `Baking the ${bootstrap.name} CLI onto ${from ?? "reeval-sandbox-base:latest"} failed: ${clipLine(first)}`,
|
|
2664
4012
|
cause,
|
|
2665
4013
|
output: outputTail(rest.join("\n")),
|
|
2666
|
-
log: options.output?.path ?? null
|
|
4014
|
+
log: options.output?.path ?? null,
|
|
4015
|
+
...engine ? { engine } : {}
|
|
2667
4016
|
}), {
|
|
2668
4017
|
stage: "harness",
|
|
2669
4018
|
ref: target,
|
|
@@ -2674,9 +4023,9 @@ async function buildImage(log, options) {
|
|
|
2674
4023
|
} finally {
|
|
2675
4024
|
await session.destroy();
|
|
2676
4025
|
}
|
|
2677
|
-
if (from) await removeQuietly(base);
|
|
2678
|
-
const now = (await imageInfo(target))?.id;
|
|
2679
|
-
for (const id of previous) if (id && id !== now) await removeQuietly(id);
|
|
4026
|
+
if (from) await removeQuietly(base, engine);
|
|
4027
|
+
const now = (await imageInfo(target, engine))?.id;
|
|
4028
|
+
for (const id of previous) if (id && id !== now) await removeQuietly(id, engine);
|
|
2680
4029
|
return {
|
|
2681
4030
|
image: target,
|
|
2682
4031
|
agentVersion
|
|
@@ -2719,15 +4068,18 @@ function installScript(steps) {
|
|
|
2719
4068
|
}
|
|
2720
4069
|
/** Builds the install layer if it's missing. `output` gets the build's output, for a log file. */
|
|
2721
4070
|
async function buildInstallLayer(parent, steps, options = {}) {
|
|
2722
|
-
const { signal } = options;
|
|
4071
|
+
const { signal, engine } = options;
|
|
2723
4072
|
const tag = installLayerTag(parent, steps);
|
|
2724
4073
|
if ((await docker([
|
|
2725
4074
|
"image",
|
|
2726
4075
|
"inspect",
|
|
2727
4076
|
"--format",
|
|
2728
|
-
"{{.
|
|
4077
|
+
"{{.Created}}",
|
|
2729
4078
|
tag
|
|
2730
|
-
], {
|
|
4079
|
+
], {
|
|
4080
|
+
signal,
|
|
4081
|
+
engine
|
|
4082
|
+
})).exitCode === 0) return tag;
|
|
2731
4083
|
const script = installScript(steps);
|
|
2732
4084
|
const encoded = Buffer.from(script).toString("base64");
|
|
2733
4085
|
const home = `$(getent passwd ${SANDBOX_USER} | cut -d: -f6)`;
|
|
@@ -2750,7 +4102,8 @@ async function buildInstallLayer(parent, steps, options = {}) {
|
|
|
2750
4102
|
"-"
|
|
2751
4103
|
], {
|
|
2752
4104
|
input: dockerfile,
|
|
2753
|
-
signal
|
|
4105
|
+
signal,
|
|
4106
|
+
engine
|
|
2754
4107
|
});
|
|
2755
4108
|
const output = `${build.stdout.toString("utf8")}${build.stderr}`;
|
|
2756
4109
|
options.output?.write(`${script}\n${dockerfile}\n\n${output}`);
|
|
@@ -2760,7 +4113,8 @@ async function buildInstallLayer(parent, steps, options = {}) {
|
|
|
2760
4113
|
stage: "install",
|
|
2761
4114
|
ref: tag,
|
|
2762
4115
|
headline: `Building the install layer (${`${steps.length} command${steps.length === 1 ? "" : "s"}`})`,
|
|
2763
|
-
log: options.output?.path ?? null
|
|
4116
|
+
log: options.output?.path ?? null,
|
|
4117
|
+
engine
|
|
2764
4118
|
}, () => failed ? `install ${failed[1]} exited ${failed[2]}: ${clipLine(failed[3] ?? "")}` : null, (line) => !line.startsWith("reeval: install "));
|
|
2765
4119
|
}
|
|
2766
4120
|
return tag;
|
|
@@ -2820,16 +4174,16 @@ function contextFiles(context, dockerfile) {
|
|
|
2820
4174
|
return files.sort();
|
|
2821
4175
|
}
|
|
2822
4176
|
/** Whether the Dockerfile starts from reeval's sandbox image, which then has to exist first. */
|
|
2823
|
-
const
|
|
4177
|
+
const usesReevalBase = (dockerfile) => new RegExp(`\\$\\{?${REEVAL_BASE_ARG}\\b`).test(readFileSync(dockerfile, "utf8"));
|
|
2824
4178
|
/**
|
|
2825
4179
|
* The tag of a `docker({ dockerfile })` build for a harness: a hash of the Dockerfile, every file
|
|
2826
4180
|
* of its build context (its directory, less `.dockerignore`) and, for a Dockerfile `FROM
|
|
2827
4181
|
* ${REEVAL_BASE}`, the id of the harness's image it names, so an edit to any of them, or a rebuilt reeval
|
|
2828
|
-
* image, builds anew. `
|
|
4182
|
+
* image, builds anew. `reevalBase` is that id (null when it isn't built).
|
|
2829
4183
|
*/
|
|
2830
|
-
function dockerfileTag(dockerfile, harness,
|
|
4184
|
+
function dockerfileTag(dockerfile, harness, reevalBase = null) {
|
|
2831
4185
|
const context = dirname(dockerfile);
|
|
2832
|
-
const base =
|
|
4186
|
+
const base = usesReevalBase(dockerfile) ? `${imageFor(harness)}@${reevalBase ?? "unbuilt"}` : "";
|
|
2833
4187
|
const hash = createHash("sha256").update(`${REEVAL_BASE_ARG}=${base}\0`);
|
|
2834
4188
|
for (const path of contextFiles(context, dockerfile)) {
|
|
2835
4189
|
const full = join(context, path);
|
|
@@ -2846,14 +4200,14 @@ function dockerfileTag(dockerfile, harness, esBase = null) {
|
|
|
2846
4200
|
}
|
|
2847
4201
|
/**
|
|
2848
4202
|
* Builds the user's Dockerfile with plain `docker build` (so Docker's layer cache applies), from
|
|
2849
|
-
* its directory, with `REEVAL_BASE` set to the harness's sandbox image (whose id is `
|
|
4203
|
+
* its directory, with `REEVAL_BASE` set to the harness's sandbox image (whose id is `reevalBase`).
|
|
2850
4204
|
* Rebuilds even when the tag exists with `force`, as `reeval image build` does, and then removes the
|
|
2851
4205
|
* image the tag pointed at before. `name` is the path failures name.
|
|
2852
4206
|
*/
|
|
2853
4207
|
async function buildDockerfile(dockerfile, options) {
|
|
2854
|
-
const { harness, signal } = options;
|
|
2855
|
-
const { tag } = dockerfileTag(dockerfile, harness, options.
|
|
2856
|
-
const previous = (await imageInfo(tag))?.id;
|
|
4208
|
+
const { harness, signal, engine } = options;
|
|
4209
|
+
const { tag } = dockerfileTag(dockerfile, harness, options.reevalBase ?? null);
|
|
4210
|
+
const previous = (await imageInfo(tag, engine))?.id;
|
|
2857
4211
|
if (previous && !options.force) return tag;
|
|
2858
4212
|
const build = await docker([
|
|
2859
4213
|
"build",
|
|
@@ -2868,20 +4222,24 @@ async function buildDockerfile(dockerfile, options) {
|
|
|
2868
4222
|
"--tag",
|
|
2869
4223
|
tag,
|
|
2870
4224
|
dirname(dockerfile)
|
|
2871
|
-
], {
|
|
4225
|
+
], {
|
|
4226
|
+
signal,
|
|
4227
|
+
engine
|
|
4228
|
+
});
|
|
2872
4229
|
const output = `${build.stdout.toString("utf8")}${build.stderr}`;
|
|
2873
4230
|
options.output?.write(output);
|
|
2874
4231
|
if (build.exitCode !== 0) throw buildError(output, {
|
|
2875
4232
|
stage: "dockerfile",
|
|
2876
4233
|
ref: tag,
|
|
2877
4234
|
headline: `Building ${options.name ?? dockerfile}`,
|
|
2878
|
-
log: options.output?.path ?? null
|
|
4235
|
+
log: options.output?.path ?? null,
|
|
4236
|
+
engine
|
|
2879
4237
|
});
|
|
2880
|
-
const now = (await imageInfo(tag))?.id;
|
|
2881
|
-
if (previous && previous !== now) await removeQuietly(previous);
|
|
4238
|
+
const now = (await imageInfo(tag, engine))?.id;
|
|
4239
|
+
if (previous && previous !== now) await removeQuietly(previous, engine);
|
|
2882
4240
|
return tag;
|
|
2883
4241
|
}
|
|
2884
4242
|
//#endregion
|
|
2885
|
-
export {
|
|
4243
|
+
export { removeContainerDetached as $, hostAllowed as A, WORKSPACE_DIR as B, applyTransformations as C, HARNESS_HOSTS as D, DOCKER_EGRESS as E, HARNESS_PACKAGES as F, docker as G, harnessLabel as H, LABEL as I, dockerOk as J, dockerAvailable as K, SANDBOX_HOME as L, BASE_IMAGE as M, BRIDGE_PORT as N, PACKAGE_HOSTS as O, DEFAULT_IMAGE as P, isRegistryDigest as Q, SANDBOX_ROOT as R, placeholder as S, onEndpoint as T, imageFor as U, adapterVersion as V, isBakedHarness as W, imageInfo as X, dockerState as Y, imageTags as Z, ROOT_CAPABILITIES as _, buildInstallLayer as a, isTransient as at, CA_PATH as b, dockerfileTag as c, ENGINES as ct, installLayerTag as d, normalizeImageId as dt, onDockerCommand as et, installScript as f, DEFAULT_LIMITS as g, usesReevalBase as h, buildImage as i, failureCause as it, BAKED_HARNESSES as j, defaultAllowedHosts as k, dockerignoreMatcher as l, dockerSeccompFile as lt, resolveFrom as m, REEVAL_BASE_ARG as n, RETRY_DELAYS as nt, contextFiles as o, parseBuildOutput as ot, pruneImages as p, dockerCapacity as q, buildDockerfile as r, causeLine as rt, contextHash as s, retryTransient as st, DOCKER_CONTEXT as t, ImageBuildError as tt, harnessImageFor as u, engineSpec as ut, createDockerSession as v, matches as w, PROXY_PORT as x, dockerSandboxProvider as y, SANDBOX_USER as z };
|
|
2886
4244
|
|
|
2887
|
-
//# sourceMappingURL=src-
|
|
4245
|
+
//# sourceMappingURL=src-B7treWa8.js.map
|