@sema-agent/server 7.141.0 → 7.142.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +215 -0
- package/USAGE.md +67 -12
- package/dist/approval-ask-audit-store.d.ts +54 -38
- package/dist/approval-ask-audit-store.js +58 -39
- package/dist/approval-card.d.ts +8 -8
- package/dist/approval-crash-convergence.d.ts +17 -7
- package/dist/approval-crash-convergence.js +94 -22
- package/dist/approval-deny-reasons.d.ts +34 -30
- package/dist/approval-deny-reasons.js +21 -6
- package/dist/approval-policy-settlement.d.ts +1 -1
- package/dist/approval-reconciler.d.ts +33 -1
- package/dist/approval-reconciler.js +43 -40
- package/dist/auth-bridge.d.ts +9 -6
- package/dist/auth-bridge.js +9 -3
- package/dist/boot/adoption.js +2 -1
- package/dist/boot/budget-tracing.d.ts +16 -0
- package/dist/boot/budget-tracing.js +10 -6
- package/dist/boot/device-lane.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +24 -4
- package/dist/boot/execution-env.js +26 -23
- package/dist/boot/execution-lane.js +2 -1
- package/dist/boot/exit-boundary.js +5 -4
- package/dist/boot/memory-consolidation.js +2 -1
- package/dist/boot/parked-revive-gate.js +2 -1
- package/dist/boot/permission-rules-audit.d.ts +0 -28
- package/dist/boot/permission-rules-audit.js +2 -1
- package/dist/boot/read-deny-anchor-audit.js +2 -1
- package/dist/boot/reapers.js +4 -3
- package/dist/boot/resolve-spec.js +11 -2
- package/dist/boot/retention-lane.js +5 -3
- package/dist/boot/runner-deps.js +16 -13
- package/dist/boot/runtime-caps.js +3 -2
- package/dist/boot/session-faces.js +4 -3
- package/dist/boot/shutdown.js +3 -2
- package/dist/boot/stage-04-stores.js +3 -2
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.js +8 -6
- package/dist/boot/stage-06-runners.d.ts +1 -1
- package/dist/boot/stage-06-runners.js +2 -1
- package/dist/boot/stage-07-capability-layer.d.ts +1 -1
- package/dist/boot/stage-07-capability-layer.js +2 -1
- package/dist/boot/stage-08-reapers.d.ts +1 -1
- package/dist/boot/stage-08-reapers.js +3 -2
- package/dist/boot/stage-09-leader.d.ts +1 -1
- package/dist/boot/stage-10-http-server.d.ts +1 -1
- package/dist/boot/stage-10-http-server.js +5 -4
- package/dist/boot/stores.js +3 -2
- package/dist/boot/web-admin.js +17 -17
- package/dist/boot/webfetch-summarize-lane.js +2 -1
- package/dist/boot/workflow-orchestration.js +3 -2
- package/dist/capabilities/builtin-tools.d.ts +2 -1
- package/dist/capabilities/builtin-tools.js +2 -4
- package/dist/capabilities/composite-members.d.ts +2 -1
- package/dist/capabilities/composite-members.js +2 -1
- package/dist/capability-facts.d.ts +24 -0
- package/dist/capability-facts.js +23 -0
- package/dist/config-catalog.js +1 -0
- package/dist/config-types.d.ts +15 -4
- package/dist/config.d.ts +6 -0
- package/dist/config.js +17 -3
- package/dist/execution-lane-caps.d.ts +2 -1
- package/dist/fleet/fleet-bus.d.ts +6 -3
- package/dist/hooks/hook-runner.d.ts +6 -0
- package/dist/hooks/hook-runner.js +30 -1
- package/dist/http/dispatch.js +4 -2
- package/dist/http/execution-context.d.ts +2 -2
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/principal-gate.d.ts +3 -1
- package/dist/http/principal-gate.js +17 -8
- package/dist/http/resume-legs.js +5 -9
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/attachments.js +18 -0
- package/dist/http/routes/capabilities.js +5 -2
- package/dist/http/routes/memory-policy.js +26 -6
- package/dist/http/routes/runs.js +3 -3
- package/dist/http/routes/session-memory-sync.d.ts +63 -0
- package/dist/http/routes/session-memory-sync.js +157 -0
- package/dist/http/routes/sessions-list.d.ts +2 -1
- package/dist/http/routes/tasks.js +7 -5
- package/dist/http/run-read-face.d.ts +7 -0
- package/dist/http/run-read-face.js +9 -3
- package/dist/http/send.d.ts +5 -0
- package/dist/http/send.js +9 -2
- package/dist/http/server.d.ts +14 -8
- package/dist/http/server.js +2 -4
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +2 -2
- package/dist/http/sync-submit-body.d.ts +21 -4
- package/dist/http/sync-submit-body.js +13 -0
- package/dist/identity-source.d.ts +21 -2
- package/dist/identity-source.js +6 -0
- package/dist/memory-incident-sink.d.ts +19 -6
- package/dist/memory-incident-sink.js +8 -4
- package/dist/memory-sync-client.d.ts +21 -21
- package/dist/memory-sync-client.js +50 -42
- package/dist/memory-sync-identity.d.ts +24 -0
- package/dist/memory-sync-identity.js +57 -0
- package/dist/memory-sync.d.ts +7 -1
- package/dist/memory-sync.js +6 -3
- package/dist/observability/fail-open.d.ts +27 -10
- package/dist/observability/fail-open.js +20 -7
- package/dist/observability/run-terminal.d.ts +92 -34
- package/dist/observability/run-terminal.js +167 -162
- package/dist/plugins/approval-ask-store-file.d.ts +14 -4
- package/dist/plugins/approval-ask-store-file.js +48 -7
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
- package/dist/plugins/approval-ask-store-memory.js +9 -8
- package/dist/plugins/approval-ask-store-sql.d.ts +42 -10
- package/dist/plugins/approval-ask-store-sql.js +49 -19
- package/dist/plugins/file-run-store.d.ts +6 -1
- package/dist/plugins/file-run-store.js +11 -1
- package/dist/plugins/local-session-store.d.ts +36 -7
- package/dist/plugins/local-session-store.js +76 -32
- package/dist/plugins/local-task-attachment-store.d.ts +12 -2
- package/dist/plugins/local-task-attachment-store.js +67 -43
- package/dist/plugins/memory-key-guards.d.ts +3 -3
- package/dist/plugins/memory-run-store.d.ts +6 -1
- package/dist/plugins/memory-run-store.js +11 -1
- package/dist/plugins/one-time-migrations.d.ts +27 -1
- package/dist/plugins/one-time-migrations.js +57 -3
- package/dist/plugins/remote-env-e2b.d.ts +23 -4
- package/dist/plugins/remote-env-e2b.js +111 -28
- package/dist/plugins/remote-env-k8s.d.ts +31 -5
- package/dist/plugins/remote-env-k8s.js +86 -19
- package/dist/plugins/remote-env-local-docker.d.ts +15 -3
- package/dist/plugins/remote-env-local-docker.js +40 -12
- package/dist/plugins/run-store-sql.d.ts +9 -1
- package/dist/plugins/run-store-sql.js +9 -1
- package/dist/plugins/store-backend.d.ts +10 -7
- package/dist/plugins/store-backend.js +1 -0
- package/dist/plugins/store-contracts.d.ts +26 -1
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/task-attachment-store.d.ts +112 -14
- package/dist/plugins/task-attachment-store.js +221 -28
- package/dist/plugins/workspace-fill.d.ts +60 -0
- package/dist/plugins/workspace-fill.js +106 -0
- package/dist/project-bundle.d.ts +38 -0
- package/dist/project-bundle.js +609 -0
- package/dist/run-local.js +2 -8
- package/dist/runs.js +1 -2
- package/dist/sandbox-egress-policy.d.ts +4 -1
- package/dist/sandbox-egress-policy.js +3 -1
- package/dist/sandbox-git-plane.d.ts +31 -12
- package/dist/sandbox-git-plane.js +24 -4
- package/dist/security.d.ts +9 -0
- package/dist/security.js +8 -0
- package/dist/session-error-wire.d.ts +24 -0
- package/dist/session-error-wire.js +7 -0
- package/dist/task-settings.d.ts +10 -2
- package/dist/task-settings.js +15 -2
- package/dist/terminal.d.ts +39 -19
- package/dist/terminal.js +65 -22
- package/dist/tool-approval.d.ts +4 -3
- package/dist/tool-approval.js +12 -14
- package/dist/trace/core-keyset-guard.d.ts +123 -6
- package/dist/trace/engine-notice-wire.d.ts +8 -2
- package/dist/trace/engine-notice-wire.js +4 -2
- package/dist/trace/exit-seat.d.ts +2 -1
- package/dist/trace/ledger-sink.d.ts +8 -4
- package/dist/trace/ledger-sink.js +2 -2
- package/dist/trace/project.d.ts +18 -1
- package/dist/trace/project.js +16 -0
- package/dist/trace/self-minted-wire.d.ts +251 -2
- package/dist/trace/self-minted-wire.js +82 -0
- package/dist/trace/wire-projection-faces.d.ts +1 -1
- package/dist/trace/wire-projection-faces.js +1 -1
- package/dist/web-admin-client/apply-effective.js +21 -1
- package/dist/web-admin-client/effective-keys.js +2 -0
- package/dist/web-admin-client/types.d.ts +4 -0
- package/package.json +1 -1
- package/wire-changes/server@7.142.0.json +639 -0
|
@@ -6,19 +6,23 @@ import { centerLaneConfigured } from "../web-admin-client/center-request.js";
|
|
|
6
6
|
import { CostQuota } from "../observability/cost-quota.js";
|
|
7
7
|
import { buildQuotaBounds } from "./limit-sync.js";
|
|
8
8
|
import { assembleFileHistory } from "../file-history-capture.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const pricing = buildPricing(config.models);
|
|
13
|
-
const counterDegradeHook = (info) => {
|
|
9
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
10
|
+
export function createCounterDegradeHook({ logger, metrics }) {
|
|
11
|
+
return (info) => {
|
|
14
12
|
metrics.setGauge("counter_flush_fail_streak", info.streak, { table: info.table, kind: info.kind });
|
|
15
13
|
if (info.streak > 0)
|
|
16
14
|
metrics.inc("counter_flush_failed_total", { table: info.table, kind: info.kind });
|
|
17
15
|
if (info.streak === 3)
|
|
18
|
-
logger.warn("counter_flush_degraded", { table: info.table, kind: info.kind, streak: info.streak, ...(info.error ? { error: info.error } : {}) });
|
|
16
|
+
logger.warn("counter_flush_degraded", { table: info.table, kind: info.kind, streak: info.streak, ...(info.error ? { error: seatText("operator-log-text", info.error) } : {}) });
|
|
19
17
|
else if (info.streak === 0 && info.prevStreak >= 3)
|
|
20
18
|
logger.info("counter_flush_recovered", { table: info.table, kind: info.kind, prevStreak: info.prevStreak });
|
|
21
19
|
};
|
|
20
|
+
}
|
|
21
|
+
export function createBudgetAndTracing(ctx) {
|
|
22
|
+
const { config, logger, metrics, backend, breakerState } = ctx;
|
|
23
|
+
const { brain, degradeRoute: degradeRouteWatch } = createBrainAssembly(config, { breakerState });
|
|
24
|
+
const pricing = buildPricing(config.models);
|
|
25
|
+
const counterDegradeHook = createCounterDegradeHook({ logger, metrics });
|
|
22
26
|
const bounds = buildQuotaBounds(config);
|
|
23
27
|
const costQuota = backend?.costQuota
|
|
24
28
|
? backend.costQuota(bounds.limitMicroUsd, bounds.windowMs, counterDegradeHook).startRefresh()
|
|
@@ -77,7 +77,7 @@ export declare function createDeviceLane(ctx: DeviceLaneCtx): DeviceLane | undef
|
|
|
77
77
|
*/
|
|
78
78
|
export declare function assertDeviceLaneWired(isDeviceLane: boolean, lane: DeviceLane | undefined, hasFactory: boolean): void;
|
|
79
79
|
/**
|
|
80
|
-
* 设备入口 × 已绑设备的起服一行(拒的那一半在配置期:device 车道上 `DEVICE_RELAY_URL`
|
|
80
|
+
* 设备入口 × 已绑设备的起服一行(拒的那一半在配置期:device 车道上 `DEVICE_RELAY_URL` 必填 —— 缺席拒起是车道必需 env 门(`config.ts` `declaredExecutionLane` → `laneMissingEnv`),坏形 / 带凭据形拒启是 `parseDeviceRelayUrlEnv`;
|
|
81
81
|
* 起不起服不随表里有几条绑定变)。
|
|
82
82
|
*
|
|
83
83
|
* 字面 `none` = 运维声明「设备拨本引擎自己的地址 + `wsPath`」。此刻根会话行上若有设备绑定(writer(device, D) 的格),这些会话的设备从此只能拨那个入口 ——
|
|
@@ -8,10 +8,13 @@ import type { DeviceEnrollment } from "../device-enrollment.js";
|
|
|
8
8
|
import type { DeviceStore } from "../device-store.js";
|
|
9
9
|
import type { ExecutionPlacementSeat } from "../execution-placement.js";
|
|
10
10
|
import type { DeviceWsHub } from "../device-ws-hub.js";
|
|
11
|
+
import { type RemoteContainerEnvDeps } from "../plugins/remote-env-e2b.js";
|
|
12
|
+
import { type WorkspaceFillOf } from "../plugins/workspace-fill.js";
|
|
11
13
|
import { k8sExecutionEnvFactory, type K8sEnvConfig, type K8sEnvDeps, type SandboxSecretSeat } from "../plugins/remote-env-k8s.js";
|
|
12
|
-
import { type
|
|
14
|
+
import { type SandboxGitPlaneSeat, type SandboxGitRunRows } from "../sandbox-git-plane.js";
|
|
13
15
|
import { type SandboxPodReaper } from "../plugins/k8s-pod-reaper.js";
|
|
14
16
|
import { type SpaceCommitRows } from "../workspace-space-commit.js";
|
|
17
|
+
import { type LocalDockerEnvDeps } from "../plugins/remote-env-local-docker.js";
|
|
15
18
|
import * as facts from "../capability-facts.js";
|
|
16
19
|
import { type TaskAttachmentStore } from "../plugins/task-attachment-store.js";
|
|
17
20
|
import type { TaskInheritEnv } from "../request-value-closure.js";
|
|
@@ -77,10 +80,19 @@ export declare function createSessionScopedRegistries(maxEntries?: number): Sess
|
|
|
77
80
|
* · 运维行座(`logger`)随部署级配置走。
|
|
78
81
|
* `deps` = 适配器自己的测试缝(假集群 / 假对象存储),生产装配不传。返回的是工厂闭包 ⇒ `create*`。
|
|
79
82
|
*/
|
|
83
|
+
/**
|
|
84
|
+
* 一条 run 是不是它工作区的属主:它的放置根就是它自己的会话(core `ExecutionEnvFactoryContext.placementRootSessionId`)。委派子代 / 后台代理与父 run 并发
|
|
85
|
+
* (一只工作区两个写者)、本服务为自己起的 run(放置根 = `INTERNAL_RUN_PLACEMENT_ROOT`)都不是。两个读者同一判:k8s 工作区空间(子代依律关)与
|
|
86
|
+
* 恢复点的播种(只有属主播种)。
|
|
87
|
+
*/
|
|
88
|
+
export declare function ownsItsWorkspace(ctx: {
|
|
89
|
+
readonly sessionId: string;
|
|
90
|
+
readonly placementRootSessionId: string;
|
|
91
|
+
}): boolean;
|
|
80
92
|
export declare function createK8sRunEnvFactory(k8sCfg: K8sEnvConfig, seats: {
|
|
81
93
|
imageOf(sessionId: string): string | undefined;
|
|
82
94
|
/** The member git-credential broker seat for the pod's run (`runId` = the one reading of the run that owns the pod, the same value its
|
|
83
|
-
* `sema.io/run` label carries; `sandbox-git-plane.ts` `
|
|
95
|
+
* `sema.io/run` label carries; `sandbox-git-plane.ts` `createSandboxBrokerSeatOf` over the plane seat's reading at that pod and the run row's identity);
|
|
84
96
|
* absent seat / `undefined` answer ⇒ the pod carries no broker. */
|
|
85
97
|
brokerSeatOf?(runId: string | undefined): Promise<K8sEnvConfig["sandboxBroker"]>;
|
|
86
98
|
/** The session store's by-id head read (`SessionStore.headOf`, picked once by `headReadOf`); the occupant is its live-occupant projection
|
|
@@ -90,11 +102,13 @@ export declare function createK8sRunEnvFactory(k8sCfg: K8sEnvConfig, seats: {
|
|
|
90
102
|
/** The run store's commit-fence rows (`workspace_space_commit`); answers `undefined` only before stage 7 binds the run store
|
|
91
103
|
* or without a store backend — the latter `assertWorkspaceSpaceReadable` refuses together with `space`. */
|
|
92
104
|
spaceCommits(): SpaceCommitRows | undefined;
|
|
105
|
+
/** The restore point's fill seat of the run (`workspace-fill.ts`; `createExecutionEnv` mints the one reading). Absent / `undefined` ⇒ the pod as it comes. */
|
|
106
|
+
workspaceFillOf?: WorkspaceFillOf;
|
|
93
107
|
}, deps?: K8sEnvDeps): ReturnType<typeof k8sExecutionEnvFactory>;
|
|
94
108
|
/**
|
|
95
109
|
* k8s 车道沙箱秘密座的**起服前提**(装配后的真门,第 5 段 await)。法只有一条:**秘密座非空(`K8S_SANDBOX_ENV` 点到了本进程环境里有的键)⇒
|
|
96
110
|
* 问一次 SelfSubjectAccessReview(env 座那一行动词 {@link SANDBOX_SECRET_SEAT_VERBS}`.env`,沙箱命名空间)** —— 只问这一座自己发的调用,
|
|
97
|
-
* 不问租约座的 `patch`(
|
|
111
|
+
* 不问租约座的 `patch`(那一座由凭据平面座在它的前提都成立时另问一次,见 `sandbox-git-plane.ts` 的 `createSandboxGitPlaneSeat` 的 `settle`):
|
|
98
112
|
* · 答了「不许」(任一动词)⇒ 拒启,一行拒句点名缺的动词、命名空间、Role 规则原文与出路(`[sandbox-secret-rbac]`)—— 不等第一个 run 才失败;
|
|
99
113
|
* · 问不到(请求失败 / 审查本身被拒 / 答复没有 `status.allowed`)⇒ 照常起服:F 类兜底口 `server.sandbox-secret.seat-unverified` 计数 + 一行
|
|
100
114
|
* `sandbox_secret_seat_unverified`。放行的最坏后果:RBAC 真缺时第一个要建 Secret 的 run 连接即拒(`auth_failed`,pod 被删)—— 秘密值仍然
|
|
@@ -141,6 +155,12 @@ export interface ExecutionEnvCtx {
|
|
|
141
155
|
/** run 店的按 id 读(成员凭据代理座读 run 行上受理时记下的身份元组 `RunRecord.identity`)。取值闭包:run 店第 7 段才绑(`late-binds.ts`),
|
|
142
156
|
* 平面开着时每个 run 的 pod 建起前求值一次。不传 / 答 `undefined`(没有存储后端)⇒ 读不到身份 ⇒ 不挂代理。 */
|
|
143
157
|
runRows?: () => SandboxGitRunRows | undefined;
|
|
158
|
+
/** 隔离车道三只适配器自己的测试缝(假 e2b SDK / 假集群 / 假 docker CLI),原样交给各自的工厂 —— 与 `K8sEnvDeps` 同一条律:生产装配不传。 */
|
|
159
|
+
laneDeps?: {
|
|
160
|
+
readonly e2b?: RemoteContainerEnvDeps;
|
|
161
|
+
readonly k8s?: K8sEnvDeps;
|
|
162
|
+
readonly localDocker?: LocalDockerEnvDeps;
|
|
163
|
+
};
|
|
144
164
|
}
|
|
145
165
|
export declare function createExecutionEnv(ctx: ExecutionEnvCtx): {
|
|
146
166
|
perTaskImage: PerTaskImageRegistry;
|
|
@@ -158,6 +178,6 @@ export declare function createExecutionEnv(ctx: ExecutionEnvCtx): {
|
|
|
158
178
|
spaceReclaimer: SpaceReclaimer | undefined;
|
|
159
179
|
sandboxSecretSeatGate: (() => Promise<void>) | undefined;
|
|
160
180
|
sandboxPodReaper: SandboxPodReaper | undefined;
|
|
161
|
-
|
|
181
|
+
sandboxGitPlane: SandboxGitPlaneSeat;
|
|
162
182
|
};
|
|
163
183
|
//# sourceMappingURL=execution-env.d.ts.map
|
|
@@ -11,10 +11,11 @@ import { PerTaskImageRegistry } from "../per-task-image.js";
|
|
|
11
11
|
import { adbExecutionEnvFactory } from "../plugins/remote-env-adb.js";
|
|
12
12
|
import { deviceExecutionEnvFactory } from "../plugins/remote-env-device.js";
|
|
13
13
|
import { e2bExecutionEnvFactory } from "../plugins/remote-env-e2b.js";
|
|
14
|
+
import { createWorkspaceFill } from "../plugins/workspace-fill.js";
|
|
14
15
|
import { hostExecutionEnvFactory, RemoteHostExecutionEnv } from "../plugins/remote-env-host.js";
|
|
15
16
|
import { boundedStoreCall, checkSandboxEgressPolicy, createSandboxPodApi, createSpaceReclaimer, k8sExecutionEnvFactory, readSandboxSecretSeat, rpcTimeoutMsOf } from "../plugins/remote-env-k8s.js";
|
|
16
17
|
import { podSpecPatchBrokerRefusal, SANDBOX_SECRET_SEAT_VERBS } from "../plugins/k8s-exec-protocol.js";
|
|
17
|
-
import {
|
|
18
|
+
import { createSandboxBrokerSeatOf, createSandboxGitPlaneSeat, sandboxGitPlanePremisesOf } from "../sandbox-git-plane.js";
|
|
18
19
|
import { createSandboxPodReaper } from "../plugins/k8s-pod-reaper.js";
|
|
19
20
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
20
21
|
import { createRunWorkspaceSnapshotSeat } from "../fleet/workspace-snapshot-residual.js";
|
|
@@ -38,6 +39,7 @@ import { sandboxPathEnvSlots, withSandboxPathEnvSlot } from "./deferred-sandbox-
|
|
|
38
39
|
import { createLaneHomeAbsenceReporter } from "../lane-home-probe.js";
|
|
39
40
|
import { REMOTE_EXEC_PROVIDER_WORDS, buildLaneHomeBootNote, buildLaneHomeClaim, capabilitiesFor, executionLaneOf, laneBindsReads, laneIsolated, laneSandboxReadFloorState } from "../execution-lane-caps.js";
|
|
40
41
|
import { warnReadDenyFloorUnkept } from "./execution-lane.js";
|
|
42
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
41
43
|
function boundedSessionSetter(map, maxEntries) {
|
|
42
44
|
return (sid, value) => {
|
|
43
45
|
map.delete(sid);
|
|
@@ -105,15 +107,19 @@ export function createSessionScopedRegistries(maxEntries = MAX_CWD_SESSIONS) {
|
|
|
105
107
|
dropSession,
|
|
106
108
|
};
|
|
107
109
|
}
|
|
110
|
+
export function ownsItsWorkspace(ctx) {
|
|
111
|
+
return ctx.placementRootSessionId === ctx.sessionId;
|
|
112
|
+
}
|
|
108
113
|
export function createK8sRunEnvFactory(k8sCfg, seats, deps) {
|
|
109
114
|
const cacheMisses = createCacheMissMemory();
|
|
110
115
|
return async (ctx) => {
|
|
111
116
|
const onWorkspaceSnapshot = createRunWorkspaceSnapshotSeat(ctx.sessionId);
|
|
112
|
-
const child = ctx
|
|
117
|
+
const child = !ownsItsWorkspace(ctx);
|
|
113
118
|
const s3Snapshot = child && k8sCfg.s3Snapshot !== undefined ? spaceOff(k8sCfg.s3Snapshot) : k8sCfg.s3Snapshot;
|
|
114
119
|
const spaceOccupant = child ? undefined : await occupantOf(seats, ctx.sessionId, ctx.taskId, rpcTimeoutMsOf(k8sCfg));
|
|
115
120
|
const runId = !child && ctx.taskId !== undefined ? ctx.taskId : undefined;
|
|
116
121
|
const sandboxBroker = await seats.brokerSeatOf?.(runId);
|
|
122
|
+
const workspaceFill = seats.workspaceFillOf?.(ctx);
|
|
117
123
|
const { cache, ...deploymentCfg } = k8sCfg;
|
|
118
124
|
return k8sExecutionEnvFactory({
|
|
119
125
|
...deploymentCfg,
|
|
@@ -123,6 +129,7 @@ export function createK8sRunEnvFactory(k8sCfg, seats, deps) {
|
|
|
123
129
|
...(spaceOccupant !== undefined ? { spaceOccupant } : {}),
|
|
124
130
|
...(runId !== undefined ? { runId } : {}),
|
|
125
131
|
...(sandboxBroker !== undefined ? { sandboxBroker } : {}),
|
|
132
|
+
...(workspaceFill !== undefined ? { workspaceFill } : {}),
|
|
126
133
|
onWorkspaceSnapshot,
|
|
127
134
|
}, deps)(ctx);
|
|
128
135
|
};
|
|
@@ -171,7 +178,7 @@ export async function ensureSandboxSecretSeat(k8sCfg, logger, deps, read = () =>
|
|
|
171
178
|
recordFailOpen("server.sandbox-secret.seat-unverified", `namespace=${namespace} ${seat.detail}`);
|
|
172
179
|
logger.warn("sandbox_secret_seat_unverified", {
|
|
173
180
|
namespace,
|
|
174
|
-
detail: seat.detail,
|
|
181
|
+
detail: seatText("operator-log-text", seat.detail),
|
|
175
182
|
effect: `the boot could not confirm the sandbox Secret RBAC (secrets ${SANDBOX_SECRET_SEAT_VERBS.env.join(" / ")}) — the service starts; if the Role lacks them, the first run that forwards K8S_SANDBOX_ENV is refused at connect (auth_failed) and its pod deleted — the values never go into the pod spec`,
|
|
176
183
|
});
|
|
177
184
|
return;
|
|
@@ -239,9 +246,9 @@ export function createExecutionEnv(ctx) {
|
|
|
239
246
|
let spaceReclaimer;
|
|
240
247
|
let sandboxSecretSeatGate;
|
|
241
248
|
let sandboxPodReaper;
|
|
242
|
-
|
|
243
|
-
let readSandboxGitPlane = async () => (planeCell.current = judgeSandboxGitPlane(sandboxGitPlanePremisesOf(config, {})));
|
|
249
|
+
let sandboxGitPlane = createSandboxGitPlaneSeat((r) => sandboxGitPlanePremisesOf(config, r), {});
|
|
244
250
|
let worktreeReap;
|
|
251
|
+
const workspaceFillOf = taskAttachmentStore === undefined ? undefined : (fctx) => createWorkspaceFill({ store: taskAttachmentStore, sessionId: fctx.sessionId, seeds: ownsItsWorkspace(fctx), logger });
|
|
245
252
|
if (config.remoteExec?.provider === "e2b") {
|
|
246
253
|
executionEnvFactory = e2bExecutionEnvFactory({
|
|
247
254
|
apiKey: config.remoteExec.apiKey,
|
|
@@ -253,9 +260,10 @@ export function createExecutionEnv(ctx) {
|
|
|
253
260
|
...(config.remoteExec.mountPath ? { mountPath: config.remoteExec.mountPath } : {}),
|
|
254
261
|
...((env) => (env !== undefined ? { sandboxEnv: env } : {}))(sandboxLaneEnvMerged(buildSandboxLaneEnv(config, config.remoteExec.sandboxEnv))),
|
|
255
262
|
sandboxReadFloor: config.sandboxReadFloor,
|
|
263
|
+
...(workspaceFillOf !== undefined ? { workspaceFillOf } : {}),
|
|
256
264
|
logger,
|
|
257
265
|
metrics,
|
|
258
|
-
});
|
|
266
|
+
}, ctx.laneDeps?.e2b);
|
|
259
267
|
}
|
|
260
268
|
else if (config.remoteExec?.provider === "k8s") {
|
|
261
269
|
const k8sCfg = {
|
|
@@ -281,30 +289,24 @@ export function createExecutionEnv(ctx) {
|
|
|
281
289
|
...((lane) => ({ ...(lane.env !== undefined ? { podEnv: lane.env } : {}), ...(lane.secretEnv !== undefined ? { podSecretEnv: lane.secretEnv } : {}) }))(buildSandboxLaneEnv(config, config.remoteExec.sandboxEnv)),
|
|
282
290
|
sandboxReadFloor: config.sandboxReadFloor,
|
|
283
291
|
};
|
|
284
|
-
|
|
292
|
+
sandboxGitPlane = createSandboxGitPlaneSeat((r) => sandboxGitPlanePremisesOf(config, r), {
|
|
293
|
+
patchRefusal: podSpecPatchBrokerRefusal(k8sCfg.podSpecPatch),
|
|
294
|
+
askSecretSeat: () => readSandboxSecretSeat(k8sCfg, "lease"),
|
|
295
|
+
});
|
|
285
296
|
executionEnvFactory = createK8sRunEnvFactory(k8sCfg, {
|
|
286
297
|
imageOf: (sid) => perTaskImage.get(sid),
|
|
287
298
|
headOf: ctx.headOf,
|
|
288
299
|
spaceCommits: ctx.spaceCommits ?? (() => undefined),
|
|
289
|
-
brokerSeatOf:
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
return undefined;
|
|
293
|
-
return sandboxBrokerSeatOf(plane, brokerImage, await runIdentitySourceOf(runId, ctx.runRows?.(), logger));
|
|
294
|
-
},
|
|
295
|
-
});
|
|
300
|
+
brokerSeatOf: createSandboxBrokerSeatOf(sandboxGitPlane.now, config.remoteExec.brokerImage, ctx.runRows, logger),
|
|
301
|
+
...(workspaceFillOf !== undefined ? { workspaceFillOf } : {}),
|
|
302
|
+
}, ctx.laneDeps?.k8s);
|
|
296
303
|
if (k8sCfg.cache !== undefined || k8sCfg.s3Snapshot !== undefined)
|
|
297
304
|
spaceReclaimer = createSpaceReclaimer(k8sCfg);
|
|
298
305
|
sandboxSecretSeatGate = () => ensureSandboxSecretSeat(k8sCfg, logger, undefined, () => readSandboxSecretSeat(k8sCfg, "env"));
|
|
299
|
-
readSandboxGitPlane = async () => {
|
|
300
|
-
const premises = sandboxGitPlanePremisesOf(config, { ...((r) => (r !== undefined ? { patchRefusal: r } : {}))(podSpecPatchBrokerRefusal(k8sCfg.podSpecPatch)) });
|
|
301
|
-
const secretSeat = sandboxGitPlaneAsksSecretSeat(premises) ? await readSandboxSecretSeat(k8sCfg, "lease") : undefined;
|
|
302
|
-
return (planeCell.current = judgeSandboxGitPlane({ ...premises, secretSeat }));
|
|
303
|
-
};
|
|
304
306
|
sandboxPodReaper = createSandboxPodReaper({ api: createSandboxPodApi(k8sCfg), logger, metrics });
|
|
305
307
|
void checkSandboxEgressPolicy(k8sCfg)
|
|
306
308
|
.then((gaps) => sayEgressPolicyReading(gaps, logger, k8sCfg.namespace))
|
|
307
|
-
.catch((e) => logger.error("sandbox_egress_policy_check_crashed", { error: e instanceof Error ? e.message : String(e), effect: "the sandbox egress self-check did not complete this boot — the lane runs; the egress policy was not read" }));
|
|
309
|
+
.catch((e) => logger.error("sandbox_egress_policy_check_crashed", { error: seatText("operator-log-text", e instanceof Error ? e.message : String(e)), effect: "the sandbox egress self-check did not complete this boot — the lane runs; the egress policy was not read" }));
|
|
308
310
|
}
|
|
309
311
|
else if (config.remoteExec?.provider === "ssh") {
|
|
310
312
|
executionEnvFactory = sshExecutionEnvFactory({
|
|
@@ -397,7 +399,8 @@ export function createExecutionEnv(ctx) {
|
|
|
397
399
|
...(config.remoteExec.commandTimeoutMs != null ? { commandTimeoutMs: config.remoteExec.commandTimeoutMs } : {}),
|
|
398
400
|
...(config.remoteExec.env ? { env: config.remoteExec.env } : {}),
|
|
399
401
|
sandboxReadFloor: config.sandboxReadFloor,
|
|
400
|
-
|
|
402
|
+
...(workspaceFillOf !== undefined ? { workspaceFillOf } : {}),
|
|
403
|
+
}, ctx.laneDeps?.localDocker);
|
|
401
404
|
}
|
|
402
405
|
if (executionEnvFactory && DEPLOYMENT_SHAPE_PREDICATES.remoteScratchpad.holds(config)) {
|
|
403
406
|
executionEnvFactory = withRemoteScratchpad(executionEnvFactory, logger);
|
|
@@ -451,7 +454,7 @@ export function createExecutionEnv(ctx) {
|
|
|
451
454
|
executionEnvFactory = registry.wrapFactory(executionEnvFactory);
|
|
452
455
|
return registry;
|
|
453
456
|
})();
|
|
454
|
-
if (taskAttachmentStore && executionEnvFactory) {
|
|
457
|
+
if (taskAttachmentStore && executionEnvFactory && !laneIsolated(executionLaneOf(config.remoteExec.provider))) {
|
|
455
458
|
const inner = executionEnvFactory;
|
|
456
459
|
const attStore = taskAttachmentStore;
|
|
457
460
|
executionEnvFactory = async (ctx) => {
|
|
@@ -507,7 +510,7 @@ export function createExecutionEnv(ctx) {
|
|
|
507
510
|
perTaskImage, sessionEnvSelection, perSessionCwd, setSessionCwd, setSessionShellEnv, setSessionInheritEnv,
|
|
508
511
|
fenceSessionOwner: sessionScoped.fenceSessionOwner,
|
|
509
512
|
dropSessionScoped: sessionScoped.dropSession,
|
|
510
|
-
executionEnvFactory, worktreeReap, sendUserFileTaskEnvs, lspManager, spaceReclaimer, sandboxSecretSeatGate, sandboxPodReaper,
|
|
513
|
+
executionEnvFactory, worktreeReap, sendUserFileTaskEnvs, lspManager, spaceReclaimer, sandboxSecretSeatGate, sandboxPodReaper, sandboxGitPlane,
|
|
511
514
|
};
|
|
512
515
|
}
|
|
513
516
|
//# sourceMappingURL=execution-env.js.map
|
|
@@ -4,6 +4,7 @@ import { crossInvariant } from "../config-invariants.js";
|
|
|
4
4
|
import { buildReadDenyFloorUnkeptNote, executionLaneOf, laneIsolated } from "../execution-lane-caps.js";
|
|
5
5
|
import { buildReadFacePostureNotice, settleDerivedReadFace } from "../read-face-posture.js";
|
|
6
6
|
import { settleHostShellAtBoot } from "../plugins/host-platform.js";
|
|
7
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
7
8
|
export const FILE_SOURCED_LANES = ["host", "local-docker"];
|
|
8
9
|
export async function composeExecutionLane(config, ctx) {
|
|
9
10
|
if (ctx.configSource === "local")
|
|
@@ -55,7 +56,7 @@ async function applyRemoteExecFile(config, ctx) {
|
|
|
55
56
|
fileRx = await loadRemoteExec(localRoot);
|
|
56
57
|
}
|
|
57
58
|
catch (err) {
|
|
58
|
-
logger.error("remote_exec_file_invalid", { root: localRoot, err: String(err) });
|
|
59
|
+
logger.error("remote_exec_file_invalid", { root: localRoot, err: seatText("operator-log-text", String(err)) });
|
|
59
60
|
throw new Error(`config.d/remote-exec.json under ${localRoot} is invalid: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
60
61
|
}
|
|
61
62
|
if (!fileRx)
|
|
@@ -2,6 +2,7 @@ import { defaultTaskRegistry } from "@sema-agent/core";
|
|
|
2
2
|
import { reportHardKillReceipts } from "../background-session-reap.js";
|
|
3
3
|
import { liveHostForegroundChildCount, reapHostForegroundChildren } from "../plugins/host-platform.js";
|
|
4
4
|
import { liveEphemeralHostWorkspaceCount, reapEphemeralHostWorkspaces } from "../plugins/host-workspace-registry.js";
|
|
5
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
5
6
|
const PROCESS_EXIT_INCLUDES_RETAINED = false;
|
|
6
7
|
export function installProcessExitBoundary({ logger }) {
|
|
7
8
|
const reapOwnChildProcesses = () => {
|
|
@@ -13,7 +14,7 @@ export function installProcessExitBoundary({ logger }) {
|
|
|
13
14
|
logger.info("shutdown_background_reaped", { reaped });
|
|
14
15
|
}
|
|
15
16
|
catch (err) {
|
|
16
|
-
logger.warn("shutdown_background_reap_failed", { err: String(err) });
|
|
17
|
+
logger.warn("shutdown_background_reap_failed", { err: seatText("operator-log-text", String(err)) });
|
|
17
18
|
}
|
|
18
19
|
try {
|
|
19
20
|
const fg = reapHostForegroundChildren();
|
|
@@ -23,7 +24,7 @@ export function installProcessExitBoundary({ logger }) {
|
|
|
23
24
|
logger.warn("shutdown_foreground_reap_incomplete", { groups: fg.failed });
|
|
24
25
|
}
|
|
25
26
|
catch (err) {
|
|
26
|
-
logger.warn("shutdown_foreground_reap_failed", { err: String(err) });
|
|
27
|
+
logger.warn("shutdown_foreground_reap_failed", { err: seatText("operator-log-text", String(err)) });
|
|
27
28
|
}
|
|
28
29
|
return backgroundSoftStopped;
|
|
29
30
|
};
|
|
@@ -33,7 +34,7 @@ export function installProcessExitBoundary({ logger }) {
|
|
|
33
34
|
reportHardKillReceipts(logger, receipts, "process_exit");
|
|
34
35
|
}
|
|
35
36
|
catch (err) {
|
|
36
|
-
logger.warn("shutdown_background_hard_kill_failed", { err: String(err) });
|
|
37
|
+
logger.warn("shutdown_background_hard_kill_failed", { err: seatText("operator-log-text", String(err)) });
|
|
37
38
|
}
|
|
38
39
|
};
|
|
39
40
|
const reapOwnHostWorkspaces = () => {
|
|
@@ -45,7 +46,7 @@ export function installProcessExitBoundary({ logger }) {
|
|
|
45
46
|
logger.warn("shutdown_host_workspace_reap_incomplete", { dirs: failed.map((f) => f.dir) });
|
|
46
47
|
}
|
|
47
48
|
catch (err) {
|
|
48
|
-
logger.warn("shutdown_host_workspace_reap_failed", { err: String(err) });
|
|
49
|
+
logger.warn("shutdown_host_workspace_reap_failed", { err: seatText("operator-log-text", String(err)) });
|
|
49
50
|
}
|
|
50
51
|
};
|
|
51
52
|
const onProcessExit = () => {
|
|
@@ -7,6 +7,7 @@ import { DEFAULT_MODEL_REF, resolveMainModel } from "../model-select.js";
|
|
|
7
7
|
import { backendOwnsControlPlane, captureRecordStoreOf } from "../memory-operator-faces.js";
|
|
8
8
|
import { memoryStoreForRequest } from "../memory-scope-stores.js";
|
|
9
9
|
import { createConsolidationWriteJudge, deliverWriteRefusal, expandTiers, MemoryEngine, modelOriginOf, readConsolidationDriverRun, resolveMemoryConsolidationDriver, runMemoryConsolidationDriver, } from "@sema-agent/core";
|
|
10
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
10
11
|
export function resolveConsolidationDriverSeat(deps) {
|
|
11
12
|
let options;
|
|
12
13
|
try {
|
|
@@ -238,7 +239,7 @@ function decideConsolidationValve(input) {
|
|
|
238
239
|
return { valve: { enabled: true, source: "derived", catalogDependent: true } };
|
|
239
240
|
const seatFact = billing.kind === "main-model"
|
|
240
241
|
? `Here the seat resolves to the main model "${billing.mainModel}" (no MODEL_CHEAP_ID naming another model, and no catalog roles.consolidate / roles.summarize / "flash" tier binding to another model)`
|
|
241
|
-
: `Here no consolidation seat resolves at all (${billing.fault})`;
|
|
242
|
+
: `Here no consolidation seat resolves at all (${seatText("operator-log-text", billing.fault)})`;
|
|
242
243
|
return {
|
|
243
244
|
valve: {
|
|
244
245
|
enabled: false,
|
|
@@ -8,6 +8,7 @@ import { DeferredSandboxPathEnv, sandboxPathEnvSlots } from "./deferred-sandbox-
|
|
|
8
8
|
import { DEPLOYMENT_SHAPE_PREDICATES } from "../deployment-shape.js";
|
|
9
9
|
import { executionLaneHomeDir } from "../execution-lane-caps.js";
|
|
10
10
|
import { createDeploymentListExemption } from "../approval.js";
|
|
11
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
11
12
|
function hostGateCwd(config, localRoot) {
|
|
12
13
|
return join(config.localDataRoot ?? localRoot, "parked-revive-unrooted");
|
|
13
14
|
}
|
|
@@ -63,7 +64,7 @@ async function resolveCapsFor(deps, identity) {
|
|
|
63
64
|
return await deps.resolveRuntimeCaps(identity.principal);
|
|
64
65
|
}
|
|
65
66
|
catch (err) {
|
|
66
|
-
deps.logger.warn("parked_revive_caps_unresolved", { principal: identity.principal ?? null, err: err instanceof Error ? err.message : String(err) });
|
|
67
|
+
deps.logger.warn("parked_revive_caps_unresolved", { principal: identity.principal ?? null, err: seatText("operator-log-text", err instanceof Error ? err.message : String(err)) });
|
|
67
68
|
return undefined;
|
|
68
69
|
}
|
|
69
70
|
}
|
|
@@ -1,31 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* [ref] §3([ref] v2 §6 F4 的**残余采纳**)—— 默认 ON 的**休眠行审计**。
|
|
3
|
-
*
|
|
4
|
-
* 🔴 这条审计存在的唯一理由:`PERMISSION_RULES_ENABLED` 的默认值在本车从 OFF 翻成 ON,而**旋钮翻转
|
|
5
|
-
* 与规则行的寿命是两条独立的时间线**。三张表自 [ref] 车二起就随中央 `ensureSchema` 建、并且从来没有被
|
|
6
|
-
* 清过,所以下面这两类部署在升级的那一刻会突然带着**既有**规则行开始放行:
|
|
7
|
-
* · 曾经把旋钮开过一段时间又关掉的部署(行留在库里,只是没人读);
|
|
8
|
-
* · 从旧库恢复/克隆出来的部署(行跟着数据一起来的)。
|
|
9
|
-
* 对运维来说,这是「我什么都没改,worker 却开始少问我了」——一次**放宽面**上的静默变化。审计做的事
|
|
10
|
-
* 很小但是承重:在启动日志里把它说出来,让「少问」是一条能被读到的因果,而不是一次玄学。
|
|
11
|
-
*
|
|
12
|
-
* ── 三条判据,逐条有理由 ────────────────────────────────────────────────────────────────────────
|
|
13
|
-
* ① **店缺席 ⇒ 整条不上场**(零 I/O、零行)。店缺席包括:显式关旋钮、`local` 车道没接 File 店的旧
|
|
14
|
-
* 部署、以及压根没有 backend 的 env-only worker。没有店就没有行,谈不上唤醒。
|
|
15
|
-
* ② **零桶 ⇒ 不打行**。一条「0 条既有规则随默认 ON 激活」的行是纯噪音:它对读日志的人不传递任何
|
|
16
|
-
* 可行动的信息,却让真正有东西被唤醒的那一行变得不显眼。
|
|
17
|
-
* ③ **运维**显式**表过态(`PERMISSION_RULES_ENABLED` 被设成 true 或 false)⇒ 不打行**。那些行本来
|
|
18
|
-
* 就是活的(或者旋钮被显式关着、店根本没装配),默认值翻不翻转对它们零影响 —— 说「随默认 ON
|
|
19
|
-
* 激活」是**假话**,而在启动日志里说假话比不说更坏。判据用 `permissionRulesEnabledExplicit`
|
|
20
|
-
* (config.ts 与 `dbBackendExplicit` 同姿势),不是猜。
|
|
21
|
-
*
|
|
22
|
-
* ── 失败方向 ────────────────────────────────────────────────────────────────────────────────────
|
|
23
|
-
* 数不出来(库抖动 / 文件读不了)⇒ **不拒启、也不编一个 0 出来**:返回 `undefined` + 一条 warn。
|
|
24
|
-
* 这是一条纯诊断面(它不参与任何放行/拒绝判决),所以它的降级方向是「安静地不知道」而不是「谎报
|
|
25
|
-
* 零」——`{ buckets: 0 }` 会被下游读成「确认没有休眠行」,那是把一次读失败伪装成一个结论。
|
|
26
|
-
* 因为它零判决,这条 fail-open 不属于 `docs/FAIL-OPEN-CENSUS.md` 的安全轴 P 类,故不占 `recordFailOpen`
|
|
27
|
-
* 的标签;它的可见性由那条 warn 承担。
|
|
28
|
-
*/
|
|
29
1
|
/** 审计只需要一只桶计数口——**刻意**不吃整个 `PermissionRuleStoreBundle`:诊断面对店的其余能力
|
|
30
2
|
* 一无所知也不该知道,窄口让测试能用四行 fixture 驱动真实现同一段代码。 */
|
|
31
3
|
export interface DormantRuleCounter {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
1
2
|
export async function auditDormantPermissionRules(ctx) {
|
|
2
3
|
if (ctx.stores === undefined)
|
|
3
4
|
return undefined;
|
|
@@ -7,7 +8,7 @@ export async function auditDormantPermissionRules(ctx) {
|
|
|
7
8
|
}
|
|
8
9
|
catch (err) {
|
|
9
10
|
ctx.logger.warn?.("permission_rules_dormant_audit_failed", {
|
|
10
|
-
error: err instanceof Error ? err.message : String(err),
|
|
11
|
+
error: seatText("operator-log-text", err instanceof Error ? err.message : String(err)),
|
|
11
12
|
note: "the boot audit could not count pre-existing permission-rule buckets; the lane itself is unaffected",
|
|
12
13
|
});
|
|
13
14
|
return undefined;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { compileReadDeny, readDenyRowAnchor } from "@sema-agent/core";
|
|
2
2
|
import { echoCallerText } from "../caller-text-echo.js";
|
|
3
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
3
4
|
export const READ_DENY_AUDIT_MAX_NAMED_ROWS = 20;
|
|
4
5
|
const NAMED_ROW_ECHO_CHARS = 200;
|
|
5
6
|
function isAnchoredCanonicalRow(canonical) {
|
|
@@ -14,7 +15,7 @@ export function auditReadDenyAnchoring(ctx) {
|
|
|
14
15
|
}
|
|
15
16
|
catch (err) {
|
|
16
17
|
ctx.logger.warn("read_deny_anchor_audit_failed", {
|
|
17
|
-
error:
|
|
18
|
+
error: seatText("operator-log-text", err instanceof Error ? err.message : String(err)),
|
|
18
19
|
note: "the boot audit could not read the deployment read-deny rows, so it names none and changes nothing; the engine itself refuses a row it cannot read when the Runner is built",
|
|
19
20
|
});
|
|
20
21
|
return [];
|
package/dist/boot/reapers.js
CHANGED
|
@@ -6,6 +6,7 @@ import { createApprovalReconciler } from "../approval-reconciler.js";
|
|
|
6
6
|
import { createE2bOrphanSandboxProvider, reclaimOrphanE2bSandboxes, E2B_ORPHAN_GRACE_MS } from "../plugins/e2b-orphan-reclaim.js";
|
|
7
7
|
import { SANDBOX_POD_REAP_PERIOD_MS } from "../plugins/k8s-pod-reaper.js";
|
|
8
8
|
import { APPROVAL_ASK_RETENTION_PASS_MS, runApprovalAskRetentionPass } from "../approval-ask-retention.js";
|
|
9
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
9
10
|
export const REAPER_FAILURE_WARN_THRESHOLD = 5;
|
|
10
11
|
export function createThrottledReaperCatch(name, logger, threshold = REAPER_FAILURE_WARN_THRESHOLD) {
|
|
11
12
|
let streak = 0;
|
|
@@ -21,7 +22,7 @@ export function createThrottledReaperCatch(name, logger, threshold = REAPER_FAIL
|
|
|
21
22
|
logger.warn("reaper_leg_repeated_failure", {
|
|
22
23
|
reaper: name,
|
|
23
24
|
consecutiveFailures: streak,
|
|
24
|
-
lastError: err instanceof Error ? err.message : String(err),
|
|
25
|
+
lastError: seatText("operator-log-text", err instanceof Error ? err.message : String(err)),
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
28
|
catch {
|
|
@@ -169,7 +170,7 @@ export function startReapers(ctx) {
|
|
|
169
170
|
catch (err) {
|
|
170
171
|
failedScopes++;
|
|
171
172
|
try {
|
|
172
|
-
logger.warn("bg_agent_reap_scope_failed", { scope, err: err instanceof Error ? err.message : String(err) });
|
|
173
|
+
logger.warn("bg_agent_reap_scope_failed", { scope, err: seatText("operator-log-text", err instanceof Error ? err.message : String(err)) });
|
|
173
174
|
}
|
|
174
175
|
catch {
|
|
175
176
|
}
|
|
@@ -266,7 +267,7 @@ export function startReapers(ctx) {
|
|
|
266
267
|
} })
|
|
267
268
|
.catch((err) => {
|
|
268
269
|
try {
|
|
269
|
-
logger.warn("attachment_orphan_sweep_failed", { err: err instanceof Error ? err.message : String(err) });
|
|
270
|
+
logger.warn("attachment_orphan_sweep_failed", { err: seatText("operator-log-text", err instanceof Error ? err.message : String(err)) });
|
|
270
271
|
}
|
|
271
272
|
catch {
|
|
272
273
|
}
|
|
@@ -21,7 +21,7 @@ import { isAtMentionable, matchCatalogModel, refusedCatalogEntry, resolveTaskMod
|
|
|
21
21
|
import { echoModelRef, modelUnavailableMessage } from "../model-entry-refusal.js";
|
|
22
22
|
import { PerTaskImageRegistry, resolveSandboxImageRef } from "../per-task-image.js";
|
|
23
23
|
import { remoteScratchpadDirFor } from "../plugins/remote-scratchpad.js";
|
|
24
|
-
import { bindAttachmentsForTask } from "../plugins/task-attachment-store.js";
|
|
24
|
+
import { attachmentBindRefusalAnswer, bindAttachmentsForTask } from "../plugins/task-attachment-store.js";
|
|
25
25
|
import { resourceSuspendOptIn } from "../resource-suspend.js";
|
|
26
26
|
import { routeServiceTask, supPostureOverrides } from "../router/route-orchestration.js";
|
|
27
27
|
import { tightenGoverned } from "../governance-overrides.js";
|
|
@@ -50,7 +50,7 @@ import { inertToolListEntryOf } from "../rule-entry-list.js";
|
|
|
50
50
|
import { TENANCY_WALL_CLOCK_BASE_SEC, enableForkFromBody, normalizeRetainSubagentSessions, selfOrchestrationFromBody } from "../task-workflow.js";
|
|
51
51
|
import { redactSecrets } from "../trace/redact.js";
|
|
52
52
|
import { DeferredSandboxPathEnv, sandboxPathEnvSlots } from "./deferred-sandbox-path-env.js";
|
|
53
|
-
import { executionLaneHomeDir, executionLaneOf, laneWiresExecutionEnv } from "../execution-lane-caps.js";
|
|
53
|
+
import { executionLaneHomeDir, executionLaneOf, laneIsolated, laneWiresExecutionEnv } from "../execution-lane-caps.js";
|
|
54
54
|
import { executionConfigRootOf } from "../execution-config-root.js";
|
|
55
55
|
import { withUnattendedLeg } from "../unattended-permission-mode.js";
|
|
56
56
|
import { fieldConflictFacts } from "../field-conflict.js";
|
|
@@ -217,11 +217,13 @@ export function createResolveSpec(ctx) {
|
|
|
217
217
|
if (!auth?.sessionId)
|
|
218
218
|
throw new HttpError(400, "`attachmentIds` requires a session-resolving deployment (no authorizer session)");
|
|
219
219
|
const sid = auth.sessionId;
|
|
220
|
+
const lane = opts.execution.lane;
|
|
220
221
|
const r = await bindAttachmentsForTask({
|
|
221
222
|
store: taskAttachmentStore,
|
|
222
223
|
owner: auth?.principal ?? "default",
|
|
223
224
|
ids: reqAtt,
|
|
224
225
|
sessionId: sid,
|
|
226
|
+
lane: { word: lane, isolated: laneIsolated(lane) },
|
|
225
227
|
leg: opts?.leg === "fresh" ? "fresh" : "resume",
|
|
226
228
|
nowMs: Date.now(),
|
|
227
229
|
onMissing: (id) => {
|
|
@@ -229,6 +231,12 @@ export function createResolveSpec(ctx) {
|
|
|
229
231
|
throw new HttpError(400, `attachment not found: ${id}`);
|
|
230
232
|
logger.warn("attachment_missing_on_resume", { sessionId: sid, id });
|
|
231
233
|
},
|
|
234
|
+
onRefused: (refusal) => {
|
|
235
|
+
const answer = attachmentBindRefusalAnswer(refusal);
|
|
236
|
+
if (opts?.leg === "fresh")
|
|
237
|
+
throw createCodedHttpError(answer.status, answer.errorCode, answer.message, answer.extra);
|
|
238
|
+
logger.warn("attachment_refused_on_resume", { sessionId: sid, errorCode: answer.errorCode, ...answer.extra });
|
|
239
|
+
},
|
|
232
240
|
});
|
|
233
241
|
attachmentNotice = r.notice;
|
|
234
242
|
}
|
|
@@ -277,6 +285,7 @@ export function createResolveSpec(ctx) {
|
|
|
277
285
|
sessionId: auth?.sessionId ?? "",
|
|
278
286
|
cwd: (auth?.sessionId ? perSessionCwd.get(auth.sessionId) : undefined) ?? process.cwd(),
|
|
279
287
|
...(parsedSettings.settings?.shellEnv ? { shellEnv: parsedSettings.settings.shellEnv } : {}),
|
|
288
|
+
httpHookAllowlistLayers: parsedSettings.settings?.httpHookAllowlist !== undefined ? [parsedSettings.settings.httpHookAllowlist] : [],
|
|
280
289
|
hookLlm,
|
|
281
290
|
hookAgent,
|
|
282
291
|
onHookNotice: (n) => fleetBus.publishHookNotice({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
2
|
+
import { seatText } from "../trace/exit-seat.js";
|
|
2
3
|
export const RETENTION_SWEEP_STUCK_THRESHOLD = 5;
|
|
3
4
|
export const RETENTION_LEASE_TTL_FACTOR = 2;
|
|
4
5
|
const DAY_MS = 86_400_000;
|
|
@@ -137,15 +138,16 @@ async function recordDomainFailure(ctx, d) {
|
|
|
137
138
|
}
|
|
138
139
|
const streaks = ctx.streaks;
|
|
139
140
|
const streak = (streaks?.get(d.domain) ?? 0) + 1;
|
|
141
|
+
const shown = seatText("operator-log-text", message);
|
|
140
142
|
streaks?.set(d.domain, streak);
|
|
141
143
|
try {
|
|
142
|
-
ctx.logger.warn("retention_sweep_domain_failed", { domain: d.domain, fencingToken: d.fencingToken, consecutiveFailures: streak, auditRowWritten, err:
|
|
144
|
+
ctx.logger.warn("retention_sweep_domain_failed", { domain: d.domain, fencingToken: d.fencingToken, consecutiveFailures: streak, auditRowWritten, err: shown });
|
|
143
145
|
if (streak >= RETENTION_SWEEP_STUCK_THRESHOLD) {
|
|
144
146
|
ctx.metrics.inc("retention_sweep_stuck", {}, 1);
|
|
145
147
|
ctx.logger.warn("retention_sweep_stuck", {
|
|
146
148
|
domain: d.domain,
|
|
147
149
|
consecutiveFailures: streak,
|
|
148
|
-
lastError:
|
|
150
|
+
lastError: shown,
|
|
149
151
|
note: "this retention domain has failed its sweep for RETENTION_SWEEP_STUCK_THRESHOLD consecutive rounds — its data is NOT being retained per policy. Check retention_audit rows with action='failed' for this domain.",
|
|
150
152
|
});
|
|
151
153
|
streaks?.set(d.domain, 0);
|
|
@@ -168,7 +170,7 @@ export function startRetentionLane(ctx) {
|
|
|
168
170
|
.then(() => undefined)
|
|
169
171
|
.catch((err) => {
|
|
170
172
|
try {
|
|
171
|
-
ctx.logger.warn("retention_sweep_round_failed", { err: err instanceof Error ? err.message : String(err) });
|
|
173
|
+
ctx.logger.warn("retention_sweep_round_failed", { err: seatText("operator-log-text", err instanceof Error ? err.message : String(err)) });
|
|
172
174
|
}
|
|
173
175
|
catch {
|
|
174
176
|
recordFailOpen("server.retention.sweep-report-dropped", "round");
|