chainlesschain 0.166.84 → 0.166.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -4
- package/package.json +3 -2
- 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-OYLnAlB5.js → AIOps-DZwiXAIh.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-uc9kbLR6.js → ActionButton-aNzXoIJP.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BH901FG0.js → Analytics-ETQk4ZXt.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-qypKb8GL.js → AppLayout-D5oEbeEC.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-Q-uPWyLY.js → Artifacts-ja48FAne.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-B8hMGMim.js → Audit-DlN0YnDt.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BSs8rJL_.js → BackgroundAgents-CzvyNsRg.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-2YMU_nCd.js → Backup-DXgEC2MQ.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DyMppTuT.js → BaseInput-D9XqejLx.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-B5QGMaDO.js → Chat-BTwuYUlN.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-B8ts_JnN.js → ChatBubbleRenderer-0anIC2Wn.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DAvtgEGd.js → Checkbox-CLuaQbDt.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BSChEVM3.js → Codegen-KwQUZs8A.js} +1 -1
- package/src/assets/web-panel/assets/{Col-G0zYohIP.js → Col-BCmROkzc.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CzCN0B_p.js → Community-CXlUEHR4.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DrIN3G8z.js → Compact-Dzx-lWI2.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CIsLa64Z.js → Compliance-CfXW82FF.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CGYoafsB.js → Cowork-DIISTRm2.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DJ1JPXuH.js → Cron-nyJ-KcFE.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-B-IqVFJl.js → Crosschain-Dtv1E4cV.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CAAczPz_.js → DID-BCTpektS.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Dkpel8VE.js → Dashboard-C1Q_m0So.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-ETNBf8-Z.js → Dropdown-BrQ5_PPL.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CJGDyjVD.js → EmailListRenderer-DjoNlONP.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-CL_hvVYe.js → EvolutionSettings-DaGaE6bX.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-iexOh6Dh.js → FamilyGuardDashboard-nJDWBECt.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DnDHvV5D.js → Federation-DhMUY_wG.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DLCDJjUp.js → FormItemContext-CbONJPuc.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CaCgXCjS.js → GenericCardRenderer-CDdX4dX-.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BVm-euUF.js → Git-DXbDVJdR.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DPnUvLWr.js → Governance-DbAfAvs1.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-5qCWSYKl.js → Inference-Dy-fGea2.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DXdv2oEh.js → KnowledgeGraph-DAxRpGUF.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BF2f7bBA.js → Logs-5L1UCR8X.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-u0FPafvT.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Bp-0Y7Ng.js → Marketplace-DUk_McDG.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-dm-Xdi63.js → McpTools-B6PNsZ_p.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-TBHK031z.js → Memory-BUUs8j5F.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BTILAlds.js → MobileBridge-pXRsgyuO.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DC0Clgzs.js → MobileProjects-D7v-2Hwm.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BvyWkmRw.js → Mtc-Deaj4faB.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-D7ksLoNa.js → MtcAudit-wUV0VUH1.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-Dpzu7X1t.js → Multisig-C67IIkts.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DZ0ADHSB.js → NLProgramming-BCA_CWrW.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-hIdkmRug.js → Notes-D9eu14hQ.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-R3jyP6Vf.js → NotificationSettings-Cnd-J4LM.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-d1zrFkqx.js → OrderTableRenderer-C4pHUuyZ.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DoA5WMcc.js → Organization-4YExAbnp.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DHjIloAQ.js → Overflow-BF-wFuZz.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-2TMon_Wy.js → P2P-CdiajqCT.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DEUxGSWO.js → PdhVaultBrowser-BkjfS6Th.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-CxKcZ-8X.js → Permissions-DrZ4D78_.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CcYtkHqc.js → PersonalDataHub-lDc6OXjz.js} +6 -6
- package/src/assets/web-panel/assets/{Pipeline-BxwOuq22.js → Pipeline-DqDS9ON1.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-VIx9pdsH.js → Privacy-BMekZRZu.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-COjp_erK.js → ProjectInit-LYS7NFvJ.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-x9NrZU80.js → ProjectSettings-CcJNHk9A.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DMgkw7QJ.js → Projects-DrfAHgdF.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-B_fR7Y7Y.js → Providers-aqsly9SR.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BUvzrn3V.js → QrScannerModal-ZWvR3zqg.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-C0sJwLy2.js → QuickAsk-BT5CgsvW.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CJC7Wpce.js → Recommend-Cz8Dz2RN.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-B62J6ZP0.js → RemoteSession-BlxPVbtQ.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-4f48kVBn.js → Reputation-B3VGBE-1.js} +1 -1
- package/src/assets/web-panel/assets/{Row-EzEMaYoV.js → Row-Bwv7vSEA.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Dy0wD83j.js → RssFeed-DHI085r_.js} +3 -3
- package/src/assets/web-panel/assets/{Search-GeVRHQND.js → Search-DBler5T0.js} +1 -1
- package/src/assets/web-panel/assets/{Security-omLr1J7w.js → Security-BZdw43NW.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DmGPaDAs.js → Services-Cslk5lUj.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CAla21Gm.js → Skeleton-Bur-C-25.js} +1 -1
- package/src/assets/web-panel/assets/Skills-v0zgLy0X.js +1 -0
- package/src/assets/web-panel/assets/{Sla-Cwi15-pZ.js → Sla-B1OWgQ51.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Cs8Zi1J8.js → SpeechSettings-CaBcEaV4.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-ipuJsDKP.js → SyncSettings-CBbG8L6J.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-C7EjXrnN.js +1 -0
- package/src/assets/web-panel/assets/{Templates-slUp9yXF.js → Templates-VBBOZ1H5.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-6edCSG5K.js → Tenant-CtQTj7IF.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DKq84G3h.js → Terminal-DXVTQjnl.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Dg0Aw6se.js → TimelineRenderer-BRIno0aN.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-D63h7qYd.js → Tokens-uiiAfkYN.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-F7gTP_gv.js → Trigger-CPApN8o6.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-zw8Zqp8k.js → Trust-T2jKVwCE.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-C-YBUmod.js → UkeySign-C2U_gbzP.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-AhVxTgmC.js → VideoEditing-BCdlr3Kj.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-C58zxjIg.js → Wallet-CWnjoSc1.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-D-n-rlfI.js → WebAuthn-CqSbYqHq.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Ddc8gGD4.js → WorkflowEditor-Dr_I3jcr.js} +1 -1
- package/src/assets/web-panel/assets/{chat-C66V_U7w.js → chat-Cg21FKdE.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BcJyVZRj.js → colors-CK85tY9e.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-UgUXWcgP.js → compact-item-m-XYPC7W.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-oxEKHKYP.js → createContext-BmiEeNvs.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CkMEODFC.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CbqzrKQO.js → hasIn-CCw4KAoc.js} +1 -1
- package/src/assets/web-panel/assets/{index-CH13yc9x.js → index-6jXf-Lln.js} +1 -1
- package/src/assets/web-panel/assets/{index-BdFgUn1S.js → index-8KzhlvJ9.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3xNhHF3.js → index-B7xJkhtJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAIuMvVR.js → index-B8IC9ZeZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrG-1Kqs.js → index-BGUYgc96.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bu1A2sXy.js → index-BGb1j2z9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQlGMcZ9.js → index-BHsiSoGY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWFNv_EG.js → index-BIOTRzaF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BrWZmUdA.js → index-BStyjmLG.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-p9hhAz.js → index-BUYyhYP6.js} +1 -1
- package/src/assets/web-panel/assets/{index-CM2S5TJZ.js → index-BcfVHmFK.js} +1 -1
- package/src/assets/web-panel/assets/{index-7lSY8B9T.js → index-BiVPFsat.js} +1 -1
- package/src/assets/web-panel/assets/index-BjE5qaKn.js +1 -0
- package/src/assets/web-panel/assets/{index-B-h0Jgtj.js → index-Br0ZNdu1.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8rgeCoC.js → index-Br9t_I1X.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRrxJygS.js → index-BtvVupUL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DO-5vgTW.js → index-Bv90WEWa.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBEL07sa.js → index-BvjC3t35.js} +1 -1
- package/src/assets/web-panel/assets/{index-UpN_kC9R.js → index-ByVvAXdl.js} +1 -1
- package/src/assets/web-panel/assets/{index-SzGgAqai.js → index-CBcgIWOe.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3j9jTfB.js → index-CN2xbLGz.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bmhw_Ler.js → index-CYEzWoyZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Crqqbu-W.js → index-Cf5arJie.js} +1 -1
- package/src/assets/web-panel/assets/index-CsFH-2Zk.js +1 -0
- package/src/assets/web-panel/assets/{index-BMOY4PSW.js → index-D1sU5-XA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BT2PZ9df.js → index-D7gS_TJl.js} +1 -1
- package/src/assets/web-panel/assets/{index-YvNh1UdB.js → index-DAlGVix-.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZ7mv_oS.js → index-DI9GJFcn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ov77O9mH.js → index-DIlGxS2W.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJluGB2F.js → index-DMbrl43d.js} +1 -1
- package/src/assets/web-panel/assets/{index-C6X26RJu.js → index-DmSgfXuz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMbJ06sF.js → index-DpIy2HzE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUmYwZyf.js → index-DxRhnsEC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNIq0NAn.js → index-IskAKXhx.js} +1 -1
- package/src/assets/web-panel/assets/{index-DR4YKlLt.js → index-J81uvUMN.js} +1 -1
- package/src/assets/web-panel/assets/{index-RnxuL8wM.js → index-OIbfsi-o.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bp9rfr-P.js → index-lhoexBDH.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpqJNeIj.js → index-sWUmvT8H.js} +1 -1
- package/src/assets/web-panel/assets/{index-CuZupgUw.js → index-yYmjkf38.js} +3 -3
- package/src/assets/web-panel/assets/{initDefaultProps-BK9ncFiF.js → initDefaultProps-Cc1XOmNe.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BxzXi1Pe.js → motion-BehsX88u.js} +1 -1
- package/src/assets/web-panel/assets/{move-CRmwRuah.js → move-BPx2YsqY.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BQq5_Znx.js → mtc-parser-BSFJgFQA.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Ch4VNY2j.js → omit-DBN5KUeo.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CUioBhrz.js → pickAttrs-BDK1yZ-9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Hj3o1CrW.js → placementArrow-C4rMmKNJ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-PfqJrlkI.js → responsiveObserve-BoeoOnxX.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BXcnR-Lu.js → slide-BKlr1bl9.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-C74a-ofo.js → statusUtils-Ky1apWPI.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Bq57I3ls.js → styleChecker-DxxR7uXk.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-ITPUjcDw.js → useFlexGapSupport-DmsUqVe9.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DzPuXDIS.js → useFs-CwkG7sOg.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DYSgt9L5.js → usePersonalDataHub-CddgeEfF.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-NPs_EJEk.js → vnode-C_-H8i4Y.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DZzO6KVS.js → zoom-aAsHUMNE.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/permissions.js +27 -2
- package/src/data/changelog.json +26 -0
- package/src/lib/background-interaction-resolver.js +4 -0
- package/src/lib/context-memory-kernel/durable-memory-port.js +71 -15
- package/src/lib/context-memory-kernel/index.js +1 -0
- package/src/lib/context-memory-kernel/memory-service.js +43 -16
- package/src/lib/context-memory-kernel/runtime.js +5 -3
- package/src/lib/context-memory-kernel/segmented-memory-port.js +687 -0
- package/src/lib/packer/pack-update-applier.js +41 -17
- package/src/lib/packer/pkg-config-generator.js +119 -2
- package/src/lib/packer/pkg-runner.js +7 -0
- package/src/lib/packer/pkg-targets.js +83 -0
- package/src/lib/packer/web-panel-builder.js +7 -0
- package/src/lib/permission-authority.js +157 -13
- package/src/lib/process-execution-broker/index.js +11 -0
- package/src/lib/process-execution-broker/linux-subreaper-helper.js +87 -13
- package/src/lib/process-execution-broker/packer-build-policy.js +31 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +11 -3
- package/src/lib/sandbox-egress-authority-monitor.js +62 -5
- package/src/lib/scoped-permission-store.js +119 -6
- package/src/lib/settings-authority-domain.cjs +37 -2
- package/src/lib/settings-loader.cjs +112 -42
- package/src/lib/settings-permission-authority.cjs +373 -0
- package/src/runtime/agent-core.js +79 -383
- package/src/runtime/headless-runner.js +8 -3
- package/src/runtime/headless-stream.js +10 -3
- package/src/runtime/permission-authority-host.js +137 -0
- package/src/runtime/provider-stream-state.js +379 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-qNJS3ygh.js +0 -1
- package/src/assets/web-panel/assets/Skills-QqEyIKOI.js +0 -1
- package/src/assets/web-panel/assets/Tasks-BbVAg9Z7.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BoDvrsgY.js +0 -1
- package/src/assets/web-panel/assets/index-BhqRbl5P.js +0 -1
- package/src/assets/web-panel/assets/index-DreT6MIR.js +0 -1
|
@@ -50,6 +50,7 @@ const _deps = {
|
|
|
50
50
|
writeSecurityStore: (...args) => securityStore().writeSecurityStore(...args),
|
|
51
51
|
withFileLock: (...args) => lockHelper()(...args),
|
|
52
52
|
};
|
|
53
|
+
const settingsObservations = new WeakSet();
|
|
53
54
|
|
|
54
55
|
// A process-wide owner deliberately revokes unrelated projects too. Matching
|
|
55
56
|
// only contributing paths misses absent files, parent discovery and aliases.
|
|
@@ -145,9 +146,11 @@ function accrete(target, sources, arr, file, kind) {
|
|
|
145
146
|
}
|
|
146
147
|
|
|
147
148
|
/** The ordered list of candidate settings files for a cwd. */
|
|
148
|
-
function settingsPaths(cwd, explicitFile) {
|
|
149
|
+
function settingsPaths(cwd, explicitFile, userSettingsFile = null) {
|
|
149
150
|
const home = _deps.homedir();
|
|
150
|
-
const list = [
|
|
151
|
+
const list = [
|
|
152
|
+
userSettingsFile || path.join(home, ".claude", "settings.json"),
|
|
153
|
+
];
|
|
151
154
|
// When run from a subdirectory, the project-root `.claude` sits BELOW cwd's
|
|
152
155
|
// own (closest wins) but ABOVE the user layer — so its rules apply yet a
|
|
153
156
|
// cwd-local settings file still overrides them. Null when cwd IS the root.
|
|
@@ -170,10 +173,10 @@ function settingsPaths(cwd, explicitFile) {
|
|
|
170
173
|
function inspectSettingsSources(opts = {}) {
|
|
171
174
|
const cwd = path.resolve(opts.cwd || process.cwd());
|
|
172
175
|
const candidates = [
|
|
173
|
-
...settingsPaths(cwd, opts.settingsFile),
|
|
176
|
+
...settingsPaths(cwd, opts.settingsFile, opts.userSettingsFile),
|
|
174
177
|
managedSettingsPath(opts),
|
|
175
178
|
];
|
|
176
|
-
|
|
179
|
+
const observation = Object.freeze({
|
|
177
180
|
schema: "chainlesschain.settings-source-observation/v1",
|
|
178
181
|
cwd,
|
|
179
182
|
sources: observeSettingsSources(candidates, {
|
|
@@ -181,6 +184,8 @@ function inspectSettingsSources(opts = {}) {
|
|
|
181
184
|
maxBytes: opts.maxBytes,
|
|
182
185
|
}),
|
|
183
186
|
});
|
|
187
|
+
settingsObservations.add(observation);
|
|
188
|
+
return observation;
|
|
184
189
|
}
|
|
185
190
|
|
|
186
191
|
/** Organization-controlled settings file. This layer is always highest. */
|
|
@@ -273,13 +278,50 @@ function loadSettings(opts = {}) {
|
|
|
273
278
|
const cwd = opts.cwd || process.cwd();
|
|
274
279
|
const env = opts.env || process.env;
|
|
275
280
|
const onWarn = opts.onWarn;
|
|
281
|
+
function* layers() {
|
|
282
|
+
for (const file of settingsPaths(cwd, opts.settingsFile)) {
|
|
283
|
+
yield { file, settings: readSettingsFile(file, { onWarn }) };
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return mergePermissionSettings(layers(), env, () =>
|
|
287
|
+
loadManagedSettings({
|
|
288
|
+
env,
|
|
289
|
+
managedSettingsFile: opts.managedSettingsFile,
|
|
290
|
+
onWarn,
|
|
291
|
+
}),
|
|
292
|
+
);
|
|
293
|
+
}
|
|
276
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Project the exact JSON trees read and hashed by inspectSettingsSources.
|
|
297
|
+
* No path discovery or filesystem read occurs here. The final source has the
|
|
298
|
+
* managed role even when an earlier explicit/user/project source has the same
|
|
299
|
+
* path; retaining both positions preserves precedence and provenance.
|
|
300
|
+
*
|
|
301
|
+
* This is a byte-bound projection, not a fresh authority check or an atomic
|
|
302
|
+
* inventory snapshot. Environment inputs retain their existing sampling rules.
|
|
303
|
+
*/
|
|
304
|
+
function projectSettingsObservation(observation, { env = {} } = {}) {
|
|
305
|
+
if (!settingsObservations.has(observation)) {
|
|
306
|
+
throw new TypeError("A strict settings source observation is required");
|
|
307
|
+
}
|
|
308
|
+
const managed = observation.sources[observation.sources.length - 1];
|
|
309
|
+
return mergePermissionSettings(
|
|
310
|
+
observation.sources.slice(0, -1).map((source) => ({
|
|
311
|
+
file: source.logicalPath,
|
|
312
|
+
settings: source.settings,
|
|
313
|
+
})),
|
|
314
|
+
env,
|
|
315
|
+
() => ({ file: managed.logicalPath, settings: managed.settings }),
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function mergePermissionSettings(layers, env, readManaged) {
|
|
277
320
|
let rules = emptyRules();
|
|
278
321
|
const sources = {};
|
|
279
322
|
const files = [];
|
|
280
323
|
|
|
281
|
-
for (const file of
|
|
282
|
-
const data = readSettingsFile(file, { onWarn });
|
|
324
|
+
for (const { file, settings: data } of layers) {
|
|
283
325
|
if (!data) continue;
|
|
284
326
|
const perms =
|
|
285
327
|
data.permissions && typeof data.permissions === "object"
|
|
@@ -308,11 +350,7 @@ function loadSettings(opts = {}) {
|
|
|
308
350
|
}
|
|
309
351
|
if (envContributed) files.push("<env>");
|
|
310
352
|
|
|
311
|
-
const managedLoaded =
|
|
312
|
-
env,
|
|
313
|
-
managedSettingsFile: opts.managedSettingsFile,
|
|
314
|
-
onWarn,
|
|
315
|
-
});
|
|
353
|
+
const managedLoaded = readManaged();
|
|
316
354
|
if (managedLoaded.settings) {
|
|
317
355
|
rules = applyManagedPermissionPolicy(
|
|
318
356
|
rules,
|
|
@@ -354,7 +392,38 @@ function scopeFile(cwd, scope) {
|
|
|
354
392
|
* @returns {{ file:string, added:boolean }} added=false → already present.
|
|
355
393
|
* @throws if the target file exists but is malformed JSON (refuse to clobber).
|
|
356
394
|
*/
|
|
357
|
-
function
|
|
395
|
+
function appendPermissionRule(data, file, kind, rule) {
|
|
396
|
+
if (
|
|
397
|
+
Object.hasOwn(data, "permissions") &&
|
|
398
|
+
(!data.permissions ||
|
|
399
|
+
typeof data.permissions !== "object" ||
|
|
400
|
+
Array.isArray(data.permissions))
|
|
401
|
+
)
|
|
402
|
+
throw new TypeError(`refusing to overwrite malformed permissions: ${file}`);
|
|
403
|
+
data.permissions ??= {};
|
|
404
|
+
for (const decision of KINDS) {
|
|
405
|
+
if (
|
|
406
|
+
Object.hasOwn(data.permissions, decision) &&
|
|
407
|
+
(!Array.isArray(data.permissions[decision]) ||
|
|
408
|
+
data.permissions[decision].some((entry) => typeof entry !== "string"))
|
|
409
|
+
)
|
|
410
|
+
throw new TypeError(
|
|
411
|
+
`refusing to overwrite malformed permission rules: ${file}`,
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
data.permissions[kind] ??= [];
|
|
415
|
+
if (data.permissions[kind].includes(rule)) return false;
|
|
416
|
+
data.permissions[kind].push(rule);
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function addRule({
|
|
421
|
+
cwd = process.cwd(),
|
|
422
|
+
kind,
|
|
423
|
+
rule,
|
|
424
|
+
scope = "project",
|
|
425
|
+
settingsAuthority = null,
|
|
426
|
+
} = {}) {
|
|
358
427
|
const entryCwd = process.cwd();
|
|
359
428
|
const absoluteCwd = path.resolve(entryCwd, cwd);
|
|
360
429
|
// Check before lock acquisition: notification callbacks may reenter here.
|
|
@@ -368,11 +437,38 @@ function addRule({ cwd = process.cwd(), kind, rule, scope = "project" } = {}) {
|
|
|
368
437
|
if (!["project", "local", "user"].includes(scope)) {
|
|
369
438
|
throw new TypeError("scope must be project | local | user");
|
|
370
439
|
}
|
|
371
|
-
|
|
372
|
-
|
|
440
|
+
let file = path.resolve(entryCwd, scopeFile(absoluteCwd, scope));
|
|
441
|
+
if (settingsAuthority !== null) {
|
|
442
|
+
const authority = require("./settings-permission-authority.cjs");
|
|
443
|
+
const bound =
|
|
444
|
+
authority.settingsPermissionAuthorityOptions(settingsAuthority);
|
|
445
|
+
if (absoluteCwd !== bound.cwd)
|
|
446
|
+
throw new TypeError("settings authority cwd mismatch");
|
|
447
|
+
if (scope === "user") file = bound.userSettingsFile;
|
|
448
|
+
} else _deps.fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
373
449
|
let began = false;
|
|
374
450
|
let committed = false;
|
|
375
451
|
try {
|
|
452
|
+
if (settingsAuthority !== null) {
|
|
453
|
+
const authority = require("./settings-permission-authority.cjs");
|
|
454
|
+
const result = authority.mutateSettingsPermissionSource(
|
|
455
|
+
settingsAuthority,
|
|
456
|
+
{
|
|
457
|
+
logicalPath: file,
|
|
458
|
+
prepare: (data) => appendPermissionRule(data, file, kind, rule),
|
|
459
|
+
revokeLocal() {
|
|
460
|
+
beginSettingsMutation();
|
|
461
|
+
began = true;
|
|
462
|
+
},
|
|
463
|
+
replace(physicalPath, data) {
|
|
464
|
+
_deps.writeSecurityStore(physicalPath, "settings", data);
|
|
465
|
+
committed = true;
|
|
466
|
+
},
|
|
467
|
+
},
|
|
468
|
+
);
|
|
469
|
+
if (began) finishSettingsMutation("ready");
|
|
470
|
+
return { file, added: result.changed };
|
|
471
|
+
}
|
|
376
472
|
const result = _deps.withFileLock(
|
|
377
473
|
file,
|
|
378
474
|
() => {
|
|
@@ -387,35 +483,8 @@ function addRule({ cwd = process.cwd(), kind, rule, scope = "project" } = {}) {
|
|
|
387
483
|
);
|
|
388
484
|
}
|
|
389
485
|
const data = _deps.readSecurityStore(file, "settings");
|
|
390
|
-
if (
|
|
391
|
-
Object.hasOwn(data, "permissions") &&
|
|
392
|
-
(!data.permissions ||
|
|
393
|
-
typeof data.permissions !== "object" ||
|
|
394
|
-
Array.isArray(data.permissions))
|
|
395
|
-
) {
|
|
396
|
-
throw new TypeError(
|
|
397
|
-
`refusing to overwrite malformed permissions: ${file}`,
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
data.permissions ??= {};
|
|
401
|
-
// Refuse to hide a damaged rule list, including a different decision.
|
|
402
|
-
for (const decision of KINDS) {
|
|
403
|
-
if (
|
|
404
|
-
Object.hasOwn(data.permissions, decision) &&
|
|
405
|
-
(!Array.isArray(data.permissions[decision]) ||
|
|
406
|
-
data.permissions[decision].some(
|
|
407
|
-
(entry) => typeof entry !== "string",
|
|
408
|
-
))
|
|
409
|
-
) {
|
|
410
|
-
throw new TypeError(
|
|
411
|
-
`refusing to overwrite malformed permission rules: ${file}`,
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
data.permissions[kind] ??= [];
|
|
416
|
-
if (data.permissions[kind].includes(rule))
|
|
486
|
+
if (!appendPermissionRule(data, file, kind, rule))
|
|
417
487
|
return { file, added: false };
|
|
418
|
-
data.permissions[kind].push(rule);
|
|
419
488
|
beginSettingsMutation();
|
|
420
489
|
began = true;
|
|
421
490
|
_deps.writeSecurityStore(file, "settings", data);
|
|
@@ -662,6 +731,7 @@ function readStringArraySetting(key, opts = {}) {
|
|
|
662
731
|
|
|
663
732
|
module.exports = {
|
|
664
733
|
inspectSettingsSources,
|
|
734
|
+
projectSettingsObservation,
|
|
665
735
|
loadSettings,
|
|
666
736
|
loadSettingsConfig,
|
|
667
737
|
readSettingsFile,
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Trusted-host, cooperative Linux binding. Only explicit provisioning creates
|
|
4
|
+
// an authority; a reader/writer never registers or repairs a missing domain.
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const { types } = require("node:util");
|
|
7
|
+
const { createHash } = require("node:crypto");
|
|
8
|
+
const fs = require("node:fs");
|
|
9
|
+
const { observeSettingsSources } = require("./settings-source-observation.cjs");
|
|
10
|
+
const domain = require("./settings-authority-domain.cjs");
|
|
11
|
+
const records = require("./settings-authority-record.cjs");
|
|
12
|
+
const bindings = new WeakMap();
|
|
13
|
+
const SCHEMA = "chainlesschain.settings-permission-launch/v1";
|
|
14
|
+
const loader = () => require("./settings-loader.cjs");
|
|
15
|
+
|
|
16
|
+
function fail(code = "CC_SETTINGS_PERMISSION_BINDING_INVALID") {
|
|
17
|
+
throw Object.assign(
|
|
18
|
+
new Error("Persistent settings permission binding is unavailable"),
|
|
19
|
+
{ code },
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function dataCopy(input, depth = 0) {
|
|
24
|
+
if (input === null || ["string", "boolean", "number"].includes(typeof input))
|
|
25
|
+
return input;
|
|
26
|
+
if (!input || typeof input !== "object" || types.isProxy(input) || depth > 12)
|
|
27
|
+
fail();
|
|
28
|
+
const array = Array.isArray(input);
|
|
29
|
+
if (
|
|
30
|
+
!array &&
|
|
31
|
+
![Object.prototype, null].includes(Object.getPrototypeOf(input))
|
|
32
|
+
)
|
|
33
|
+
fail();
|
|
34
|
+
const output = array ? [] : {};
|
|
35
|
+
const keys = Reflect.ownKeys(input);
|
|
36
|
+
if (keys.length > 1024) fail();
|
|
37
|
+
for (const key of keys) {
|
|
38
|
+
if (array && key === "length") continue;
|
|
39
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
40
|
+
if (
|
|
41
|
+
typeof key !== "string" ||
|
|
42
|
+
!descriptor ||
|
|
43
|
+
!Object.hasOwn(descriptor, "value") ||
|
|
44
|
+
key === "__proto__" ||
|
|
45
|
+
(array && !/^(0|[1-9][0-9]*)$/.test(key))
|
|
46
|
+
)
|
|
47
|
+
fail();
|
|
48
|
+
output[key] = dataCopy(descriptor.value, depth + 1);
|
|
49
|
+
}
|
|
50
|
+
if (
|
|
51
|
+
array &&
|
|
52
|
+
(output.length !== input.length ||
|
|
53
|
+
Object.keys(output).length !== input.length)
|
|
54
|
+
)
|
|
55
|
+
fail();
|
|
56
|
+
return Object.freeze(output);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function exactKeys(value, keys) {
|
|
60
|
+
if (
|
|
61
|
+
!value ||
|
|
62
|
+
Array.isArray(value) ||
|
|
63
|
+
Object.keys(value).sort().join(",") !== [...keys].sort().join(",")
|
|
64
|
+
)
|
|
65
|
+
fail();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function absolute(value) {
|
|
69
|
+
if (
|
|
70
|
+
typeof value !== "string" ||
|
|
71
|
+
!value ||
|
|
72
|
+
!path.isAbsolute(value) ||
|
|
73
|
+
path.resolve(value) !== value
|
|
74
|
+
)
|
|
75
|
+
fail();
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function captureContexts(input, captured = false) {
|
|
80
|
+
const contexts = dataCopy(input);
|
|
81
|
+
if (!Array.isArray(contexts) || !contexts.length || contexts.length > 64)
|
|
82
|
+
fail();
|
|
83
|
+
const ids = new Set();
|
|
84
|
+
return Object.freeze(
|
|
85
|
+
contexts.map((context) => {
|
|
86
|
+
const fields = [
|
|
87
|
+
"contextId",
|
|
88
|
+
"cwd",
|
|
89
|
+
"settingsFile",
|
|
90
|
+
"managedSettingsFile",
|
|
91
|
+
"userSettingsFile",
|
|
92
|
+
"scopedFile",
|
|
93
|
+
];
|
|
94
|
+
if (captured) exactKeys(context, fields);
|
|
95
|
+
else if (Object.keys(context).some((key) => !fields.includes(key)))
|
|
96
|
+
fail();
|
|
97
|
+
if (
|
|
98
|
+
typeof context.contextId !== "string" ||
|
|
99
|
+
!/^[a-zA-Z0-9._:-]{1,128}$/.test(context.contextId) ||
|
|
100
|
+
ids.has(context.contextId)
|
|
101
|
+
)
|
|
102
|
+
fail();
|
|
103
|
+
ids.add(context.contextId);
|
|
104
|
+
const cwd = captured
|
|
105
|
+
? absolute(context.cwd)
|
|
106
|
+
: path.resolve(context.cwd || process.cwd());
|
|
107
|
+
const settingsFile =
|
|
108
|
+
context.settingsFile === null || context.settingsFile === undefined
|
|
109
|
+
? null
|
|
110
|
+
: captured
|
|
111
|
+
? absolute(context.settingsFile)
|
|
112
|
+
: path.resolve(cwd, context.settingsFile);
|
|
113
|
+
const managedSettingsFile = captured
|
|
114
|
+
? absolute(context.managedSettingsFile)
|
|
115
|
+
: loader().managedSettingsPath(context);
|
|
116
|
+
const userSettingsFile = captured
|
|
117
|
+
? absolute(context.userSettingsFile)
|
|
118
|
+
: context.userSettingsFile
|
|
119
|
+
? path.resolve(context.userSettingsFile)
|
|
120
|
+
: loader().scopeFile(cwd, "user");
|
|
121
|
+
const scopedFile = captured
|
|
122
|
+
? absolute(context.scopedFile)
|
|
123
|
+
: context.scopedFile
|
|
124
|
+
? path.resolve(context.scopedFile)
|
|
125
|
+
: require("./scoped-permission-store.js").defaultScopedPermissionStatePath(
|
|
126
|
+
cwd,
|
|
127
|
+
);
|
|
128
|
+
return Object.freeze({
|
|
129
|
+
contextId: context.contextId,
|
|
130
|
+
cwd,
|
|
131
|
+
settingsFile,
|
|
132
|
+
managedSettingsFile: path.resolve(managedSettingsFile),
|
|
133
|
+
userSettingsFile: path.resolve(userSettingsFile),
|
|
134
|
+
scopedFile,
|
|
135
|
+
});
|
|
136
|
+
}),
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function observe(contexts) {
|
|
141
|
+
const observations = new Map();
|
|
142
|
+
const manifests = contexts.map((context) => {
|
|
143
|
+
const observation = loader().inspectSettingsSources(context);
|
|
144
|
+
const scopedObservation = observeSettingsSources([context.scopedFile])[0];
|
|
145
|
+
observations.set(context.contextId, { observation, scopedObservation });
|
|
146
|
+
return records.createManifest({
|
|
147
|
+
contextId: context.contextId,
|
|
148
|
+
discovery: [
|
|
149
|
+
context.cwd,
|
|
150
|
+
context.userSettingsFile,
|
|
151
|
+
context.managedSettingsFile,
|
|
152
|
+
...(context.settingsFile ? [context.settingsFile] : []),
|
|
153
|
+
context.scopedFile,
|
|
154
|
+
],
|
|
155
|
+
sources: [...observation.sources, scopedObservation],
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
return { observations, manifests };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function observer(contexts, save = () => {}) {
|
|
162
|
+
return (expected) => {
|
|
163
|
+
if (
|
|
164
|
+
expected.length !== contexts.length ||
|
|
165
|
+
expected.some(
|
|
166
|
+
(context, index) => context.contextId !== contexts[index].contextId,
|
|
167
|
+
)
|
|
168
|
+
)
|
|
169
|
+
fail("CC_SETTINGS_AUTHORITY_BINDING_CHANGED");
|
|
170
|
+
// Recompute the complete discovery route, never reuse ledger source paths.
|
|
171
|
+
const current = observe(contexts);
|
|
172
|
+
save(current.observations);
|
|
173
|
+
return current.manifests;
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Explicit administrator/host provisioning. Parent directories must exist. */
|
|
178
|
+
function initializeSettingsPermissionAuthority({
|
|
179
|
+
directory,
|
|
180
|
+
forbiddenRoots,
|
|
181
|
+
contexts,
|
|
182
|
+
}) {
|
|
183
|
+
const captured = captureContexts(contexts);
|
|
184
|
+
const initial = observe(captured);
|
|
185
|
+
const handle = domain.initializeSettingsAuthorityDomain({
|
|
186
|
+
directory,
|
|
187
|
+
forbiddenRoots: [
|
|
188
|
+
...new Set([
|
|
189
|
+
...forbiddenRoots,
|
|
190
|
+
...captured.map((context) => context.cwd),
|
|
191
|
+
]),
|
|
192
|
+
],
|
|
193
|
+
contexts: initial.manifests,
|
|
194
|
+
observeContexts: observer(captured),
|
|
195
|
+
});
|
|
196
|
+
try {
|
|
197
|
+
return dataCopy({
|
|
198
|
+
schema: SCHEMA,
|
|
199
|
+
domain: domain.exportSettingsAuthorityDomain(handle),
|
|
200
|
+
contexts: captured,
|
|
201
|
+
});
|
|
202
|
+
} finally {
|
|
203
|
+
domain.closeSettingsAuthorityDomain(handle);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Reopen a fixed launch descriptor in a process or Worker; never bootstrap. */
|
|
208
|
+
function openSettingsPermissionAuthority({ launch, contextId }) {
|
|
209
|
+
launch = dataCopy(launch);
|
|
210
|
+
exactKeys(launch, ["schema", "domain", "contexts"]);
|
|
211
|
+
if (launch.schema !== SCHEMA) fail();
|
|
212
|
+
const contexts = captureContexts(launch.contexts, true);
|
|
213
|
+
const selected = contexts.find((context) => context.contextId === contextId);
|
|
214
|
+
if (!selected) fail("CC_SETTINGS_AUTHORITY_CONTEXT_UNREGISTERED");
|
|
215
|
+
const handle = domain.reopenSettingsAuthorityDomain({
|
|
216
|
+
descriptor: launch.domain,
|
|
217
|
+
});
|
|
218
|
+
const binding = Object.freeze({});
|
|
219
|
+
const state = { handle, launch, contexts, selected, closed: false };
|
|
220
|
+
bindings.set(binding, state);
|
|
221
|
+
try {
|
|
222
|
+
readSettingsPermissionAuthority(binding);
|
|
223
|
+
return binding;
|
|
224
|
+
} catch (error) {
|
|
225
|
+
closeSettingsPermissionAuthority(binding);
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function stateFor(binding) {
|
|
231
|
+
const state = bindings.get(binding);
|
|
232
|
+
if (!state || state.closed) fail();
|
|
233
|
+
return state;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function settingsPermissionAuthorityOptions(binding) {
|
|
237
|
+
return stateFor(binding).selected;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function exportSettingsPermissionAuthority(binding) {
|
|
241
|
+
const state = stateFor(binding);
|
|
242
|
+
domain.exportSettingsAuthorityDomain(state.handle); // Verify namespace first.
|
|
243
|
+
return state.launch;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function readSettingsPermissionAuthority(binding, { forUpdate = false } = {}) {
|
|
247
|
+
const state = stateFor(binding);
|
|
248
|
+
let observations;
|
|
249
|
+
const read = forUpdate
|
|
250
|
+
? domain.readSettingsAuthorityForUpdate
|
|
251
|
+
: domain.readSettingsAuthority;
|
|
252
|
+
const result = read(state.handle, {
|
|
253
|
+
observeContexts: observer(state.contexts, (value) => {
|
|
254
|
+
observations = value;
|
|
255
|
+
}),
|
|
256
|
+
localRevision: () => localRevision(state),
|
|
257
|
+
});
|
|
258
|
+
const observed = observations.get(state.selected.contextId);
|
|
259
|
+
return Object.freeze({
|
|
260
|
+
snapshot: result.snapshot,
|
|
261
|
+
observation: observed.observation,
|
|
262
|
+
scopedObservation: observed.scopedObservation,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function localRevision(state) {
|
|
267
|
+
const settings = loader().getSettingsPermissionRevision();
|
|
268
|
+
const scoped =
|
|
269
|
+
require("./scoped-permission-store.js").getScopedPermissionRevision();
|
|
270
|
+
if (
|
|
271
|
+
state.localRevision?.settings !== settings ||
|
|
272
|
+
state.localRevision?.scoped !== scoped
|
|
273
|
+
)
|
|
274
|
+
state.localRevision = Object.freeze({ settings, scoped });
|
|
275
|
+
return state.localRevision;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Keep the observation's minting and projection within one loader instance.
|
|
279
|
+
// Hosts with an ESM transform loader can also load CJS through native require;
|
|
280
|
+
// the native observation must still pass its original private WeakSet brand.
|
|
281
|
+
function projectSettingsPermissionObservation(observation, options) {
|
|
282
|
+
return loader().projectSettingsObservation(observation, options);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function assertSettingsPermissionWritableRoots(binding, roots) {
|
|
286
|
+
const state = stateFor(binding);
|
|
287
|
+
const directory = domain.exportSettingsAuthorityDomain(
|
|
288
|
+
state.handle,
|
|
289
|
+
).directory;
|
|
290
|
+
for (const root of roots) {
|
|
291
|
+
const canonical = fs.realpathSync(absolute(root));
|
|
292
|
+
const overlaps = [
|
|
293
|
+
path.relative(canonical, directory),
|
|
294
|
+
path.relative(directory, canonical),
|
|
295
|
+
].some(
|
|
296
|
+
(relative) =>
|
|
297
|
+
relative === "" ||
|
|
298
|
+
(!relative.startsWith(".." + path.sep) &&
|
|
299
|
+
relative !== ".." &&
|
|
300
|
+
!path.isAbsolute(relative)),
|
|
301
|
+
);
|
|
302
|
+
if (overlaps) fail("CC_SETTINGS_AUTHORITY_DOMAIN_OVERLAP");
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Used only by the official synchronous settings writer. Callbacks remain a
|
|
307
|
+
// trusted host contract; no callback or arbitrary source enters launch data.
|
|
308
|
+
function mutateSettingsPermissionSource(
|
|
309
|
+
binding,
|
|
310
|
+
{ logicalPath, prepare, revokeLocal, replace },
|
|
311
|
+
) {
|
|
312
|
+
const state = stateFor(binding);
|
|
313
|
+
logicalPath = absolute(logicalPath);
|
|
314
|
+
for (let attempt = 0; attempt < 8; attempt++) {
|
|
315
|
+
const current = readSettingsPermissionAuthority(binding, {
|
|
316
|
+
forUpdate: true,
|
|
317
|
+
});
|
|
318
|
+
const source = [
|
|
319
|
+
...current.observation.sources,
|
|
320
|
+
current.scopedObservation,
|
|
321
|
+
].find((item) => item.logicalPath === logicalPath);
|
|
322
|
+
if (!source) fail("CC_SETTINGS_AUTHORITY_SOURCE_UNREGISTERED");
|
|
323
|
+
const data = JSON.parse(JSON.stringify(source.settings || {}));
|
|
324
|
+
if (prepare(data) === false)
|
|
325
|
+
return { changed: false, snapshot: current.snapshot };
|
|
326
|
+
const bytes = Buffer.from(`${JSON.stringify(data, null, 2)}\n`);
|
|
327
|
+
if (bytes.length > 1024 * 1024) fail("CC_SETTINGS_SOURCE_TOO_LARGE");
|
|
328
|
+
try {
|
|
329
|
+
return domain.transitionSettingsAuthority(state.handle, {
|
|
330
|
+
intent: {
|
|
331
|
+
kind: "write",
|
|
332
|
+
physicalPath: source.physicalPath,
|
|
333
|
+
after: {
|
|
334
|
+
exists: true,
|
|
335
|
+
byteLength: bytes.length,
|
|
336
|
+
digest: createHash("sha256").update(bytes).digest("hex"),
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
expectedSnapshot: current.snapshot,
|
|
340
|
+
localRevision: () => localRevision(state),
|
|
341
|
+
observeContexts: observer(state.contexts),
|
|
342
|
+
revokeLocal,
|
|
343
|
+
replace: () => replace(source.physicalPath, data),
|
|
344
|
+
});
|
|
345
|
+
} catch (error) {
|
|
346
|
+
if (
|
|
347
|
+
error.cause?.code !== "CC_SETTINGS_AUTHORITY_CONFLICT" ||
|
|
348
|
+
error.commitState !== "not-committed" ||
|
|
349
|
+
error.authorityState !== "unchanged"
|
|
350
|
+
)
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
fail("CC_SETTINGS_AUTHORITY_CONFLICT");
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function closeSettingsPermissionAuthority(binding) {
|
|
358
|
+
const state = stateFor(binding);
|
|
359
|
+
domain.closeSettingsAuthorityDomain(state.handle);
|
|
360
|
+
state.closed = true;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
module.exports = {
|
|
364
|
+
initializeSettingsPermissionAuthority,
|
|
365
|
+
openSettingsPermissionAuthority,
|
|
366
|
+
exportSettingsPermissionAuthority,
|
|
367
|
+
closeSettingsPermissionAuthority,
|
|
368
|
+
settingsPermissionAuthorityOptions,
|
|
369
|
+
readSettingsPermissionAuthority,
|
|
370
|
+
projectSettingsPermissionObservation,
|
|
371
|
+
mutateSettingsPermissionSource,
|
|
372
|
+
assertSettingsPermissionWritableRoots,
|
|
373
|
+
};
|