@camstack/system 1.2.163 → 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/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +17 -5
- package/dist/builtins/device-manager/device-manager.addon.mjs +17 -5
- package/dist/builtins/device-manager/device-projection.d.ts +12 -2
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.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/builtins/storage-orchestrator/storage-migration-coordinator.d.ts +1 -18
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +43 -75
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +43 -75
- package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +6 -7
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-B29Skpzo.js → dist-BhE8zNfY.js} +72 -0
- package/dist/{dist-DxFjna2a.mjs → dist-BpsHt11f.mjs} +72 -0
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- 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-CG9ESHhv.mjs → manifest-system-deps-D2GebQTp.mjs} +142 -6
- package/dist/{manifest-system-deps-DBje540e.js → manifest-system-deps-uflHvHDB.js} +140 -5
- package/dist/{retired-settings-keys-CRL0qOnU.js → retired-settings-keys-CqDbI-vK.js} +1 -1
- package/dist/{retired-settings-keys-N0NZzDE3.mjs → retired-settings-keys-DLwieFXR.mjs} +1 -1
- package/package.json +1 -1
|
@@ -18151,6 +18151,47 @@ var RebuildStatusSchema = z.object({
|
|
|
18151
18151
|
/** Present when the pass ended by throwing. */
|
|
18152
18152
|
error: z.string().nullable()
|
|
18153
18153
|
});
|
|
18154
|
+
/**
|
|
18155
|
+
* Acknowledgement that a debug-media reclaim STARTED.
|
|
18156
|
+
*
|
|
18157
|
+
* The pass is paced at ~2 MB/s over a standing 100 GB — tens of minutes — so
|
|
18158
|
+
* it runs detached and this returns immediately. Awaiting it is how the
|
|
18159
|
+
* `addons.custom` door hit the 60 s UDS deadline while the walk carried on
|
|
18160
|
+
* with no status. Poll {@link pipelineAnalyticsCapability.methods.getMediaReclaimStatus}.
|
|
18161
|
+
*/
|
|
18162
|
+
var MediaReclaimStartResultSchema = z.object({
|
|
18163
|
+
started: z.boolean(),
|
|
18164
|
+
/** True when a pass was already running; the new request is ignored. */
|
|
18165
|
+
alreadyRunning: z.boolean()
|
|
18166
|
+
});
|
|
18167
|
+
var MediaReclaimInputSchema = z.object({
|
|
18168
|
+
mode: z.enum(["report", "reclaim"]).default("report"),
|
|
18169
|
+
scopes: z.array(z.enum(["motion-still", "track-filmstrip"])).min(1).optional(),
|
|
18170
|
+
deviceIds: z.array(z.number().int()).min(1).optional(),
|
|
18171
|
+
restart: z.boolean().optional(),
|
|
18172
|
+
pageSize: z.number().int().min(50).max(5e3).optional(),
|
|
18173
|
+
maxRowsPerDevice: z.number().int().min(1).max(5e5).optional(),
|
|
18174
|
+
maxReclaimPerDevice: z.number().int().min(1).max(5e5).optional(),
|
|
18175
|
+
maxBytesPerRun: z.number().int().min(1).optional(),
|
|
18176
|
+
budgetMinutes: z.number().int().min(1).max(720).optional(),
|
|
18177
|
+
throttleBytesPerSec: z.number().int().min(64 * 1024).optional(),
|
|
18178
|
+
graceMinutes: z.number().int().min(1).max(10080).optional()
|
|
18179
|
+
});
|
|
18180
|
+
var MediaReclaimStatusSchema = z.object({
|
|
18181
|
+
running: z.boolean(),
|
|
18182
|
+
mode: z.enum(["report", "reclaim"]).nullable(),
|
|
18183
|
+
totalExamined: z.number(),
|
|
18184
|
+
totalEligible: z.number(),
|
|
18185
|
+
totalReclaimed: z.number(),
|
|
18186
|
+
totalBytesReclaimed: z.number(),
|
|
18187
|
+
totalRefused: z.number(),
|
|
18188
|
+
/** Device+scope windows finished in this pass. */
|
|
18189
|
+
devicesDone: z.number(),
|
|
18190
|
+
complete: z.boolean().nullable(),
|
|
18191
|
+
startedAtMs: z.number().nullable(),
|
|
18192
|
+
finishedAtMs: z.number().nullable(),
|
|
18193
|
+
error: z.string().nullable()
|
|
18194
|
+
});
|
|
18154
18195
|
var ReplayFrameInputSchema = z.object({
|
|
18155
18196
|
timestamp: z.number(),
|
|
18156
18197
|
frame: PipelineRunResultBridge
|
|
@@ -18574,6 +18615,20 @@ var pipelineAnalyticsCapability = {
|
|
|
18574
18615
|
auth: "admin"
|
|
18575
18616
|
}),
|
|
18576
18617
|
/**
|
|
18618
|
+
* Reclaim the standing debug-media backlog (motion-visit stills + track
|
|
18619
|
+
* filmstrips). DETACHED: returns `{ started }` immediately. The pass is
|
|
18620
|
+
* tens of minutes; awaiting it is a timeout, not a verdict. Dry-run unless
|
|
18621
|
+
* `mode: 'reclaim'`. Poll `getMediaReclaimStatus`.
|
|
18622
|
+
*/
|
|
18623
|
+
reclaimDebugMedia: method(MediaReclaimInputSchema, MediaReclaimStartResultSchema, {
|
|
18624
|
+
kind: "mutation",
|
|
18625
|
+
auth: "admin"
|
|
18626
|
+
}),
|
|
18627
|
+
getMediaReclaimStatus: method(z.object({}), MediaReclaimStatusSchema, {
|
|
18628
|
+
kind: "query",
|
|
18629
|
+
auth: "admin"
|
|
18630
|
+
}),
|
|
18631
|
+
/**
|
|
18577
18632
|
* The CHEAP QUESTION, asked before any media moves: how big is the dataset
|
|
18578
18633
|
* the marked (`markForTrain`) tracks would produce?
|
|
18579
18634
|
*
|
|
@@ -37160,6 +37215,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
37160
37215
|
addonId: null,
|
|
37161
37216
|
access: "view"
|
|
37162
37217
|
},
|
|
37218
|
+
"pipelineAnalytics.getMediaReclaimStatus": {
|
|
37219
|
+
capName: "pipeline-analytics",
|
|
37220
|
+
capScope: "device",
|
|
37221
|
+
addonId: null,
|
|
37222
|
+
access: "view"
|
|
37223
|
+
},
|
|
37163
37224
|
"pipelineAnalytics.getMotionEvents": {
|
|
37164
37225
|
capName: "pipeline-analytics",
|
|
37165
37226
|
capScope: "device",
|
|
@@ -37334,6 +37395,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
37334
37395
|
addonId: null,
|
|
37335
37396
|
access: "create"
|
|
37336
37397
|
},
|
|
37398
|
+
"pipelineAnalytics.reclaimDebugMedia": {
|
|
37399
|
+
capName: "pipeline-analytics",
|
|
37400
|
+
capScope: "device",
|
|
37401
|
+
addonId: null,
|
|
37402
|
+
access: "create"
|
|
37403
|
+
},
|
|
37337
37404
|
"pipelineAnalytics.reconcileFromDisk": {
|
|
37338
37405
|
capName: "pipeline-analytics",
|
|
37339
37406
|
capScope: "device",
|
|
@@ -40950,6 +41017,11 @@ Object.freeze({
|
|
|
40950
41017
|
form: "single",
|
|
40951
41018
|
optional: true
|
|
40952
41019
|
}],
|
|
41020
|
+
"pipelineAnalytics.reclaimDebugMedia": [{
|
|
41021
|
+
name: "deviceIds",
|
|
41022
|
+
form: "array",
|
|
41023
|
+
optional: true
|
|
41024
|
+
}],
|
|
40953
41025
|
"pipelineAnalytics.reconcileFromDisk": [{
|
|
40954
41026
|
name: "deviceId",
|
|
40955
41027
|
form: "single",
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("./dist-
|
|
3
|
+
const require_dist = require("./dist-BhE8zNfY.js");
|
|
4
4
|
const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
|
|
5
5
|
require("./builtins/alerts/index.js");
|
|
6
6
|
const require_formatter = require("./formatter-DqAKDlvN.js");
|
|
@@ -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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import { $ as isObjectInput, $t as parseJsonUnknown$1, Bt as ReadinessTimeoutError, Ft as DEVICE_STATUS_METHOD, Gt as createEvent, Ht as asJsonObject$1, J as extractNestedAddonId, Jt as expandCapMethods, Kt as emitDownForOwnedCaps, Nt as DATAPLANE_SECRET_HEADER$1, Pt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Q as isCollectionArrayMethod, Qt as parseJsonObject, T as addonSettingsCapability, Ut as asNumber, Wt as asString$1, Z as isArrayOutputSchema, _t as resolveMethodAuth, bt as scopesAllowDeviceCap, ct as looseSchema, dt as objectInputDeclaresAddonId, en as readinessKey, f as LOG_LEVEL_RANK, h as RUNTIME_DEFAULTS, in as EventCategory$1, it as lifecycleJobSchema, jt as errMsg$1, mt as procedureAuthKey, nn as scopeKey, nt as isVoidInput, p as METHOD_ACCESS_MAP, rt as kebabToCamel, st as logLevelAtMost, t as ALL_CAPABILITY_DEFINITIONS, tn as resolveCapMount, yt as scopesAllowAddon, zt as ReadinessRegistry } from "./dist-
|
|
2
|
+
import { $ as isObjectInput, $t as parseJsonUnknown$1, Bt as ReadinessTimeoutError, Ft as DEVICE_STATUS_METHOD, Gt as createEvent, Ht as asJsonObject$1, J as extractNestedAddonId, Jt as expandCapMethods, Kt as emitDownForOwnedCaps, Nt as DATAPLANE_SECRET_HEADER$1, Pt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Q as isCollectionArrayMethod, Qt as parseJsonObject, T as addonSettingsCapability, Ut as asNumber, Wt as asString$1, Z as isArrayOutputSchema, _t as resolveMethodAuth, bt as scopesAllowDeviceCap, ct as looseSchema, dt as objectInputDeclaresAddonId, en as readinessKey, f as LOG_LEVEL_RANK, h as RUNTIME_DEFAULTS, in as EventCategory$1, it as lifecycleJobSchema, jt as errMsg$1, mt as procedureAuthKey, nn as scopeKey, nt as isVoidInput, p as METHOD_ACCESS_MAP, rt as kebabToCamel, st as logLevelAtMost, t as ALL_CAPABILITY_DEFINITIONS, tn as resolveCapMount, yt as scopesAllowAddon, zt as ReadinessRegistry } from "./dist-BpsHt11f.mjs";
|
|
3
3
|
import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
|
|
4
4
|
import "./builtins/alerts/index.mjs";
|
|
5
5
|
import { t as formatLogLine } from "./formatter-B7qW8bPJ.mjs";
|
|
@@ -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>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "./dist-
|
|
1
|
+
import "./dist-BpsHt11f.mjs";
|
|
2
2
|
import * as crypto$1 from "node:crypto";
|
|
3
3
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
4
4
|
import { ensureBinary, ensureFfmpeg, ensurePython, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
|
|
@@ -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,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
require("./dist-
|
|
2
|
+
require("./dist-BhE8zNfY.js");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
5
5
|
let _camstack_types_node = require("@camstack/types/node");
|
|
@@ -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,
|