@camstack/system 1.2.164 → 1.2.165
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/dist/addon-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/builtins/sqlite-storage/index.d.ts +1 -1
- package/dist/builtins/sqlite-storage/index.js +2 -0
- package/dist/builtins/sqlite-storage/index.mjs +2 -2
- package/dist/builtins/sqlite-storage/query-profiler.d.ts +21 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/kernel/deps/manifest-system-deps.d.ts +5 -2
- package/dist/kernel/deps/system-package-allowlist.d.ts +12 -0
- package/dist/kernel/deps/system-package-broker.d.ts +31 -0
- package/dist/kernel/deps/system-package-client.d.ts +9 -0
- package/dist/{manifest-system-deps-Bk_XLYbB.mjs → manifest-system-deps-D2GebQTp.mjs} +141 -5
- package/dist/{manifest-system-deps-CJLqfJUs.js → manifest-system-deps-uflHvHDB.js} +139 -4
- package/package.json +1 -1
package/dist/addon-runner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
const require_manifest_system_deps = require("./manifest-system-deps-
|
|
2
|
+
const require_manifest_system_deps = require("./manifest-system-deps-uflHvHDB.js");
|
|
3
3
|
const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
|
|
4
4
|
let node_path = require("node:path");
|
|
5
5
|
node_path = require_chunk.__toESM(node_path);
|
package/dist/addon-runner.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ct as resolveAddonClass, N as createUdsLoggerWithControl, P as LocalChildClient, Rt as RUNNER_RSS_BUDGET_ENV, St as installManifestNativeDeps, Zt as startRunnerHeapWatch, a as createUdsAddonContext, at as getWorkerNativeCapSnapshot, it as getWorkerNativeCapProvider, lt as validateProviderRegistrations, n as installManifestPythonDeps, nn as emitHeapDiagnosticReport, st as setWorkerNativeCapsChangeListener, t as installManifestSystemDeps } from "./manifest-system-deps-
|
|
1
|
+
import { Ct as resolveAddonClass, N as createUdsLoggerWithControl, P as LocalChildClient, Rt as RUNNER_RSS_BUDGET_ENV, St as installManifestNativeDeps, Zt as startRunnerHeapWatch, a as createUdsAddonContext, at as getWorkerNativeCapSnapshot, it as getWorkerNativeCapProvider, lt as validateProviderRegistrations, n as installManifestPythonDeps, nn as emitHeapDiagnosticReport, st as setWorkerNativeCapsChangeListener, t as installManifestSystemDeps } from "./manifest-system-deps-D2GebQTp.mjs";
|
|
2
2
|
import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
|
|
3
3
|
import { register } from "node:module";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -4,7 +4,7 @@ export { DeviceStore } from './device-store.js';
|
|
|
4
4
|
export { FilesystemStorageAddon, FilesystemStorageAddon as default, } from './filesystem-storage.addon.js';
|
|
5
5
|
export { FilesystemStorageProvider } from './filesystem-storage-provider.js';
|
|
6
6
|
export type { SqliteOpLabel, SqliteOpSample, SqliteOpStat } from './query-profiler.js';
|
|
7
|
-
export { SQLITE_PROFILE_REPORT_FLOOR_MS, SQLITE_PROFILE_REPORT_INTERVAL_MS, SQLITE_PROFILE_TOP_N, SQLITE_SLOW_CALL_MS, SqliteOpProfiler, } from './query-profiler.js';
|
|
7
|
+
export { SQLITE_ENGINE_STORM_WALL_SHARE, SQLITE_PROFILE_REPORT_FLOOR_MS, SQLITE_PROFILE_REPORT_INTERVAL_MS, SQLITE_PROFILE_TOP_N, SQLITE_SLOW_CALL_MS, sqliteEngineStorm, SqliteOpProfiler, } from './query-profiler.js';
|
|
8
8
|
export { SQLITE_JOURNAL_SIZE_LIMIT_BYTES, SQLITE_MMAP_CEILING_BYTES, SQLITE_MMAP_FLOOR_BYTES, SQLITE_PAGE_CACHE_CEILING_KIB, SQLITE_PAGE_CACHE_FLOOR_KIB, sqliteMmapSizeFor, sqlitePageCacheKibFor, } from './sqlite-pragmas.js';
|
|
9
9
|
export { SqliteSettingsAddon } from './sqlite-settings.addon.js';
|
|
10
10
|
export { SqliteSettingsBackend } from './sqlite-settings-backend.js';
|
|
@@ -57,6 +57,7 @@ exports.DeviceStore = DeviceStore;
|
|
|
57
57
|
exports.DeviceStore$1 = DeviceStore;
|
|
58
58
|
exports.FilesystemStorageAddon = require_builtins_sqlite_storage_filesystem_storage_addon.FilesystemStorageAddon;
|
|
59
59
|
exports.FilesystemStorageProvider = require_builtins_sqlite_storage_filesystem_storage_addon.FilesystemStorageProvider;
|
|
60
|
+
exports.SQLITE_ENGINE_STORM_WALL_SHARE = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_ENGINE_STORM_WALL_SHARE;
|
|
60
61
|
exports.SQLITE_JOURNAL_SIZE_LIMIT_BYTES = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_JOURNAL_SIZE_LIMIT_BYTES;
|
|
61
62
|
exports.SQLITE_MMAP_CEILING_BYTES = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_MMAP_CEILING_BYTES;
|
|
62
63
|
exports.SQLITE_MMAP_FLOOR_BYTES = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_MMAP_FLOOR_BYTES;
|
|
@@ -75,5 +76,6 @@ exports.WAL_IDLE_QUIET_MS = require_builtins_sqlite_storage_sqlite_settings_addo
|
|
|
75
76
|
exports.WAL_MAINTENANCE_INTERVAL_MS = require_builtins_sqlite_storage_sqlite_settings_addon.WAL_MAINTENANCE_INTERVAL_MS;
|
|
76
77
|
exports.WalMaintenance = require_builtins_sqlite_storage_sqlite_settings_addon.WalMaintenance;
|
|
77
78
|
exports.default = require_builtins_sqlite_storage_filesystem_storage_addon.FilesystemStorageAddon;
|
|
79
|
+
exports.sqliteEngineStorm = require_builtins_sqlite_storage_sqlite_settings_addon.sqliteEngineStorm;
|
|
78
80
|
exports.sqliteMmapSizeFor = require_builtins_sqlite_storage_sqlite_settings_addon.sqliteMmapSizeFor;
|
|
79
81
|
exports.sqlitePageCacheKibFor = require_builtins_sqlite_storage_sqlite_settings_addon.sqlitePageCacheKibFor;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FilesystemStorageAddon, t as FilesystemStorageProvider } from "./filesystem-storage.addon.mjs";
|
|
2
|
-
import { SqliteSettingsAddon, _ as
|
|
2
|
+
import { SqliteSettingsAddon, _ as SQLITE_PROFILE_REPORT_INTERVAL_MS, a as WalMaintenance, b as SqliteOpProfiler, c as SQLITE_JOURNAL_SIZE_LIMIT_BYTES, d as SQLITE_PAGE_CACHE_CEILING_KIB, f as SQLITE_PAGE_CACHE_FLOOR_KIB, g as SQLITE_PROFILE_REPORT_FLOOR_MS, h as SQLITE_ENGINE_STORM_WALL_SHARE, i as WAL_MAINTENANCE_INTERVAL_MS, l as SQLITE_MMAP_CEILING_BYTES, m as sqlitePageCacheKibFor, n as WAL_HIGH_WATER_BYTES, o as SqliteSettingsBackend, p as sqliteMmapSizeFor, r as WAL_IDLE_QUIET_MS, t as WAL_CHECKPOINT_BUSY_TIMEOUT_MS, u as SQLITE_MMAP_FLOOR_BYTES, v as SQLITE_PROFILE_TOP_N, x as sqliteEngineStorm, y as SQLITE_SLOW_CALL_MS } from "./sqlite-settings.addon.mjs";
|
|
3
3
|
//#region src/builtins/sqlite-storage/config-store.ts
|
|
4
4
|
var ConfigStore = class {
|
|
5
5
|
db;
|
|
@@ -46,4 +46,4 @@ var DeviceStore = class {
|
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
48
|
//#endregion
|
|
49
|
-
export { ConfigStore, DeviceStore, FilesystemStorageAddon, FilesystemStorageAddon as default, FilesystemStorageProvider, SQLITE_JOURNAL_SIZE_LIMIT_BYTES, SQLITE_MMAP_CEILING_BYTES, SQLITE_MMAP_FLOOR_BYTES, SQLITE_PAGE_CACHE_CEILING_KIB, SQLITE_PAGE_CACHE_FLOOR_KIB, SQLITE_PROFILE_REPORT_FLOOR_MS, SQLITE_PROFILE_REPORT_INTERVAL_MS, SQLITE_PROFILE_TOP_N, SQLITE_SLOW_CALL_MS, SqliteOpProfiler, SqliteSettingsAddon, SqliteSettingsBackend, WAL_CHECKPOINT_BUSY_TIMEOUT_MS, WAL_HIGH_WATER_BYTES, WAL_IDLE_QUIET_MS, WAL_MAINTENANCE_INTERVAL_MS, WalMaintenance, sqliteMmapSizeFor, sqlitePageCacheKibFor };
|
|
49
|
+
export { ConfigStore, DeviceStore, FilesystemStorageAddon, FilesystemStorageAddon as default, FilesystemStorageProvider, SQLITE_ENGINE_STORM_WALL_SHARE, SQLITE_JOURNAL_SIZE_LIMIT_BYTES, SQLITE_MMAP_CEILING_BYTES, SQLITE_MMAP_FLOOR_BYTES, SQLITE_PAGE_CACHE_CEILING_KIB, SQLITE_PAGE_CACHE_FLOOR_KIB, SQLITE_PROFILE_REPORT_FLOOR_MS, SQLITE_PROFILE_REPORT_INTERVAL_MS, SQLITE_PROFILE_TOP_N, SQLITE_SLOW_CALL_MS, SqliteOpProfiler, SqliteSettingsAddon, SqliteSettingsBackend, WAL_CHECKPOINT_BUSY_TIMEOUT_MS, WAL_HIGH_WATER_BYTES, WAL_IDLE_QUIET_MS, WAL_MAINTENANCE_INTERVAL_MS, WalMaintenance, sqliteEngineStorm, sqliteMmapSizeFor, sqlitePageCacheKibFor };
|
|
@@ -133,6 +133,27 @@ export declare const SQLITE_PROFILE_REPORT_INTERVAL_MS = 60000;
|
|
|
133
133
|
export declare const SQLITE_PROFILE_REPORT_FLOOR_MS = 250;
|
|
134
134
|
/** Pairs named in one report line. Enough to see the shape, short enough to read. */
|
|
135
135
|
export declare const SQLITE_PROFILE_TOP_N = 5;
|
|
136
|
+
/**
|
|
137
|
+
* Share of window wall-clock at which ONE shape is a storm, not a busy engine.
|
|
138
|
+
*
|
|
139
|
+
* Measured 2026-08-31: the OFFSET census on `pipeline-analytics:media` was
|
|
140
|
+
* 88.7 % of wall for six hours. A healthy bounded census (20 s budget in a
|
|
141
|
+
* 60 s window) is 33 % and must not warn. Half the loop is the line between
|
|
142
|
+
* "the engine is working" and "the cluster is queuing behind one query".
|
|
143
|
+
*
|
|
144
|
+
* Cap-usage rate cannot name this class — see `sqliteEngineStorm`.
|
|
145
|
+
*/
|
|
146
|
+
export declare const SQLITE_ENGINE_STORM_WALL_SHARE = 0.5;
|
|
147
|
+
/**
|
|
148
|
+
* The dominating shape if it held {@link SQLITE_ENGINE_STORM_WALL_SHARE} of
|
|
149
|
+
* the window, otherwise `null`.
|
|
150
|
+
*
|
|
151
|
+
* Share is of WINDOW wall, not of busy time: an engine that is 90 % busy with
|
|
152
|
+
* ten equal shapes is healthy; one shape at 50 % of wall is the 2026-08-31
|
|
153
|
+
* store saturation regardless of what else ran. `stats` must already be
|
|
154
|
+
* busiest-first (as {@link SqliteOpProfiler.drain} returns them).
|
|
155
|
+
*/
|
|
156
|
+
export declare function sqliteEngineStorm(stats: readonly SqliteOpStat[], windowMs: number): SqliteOpStat | null;
|
|
136
157
|
export interface SqliteOpProfilerOptions {
|
|
137
158
|
readonly logger: IScopedLogger;
|
|
138
159
|
/** Injected for tests; production reads the wall clock. */
|
|
Binary file
|
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ require("./builtins/system-config/index.js");
|
|
|
26
26
|
const require_builtins_winston_logging_index = require("./builtins/winston-logging/index.js");
|
|
27
27
|
const require_file_data_plane = require("./file-data-plane-DO8KbxCe.js");
|
|
28
28
|
const require_tls$1 = require("./tls-BxQlomxd.js");
|
|
29
|
-
const require_manifest_system_deps = require("./manifest-system-deps-
|
|
29
|
+
const require_manifest_system_deps = require("./manifest-system-deps-uflHvHDB.js");
|
|
30
30
|
const require_resource_monitor = require("./resource-monitor-CdnzxBLP.js");
|
|
31
31
|
const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
|
|
32
32
|
let zod = require("zod");
|
package/dist/index.mjs
CHANGED
|
@@ -25,7 +25,7 @@ import "./builtins/system-config/index.mjs";
|
|
|
25
25
|
import { WinstonDestination, WinstonLoggingAddon } from "./builtins/winston-logging/index.mjs";
|
|
26
26
|
import { a as parseTokenizedUrl, c as collectModelFiles, d as downloadModel, f as ensureModel, h as isModelDownloaded, i as parseRangeHeader, l as deleteModelFromDisk, m as getModelFilePath, n as contentTypeFor, o as resolveFilePath, p as fetchJson, r as createAuthenticatedFileServer, s as ModelDownloadService, t as createFileDataPlaneHandler, u as downloadFile } from "./file-data-plane-BhKdxJgf.mjs";
|
|
27
27
|
import { C as registerLanHttpHandler, S as readLanHttpState, _ as DEFAULT_LAN_HTTP_PORT, a as writeTlsMode, b as bindPendingLanHttp, c as loadTlsCert, d as collectCertIdentity, f as CA_VALIDITY_DAYS, g as evaluateExistingCert, h as SERVER_AUTH_OID, i as writeExtraSans, l as reissueTlsLeaf, m as MAX_LEAF_VALIDITY_DAYS, n as readTlsAccessStatus, o as validateUploadedTls, p as LEAF_RENEWAL_WINDOW_DAYS, r as readTlsMode, s as ensureTlsCert, t as readExtraSans, u as CA_COMMON_NAME, v as allFamiliesListenHost, x as closeLanHttp, y as applyLanHttp } from "./tls-DOTmtLCW.mjs";
|
|
28
|
-
import { $ as FrameDecoder, $t as DECISIVE_HEAP_SPACES, A as createUdsEventBus, At as HEAP_WATCH_INTERVAL_MS, B as CapRouteError, Bt as buildHeapSample, C as ipcParentLink, Cn as diffEventPlane, Ct as resolveAddonClass, D as createHubCapForwardService, Dt as HEAP_RECLAIM_MIN_INTERVAL_MS, E as HUB_CAP_FWD_SERVICE, Et as createAddonDataPlaneFacility, F as LocalChildRegistry, Ft as RSS_BUDGET_REANNOUNCE_MIN_MS, G as PARENT_ROUTED_PROVIDER_ADDON_ID, Gt as hubMainRssBudget, H as callWithServiceDiscovery, Ht as createLoopDelayMeter, I as UDS_NO_ROUTE_PREFIX, It as RSS_BUDGET_RELEASE_RATIO, J as createLocalTransport, Jt as reclaimIntervalMs, K as __resetCapUsageRegistryForTests, Kt as nextRssBudgetState, L as AGENT_CAP_FWD_ACTION, Lt as RUNNER_HEAP_WATCH_INTERVAL_MS, M as createUdsLogger, Mt as HUB_MAIN_HEAP_WATCH_LABEL, N as createUdsLoggerWithControl, Nt as HUB_MAIN_RSS_BUDGET_MB, O as createParentUnownedCallHandler, Ot as HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS, P as LocalChildClient, Pt as HUB_RSS_BUDGET_ENV, Q as localEndpointPath, Qt as strandedMb, R as AGENT_CAP_FWD_SERVICE, Rt as RUNNER_RSS_BUDGET_ENV, S as buildLinkChain, Sn as createEventPlaneReader, St as installManifestNativeDeps, T as HUB_CAP_FWD_ACTION, Tt as runNpm, U as readMoleculerFanoutMode, Ut as createV8Reclaimer, V as classifyCapRoute, Vt as createDeferredHeapWatchSink, W as CapUsageRegistry, Wt as describeRss, X as UdsLocalTransportServer, Xt as startHeapWatch, Y as UdsLocalTransportClient, Yt as shouldReclaim, Z as SocketChannel, Zt as startRunnerHeapWatch, _ as AddonDepsManager, _n as sampleSocketDirection, _t as serializeTypedArrays, a as createUdsAddonContext, an as heapSpaceField, b as brokerCallForCap, bn as EVENT_PLANE_TOP_N, bt as CapabilityUnavailableError, c as getOrInitReadinessRegistryForClient, cn as EMPTY_SOCKET_PLANE_BASELINE, ct as createAddonService, d as clusterEventTopic, dn as createSocketPlaneReader, dt as capActionName, en as HEAP_SPACE_REPORT_MIN_MB, et as encodeFrame, f as getBrokerEventBus, fn as diffSocketPlane, ft as capActionSuffix, g as subscribePassthrough, gn as recordSocketFrame, gt as deserializeTypedArrays, h as setNodeEventInterest, hn as createSocketDirectionCounters, ht as parseCapAction, i as createAddonContext, in as heapSnapshotAuthorised, j as udsChildLogToWorkerEntry, jt as HEAP_WATCH_WARN_RATIO, k as createUdsEventBridge, kt as HEAP_RECLAIM_TRIGGER_MB, l as setHubConnected, ln as SOCKET_PLANE_TOP_N, lt as validateProviderRegistrations, m as registerEventBusService, mn as EMPTY_SOCKET_DIRECTION, mt as capServiceName, n as installManifestPythonDeps, nn as emitHeapDiagnosticReport, nt as buildUdsNativeCapProxy, o as getWorkerDeviceRegistry, on as readHeapSpaces, ot as mountNativeCapService, p as getMoleculerEventStats, pn as formatSocketPlane, pt as capBareAction, q as getCapUsageRegistry, qt as parseRssBudgetMb, r as adaptBrokerToCluster, rn as formatHeapSpaces, rt as createBrokerDeviceManagerApi, s as getOrInitReadinessRegistry, sn as selectReportedSpaces, t as installManifestSystemDeps, tn as RUNNER_HEAP_SNAPSHOT_ENV, tt as buildNativeCapProxy, u as EVENT_TOPIC_PREFIX, un as createSocketPlaneMeter, ut as NATIVE_PROVIDER_SERVICE_INFIX, v as createKernelHwAccel, vn as socketDirectionBytes, vt as DeviceRegistry, w as localProviderLink, wn as formatEventPlane, wt as resolveNpmInvocation, x as brokerTransportLink, xn as createEventPlaneMeter, xt as copyBundledNativeModules, y as resolveHwAccel, yn as socketDirectionMessages, yt as CapabilityHandle, z as CapRouteResolver, zt as ZERO_LOOP_DELAY } from "./manifest-system-deps-
|
|
28
|
+
import { $ as FrameDecoder, $t as DECISIVE_HEAP_SPACES, A as createUdsEventBus, At as HEAP_WATCH_INTERVAL_MS, B as CapRouteError, Bt as buildHeapSample, C as ipcParentLink, Cn as diffEventPlane, Ct as resolveAddonClass, D as createHubCapForwardService, Dt as HEAP_RECLAIM_MIN_INTERVAL_MS, E as HUB_CAP_FWD_SERVICE, Et as createAddonDataPlaneFacility, F as LocalChildRegistry, Ft as RSS_BUDGET_REANNOUNCE_MIN_MS, G as PARENT_ROUTED_PROVIDER_ADDON_ID, Gt as hubMainRssBudget, H as callWithServiceDiscovery, Ht as createLoopDelayMeter, I as UDS_NO_ROUTE_PREFIX, It as RSS_BUDGET_RELEASE_RATIO, J as createLocalTransport, Jt as reclaimIntervalMs, K as __resetCapUsageRegistryForTests, Kt as nextRssBudgetState, L as AGENT_CAP_FWD_ACTION, Lt as RUNNER_HEAP_WATCH_INTERVAL_MS, M as createUdsLogger, Mt as HUB_MAIN_HEAP_WATCH_LABEL, N as createUdsLoggerWithControl, Nt as HUB_MAIN_RSS_BUDGET_MB, O as createParentUnownedCallHandler, Ot as HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS, P as LocalChildClient, Pt as HUB_RSS_BUDGET_ENV, Q as localEndpointPath, Qt as strandedMb, R as AGENT_CAP_FWD_SERVICE, Rt as RUNNER_RSS_BUDGET_ENV, S as buildLinkChain, Sn as createEventPlaneReader, St as installManifestNativeDeps, T as HUB_CAP_FWD_ACTION, Tt as runNpm, U as readMoleculerFanoutMode, Ut as createV8Reclaimer, V as classifyCapRoute, Vt as createDeferredHeapWatchSink, W as CapUsageRegistry, Wt as describeRss, X as UdsLocalTransportServer, Xt as startHeapWatch, Y as UdsLocalTransportClient, Yt as shouldReclaim, Z as SocketChannel, Zt as startRunnerHeapWatch, _ as AddonDepsManager, _n as sampleSocketDirection, _t as serializeTypedArrays, a as createUdsAddonContext, an as heapSpaceField, b as brokerCallForCap, bn as EVENT_PLANE_TOP_N, bt as CapabilityUnavailableError, c as getOrInitReadinessRegistryForClient, cn as EMPTY_SOCKET_PLANE_BASELINE, ct as createAddonService, d as clusterEventTopic, dn as createSocketPlaneReader, dt as capActionName, en as HEAP_SPACE_REPORT_MIN_MB, et as encodeFrame, f as getBrokerEventBus, fn as diffSocketPlane, ft as capActionSuffix, g as subscribePassthrough, gn as recordSocketFrame, gt as deserializeTypedArrays, h as setNodeEventInterest, hn as createSocketDirectionCounters, ht as parseCapAction, i as createAddonContext, in as heapSnapshotAuthorised, j as udsChildLogToWorkerEntry, jt as HEAP_WATCH_WARN_RATIO, k as createUdsEventBridge, kt as HEAP_RECLAIM_TRIGGER_MB, l as setHubConnected, ln as SOCKET_PLANE_TOP_N, lt as validateProviderRegistrations, m as registerEventBusService, mn as EMPTY_SOCKET_DIRECTION, mt as capServiceName, n as installManifestPythonDeps, nn as emitHeapDiagnosticReport, nt as buildUdsNativeCapProxy, o as getWorkerDeviceRegistry, on as readHeapSpaces, ot as mountNativeCapService, p as getMoleculerEventStats, pn as formatSocketPlane, pt as capBareAction, q as getCapUsageRegistry, qt as parseRssBudgetMb, r as adaptBrokerToCluster, rn as formatHeapSpaces, rt as createBrokerDeviceManagerApi, s as getOrInitReadinessRegistry, sn as selectReportedSpaces, t as installManifestSystemDeps, tn as RUNNER_HEAP_SNAPSHOT_ENV, tt as buildNativeCapProxy, u as EVENT_TOPIC_PREFIX, un as createSocketPlaneMeter, ut as NATIVE_PROVIDER_SERVICE_INFIX, v as createKernelHwAccel, vn as socketDirectionBytes, vt as DeviceRegistry, w as localProviderLink, wn as formatEventPlane, wt as resolveNpmInvocation, x as brokerTransportLink, xn as createEventPlaneMeter, xt as copyBundledNativeModules, y as resolveHwAccel, yn as socketDirectionMessages, yt as CapabilityHandle, z as CapRouteResolver, zt as ZERO_LOOP_DELAY } from "./manifest-system-deps-D2GebQTp.mjs";
|
|
29
29
|
import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-BWmQ5i-o.mjs";
|
|
30
30
|
import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
|
|
31
31
|
import { z } from "zod";
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { AddonDeclaration, IScopedLogger } from '@camstack/types';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { PackageInstallRequest, PackageInstallResult } from './system-package-broker.js';
|
|
3
|
+
import { SystemPackageManager } from './system-package-allowlist.js';
|
|
4
|
+
export type { SystemPackageManager } from './system-package-allowlist.js';
|
|
4
5
|
/** Test seams — production callers omit these. */
|
|
5
6
|
export interface InstallManifestSystemDepsOptions {
|
|
6
7
|
readonly hasBinary?: (binary: string) => Promise<boolean>;
|
|
7
8
|
readonly detectManager?: () => Promise<SystemPackageManager | null>;
|
|
8
9
|
readonly run?: (command: string, args: readonly string[]) => Promise<void>;
|
|
9
10
|
readonly platform?: NodeJS.Platform;
|
|
11
|
+
readonly helperAvailable?: () => Promise<boolean>;
|
|
12
|
+
readonly requestInstall?: (req: PackageInstallRequest) => Promise<PackageInstallResult>;
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
12
15
|
* Satisfy every `systemDependencies` entry the declaration carries.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packages the privileged helper will install (D326).
|
|
3
|
+
*
|
|
4
|
+
* The helper process reads `scripts/docker/pkg-allowlist.json` (baked into
|
|
5
|
+
* the image). This module is the runner-side copy of the same list, so an
|
|
6
|
+
* unknown package is refused before a socket write. Keep them identical —
|
|
7
|
+
* `scripts/check-pkg-allowlist.ts` fails CI when they drift.
|
|
8
|
+
*/
|
|
9
|
+
export type SystemPackageManager = 'apt' | 'apk' | 'dnf' | 'brew';
|
|
10
|
+
export type DistroPackageManager = Exclude<SystemPackageManager, 'brew'>;
|
|
11
|
+
export declare const DISTRO_PACKAGE_ALLOWLIST: Readonly<Record<DistroPackageManager, readonly string[]>>;
|
|
12
|
+
export declare function packageIsAllowlisted(manager: SystemPackageManager, packageName: string): boolean;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SystemPackageManager } from './system-package-allowlist.js';
|
|
2
|
+
export interface PackageInstallRequest {
|
|
3
|
+
readonly addonId: string;
|
|
4
|
+
readonly binary: string;
|
|
5
|
+
readonly manager: SystemPackageManager;
|
|
6
|
+
readonly packageName: string;
|
|
7
|
+
}
|
|
8
|
+
export interface PackageInstallResult {
|
|
9
|
+
readonly ok: boolean;
|
|
10
|
+
readonly error?: string;
|
|
11
|
+
}
|
|
12
|
+
export type PackageInstallDecision = {
|
|
13
|
+
readonly kind: 'helper';
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: 'local';
|
|
16
|
+
} | {
|
|
17
|
+
readonly kind: 'refuse';
|
|
18
|
+
readonly reason: 'not-allowlisted' | 'helper-unavailable';
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Who is allowed to run the package manager for this request.
|
|
22
|
+
*
|
|
23
|
+
* Apt/apk/dnf need root. In the CamStack container that is the
|
|
24
|
+
* `camstack-pkgd` helper, not the runner and not hub-main (both uid
|
|
25
|
+
* 1001). Brew is owned by the logged-in user, so it stays in-process.
|
|
26
|
+
*/
|
|
27
|
+
export declare function decidePackageInstall(input: {
|
|
28
|
+
readonly manager: SystemPackageManager;
|
|
29
|
+
readonly packageName: string;
|
|
30
|
+
readonly helperAvailable: boolean;
|
|
31
|
+
}): PackageInstallDecision;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PackageInstallRequest, PackageInstallResult } from './system-package-broker.js';
|
|
2
|
+
/** Default path the entrypoint binds before dropping to uid 1001. */
|
|
3
|
+
export declare const DEFAULT_PKGD_SOCKET = "/run/camstack/pkgd.sock";
|
|
4
|
+
export declare function pkgdSocketPath(): string;
|
|
5
|
+
export declare function privilegedHelperAvailable(socketPath?: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* One JSON object per line. The helper answers one request per connection.
|
|
8
|
+
*/
|
|
9
|
+
export declare function requestPrivilegedInstall(req: PackageInstallRequest, socketPath?: string, timeoutMs?: number): Promise<PackageInstallResult>;
|
|
@@ -8,6 +8,7 @@ import { isAbsolute, join } from "node:path";
|
|
|
8
8
|
import { execFile } from "node:child_process";
|
|
9
9
|
import { promisify } from "node:util";
|
|
10
10
|
import * as fs from "node:fs";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
11
12
|
import * as os from "node:os";
|
|
12
13
|
import { tmpdir } from "node:os";
|
|
13
14
|
import { createServer } from "node:http";
|
|
@@ -15,7 +16,7 @@ import * as v8 from "node:v8";
|
|
|
15
16
|
import { monitorEventLoopDelay } from "node:perf_hooks";
|
|
16
17
|
import * as vm from "node:vm";
|
|
17
18
|
import { BOOT_RECOVERY_BACKOFF_MS, DATAPLANE_SECRET_HEADER, DeviceType, DisposerChain, EventCategory, ReadinessRegistry, asJsonObject, asString, createDeviceProxy, createEventBusSliceSource, deviceOpsCapability, emitReadiness, errMsg, expandCapMethods, readNodePin, scopeKey, sleep, withCapInputDefaults } from "@camstack/types/addon";
|
|
18
|
-
import { connect, createServer as createServer$1 } from "node:net";
|
|
19
|
+
import { connect, createConnection, createServer as createServer$1 } from "node:net";
|
|
19
20
|
import { TRPCClientError, createTRPCClient } from "@trpc/client";
|
|
20
21
|
//#region src/kernel/event-plane-report.ts
|
|
21
22
|
/**
|
|
@@ -9694,6 +9695,106 @@ async function installManifestPythonDeps(declaration, addonDir, deps, logger) {
|
|
|
9694
9695
|
await deps.installPythonRequirements(reqAbs);
|
|
9695
9696
|
}
|
|
9696
9697
|
//#endregion
|
|
9698
|
+
//#region src/kernel/deps/system-package-allowlist.ts
|
|
9699
|
+
var DISTRO_PACKAGE_ALLOWLIST = {
|
|
9700
|
+
apt: ["smbclient"],
|
|
9701
|
+
apk: ["samba-client"],
|
|
9702
|
+
dnf: ["samba-client"]
|
|
9703
|
+
};
|
|
9704
|
+
function packageIsAllowlisted(manager, packageName) {
|
|
9705
|
+
if (manager === "brew") return true;
|
|
9706
|
+
if (packageName.length === 0) return false;
|
|
9707
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9+._-]*$/.test(packageName)) return false;
|
|
9708
|
+
return DISTRO_PACKAGE_ALLOWLIST[manager].includes(packageName);
|
|
9709
|
+
}
|
|
9710
|
+
//#endregion
|
|
9711
|
+
//#region src/kernel/deps/system-package-broker.ts
|
|
9712
|
+
/**
|
|
9713
|
+
* Who is allowed to run the package manager for this request.
|
|
9714
|
+
*
|
|
9715
|
+
* Apt/apk/dnf need root. In the CamStack container that is the
|
|
9716
|
+
* `camstack-pkgd` helper, not the runner and not hub-main (both uid
|
|
9717
|
+
* 1001). Brew is owned by the logged-in user, so it stays in-process.
|
|
9718
|
+
*/
|
|
9719
|
+
function decidePackageInstall(input) {
|
|
9720
|
+
if (input.manager === "brew") return { kind: "local" };
|
|
9721
|
+
if (!packageIsAllowlisted(input.manager, input.packageName)) return {
|
|
9722
|
+
kind: "refuse",
|
|
9723
|
+
reason: "not-allowlisted"
|
|
9724
|
+
};
|
|
9725
|
+
if (!input.helperAvailable) return {
|
|
9726
|
+
kind: "refuse",
|
|
9727
|
+
reason: "helper-unavailable"
|
|
9728
|
+
};
|
|
9729
|
+
return { kind: "helper" };
|
|
9730
|
+
}
|
|
9731
|
+
function pkgdSocketPath() {
|
|
9732
|
+
return process.env["CAMSTACK_PKGD_SOCKET"] ?? "/run/camstack/pkgd.sock";
|
|
9733
|
+
}
|
|
9734
|
+
function privilegedHelperAvailable(socketPath = pkgdSocketPath()) {
|
|
9735
|
+
return existsSync(socketPath);
|
|
9736
|
+
}
|
|
9737
|
+
/**
|
|
9738
|
+
* One JSON object per line. The helper answers one request per connection.
|
|
9739
|
+
*/
|
|
9740
|
+
function requestPrivilegedInstall(req, socketPath = pkgdSocketPath(), timeoutMs = 360 * 1e3) {
|
|
9741
|
+
return new Promise((resolve) => {
|
|
9742
|
+
const socket = createConnection({ path: socketPath });
|
|
9743
|
+
const chunks = [];
|
|
9744
|
+
const finish = (result) => {
|
|
9745
|
+
socket.destroy();
|
|
9746
|
+
resolve(result);
|
|
9747
|
+
};
|
|
9748
|
+
const timer = setTimeout(() => {
|
|
9749
|
+
finish({
|
|
9750
|
+
ok: false,
|
|
9751
|
+
error: `privileged helper timed out after ${timeoutMs}ms`
|
|
9752
|
+
});
|
|
9753
|
+
}, timeoutMs);
|
|
9754
|
+
socket.on("connect", () => {
|
|
9755
|
+
socket.write(`${JSON.stringify({
|
|
9756
|
+
v: 1,
|
|
9757
|
+
...req
|
|
9758
|
+
})}\n`);
|
|
9759
|
+
});
|
|
9760
|
+
socket.on("data", (data) => {
|
|
9761
|
+
chunks.push(data);
|
|
9762
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
9763
|
+
const nl = text.indexOf("\n");
|
|
9764
|
+
if (nl === -1) return;
|
|
9765
|
+
clearTimeout(timer);
|
|
9766
|
+
try {
|
|
9767
|
+
const parsed = JSON.parse(text.slice(0, nl));
|
|
9768
|
+
finish({
|
|
9769
|
+
ok: parsed.ok === true,
|
|
9770
|
+
...parsed.error !== void 0 ? { error: parsed.error } : {}
|
|
9771
|
+
});
|
|
9772
|
+
} catch (err) {
|
|
9773
|
+
finish({
|
|
9774
|
+
ok: false,
|
|
9775
|
+
error: err instanceof Error ? err.message : String(err)
|
|
9776
|
+
});
|
|
9777
|
+
}
|
|
9778
|
+
});
|
|
9779
|
+
socket.on("error", (err) => {
|
|
9780
|
+
clearTimeout(timer);
|
|
9781
|
+
finish({
|
|
9782
|
+
ok: false,
|
|
9783
|
+
error: err.message
|
|
9784
|
+
});
|
|
9785
|
+
});
|
|
9786
|
+
socket.on("end", () => {
|
|
9787
|
+
if (chunks.length === 0) {
|
|
9788
|
+
clearTimeout(timer);
|
|
9789
|
+
finish({
|
|
9790
|
+
ok: false,
|
|
9791
|
+
error: "privileged helper closed without a reply"
|
|
9792
|
+
});
|
|
9793
|
+
}
|
|
9794
|
+
});
|
|
9795
|
+
});
|
|
9796
|
+
}
|
|
9797
|
+
//#endregion
|
|
9697
9798
|
//#region src/kernel/deps/manifest-system-deps.ts
|
|
9698
9799
|
/**
|
|
9699
9800
|
* Auto-install the host binaries declared in an addon's manifest
|
|
@@ -9724,6 +9825,9 @@ async function installManifestPythonDeps(declaration, addonDir, deps, logger) {
|
|
|
9724
9825
|
* 4. **Platform reality is stated, not assumed.** An unsupported host logs
|
|
9725
9826
|
* which manager it looked for and continues. Silence would read as
|
|
9726
9827
|
* "installed".
|
|
9828
|
+
* 5. **Apt is not the runner's.** Distro package managers need root. The
|
|
9829
|
+
* runner and hub-main are uid 1001 (`gosu` in the entrypoint). Apt/apk/dnf
|
|
9830
|
+
* go through `camstack-pkgd` (allowlisted). Brew stays in-process.
|
|
9727
9831
|
*
|
|
9728
9832
|
* Every branch that declines to install SAYS SO. A dependency step that
|
|
9729
9833
|
* produced no line at all is indistinguishable from one that never ran, and
|
|
@@ -9746,12 +9850,16 @@ async function installManifestSystemDeps(declaration, logger, options = {}) {
|
|
|
9746
9850
|
const detectManager = options.detectManager ?? defaultDetectManager;
|
|
9747
9851
|
const run = options.run ?? defaultRun;
|
|
9748
9852
|
const platform = options.platform ?? process.platform;
|
|
9853
|
+
const helperAvailable = options.helperAvailable ?? (async () => privilegedHelperAvailable());
|
|
9854
|
+
const requestInstall = options.requestInstall ?? ((req) => requestPrivilegedInstall(req));
|
|
9749
9855
|
for (const dep of deps) try {
|
|
9750
9856
|
await satisfyOne(dep, declaration.id, {
|
|
9751
9857
|
hasBinary,
|
|
9752
9858
|
detectManager,
|
|
9753
9859
|
run,
|
|
9754
|
-
platform
|
|
9860
|
+
platform,
|
|
9861
|
+
helperAvailable,
|
|
9862
|
+
requestInstall
|
|
9755
9863
|
}, logger);
|
|
9756
9864
|
} catch (err) {
|
|
9757
9865
|
logger.warn("system dependency step failed", { meta: {
|
|
@@ -9789,15 +9897,43 @@ async function satisfyOne(dep, addonId, rt, logger) {
|
|
|
9789
9897
|
} });
|
|
9790
9898
|
return;
|
|
9791
9899
|
}
|
|
9792
|
-
const
|
|
9900
|
+
const decision = decidePackageInstall({
|
|
9901
|
+
manager,
|
|
9902
|
+
packageName,
|
|
9903
|
+
helperAvailable: await rt.helperAvailable()
|
|
9904
|
+
});
|
|
9905
|
+
if (decision.kind === "refuse") {
|
|
9906
|
+
const message = decision.reason === "helper-unavailable" ? "system dependency missing and the privileged helper is not running — apt cannot run as uid 1001" : "system dependency missing and the package is not on the helper allowlist";
|
|
9907
|
+
logger.warn(message, { meta: {
|
|
9908
|
+
addonId,
|
|
9909
|
+
binary: dep.binary,
|
|
9910
|
+
manager,
|
|
9911
|
+
package: packageName,
|
|
9912
|
+
reason: decision.reason,
|
|
9913
|
+
...dep.reason !== void 0 ? { reason: dep.reason } : {}
|
|
9914
|
+
} });
|
|
9915
|
+
return;
|
|
9916
|
+
}
|
|
9793
9917
|
logger.info("installing system dependency", { meta: {
|
|
9794
9918
|
addonId,
|
|
9795
9919
|
binary: dep.binary,
|
|
9796
9920
|
manager,
|
|
9797
|
-
package: packageName
|
|
9921
|
+
package: packageName,
|
|
9922
|
+
via: decision.kind
|
|
9798
9923
|
} });
|
|
9799
9924
|
try {
|
|
9800
|
-
|
|
9925
|
+
if (decision.kind === "helper") {
|
|
9926
|
+
const result = await rt.requestInstall({
|
|
9927
|
+
addonId,
|
|
9928
|
+
binary: dep.binary,
|
|
9929
|
+
manager,
|
|
9930
|
+
packageName
|
|
9931
|
+
});
|
|
9932
|
+
if (!result.ok) throw new Error(result.error ?? "privileged helper refused");
|
|
9933
|
+
} else {
|
|
9934
|
+
const plan = planFor(manager, packageName);
|
|
9935
|
+
for (const [command, args] of plan.steps) await rt.run(command, args);
|
|
9936
|
+
}
|
|
9801
9937
|
} catch (err) {
|
|
9802
9938
|
logger.warn("system dependency install failed — the addon loads, its capability must refuse", { meta: {
|
|
9803
9939
|
addonId,
|
|
@@ -9698,6 +9698,106 @@ async function installManifestPythonDeps(declaration, addonDir, deps, logger) {
|
|
|
9698
9698
|
await deps.installPythonRequirements(reqAbs);
|
|
9699
9699
|
}
|
|
9700
9700
|
//#endregion
|
|
9701
|
+
//#region src/kernel/deps/system-package-allowlist.ts
|
|
9702
|
+
var DISTRO_PACKAGE_ALLOWLIST = {
|
|
9703
|
+
apt: ["smbclient"],
|
|
9704
|
+
apk: ["samba-client"],
|
|
9705
|
+
dnf: ["samba-client"]
|
|
9706
|
+
};
|
|
9707
|
+
function packageIsAllowlisted(manager, packageName) {
|
|
9708
|
+
if (manager === "brew") return true;
|
|
9709
|
+
if (packageName.length === 0) return false;
|
|
9710
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9+._-]*$/.test(packageName)) return false;
|
|
9711
|
+
return DISTRO_PACKAGE_ALLOWLIST[manager].includes(packageName);
|
|
9712
|
+
}
|
|
9713
|
+
//#endregion
|
|
9714
|
+
//#region src/kernel/deps/system-package-broker.ts
|
|
9715
|
+
/**
|
|
9716
|
+
* Who is allowed to run the package manager for this request.
|
|
9717
|
+
*
|
|
9718
|
+
* Apt/apk/dnf need root. In the CamStack container that is the
|
|
9719
|
+
* `camstack-pkgd` helper, not the runner and not hub-main (both uid
|
|
9720
|
+
* 1001). Brew is owned by the logged-in user, so it stays in-process.
|
|
9721
|
+
*/
|
|
9722
|
+
function decidePackageInstall(input) {
|
|
9723
|
+
if (input.manager === "brew") return { kind: "local" };
|
|
9724
|
+
if (!packageIsAllowlisted(input.manager, input.packageName)) return {
|
|
9725
|
+
kind: "refuse",
|
|
9726
|
+
reason: "not-allowlisted"
|
|
9727
|
+
};
|
|
9728
|
+
if (!input.helperAvailable) return {
|
|
9729
|
+
kind: "refuse",
|
|
9730
|
+
reason: "helper-unavailable"
|
|
9731
|
+
};
|
|
9732
|
+
return { kind: "helper" };
|
|
9733
|
+
}
|
|
9734
|
+
function pkgdSocketPath() {
|
|
9735
|
+
return process.env["CAMSTACK_PKGD_SOCKET"] ?? "/run/camstack/pkgd.sock";
|
|
9736
|
+
}
|
|
9737
|
+
function privilegedHelperAvailable(socketPath = pkgdSocketPath()) {
|
|
9738
|
+
return (0, node_fs.existsSync)(socketPath);
|
|
9739
|
+
}
|
|
9740
|
+
/**
|
|
9741
|
+
* One JSON object per line. The helper answers one request per connection.
|
|
9742
|
+
*/
|
|
9743
|
+
function requestPrivilegedInstall(req, socketPath = pkgdSocketPath(), timeoutMs = 360 * 1e3) {
|
|
9744
|
+
return new Promise((resolve) => {
|
|
9745
|
+
const socket = (0, node_net.createConnection)({ path: socketPath });
|
|
9746
|
+
const chunks = [];
|
|
9747
|
+
const finish = (result) => {
|
|
9748
|
+
socket.destroy();
|
|
9749
|
+
resolve(result);
|
|
9750
|
+
};
|
|
9751
|
+
const timer = setTimeout(() => {
|
|
9752
|
+
finish({
|
|
9753
|
+
ok: false,
|
|
9754
|
+
error: `privileged helper timed out after ${timeoutMs}ms`
|
|
9755
|
+
});
|
|
9756
|
+
}, timeoutMs);
|
|
9757
|
+
socket.on("connect", () => {
|
|
9758
|
+
socket.write(`${JSON.stringify({
|
|
9759
|
+
v: 1,
|
|
9760
|
+
...req
|
|
9761
|
+
})}\n`);
|
|
9762
|
+
});
|
|
9763
|
+
socket.on("data", (data) => {
|
|
9764
|
+
chunks.push(data);
|
|
9765
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
9766
|
+
const nl = text.indexOf("\n");
|
|
9767
|
+
if (nl === -1) return;
|
|
9768
|
+
clearTimeout(timer);
|
|
9769
|
+
try {
|
|
9770
|
+
const parsed = JSON.parse(text.slice(0, nl));
|
|
9771
|
+
finish({
|
|
9772
|
+
ok: parsed.ok === true,
|
|
9773
|
+
...parsed.error !== void 0 ? { error: parsed.error } : {}
|
|
9774
|
+
});
|
|
9775
|
+
} catch (err) {
|
|
9776
|
+
finish({
|
|
9777
|
+
ok: false,
|
|
9778
|
+
error: err instanceof Error ? err.message : String(err)
|
|
9779
|
+
});
|
|
9780
|
+
}
|
|
9781
|
+
});
|
|
9782
|
+
socket.on("error", (err) => {
|
|
9783
|
+
clearTimeout(timer);
|
|
9784
|
+
finish({
|
|
9785
|
+
ok: false,
|
|
9786
|
+
error: err.message
|
|
9787
|
+
});
|
|
9788
|
+
});
|
|
9789
|
+
socket.on("end", () => {
|
|
9790
|
+
if (chunks.length === 0) {
|
|
9791
|
+
clearTimeout(timer);
|
|
9792
|
+
finish({
|
|
9793
|
+
ok: false,
|
|
9794
|
+
error: "privileged helper closed without a reply"
|
|
9795
|
+
});
|
|
9796
|
+
}
|
|
9797
|
+
});
|
|
9798
|
+
});
|
|
9799
|
+
}
|
|
9800
|
+
//#endregion
|
|
9701
9801
|
//#region src/kernel/deps/manifest-system-deps.ts
|
|
9702
9802
|
/**
|
|
9703
9803
|
* Auto-install the host binaries declared in an addon's manifest
|
|
@@ -9728,6 +9828,9 @@ async function installManifestPythonDeps(declaration, addonDir, deps, logger) {
|
|
|
9728
9828
|
* 4. **Platform reality is stated, not assumed.** An unsupported host logs
|
|
9729
9829
|
* which manager it looked for and continues. Silence would read as
|
|
9730
9830
|
* "installed".
|
|
9831
|
+
* 5. **Apt is not the runner's.** Distro package managers need root. The
|
|
9832
|
+
* runner and hub-main are uid 1001 (`gosu` in the entrypoint). Apt/apk/dnf
|
|
9833
|
+
* go through `camstack-pkgd` (allowlisted). Brew stays in-process.
|
|
9731
9834
|
*
|
|
9732
9835
|
* Every branch that declines to install SAYS SO. A dependency step that
|
|
9733
9836
|
* produced no line at all is indistinguishable from one that never ran, and
|
|
@@ -9750,12 +9853,16 @@ async function installManifestSystemDeps(declaration, logger, options = {}) {
|
|
|
9750
9853
|
const detectManager = options.detectManager ?? defaultDetectManager;
|
|
9751
9854
|
const run = options.run ?? defaultRun;
|
|
9752
9855
|
const platform = options.platform ?? process.platform;
|
|
9856
|
+
const helperAvailable = options.helperAvailable ?? (async () => privilegedHelperAvailable());
|
|
9857
|
+
const requestInstall = options.requestInstall ?? ((req) => requestPrivilegedInstall(req));
|
|
9753
9858
|
for (const dep of deps) try {
|
|
9754
9859
|
await satisfyOne(dep, declaration.id, {
|
|
9755
9860
|
hasBinary,
|
|
9756
9861
|
detectManager,
|
|
9757
9862
|
run,
|
|
9758
|
-
platform
|
|
9863
|
+
platform,
|
|
9864
|
+
helperAvailable,
|
|
9865
|
+
requestInstall
|
|
9759
9866
|
}, logger);
|
|
9760
9867
|
} catch (err) {
|
|
9761
9868
|
logger.warn("system dependency step failed", { meta: {
|
|
@@ -9793,15 +9900,43 @@ async function satisfyOne(dep, addonId, rt, logger) {
|
|
|
9793
9900
|
} });
|
|
9794
9901
|
return;
|
|
9795
9902
|
}
|
|
9796
|
-
const
|
|
9903
|
+
const decision = decidePackageInstall({
|
|
9904
|
+
manager,
|
|
9905
|
+
packageName,
|
|
9906
|
+
helperAvailable: await rt.helperAvailable()
|
|
9907
|
+
});
|
|
9908
|
+
if (decision.kind === "refuse") {
|
|
9909
|
+
const message = decision.reason === "helper-unavailable" ? "system dependency missing and the privileged helper is not running — apt cannot run as uid 1001" : "system dependency missing and the package is not on the helper allowlist";
|
|
9910
|
+
logger.warn(message, { meta: {
|
|
9911
|
+
addonId,
|
|
9912
|
+
binary: dep.binary,
|
|
9913
|
+
manager,
|
|
9914
|
+
package: packageName,
|
|
9915
|
+
reason: decision.reason,
|
|
9916
|
+
...dep.reason !== void 0 ? { reason: dep.reason } : {}
|
|
9917
|
+
} });
|
|
9918
|
+
return;
|
|
9919
|
+
}
|
|
9797
9920
|
logger.info("installing system dependency", { meta: {
|
|
9798
9921
|
addonId,
|
|
9799
9922
|
binary: dep.binary,
|
|
9800
9923
|
manager,
|
|
9801
|
-
package: packageName
|
|
9924
|
+
package: packageName,
|
|
9925
|
+
via: decision.kind
|
|
9802
9926
|
} });
|
|
9803
9927
|
try {
|
|
9804
|
-
|
|
9928
|
+
if (decision.kind === "helper") {
|
|
9929
|
+
const result = await rt.requestInstall({
|
|
9930
|
+
addonId,
|
|
9931
|
+
binary: dep.binary,
|
|
9932
|
+
manager,
|
|
9933
|
+
packageName
|
|
9934
|
+
});
|
|
9935
|
+
if (!result.ok) throw new Error(result.error ?? "privileged helper refused");
|
|
9936
|
+
} else {
|
|
9937
|
+
const plan = planFor(manager, packageName);
|
|
9938
|
+
for (const [command, args] of plan.steps) await rt.run(command, args);
|
|
9939
|
+
}
|
|
9805
9940
|
} catch (err) {
|
|
9806
9941
|
logger.warn("system dependency install failed — the addon loads, its capability must refuse", { meta: {
|
|
9807
9942
|
addonId,
|