chainlesschain 0.166.92 → 0.166.93
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/package.json +3 -3
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-C74YzqwJ.js → AIOps-oo9rE0gh.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-TFef1hOE.js → ActionButton-CVJVVv4i.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CYsWpkkU.js → Analytics-CUXuwmia.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CFf9kjwu.js → AppLayout-iM4PvCuY.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-TQqa94YO.js → Artifacts-DKUIJbf9.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-B79ayqfS.js → Audit-C4_SzFN2.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-pjkHfLP9.js → BackgroundAgents-C3427uy-.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CE6A-t_r.js → Backup-BpEQQiog.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CwcgWMBY.js → BaseInput-C_exQomZ.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BIkDNesY.js → Chat-DzpkLtWa.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-DgaokYts.js → ChatBubbleRenderer-DX4XmTWm.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-MbypIy5V.js → Checkbox-CxAC1CU8.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DiFHWDnt.js → Codegen-wDFAGCLp.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BNMlYMso.js → Col-BvwirhMf.js} +1 -1
- package/src/assets/web-panel/assets/{Community-B3HVyHOX.js → Community-BJuA7paY.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-C7hlAubb.js → Compact-DzV35_u2.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-PaXZu6sE.js → Compliance-CIDPPvr9.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BGiojbm-.js → Cowork-DyTMxP3N.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-Bmr-1QAx.js → Cron-PcNLjMFx.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BwUvWCVd.js → Crosschain-B_O7ck6Z.js} +1 -1
- package/src/assets/web-panel/assets/{DID-k_4QZocW.js → DID-CII35Me1.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-_ieRo2C5.js → Dashboard-DU56fkNz.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DYHh6T27.js → Dropdown-DHC8HVeJ.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BNlQcWQX.js → EmailListRenderer-oUOHFNsD.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-DIkZ6U2D.js → EvolutionSettings-D7RCAWNl.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Dq7qSr0P.js → FamilyGuardDashboard-CGONPZxC.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-C64e3Cbx.js → Federation-BbDlPWcl.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-D-GE2vUa.js → FormItemContext-BBJbFQQT.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DO3B2gis.js → GenericCardRenderer-iuxAero4.js} +1 -1
- package/src/assets/web-panel/assets/{Git-0ETirIQH.js → Git-Dw0prdY5.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C9fnRygX.js → Governance-DOGqi_uV.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CLJ9RTsK.js → Inference-BY5oUGGj.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-D3C_GxrN.js → KnowledgeGraph-CcE2EVYX.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-C5ctGbkN.js → Logs-DyfN4R5w.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-Bj62Aq0M.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-GF_t6hJ_.js → Marketplace-CuuuAXUh.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BGsGzgQs.js → McpTools-948Fithv.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-CcrY2A0j.js → Memory-D4PINvyy.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Bi4T0RlS.js → MobileBridge-ECKMaLzX.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DvjEGyvf.js → MobileProjects-CB5MAcvD.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-DL77Vf-k.js → Mtc-BRzIM3HJ.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CDy_Uswb.js → MtcAudit-CGeAXJGn.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DL0BAO_c.js → Multisig-C_qJ-8K-.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-B-woh5IR.js → NLProgramming-DAEyCn7T.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CEFVCxk7.js → Notes-DmD3MEec.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BqPPMuAP.js → NotificationSettings-Cv4Q3VC9.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BNlpaFjH.js +1 -0
- package/src/assets/web-panel/assets/{Organization-B1gX8jlr.js → Organization-DqAFdz6p.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-CeMxuUZy.js → Overflow-8Ye9cIcE.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-B5aIRWwJ.js → P2P-755SfHoJ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-6rYgejd4.js → PdhVaultBrowser-CgZLiucX.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-CqCp2SIl.js → Permissions-C-vFF_rL.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-BsA7DJWW.js → PersonalDataHub-Diz1oXM3.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-CiW6HeZh.js → Pipeline-D4kIzsZG.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DckUOLYq.js → Privacy-QKLkSAUH.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CZppOOYR.js → ProjectInit-I0S9o_RT.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-B9QPzhDU.js → ProjectSettings-DdgV3-Ho.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BErjjGha.js → Projects-BJHHegtj.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DehU6Qiz.js → Providers-uVa1zfbS.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-E1SUvv1m.js → QrScannerModal-YLVpOChR.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-COWFxyH3.js → QuickAsk-535AYH61.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-D26pWKxX.js → Recommend-C_P6eNSw.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DCOIaId3.js → RemoteSession-EXH1SbNj.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DT_AHGAR.js → Reputation-Cxc7d3eU.js} +1 -1
- package/src/assets/web-panel/assets/{Row-B50S-1nl.js → Row-EDqJy-wS.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BaBnHg3Q.js → RssFeed-C03Xeg9_.js} +2 -2
- package/src/assets/web-panel/assets/{Search-BVdnLuuS.js → Search-DsIga9DK.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BnacH74J.js → Security-DgArMFc-.js} +3 -3
- package/src/assets/web-panel/assets/{Services-CxM08Zch.js → Services-MooDpHBP.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DE7CIc1N.js → Skeleton-B10P1Dr6.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CGI0SJmf.js → Skills-DHLHEkLl.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DpEzPcqc.js → Sla-D4RT7d4g.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CTmnmMHn.js → SpeechSettings-D8u6F-LV.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Dxgrd9hd.js → SyncSettings-4nvNzRq8.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CW4slS0A.js → Tasks-CmCb8zNO.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DxvGWDgB.js → Templates-CzESIa21.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-_Q0o2tNK.js → Tenant-Ch_N3p4d.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BTZn8pow.js → Terminal-BZccUf_X.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CauL0KFe.js → TimelineRenderer-FrKcNy_3.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CDoM2qeT.js → Tokens-4xvLpXfD.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-B-QYGEU7.js → Trigger-84UjyxXd.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BD6XJHT-.js → Trust-M6UtHnji.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-x4TFwCy0.js → UkeySign-L_xEgtCg.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-t3imBK_0.js → VideoEditing-BLJCX9ru.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BCfkWwNC.js → Wallet-DwL6uJCj.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-WH314Mdm.js → WebAuthn-Bmn9pdzz.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-jUlcjrUg.js → WorkflowEditor-DSsZ5xG1.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Dg3VASTL.js → chat--FGNUaa8.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BNvmBRKE.js → colors-DeuwNdqX.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BGOfoqf4.js → compact-item-I4XKxRFU.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BNQeqKAs.js → createContext-RoD2p5Ba.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-ctnml4IW.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Bg3AjCrq.js → hasIn-BsvyddUM.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6UqK83L.js → index-0tRU1Sv-.js} +1 -1
- package/src/assets/web-panel/assets/{index-uH2LnAs_.js → index-4xHc2WjT.js} +1 -1
- package/src/assets/web-panel/assets/{index-xzaUx19r.js → index-B8-eGLN9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYn5DnDk.js → index-BS_uqSTa.js} +1 -1
- package/src/assets/web-panel/assets/{index-DO0VlNtc.js → index-BYEVBlCl.js} +1 -1
- package/src/assets/web-panel/assets/{index-DF_FKSVH.js → index-BcBM065G.js} +1 -1
- package/src/assets/web-panel/assets/{index-CY8cRKHR.js → index-BnrL4s-3.js} +1 -1
- package/src/assets/web-panel/assets/{index-COol3xfA.js → index-BrZPb0On.js} +1 -1
- package/src/assets/web-panel/assets/index-C7PN8mh1.js +1 -0
- package/src/assets/web-panel/assets/{index-BBCMulQ-.js → index-CBazK4-7.js} +1 -1
- package/src/assets/web-panel/assets/{index-OUFoxUgH.js → index-CPS3zv1c.js} +1 -1
- package/src/assets/web-panel/assets/{index-60AnjUTX.js → index-CSrZiiAs.js} +1 -1
- package/src/assets/web-panel/assets/{index-D072oLjp.js → index-CVwZMt9Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_O2ZjPk.js → index-CdgKZYgm.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcCnO0RU.js → index-CesTu01s.js} +1 -1
- package/src/assets/web-panel/assets/{index-7QJUWemf.js → index-CiHlSuMl.js} +1 -1
- package/src/assets/web-panel/assets/{index-DS04wRll.js → index-CsLVac9n.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dkp-okWa.js → index-D1ONyBTW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmTacaQV.js → index-D4IZsKbF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaPvEvB4.js → index-D4P4vpmv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Co_LnCWD.js → index-D6J8dz7X.js} +1 -1
- package/src/assets/web-panel/assets/{index--I3UF5t1.js → index-DChy2sHE.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0mgngoB.js → index-DKUCl_Lk.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cx2EXRfr.js → index-DRluW3_r.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_JmInC0.js → index-DWUmhNO-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLwEXRrb.js → index-DXnpVGG3.js} +1 -1
- package/src/assets/web-panel/assets/{index-fOwii3LP.js → index-DYOpAS6-.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZD5Kd8tx.js → index-DiH-3cR2.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-mSvCQK.js → index-DlEfwgzr.js} +1 -1
- package/src/assets/web-panel/assets/index-KnbBJAO-.js +1 -0
- package/src/assets/web-panel/assets/{index-B--0QM0S.js → index-R4St_zjR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCFZN66A.js → index-ScgoDU9V.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSNhW95G.js → index-UWdT_lty.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cbp-wp-U.js → index-VAlor744.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bkz1tgFR.js → index-Wco_uvRo.js} +1 -1
- package/src/assets/web-panel/assets/{index-pVdQieac.js → index-ZgFED_Zd.js} +1 -1
- package/src/assets/web-panel/assets/{index-2D04Zltx.js → index-jaHeti4i.js} +3 -3
- package/src/assets/web-panel/assets/{index-hG7jXGEW.js → index-rJDabtw4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Wo0f2iqb.js → index-vRiGKIP0.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-B8PN9AxJ.js → initDefaultProps-BHT0PacY.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BHivfw5Q.js → motion-CBYsMtsC.js} +1 -1
- package/src/assets/web-panel/assets/{move-B0QU5nDd.js → move-DnHfFV4K.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DRwRM3PE.js → mtc-parser-DfGkRYrx.js} +1 -1
- package/src/assets/web-panel/assets/{omit-SHt2rV2p.js → omit-SjLcPQA9.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CcmDlEb2.js → pickAttrs-CCZHF4ep.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DYatmXDS.js → placementArrow-DjCGn2sJ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B7qrsXq5.js → responsiveObserve-BCFCl2on.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BRGhlOWd.js → slide-DsfmuIZu.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CT-7NXsQ.js → statusUtils-hPKuJUia.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-rZdw_Yyp.js → styleChecker-DOXKH7Kf.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-D8YNIP4P.js → useFlexGapSupport-B_G7yqio.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-B8pt0Gu-.js → useFs-BXOTOm2l.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-VMmYM1tt.js → usePersonalDataHub-CRvie3g7.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-UNDuoPoq.js → vnode-D9_zMmww.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-dN-u667S.js → zoom-C4tW03qI.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +13 -0
- package/src/lib/artifact-store.js +51 -3
- package/src/lib/bounded-artifact-file-read.js +131 -0
- package/src/lib/evolution/evolution-artifact-ports.js +209 -129
- package/src/lib/evolution/rrsi-history-ledger-adapter.js +25 -0
- package/src/lib/evolution/rrsi-installation-route-contracts.js +275 -0
- package/src/lib/evolution/rrsi-installation-route-reader.js +282 -0
- package/src/lib/evolution/rrsi-observed-text-index.js +978 -0
- package/src/lib/evolution/rrsi-registry-runtime-policy.js +648 -0
- package/src/lib/evolution/rrsi-registry-store-policy.js +95 -15
- package/src/lib/evolution/rrsi-tenant-index-anchor-contracts.js +223 -0
- package/src/lib/evolution/rrsi-tenant-index-anchor-history.js +157 -0
- package/src/lib/evolution/skill-release-registry.js +20 -5
- package/src/lib/process-execution-broker/windows-native-evaluator-capabilities.js +291 -30
- package/src/lib/remote-read-loop-guard.js +227 -24
- package/src/lib/task-progress-tracker.js +6 -1
- package/src/runtime/agent-core.js +71 -23
- package/src/assets/web-panel/assets/MarkdownRenderer-Ce-eWK3j.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-GUKQ1xwp.js +0 -1
- package/src/assets/web-panel/assets/devWarning-B7_ypN1G.js +0 -1
- package/src/assets/web-panel/assets/index-B-jSKJK6.js +0 -1
- package/src/assets/web-panel/assets/index-P4FXZJqI.js +0 -1
|
@@ -24,7 +24,9 @@ import fs from "fs";
|
|
|
24
24
|
import os from "os";
|
|
25
25
|
import path from "path";
|
|
26
26
|
import crypto from "crypto";
|
|
27
|
+
import { types as utilTypes } from "node:util";
|
|
27
28
|
import { withFileLock } from "./with-file-lock.js";
|
|
29
|
+
import { readBoundedArtifactFile } from "./bounded-artifact-file-read.js";
|
|
28
30
|
|
|
29
31
|
export const ARTIFACT_KINDS = Object.freeze([
|
|
30
32
|
"report",
|
|
@@ -144,6 +146,39 @@ function normalizeLineage(lineage) {
|
|
|
144
146
|
return normalized;
|
|
145
147
|
}
|
|
146
148
|
|
|
149
|
+
function integrityReadBounds(value) {
|
|
150
|
+
if (
|
|
151
|
+
!value ||
|
|
152
|
+
typeof value !== "object" ||
|
|
153
|
+
utilTypes.isProxy(value) ||
|
|
154
|
+
Object.getPrototypeOf(value) !== Object.prototype ||
|
|
155
|
+
Reflect.ownKeys(value).length !== 2
|
|
156
|
+
)
|
|
157
|
+
throw new TypeError(
|
|
158
|
+
"artifact integrity bounds require exact own data fields",
|
|
159
|
+
);
|
|
160
|
+
const values = Object.fromEntries(
|
|
161
|
+
["expectedSize", "maximumBytes"].map((name) => {
|
|
162
|
+
const field = Object.getOwnPropertyDescriptor(value, name);
|
|
163
|
+
if (!field?.enumerable || !("value" in field))
|
|
164
|
+
throw new TypeError("artifact integrity bounds cannot use accessors");
|
|
165
|
+
return [name, field.value];
|
|
166
|
+
}),
|
|
167
|
+
);
|
|
168
|
+
if (
|
|
169
|
+
!Number.isSafeInteger(values.expectedSize) ||
|
|
170
|
+
!Number.isSafeInteger(values.maximumBytes) ||
|
|
171
|
+
values.expectedSize < 0 ||
|
|
172
|
+
values.maximumBytes < 1 ||
|
|
173
|
+
values.expectedSize > values.maximumBytes ||
|
|
174
|
+
values.maximumBytes > MAX_ARTIFACT_BYTES
|
|
175
|
+
)
|
|
176
|
+
throw new TypeError(
|
|
177
|
+
"artifact integrity bounds exceed finite deliverable limits",
|
|
178
|
+
);
|
|
179
|
+
return Object.freeze(values);
|
|
180
|
+
}
|
|
181
|
+
|
|
147
182
|
export class ArtifactStore {
|
|
148
183
|
constructor({
|
|
149
184
|
dir = null,
|
|
@@ -449,8 +484,14 @@ export class ArtifactStore {
|
|
|
449
484
|
return path.join(this._filesDir(), entry.file);
|
|
450
485
|
}
|
|
451
486
|
|
|
452
|
-
/**
|
|
453
|
-
verifyIntegrity(idOrEntry) {
|
|
487
|
+
/** Explicit bounds constrain artifact bytes only; id lookup may still read the index. */
|
|
488
|
+
verifyIntegrity(idOrEntry, bounds) {
|
|
489
|
+
if (arguments.length > 2)
|
|
490
|
+
throw new TypeError(
|
|
491
|
+
"artifact integrity accepts at most one bounds object",
|
|
492
|
+
);
|
|
493
|
+
// An explicitly supplied invalid value must never select the legacy raw read.
|
|
494
|
+
const bounded = arguments.length > 1 ? integrityReadBounds(bounds) : null;
|
|
454
495
|
const entry =
|
|
455
496
|
typeof idOrEntry === "object" && idOrEntry
|
|
456
497
|
? idOrEntry
|
|
@@ -465,7 +506,14 @@ export class ArtifactStore {
|
|
|
465
506
|
}
|
|
466
507
|
let body;
|
|
467
508
|
try {
|
|
468
|
-
|
|
509
|
+
const target = this.storedPath(entry);
|
|
510
|
+
body = bounded
|
|
511
|
+
? readBoundedArtifactFile(
|
|
512
|
+
path.resolve(target),
|
|
513
|
+
bounded.expectedSize,
|
|
514
|
+
bounded.maximumBytes,
|
|
515
|
+
)
|
|
516
|
+
: fs.readFileSync(target);
|
|
469
517
|
} catch {
|
|
470
518
|
return {
|
|
471
519
|
ok: false,
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/** A bounded canonical-path read, not a persistent identity or authority grant. */
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { readBoundedDescriptor } from "./evolution/bounded-descriptor-read.js";
|
|
5
|
+
import { withEvolutionFileIdentity } from "./evolution/evolution-file-identity.js";
|
|
6
|
+
import { artifactPhysicalIdentity } from "./evolution/evolution-artifact-identity.js";
|
|
7
|
+
|
|
8
|
+
export const ARTIFACT_BOUNDED_READ_FAILED_CODE =
|
|
9
|
+
"CC_ARTIFACT_BOUNDED_READ_FAILED";
|
|
10
|
+
const FIELDS = Object.freeze([
|
|
11
|
+
"dev",
|
|
12
|
+
"ino",
|
|
13
|
+
"mode",
|
|
14
|
+
"uid",
|
|
15
|
+
"gid",
|
|
16
|
+
"nlink",
|
|
17
|
+
"size",
|
|
18
|
+
"mtimeNs",
|
|
19
|
+
"ctimeNs",
|
|
20
|
+
]);
|
|
21
|
+
const MUTATION_FIELDS = Object.freeze(
|
|
22
|
+
FIELDS.filter((name) => name !== "dev" && name !== "ino"),
|
|
23
|
+
);
|
|
24
|
+
const DIRECTORY_FS = Object.freeze({
|
|
25
|
+
constants: fs.constants,
|
|
26
|
+
realpathSync: fs.realpathSync,
|
|
27
|
+
lstatSync: (...args) => fs.lstatSync(...args),
|
|
28
|
+
fstatSync: (...args) => fs.fstatSync(...args),
|
|
29
|
+
closeSync: (...args) => fs.closeSync(...args),
|
|
30
|
+
openSync: (target, flags) =>
|
|
31
|
+
fs.openSync(
|
|
32
|
+
target,
|
|
33
|
+
flags | (fs.constants.O_NONBLOCK || 0) | (fs.constants.O_DIRECTORY || 0),
|
|
34
|
+
),
|
|
35
|
+
});
|
|
36
|
+
const canonical = (value) =>
|
|
37
|
+
process.platform === "win32" ? value.toLowerCase() : value;
|
|
38
|
+
function fail(message, cause) {
|
|
39
|
+
const error = new Error(message, cause ? { cause } : undefined);
|
|
40
|
+
error.code = ARTIFACT_BOUNDED_READ_FAILED_CODE;
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
function safeStat(stat, expectedSize, maximumBytes, label) {
|
|
44
|
+
if (FIELDS.some((name) => typeof stat?.[name] !== "bigint"))
|
|
45
|
+
fail(`${label} requires full-precision stat fields`);
|
|
46
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1n)
|
|
47
|
+
fail(`${label} must be a regular, non-symlink, single-link file`);
|
|
48
|
+
if (
|
|
49
|
+
stat.size < 0n ||
|
|
50
|
+
stat.size > BigInt(maximumBytes) ||
|
|
51
|
+
stat.size !== BigInt(expectedSize)
|
|
52
|
+
)
|
|
53
|
+
fail(`${label} differs from its bounded expected size`);
|
|
54
|
+
}
|
|
55
|
+
function sameMetadata(left, right) {
|
|
56
|
+
return (
|
|
57
|
+
MUTATION_FIELDS.every((name) => left[name] === right[name]) &&
|
|
58
|
+
artifactPhysicalIdentity(left).birthtimeMs ===
|
|
59
|
+
artifactPhysicalIdentity(right).birthtimeMs
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
function sameStat(left, right) {
|
|
63
|
+
return (
|
|
64
|
+
left.dev === right.dev &&
|
|
65
|
+
left.ino === right.ino &&
|
|
66
|
+
sameMetadata(left, right)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Read one stable window only. Callers retain hash/signature and root checks. */
|
|
71
|
+
export function readBoundedArtifactFile(target, expectedSize, maximumBytes) {
|
|
72
|
+
if (
|
|
73
|
+
arguments.length !== 3 ||
|
|
74
|
+
typeof target !== "string" ||
|
|
75
|
+
!path.isAbsolute(target) ||
|
|
76
|
+
path.resolve(target) !== target ||
|
|
77
|
+
!Number.isSafeInteger(expectedSize) ||
|
|
78
|
+
!Number.isSafeInteger(maximumBytes) ||
|
|
79
|
+
expectedSize < 0 ||
|
|
80
|
+
maximumBytes < 1 ||
|
|
81
|
+
expectedSize > maximumBytes
|
|
82
|
+
)
|
|
83
|
+
throw new TypeError(
|
|
84
|
+
"bounded artifact read requires a canonical path and finite size bounds",
|
|
85
|
+
);
|
|
86
|
+
try {
|
|
87
|
+
return withEvolutionFileIdentity(DIRECTORY_FS, target, (samePathHandle) => {
|
|
88
|
+
const before = fs.lstatSync(target, { bigint: true });
|
|
89
|
+
safeStat(before, expectedSize, maximumBytes, "artifact path");
|
|
90
|
+
if (canonical(fs.realpathSync.native(target)) !== canonical(target))
|
|
91
|
+
fail("artifact path is not physically canonical");
|
|
92
|
+
const fd = fs.openSync(
|
|
93
|
+
target,
|
|
94
|
+
fs.constants.O_RDONLY |
|
|
95
|
+
(fs.constants.O_NOFOLLOW || 0) |
|
|
96
|
+
(fs.constants.O_NONBLOCK || 0),
|
|
97
|
+
);
|
|
98
|
+
try {
|
|
99
|
+
const opened = fs.fstatSync(fd, { bigint: true });
|
|
100
|
+
safeStat(opened, expectedSize, maximumBytes, "artifact descriptor");
|
|
101
|
+
if (!samePathHandle(before, opened) || !sameMetadata(before, opened))
|
|
102
|
+
fail("artifact path and descriptor identities differ");
|
|
103
|
+
const bytes = readBoundedDescriptor(
|
|
104
|
+
fs,
|
|
105
|
+
fd,
|
|
106
|
+
Number(opened.size),
|
|
107
|
+
maximumBytes,
|
|
108
|
+
);
|
|
109
|
+
const closed = fs.fstatSync(fd, { bigint: true });
|
|
110
|
+
const after = fs.lstatSync(target, { bigint: true });
|
|
111
|
+
safeStat(closed, expectedSize, maximumBytes, "artifact descriptor");
|
|
112
|
+
safeStat(after, expectedSize, maximumBytes, "artifact path");
|
|
113
|
+
if (!sameStat(opened, closed))
|
|
114
|
+
fail("artifact descriptor changed during bounded read");
|
|
115
|
+
if (
|
|
116
|
+
!sameStat(before, after) ||
|
|
117
|
+
!samePathHandle(after, closed) ||
|
|
118
|
+
!sameMetadata(after, closed) ||
|
|
119
|
+
canonical(fs.realpathSync.native(target)) !== canonical(target)
|
|
120
|
+
)
|
|
121
|
+
fail("artifact pathname changed during bounded read");
|
|
122
|
+
return bytes;
|
|
123
|
+
} finally {
|
|
124
|
+
fs.closeSync(fd);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
} catch (cause) {
|
|
128
|
+
if (cause?.code === ARTIFACT_BOUNDED_READ_FAILED_CODE) throw cause;
|
|
129
|
+
fail("artifact bounded descriptor read failed", cause);
|
|
130
|
+
}
|
|
131
|
+
}
|