@poetic-ai/poetic 1.42.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/.github/SECURITY.md +47 -0
- package/.nvmrc +1 -0
- package/.poetic/README.md +37 -0
- package/.poetic/providers/catalog.json +12051 -0
- package/.poetic/providers/pricing.json +1272 -0
- package/.poetic/providers/registry.json +3369 -0
- package/CHANGELOG.md +552 -0
- package/CODE_OF_CONDUCT.md +40 -0
- package/CONTRIBUTING.md +23 -0
- package/INSTALL.md +454 -0
- package/LICENSE +21 -0
- package/README.md +474 -0
- package/dist/BasicOptimizationCompetitionRunner-5H5TBYO4.js +153 -0
- package/dist/ExecutionTracker-UVONC4C6.js +16 -0
- package/dist/OptimizationConfig-7DFY2TST.js +17 -0
- package/dist/OptimizationEngine-JIMGP3LY.js +1597 -0
- package/dist/PromptStore-U6ZD3ZMQ.js +18 -0
- package/dist/actions-LUJPINLJ.js +322 -0
- package/dist/agent-ingest-3DJUJ7FU.js +53 -0
- package/dist/aggregator-DNCBINFO.js +12 -0
- package/dist/ai-judge-5QT5QJVU.js +156 -0
- package/dist/allowlist-grounding-RO6HKUFI.js +16 -0
- package/dist/allowlist-utils-23V7TJ3G.js +28 -0
- package/dist/anchored-turn-service-JULUCUIK.js +489 -0
- package/dist/api-transport-4TYTNLTJ.js +1087 -0
- package/dist/apply-completion-mode-AW2MOS3R.js +89 -0
- package/dist/artifact-migrator-23L45ISD.js +267 -0
- package/dist/ask-HWVV6QFR.js +135 -0
- package/dist/auth-5KEDKAPP.js +67 -0
- package/dist/auth-7TT3JINV.js +78 -0
- package/dist/auth-E6XUNZ5M.js +68 -0
- package/dist/auth-H3XDZE22.js +134 -0
- package/dist/auth-OC4E6633.js +71 -0
- package/dist/auth-S4CTX4GQ.js +44 -0
- package/dist/auth-YLH3S7EY.js +69 -0
- package/dist/auth-liveness-TDDEZY3T.js +46 -0
- package/dist/auto-optimizer-VPRWOWGU.js +80 -0
- package/dist/autoloop-cleanup-JOGKTLWA.js +109 -0
- package/dist/autoloop-evidence-gates-PCDALGVJ.js +38 -0
- package/dist/autoloop-gate-policy-Z7FVJVXV.js +175 -0
- package/dist/autoloop-helpers-2KTK43GL.js +22 -0
- package/dist/autoloop-ledger-W7QO62PX.js +96 -0
- package/dist/autoloop-ledger-subscriber-Z5RW5EIE.js +162 -0
- package/dist/autoloop-run-defaults-FERGRZGP.js +19 -0
- package/dist/autoloop-run-lock-CT2NWSV3.js +197 -0
- package/dist/autoloop-success-J2VKKBXQ.js +85 -0
- package/dist/autoloop-termination-summary-RN75F422.js +58 -0
- package/dist/autoloop-trajectory-XFIEXP5Z.js +282 -0
- package/dist/autoloop-wall-clock-T7ZVIQOC.js +12 -0
- package/dist/autonomous-loop-controller-PW4XVFGQ.js +4120 -0
- package/dist/backend-P3DAYRP7.js +29 -0
- package/dist/background-executor-CBN552V4.js +257 -0
- package/dist/backlog-execution-intent-U4XYPTV6.js +15 -0
- package/dist/backup-active-store-5WXG6SXT.js +17 -0
- package/dist/backup-telemetry-db-XGLXAA3N.js +254 -0
- package/dist/basic-competition-master-VCSBJVRN.js +344 -0
- package/dist/branch-archive-manager-RP6FP3ZC.js +254 -0
- package/dist/branch-cleanup-manager-RSHAI7YR.js +20 -0
- package/dist/build-gate-YHGRB4QB.js +71 -0
- package/dist/change-summary-WY7J5TOX.js +33 -0
- package/dist/chunk-23A26CSN.js +123 -0
- package/dist/chunk-27UTJD3M.js +265 -0
- package/dist/chunk-2A5CILN3.js +310 -0
- package/dist/chunk-2AQUWJPW.js +225 -0
- package/dist/chunk-2BZ53J6J.js +2344 -0
- package/dist/chunk-2DY5KNVM.js +276 -0
- package/dist/chunk-2EIA4RBE.js +659 -0
- package/dist/chunk-2IUXIGQD.js +1064 -0
- package/dist/chunk-2N42MS2Z.js +2193 -0
- package/dist/chunk-2QJ3H3L7.js +42 -0
- package/dist/chunk-2QLYTVYX.js +791 -0
- package/dist/chunk-2VSQMRCB.js +18 -0
- package/dist/chunk-2XQXYBM2.js +130 -0
- package/dist/chunk-2YFUIER7.js +426 -0
- package/dist/chunk-34CNP2HB.js +148 -0
- package/dist/chunk-35P3W3JX.js +456 -0
- package/dist/chunk-36PEBZAF.js +18 -0
- package/dist/chunk-3AOKYKA7.js +22 -0
- package/dist/chunk-3BCUNHKF.js +475 -0
- package/dist/chunk-3FLXLLB7.js +26 -0
- package/dist/chunk-3FOZ2VHV.js +100 -0
- package/dist/chunk-3G6FZCRF.js +106 -0
- package/dist/chunk-3M57DADF.js +44 -0
- package/dist/chunk-3S62LLWJ.js +543 -0
- package/dist/chunk-3ZPQLGV7.js +2904 -0
- package/dist/chunk-44N5WZZH.js +45 -0
- package/dist/chunk-45FPSA3B.js +125 -0
- package/dist/chunk-4BJ3O4RQ.js +929 -0
- package/dist/chunk-4BOP7T6L.js +2321 -0
- package/dist/chunk-4BTDUT2S.js +42 -0
- package/dist/chunk-4CSS7WVI.js +143 -0
- package/dist/chunk-4CUY7AFY.js +247 -0
- package/dist/chunk-4GSN5O5J.js +62 -0
- package/dist/chunk-4HN6DF7V.js +1027 -0
- package/dist/chunk-4IAPOG5V.js +415 -0
- package/dist/chunk-4IYIZQWV.js +48 -0
- package/dist/chunk-4NXPXE62.js +84 -0
- package/dist/chunk-4RCCF5BR.js +712 -0
- package/dist/chunk-4V7NAQ4R.js +19527 -0
- package/dist/chunk-4VJITV4P.js +445 -0
- package/dist/chunk-4YX7J6QL.js +1859 -0
- package/dist/chunk-527OBWQB.js +338 -0
- package/dist/chunk-5D4A7E3D.js +448 -0
- package/dist/chunk-5DLKYTQX.js +4003 -0
- package/dist/chunk-5EERLVZB.js +139 -0
- package/dist/chunk-5H72XE4H.js +256 -0
- package/dist/chunk-5HDP7XZG.js +91 -0
- package/dist/chunk-5LAMRH4X.js +969 -0
- package/dist/chunk-5LTN43AS.js +1972 -0
- package/dist/chunk-5RBHQYDB.js +2206 -0
- package/dist/chunk-5WCQRDRB.js +588 -0
- package/dist/chunk-5WRLK5KW.js +700 -0
- package/dist/chunk-5ZCXC23G.js +595 -0
- package/dist/chunk-6BM72ZMG.js +31 -0
- package/dist/chunk-6EDAJH2I.js +68 -0
- package/dist/chunk-6EQKFDBH.js +457 -0
- package/dist/chunk-6MFRHTRI.js +115 -0
- package/dist/chunk-6TZJRKNW.js +321 -0
- package/dist/chunk-6V7HGQFZ.js +20 -0
- package/dist/chunk-6VWVO2TU.js +3746 -0
- package/dist/chunk-6Y5TWI7H.js +146 -0
- package/dist/chunk-6Y5U7UFY.js +91 -0
- package/dist/chunk-6ZLAK3XG.js +14 -0
- package/dist/chunk-72XCRQED.js +34 -0
- package/dist/chunk-72YTZMAM.js +589 -0
- package/dist/chunk-73BBJOKA.js +263 -0
- package/dist/chunk-73NCTWKL.js +188 -0
- package/dist/chunk-77I6G4CO.js +1 -0
- package/dist/chunk-7DHRDWFS.js +3104 -0
- package/dist/chunk-7DNSNKJV.js +78 -0
- package/dist/chunk-7FMJVYBS.js +307 -0
- package/dist/chunk-7GDRQBQC.js +419 -0
- package/dist/chunk-7GPCEFUV.js +270 -0
- package/dist/chunk-7IL4A2PP.js +948 -0
- package/dist/chunk-7MMLMXO6.js +3679 -0
- package/dist/chunk-7QCZSLBH.js +1 -0
- package/dist/chunk-7R2WLDOS.js +62 -0
- package/dist/chunk-7T7RUJI7.js +949 -0
- package/dist/chunk-A2WKSVX7.js +43 -0
- package/dist/chunk-A3YGID55.js +133 -0
- package/dist/chunk-A722DEVA.js +14 -0
- package/dist/chunk-ACDIT7OP.js +1376 -0
- package/dist/chunk-ACKIPAOJ.js +302 -0
- package/dist/chunk-APPNGGN7.js +365 -0
- package/dist/chunk-APV6MK5E.js +137 -0
- package/dist/chunk-ASEP3M2W.js +968 -0
- package/dist/chunk-AT4TNPWW.js +2931 -0
- package/dist/chunk-ATVKCSGT.js +250 -0
- package/dist/chunk-AURFMVCD.js +899 -0
- package/dist/chunk-AX6GWE7V.js +47 -0
- package/dist/chunk-AY5EWJPF.js +385 -0
- package/dist/chunk-BAV2HJXS.js +194 -0
- package/dist/chunk-BBHRN366.js +89 -0
- package/dist/chunk-BBPSTTPA.js +1004 -0
- package/dist/chunk-BDATUDDJ.js +992 -0
- package/dist/chunk-BKE5PG5L.js +20414 -0
- package/dist/chunk-BLPHWMDK.js +797 -0
- package/dist/chunk-BSE4R6XD.js +322 -0
- package/dist/chunk-BXGMAU4A.js +396 -0
- package/dist/chunk-BXI4NXL3.js +507 -0
- package/dist/chunk-BZU2O43F.js +1125 -0
- package/dist/chunk-C3L6YQ7P.js +147 -0
- package/dist/chunk-C57KJOUQ.js +121 -0
- package/dist/chunk-CCV7BPSY.js +118 -0
- package/dist/chunk-CD7ISXA4.js +826 -0
- package/dist/chunk-CE5OZBYY.js +21 -0
- package/dist/chunk-CFBIG37O.js +154 -0
- package/dist/chunk-CJC6GZ46.js +457 -0
- package/dist/chunk-CKCDGXIV.js +408 -0
- package/dist/chunk-CKNX3TTP.js +10338 -0
- package/dist/chunk-CLKSETWE.js +10 -0
- package/dist/chunk-CP7H3HSP.js +1552 -0
- package/dist/chunk-CPLEWXNZ.js +66 -0
- package/dist/chunk-CQM3A35X.js +844 -0
- package/dist/chunk-CS6P76D3.js +103 -0
- package/dist/chunk-CTLUBNCW.js +622 -0
- package/dist/chunk-CUSRN6RJ.js +632 -0
- package/dist/chunk-D5EP5D2W.js +26 -0
- package/dist/chunk-D5RYINO7.js +412 -0
- package/dist/chunk-DBFS4HMH.js +751 -0
- package/dist/chunk-DC4ZYMXJ.js +115 -0
- package/dist/chunk-DCBZP442.js +9243 -0
- package/dist/chunk-DCYF7EKG.js +26 -0
- package/dist/chunk-DDMAFNUK.js +5351 -0
- package/dist/chunk-DF5SLDE4.js +966 -0
- package/dist/chunk-DJFW7SMX.js +348 -0
- package/dist/chunk-DQFLLBJW.js +121 -0
- package/dist/chunk-DSFM56OA.js +1203 -0
- package/dist/chunk-DTY4APYV.js +218 -0
- package/dist/chunk-DXH5JBRS.js +437 -0
- package/dist/chunk-E3NTPHEO.js +194 -0
- package/dist/chunk-E74LUIID.js +302 -0
- package/dist/chunk-EI57M5BI.js +194 -0
- package/dist/chunk-EJ4ZAWLV.js +305 -0
- package/dist/chunk-EJGCZGUF.js +1483 -0
- package/dist/chunk-EK2U3YEG.js +486 -0
- package/dist/chunk-ELMFYNV7.js +109 -0
- package/dist/chunk-ENRGKNR5.js +25 -0
- package/dist/chunk-ETYDXCK7.js +679 -0
- package/dist/chunk-EYRH3W74.js +239 -0
- package/dist/chunk-F23DIWNN.js +1024 -0
- package/dist/chunk-F5JO7HAS.js +94 -0
- package/dist/chunk-F7ER6ANO.js +174 -0
- package/dist/chunk-FATUVIIN.js +374 -0
- package/dist/chunk-FC23CTXV.js +322 -0
- package/dist/chunk-FD4ERYEG.js +22 -0
- package/dist/chunk-FH7WOJAE.js +79 -0
- package/dist/chunk-FHOWVDF5.js +1342 -0
- package/dist/chunk-FKAUPHMR.js +96 -0
- package/dist/chunk-FONNFJXA.js +137 -0
- package/dist/chunk-FQ7FSZRW.js +75 -0
- package/dist/chunk-FRG57FPM.js +240 -0
- package/dist/chunk-FUVP64ER.js +31 -0
- package/dist/chunk-FYOILAN5.js +6818 -0
- package/dist/chunk-G35UYQ6Z.js +69 -0
- package/dist/chunk-G36W2T2S.js +1143 -0
- package/dist/chunk-G3L2L5XZ.js +49 -0
- package/dist/chunk-G4THLFV3.js +148 -0
- package/dist/chunk-GAFJEYLK.js +29 -0
- package/dist/chunk-GFGYB2ZU.js +1689 -0
- package/dist/chunk-GG6KJYW6.js +85 -0
- package/dist/chunk-GHHFDU2U.js +55 -0
- package/dist/chunk-GHTZSQB7.js +57 -0
- package/dist/chunk-GK37ILCX.js +1231 -0
- package/dist/chunk-GKN3HMN4.js +2809 -0
- package/dist/chunk-GNVDBVJP.js +156 -0
- package/dist/chunk-GPEL3FBM.js +924 -0
- package/dist/chunk-GPSNGPZS.js +1604 -0
- package/dist/chunk-GSGD5E4C.js +30 -0
- package/dist/chunk-GSUQJJXQ.js +331 -0
- package/dist/chunk-GSV226X6.js +110 -0
- package/dist/chunk-H2AYQIHW.js +224 -0
- package/dist/chunk-H66DXFS5.js +1374 -0
- package/dist/chunk-H6G7QRMQ.js +35 -0
- package/dist/chunk-H7JAGHZT.js +59 -0
- package/dist/chunk-H7ZEFECA.js +316 -0
- package/dist/chunk-HAC6EHZZ.js +79 -0
- package/dist/chunk-HIO33P3G.js +19 -0
- package/dist/chunk-HMVQIPH3.js +547 -0
- package/dist/chunk-HOYBYAOA.js +257 -0
- package/dist/chunk-HX5P3CSP.js +1784 -0
- package/dist/chunk-I46EG2XQ.js +65 -0
- package/dist/chunk-I4NPDSCB.js +279 -0
- package/dist/chunk-I5WRT7ZR.js +514 -0
- package/dist/chunk-IC7I6YIJ.js +301 -0
- package/dist/chunk-IDCSOZVN.js +78 -0
- package/dist/chunk-IFCBYECK.js +112 -0
- package/dist/chunk-IFZCPEY2.js +66 -0
- package/dist/chunk-IKFP2KUR.js +48 -0
- package/dist/chunk-IRFBN336.js +878 -0
- package/dist/chunk-IUXNGKA6.js +152 -0
- package/dist/chunk-IV2RVAN7.js +1356 -0
- package/dist/chunk-IZYIQQ7X.js +53 -0
- package/dist/chunk-J3UUR7DE.js +210 -0
- package/dist/chunk-J54VUAY2.js +566 -0
- package/dist/chunk-J62KPGII.js +464 -0
- package/dist/chunk-J6P3FWWW.js +130 -0
- package/dist/chunk-JKBHJQMT.js +434 -0
- package/dist/chunk-JLS65NUQ.js +14 -0
- package/dist/chunk-JOSYEJKY.js +141 -0
- package/dist/chunk-JPKSXKNB.js +94 -0
- package/dist/chunk-JQNJB2BB.js +2440 -0
- package/dist/chunk-JRVNSWSQ.js +2626 -0
- package/dist/chunk-JSWMRQYG.js +28 -0
- package/dist/chunk-JZKNBBIB.js +152 -0
- package/dist/chunk-K54Y7MLK.js +160 -0
- package/dist/chunk-K65546RE.js +183 -0
- package/dist/chunk-KM3F7SYE.js +702 -0
- package/dist/chunk-KNDYMVWN.js +102 -0
- package/dist/chunk-KNT72VR6.js +132 -0
- package/dist/chunk-KP6YILMU.js +482 -0
- package/dist/chunk-KQEBSK3T.js +274 -0
- package/dist/chunk-KT6VHSPF.js +84 -0
- package/dist/chunk-KTMW65UX.js +14 -0
- package/dist/chunk-KZ5CJVBP.js +1813 -0
- package/dist/chunk-L4427KOE.js +26 -0
- package/dist/chunk-L6OM4A22.js +189 -0
- package/dist/chunk-L7E6XCRA.js +1042 -0
- package/dist/chunk-L7JZLXQL.js +173 -0
- package/dist/chunk-LAMKBTXX.js +40 -0
- package/dist/chunk-LDCF2MKN.js +132 -0
- package/dist/chunk-LEIIWPWQ.js +78 -0
- package/dist/chunk-LFTQVYBB.js +31 -0
- package/dist/chunk-LG3PDRTR.js +2872 -0
- package/dist/chunk-LGHII5ET.js +23 -0
- package/dist/chunk-LH5QY22X.js +1205 -0
- package/dist/chunk-LIVJ6266.js +438 -0
- package/dist/chunk-LKRAR3IH.js +276 -0
- package/dist/chunk-LO23NABI.js +3063 -0
- package/dist/chunk-LO3X5NLS.js +326 -0
- package/dist/chunk-LPITVM7M.js +339 -0
- package/dist/chunk-LR5IJIGV.js +810 -0
- package/dist/chunk-LRGMHROI.js +79 -0
- package/dist/chunk-LUVKFFWR.js +315 -0
- package/dist/chunk-LWCBNGH6.js +35 -0
- package/dist/chunk-LWTN3WRV.js +260 -0
- package/dist/chunk-M3HQYKQX.js +308 -0
- package/dist/chunk-M6GVSPEH.js +1016 -0
- package/dist/chunk-MF5HP6XV.js +221 -0
- package/dist/chunk-MHLCBZJB.js +328 -0
- package/dist/chunk-MN6PL4AN.js +120 -0
- package/dist/chunk-MOEY65Z6.js +5678 -0
- package/dist/chunk-MQ4WA34C.js +206 -0
- package/dist/chunk-MWHF5V7U.js +223 -0
- package/dist/chunk-MWHLBPNU.js +211 -0
- package/dist/chunk-MWK5UZQ3.js +1068 -0
- package/dist/chunk-MYLH2S4G.js +64 -0
- package/dist/chunk-MZ5WYKNA.js +28 -0
- package/dist/chunk-N4VTRA7K.js +131 -0
- package/dist/chunk-N5DX4JAK.js +12 -0
- package/dist/chunk-N65O4XTH.js +5011 -0
- package/dist/chunk-NEQUQHOX.js +223 -0
- package/dist/chunk-NGK6PEOG.js +25 -0
- package/dist/chunk-NJVD4PWE.js +1033 -0
- package/dist/chunk-NM6PMYY4.js +768 -0
- package/dist/chunk-NN4PJDHP.js +708 -0
- package/dist/chunk-NP2V3L7K.js +226 -0
- package/dist/chunk-NRLY536M.js +260 -0
- package/dist/chunk-NRNE225N.js +1270 -0
- package/dist/chunk-NS2K2GTP.js +605 -0
- package/dist/chunk-NS33V3IM.js +51 -0
- package/dist/chunk-NSHASMZZ.js +71 -0
- package/dist/chunk-NWOYOA6H.js +378 -0
- package/dist/chunk-NWRUSEXG.js +322 -0
- package/dist/chunk-NZGDAWIP.js +1905 -0
- package/dist/chunk-O47UOKU3.js +395 -0
- package/dist/chunk-O4G2W3ST.js +9831 -0
- package/dist/chunk-O6V4PNLO.js +63 -0
- package/dist/chunk-OA4GPILI.js +624 -0
- package/dist/chunk-OGMSYL6J.js +227 -0
- package/dist/chunk-OIS7J26S.js +319 -0
- package/dist/chunk-OMX5VL43.js +79 -0
- package/dist/chunk-ON3G73BU.js +264 -0
- package/dist/chunk-OPYFYTWQ.js +220 -0
- package/dist/chunk-OQ6K46CK.js +1734 -0
- package/dist/chunk-OYZYO7TV.js +47 -0
- package/dist/chunk-OZ4REHIN.js +4386 -0
- package/dist/chunk-P47VN5F4.js +282 -0
- package/dist/chunk-P5I4X7A7.js +353 -0
- package/dist/chunk-P6VQROCO.js +594 -0
- package/dist/chunk-P7CQGPLS.js +30 -0
- package/dist/chunk-PCAGC5MR.js +1763 -0
- package/dist/chunk-PFTQBXS6.js +5181 -0
- package/dist/chunk-PGSPX4SU.js +15 -0
- package/dist/chunk-PIKLF7BM.js +432 -0
- package/dist/chunk-PJWJ3SAV.js +22 -0
- package/dist/chunk-PKIFMV72.js +100 -0
- package/dist/chunk-PL37JDNA.js +189 -0
- package/dist/chunk-PTH5E5XO.js +195 -0
- package/dist/chunk-PW6AXLQC.js +4128 -0
- package/dist/chunk-PYITM4N2.js +79 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-Q3RO7N35.js +45 -0
- package/dist/chunk-Q3WIC6GQ.js +2670 -0
- package/dist/chunk-Q5XIXSHX.js +271 -0
- package/dist/chunk-QGJDMEOV.js +34 -0
- package/dist/chunk-QNOB37UH.js +58 -0
- package/dist/chunk-QOCOVLUH.js +462 -0
- package/dist/chunk-QTCJ5CC5.js +172 -0
- package/dist/chunk-QVFV5IP2.js +232 -0
- package/dist/chunk-QVZMFDYG.js +29 -0
- package/dist/chunk-R35PEUKH.js +511 -0
- package/dist/chunk-R4UWBC35.js +200 -0
- package/dist/chunk-R6MLCREW.js +44 -0
- package/dist/chunk-R6W23LKN.js +254 -0
- package/dist/chunk-R7XDDX2A.js +4007 -0
- package/dist/chunk-RDFRCT64.js +168 -0
- package/dist/chunk-RE5VZDFQ.js +58 -0
- package/dist/chunk-RGROYC2G.js +638 -0
- package/dist/chunk-RGWHUI5E.js +68 -0
- package/dist/chunk-RHVG6UNL.js +205 -0
- package/dist/chunk-RI4EX2QE.js +18 -0
- package/dist/chunk-RJAAKDRX.js +17 -0
- package/dist/chunk-ROMHOSMQ.js +185 -0
- package/dist/chunk-RWREC3KJ.js +517 -0
- package/dist/chunk-RYNETRDJ.js +118 -0
- package/dist/chunk-RZY7RKM5.js +500 -0
- package/dist/chunk-S2MNWFAG.js +52 -0
- package/dist/chunk-S2VQCZO4.js +22 -0
- package/dist/chunk-S54MKU6V.js +117 -0
- package/dist/chunk-S5OIDFRM.js +302 -0
- package/dist/chunk-SCW4ZF6R.js +150 -0
- package/dist/chunk-SLS2N4PH.js +2213 -0
- package/dist/chunk-SNLBO4BF.js +247 -0
- package/dist/chunk-SP3LFU6B.js +60 -0
- package/dist/chunk-SQQTDDQA.js +537 -0
- package/dist/chunk-STV6LYYE.js +45 -0
- package/dist/chunk-SURZ2WFE.js +326 -0
- package/dist/chunk-SZ7DL357.js +1047 -0
- package/dist/chunk-T5E4NQCM.js +5742 -0
- package/dist/chunk-TAJPCXSB.js +13 -0
- package/dist/chunk-TAOOYK3P.js +358 -0
- package/dist/chunk-TDSEX5CF.js +24 -0
- package/dist/chunk-TFTGP7Z7.js +174 -0
- package/dist/chunk-TGON4N4O.js +197 -0
- package/dist/chunk-TGQZHDY2.js +2373 -0
- package/dist/chunk-TJJZ2OKV.js +6783 -0
- package/dist/chunk-TRSVUPCX.js +25 -0
- package/dist/chunk-TSXGRLPR.js +107 -0
- package/dist/chunk-U2S3YEX3.js +224 -0
- package/dist/chunk-U45RTRGY.js +818 -0
- package/dist/chunk-U6C3VVWS.js +13 -0
- package/dist/chunk-UDMS5AD3.js +307 -0
- package/dist/chunk-UGX7GI37.js +94 -0
- package/dist/chunk-UH3JJSHK.js +1 -0
- package/dist/chunk-UHRBTZYY.js +208 -0
- package/dist/chunk-UHT2KRG5.js +193 -0
- package/dist/chunk-UI2F6DJ5.js +118 -0
- package/dist/chunk-UMAKSB4Z.js +284 -0
- package/dist/chunk-UR2IBGIM.js +521 -0
- package/dist/chunk-UUH2RVKS.js +585 -0
- package/dist/chunk-UVJ4PJDK.js +4533 -0
- package/dist/chunk-V53UG2OT.js +9924 -0
- package/dist/chunk-V72RMBM4.js +48 -0
- package/dist/chunk-VBNCKCCI.js +16 -0
- package/dist/chunk-VNSYKC25.js +24 -0
- package/dist/chunk-VPHVFK4A.js +1984 -0
- package/dist/chunk-VTLNJQ44.js +133 -0
- package/dist/chunk-VTW7HP3R.js +100 -0
- package/dist/chunk-VVGEPBPS.js +218 -0
- package/dist/chunk-VVLLL7I4.js +166 -0
- package/dist/chunk-VX3UMWB7.js +483 -0
- package/dist/chunk-VXF4Q3FW.js +20 -0
- package/dist/chunk-W3JMT2YY.js +712 -0
- package/dist/chunk-WDUORIHF.js +877 -0
- package/dist/chunk-WDVTY4U6.js +148 -0
- package/dist/chunk-WIFZCHEG.js +12566 -0
- package/dist/chunk-WIRN3F75.js +736 -0
- package/dist/chunk-WMPU2UOV.js +82 -0
- package/dist/chunk-WTOKKE2V.js +784 -0
- package/dist/chunk-WX5IRLF6.js +740 -0
- package/dist/chunk-WZ6U3O7I.js +1581 -0
- package/dist/chunk-XAONGNST.js +57 -0
- package/dist/chunk-XB5YLCLB.js +13 -0
- package/dist/chunk-XEP5NQ5Y.js +688 -0
- package/dist/chunk-XGYF2QMZ.js +351 -0
- package/dist/chunk-XHEKQENB.js +255 -0
- package/dist/chunk-XNO4FM6X.js +1124 -0
- package/dist/chunk-XPHKYHO4.js +878 -0
- package/dist/chunk-XPK2I4NC.js +405 -0
- package/dist/chunk-XPU2XADL.js +2175 -0
- package/dist/chunk-XQD2B6BB.js +507 -0
- package/dist/chunk-XT2ZQVTC.js +558 -0
- package/dist/chunk-XTXJGGUV.js +351 -0
- package/dist/chunk-XUXVDPSZ.js +50 -0
- package/dist/chunk-XV7NZL4B.js +57 -0
- package/dist/chunk-XZE4XARH.js +563 -0
- package/dist/chunk-XZYR5EDO.js +152 -0
- package/dist/chunk-Y3J4JMTU.js +61 -0
- package/dist/chunk-Y55LZN5U.js +52 -0
- package/dist/chunk-Y5VN7DMP.js +112 -0
- package/dist/chunk-Y67VAHN4.js +459 -0
- package/dist/chunk-YAXSKEUH.js +3544 -0
- package/dist/chunk-YB3JD4E6.js +975 -0
- package/dist/chunk-YESZJFK6.js +220 -0
- package/dist/chunk-YGXKOBQQ.js +292 -0
- package/dist/chunk-YMX76IOS.js +31 -0
- package/dist/chunk-YOTXESEH.js +257 -0
- package/dist/chunk-YTYIEZQY.js +119 -0
- package/dist/chunk-YVORHQ2S.js +579 -0
- package/dist/chunk-Z2CUQDAR.js +3429 -0
- package/dist/chunk-Z2KYOFHS.js +7000 -0
- package/dist/chunk-Z6PC7QX6.js +161 -0
- package/dist/chunk-ZDTGECTN.js +235 -0
- package/dist/chunk-ZIPWI2LY.js +151 -0
- package/dist/chunk-ZSKKMTQJ.js +554 -0
- package/dist/chunk-ZTT5IVPY.js +1160 -0
- package/dist/chunk-ZX65UI5W.js +78 -0
- package/dist/chunk-ZYG7GGKO.js +218 -0
- package/dist/chunk-ZZZUL4OF.js +38 -0
- package/dist/cli-utils-IXL26KJT.js +40 -0
- package/dist/cli-validation-WLXWLUJL.js +111 -0
- package/dist/commit-utils-P7CRJF5N.js +202 -0
- package/dist/compete-config-resolver-R5ULXMYH.js +76 -0
- package/dist/compete-request-62JESVET.js +364 -0
- package/dist/compete-results-QEPG6FZX.js +208 -0
- package/dist/competition-outcome-tracker-R32OOZ43.js +38 -0
- package/dist/config-JCOKXOQT.js +166 -0
- package/dist/config-audit-EL3GHXS7.js +360 -0
- package/dist/config-explain-TNILDEVJ.js +12 -0
- package/dist/config-loader-VPFPFO4B.js +38 -0
- package/dist/config-manager-7T4E2BQO.js +67 -0
- package/dist/config-validator-KKOHOW7O.js +72 -0
- package/dist/cost-YC42XUF3.js +53 -0
- package/dist/coverage-orchestrator-CISNKJC2.js +772 -0
- package/dist/coverage-scanner-YVD62MLH.js +12 -0
- package/dist/createCompetitionRunner-LJG6ZQSO.js +46 -0
- package/dist/data-migration-state-VJK64DLT.js +31 -0
- package/dist/db-migrator-XSEIOGWY.js +34 -0
- package/dist/discovery-JGYGDD25.js +25 -0
- package/dist/doctor-GJOYE7AE.js +186 -0
- package/dist/domain-analyzer-AWF3RP6E.js +29 -0
- package/dist/ensure-initialized-744DIZEZ.js +52 -0
- package/dist/entry.js +940 -0
- package/dist/environment-YS45U5ZI.js +81 -0
- package/dist/error-parser-core-PPZ36A4S.js +50 -0
- package/dist/escalation-ladder-MKTCEGSA.js +130 -0
- package/dist/evaluation-context-KV4GZNN7.js +35 -0
- package/dist/evidence-plan-resolver-GBSYSAPX.js +85 -0
- package/dist/execution-data-writer-3ODTBDLH.js +53 -0
- package/dist/execution-policy-applier-ZHD3DCF3.js +31 -0
- package/dist/execution-preflight-Z4Y64V3I.js +209 -0
- package/dist/execution-roles-R3DPPMD3.js +66 -0
- package/dist/exit-code-error-Z4SW2DVK.js +14 -0
- package/dist/external-temp-cleanup-N2RZH4QP.js +311 -0
- package/dist/factory-XBN7DFIM.js +149 -0
- package/dist/file-utils-XIVR2ZMA.js +47 -0
- package/dist/flywheel-autoloop-executor-UILGOFFK.js +249 -0
- package/dist/flywheel-competition-executor-JOBEXTRB.js +259 -0
- package/dist/flywheel-executor-6JFLA6J5.js +369 -0
- package/dist/flywheel-git-isolation-UC5NIEVU.js +48 -0
- package/dist/flywheel-manifest-5UC4VBMA.js +108 -0
- package/dist/flywheel-model-defaults-7CVKP53V.js +27 -0
- package/dist/flywheel-preflight-XEY5SHM6.js +104 -0
- package/dist/flywheel-resume-7HELH7QS.js +23 -0
- package/dist/flywheel-safety-7U7DPOAP.js +28 -0
- package/dist/flywheel-scope-decision-ZHKF6ZIN.js +11 -0
- package/dist/get-telemetry-logger-DPVWWIYY.js +73 -0
- package/dist/git-worktree-IY6V6DUO.js +18 -0
- package/dist/github-pr-manager-4LXEKJTA.js +211 -0
- package/dist/guidance-profile-config-E7XJL2VP.js +117 -0
- package/dist/guidance-profile-renderer-QK2YMAAP.js +21 -0
- package/dist/index-query-4JEUKA44.js +31 -0
- package/dist/index.js +108661 -0
- package/dist/instructions-6BURLQJC.js +64 -0
- package/dist/invoke-provider-auth-GRUYP44M.js +223 -0
- package/dist/judge-scoring.json +80 -0
- package/dist/judge-test.js +555 -0
- package/dist/lab-mode-OTWVHN63.js +39 -0
- package/dist/lab-utils-BJRFLGK4.js +23 -0
- package/dist/linux-host-class-UY4KVLFD.js +29 -0
- package/dist/llm-judge-executor-F7Z3HO77.js +133 -0
- package/dist/local-executor-CEHWE2PL.js +223 -0
- package/dist/logger-33TR6EE5.js +72 -0
- package/dist/loop-spec-XTLQAVZ7.js +191 -0
- package/dist/manager-2HJG5CLT.js +25 -0
- package/dist/matrix-prompt-builder-6UDN5X3F.js +497 -0
- package/dist/matrix-result-parser-7W35EUOV.js +15 -0
- package/dist/metadata-HQ43NDEK.js +22 -0
- package/dist/model-invocations-db-QBO4Y7WZ.js +38 -0
- package/dist/monitor-XGYBG2DW.js +72 -0
- package/dist/next-PB5ZXZKB.js +90 -0
- package/dist/next-ZBDK725T.js +69 -0
- package/dist/optimization-config-resolver-O6WKR47U.js +75 -0
- package/dist/package-3YCWIQQ5.js +10 -0
- package/dist/parallel-orchestrator-NL7YJJU2.js +297 -0
- package/dist/parallel-worker.js +279 -0
- package/dist/parse-git-status-PIAF3OTP.js +10 -0
- package/dist/path-security-ETTH6TZL.js +39 -0
- package/dist/pattern-bank-UNJR5ADV.js +15 -0
- package/dist/plan-backlog-list-fast-VAGYBV3J.js +270 -0
- package/dist/plan-backlog-show-fast-SG2CZPW3.js +406 -0
- package/dist/plan-sprint-list-fast-LURAX47V.js +162 -0
- package/dist/plan-sprint-status-fast-FJAODCHD.js +208 -0
- package/dist/plan-task-status-fast-HNYBMQI4.js +349 -0
- package/dist/plan-to-flywheel-Z4U3GWPN.js +456 -0
- package/dist/planning-backlog-3CQ5QQBQ.js +319 -0
- package/dist/poetic-root-V5DNXEAE.js +17 -0
- package/dist/preflight-OPANWMME.js +12 -0
- package/dist/process-registry-PDZJPTAS.js +27 -0
- package/dist/process-scanner-C22SYXYD.js +22 -0
- package/dist/processes-KMQUD7HY.js +29 -0
- package/dist/processes-json-fast-IBDXZ6WW.js +135 -0
- package/dist/profile-SE5EVXAP.js +149 -0
- package/dist/prompts-WZZPGWBX.js +168 -0
- package/dist/protected-branches-RNTEX7ET.js +57 -0
- package/dist/provider-aware-resource-manager-QBTZJMNP.js +18 -0
- package/dist/provider-matrix-N5X57V3Y.js +154 -0
- package/dist/provider-matrix-renderer-MZDWKKID.js +139 -0
- package/dist/provider-output-forwarding-DERID3TP.js +30 -0
- package/dist/provider-registry-J5NRBJKI.js +128 -0
- package/dist/provider-temp-cleanup-KYGLF6YU.js +14 -0
- package/dist/prune-engine-Q6E2DXBN.js +451 -0
- package/dist/quality-gate-YRHMQAEI.js +70 -0
- package/dist/quickstart-FIRLKGJI.js +62 -0
- package/dist/readiness-VZTMSG6J.js +96 -0
- package/dist/registry-YODFY77A.js +153 -0
- package/dist/repair-helpers-TTV5FEF4.js +117 -0
- package/dist/repo-root-2IGD4H7X.js +22 -0
- package/dist/resolution-engine-D6TX6FRG.js +127 -0
- package/dist/resolve-provider-cli-O2P6XZBZ.js +35 -0
- package/dist/restore-telemetry-db-BQL6DTQF.js +360 -0
- package/dist/result-streamer-WEHW476R.js +19 -0
- package/dist/routing-events-DHPUZDDF.js +27 -0
- package/dist/routing-history-store-UWCEXAP3.js +46 -0
- package/dist/routing-planner-F5WQEUOM.js +160 -0
- package/dist/run-poetic-tui-J6LWRJUP.js +13517 -0
- package/dist/run-simulation.js +376 -0
- package/dist/runner-CS2TNGHA.js +1092 -0
- package/dist/runner-HHH7ZN2Z.js +1571 -0
- package/dist/safety-OCC4KJJR.js +64 -0
- package/dist/safety-stanza-7SV3HGG3.js +60 -0
- package/dist/sandbox-32QXJEMV.js +81 -0
- package/dist/sandbox-RSO7VP6V.js +94 -0
- package/dist/schema-extensions.sql +234 -0
- package/dist/security-2KI5XNDG.js +17 -0
- package/dist/setup-bb-plugin-QAQWZCV5.js +738 -0
- package/dist/setup-claude-code-P7BTTSPO.js +317 -0
- package/dist/setup-temp-cleanup-GASCWZ2I.js +20 -0
- package/dist/shared-utils-D6U6UREP.js +37 -0
- package/dist/simple-artifact-goal-OTXNGZY6.js +25 -0
- package/dist/sprint-UIXPYOXQ.js +338 -0
- package/dist/sprint-bridge-4BHMSC3M.js +68 -0
- package/dist/sprint-execution-service-2B7WHL5L.js +311 -0
- package/dist/sprint-manager-IDQUDNQI.js +91 -0
- package/dist/sqlite-wrapper-UDWCTNLJ.js +17 -0
- package/dist/stale-cleanup-orchestrator-XWXV7KCZ.js +62 -0
- package/dist/storage-access-F6ALDN4S.js +22 -0
- package/dist/synthesis-XD6EDVHF.js +185 -0
- package/dist/task-classifier-LNLXSHOM.js +494 -0
- package/dist/task-list-fast-PTMA4LUC.js +147 -0
- package/dist/task-manager-XAT7GOWB.js +93 -0
- package/dist/task-splitter-U7DJ7W6A.js +79 -0
- package/dist/task-type-detector-OLVOMXZO.js +21 -0
- package/dist/task-type-resolver-KKNQYSB4.js +42 -0
- package/dist/telemetry-5HWBBXLX.js +131 -0
- package/dist/telemetry-health-tracker-DMSSGBZ2.js +11 -0
- package/dist/telemetry-path-resolver-7ICSG276.js +28 -0
- package/dist/telemetry-reliability-XUOZNZZ6.js +125 -0
- package/dist/token-estimator-MEQUL3EJ.js +37 -0
- package/dist/transports-KNSSV2V4.js +255 -0
- package/dist/unified-cost-tracker-4TFRBVPR.js +35 -0
- package/dist/unified-state-cleanup-LJPF2BOW.js +276 -0
- package/dist/universal-cost-calculator-BAJV35GA.js +42 -0
- package/dist/user-agents-GHUGCSKN.js +22 -0
- package/dist/variant-delivery-state-KLRNG6XA.js +33 -0
- package/dist/variant-state-cleanup-MZGGLQAJ.js +280 -0
- package/dist/variant-success-PJXWE3ZV.js +12 -0
- package/dist/variant-worker-KUWKBLAH.js +4196 -0
- package/dist/variant-worker.js +24 -0
- package/dist/variants-JE2FSAQS.js +233 -0
- package/dist/verification-toolchains-V24UHW6Q.js +28 -0
- package/dist/verify-commands-H3DTCSGI.js +37 -0
- package/dist/warning-EGQGUUIO.js +12 -0
- package/dist/work-edge-RWEDWJZF.js +49 -0
- package/dist/work-item-writer-WHAVZXAY.js +19 -0
- package/dist/worker-7SA2VS2Y.js +1435 -0
- package/dist/worker.js +19 -0
- package/dist/worktree-metrics-3DFUYVYE.js +26 -0
- package/dist/writeback-VZKHYHSN.js +44 -0
- package/docs/CLI_REFERENCE.md +7042 -0
- package/docs/PROVIDER_SETUP.md +1570 -0
- package/docs/README.md +96 -0
- package/docs/TROUBLESHOOTING.md +2232 -0
- package/docs/getting-started/QUICK_START.md +294 -0
- package/docs/getting-started/README.md +188 -0
- package/docs/getting-started/SETUP.md +52 -0
- package/docs/reference/AGENT_CONTEXT.md +38 -0
- package/docs/reference/PROVIDER_RELEASE_TIERS.md +34 -0
- package/docs/reference/README.md +381 -0
- package/docs/reference/SECURITY.md +262 -0
- package/integrations/bb-plugin-poetic/README.md +362 -0
- package/integrations/bb-plugin-poetic/app.css +341 -0
- package/integrations/bb-plugin-poetic/app.tsx +5059 -0
- package/integrations/bb-plugin-poetic/package.json +45 -0
- package/integrations/bb-plugin-poetic/server.ts +444 -0
- package/integrations/bb-plugin-poetic/src/adapter.ts +3312 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-model.ts +150 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-schema.ts +355 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-service.ts +419 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-view.ts +1026 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-schema.ts +122 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-service.ts +105 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-view.ts +138 -0
- package/integrations/bb-plugin-poetic/src/contract.ts +615 -0
- package/integrations/bb-plugin-poetic/src/finalize-model.ts +205 -0
- package/integrations/bb-plugin-poetic/src/finalize-schema.ts +158 -0
- package/integrations/bb-plugin-poetic/src/finalize-service.ts +382 -0
- package/integrations/bb-plugin-poetic/src/finalize-view.ts +159 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-readback.ts +303 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-schema.ts +33 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-view.ts +459 -0
- package/integrations/bb-plugin-poetic/src/model.ts +1302 -0
- package/integrations/bb-plugin-poetic/src/monitor-service.ts +233 -0
- package/integrations/bb-plugin-poetic/src/panel-read-ux.ts +97 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-schema.ts +166 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-service.ts +480 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-view.ts +109 -0
- package/integrations/bb-plugin-poetic/src/planning-readback.ts +204 -0
- package/integrations/bb-plugin-poetic/src/planning-service.ts +594 -0
- package/integrations/bb-plugin-poetic/src/planning-workspace-schema.ts +95 -0
- package/integrations/bb-plugin-poetic/src/planning-workspace.ts +323 -0
- package/integrations/bb-plugin-poetic/src/poll-handoff.ts +136 -0
- package/integrations/bb-plugin-poetic/src/project-target-server.ts +21 -0
- package/integrations/bb-plugin-poetic/src/project-target.ts +45 -0
- package/integrations/bb-plugin-poetic/src/reference-index.ts +192 -0
- package/integrations/bb-plugin-poetic/src/repository-schema.ts +30 -0
- package/integrations/bb-plugin-poetic/src/result-explorer-view.ts +597 -0
- package/integrations/bb-plugin-poetic/src/result-readback-model.ts +163 -0
- package/integrations/bb-plugin-poetic/src/result-readback-schema.ts +319 -0
- package/integrations/bb-plugin-poetic/src/result-readback-service.ts +333 -0
- package/integrations/bb-plugin-poetic/src/run-page-view.ts +177 -0
- package/integrations/bb-plugin-poetic/src/setup-config-schema.ts +291 -0
- package/integrations/bb-plugin-poetic/src/setup-config-service.ts +590 -0
- package/integrations/bb-plugin-poetic/src/setup-config-view.ts +413 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-model.ts +150 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-schema.ts +136 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-service.ts +341 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-view.ts +116 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-model.ts +714 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-readback.ts +231 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-schema.ts +601 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-service.ts +775 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-view.ts +1221 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-model.ts +567 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-schema.ts +635 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-service.ts +842 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-view.ts +1227 -0
- package/integrations/bb-plugin-poetic/src/task-detail-readback.ts +56 -0
- package/integrations/bb-plugin-poetic/src/task-detail-schema.ts +144 -0
- package/integrations/bb-plugin-poetic/src/task-navigation.ts +446 -0
- package/integrations/bb-plugin-poetic/src/workbench-route.ts +74 -0
- package/integrations/bb-plugin-poetic/tests/host-contract.test.ts +773 -0
- package/integrations/bb-plugin-poetic/tsconfig.json +18 -0
- package/integrations/bb-plugin-poetic/types/PROVENANCE.json +52 -0
- package/integrations/bb-plugin-poetic/types/bb-plugin-sdk-app.d.ts +1444 -0
- package/integrations/bb-plugin-poetic/types/bb-plugin-sdk.d.ts +13030 -0
- package/integrations/bb-plugin-poetic/vitest.host.config.ts +71 -0
- package/npm-shrinkwrap.json +4950 -0
- package/package.json +331 -0
- package/schemas/README.md +80 -0
- package/schemas/config-v1.schema.json +136 -0
- package/schemas/execution-config.schema.json +47 -0
- package/schemas/judge-scoring.schema.json +370 -0
- package/schemas/poetic.config.schema.json +2214 -0
- package/schemas/provider-config.schema.json +203 -0
- package/schemas/telemetry-config.schema.json +79 -0
- package/schemas/user-preferences.schema.json +141 -0
- package/scripts/assert-node-runtime.mjs +140 -0
- package/scripts/preflight-native.mjs +49 -0
- package/scripts/preinstall-node-check.mjs +78 -0
- package/scripts/setup-git-hooks.mjs +24 -0
- package/scripts/sync.sh +2722 -0
- package/scripts/write-node-launcher.sh +108 -0
- package/src/resources/gemini/slash-packs/default/plan.toml +15 -0
- package/src/resources/gemini/slash-packs/default/summary.toml +16 -0
- package/src/resources/gemini/slash-packs/default/tests.toml +16 -0
- package/templates/.poetic/README.md +37 -0
- package/templates/.poetic/agents/README.md +296 -0
- package/templates/.poetic/agents/api-documenter.md +147 -0
- package/templates/.poetic/agents/backend-architect.md +31 -0
- package/templates/.poetic/agents/code-reviewer.md +157 -0
- package/templates/.poetic/agents/data-scientist.md +179 -0
- package/templates/.poetic/agents/database-optimizer.md +145 -0
- package/templates/.poetic/agents/debugger.md +31 -0
- package/templates/.poetic/agents/deployment-engineer.md +164 -0
- package/templates/.poetic/agents/devops-troubleshooter.md +139 -0
- package/templates/.poetic/agents/frontend-developer.md +150 -0
- package/templates/.poetic/agents/javascript-pro.md +36 -0
- package/templates/.poetic/agents/performance-engineer.md +151 -0
- package/templates/.poetic/agents/python-pro.md +137 -0
- package/templates/.poetic/agents/test-automator.md +147 -0
- package/templates/.poetic/agents/typescript-pro.md +34 -0
- package/templates/.poetic/config/poetic.config.jsonc +69 -0
- package/templates/.poetic/config/project-context.template.json +6 -0
- package/templates/.poetic/config/task-type-aliases.presets/kanban.yaml +14 -0
- package/templates/.poetic/config/task-type-aliases.presets/scrum.yaml +17 -0
- package/templates/.poetic/config/task-type-aliases.presets/xp.yaml +12 -0
- package/templates/.poetic/config/task-type-aliases.yaml +28 -0
- package/templates/.poetic/gitignore.template +55 -0
- package/templates/.poetic/task-types/analysis.yaml +40 -0
- package/templates/.poetic/task-types/architecture.yaml +38 -0
- package/templates/.poetic/task-types/doc.yaml +35 -0
- package/templates/.poetic/task-types/feature.yaml +23 -0
- package/templates/.poetic/task-types/general.yaml +6 -0
- package/templates/.poetic/task-types/security.yaml +39 -0
- package/templates/AGENTS.template.md +99 -0
- package/templates/CLAUDE.template.md +1 -0
- package/templates/GEMINI.template.md +1 -0
- package/templates/builtin-workflows/code-review.yaml +73 -0
- package/templates/builtin-workflows/compete-streak.yaml +78 -0
- package/templates/builtin-workflows/hello-verify.yaml +10 -0
- package/templates/builtin-workflows/judge-regression.yaml +114 -0
- package/templates/builtin-workflows/skills/code-review/SKILL.md +60 -0
- package/templates/builtin-workflows/skills/hello-verify/SKILL.md +6 -0
- package/templates/guard-kit/GUARD_SETUP.md.template +255 -0
- package/templates/guard-kit/check.mjs.template +777 -0
- package/templates/guard-kit/config.json.template +6 -0
- package/templates/guard-kit/poetic-guard.yml.template +189 -0
- package/templates/profiles/README.md +56 -0
- package/templates/profiles/frontier-claude.json +27 -0
- package/templates/profiles/frontier-codex.json +26 -0
|
@@ -0,0 +1,1763 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatSandboxCapabilityFailure,
|
|
3
|
+
getAllProviderWritePathSpecs,
|
|
4
|
+
getProviderAuthorityWriteDenyPathSpecs,
|
|
5
|
+
getRequiredWritePathsForProvider,
|
|
6
|
+
isAllowedRuntimeWritePath,
|
|
7
|
+
probeProviderSandboxCapability,
|
|
8
|
+
resolveWritePathSpec
|
|
9
|
+
} from "./chunk-5WCQRDRB.js";
|
|
10
|
+
import {
|
|
11
|
+
resolveAllowAwsCredentialRead
|
|
12
|
+
} from "./chunk-5WRLK5KW.js";
|
|
13
|
+
import {
|
|
14
|
+
execGitSync
|
|
15
|
+
} from "./chunk-KNDYMVWN.js";
|
|
16
|
+
import {
|
|
17
|
+
authorizeLinuxHostClassWrites,
|
|
18
|
+
hasContainerOsSignal,
|
|
19
|
+
resolveLinuxHostClass
|
|
20
|
+
} from "./chunk-RWREC3KJ.js";
|
|
21
|
+
import {
|
|
22
|
+
ProviderExecutionError
|
|
23
|
+
} from "./chunk-LUVKFFWR.js";
|
|
24
|
+
import {
|
|
25
|
+
isDebugMode
|
|
26
|
+
} from "./chunk-EJGCZGUF.js";
|
|
27
|
+
import {
|
|
28
|
+
POETIC_SANDBOX_BOUNDARY_POLICY,
|
|
29
|
+
POETIC_SANDBOX_CONTAINER_ATTESTED,
|
|
30
|
+
POETIC_SANDBOX_PROVENANCE,
|
|
31
|
+
readEnv,
|
|
32
|
+
readRawEnv
|
|
33
|
+
} from "./chunk-5DLKYTQX.js";
|
|
34
|
+
|
|
35
|
+
// src/core/sandbox/index.ts
|
|
36
|
+
import fs4 from "fs";
|
|
37
|
+
import os4 from "os";
|
|
38
|
+
|
|
39
|
+
// src/telemetry/sandbox-decision-log.ts
|
|
40
|
+
var SANDBOX_DECISION_EVENT = "sandbox_decision";
|
|
41
|
+
var SANDBOX_CAPABILITY_DENIED_EVENT = "sandbox_capability_denied";
|
|
42
|
+
function buildSandboxDecisionEvent(entry, options = {}) {
|
|
43
|
+
const denial = options.denial ?? false;
|
|
44
|
+
const event = {
|
|
45
|
+
event: denial ? SANDBOX_CAPABILITY_DENIED_EVENT : SANDBOX_DECISION_EVENT,
|
|
46
|
+
providerName: entry.providerName,
|
|
47
|
+
sandboxed: entry.sandboxed,
|
|
48
|
+
platform: entry.platform
|
|
49
|
+
};
|
|
50
|
+
if (entry.providerId !== void 0) event.providerId = entry.providerId;
|
|
51
|
+
if (entry.reason !== void 0) event.reason = entry.reason;
|
|
52
|
+
if (entry.provenance !== void 0) event.provenance = entry.provenance;
|
|
53
|
+
if (entry.boundaryProof !== void 0) event.boundaryProof = entry.boundaryProof;
|
|
54
|
+
if (entry.policyProof !== void 0) event.policyProof = entry.policyProof;
|
|
55
|
+
if (denial && entry.deniedPaths && entry.deniedPaths.length > 0) {
|
|
56
|
+
event.deniedPaths = entry.deniedPaths;
|
|
57
|
+
}
|
|
58
|
+
return event;
|
|
59
|
+
}
|
|
60
|
+
var cachedLogger = null;
|
|
61
|
+
var loaderStarted = false;
|
|
62
|
+
var PENDING_QUEUE_MAX = 32;
|
|
63
|
+
var pendingEvents = [];
|
|
64
|
+
var droppedPendingCount = 0;
|
|
65
|
+
function enqueuePending(payload) {
|
|
66
|
+
pendingEvents.push(payload);
|
|
67
|
+
while (pendingEvents.length > PENDING_QUEUE_MAX) {
|
|
68
|
+
pendingEvents.shift();
|
|
69
|
+
droppedPendingCount += 1;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function flushPending() {
|
|
73
|
+
if (!cachedLogger || pendingEvents.length === 0) return;
|
|
74
|
+
const queued = pendingEvents.splice(0, pendingEvents.length);
|
|
75
|
+
for (const payload of queued) {
|
|
76
|
+
try {
|
|
77
|
+
cachedLogger.logCustomEvent(payload);
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (droppedPendingCount > 0) {
|
|
82
|
+
try {
|
|
83
|
+
cachedLogger.logCustomEvent({
|
|
84
|
+
event: "sandbox_decision_queue_overflow",
|
|
85
|
+
dropped: droppedPendingCount
|
|
86
|
+
});
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
droppedPendingCount = 0;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function ensureLoggerLoading() {
|
|
93
|
+
if (cachedLogger || loaderStarted) return;
|
|
94
|
+
loaderStarted = true;
|
|
95
|
+
void import("./get-telemetry-logger-DPVWWIYY.js").then(({ getTelemetryLogger }) => {
|
|
96
|
+
try {
|
|
97
|
+
cachedLogger = getTelemetryLogger();
|
|
98
|
+
flushPending();
|
|
99
|
+
} catch {
|
|
100
|
+
pendingEvents.length = 0;
|
|
101
|
+
droppedPendingCount = 0;
|
|
102
|
+
}
|
|
103
|
+
}).catch(() => {
|
|
104
|
+
pendingEvents.length = 0;
|
|
105
|
+
droppedPendingCount = 0;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function recordSandboxDecision(entry) {
|
|
109
|
+
try {
|
|
110
|
+
const denial = Boolean(entry.deniedPaths && entry.deniedPaths.length > 0);
|
|
111
|
+
const payload = buildSandboxDecisionEvent(entry, { denial });
|
|
112
|
+
if (!cachedLogger) {
|
|
113
|
+
enqueuePending(payload);
|
|
114
|
+
ensureLoggerLoading();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
cachedLogger.logCustomEvent(payload);
|
|
118
|
+
} catch {
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/core/sandbox/platform.ts
|
|
123
|
+
import { execFileSync } from "child_process";
|
|
124
|
+
import fs from "fs";
|
|
125
|
+
import os from "os";
|
|
126
|
+
import path from "path";
|
|
127
|
+
var cachedSupport = null;
|
|
128
|
+
var loggedUnavailable = false;
|
|
129
|
+
var cachedRestrictiveSupport = null;
|
|
130
|
+
var loggedRestrictiveUnavailable = false;
|
|
131
|
+
var cachedKernelSandboxActive = null;
|
|
132
|
+
var cachedNestedSandboxReinitDenied = null;
|
|
133
|
+
var loggedLinuxHostClassNote = false;
|
|
134
|
+
function findSandboxExecOnPath() {
|
|
135
|
+
const envPath = process.env.PATH ?? "";
|
|
136
|
+
if (!envPath) return null;
|
|
137
|
+
for (const entry of envPath.split(path.delimiter)) {
|
|
138
|
+
if (!entry) continue;
|
|
139
|
+
const candidate = path.join(entry, "sandbox-exec");
|
|
140
|
+
try {
|
|
141
|
+
fs.accessSync(candidate, fs.constants.X_OK);
|
|
142
|
+
return candidate;
|
|
143
|
+
} catch {
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
function resolveSandboxExecPath() {
|
|
149
|
+
try {
|
|
150
|
+
fs.accessSync("/usr/bin/sandbox-exec", fs.constants.X_OK);
|
|
151
|
+
return "/usr/bin/sandbox-exec";
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
return findSandboxExecOnPath();
|
|
155
|
+
}
|
|
156
|
+
function parseExecErrorOutput(error) {
|
|
157
|
+
if (!error || typeof error !== "object") return "";
|
|
158
|
+
const record = error;
|
|
159
|
+
const stderr = typeof record.stderr === "string" ? record.stderr : Buffer.isBuffer(record.stderr) ? record.stderr.toString("utf8") : "";
|
|
160
|
+
const stdout = typeof record.stdout === "string" ? record.stdout : Buffer.isBuffer(record.stdout) ? record.stdout.toString("utf8") : "";
|
|
161
|
+
const message = typeof record.message === "string" ? record.message : "";
|
|
162
|
+
return `${stderr}
|
|
163
|
+
${stdout}
|
|
164
|
+
${message}`.toLowerCase();
|
|
165
|
+
}
|
|
166
|
+
function isSandboxSupported() {
|
|
167
|
+
if (cachedSupport !== null) return cachedSupport;
|
|
168
|
+
if (os.platform() !== "darwin") {
|
|
169
|
+
cachedSupport = false;
|
|
170
|
+
return cachedSupport;
|
|
171
|
+
}
|
|
172
|
+
cachedSupport = resolveSandboxExecPath() !== null;
|
|
173
|
+
return cachedSupport;
|
|
174
|
+
}
|
|
175
|
+
function isSandboxEnforcementSupported() {
|
|
176
|
+
if (cachedRestrictiveSupport !== null) return cachedRestrictiveSupport;
|
|
177
|
+
if (!isSandboxSupported()) {
|
|
178
|
+
cachedRestrictiveSupport = false;
|
|
179
|
+
return cachedRestrictiveSupport;
|
|
180
|
+
}
|
|
181
|
+
if (os.platform() !== "darwin") {
|
|
182
|
+
cachedRestrictiveSupport = false;
|
|
183
|
+
return cachedRestrictiveSupport;
|
|
184
|
+
}
|
|
185
|
+
const sandboxExec = resolveSandboxExecPath();
|
|
186
|
+
if (!sandboxExec) {
|
|
187
|
+
cachedRestrictiveSupport = false;
|
|
188
|
+
return cachedRestrictiveSupport;
|
|
189
|
+
}
|
|
190
|
+
const probeProfile = "(version 1) (deny default) (allow process*) (allow file-read*)";
|
|
191
|
+
try {
|
|
192
|
+
execFileSync(sandboxExec, ["-p", probeProfile, "/usr/bin/true"], {
|
|
193
|
+
stdio: "ignore",
|
|
194
|
+
timeout: 1500
|
|
195
|
+
});
|
|
196
|
+
cachedRestrictiveSupport = true;
|
|
197
|
+
} catch {
|
|
198
|
+
cachedRestrictiveSupport = false;
|
|
199
|
+
}
|
|
200
|
+
return cachedRestrictiveSupport;
|
|
201
|
+
}
|
|
202
|
+
function isKernelSandboxActive() {
|
|
203
|
+
if (cachedKernelSandboxActive !== null) return cachedKernelSandboxActive;
|
|
204
|
+
if (os.platform() !== "darwin") {
|
|
205
|
+
cachedKernelSandboxActive = false;
|
|
206
|
+
return cachedKernelSandboxActive;
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
fs.accessSync("/usr/bin/python3", fs.constants.X_OK);
|
|
210
|
+
} catch {
|
|
211
|
+
cachedKernelSandboxActive = false;
|
|
212
|
+
return cachedKernelSandboxActive;
|
|
213
|
+
}
|
|
214
|
+
const probeScript = [
|
|
215
|
+
"import ctypes, os, sys",
|
|
216
|
+
"lib = ctypes.CDLL('/usr/lib/libSystem.B.dylib')",
|
|
217
|
+
"sandbox_check = lib.sandbox_check",
|
|
218
|
+
"sandbox_check.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int]",
|
|
219
|
+
"sandbox_check.restype = ctypes.c_int",
|
|
220
|
+
"rc = sandbox_check(os.getpid(), None, 0)",
|
|
221
|
+
"sys.stdout.write(str(rc))"
|
|
222
|
+
].join("; ");
|
|
223
|
+
try {
|
|
224
|
+
const output = execFileSync("/usr/bin/python3", ["-c", probeScript], {
|
|
225
|
+
encoding: "utf8",
|
|
226
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
227
|
+
timeout: 1500
|
|
228
|
+
}).toString().trim();
|
|
229
|
+
cachedKernelSandboxActive = output === "1";
|
|
230
|
+
} catch {
|
|
231
|
+
cachedKernelSandboxActive = false;
|
|
232
|
+
}
|
|
233
|
+
return cachedKernelSandboxActive;
|
|
234
|
+
}
|
|
235
|
+
function isNestedSandboxReinitDenied() {
|
|
236
|
+
if (cachedNestedSandboxReinitDenied !== null) return cachedNestedSandboxReinitDenied;
|
|
237
|
+
if (os.platform() !== "darwin") {
|
|
238
|
+
cachedNestedSandboxReinitDenied = false;
|
|
239
|
+
return cachedNestedSandboxReinitDenied;
|
|
240
|
+
}
|
|
241
|
+
const sandboxExec = resolveSandboxExecPath();
|
|
242
|
+
if (!sandboxExec) {
|
|
243
|
+
cachedNestedSandboxReinitDenied = false;
|
|
244
|
+
return cachedNestedSandboxReinitDenied;
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
execFileSync(sandboxExec, ["-p", "(version 1) (allow default)", "/usr/bin/true"], {
|
|
248
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
249
|
+
timeout: 1500
|
|
250
|
+
});
|
|
251
|
+
cachedNestedSandboxReinitDenied = false;
|
|
252
|
+
} catch (error) {
|
|
253
|
+
const message = parseExecErrorOutput(error);
|
|
254
|
+
const status = typeof error === "object" && error !== null && "status" in error ? Number(error.status) : void 0;
|
|
255
|
+
cachedNestedSandboxReinitDenied = status === 71 && (message.includes("sandbox_apply") || message.includes("operation not permitted") || isKernelSandboxActive());
|
|
256
|
+
}
|
|
257
|
+
return cachedNestedSandboxReinitDenied;
|
|
258
|
+
}
|
|
259
|
+
function logSandboxUnavailable() {
|
|
260
|
+
if (loggedUnavailable) return;
|
|
261
|
+
const explicitlyDisabled = process.env.POETIC_SANDBOX_ENABLED === "0";
|
|
262
|
+
if (explicitlyDisabled) return;
|
|
263
|
+
const platform = os.platform();
|
|
264
|
+
const onMacOS = platform === "darwin";
|
|
265
|
+
console.warn(
|
|
266
|
+
"[Sandbox] sandbox-exec unavailable - no self-generated boundary. " + (onMacOS ? "This is unexpected on macOS. Check if sandbox-exec is at /usr/bin/sandbox-exec." : "Sandboxing is only self-generated on macOS. Linux write-capable runs use host class (isolated or a recorded desktop ack), not a Seatbelt profile.")
|
|
267
|
+
);
|
|
268
|
+
loggedUnavailable = true;
|
|
269
|
+
}
|
|
270
|
+
function logLinuxHostClassNote(note) {
|
|
271
|
+
if (loggedLinuxHostClassNote) return;
|
|
272
|
+
if (!note) return;
|
|
273
|
+
console.warn(note);
|
|
274
|
+
loggedLinuxHostClassNote = true;
|
|
275
|
+
}
|
|
276
|
+
function logSandboxEnforcementUnavailable() {
|
|
277
|
+
if (loggedRestrictiveUnavailable) return;
|
|
278
|
+
const explicitlyDisabled = process.env.POETIC_SANDBOX_ENABLED === "0";
|
|
279
|
+
if (explicitlyDisabled) return;
|
|
280
|
+
console.warn(
|
|
281
|
+
"[Sandbox] sandbox-exec is present but restrictive deny-default profile probing failed. Readonly agentic execution will be blocked (reason=sandbox_unavailable)."
|
|
282
|
+
);
|
|
283
|
+
loggedRestrictiveUnavailable = true;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/core/sandbox/profile-cache.ts
|
|
287
|
+
import crypto from "crypto";
|
|
288
|
+
import fs3 from "fs";
|
|
289
|
+
import path5 from "path";
|
|
290
|
+
|
|
291
|
+
// src/core/sandbox/profile-generator.ts
|
|
292
|
+
import fs2 from "fs";
|
|
293
|
+
import os3 from "os";
|
|
294
|
+
import path4 from "path";
|
|
295
|
+
|
|
296
|
+
// src/core/ci/local-ci-publication-mac.ts
|
|
297
|
+
import { createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from "crypto";
|
|
298
|
+
import {
|
|
299
|
+
mkdirSync,
|
|
300
|
+
readdirSync,
|
|
301
|
+
readFileSync,
|
|
302
|
+
renameSync,
|
|
303
|
+
unlinkSync,
|
|
304
|
+
writeFileSync
|
|
305
|
+
} from "fs";
|
|
306
|
+
import { homedir } from "os";
|
|
307
|
+
import path2 from "path";
|
|
308
|
+
var LOCAL_CI_PUBLICATION_MAC_KEY_HOME_RELATIVE_DIR = ".local/poetic-secrets";
|
|
309
|
+
var LOCAL_CI_PUBLICATION_MAC_KEY_FILENAME = "local-ci-publication.key";
|
|
310
|
+
var PUBLICATION_MAC_VERSION = "v1";
|
|
311
|
+
var PUBLICATION_MAC_KEY_BYTES = 32;
|
|
312
|
+
var cachedKey;
|
|
313
|
+
var secretsRootOverride;
|
|
314
|
+
function publicationGenerationIdentity(repository, sha) {
|
|
315
|
+
return `${repository}\0${sha.toLowerCase()}`;
|
|
316
|
+
}
|
|
317
|
+
function getLocalCiPublicationGenerationPath(repository, sha) {
|
|
318
|
+
const identity = createHash("sha256").update(publicationGenerationIdentity(repository, sha)).digest("hex").slice(0, 32);
|
|
319
|
+
return path2.join(getLocalCiPublicationSecretsRoot(), "generations", `${identity}.gen`);
|
|
320
|
+
}
|
|
321
|
+
function getLocalCiPublicationSecretsRoot() {
|
|
322
|
+
return secretsRootOverride ?? path2.join(homedir(), LOCAL_CI_PUBLICATION_MAC_KEY_HOME_RELATIVE_DIR);
|
|
323
|
+
}
|
|
324
|
+
function getLocalCiPublicationMacKeyPath() {
|
|
325
|
+
return path2.join(getLocalCiPublicationSecretsRoot(), LOCAL_CI_PUBLICATION_MAC_KEY_FILENAME);
|
|
326
|
+
}
|
|
327
|
+
function isNodeErrorCode(error, code) {
|
|
328
|
+
return Boolean(error && typeof error === "object" && "code" in error && error.code === code);
|
|
329
|
+
}
|
|
330
|
+
function publicationMacMaterial(obligation) {
|
|
331
|
+
return [
|
|
332
|
+
PUBLICATION_MAC_VERSION,
|
|
333
|
+
obligation.repository,
|
|
334
|
+
obligation.sha.toLowerCase(),
|
|
335
|
+
obligation.context,
|
|
336
|
+
obligation.state,
|
|
337
|
+
obligation.description,
|
|
338
|
+
obligation.targetStatus ?? "",
|
|
339
|
+
obligation.generation ?? ""
|
|
340
|
+
].join("\0");
|
|
341
|
+
}
|
|
342
|
+
function mintPublicationGeneration() {
|
|
343
|
+
return randomUUID();
|
|
344
|
+
}
|
|
345
|
+
function getLocalCiPublicationGenerationJournalDir(repository, sha) {
|
|
346
|
+
const identity = createHash("sha256").update(publicationGenerationIdentity(repository, sha)).digest("hex").slice(0, 32);
|
|
347
|
+
return path2.join(getLocalCiPublicationSecretsRoot(), "generations", identity);
|
|
348
|
+
}
|
|
349
|
+
function getLocalCiPublicationGenerationJournalPath(repository, sha, attemptId) {
|
|
350
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(attemptId)) {
|
|
351
|
+
throw new Error("Local CI publication generation journal attemptId must be a UUID.");
|
|
352
|
+
}
|
|
353
|
+
return path2.join(
|
|
354
|
+
getLocalCiPublicationGenerationJournalDir(repository, sha),
|
|
355
|
+
`${attemptId}.journal`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
function writeAtomicFile(filePath, contents) {
|
|
359
|
+
mkdirSync(path2.dirname(filePath), { recursive: true, mode: 448 });
|
|
360
|
+
const temporary = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
361
|
+
writeFileSync(temporary, contents, { encoding: "utf8", mode: 384 });
|
|
362
|
+
try {
|
|
363
|
+
renameSync(temporary, filePath);
|
|
364
|
+
} catch (error) {
|
|
365
|
+
try {
|
|
366
|
+
unlinkSync(temporary);
|
|
367
|
+
} catch {
|
|
368
|
+
}
|
|
369
|
+
throw error;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function unlinkIfExists(filePath) {
|
|
373
|
+
try {
|
|
374
|
+
unlinkSync(filePath);
|
|
375
|
+
} catch (error) {
|
|
376
|
+
if (!isNodeErrorCode(error, "ENOENT")) throw error;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function buildPublicationGenerationJournal(record, attemptId) {
|
|
380
|
+
const obligation = record.outstandingRemoteStatusPublication;
|
|
381
|
+
if (obligation?.generation) {
|
|
382
|
+
return {
|
|
383
|
+
op: "activate",
|
|
384
|
+
repository: record.repository,
|
|
385
|
+
sha: record.sha,
|
|
386
|
+
attemptId,
|
|
387
|
+
generation: obligation.generation
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
return { op: "retire", repository: record.repository, sha: record.sha, attemptId };
|
|
391
|
+
}
|
|
392
|
+
function parsePublicationGenerationJournal(raw) {
|
|
393
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
394
|
+
const parsed = raw;
|
|
395
|
+
if (parsed.op !== "activate" && parsed.op !== "retire") return void 0;
|
|
396
|
+
if (parsed.op === "activate" && !parsed.generation) return void 0;
|
|
397
|
+
if (!parsed.attemptId) return void 0;
|
|
398
|
+
return parsed;
|
|
399
|
+
}
|
|
400
|
+
function readPublicationGenerationJournal(repository, sha, attemptId) {
|
|
401
|
+
try {
|
|
402
|
+
return parsePublicationGenerationJournal(
|
|
403
|
+
JSON.parse(
|
|
404
|
+
readFileSync(getLocalCiPublicationGenerationJournalPath(repository, sha, attemptId), "utf8")
|
|
405
|
+
)
|
|
406
|
+
);
|
|
407
|
+
} catch (error) {
|
|
408
|
+
if (isNodeErrorCode(error, "ENOENT")) return void 0;
|
|
409
|
+
throw error;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function listPublicationGenerationJournals(repository, sha) {
|
|
413
|
+
try {
|
|
414
|
+
const entries = readdirSync(getLocalCiPublicationGenerationJournalDir(repository, sha));
|
|
415
|
+
const journals = [];
|
|
416
|
+
for (const entry of entries) {
|
|
417
|
+
if (!entry.endsWith(".journal")) continue;
|
|
418
|
+
const attemptId = entry.slice(0, -".journal".length);
|
|
419
|
+
const journal = readPublicationGenerationJournal(repository, sha, attemptId);
|
|
420
|
+
if (journal) journals.push(journal);
|
|
421
|
+
}
|
|
422
|
+
return journals;
|
|
423
|
+
} catch (error) {
|
|
424
|
+
if (isNodeErrorCode(error, "ENOENT")) return [];
|
|
425
|
+
throw error;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function applyPublicationGenerationJournal(journal) {
|
|
429
|
+
if (journal.op === "activate" && journal.generation) {
|
|
430
|
+
writeAtomicFile(
|
|
431
|
+
getLocalCiPublicationGenerationPath(journal.repository, journal.sha),
|
|
432
|
+
`${journal.generation}
|
|
433
|
+
`
|
|
434
|
+
);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
unlinkIfExists(getLocalCiPublicationGenerationPath(journal.repository, journal.sha));
|
|
438
|
+
}
|
|
439
|
+
function clearPublicationGenerationJournal(repository, sha, attemptId) {
|
|
440
|
+
unlinkIfExists(getLocalCiPublicationGenerationJournalPath(repository, sha, attemptId));
|
|
441
|
+
}
|
|
442
|
+
function beginHostPublicationGenerationJournal(record) {
|
|
443
|
+
const attemptId = randomUUID();
|
|
444
|
+
const journal = buildPublicationGenerationJournal(record, attemptId);
|
|
445
|
+
writeAtomicFile(
|
|
446
|
+
getLocalCiPublicationGenerationJournalPath(record.repository, record.sha, attemptId),
|
|
447
|
+
`${JSON.stringify(journal)}
|
|
448
|
+
`
|
|
449
|
+
);
|
|
450
|
+
return attemptId;
|
|
451
|
+
}
|
|
452
|
+
function abandonHostPublicationGenerationJournal(record, attemptId) {
|
|
453
|
+
clearPublicationGenerationJournal(record.repository, record.sha, attemptId);
|
|
454
|
+
}
|
|
455
|
+
function recoverHostPublicationGeneration(record) {
|
|
456
|
+
const journals = listPublicationGenerationJournals(record.repository, record.sha);
|
|
457
|
+
const generation = record.outstandingRemoteStatusPublication?.generation;
|
|
458
|
+
const journal = generation ? journals.find((entry) => entry.op === "activate" && entry.generation === generation) : journals.find((entry) => entry.op === "retire");
|
|
459
|
+
if (!journal) return;
|
|
460
|
+
applyPublicationGenerationJournal(journal);
|
|
461
|
+
clearPublicationGenerationJournal(record.repository, record.sha, journal.attemptId);
|
|
462
|
+
}
|
|
463
|
+
function syncHostPublicationGeneration(record, attemptId) {
|
|
464
|
+
const journal = readPublicationGenerationJournal(record.repository, record.sha, attemptId) ?? buildPublicationGenerationJournal(record, attemptId);
|
|
465
|
+
applyPublicationGenerationJournal(journal);
|
|
466
|
+
clearPublicationGenerationJournal(record.repository, record.sha, attemptId);
|
|
467
|
+
}
|
|
468
|
+
function readHostPublicationGeneration(repository, sha) {
|
|
469
|
+
try {
|
|
470
|
+
const raw = readFileSync(getLocalCiPublicationGenerationPath(repository, sha), "utf8").trim();
|
|
471
|
+
return raw.length > 0 ? raw : void 0;
|
|
472
|
+
} catch (error) {
|
|
473
|
+
if (isNodeErrorCode(error, "ENOENT")) return void 0;
|
|
474
|
+
throw error;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
function computePublicationMac(obligation, key) {
|
|
478
|
+
return createHmac("sha256", key).update(publicationMacMaterial(obligation)).digest("hex");
|
|
479
|
+
}
|
|
480
|
+
function loadLocalCiPublicationMacKey() {
|
|
481
|
+
if (cachedKey) return cachedKey;
|
|
482
|
+
const keyPath = getLocalCiPublicationMacKeyPath();
|
|
483
|
+
try {
|
|
484
|
+
const raw = readFileSync(keyPath);
|
|
485
|
+
if (raw.length >= PUBLICATION_MAC_KEY_BYTES) {
|
|
486
|
+
cachedKey = Buffer.from(raw.subarray(0, PUBLICATION_MAC_KEY_BYTES));
|
|
487
|
+
return cachedKey;
|
|
488
|
+
}
|
|
489
|
+
} catch (error) {
|
|
490
|
+
if (!isNodeErrorCode(error, "ENOENT")) {
|
|
491
|
+
throw error;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
mkdirSync(path2.dirname(keyPath), { recursive: true, mode: 448 });
|
|
495
|
+
const generated = randomBytes(PUBLICATION_MAC_KEY_BYTES);
|
|
496
|
+
try {
|
|
497
|
+
writeFileSync(keyPath, generated, { mode: 384, flag: "wx" });
|
|
498
|
+
cachedKey = generated;
|
|
499
|
+
return cachedKey;
|
|
500
|
+
} catch (error) {
|
|
501
|
+
if (!isNodeErrorCode(error, "EEXIST")) {
|
|
502
|
+
throw error;
|
|
503
|
+
}
|
|
504
|
+
const raw = readFileSync(keyPath);
|
|
505
|
+
if (raw.length < PUBLICATION_MAC_KEY_BYTES) {
|
|
506
|
+
throw new Error(`Local CI publication MAC key at ${keyPath} is truncated.`);
|
|
507
|
+
}
|
|
508
|
+
cachedKey = Buffer.from(raw.subarray(0, PUBLICATION_MAC_KEY_BYTES));
|
|
509
|
+
return cachedKey;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
function attachOutstandingStatusPublicationMac(obligation) {
|
|
513
|
+
const generation = mintPublicationGeneration();
|
|
514
|
+
const unsigned = {
|
|
515
|
+
repository: obligation.repository,
|
|
516
|
+
sha: obligation.sha,
|
|
517
|
+
context: obligation.context,
|
|
518
|
+
state: obligation.state,
|
|
519
|
+
description: obligation.description,
|
|
520
|
+
generation,
|
|
521
|
+
...obligation.targetStatus !== void 0 ? { targetStatus: obligation.targetStatus } : {}
|
|
522
|
+
};
|
|
523
|
+
const mac = computePublicationMac(unsigned, loadLocalCiPublicationMacKey());
|
|
524
|
+
return { ...obligation, ...unsigned, generation, mac };
|
|
525
|
+
}
|
|
526
|
+
function outstandingStatusPublicationMacIsValid(obligation) {
|
|
527
|
+
if (!obligation.mac || !/^[a-f0-9]{64}$/i.test(obligation.mac)) {
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
530
|
+
if (!obligation.generation) {
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
let hostGeneration;
|
|
534
|
+
try {
|
|
535
|
+
hostGeneration = readHostPublicationGeneration(obligation.repository, obligation.sha);
|
|
536
|
+
} catch {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
if (!hostGeneration || hostGeneration !== obligation.generation) {
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
let key;
|
|
543
|
+
try {
|
|
544
|
+
key = loadLocalCiPublicationMacKey();
|
|
545
|
+
} catch {
|
|
546
|
+
return false;
|
|
547
|
+
}
|
|
548
|
+
const expected = computePublicationMac(obligation, key);
|
|
549
|
+
const actual = Buffer.from(obligation.mac, "hex");
|
|
550
|
+
const expectedBuf = Buffer.from(expected, "hex");
|
|
551
|
+
if (actual.length !== expectedBuf.length) return false;
|
|
552
|
+
return timingSafeEqual(actual, expectedBuf);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// src/core/sandbox/profile-storage.ts
|
|
556
|
+
import os2 from "os";
|
|
557
|
+
import path3 from "path";
|
|
558
|
+
function getSandboxProfileStorageDirectory() {
|
|
559
|
+
return path3.join(os2.homedir(), "Library", "Application Support", "Poetic", "sandbox-profiles");
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/core/sandbox/profile-generator.ts
|
|
563
|
+
var CREDENTIAL_DENY_SPECS = [
|
|
564
|
+
{ kind: "subpath", homeRelative: ".ssh" },
|
|
565
|
+
{ kind: "subpath", homeRelative: ".azure" },
|
|
566
|
+
{ kind: "subpath", homeRelative: ".gnupg" },
|
|
567
|
+
{ kind: "subpath", homeRelative: ".kube" },
|
|
568
|
+
{ kind: "subpath", homeRelative: ".docker/config.json" },
|
|
569
|
+
{ kind: "literal", homeRelative: ".npmrc" },
|
|
570
|
+
{ kind: "literal", homeRelative: ".git-credentials" },
|
|
571
|
+
{ kind: "subpath", homeRelative: ".op" },
|
|
572
|
+
{ kind: "subpath", homeRelative: ".config/op" },
|
|
573
|
+
{ kind: "literal", homeRelative: ".netrc" },
|
|
574
|
+
{ kind: "literal", homeRelative: ".pypirc" },
|
|
575
|
+
{ kind: "subpath", homeRelative: ".gem/credentials" },
|
|
576
|
+
{ kind: "literal", homeRelative: ".cargo/credentials" },
|
|
577
|
+
{ kind: "literal", homeRelative: ".cargo/credentials.toml" },
|
|
578
|
+
{ kind: "subpath", homeRelative: ".config/heroku" },
|
|
579
|
+
{ kind: "subpath", homeRelative: ".terraform.d" },
|
|
580
|
+
{ kind: "literal", homeRelative: ".vault-token" },
|
|
581
|
+
{ kind: "subpath", homeRelative: ".config/stripe" },
|
|
582
|
+
{ kind: "subpath", homeRelative: ".cloudflare" },
|
|
583
|
+
{ kind: "subpath", homeRelative: ".wrangler" },
|
|
584
|
+
{ kind: "literal", homeRelative: ".pulumi/credentials.json" },
|
|
585
|
+
{ kind: "subpath", homeRelative: ".config/vercel" },
|
|
586
|
+
{ kind: "subpath", homeRelative: ".config/netlify" },
|
|
587
|
+
// Local CI publication MAC key. Outside the sandbox-writable `.poetic`
|
|
588
|
+
// tree; denied for read+write so a confined agent cannot mint a valid
|
|
589
|
+
// success publication.
|
|
590
|
+
{ kind: "subpath", homeRelative: LOCAL_CI_PUBLICATION_MAC_KEY_HOME_RELATIVE_DIR }
|
|
591
|
+
];
|
|
592
|
+
var AWS_CREDENTIAL_DENY_SPECS = [
|
|
593
|
+
{ kind: "subpath", homeRelative: ".aws" },
|
|
594
|
+
{ kind: "literal", homeRelative: ".aws/credentials" }
|
|
595
|
+
];
|
|
596
|
+
function getCredentialDenySpecs(allowAwsCredentialRead = false) {
|
|
597
|
+
return allowAwsCredentialRead ? CREDENTIAL_DENY_SPECS : [...CREDENTIAL_DENY_SPECS, ...AWS_CREDENTIAL_DENY_SPECS];
|
|
598
|
+
}
|
|
599
|
+
var TOOLCHAIN_CREDENTIAL_DENY_SPECS = [
|
|
600
|
+
{ kind: "literal", homeRelative: ".m2/settings.xml" },
|
|
601
|
+
{ kind: "literal", homeRelative: ".m2/settings-security.xml" },
|
|
602
|
+
{ kind: "literal", homeRelative: ".gradle/gradle.properties" },
|
|
603
|
+
// Gradle init scripts auto-execute as the user on the next build (deferred
|
|
604
|
+
// exec). ~/.gradle is write-granted via COMMON_TOOLCHAIN_WRITE_PATHS, so these
|
|
605
|
+
// must be re-denied post-allow to block planted init scripts.
|
|
606
|
+
{ kind: "subpath", homeRelative: ".gradle/init.d" },
|
|
607
|
+
{ kind: "literal", homeRelative: ".gradle/init.gradle" },
|
|
608
|
+
{ kind: "literal", homeRelative: ".gradle/init.gradle.kts" }
|
|
609
|
+
];
|
|
610
|
+
var PROVIDER_TOKEN_WRITE_DENY_SPECS = [
|
|
611
|
+
{ kind: "literal", homeRelative: ".config/gh/hosts.yml" },
|
|
612
|
+
{ kind: "literal", homeRelative: ".gemini/oauth_creds.json" },
|
|
613
|
+
{ kind: "literal", homeRelative: ".config/gcloud/application_default_credentials.json" },
|
|
614
|
+
// gcloud stores live OAuth/access tokens in SQLite stores under the recursively
|
|
615
|
+
// write-granted ~/.config/gcloud tree, not just the ADC json. credentials.db and
|
|
616
|
+
// access_tokens.db are the actual token stores gcloud reads/refreshes. Deny WRITES
|
|
617
|
+
// to them (reads stay allowed) so a confined agent cannot overwrite/forge tokens.
|
|
618
|
+
// Note: denying writes may interfere with in-sandbox gcloud token refresh, which
|
|
619
|
+
// is the same posture already chosen for .config/gh/hosts.yml and .gemini tokens.
|
|
620
|
+
{ kind: "literal", homeRelative: ".config/gcloud/credentials.db" },
|
|
621
|
+
{ kind: "literal", homeRelative: ".config/gcloud/access_tokens.db" },
|
|
622
|
+
// Codex stores browser-login tokens in auth.json under the recursively
|
|
623
|
+
// write-granted ~/.codex (CODEX_HOME) tree. Re-deny writes (reads stay
|
|
624
|
+
// allowed) so a confined agent cannot overwrite/forge the login secret.
|
|
625
|
+
// Isolated/custom CODEX_HOME is re-denied separately via absolute paths
|
|
626
|
+
// (see renderCodexAuthJsonRedenyEntries) so every granted state root is covered.
|
|
627
|
+
{ kind: "literal", homeRelative: ".codex/auth.json" }
|
|
628
|
+
];
|
|
629
|
+
var CLIENT_SIDE_GIT_HOOK_NAMES = [
|
|
630
|
+
"applypatch-msg",
|
|
631
|
+
"pre-applypatch",
|
|
632
|
+
"post-applypatch",
|
|
633
|
+
"pre-commit",
|
|
634
|
+
"pre-merge-commit",
|
|
635
|
+
"prepare-commit-msg",
|
|
636
|
+
"commit-msg",
|
|
637
|
+
"post-commit",
|
|
638
|
+
"pre-rebase",
|
|
639
|
+
"post-checkout",
|
|
640
|
+
"post-merge",
|
|
641
|
+
"pre-push",
|
|
642
|
+
"post-rewrite",
|
|
643
|
+
"post-index-change",
|
|
644
|
+
"pre-auto-gc"
|
|
645
|
+
];
|
|
646
|
+
function renderWritePathDirectives(home, specs) {
|
|
647
|
+
return specs.map((spec) => `
|
|
648
|
+
(${spec.kind} "${escapeSeatbeltString(`${home}/${spec.homeRelative}`)}")`).join("");
|
|
649
|
+
}
|
|
650
|
+
function escapeSeatbeltString(value) {
|
|
651
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
652
|
+
}
|
|
653
|
+
function regexEscapeString(value) {
|
|
654
|
+
return value.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
655
|
+
}
|
|
656
|
+
function renderProviderStateWriteEntries(home, env, providerId) {
|
|
657
|
+
const specs = providerId ? getRequiredWritePathsForProvider(providerId, { env }) : getAllProviderWritePathSpecs({ env });
|
|
658
|
+
return specs.flatMap((spec) => {
|
|
659
|
+
if (spec.rejected) return [];
|
|
660
|
+
if (spec.kind === "regex") {
|
|
661
|
+
const anchoredPrefix = `^${regexEscapeString(home)}/`;
|
|
662
|
+
return [`
|
|
663
|
+
(regex "${escapeSeatbeltString(anchoredPrefix)}${spec.homeRelative}")`];
|
|
664
|
+
}
|
|
665
|
+
const resolved = resolveWritePathSpec(spec, home);
|
|
666
|
+
if (!resolved) return [];
|
|
667
|
+
switch (spec.kind) {
|
|
668
|
+
case "literal":
|
|
669
|
+
return [`
|
|
670
|
+
(literal "${escapeSeatbeltString(resolved)}")`];
|
|
671
|
+
default:
|
|
672
|
+
return [`
|
|
673
|
+
(subpath "${escapeSeatbeltString(resolved)}")`];
|
|
674
|
+
}
|
|
675
|
+
}).join("");
|
|
676
|
+
}
|
|
677
|
+
function renderProviderStateWriteEntriesWithinWorkingDir(home, resolvedWorkingDir, env, providerId) {
|
|
678
|
+
const specs = providerId ? getRequiredWritePathsForProvider(providerId, { env }) : getAllProviderWritePathSpecs({ env });
|
|
679
|
+
const workingDirVariants = getMacosTempRootSymlinkVariants(resolvedWorkingDir);
|
|
680
|
+
const entries = /* @__PURE__ */ new Set();
|
|
681
|
+
for (const spec of specs) {
|
|
682
|
+
if (spec.rejected || spec.kind === "regex") continue;
|
|
683
|
+
const resolved = resolveWritePathSpec(spec, home);
|
|
684
|
+
if (!resolved) continue;
|
|
685
|
+
for (const candidate of getMacosTempRootSymlinkVariants(resolved)) {
|
|
686
|
+
const contained = workingDirVariants.some(
|
|
687
|
+
(workingDirVariant) => candidate !== workingDirVariant && isPathUnder(candidate, workingDirVariant)
|
|
688
|
+
);
|
|
689
|
+
if (!contained) continue;
|
|
690
|
+
const directive = spec.kind === "literal" ? "literal" : "subpath";
|
|
691
|
+
entries.add(`
|
|
692
|
+
(${directive} "${escapeSeatbeltString(candidate)}")`);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return [...entries].join("");
|
|
696
|
+
}
|
|
697
|
+
function renderCredentialWriteDenyEntries(realHome, envHome, allowAwsCredentialRead = false) {
|
|
698
|
+
return `${renderWritePathDirectives(realHome, getCredentialDenySpecs(allowAwsCredentialRead))}${renderWritePathDirectives(
|
|
699
|
+
realHome,
|
|
700
|
+
TOOLCHAIN_CREDENTIAL_DENY_SPECS
|
|
701
|
+
)}${renderWritePathDirectives(envHome, PROVIDER_TOKEN_WRITE_DENY_SPECS)}`;
|
|
702
|
+
}
|
|
703
|
+
function renderCodexAuthJsonRedenyEntries(home, env) {
|
|
704
|
+
const authPaths = /* @__PURE__ */ new Set();
|
|
705
|
+
authPaths.add(path4.join(home, ".codex", "auth.json"));
|
|
706
|
+
const specs = getRequiredWritePathsForProvider("codex", {
|
|
707
|
+
env: env ?? { HOME: home },
|
|
708
|
+
includeSharedPaths: false
|
|
709
|
+
});
|
|
710
|
+
for (const spec of specs) {
|
|
711
|
+
if (spec.rejected) continue;
|
|
712
|
+
const resolved = resolveWritePathSpec(spec, home);
|
|
713
|
+
if (!resolved) continue;
|
|
714
|
+
authPaths.add(path4.join(resolved, "auth.json"));
|
|
715
|
+
}
|
|
716
|
+
return [...authPaths].flatMap((authPath) => getMacosTempRootSymlinkVariants(authPath)).map((authPath) => `
|
|
717
|
+
(literal "${escapeSeatbeltString(authPath)}")`).join("");
|
|
718
|
+
}
|
|
719
|
+
function renderCredentialRedenyEntries(realHome, envHome, env, allowAwsCredentialRead = false) {
|
|
720
|
+
return `
|
|
721
|
+
;; Credential directories/files must be re-denied after the write allow block.
|
|
722
|
+
;; macOS seatbelt uses last-match-wins, so the early read/write deny is not
|
|
723
|
+
;; enough if a runtime provider path accidentally overlaps a credential path.${renderCredentialWriteDenyEntries(realHome, envHome, allowAwsCredentialRead)}${renderCodexAuthJsonRedenyEntries(envHome, env)}`;
|
|
724
|
+
}
|
|
725
|
+
function renderProviderAuthorityWriteDenyEntries(env, providerId) {
|
|
726
|
+
const entries = /* @__PURE__ */ new Set();
|
|
727
|
+
for (const spec of getProviderAuthorityWriteDenyPathSpecs(providerId, { env })) {
|
|
728
|
+
const resolved = resolveWritePathSpec(spec, env?.HOME);
|
|
729
|
+
if (!resolved) continue;
|
|
730
|
+
for (const candidate of getMacosTempRootSymlinkVariants(resolved)) {
|
|
731
|
+
entries.add(`
|
|
732
|
+
(${spec.kind} "${escapeSeatbeltString(candidate)}")`);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return [...entries].join("");
|
|
736
|
+
}
|
|
737
|
+
var MACOS_TEMP_ROOT_PREFIXES = [
|
|
738
|
+
"/tmp",
|
|
739
|
+
"/private/tmp",
|
|
740
|
+
"/var/folders",
|
|
741
|
+
"/private/var/folders"
|
|
742
|
+
];
|
|
743
|
+
function normalizeSeatbeltPath(candidatePath) {
|
|
744
|
+
return candidatePath.replace(/\\/g, "/");
|
|
745
|
+
}
|
|
746
|
+
function isPathUnder(candidate, parent) {
|
|
747
|
+
const rel = path4.relative(parent, candidate);
|
|
748
|
+
return rel === "" || !!rel && !rel.startsWith("..") && !path4.isAbsolute(rel);
|
|
749
|
+
}
|
|
750
|
+
function isUnderMacosTempRoot(resolvedPath) {
|
|
751
|
+
const normalized = normalizeSeatbeltPath(path4.resolve(resolvedPath));
|
|
752
|
+
return MACOS_TEMP_ROOT_PREFIXES.some(
|
|
753
|
+
(root) => normalized === root || normalized.startsWith(`${root}/`)
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
function getMacosTempRootSymlinkVariants(resolvedPath) {
|
|
757
|
+
const normalized = normalizeSeatbeltPath(path4.resolve(resolvedPath));
|
|
758
|
+
const variants = /* @__PURE__ */ new Set([normalized]);
|
|
759
|
+
if (normalized === "/private/tmp" || normalized.startsWith("/private/tmp/")) {
|
|
760
|
+
variants.add(normalized.replace(/^\/private\/tmp/, "/tmp"));
|
|
761
|
+
} else if (normalized === "/tmp" || normalized.startsWith("/tmp/")) {
|
|
762
|
+
variants.add(normalized.replace(/^\/tmp/, "/private/tmp"));
|
|
763
|
+
}
|
|
764
|
+
if (normalized === "/private/var/folders" || normalized.startsWith("/private/var/folders/")) {
|
|
765
|
+
variants.add(normalized.replace(/^\/private\/var\/folders/, "/var/folders"));
|
|
766
|
+
} else if (normalized === "/var/folders" || normalized.startsWith("/var/folders/")) {
|
|
767
|
+
variants.add(normalized.replace(/^\/var\/folders/, "/private/var/folders"));
|
|
768
|
+
}
|
|
769
|
+
return Array.from(variants).sort();
|
|
770
|
+
}
|
|
771
|
+
function renderReadOnlyTempRootedDenyEntry(resolvedWorkingDir, readOnlyWorkingDir) {
|
|
772
|
+
if (!readOnlyWorkingDir || !isUnderMacosTempRoot(resolvedWorkingDir)) {
|
|
773
|
+
return "";
|
|
774
|
+
}
|
|
775
|
+
return getMacosTempRootSymlinkVariants(resolvedWorkingDir).map((candidate) => `
|
|
776
|
+
(subpath "${candidate}")`).join("");
|
|
777
|
+
}
|
|
778
|
+
var GIT_AUTHORITY_READ_TIMEOUT_MS = 5e3;
|
|
779
|
+
function getGitWorktreeLayout(worktreePath) {
|
|
780
|
+
try {
|
|
781
|
+
const probe = execGitSync(
|
|
782
|
+
["rev-parse", "--path-format=absolute", "--git-common-dir", "--git-dir"],
|
|
783
|
+
{
|
|
784
|
+
cwd: worktreePath,
|
|
785
|
+
timeoutMs: GIT_AUTHORITY_READ_TIMEOUT_MS,
|
|
786
|
+
scrubGitConfigFileOverrides: true
|
|
787
|
+
}
|
|
788
|
+
);
|
|
789
|
+
const [commonDir, worktreeGitDir] = probe.exitCode === 0 ? probe.stdout.trim().split(/\r?\n/) : [];
|
|
790
|
+
if (commonDir) {
|
|
791
|
+
return { projectRoot: path4.dirname(commonDir), worktreeGitDir };
|
|
792
|
+
}
|
|
793
|
+
} catch {
|
|
794
|
+
}
|
|
795
|
+
const normalizedPath = worktreePath.replace(/\\/g, "/");
|
|
796
|
+
const tmpWorktreeMarker = "/.poetic/tmp/worktrees/";
|
|
797
|
+
const tmpIdx = normalizedPath.indexOf(tmpWorktreeMarker);
|
|
798
|
+
if (tmpIdx > 0) {
|
|
799
|
+
return { projectRoot: normalizedPath.slice(0, tmpIdx) };
|
|
800
|
+
}
|
|
801
|
+
const labWorktreeMarker = "/.poetic/labs/";
|
|
802
|
+
const labIdx = normalizedPath.indexOf(labWorktreeMarker);
|
|
803
|
+
if (labIdx > 0) {
|
|
804
|
+
const suffix = normalizedPath.slice(labIdx + labWorktreeMarker.length);
|
|
805
|
+
const segments = suffix.split("/").filter(Boolean);
|
|
806
|
+
const isLabWorktreePath = segments.length >= 5 && segments[1] === "runs" && segments[3] === "worktrees";
|
|
807
|
+
if (isLabWorktreePath) {
|
|
808
|
+
return { projectRoot: normalizedPath.slice(0, labIdx) };
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return {};
|
|
812
|
+
}
|
|
813
|
+
function generateSandboxProfile(workingDir, extraWritePaths, readOnlyWorkingDir = false, env, providerId, allowGitWrites = true, allowAwsCredentialRead = false) {
|
|
814
|
+
const realHome = process.env.HOME ?? os3.homedir();
|
|
815
|
+
const home = env?.HOME ?? realHome;
|
|
816
|
+
const resolvedWorkingDir = path4.resolve(workingDir);
|
|
817
|
+
const { projectRoot, worktreeGitDir } = getGitWorktreeLayout(resolvedWorkingDir);
|
|
818
|
+
const sharedGitDir = projectRoot ? path4.join(projectRoot, ".git") : void 0;
|
|
819
|
+
const sharedGitDirEntry = sharedGitDir && !readOnlyWorkingDir && allowGitWrites ? `
|
|
820
|
+
(subpath "${escapeSeatbeltString(sharedGitDir)}")` : "";
|
|
821
|
+
const workingDirWriteEntry = readOnlyWorkingDir ? "" : `
|
|
822
|
+
(subpath "${escapeSeatbeltString(resolvedWorkingDir)}")`;
|
|
823
|
+
const gitWriteGuardDirs = Array.from(
|
|
824
|
+
new Set([sharedGitDir, path4.join(resolvedWorkingDir, ".git")].filter((d) => !!d))
|
|
825
|
+
);
|
|
826
|
+
let gitHookConfigDenyEntry = gitWriteGuardDirs.map(
|
|
827
|
+
(g) => `
|
|
828
|
+
(subpath "${escapeSeatbeltString(`${g}/hooks`)}")
|
|
829
|
+
(literal "${escapeSeatbeltString(`${g}/config`)}")`
|
|
830
|
+
).join("");
|
|
831
|
+
if (!allowGitWrites) {
|
|
832
|
+
gitHookConfigDenyEntry += Array.from(
|
|
833
|
+
new Set(
|
|
834
|
+
[sharedGitDir, path4.join(resolvedWorkingDir, ".git")].filter(
|
|
835
|
+
(gitDir) => !!gitDir
|
|
836
|
+
)
|
|
837
|
+
)
|
|
838
|
+
).flatMap((gitDir) => getMacosTempRootSymlinkVariants(gitDir)).map((gitDir) => `
|
|
839
|
+
(subpath "${escapeSeatbeltString(gitDir)}")`).join("");
|
|
840
|
+
}
|
|
841
|
+
let sharedGitRefDenyEntry = "";
|
|
842
|
+
let activeGitRefAllowEntry = "";
|
|
843
|
+
if (sharedGitDir && !readOnlyWorkingDir && allowGitWrites) {
|
|
844
|
+
const protectedGitPaths = [
|
|
845
|
+
path4.join(sharedGitDir, "refs"),
|
|
846
|
+
path4.join(sharedGitDir, "logs", "refs"),
|
|
847
|
+
path4.join(sharedGitDir, "packed-refs"),
|
|
848
|
+
path4.join(sharedGitDir, "packed-refs.lock")
|
|
849
|
+
];
|
|
850
|
+
sharedGitRefDenyEntry = protectedGitPaths.flatMap((protectedPath) => getMacosTempRootSymlinkVariants(protectedPath)).map((protectedPath) => `
|
|
851
|
+
(subpath "${escapeSeatbeltString(protectedPath)}")`).join("");
|
|
852
|
+
try {
|
|
853
|
+
const head = execGitSync(["symbolic-ref", "--quiet", "HEAD"], {
|
|
854
|
+
cwd: resolvedWorkingDir,
|
|
855
|
+
timeoutMs: GIT_AUTHORITY_READ_TIMEOUT_MS,
|
|
856
|
+
scrubGitConfigFileOverrides: true
|
|
857
|
+
});
|
|
858
|
+
const activeRef = head.exitCode === 0 ? head.stdout.trim() : "";
|
|
859
|
+
if (activeRef && /^refs\/heads\/[A-Za-z0-9._/-]+$/.test(activeRef) && !activeRef.includes("..")) {
|
|
860
|
+
const refPath = path4.join(sharedGitDir, activeRef);
|
|
861
|
+
const logPath = path4.join(sharedGitDir, "logs", activeRef);
|
|
862
|
+
activeGitRefAllowEntry = [refPath, `${refPath}.lock`, logPath, `${logPath}.lock`].flatMap((activePath) => getMacosTempRootSymlinkVariants(activePath)).map((activePath) => `
|
|
863
|
+
(literal "${escapeSeatbeltString(activePath)}")`).join("");
|
|
864
|
+
}
|
|
865
|
+
} catch {
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
const worktreeGitfile = path4.join(resolvedWorkingDir, ".git");
|
|
869
|
+
if (sharedGitDir) {
|
|
870
|
+
try {
|
|
871
|
+
const stat = fs2.lstatSync(worktreeGitfile);
|
|
872
|
+
const match = stat.isFile() ? /^gitdir:\s*(.+)\s*$/i.exec(fs2.readFileSync(worktreeGitfile, "utf8").trim()) : null;
|
|
873
|
+
if (match?.[1]) {
|
|
874
|
+
const declaredGitDir = path4.resolve(resolvedWorkingDir, match[1]);
|
|
875
|
+
const actualGitDir = worktreeGitDir;
|
|
876
|
+
if (!actualGitDir) throw new Error("Git did not report a worktree git directory");
|
|
877
|
+
const realDeclaredGitDir = fs2.realpathSync(declaredGitDir);
|
|
878
|
+
const realActualGitDir = fs2.realpathSync(actualGitDir);
|
|
879
|
+
const realSharedGitDir = fs2.realpathSync(sharedGitDir);
|
|
880
|
+
if (realDeclaredGitDir === realActualGitDir && isPathUnder(realActualGitDir, path4.join(realSharedGitDir, "worktrees"))) {
|
|
881
|
+
gitHookConfigDenyEntry += getMacosTempRootSymlinkVariants(worktreeGitfile).map((gitfile) => `
|
|
882
|
+
(literal "${escapeSeatbeltString(gitfile)}")`).join("");
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
} catch {
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
const profileStorageDenyEntry = `
|
|
889
|
+
(subpath "${escapeSeatbeltString(
|
|
890
|
+
getSandboxProfileStorageDirectory()
|
|
891
|
+
)}")`;
|
|
892
|
+
const isAllowedExtraWritePath = (resolved) => resolved === resolvedWorkingDir || !!sharedGitDir && (resolved === sharedGitDir || isPathUnder(resolved, sharedGitDir)) || isPathUnder(resolved, resolvedWorkingDir) || isUnderMacosTempRoot(resolved) || isAllowedRuntimeWritePath(resolved, env);
|
|
893
|
+
const droppedExtraWritePaths = [];
|
|
894
|
+
const grantedExtraWritePaths = (extraWritePaths || []).map((p) => path4.resolve(p)).filter((p) => p && p !== resolvedWorkingDir && p !== sharedGitDir).filter((p) => {
|
|
895
|
+
if (isAllowedExtraWritePath(p)) return true;
|
|
896
|
+
droppedExtraWritePaths.push(p);
|
|
897
|
+
return false;
|
|
898
|
+
}).sort();
|
|
899
|
+
const isUnderBroadWriteRoot = (candidate) => isUnderMacosTempRoot(candidate) || !!sharedGitDir && (candidate === sharedGitDir || isPathUnder(candidate, sharedGitDir)) || grantedExtraWritePaths.some((root) => candidate === root || isPathUnder(candidate, root));
|
|
900
|
+
try {
|
|
901
|
+
const hooksPathProbe = execGitSync(["config", "--get", "core.hooksPath"], {
|
|
902
|
+
cwd: resolvedWorkingDir,
|
|
903
|
+
timeoutMs: GIT_AUTHORITY_READ_TIMEOUT_MS,
|
|
904
|
+
scrubGitConfigFileOverrides: true
|
|
905
|
+
});
|
|
906
|
+
const hooksPathRaw = hooksPathProbe.exitCode === 0 ? hooksPathProbe.stdout.trim() : "";
|
|
907
|
+
if (hooksPathRaw) {
|
|
908
|
+
const absHooksPath = path4.isAbsolute(hooksPathRaw) ? path4.resolve(hooksPathRaw) : path4.resolve(resolvedWorkingDir, hooksPathRaw);
|
|
909
|
+
const rel = path4.relative(resolvedWorkingDir, absHooksPath);
|
|
910
|
+
if (rel === "") {
|
|
911
|
+
if (!readOnlyWorkingDir) {
|
|
912
|
+
for (const hookName of CLIENT_SIDE_GIT_HOOK_NAMES) {
|
|
913
|
+
gitHookConfigDenyEntry += `
|
|
914
|
+
(literal "${escapeSeatbeltString(
|
|
915
|
+
path4.join(resolvedWorkingDir, hookName)
|
|
916
|
+
)}")`;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
} else {
|
|
920
|
+
const strictlyInside = !rel.startsWith("..") && !path4.isAbsolute(rel);
|
|
921
|
+
if (strictlyInside) {
|
|
922
|
+
if (!readOnlyWorkingDir) {
|
|
923
|
+
gitHookConfigDenyEntry += `
|
|
924
|
+
(subpath "${escapeSeatbeltString(absHooksPath)}")`;
|
|
925
|
+
try {
|
|
926
|
+
const realHooksPath = fs2.realpathSync(absHooksPath);
|
|
927
|
+
if (realHooksPath !== absHooksPath) {
|
|
928
|
+
gitHookConfigDenyEntry += `
|
|
929
|
+
(subpath "${escapeSeatbeltString(realHooksPath)}")`;
|
|
930
|
+
}
|
|
931
|
+
} catch {
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
} else {
|
|
935
|
+
let realHooksPath;
|
|
936
|
+
try {
|
|
937
|
+
realHooksPath = fs2.realpathSync(absHooksPath);
|
|
938
|
+
} catch {
|
|
939
|
+
}
|
|
940
|
+
if (isUnderBroadWriteRoot(absHooksPath)) {
|
|
941
|
+
gitHookConfigDenyEntry += `
|
|
942
|
+
(subpath "${escapeSeatbeltString(absHooksPath)}")`;
|
|
943
|
+
}
|
|
944
|
+
if (realHooksPath && realHooksPath !== absHooksPath && isUnderBroadWriteRoot(realHooksPath)) {
|
|
945
|
+
gitHookConfigDenyEntry += `
|
|
946
|
+
(subpath "${escapeSeatbeltString(realHooksPath)}")`;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
} catch {
|
|
952
|
+
}
|
|
953
|
+
const extraWritePathsEntry = grantedExtraWritePaths.map((p) => `
|
|
954
|
+
(subpath "${escapeSeatbeltString(p)}")`).join("");
|
|
955
|
+
if (droppedExtraWritePaths.length > 0 && isDebugMode()) {
|
|
956
|
+
process.stderr.write(
|
|
957
|
+
`[sandbox] dropped out-of-allowed-root extraWritePaths: ${droppedExtraWritePaths.join(", ")}
|
|
958
|
+
`
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
const readOnlyTempRootedDenyEntry = renderReadOnlyTempRootedDenyEntry(
|
|
962
|
+
resolvedWorkingDir,
|
|
963
|
+
readOnlyWorkingDir
|
|
964
|
+
);
|
|
965
|
+
const readOnlyProviderStateReallowEntry = readOnlyTempRootedDenyEntry ? renderProviderStateWriteEntriesWithinWorkingDir(home, resolvedWorkingDir, env, providerId) : "";
|
|
966
|
+
const providerAuthorityWriteDenyEntry = renderProviderAuthorityWriteDenyEntries(env, providerId);
|
|
967
|
+
return `(version 1)
|
|
968
|
+
(deny default)
|
|
969
|
+
|
|
970
|
+
;; ============================================
|
|
971
|
+
;; FILESYSTEM READ ACCESS (BROAD)
|
|
972
|
+
;; ============================================
|
|
973
|
+
;; Allow reading most of the filesystem - the security
|
|
974
|
+
;; boundary is on WRITE access, not read access.
|
|
975
|
+
;; This matches Claude Code's default behavior.
|
|
976
|
+
(allow file-read* (subpath "/"))
|
|
977
|
+
|
|
978
|
+
;; ============================================
|
|
979
|
+
;; EXPLICIT DENY - SENSITIVE DIRECTORIES
|
|
980
|
+
;; ============================================
|
|
981
|
+
;; Protect credentials, keys, and secrets from read/write
|
|
982
|
+
;; These are blocked even with broad filesystem read access
|
|
983
|
+
(deny file-read* file-write*
|
|
984
|
+
${renderWritePathDirectives(realHome, getCredentialDenySpecs(allowAwsCredentialRead))}
|
|
985
|
+
)
|
|
986
|
+
|
|
987
|
+
;; ============================================
|
|
988
|
+
;; EXPLICIT DENY - TOOLCHAIN CREDENTIAL WRITES
|
|
989
|
+
;; ============================================
|
|
990
|
+
;; Allow build caches, but prevent tampering with common local credential files.
|
|
991
|
+
;; Safe for ordinary target builds against public package registries, and reduces
|
|
992
|
+
;; the risk of an AI process modifying user credential configuration.
|
|
993
|
+
(deny file-write*
|
|
994
|
+
${renderWritePathDirectives(realHome, TOOLCHAIN_CREDENTIAL_DENY_SPECS)}
|
|
995
|
+
)
|
|
996
|
+
|
|
997
|
+
;; ============================================
|
|
998
|
+
;; AI CLI PROVIDER CREDENTIALS (ALLOWED)
|
|
999
|
+
;; ============================================
|
|
1000
|
+
;; These directories are needed for AI CLI tools to authenticate.
|
|
1001
|
+
;; Read access is allowed by removing them from the deny list. Some CLIs also
|
|
1002
|
+
;; require small, scoped write access for token caches (e.g. AWS SSO), which is
|
|
1003
|
+
;; granted below under FILESYSTEM WRITE ACCESS.
|
|
1004
|
+
;; - ~/.aws: Bedrock backends only (allowAwsCredentialRead);
|
|
1005
|
+
;; missing attestation fails closed and denies ~/.aws)
|
|
1006
|
+
;; - ~/.config/gh: GitHub Copilot CLI
|
|
1007
|
+
;; - ~/.gcloud, ~/.config/gcloud: Gemini CLI
|
|
1008
|
+
;; - ~/.config/opencode: OpenCode CLI state
|
|
1009
|
+
|
|
1010
|
+
;; ============================================
|
|
1011
|
+
;; FILESYSTEM WRITE ACCESS (RESTRICTED)
|
|
1012
|
+
;; ============================================
|
|
1013
|
+
;; This is the main security boundary - writes are
|
|
1014
|
+
;; restricted to worktree, temp dirs, caches, and
|
|
1015
|
+
;; CLI tool state directories.
|
|
1016
|
+
(allow file-write*${workingDirWriteEntry}${sharedGitDirEntry}
|
|
1017
|
+
;; macOS temp directories - allow both symlinked and canonical paths
|
|
1018
|
+
;; /var/folders is a symlink to /private/var/folders, but sandbox-exec
|
|
1019
|
+
;; doesn't resolve symlinks when checking paths, so we need both
|
|
1020
|
+
(subpath "/var/folders")
|
|
1021
|
+
(subpath "/private/var/folders")
|
|
1022
|
+
(subpath "/private/tmp")
|
|
1023
|
+
(subpath "/tmp")
|
|
1024
|
+
;; Credential/token caches required by some provider auth flows. These are not
|
|
1025
|
+
;; declared in provider manifests (they live under the otherwise-denied ~/.aws
|
|
1026
|
+
;; tree and are scoped to the cache subdirs only).
|
|
1027
|
+
(subpath "${escapeSeatbeltString(`${home}/.aws/cli/cache`)}")
|
|
1028
|
+
(subpath "${escapeSeatbeltString(`${home}/.aws/sso/cache`)}")
|
|
1029
|
+
;; NOTE: macOS Keychain write access is NOT granted here. Providers that store
|
|
1030
|
+
;; credentials in the system keychain declare ~/Library/Keychains in their own
|
|
1031
|
+
;; manifest (provider-manifests.ts) so the grant is provider-scoped and is
|
|
1032
|
+
;; covered by the inherited-sandbox capability probe. Reading a keychain secret
|
|
1033
|
+
;; genuinely requires WRITE access (Security.framework updates lock/session
|
|
1034
|
+
;; state and the db during a lookup), so a keychain-backed provider that also
|
|
1035
|
+
;; hits a GUI authorization prompt on first read has TWO independent gates:
|
|
1036
|
+
;; this profile and the keychain item's own per-item ACL, which no sandbox
|
|
1037
|
+
;; profile can satisfy. An unattended run blocks on that prompt until a human
|
|
1038
|
+
;; chooses "Always Allow"; a provider that stalls unattended after working
|
|
1039
|
+
;; interactively is the ACL gate, not this profile.
|
|
1040
|
+
;; Provider state/config/cache and Poetic runtime paths, derived from the
|
|
1041
|
+
;; filesystem manifests (provider-manifests.ts) so the granted allowlist stays
|
|
1042
|
+
;; in lockstep with the sandbox capability probe.${renderProviderStateWriteEntries(home, env, providerId)}
|
|
1043
|
+
(subpath "/dev")${extraWritePathsEntry}
|
|
1044
|
+
)
|
|
1045
|
+
|
|
1046
|
+
${readOnlyTempRootedDenyEntry ? `;; ============================================
|
|
1047
|
+
;; READ-ONLY WORKING DIR (TEMP-ROOTED DENY)
|
|
1048
|
+
;; ============================================
|
|
1049
|
+
;; When readOnlyWorkingDir omits the working-dir write entry, macOS temp-root
|
|
1050
|
+
;; allows still grant writes under /tmp and /var/folders. Re-deny the resolved
|
|
1051
|
+
;; working dir (and symlink variants) after those allows so last-match-wins
|
|
1052
|
+
;; restores read-only enforcement for temp-rooted repos.
|
|
1053
|
+
(deny file-write*${readOnlyTempRootedDenyEntry}
|
|
1054
|
+
)
|
|
1055
|
+
|
|
1056
|
+
` : ""}${readOnlyProviderStateReallowEntry ? `;; ============================================
|
|
1057
|
+
;; PROVIDER RUNTIME STATE INSIDE READ-ONLY WORKTREE (ALLOW)
|
|
1058
|
+
;; ============================================
|
|
1059
|
+
;; Re-open only manifest-declared provider runtime state beneath the worktree.
|
|
1060
|
+
;; Credential files are re-denied by the following block.
|
|
1061
|
+
(allow file-write*${readOnlyProviderStateReallowEntry}
|
|
1062
|
+
)
|
|
1063
|
+
|
|
1064
|
+
` : ""};; ============================================
|
|
1065
|
+
;; CREDENTIAL WRITE SURFACES (DENY)
|
|
1066
|
+
;; ============================================
|
|
1067
|
+
;; Re-deny credential writes after the provider write allow block so
|
|
1068
|
+
;; environment-derived paths cannot reopen sensitive locations under
|
|
1069
|
+
;; last-match-wins seatbelt semantics. Includes Codex auth.json under the
|
|
1070
|
+
;; default ~/.codex root and any granted isolated/custom CODEX_HOME.
|
|
1071
|
+
(deny file-write*${renderCredentialRedenyEntries(realHome, home, env, allowAwsCredentialRead)}
|
|
1072
|
+
)
|
|
1073
|
+
|
|
1074
|
+
${providerAuthorityWriteDenyEntry ? `;; ============================================
|
|
1075
|
+
;; PROVIDER SETTINGS AND HOOK SURFACES (DENY)
|
|
1076
|
+
;; ============================================
|
|
1077
|
+
;; Provider runtime state remains writable for auth and session operation, but
|
|
1078
|
+
;; settings and hook storage can change policy or execute outside this run.
|
|
1079
|
+
;; Re-deny those manifest-declared persistent authority surfaces post-allow.
|
|
1080
|
+
(deny file-write*${providerAuthorityWriteDenyEntry}
|
|
1081
|
+
)
|
|
1082
|
+
|
|
1083
|
+
` : ""};; ============================================
|
|
1084
|
+
;; GIT EXECUTABLE/AUTHORITY SURFACES (DENY)
|
|
1085
|
+
;; ============================================
|
|
1086
|
+
;; Block writes to git hooks and config even though the surrounding .git is
|
|
1087
|
+
;; writable for normal worktree operations. This closes deferred host code
|
|
1088
|
+
;; execution (planted hooks / core.hooksPath) without breaking commits.
|
|
1089
|
+
;; Placed AFTER the write-allow block so it wins under last-match-wins.
|
|
1090
|
+
(deny file-write*${gitHookConfigDenyEntry}${profileStorageDenyEntry}
|
|
1091
|
+
)
|
|
1092
|
+
|
|
1093
|
+
${sharedGitRefDenyEntry ? `;; Shared Git refs are global across linked worktrees. Deny all ref writes, then
|
|
1094
|
+
;; reopen only this worktree's active branch ref and reflog for normal commits.
|
|
1095
|
+
(deny file-write*${sharedGitRefDenyEntry}
|
|
1096
|
+
)` : ""}
|
|
1097
|
+
${activeGitRefAllowEntry ? `(allow file-write*${activeGitRefAllowEntry}
|
|
1098
|
+
)` : ""}
|
|
1099
|
+
|
|
1100
|
+
;; ============================================
|
|
1101
|
+
;; IPC & MACH (FOR CLI AUTH + SUBPROCESSES)
|
|
1102
|
+
;; ============================================
|
|
1103
|
+
(allow mach*)
|
|
1104
|
+
(allow ipc*)
|
|
1105
|
+
|
|
1106
|
+
;; ============================================
|
|
1107
|
+
;; NETWORK (OUTBOUND + LOCAL SERVER)
|
|
1108
|
+
;; ============================================
|
|
1109
|
+
(allow network-outbound)
|
|
1110
|
+
;; Some CLIs (notably OpenCode) start a local loopback server even for one-shot
|
|
1111
|
+
;; commands (e.g. "opencode run"). Allow inbound connections but restrict binds
|
|
1112
|
+
;; to loopback interfaces only.
|
|
1113
|
+
(allow network-inbound)
|
|
1114
|
+
(allow network-bind (local ip "localhost:*"))
|
|
1115
|
+
|
|
1116
|
+
;; ============================================
|
|
1117
|
+
;; PROCESS EXECUTION
|
|
1118
|
+
;; ============================================
|
|
1119
|
+
(allow process-exec*)
|
|
1120
|
+
(allow process-fork)
|
|
1121
|
+
(allow signal)
|
|
1122
|
+
(allow sysctl-read)
|
|
1123
|
+
`;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// src/core/sandbox/profile-cache.ts
|
|
1127
|
+
var profileCache = /* @__PURE__ */ new Map();
|
|
1128
|
+
function getProfileBaseDir() {
|
|
1129
|
+
return getSandboxProfileStorageDirectory();
|
|
1130
|
+
}
|
|
1131
|
+
function getProfileCacheKey(profile) {
|
|
1132
|
+
return crypto.createHash("sha256").update(profile).digest("hex");
|
|
1133
|
+
}
|
|
1134
|
+
function isExpectedProfile(profilePath, profile) {
|
|
1135
|
+
try {
|
|
1136
|
+
const stat = fs3.lstatSync(profilePath);
|
|
1137
|
+
return stat.isFile() && !stat.isSymbolicLink() && (stat.mode & 511) === 384 && fs3.readFileSync(profilePath, "utf8") === profile;
|
|
1138
|
+
} catch {
|
|
1139
|
+
return false;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
function ensurePrivateStorageDirectory(baseDir) {
|
|
1143
|
+
fs3.mkdirSync(baseDir, { recursive: true, mode: 448 });
|
|
1144
|
+
const stat = fs3.lstatSync(baseDir);
|
|
1145
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
1146
|
+
throw new Error(`Sandbox profile storage is not a private directory: ${baseDir}`);
|
|
1147
|
+
}
|
|
1148
|
+
if ((stat.mode & 511) !== 448) {
|
|
1149
|
+
fs3.chmodSync(baseDir, 448);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
function writeProfileAtomically(profilePath, profile) {
|
|
1153
|
+
const temporaryPath = `${profilePath}.${process.pid}.${crypto.randomUUID()}.tmp`;
|
|
1154
|
+
try {
|
|
1155
|
+
fs3.writeFileSync(temporaryPath, profile, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
1156
|
+
fs3.renameSync(temporaryPath, profilePath);
|
|
1157
|
+
fs3.chmodSync(profilePath, 384);
|
|
1158
|
+
} finally {
|
|
1159
|
+
try {
|
|
1160
|
+
fs3.rmSync(temporaryPath, { force: true });
|
|
1161
|
+
} catch {
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
function getOrCreateProfile(workingDir, extraWritePaths, readOnlyWorkingDir = false, env, providerId, allowGitWrites = true, allowAwsCredentialRead = false) {
|
|
1166
|
+
const profile = generateSandboxProfile(
|
|
1167
|
+
workingDir,
|
|
1168
|
+
extraWritePaths,
|
|
1169
|
+
readOnlyWorkingDir,
|
|
1170
|
+
env,
|
|
1171
|
+
providerId,
|
|
1172
|
+
allowGitWrites,
|
|
1173
|
+
allowAwsCredentialRead
|
|
1174
|
+
);
|
|
1175
|
+
const cacheKey = getProfileCacheKey(profile);
|
|
1176
|
+
const baseDir = getProfileBaseDir();
|
|
1177
|
+
ensurePrivateStorageDirectory(baseDir);
|
|
1178
|
+
const profilePath = path5.join(baseDir, `${cacheKey}.sb`);
|
|
1179
|
+
const cached = profileCache.get(cacheKey);
|
|
1180
|
+
if (cached === profilePath && isExpectedProfile(cached, profile)) {
|
|
1181
|
+
return cached;
|
|
1182
|
+
}
|
|
1183
|
+
if (!isExpectedProfile(profilePath, profile)) {
|
|
1184
|
+
writeProfileAtomically(profilePath, profile);
|
|
1185
|
+
}
|
|
1186
|
+
profileCache.set(cacheKey, profilePath);
|
|
1187
|
+
return profilePath;
|
|
1188
|
+
}
|
|
1189
|
+
function registerGlobalCleanup() {
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// src/core/sandbox/index.ts
|
|
1193
|
+
var sandboxTelemetryLog = [];
|
|
1194
|
+
function isTestRuntime() {
|
|
1195
|
+
return Boolean(process.env.VITEST || process.env.VITEST_WORKER_ID);
|
|
1196
|
+
}
|
|
1197
|
+
function isBooleanTrueEnv(value) {
|
|
1198
|
+
if (value === void 0) return false;
|
|
1199
|
+
return ["1", "true", "yes", "on"].includes(value.trim().toLowerCase());
|
|
1200
|
+
}
|
|
1201
|
+
function isContainerAttestedByEnv(env) {
|
|
1202
|
+
const source = env ?? process.env;
|
|
1203
|
+
const attestedClaim = env ? isBooleanTrueEnv(source[POETIC_SANDBOX_CONTAINER_ATTESTED.name]) : readEnv(POETIC_SANDBOX_CONTAINER_ATTESTED).value === true;
|
|
1204
|
+
const provenanceClaim = env ? source[POETIC_SANDBOX_PROVENANCE.name] === "container" : readRawEnv(POETIC_SANDBOX_PROVENANCE) === "container";
|
|
1205
|
+
if (!attestedClaim && !provenanceClaim) return false;
|
|
1206
|
+
return hasContainerOsSignal();
|
|
1207
|
+
}
|
|
1208
|
+
function isLinuxHostClassProvenance(provenance) {
|
|
1209
|
+
return provenance === "linux_isolated" || provenance === "linux_acknowledged" || provenance === "linux_desktop_unacked";
|
|
1210
|
+
}
|
|
1211
|
+
function isLinuxWriteProvenance(provenance) {
|
|
1212
|
+
return provenance === "linux_isolated" || provenance === "linux_acknowledged";
|
|
1213
|
+
}
|
|
1214
|
+
function normalizeProviderName(name) {
|
|
1215
|
+
return name.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
1216
|
+
}
|
|
1217
|
+
function hasExplicitSandboxOptOut(providerName, providerId) {
|
|
1218
|
+
if (!isImplicitTestRuntimeSandboxDisable()) {
|
|
1219
|
+
return !isSandboxEnabled(providerName, providerId);
|
|
1220
|
+
}
|
|
1221
|
+
return isProviderSandboxOptOut(providerName, providerId);
|
|
1222
|
+
}
|
|
1223
|
+
function isSandboxEnabledForProvider(providerName, providerId) {
|
|
1224
|
+
return isSandboxEnabled(providerName, providerId);
|
|
1225
|
+
}
|
|
1226
|
+
function willSandboxBeActive(providerName, providerId, options) {
|
|
1227
|
+
const enabled = isSandboxEnabled(providerName, providerId);
|
|
1228
|
+
if (!enabled) return false;
|
|
1229
|
+
if (isSandboxSupported() && !(isKernelSandboxActive() && isNestedSandboxReinitDenied())) {
|
|
1230
|
+
return true;
|
|
1231
|
+
}
|
|
1232
|
+
const attestation = detectSandboxBoundaryAttestation(providerName, providerId, options);
|
|
1233
|
+
if (isLinuxHostClassProvenance(attestation.provenance)) {
|
|
1234
|
+
return false;
|
|
1235
|
+
}
|
|
1236
|
+
return isSandboxBoundaryAccepted(attestation, resolveEnvSandboxBoundaryPolicy());
|
|
1237
|
+
}
|
|
1238
|
+
function isSandboxEnforcementOperational(providerName, providerId) {
|
|
1239
|
+
if (!willSandboxBeActive(providerName, providerId)) return false;
|
|
1240
|
+
return isSandboxEnforcementSupported();
|
|
1241
|
+
}
|
|
1242
|
+
function isSelfGeneratedSeatbeltOperational(providerName, providerId) {
|
|
1243
|
+
if (!isSandboxEnabled(providerName, providerId)) return false;
|
|
1244
|
+
if (!isSandboxSupported()) return false;
|
|
1245
|
+
return isSandboxEnforcementSupported();
|
|
1246
|
+
}
|
|
1247
|
+
function requireActiveSandboxBoundary(providerName, reason, providerId, options) {
|
|
1248
|
+
const attestation = detectSandboxBoundaryAttestation(providerName, providerId, options);
|
|
1249
|
+
const effectivePolicy = resolveEnvSandboxBoundaryPolicy();
|
|
1250
|
+
const accepted = isSandboxBoundaryAccepted(attestation, effectivePolicy);
|
|
1251
|
+
if (accepted) {
|
|
1252
|
+
return attestation;
|
|
1253
|
+
}
|
|
1254
|
+
if (os4.platform() === "linux") {
|
|
1255
|
+
const authorized = authorizeLinuxHostClassWrites(options);
|
|
1256
|
+
if (authorized.status === "allowed") {
|
|
1257
|
+
return {
|
|
1258
|
+
provenance: authorized.provenance,
|
|
1259
|
+
evidence: attestation.evidence
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
throw new ProviderExecutionError(
|
|
1264
|
+
`[${providerName}] ${reason} requires an active sandbox boundary, but none is available (provenance=${attestation.provenance}) [reason=sandbox_boundary_required]`,
|
|
1265
|
+
{ retryable: false, reason: "sandbox_boundary_required" }
|
|
1266
|
+
);
|
|
1267
|
+
}
|
|
1268
|
+
function provenanceProvesPolicyByConstruction(attestation) {
|
|
1269
|
+
return attestation.provenance === "seatbelt_self";
|
|
1270
|
+
}
|
|
1271
|
+
function provenanceSkipsCapabilityProbe(attestation) {
|
|
1272
|
+
return attestation.provenance === "seatbelt_self" || attestation.provenance === "linux_isolated" || attestation.provenance === "linux_acknowledged";
|
|
1273
|
+
}
|
|
1274
|
+
function policyProofForAcceptedBoundary(attestation, providerId, env) {
|
|
1275
|
+
if (isLinuxWriteProvenance(attestation.provenance)) {
|
|
1276
|
+
return "linux_host_class";
|
|
1277
|
+
}
|
|
1278
|
+
if (provenanceProvesPolicyByConstruction(attestation)) {
|
|
1279
|
+
return "wrap_applied";
|
|
1280
|
+
}
|
|
1281
|
+
const capability = probeProviderSandboxCapability(providerId, {
|
|
1282
|
+
env,
|
|
1283
|
+
includeSharedPaths: false
|
|
1284
|
+
});
|
|
1285
|
+
return capability.capable ? "capability_probe" : void 0;
|
|
1286
|
+
}
|
|
1287
|
+
function boundaryProofForProvenance(provenance) {
|
|
1288
|
+
switch (provenance) {
|
|
1289
|
+
case "seatbelt_self":
|
|
1290
|
+
return void 0;
|
|
1291
|
+
case "container":
|
|
1292
|
+
return "container";
|
|
1293
|
+
case "inherited_outer":
|
|
1294
|
+
return "inherited_outer";
|
|
1295
|
+
case "linux_isolated":
|
|
1296
|
+
return "linux_isolated";
|
|
1297
|
+
case "linux_acknowledged":
|
|
1298
|
+
return "linux_acknowledged";
|
|
1299
|
+
default:
|
|
1300
|
+
return void 0;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
function requireActivePolicyBoundary(providerName, reason, providerId, options = {}) {
|
|
1304
|
+
const attestation = requireActiveSandboxBoundary(providerName, reason, providerId, options);
|
|
1305
|
+
if (provenanceSkipsCapabilityProbe(attestation)) {
|
|
1306
|
+
return { attestation, kind: "policy" };
|
|
1307
|
+
}
|
|
1308
|
+
const capability = probeProviderSandboxCapability(providerId ?? providerName.toLowerCase(), {
|
|
1309
|
+
env: options.env,
|
|
1310
|
+
includeSharedPaths: false
|
|
1311
|
+
});
|
|
1312
|
+
if (capability.capable) {
|
|
1313
|
+
return { attestation, kind: "policy", capability };
|
|
1314
|
+
}
|
|
1315
|
+
recordSandboxDecision({
|
|
1316
|
+
providerName,
|
|
1317
|
+
providerId: providerId ?? providerName.toLowerCase(),
|
|
1318
|
+
sandboxed: false,
|
|
1319
|
+
reason: "sandbox_capability_denied",
|
|
1320
|
+
provenance: attestation.provenance,
|
|
1321
|
+
deniedPaths: capability.missing.map((entry) => entry.path),
|
|
1322
|
+
platform: os4.platform()
|
|
1323
|
+
});
|
|
1324
|
+
throw new ProviderExecutionError(
|
|
1325
|
+
`[${providerName}] ${reason}: ${formatSandboxCapabilityFailure(capability)} [reason=sandbox_capability_denied]`,
|
|
1326
|
+
{ retryable: false, reason: "sandbox_capability_denied" }
|
|
1327
|
+
);
|
|
1328
|
+
}
|
|
1329
|
+
function shouldBypassProviderInternalSandbox(providerName, reason, providerId, options = {}) {
|
|
1330
|
+
requireActivePolicyBoundary(providerName, reason, providerId, options);
|
|
1331
|
+
return true;
|
|
1332
|
+
}
|
|
1333
|
+
function detectSandboxBoundaryAttestation(providerName, providerId, options) {
|
|
1334
|
+
const seatbeltSelfOperational = isSelfGeneratedSeatbeltOperational(providerName, providerId);
|
|
1335
|
+
const sandboxRuntimeEnv = process.env.SANDBOX_RUNTIME === "1";
|
|
1336
|
+
const kernelSandboxActive = isKernelSandboxActive();
|
|
1337
|
+
const nestedSandboxReinitDenied = isNestedSandboxReinitDenied();
|
|
1338
|
+
const containerAttested = isContainerAttestedByEnv(options?.env);
|
|
1339
|
+
const evidence = {
|
|
1340
|
+
seatbeltSelfOperational,
|
|
1341
|
+
sandboxRuntimeEnv,
|
|
1342
|
+
kernelSandboxActive,
|
|
1343
|
+
nestedSandboxReinitDenied,
|
|
1344
|
+
containerAttested
|
|
1345
|
+
};
|
|
1346
|
+
if (seatbeltSelfOperational) {
|
|
1347
|
+
return { provenance: "seatbelt_self", evidence };
|
|
1348
|
+
}
|
|
1349
|
+
const linuxResolution = os4.platform() === "linux" ? resolveLinuxHostClass(options) : null;
|
|
1350
|
+
const forcedDesktop = linuxResolution?.source === "env_desktop" || linuxResolution?.evidence.envHostClass === "desktop";
|
|
1351
|
+
if (containerAttested && !forcedDesktop) {
|
|
1352
|
+
return { provenance: "container", evidence };
|
|
1353
|
+
}
|
|
1354
|
+
if (linuxResolution?.hostClass === "isolated" && linuxResolution.source !== "container_attested") {
|
|
1355
|
+
logLinuxHostClassNote(linuxResolution.note);
|
|
1356
|
+
return { provenance: "linux_isolated", evidence };
|
|
1357
|
+
}
|
|
1358
|
+
const inheritedOuterAttested = kernelSandboxActive && (sandboxRuntimeEnv || nestedSandboxReinitDenied);
|
|
1359
|
+
if (inheritedOuterAttested) {
|
|
1360
|
+
return { provenance: "inherited_outer", evidence };
|
|
1361
|
+
}
|
|
1362
|
+
if (linuxResolution?.hostClass === "desktop-acked") {
|
|
1363
|
+
logLinuxHostClassNote(linuxResolution.note);
|
|
1364
|
+
return { provenance: "linux_acknowledged", evidence };
|
|
1365
|
+
}
|
|
1366
|
+
if (linuxResolution?.hostClass === "desktop-unacked") {
|
|
1367
|
+
return { provenance: "linux_desktop_unacked", evidence };
|
|
1368
|
+
}
|
|
1369
|
+
return { provenance: "none", evidence };
|
|
1370
|
+
}
|
|
1371
|
+
function resolveSandboxBoundaryPolicy(raw) {
|
|
1372
|
+
return raw === "strict" ? "strict" : "attested_outer_ok";
|
|
1373
|
+
}
|
|
1374
|
+
function resolveEnvSandboxBoundaryPolicy() {
|
|
1375
|
+
return resolveSandboxBoundaryPolicy(readRawEnv(POETIC_SANDBOX_BOUNDARY_POLICY));
|
|
1376
|
+
}
|
|
1377
|
+
function isAttestedInheritedOuterBoundary(attestation) {
|
|
1378
|
+
return attestation.provenance === "inherited_outer" && attestation.evidence.kernelSandboxActive && attestation.evidence.nestedSandboxReinitDenied;
|
|
1379
|
+
}
|
|
1380
|
+
function isSandboxBoundaryAccepted(attestation, policy) {
|
|
1381
|
+
if (attestation.provenance === "seatbelt_self" || attestation.provenance === "container") {
|
|
1382
|
+
return true;
|
|
1383
|
+
}
|
|
1384
|
+
if (isLinuxWriteProvenance(attestation.provenance)) {
|
|
1385
|
+
return os4.platform() === "linux";
|
|
1386
|
+
}
|
|
1387
|
+
if (policy === "attested_outer_ok" && isAttestedInheritedOuterBoundary(attestation)) {
|
|
1388
|
+
return true;
|
|
1389
|
+
}
|
|
1390
|
+
return false;
|
|
1391
|
+
}
|
|
1392
|
+
function warnSandboxEnforcementUnavailable() {
|
|
1393
|
+
logSandboxEnforcementUnavailable();
|
|
1394
|
+
}
|
|
1395
|
+
function isImplicitTestRuntimeSandboxDisable() {
|
|
1396
|
+
return isTestRuntime() && process.env.POETIC_SANDBOX_ENABLED === void 0;
|
|
1397
|
+
}
|
|
1398
|
+
function isSandboxEnabled(providerName, providerId) {
|
|
1399
|
+
if (isImplicitTestRuntimeSandboxDisable()) {
|
|
1400
|
+
return false;
|
|
1401
|
+
}
|
|
1402
|
+
return !isProviderSandboxOptOut(providerName, providerId);
|
|
1403
|
+
}
|
|
1404
|
+
function isProviderSandboxOptOut(providerName, providerId) {
|
|
1405
|
+
const globalDisabled = process.env.POETIC_SANDBOX_ENABLED === "0";
|
|
1406
|
+
if (globalDisabled) return true;
|
|
1407
|
+
const normalizedName = normalizeProviderName(providerName);
|
|
1408
|
+
const nameOverride = process.env[`POETIC_SANDBOX_${normalizedName}_ENABLED`];
|
|
1409
|
+
if (nameOverride === "0") return true;
|
|
1410
|
+
if (providerId) {
|
|
1411
|
+
const normalizedId = normalizeProviderName(providerId);
|
|
1412
|
+
const idOverride = process.env[`POETIC_SANDBOX_${normalizedId}_ENABLED`];
|
|
1413
|
+
if (idOverride === "0") return true;
|
|
1414
|
+
}
|
|
1415
|
+
return false;
|
|
1416
|
+
}
|
|
1417
|
+
function validateCustomSandboxProfile(profilePath) {
|
|
1418
|
+
let contents;
|
|
1419
|
+
try {
|
|
1420
|
+
const stat = fs4.statSync(profilePath);
|
|
1421
|
+
if (!stat.isFile()) {
|
|
1422
|
+
throw new ProviderExecutionError(
|
|
1423
|
+
`[Sandbox] POETIC_SANDBOX_PROFILE_PATH is not a regular file: ${profilePath} [reason=invalid_custom_sandbox_profile]`,
|
|
1424
|
+
{ retryable: false, reason: "invalid_custom_sandbox_profile" }
|
|
1425
|
+
);
|
|
1426
|
+
}
|
|
1427
|
+
contents = fs4.readFileSync(profilePath, "utf8");
|
|
1428
|
+
} catch (error) {
|
|
1429
|
+
if (error instanceof ProviderExecutionError) throw error;
|
|
1430
|
+
throw new ProviderExecutionError(
|
|
1431
|
+
`[Sandbox] POETIC_SANDBOX_PROFILE_PATH could not be read: ${profilePath} [reason=invalid_custom_sandbox_profile]`,
|
|
1432
|
+
{ retryable: false, reason: "invalid_custom_sandbox_profile" }
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
const policy = contents.replace(/;.*$/gm, "");
|
|
1436
|
+
const hasDenyDefault = /\(\s*deny\s+default\s*\)/.test(policy);
|
|
1437
|
+
const hasAllowDefault = /\(\s*allow\s+default\s*\)/.test(policy);
|
|
1438
|
+
if (hasAllowDefault) {
|
|
1439
|
+
throw new ProviderExecutionError(
|
|
1440
|
+
`[Sandbox] Custom sandbox profile contains (allow default), which grants an unrestricted sandbox: ${profilePath} [reason=invalid_custom_sandbox_profile]`,
|
|
1441
|
+
{ retryable: false, reason: "invalid_custom_sandbox_profile" }
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
if (!hasDenyDefault) {
|
|
1445
|
+
throw new ProviderExecutionError(
|
|
1446
|
+
`[Sandbox] Custom sandbox profile must contain (deny default): ${profilePath} [reason=invalid_custom_sandbox_profile]`,
|
|
1447
|
+
{ retryable: false, reason: "invalid_custom_sandbox_profile" }
|
|
1448
|
+
);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
function unwrappedAcceptedBoundaryResult(attestation, config, platform) {
|
|
1452
|
+
const boundaryProof = boundaryProofForProvenance(attestation.provenance);
|
|
1453
|
+
if (boundaryProof === void 0) {
|
|
1454
|
+
return void 0;
|
|
1455
|
+
}
|
|
1456
|
+
const policyProof = policyProofForAcceptedBoundary(
|
|
1457
|
+
attestation,
|
|
1458
|
+
config.providerId ?? config.providerName.toLowerCase(),
|
|
1459
|
+
config.env
|
|
1460
|
+
);
|
|
1461
|
+
const linuxHostClass = isLinuxWriteProvenance(attestation.provenance);
|
|
1462
|
+
logSandboxTelemetry(
|
|
1463
|
+
{
|
|
1464
|
+
providerName: config.providerName,
|
|
1465
|
+
sandboxed: !linuxHostClass,
|
|
1466
|
+
reason: attestation.provenance,
|
|
1467
|
+
platform,
|
|
1468
|
+
workingDir: config.workingDir
|
|
1469
|
+
},
|
|
1470
|
+
{
|
|
1471
|
+
provenance: attestation.provenance,
|
|
1472
|
+
boundaryProof,
|
|
1473
|
+
policyProof,
|
|
1474
|
+
providerId: config.providerId ?? config.providerName.toLowerCase()
|
|
1475
|
+
}
|
|
1476
|
+
);
|
|
1477
|
+
return {
|
|
1478
|
+
command: config.command,
|
|
1479
|
+
args: config.args,
|
|
1480
|
+
// Host class is write permission, not confinement. Gate 3 checks proofs.
|
|
1481
|
+
sandboxed: !linuxHostClass,
|
|
1482
|
+
boundaryProof,
|
|
1483
|
+
policyProof
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
function wrapWithSandbox(config, options) {
|
|
1487
|
+
const {
|
|
1488
|
+
workingDir,
|
|
1489
|
+
command,
|
|
1490
|
+
args,
|
|
1491
|
+
providerName,
|
|
1492
|
+
extraWritePaths,
|
|
1493
|
+
readOnlyWorkingDir,
|
|
1494
|
+
allowGitWrites,
|
|
1495
|
+
requiresBoundaryForWrites,
|
|
1496
|
+
providerId,
|
|
1497
|
+
env
|
|
1498
|
+
} = config;
|
|
1499
|
+
const platform = os4.platform();
|
|
1500
|
+
let reason;
|
|
1501
|
+
const runningUnderVitest = isTestRuntime();
|
|
1502
|
+
if (!isSandboxEnabled(providerName, providerId)) {
|
|
1503
|
+
const attestation = detectSandboxBoundaryAttestation(providerName, providerId, options);
|
|
1504
|
+
const boundaryPolicy = resolveEnvSandboxBoundaryPolicy();
|
|
1505
|
+
if (isSandboxBoundaryAccepted(attestation, boundaryPolicy)) {
|
|
1506
|
+
const accepted = unwrappedAcceptedBoundaryResult(attestation, config, platform);
|
|
1507
|
+
if (accepted) {
|
|
1508
|
+
return accepted;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
const globalDisabled = process.env.POETIC_SANDBOX_ENABLED === "0";
|
|
1512
|
+
const disabledKey = providerId ? `provider_disabled_${providerId}` : `provider_disabled_${providerName}`;
|
|
1513
|
+
reason = globalDisabled ? "globally_disabled" : disabledKey;
|
|
1514
|
+
logSandboxTelemetry({
|
|
1515
|
+
providerName,
|
|
1516
|
+
sandboxed: false,
|
|
1517
|
+
reason,
|
|
1518
|
+
platform,
|
|
1519
|
+
workingDir
|
|
1520
|
+
});
|
|
1521
|
+
if (requiresBoundaryForWrites && !readOnlyWorkingDir && !hasExplicitSandboxOptOut(providerName, providerId)) {
|
|
1522
|
+
if (platform === "linux") {
|
|
1523
|
+
authorizeLinuxHostClassWrites(options);
|
|
1524
|
+
}
|
|
1525
|
+
throw new ProviderExecutionError(
|
|
1526
|
+
`[${providerName}] write-capable provider execution requires an active sandbox boundary; the sandbox is disabled only by an implicit test-runtime signal (reason=${reason}). Set POETIC_SANDBOX_ENABLED=0 explicitly to accept unconfined execution [reason=sandbox_boundary_required]`,
|
|
1527
|
+
{ retryable: false, reason: "sandbox_boundary_required", providerName }
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1530
|
+
return { command, args, sandboxed: false };
|
|
1531
|
+
}
|
|
1532
|
+
if (!isSandboxSupported()) {
|
|
1533
|
+
const attestation = detectSandboxBoundaryAttestation(providerName, providerId, options);
|
|
1534
|
+
const boundaryPolicy = resolveEnvSandboxBoundaryPolicy();
|
|
1535
|
+
if (isSandboxBoundaryAccepted(attestation, boundaryPolicy)) {
|
|
1536
|
+
const accepted = unwrappedAcceptedBoundaryResult(attestation, config, platform);
|
|
1537
|
+
if (accepted) {
|
|
1538
|
+
return accepted;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
if (platform !== "linux") {
|
|
1542
|
+
logSandboxUnavailable();
|
|
1543
|
+
}
|
|
1544
|
+
reason = platform === "darwin" ? "sandbox_exec_not_found" : "unsupported_platform";
|
|
1545
|
+
logSandboxTelemetry({
|
|
1546
|
+
providerName,
|
|
1547
|
+
sandboxed: false,
|
|
1548
|
+
reason,
|
|
1549
|
+
platform,
|
|
1550
|
+
workingDir
|
|
1551
|
+
});
|
|
1552
|
+
if (requiresBoundaryForWrites && !readOnlyWorkingDir) {
|
|
1553
|
+
if (platform === "linux") {
|
|
1554
|
+
const authorized = authorizeLinuxHostClassWrites(options);
|
|
1555
|
+
if (authorized.status === "allowed") {
|
|
1556
|
+
const allowedAttestation = {
|
|
1557
|
+
provenance: authorized.provenance,
|
|
1558
|
+
evidence: attestation.evidence
|
|
1559
|
+
};
|
|
1560
|
+
const accepted = unwrappedAcceptedBoundaryResult(allowedAttestation, config, platform);
|
|
1561
|
+
if (accepted) {
|
|
1562
|
+
return accepted;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
throw new ProviderExecutionError(
|
|
1567
|
+
`[${providerName}] write-capable provider execution requires an active sandbox boundary, but none is available on this platform (platform=${platform}, provenance=${attestation.provenance}) [reason=sandbox_boundary_required]`,
|
|
1568
|
+
{ retryable: false, reason: "sandbox_boundary_required", providerName }
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
return { command, args, sandboxed: false };
|
|
1572
|
+
}
|
|
1573
|
+
if (!readOnlyWorkingDir && !runningUnderVitest && isKernelSandboxActive() && isNestedSandboxReinitDenied()) {
|
|
1574
|
+
const inheritedAttestation = {
|
|
1575
|
+
provenance: "inherited_outer",
|
|
1576
|
+
evidence: {
|
|
1577
|
+
seatbeltSelfOperational: false,
|
|
1578
|
+
sandboxRuntimeEnv: process.env.SANDBOX_RUNTIME === "1",
|
|
1579
|
+
kernelSandboxActive: true,
|
|
1580
|
+
nestedSandboxReinitDenied: true,
|
|
1581
|
+
containerAttested: isContainerAttestedByEnv()
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
if (!isSandboxBoundaryAccepted(inheritedAttestation, resolveEnvSandboxBoundaryPolicy())) {
|
|
1585
|
+
logSandboxTelemetry({
|
|
1586
|
+
providerName,
|
|
1587
|
+
sandboxed: false,
|
|
1588
|
+
reason: "inherited_outer_rejected_by_policy",
|
|
1589
|
+
platform,
|
|
1590
|
+
workingDir
|
|
1591
|
+
});
|
|
1592
|
+
if (requiresBoundaryForWrites) {
|
|
1593
|
+
throw new ProviderExecutionError(
|
|
1594
|
+
`[${providerName}] write-capable provider execution requires an active sandbox boundary, but the inherited outer boundary is rejected under POETIC_SANDBOX_BOUNDARY_POLICY=strict [reason=sandbox_boundary_required]`,
|
|
1595
|
+
{ retryable: false, reason: "sandbox_boundary_required", providerName }
|
|
1596
|
+
);
|
|
1597
|
+
}
|
|
1598
|
+
return { command, args, sandboxed: false };
|
|
1599
|
+
}
|
|
1600
|
+
reason = "inherited_outer";
|
|
1601
|
+
logSandboxTelemetry({
|
|
1602
|
+
providerName,
|
|
1603
|
+
sandboxed: true,
|
|
1604
|
+
reason,
|
|
1605
|
+
platform,
|
|
1606
|
+
workingDir
|
|
1607
|
+
});
|
|
1608
|
+
return {
|
|
1609
|
+
command,
|
|
1610
|
+
args,
|
|
1611
|
+
sandboxed: true,
|
|
1612
|
+
boundaryProof: "inherited_outer",
|
|
1613
|
+
policyProof: policyProofForAcceptedBoundary(
|
|
1614
|
+
inheritedAttestation,
|
|
1615
|
+
providerId ?? providerName.toLowerCase(),
|
|
1616
|
+
env
|
|
1617
|
+
)
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
const customProfile = process.env.POETIC_SANDBOX_PROFILE_PATH;
|
|
1621
|
+
let profilePath;
|
|
1622
|
+
try {
|
|
1623
|
+
if (customProfile) {
|
|
1624
|
+
validateCustomSandboxProfile(customProfile);
|
|
1625
|
+
profilePath = customProfile;
|
|
1626
|
+
} else {
|
|
1627
|
+
profilePath = getOrCreateProfile(
|
|
1628
|
+
workingDir,
|
|
1629
|
+
extraWritePaths,
|
|
1630
|
+
readOnlyWorkingDir,
|
|
1631
|
+
env,
|
|
1632
|
+
providerId ?? providerName.toLowerCase(),
|
|
1633
|
+
allowGitWrites,
|
|
1634
|
+
resolveAllowAwsCredentialRead({
|
|
1635
|
+
providerId: providerId ?? providerName.toLowerCase(),
|
|
1636
|
+
env,
|
|
1637
|
+
workingDir
|
|
1638
|
+
})
|
|
1639
|
+
);
|
|
1640
|
+
registerGlobalCleanup();
|
|
1641
|
+
}
|
|
1642
|
+
} catch (error) {
|
|
1643
|
+
reason = "profile_generation_failed";
|
|
1644
|
+
logSandboxTelemetry({
|
|
1645
|
+
providerName,
|
|
1646
|
+
sandboxed: false,
|
|
1647
|
+
reason,
|
|
1648
|
+
platform,
|
|
1649
|
+
workingDir
|
|
1650
|
+
});
|
|
1651
|
+
throw error;
|
|
1652
|
+
}
|
|
1653
|
+
const policyProof = customProfile ? void 0 : "wrap_applied";
|
|
1654
|
+
logSandboxTelemetry(
|
|
1655
|
+
{
|
|
1656
|
+
providerName,
|
|
1657
|
+
sandboxed: true,
|
|
1658
|
+
platform,
|
|
1659
|
+
workingDir,
|
|
1660
|
+
customProfile: !!customProfile
|
|
1661
|
+
},
|
|
1662
|
+
{
|
|
1663
|
+
provenance: "seatbelt_self",
|
|
1664
|
+
boundaryProof: "wrap_applied",
|
|
1665
|
+
policyProof,
|
|
1666
|
+
providerId: providerId ?? providerName.toLowerCase()
|
|
1667
|
+
}
|
|
1668
|
+
);
|
|
1669
|
+
return {
|
|
1670
|
+
command: "sandbox-exec",
|
|
1671
|
+
args: ["-f", profilePath, command, ...args],
|
|
1672
|
+
sandboxed: true,
|
|
1673
|
+
boundaryProof: "wrap_applied",
|
|
1674
|
+
policyProof
|
|
1675
|
+
};
|
|
1676
|
+
}
|
|
1677
|
+
function logSandboxTelemetry(entry, durable) {
|
|
1678
|
+
sandboxTelemetryLog.push({
|
|
1679
|
+
...entry,
|
|
1680
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1681
|
+
});
|
|
1682
|
+
if (sandboxTelemetryLog.length > 100) {
|
|
1683
|
+
sandboxTelemetryLog = sandboxTelemetryLog.slice(-100);
|
|
1684
|
+
}
|
|
1685
|
+
recordSandboxDecision({
|
|
1686
|
+
providerName: entry.providerName,
|
|
1687
|
+
providerId: durable?.providerId,
|
|
1688
|
+
sandboxed: entry.sandboxed,
|
|
1689
|
+
reason: entry.reason,
|
|
1690
|
+
provenance: durable?.provenance,
|
|
1691
|
+
boundaryProof: durable?.boundaryProof,
|
|
1692
|
+
policyProof: durable?.policyProof,
|
|
1693
|
+
platform: entry.platform
|
|
1694
|
+
});
|
|
1695
|
+
}
|
|
1696
|
+
function getSandboxTelemetry() {
|
|
1697
|
+
return [...sandboxTelemetryLog];
|
|
1698
|
+
}
|
|
1699
|
+
function clearSandboxTelemetry() {
|
|
1700
|
+
sandboxTelemetryLog = [];
|
|
1701
|
+
}
|
|
1702
|
+
function getSandboxStatusSummary() {
|
|
1703
|
+
const byProvider = {};
|
|
1704
|
+
const byReason = {};
|
|
1705
|
+
let sandboxedCount = 0;
|
|
1706
|
+
let unsandboxedCount = 0;
|
|
1707
|
+
for (const entry of sandboxTelemetryLog) {
|
|
1708
|
+
if (entry.sandboxed) {
|
|
1709
|
+
sandboxedCount++;
|
|
1710
|
+
} else {
|
|
1711
|
+
unsandboxedCount++;
|
|
1712
|
+
if (entry.reason) {
|
|
1713
|
+
byReason[entry.reason] = (byReason[entry.reason] || 0) + 1;
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
if (!byProvider[entry.providerName]) {
|
|
1717
|
+
byProvider[entry.providerName] = { sandboxed: 0, unsandboxed: 0 };
|
|
1718
|
+
}
|
|
1719
|
+
const providerStats = byProvider[entry.providerName];
|
|
1720
|
+
if (entry.sandboxed) {
|
|
1721
|
+
providerStats.sandboxed++;
|
|
1722
|
+
} else {
|
|
1723
|
+
providerStats.unsandboxed++;
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
return {
|
|
1727
|
+
totalExecutions: sandboxTelemetryLog.length,
|
|
1728
|
+
sandboxedCount,
|
|
1729
|
+
unsandboxedCount,
|
|
1730
|
+
byProvider,
|
|
1731
|
+
byReason
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
export {
|
|
1736
|
+
isSandboxSupported,
|
|
1737
|
+
isSandboxEnforcementSupported,
|
|
1738
|
+
LOCAL_CI_PUBLICATION_MAC_KEY_HOME_RELATIVE_DIR,
|
|
1739
|
+
beginHostPublicationGenerationJournal,
|
|
1740
|
+
abandonHostPublicationGenerationJournal,
|
|
1741
|
+
recoverHostPublicationGeneration,
|
|
1742
|
+
syncHostPublicationGeneration,
|
|
1743
|
+
attachOutstandingStatusPublicationMac,
|
|
1744
|
+
outstandingStatusPublicationMacIsValid,
|
|
1745
|
+
hasExplicitSandboxOptOut,
|
|
1746
|
+
isSandboxEnabledForProvider,
|
|
1747
|
+
willSandboxBeActive,
|
|
1748
|
+
isSandboxEnforcementOperational,
|
|
1749
|
+
requireActiveSandboxBoundary,
|
|
1750
|
+
requireActivePolicyBoundary,
|
|
1751
|
+
shouldBypassProviderInternalSandbox,
|
|
1752
|
+
detectSandboxBoundaryAttestation,
|
|
1753
|
+
resolveSandboxBoundaryPolicy,
|
|
1754
|
+
resolveEnvSandboxBoundaryPolicy,
|
|
1755
|
+
isAttestedInheritedOuterBoundary,
|
|
1756
|
+
isSandboxBoundaryAccepted,
|
|
1757
|
+
warnSandboxEnforcementUnavailable,
|
|
1758
|
+
wrapWithSandbox,
|
|
1759
|
+
getSandboxTelemetry,
|
|
1760
|
+
clearSandboxTelemetry,
|
|
1761
|
+
getSandboxStatusSummary
|
|
1762
|
+
};
|
|
1763
|
+
//# sourceMappingURL=chunk-PCAGC5MR.js.map
|