chore(reconcile): integrate upstream v1.1.0 with fork behaviors retained - #24
Merged
Merged
Conversation
* fix(codeapi): add session cache recovery utility * fix(codeapi): accept emitted session keys
…AI#71) Source: ClickHouse/ai@573e859e52c5e8566843556438bdc2e479f011b4 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat: add outbound stateful code bridge * test: cover remote bridge startup policy * fix: harden remote bridge lifecycle fencing * fix: harden remote bridge assignment lifecycle * fix: close remote bridge commit races * fix: surface shutdown workspace quarantine * fix: fail closed across bridge lifecycle gaps * fix: persist stateful settlement commit barriers * fix: bound bridge control-plane timing * fix: recover abandoned bridge leases * fix: fence stateful bridge workspaces * fix: recover bridge lease read failures * fix: add safe workspace fence recovery * fix: bound bridge liveness timers * fix: bound bridge cleanup recovery * fix: preserve bridge deadline fencing * fix: acknowledge bridge lease delivery * fix: close bridge deadline gaps * fix: harden bridge recovery edges * fix: preserve bridge rejection recovery * fix: fence bridge lease recovery * fix: bound bridge control lifetimes * fix: retain bridge recovery ownership * fix: isolate bridge control state * fix: bound bridge workspace reset * fix: validate bridge deployment inputs * fix: close bridge registration and deadline races * fix: anchor bridge lease freshness * fix: preserve bridge response status
* feat: add outbound stateful code bridge * test: cover remote bridge startup policy * fix: harden remote bridge lifecycle fencing * feat: add secure code worker pairing * fix: harden paired worker lifecycle * fix: require paired auth on hardened APIs * fix: harden bridge pairing startup policy * fix: preserve bridge fencing through pairing * fix: distinguish assignment settlement conflicts * fix: harden remote bridge assignment lifecycle * fix: close remote bridge commit races * fix: surface shutdown workspace quarantine * fix: fail closed across bridge lifecycle gaps * fix: persist stateful settlement commit barriers * fix: bound bridge control-plane timing * fix: recover abandoned bridge leases * fix: fence stateful bridge workspaces * fix: recover bridge lease read failures * fix: add safe workspace fence recovery * fix: bound bridge liveness timers * fix: bound bridge cleanup recovery * fix: preserve bridge deadline fencing * fix: acknowledge bridge lease delivery * fix: close bridge deadline gaps * fix: harden bridge recovery edges * fix: preserve bridge rejection recovery * fix: fence bridge lease recovery * fix: bound bridge control lifetimes * fix: retain bridge recovery ownership * fix: isolate bridge control state * fix: bound bridge workspace reset * fix: validate bridge deployment inputs * fix: close bridge registration and deadline races * fix: anchor bridge lease freshness * fix: preserve bridge response status * fix: harden paired bridge lifecycle * fix: sustain paired credentials in flight * fix: fence credential refresh deadlines * fix: fence sandbox start at deadline * fix: complete paired worker revocation * fix: make worker revocation atomic * fix(bridge): fence queued registration after revoke
* feat: add outbound stateful code bridge * test: cover remote bridge startup policy * fix: harden remote bridge lifecycle fencing * feat: add secure code worker pairing * fix: harden paired worker lifecycle * fix: require paired auth on hardened APIs * fix: harden bridge pairing startup policy * fix: preserve bridge fencing through pairing * fix: distinguish assignment settlement conflicts * feat: add principal-bound bridge workers * fix: authenticate principal worker routing * fix: fence bridge identity and backend routing * fix: fence bridge redemption and queue routing * fix: preserve legacy routing and assignment auth * fix: preserve long-lived bridge assignments * fix: persist replay queue backend * fix: fence bridge replay and credential rotation * fix: address principal worker review findings * fix: reconcile principal workers with bridge fencing * fix: fence principal worker lifecycle transitions * fix: fence bridge settlement ownership * fix: fence bridge leases to active principals
* feat: add outbound stateful code bridge * test: cover remote bridge startup policy * fix: harden remote bridge lifecycle fencing * feat: add secure code worker pairing * fix: harden paired worker lifecycle * fix: require paired auth on hardened APIs * fix: harden bridge pairing startup policy * fix: preserve bridge fencing through pairing * fix: distinguish assignment settlement conflicts * feat: add principal-bound bridge workers * fix: authenticate principal worker routing * fix: fence bridge identity and backend routing * fix: fence bridge redemption and queue routing * fix: preserve legacy routing and assignment auth * fix: preserve long-lived bridge assignments * fix: persist replay queue backend * fix: fence bridge replay and credential rotation * fix: address principal worker review findings * fix: reconcile principal workers with bridge fencing * fix: fence principal worker lifecycle transitions * fix: fence bridge settlement ownership * fix: fence bridge leases to active principals * fix: invalidate pending worker pairings on revoke * fix: package bridge protocol in API image * fix: fence mixed-version pairing revocation * fix: redeem valid legacy pairing codes * fix: harden pairing rollout compatibility * fix: make pairing revocation atomic * fix: preserve pairing identity across rollouts * fix: reopen pairing cleanup after rollbacks * fix: bound legacy pairing migration scans * fix: retry interrupted pairing migrations * fix: harden pairing migration cleanup * fix: make pairing cleanup recoverable * fix: preserve pairing recovery across lifecycle rollout * fix: drain API pods before pairing rollback * fix: fence rollback reentry and pairing epochs * fix: close rollback verification gaps * fix: keep rollback drain on one cluster * fix: bound rollback recovery triggers
…ibreChat-AI#65) The /upload and /upload/batch endpoints in router.ts construct busboy without specifying defCharset or defParamCharset. Busboy defaults to Latin-1 (ISO-8859-1) for multipart parameter decoding, which causes non-ASCII filenames (e.g. Japanese characters) to be garbled. file-server.ts already sets defCharset: 'utf8' and defParamCharset: 'utf8' (lines 336-337), but router.ts was missing the same options — an asymmetry that surfaces as mojibake when uploading files with non-ASCII names through the API gateway. Add both options to the two busboy() calls in router.ts for consistency with file-server.ts.
…lization (LibreChat-AI#75) * fix: large tool inputs break bash PTC replay and pending-call serialization * fix: reject multi-document tool input and invalid PTC byte-cap env values * fix: validate floored PTC byte caps to avoid a zero-cap collapse --------- Co-authored-by: kenzaelk98 <254484110+kenzaelk98@users.noreply.github.com>
* feat: Add Stateful Runtime Supervisor 🧰 * fix: harden runtime supervisor lifecycle
* feat: add Docker runtime supervisor * fix: preserve Docker runtime lifecycle safety * fix: close interrupted Docker lifecycle paths
* feat: add Docker supervisor CLI mode * fix: allow image-free Docker workspace reset
Deployments currently have to track main, which advances whenever an internal snapshot is merged. Cut versioned tags instead, each carrying the packaged Helm chart so a deployment can pin one. The tag is the app version and must match helm/codeapi/Chart.yaml appVersion, so a deployed chart cannot report a version no release ever carried. `latest` moves only for the highest stable tag, and the chart is packaged before the tag is created so a rate-limited subchart pull leaves the version unused and the run retryable. Closes LibreChat-AI#63
* feat: add local NsJail runtime profile * fix: refresh stale local runtimes * fix: surface local runtime state loss
* fix(lambda-microvm): give each PTC replay iteration a distinct clientToken PTC replay reuses one executionId across every stateless iteration, but the launch clientToken was derived from that executionId alone. Each iteration relaunches with a changed sandbox payload (a fresh _ptc_history.json), so AWS rejected the second launch with "The provided clientToken was used with different request parameters" and LibreChat surfaced the generic "Bash programmatic execution failed" (LibreChat-AI#59). Fold the launch inputs and the per-iteration request body into the token so each distinct launch gets a distinct token while an identical retry stays idempotent. Reuses runtimeSessionLaunchRequestFingerprint rather than restating the launch inputs. Reported with a working patch by @snapydziuba. * fix(lambda-microvm): key the stateless launch token to the queued job Addresses codex review on LibreChat-AI#82. Hashing the request body made the token move between attempts of the same job: workers.ts rebuilds the request on every attempt with a fresh egress grant (random IV and sandbox session id) and a re-signed manifest, so a replacement worker taking over a stalled job would derive a different token, launch a second VM, and leave the accepted one burning capacity until its maximum duration expired. Use the queued job id instead. Each PTC replay iteration is enqueued as its own job, so it is distinct per iteration and stable across attempts of the same job -- and it carries no capability-bearing material. The launch configuration stays in the digest so a worker with a different config cannot reuse another's token.
* fix: preserve uploaded filenames without s3 metadata * fix: preserve filenames through hardened egress
Guest clock drift past the 30s execution-manifest tolerance makes every /v1/exec fail with "not_yet_valid" while both health endpoints keep reporting healthy, so the stack looks fine while nothing runs (LibreChat-AI#37). The healthcheck already detects this, but it stays disabled unless an orchestrator opts in, and the Compose files never did -- only the Helm chart set it. Opt in there too, at the same 10s the chart uses. The 2s probe timeout keeps the check inside both files' healthcheck timeouts (3s and 5s) and leaves headroom under the 30s tolerance.
* fix(helm): resolve Bitnami subcharts over OCI Bitnami distributes charts OCI-only. The classic charts.bitnami.com index still lists redis 24.1.0 and minio 17.0.21, but resolves them to an oci:// download URL that HTTP-repository getters cannot follow, so FluxCD's source-controller fails dependency resolution outright with 'unsupported protocol scheme "oci"' (#21). Point both dependencies at the OCI registry directly. Requires Helm >= 3.8. Reported by @meroo36. * docs(helm): require Helm >= 3.8 for OCI subchart resolution Addresses codex review on LibreChat-AI#83. The README's "Helm 3.x" prerequisite and setup-local.sh's existence-only check both allowed 3.0-3.7, where OCI dependency references are not resolved without an experimental flag -- so the documented setup flow would fail at dependency resolution rather than with a clear message. State the real minimum, and reject older Helm in setup-local.sh before it gets that far. Also drop the classic bitnami repo registration, which the OCI references no longer use; verified 'helm dependency update' resolves both subcharts with that repo removed from the local Helm config. * chore(helm): bump chart to 0.3.1 for the dependency source change Addresses codex review on LibreChat-AI#83. Changing where the subcharts resolve from is a chart-level change, and Chart.yaml's own version comment asks for a bump. Leaving 0.3.0 in place lets consumers reconciling on chart version treat the corrected chart as the already-seen 0.3.0 artifact and keep the broken HTTP dependency metadata. Matches 4b72e9d, which bumped the chart for the same reason.
* feat: add networkless BYOM file relay * fix: harden managed file relay * fix: fence relay lifecycle races * fix: order relay handoffs by registration * fix: gate relay workers on runtime readiness * fix: preserve legacy marker listings * fix: recover reclaimed relay staging
* 🗑️ fix: Make Code Environment File Deletion Work Object deletion has never removed anything, and the failure was silent at every layer. The client (LibreChat `deleteCodeEnvFile`) issues DELETE against `/v1/sessions/:session_id/objects/:fileId`, the file-server's own path, which is not exposed on `/v1` — only GET is mounted there. Every deletion 404'd, and a 404 is indistinguishable from "already gone", so the caller cleared its state and the bucket only ever grew (13 GiB / 29k objects on a six-week-old deployment, per danny-avila/LibreChat#15511). Mount DELETE on that path as an alias of `/v1/files/:session_id/:fileId`, so deployments running a client older than LibreChat v0.8.6 — before the fallback to `/files/...` landed — delete successfully. Pass the file-server's 404 through instead of collapsing it into a 500: a 500 reads as retryable, and a client sweeping its retention window re-issues the same DELETE hourly, forever, for an object that no longer exists. Correcting the route is not sufficient on its own. `sessionAuth` authorizes deletion against `session:<session_id>`, whose `SESSION_CACHE_TTL` is 24h and is not refreshed by use, so an object was deletable only for the day following upload and stranded permanently after that — unreadable, unusable as an execution input, and undeletable through every route. Clients are typically far outside that window when they get there; LibreChat's default retention is 30 days. Record ownership twice: `session:<id>` stays the hot-path cache bounding read access, and a durable `session-owner:<id>` record (`SESSION_OWNER_TTL`, 90 days, never shorter than the cache TTL) backs deletion once the cache key has lapsed. The fallback applies to DELETE only — reads keep the window they have always had — and a live cache key naming a different owner remains authoritative, so a re-registered session is never deletable by its previous owner. The recovery script restores both records, so a rehydrated session stays deletable rather than stranding again a day later. * fix: Close Codex review findings on session ownership Four P2 findings from the review of daae56c: - The 404 deletion path cleared the upload key with a bare `await` inside the catch block. A Redis failure there rejects with no handler above it, and Express 4 does not forward async rejections, so the request would hang instead of answering 404. Make the cleanup best effort and log it. - The blocking PTC path discarded the registration promise with `void`, preserving the previous fire-and-forget behavior. That now spans two keys: a partial write (cache key stored, durable record refused by a Redis ACL scoped to `session:*`) would produce exactly the undeletable files this change exists to prevent. Await it; the caller turns a rejection into a 500 before anything is enqueued. - Recovery treated a durable owner record naming someone else as a log line while still counting the session as restored or matching, so an apply could exit 0 having recovered nothing usable. Reconcile the owner record before touching the cache key and report the disagreement as a conflict, in dry run as well as apply. The cache key is no longer restored for those sessions either — the manifest's claimant should not get a day of access the service never granted it. - `SET NX` cannot extend an expiry, so a matching owner record could carry less remaining TTL than the cache key being restored and lapse first, stranding the session again just as recovery reported success. Top up the expiry when it is shorter than the target, leaving longer ones alone. * fix: Settle session ownership before recovery writes anything Two findings from the review of 816dbb5: - Reconciling the durable owner record first meant creating it before the live cache key had been consulted. For a session whose durable record was absent and whose cache key named a different owner, recovery wrote a durable record for the manifest's claimant, then reported the cache conflict and moved on — leaving the record behind. It outlives the cache key by design, so once that expired, `sessionAuth` would authorize the manifest owner to delete the real owner's files. Split the read from the write. The durable record is now inspected read-only up front, where a disagreement still settles the session before anything is written, and is created or extended only once the cache key has been confirmed to name the same owner. - `/exec` registered ownership before entering the route's `try`. Express 4 does not forward a rejected async handler to the error middleware, so a Redis failure there would hang the request rather than answering. Guard it and return a controlled 500. * fix: Harden recovery's durable owner handling Three findings from the review of 47b36e0, all in the recovery script: - A `SET NX` that lost the race to a key which then expired before the follow-up read left no record and no conflict, and the session was reported as recovered while its durable half did not exist. Retry once, and report anything past that as missing so an apply exits nonzero instead of claiming success. - When the owner commit conflicted on a session whose cache key this run had just created, the cache key stayed. That grant authorizes reads and deletes for its full TTL while the durable record names somebody else, so roll it back. A durable record that merely could not be created is left alone: the session is no worse off than before the run, and removing the grant would leave the operator with nothing. - A dry run reported a session whose cache key already matched as `matching` even when its owner record was absent or short-lived, hiding the work an apply would do and inviting operators to skip it. Pending owner repairs now count as missing. * fix: Answer Redis failures instead of hanging on them Two findings from the review of d1de664: - `sessionAuth` awaited the ownership lookup unguarded. Express 4 does not forward a rejected async middleware, so an unavailable Redis — or an ACL granting `session:*` but not `session-owner:*` — would hang a DELETE rather than answering it. Catch and return a controlled 500. - The recovery script's TTL top-up read, extended and returned across three round trips, reporting success on evidence it had not rechecked. The record can lapse in between, in which case it is now created fresh, or name somebody else, in which case the session is a conflict. Extending a record that turns out to belong to another owner prolongs a claim the service itself wrote and grants nothing new, but reporting the session as recovered on that basis would not be true.
* feat(code): add confined local workspace tools * fix(code): confine workspace text search * fix(code): center bounded search previews * fix(code): tighten workspace result semantics * fix(code): harden workspace text search * fix(code): normalize workspace text boundaries
* feat(code): dispatch local workspace tools * fix(code): fence workspace tool completion * fix(code): drain workspace cancellation before settlement * fix(code): drain active cancellation responses * fix(code): preserve drained cancellation fences * fix(code): Fall back from invalid workspace names
* feat(code): add workspace tool API * docs(code): clarify repository-optional workspaces * fix(code): validate workspace API boundaries * fix(code): Harden workspace API validation * fix(code): Preserve workspace search scope * fix(code): close workspace API lifecycle gaps
* feat(code): list attached workspace files * fix: preserve canonical workspace listings * fix: preserve exact UTF-8 workspace paths * fix: preserve workspace listing policy
* feat: add dedicated Lambda hosted-app runner * fix: serialize hosted app cgroup cleanup * fix: serialize hosted app workspace lifecycle * fix: fence hosted app replacement cleanup * fix: preserve hosted app lifecycle invariants * fix: complete hosted app workspace coordination
…t-AI#94) Redo of the Dependabot bump, which only updated `api/package.json` and `api/package-lock.json`: - `api/bun.lock` is the lockfile CI and `api/Dockerfile` actually install from (`bun ci` / `bun install --frozen-lockfile`), and it was left on express 4, so every api job failed with "lockfile had changes, but lockfile is frozen". - The `path-to-regexp: 0.1.13` override pinned express 4's router dependency. Express 5 routes through `router@2`, which needs path-to-regexp ^8, so the override had to go rather than be carried forward. - qs stayed on 6.15.3: it already satisfied express 5's `qs@^6.14.0`, so resolution never moved it to the 6.16.0 the bump was for. Both lockfiles are regenerated and agree on express 5.2.1, qs 6.16.0, path-to-regexp 8.4.2 and router 2.2.0. The api's express surface is v5-clean: all route paths are literal (no wildcards or optional params for path-to-regexp 8 to reject), `req.query` is never read (so the query-parser default change is inert), and the only `req.body` reads are behind a JSON parser, an `application/json` guard, or already undefined-tolerant. `@types/express` was already ^5.0.0, so the types now match the runtime instead of being a version ahead of it. Co-authored-by: Danny Avila <danny@librechat.ai>
* feat(code): add opt-in workspace mutations * fix(code): fence workspace mutation commits * fix(code): harden workspace replacement invariants * fix(code): close workspace mutation lifecycle gaps * fix(code): revalidate edits after metadata restore * fix(code): persist mutation quarantine across restarts * fix(code): fence uncertain mutation executor failures * fix(code): close durable mutation guard races * fix(code): bind durable guards to workspace roots * fix(code): harden mutation durability * fix(code): fence concurrent workspace mutations
* feat: run PTC in selected BYOM workspaces * fix: harden native workspace PTC replay * fix: preserve replay isolation and bridge limits * test: tolerate hosts without filesystem cloning * test: surface copy-on-write clone faults * fix: harden native workspace PTC admission * fix: close native replay effect and finalization boundaries
* feat: report truncated output artifacts * fix: classify omitted artifacts precisely * fix: preserve artifact scan invariants * fix: bound depth truncation probes * fix: bound capped directory enumeration * fix: constrain truncation probes across the job * fix: stop exhausted artifact probes
* fix: cancel replay jobs across API and worker processes * fix: drain worker cancellation watches promptly * fix: close programmatic cancellation races * fix: preserve cancellation response ordering * fix: close distributed cancellation races * fix: harden cancellation under concurrent load * fix: make cancellation ownership durable through completion * fix: recover durable replay outcomes across lost replies * fix: return atomic cancellation outcomes with aligned retention * fix: commit native results inside the workspace mutation fence * fix: claim programmatic execution before stalled-job redelivery
* fix: report deleted persisted files * fix: reconcile deletions across code runtimes * fix: preserve protected session inputs * fix: classify reserved runtime paths
* feat: declare named worker project environments * fix: preserve environment trust and negotiated action boundaries * Harden environment loading and executor identity * Protect environment root traversal and exact config bytes * Reject self-controlled environment root aliases * Check filesystem identities at environment trust boundaries * Validate environment containment across Linux mount aliases * Handle stacked mounts conservatively without blocking unrelated paths
* fix: Allow Trusted Own-Root Environment Symlinks * fix: Check Alias Parent Ownership by Filesystem Identity * fix: Enforce Parent Ownership Across Every Environment Path
* fix: Retain Quarantine After Failed Environment Setup * test: Run Native Environment Setup Lifecycle in CI * fix: Document and Verify Local Setup Quarantine Recovery
* fix: decouple repository release versions * ci: automate releases after successful main builds
* feat: add bounded local project inventory * fix: report incomplete Git metadata reads * fix: preserve incomplete discovery and remote identities * fix: finalize discovery budgets and nested remote identities * fix(code): stop project traversal at filesystem budget boundaries
Merge LibreChat-AI/code-interpreter v1.1.0 (b35c503, chart 0.3.1) into the UZH fork. Resolves the eight conflicted files: - Dockerfiles: adopt upstream docker/rootfs-setup.c, guest-dns.sh and the hosted-app launcher; keep the UZH chmod 0555 read permission on both spec-guard and sandbox-rootfs-setup. - service/tsconfig.json and rollup.config.js: union upstream packages/code/src inputs with the fork shared/operational-log.ts policy. - service/src/queue.ts: keep the queue-wait import and export surface alongside upstream jobCancellationRegistry, closeQueueConnections and redisReconnectDelay. - service/src/service/programmatic-router.ts: adopt upstream cancellation-aware waits; add the additive BullMQ poll fallback via a never-rejecting fallbackCompletion channel in waitForJobWithCancellation, and keep the fork events+poll race on the blocking path. - service/src/auth/librechat-jwt.ts: keep the issuer trust table, principal sources and tenant namespacing while adopting upstream code_worker_id. - service/src/service/exec-timeout.test.ts: expose waitForJobFinished in the queue mock to match the fork router contract. service: 1076 pass / 0 fail. api: 481 pass / 0 fail.
Record the v1.1.0 re-audit basis (fork f5bf3b4, upstream tag b35c503, merge base 2c7fb8f), narrow the egress-ledger patch to the singleton ledger now that upstream reconnects queue clients indefinitely, add the PR #23 nonfatal-telemetry patch, extend the spec-guard and PVC package-init sections with their v1.1.0 evidence and retirement review, and record the values-free logging re-inventory.
Resolve the completion-event channel from its QueueEvents payload instead of re-reading a possibly-evicted job, and give an in-flight event one poll interval of grace before honoring a poll failure so a completed job is never reported as missing. Restore the poll fallback's retention depth in programmatic-router.ts (removeOnComplete.count 1 -> 100, as router.ts already had), own the fallback poller's abort signal in waitForJobWithCancellation so it stops when any other outcome settles, and bound the upstream code_worker_id claim per trust entry via codeWorkerIdPrefixes so an external issuer cannot name another issuer's bridge worker in a multi-entry trust table.
…view reports Keeps plan-hardening and review reports under docs/project/_local/ out of history, and records the executed slices with their verification receipts.
The focused confirmation review of 53ed390 confirmed the three required fixes but found one regression and two unpinned behaviors: - queue-wait.ts declared the QueueEvents payload with the typed result, which introduced two TS2345 errors against BullMQ's string declaration. Declare the field as BullMQ does and convert through unknown instead. - The fallback poller's abort contract had no test coverage: removing either abort call left the suite green. Cover the pending/aborted lifecycle, the registration-failure abort, and the additive rejection contract. - codeWorkerIdPrefixes had no cross-entry uniqueness check, so two external entries could declare duplicate or nested prefixes and each admit the other's bridge workers. Reject overlapping prefixes at config time, mirroring the existing keyId and external-source checks. - Rename the fallback poller's parameter so it no longer shadows the client-disconnect signal in programmatic-router.ts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merges upstream LibreChat-AI/code-interpreter v1.1.0 (tag
b35c503fd2fe, chart 0.3.1, appVersion 2.0.0) into the UZH fork while replaying every fork behavior onto the new upstream tree. Nothing in current fork behavior is dropped; the merge delta is 108 upstream commits since the PR #17 reconcile point (2c7fb8fc).The fork is still required after this release: v1.1.0 absorbs none of the ten fork behaviors. Upstream remains single-issuer JWT trust, raw Winston/Pino logging, five-attempt Redis reconnect, event-only job completion, single-namespace Helm, chart-owned secrets/HPA, hook-based package-init, and has no image-publication workflow. The fork is active production GitOps infrastructure (df-cloud Argo Applications pinned to UZH GHCR images), so the reconciliation keeps those contracts while adopting upstream's new BYOM/remote-worker system, hosted apps, PTC cancellation, workspace tools and admission capacity, artifact delivery/truncation, express 5 / nanoid 5, chart 0.3.1, and the new security fixes (bounded upload memory, input-file limits into guests, credential ACL).
What changed
Merge and conflict resolution. Eight files conflicted:
api/Dockerfile,docker/Dockerfile.worker-sandbox,launcher/Dockerfile,service/rollup.config.js,service/tsconfig.json,service/src/auth/librechat-jwt.ts,service/src/queue.ts,service/src/service/programmatic-router.ts. The Dockerfiles adopt upstream'sdocker/rootfs-setup.c,guest-dns.shand hosted-app launcher, and keep the fork'schmod 0555on bothspec-guardandsandbox-rootfs-setup; rollup/tsconfig take the union including../shared/operational-log.ts. Helm templates,values.yaml,ci.yml,egress-ledger.tsand the logger sinks auto-merged and were verified rather than replayed.Adopted upstream capabilities. The BYOM remote-worker system and worker admission, hosted-app control plane, PTC cancellation across processes, confined local workspace tools, artifact delivery/truncation reporting, express 5 / nanoid 5, chart 0.3.1, and the security fixes above.
Retained fork behaviors (ten logical patches, ledger in
docs/fork/patches.md). Exact-SHA UZH GHCR images; readablespec-guardroots (0555); split/hardened untrusted sandbox namespace; ceded ownership to external controllers; Argo-safe PVC package-init (de-hooked to sync-wave -5, marked for retirement review after rollout); BullMQ poll fallback composed into the new cancellation-aware waiter; egress-ledger indefinite reconnect (narrowed toegress-ledger.ts, since the queue-client finite-retry concern is resolved upstream); issuer-scoped JWT trust table extended withcode_worker_id; values-free operational logs; nonfatal telemetry (PR #23).Final-review fixes (commit
53ed390)One integrated final review (correctness, maintainability, security) returned PASS_WITH_CONCERNS with three required fixes; all three are addressed in
53ed390with covering tests:service/src/queue-wait.ts) — the event channel now resolves from the QueueEvents payload instead of re-fetching a possibly-evicted job, and a poll failure grants one in-flight event poll interval before propagating. Without this,handleBlockingcould surface a successful execution as an error when a concurrent completion evicted the job.service/src/job-cancellation.ts,service/src/service/programmatic-router.ts) — the fallback poller now receives an abort signal owned bywaitForJobWithCancellationand stops on the first terminal outcome; retention restored toremoveOnComplete.count: 100at both enqueue sites, which the merge had silently reverted to upstream's1and which left the replay fallback inert.code_worker_idbounding (service/src/auth/librechat-jwt.ts) — a multi-entry trust table must now declarecodeWorkerIdPrefixesfor its external entry and the claim is verified against them; a single-entry table stays unconstrained for backward compatibility. This closes a cross-issuer bridge-worker routing gap that only appears withCODEAPI_BRIDGE_DYNAMIC_WORKERS=trueand two or more trust entries.A focused confirmation pass over
53ed390(Claude Opus 5, trusted read-only) confirmed fixes 1 and 3 and found one regression plus two unpinned behaviors; all are closed ina0ebd3c:unknown.fallbackAbortController.abort()call left the suite green, so the fallback poller's lifecycle is now covered: it runs while the wait is pending, stops once completion wins, aborts when subscription registration fails, and a rejecting poller cannot override the completion outcome.codeWorkerIdPrefixeshad no cross-entry uniqueness check, so two external entries could declare duplicate or nested prefixes and each admit the other's bridge workers. Overlapping prefixes are now rejected at config time, mirroring the existing keyId and external-source checks.programmatic-router.ts.Two residual, non-required findings are recorded as follow-ups, not slices: internal principal sources are not de-duplicated across trust entries (inherited pre-fix), and Redis TLS keeps
rejectUnauthorized: falseupstream-inherited. The inherited 7packages/codefailures,tests/kvm_guest_dns.shfailure, and the trailing blank line inservice/src/minio-client.tsare byte-identical to pristine v1.1.0 and are not regressions from this package.Review and validation
Local verification is green at the pushed head:
bun run buildOKbun run buildOKhelm lintOK; chart 0.3.1 render verified for STG+PRD ownership (no chart Secret/HPA in external mode; package-init Job + PVC only in pvc mode, at sync-wave -5)block_root_package_delivery.sh,sandbox_runner_healthcheck.sh,bridge_pairing_rollout.sh,release-versioning.sh,compose-bridge-config.cjsspec-guardcompile + smoke PASS inubuntu:24.04;docker buildx --checkclean on the api and worker-sandbox Dockerfilesgit diff --checkclean apart from the inherited v1.1.0 blank-line-at-EOFVerification receipts (commands and revisions)
Tested revision:
53ed390code head (docs-only5e49e0don top). Reused evidence:packages/codefailure set is byte-identical to pristine v1.1.0 under container;tests/kvm_guest_dns.shfails identically on pristine v1.1.0. A singlebridge/store.test.tsDNSException: getaddrinfo ENOTFOUNDflake reproduces at the pre-fix commit and is a missing localredis-server, not a CI concern. Planner gate recorded as blocked (native planner route failed on an account usage limit), not passed; plan isdocs/project/2026-09-17-upstream-v1.1.0-integration-plan.md.Out of scope
Deployment, image publication, GitOps promotion, and any cluster change are excluded. Merging into
main, closing superseded dependabot PRs, and the PR #21 re-derivation are separately gated decisions, not part of this package.