🔐 feat: Mint Code API Auth Tokens - #13028
Conversation
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e3c85665a5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR adds first-party (LibreChat-minted) short-lived JWT bearer authentication for managed CodeAPI requests, propagating authenticated request context (tenant + principal/source metadata) into CodeAPI-bound operations.
Changes:
- Added CodeAPI JWT minting + Authorization header helper (
mintCodeApiToken,getCodeApiAuthHeaders) with brief caching and scoped claims. - Threaded
authHeadersthrough tool construction paths (programmatic tool calling, bash/code execution) so remote execution can attach CodeAPI auth. - Injected CodeAPI Authorization headers into CodeAPI file upload/batch upload/download flows and plumbed request auth strategy through JWT middleware.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/api/src/types/http.ts | Extends ServerRequest to carry the auth strategy used to populate req.user. |
| packages/api/src/tools/classification.ts | Adds optional authHeaders provider to tool classification and forwards it into PTC tool creation. |
| packages/api/src/auth/index.ts | Exposes the new CodeAPI auth helpers via the auth barrel export. |
| packages/api/src/auth/codeapi.ts | Implements JWT minting, claim shaping, signing, and header generation for CodeAPI. |
| packages/api/src/auth/codeapi.spec.ts | Adds unit tests covering minting behavior, spoofing resistance, and caching window behavior. |
| api/server/services/ToolService.js | Passes authHeaders into agent tool classification and into PTC + bash tool creation for execution-time calls. |
| api/server/services/Files/Code/crud.js | Adds CodeAPI Authorization headers to CodeAPI download/upload/batch-upload axios requests. |
| api/server/routes/files/files.js | Passes req into the code-output download stream strategy to enable per-request auth headers. |
| api/server/middleware/requireJwtAuth.js | Records chosen passport strategy on req.authStrategy before tenant context middleware runs. |
| api/server/middleware/optionalJwtAuth.js | Sets req.authStrategy consistently when optional auth succeeds (openidJwt vs jwt). |
| api/app/clients/tools/util/handleTools.js | Provides CodeAPI auth headers to the code execution tool for managed remote execution. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: abc2daf3bb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
GitNexus: 🚀 deployedThe |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e27ab4356e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
1 similar comment
|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
GitNexus: 🚀 deployedThe |
|
@codex review |
1 similar comment
|
@codex review |
GitNexus: 🚀 deployedThe |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7281fd5c28
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1a270f35b7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
GitNexus: 🚀 deployedThe |
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
GitNexus: 🚀 deployedThe |
72a882e to
bfb5cb3
Compare
GitNexus: 🚀 deployedThe |
GitNexus: 🚀 deployedThe |
GitNexus: 🚀 deployedThe |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c094b51baa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
GitNexus: 🚀 deployedThe |
|
Codex Review: Didn't find any major issues. 👍 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
9879b68 to
24c0acf
Compare
* feat: Mint CodeAPI auth tokens * style: Format CodeAPI download route * fix: Prune CodeAPI token cache * fix: Propagate CodeAPI managed auth * test: Mock CodeAPI auth in traversal suite * fix: Pass auth context to invoked skill cache * feat: Mint CodeAPI plan context * chore: Refresh CodeAPI auth guidance * fix: Guard OpenID JWT fallback * fix: Default CodeAPI JWT tenant in single-tenant mode * chore: Update @librechat/agents to version 3.1.84 in package-lock.json and package.json files * chore: Standardize references to Code API in comments and tests
* feat: Mint CodeAPI auth tokens * style: Format CodeAPI download route * fix: Prune CodeAPI token cache * fix: Propagate CodeAPI managed auth * test: Mock CodeAPI auth in traversal suite * fix: Pass auth context to invoked skill cache * feat: Mint CodeAPI plan context * chore: Refresh CodeAPI auth guidance * fix: Guard OpenID JWT fallback * fix: Default CodeAPI JWT tenant in single-tenant mode * chore: Update @librechat/agents to version 3.1.84 in package-lock.json and package.json files * chore: Standardize references to Code API in comments and tests
…batch LibreChat 0.8.5 (@librechat/agents >= 3.1.74) and the LC PRs around the codeapi auth refactor (LibreChat-AI/LibreChat#13028, #12767) shifted the upload/exec wire contract in ways that broke our clients: 1. Responses are expected to carry ``storage_session_id`` (renamed from ``session_id``) on upload responses and per-file entries. packages/data-provider/src/codeEnvRef.ts and api/server/services/Files/Code/crud.js both read this field; a missing key was making LC throw "Unexpected batch upload response". 2. File references gained ``resource_id``, ``kind`` ('skill'|'agent'| 'user'), and ``version`` discriminator fields (CodeEnvFile type). LC fans them through to skill priming, sandbox file routing, and tool-output references. 3. ``POST /upload/batch`` is the endpoint LC uses for skill bundles — uploading many files in one request. We didn't have it, so skill priming silently 404'd. 4. ``GET /files/{session_id}`` is called with ``kind``/``id``/ ``version`` query params by fetchSessionFiles. Without accepting them the request 422'd. Changes: src/models/exec.py - FileRef: populate_by_name; resource_id/kind/version added; storage_session_id computed-field mirrors session_id. - RequestFile: storage_session_id accepted via AliasChoices alongside legacy session_id; resource_id/kind/version added. src/api/files.py - POST /upload response: dual-emit storage_session_id + session_id. - POST /upload/batch: new endpoint. Returns per-file succeeded/failed counts; persists kind/resource_id on session.metadata when present. - GET /files/{session_id}: kind/id/version query params accepted (pass-through; no server-side filter today). Each list item gets both storage_session_id and session_id. tests/unit/test_librechat_contract.py - 16 new tests pinning every contract point above so a future model refactor cannot silently regress LC compatibility. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
LibreChat LibreChat-AI/LibreChat#13028 introduced signed JWT auth for the code-interpreter API. Tokens are minted by LC's packages/api/src/auth/codeapi.ts (EdDSA Ed25519 by default, RS256 supported) and sent as `Authorization: Bearer <jwt>` with claims {iss, aud, sub, iat, nbf, exp, jti, tenant_id, role, principal_source, auth_context_hash}. This commit adds the verifier side as a new service module — src/services/codeapi_jwt.py — and the env knobs to configure it. The middleware wiring lands in a follow-up commit so the verifier can be unit-tested in isolation first. Settings (env names match LC's signer 1:1): - CODEAPI_JWT_ENABLED (default false; opt-in) - CODEAPI_JWT_PUBLIC_KEY (PEM, raw JWK JSON, or file path) - CODEAPI_JWT_ALGORITHM (EdDSA | RS256; default EdDSA) - CODEAPI_JWT_ISSUER (default 'librechat') - CODEAPI_JWT_AUDIENCE (default 'codeapi') - CODEAPI_JWT_LEEWAY_SECONDS (default 10; clock-skew tolerance) - CODEAPI_JWT_TRUST_TENANT_ID (default false; observability-only) Security: - Algorithm is pinned to the operator-configured value — never the JWT header's `alg`. Standard alg-confusion defence; an attacker hand-crafting an HS256 token signed with the public key as the HMAC secret is rejected. - iss/aud are checked exactly; exp/nbf get the configured leeway. - require=[iss, aud, sub, exp, iat] so a token missing any of those is rejected without falling through to defaults. - Public key loaded once and process-cached; rotate by restart. CodeApiJwtConfigurationError vs CodeApiJwtError distinction lets the caller map config bugs to 500 and token problems to 401. 22 unit tests in tests/unit/test_codeapi_jwt.py cover: EdDSA + RS256 happy path, expired / wrong iss / wrong aud / wrong key / empty sub / malformed / alg-confusion / missing-required-claim rejection, and PEM / JWK / file-path key formats. New dependency: pyjwt[crypto]>=2.10.0 (pulls in cryptography). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ll-runtimes bash image (#66) * fix(security): prevent cross-user file leak via session reuse Sessions referenced by file_ref.session_id or entity_id are now reused only when the existing session's metadata.user_id matches the request's user_id. Before this change, a request from user-B carrying a file_ref that pointed at user-A's upload session would execute *in* user-A's session, where _mount_files would then re-hydrate every file ever uploaded under that session into user-B's pod (issue surfaced in multiple user reports of "users seeing other users files"). Defense-in-depth in _mount_files: even after the session-isolation fix routes user-B to a fresh execution session, refuse to read file content out of a session owned by a different user. Legacy sessions without metadata.user_id are still readable for back-compat — the window pre-dates the ownership concept. license; semantics preserved, doc strings rewritten for our codebase). Pre-existing TestMountFilesExtended tests were updated to set ctx.session_id, which they had been implicitly relying on; the realistic "upload-then-exec in same session" scenario short-circuits the new authorization guard. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(auth): accept HTTP Basic auth, add AUTH_ENABLED bypass LibreChat 0.8.5 (@librechat/agents >= 3.1.74) removed the x-api-key header and the body-spread LIBRECHAT_CODE_API_KEY field from its code- interpreter client. Users with the legacy URL-credentials configuration (LIBRECHAT_CODE_BASEURL=https://KEY@host/v1) now reach us with the key in an Authorization: Basic header that axios derives from the URL — which our middleware was ignoring, causing every request to 401. Extractor now accepts: - x-api-key (preferred, unchanged) - Authorization: Bearer / ApiKey (unchanged) - Authorization: Basic base64(KEY:) ← new; LC convention is user-half - Authorization: Basic base64(:KEY) ← also accepted; falls through - Authorization: Basic base64(user:KEY) → returns user (documented) Malformed Basic headers return None (no 500). x-api-key still wins so reverse-proxy injection has deterministic behavior. New AUTH_ENABLED setting (default true) lets operators with their own trust boundary (mTLS sidecar, VPC ingress) globally bypass key auth on user paths. Admin endpoints (/api/v1/admin) still require MASTER_API_KEY regardless — the bypass is intentionally gated. Bypassed requests get scope["state"] seeded with anonymous markers so downstream metrics code keeps working without crashing on missing api_key_hash. _should_skip_auth gained a `scope` parameter to perform that seeding. Three legacy callers in test_trusted_networks.py updated to pass {}. Same change applied to the older AuthenticationMiddleware in middleware/auth.py for consistency; main.py uses SecurityMiddleware. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(api): wire LibreChat User-Id header into session ownership LibreChat 0.8.5 sends the user identifier in the User-Id HTTP header on every code-interpreter call (api/server/services/Files/Code/crud.js). It is NOT in the request body. Without consuming the header, every LibreChat request reaches us with request.user_id=None, which after the session-isolation fix forces the orchestrator into "create new session" on every call — breaking same-user file continuity (upload → exec → next exec all land in separate sessions). Changes: POST /exec — exec.py copies the User-Id (or X-User-Id) header onto request.user_id when the body field is missing. Body wins when both are set, preserving direct-API compatibility. POST /upload — upload_file gained User-Id / X-User-Id Header params. When present, the value is persisted onto session.metadata.user_id at session-creation time, AND the entity_id reuse path now matches the requesting user (mirrors the orchestrator's same-user gate). Without this, the upload-side entity_id reuse was its own cross-user collapse vector: two users uploading via the same shared agent would converge on a single session. Pre-existing tests in test_cross_session_files.py modeled the legacy issue-#34 entity_id=null scenario. They now explicitly configure session_service.get_session to return None so the orchestrator treats the upload sessions as legacy/anonymous (allowed for back-compat). The upload reuse test was split into same-user-reuse (must reuse) and cross-user-must-not-reuse cases, and a third test pins that User-Id is persisted onto session metadata. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(api): LibreChat 0.8.5 wire contract — storage_session_id, kind, batch LibreChat 0.8.5 (@librechat/agents >= 3.1.74) and the LC PRs around the codeapi auth refactor (LibreChat-AI/LibreChat#13028, #12767) shifted the upload/exec wire contract in ways that broke our clients: 1. Responses are expected to carry ``storage_session_id`` (renamed from ``session_id``) on upload responses and per-file entries. packages/data-provider/src/codeEnvRef.ts and api/server/services/Files/Code/crud.js both read this field; a missing key was making LC throw "Unexpected batch upload response". 2. File references gained ``resource_id``, ``kind`` ('skill'|'agent'| 'user'), and ``version`` discriminator fields (CodeEnvFile type). LC fans them through to skill priming, sandbox file routing, and tool-output references. 3. ``POST /upload/batch`` is the endpoint LC uses for skill bundles — uploading many files in one request. We didn't have it, so skill priming silently 404'd. 4. ``GET /files/{session_id}`` is called with ``kind``/``id``/ ``version`` query params by fetchSessionFiles. Without accepting them the request 422'd. Changes: src/models/exec.py - FileRef: populate_by_name; resource_id/kind/version added; storage_session_id computed-field mirrors session_id. - RequestFile: storage_session_id accepted via AliasChoices alongside legacy session_id; resource_id/kind/version added. src/api/files.py - POST /upload response: dual-emit storage_session_id + session_id. - POST /upload/batch: new endpoint. Returns per-file succeeded/failed counts; persists kind/resource_id on session.metadata when present. - GET /files/{session_id}: kind/id/version query params accepted (pass-through; no server-side filter today). Each list item gets both storage_session_id and session_id. tests/unit/test_librechat_contract.py - 16 new tests pinning every contract point above so a future model refactor cannot silently regress LC compatibility. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(auth): CodeAPI JWT verifier (LibreChat 0.8.5 signer side) LibreChat LibreChat-AI/LibreChat#13028 introduced signed JWT auth for the code-interpreter API. Tokens are minted by LC's packages/api/src/auth/codeapi.ts (EdDSA Ed25519 by default, RS256 supported) and sent as `Authorization: Bearer <jwt>` with claims {iss, aud, sub, iat, nbf, exp, jti, tenant_id, role, principal_source, auth_context_hash}. This commit adds the verifier side as a new service module — src/services/codeapi_jwt.py — and the env knobs to configure it. The middleware wiring lands in a follow-up commit so the verifier can be unit-tested in isolation first. Settings (env names match LC's signer 1:1): - CODEAPI_JWT_ENABLED (default false; opt-in) - CODEAPI_JWT_PUBLIC_KEY (PEM, raw JWK JSON, or file path) - CODEAPI_JWT_ALGORITHM (EdDSA | RS256; default EdDSA) - CODEAPI_JWT_ISSUER (default 'librechat') - CODEAPI_JWT_AUDIENCE (default 'codeapi') - CODEAPI_JWT_LEEWAY_SECONDS (default 10; clock-skew tolerance) - CODEAPI_JWT_TRUST_TENANT_ID (default false; observability-only) Security: - Algorithm is pinned to the operator-configured value — never the JWT header's `alg`. Standard alg-confusion defence; an attacker hand-crafting an HS256 token signed with the public key as the HMAC secret is rejected. - iss/aud are checked exactly; exp/nbf get the configured leeway. - require=[iss, aud, sub, exp, iat] so a token missing any of those is rejected without falling through to defaults. - Public key loaded once and process-cached; rotate by restart. CodeApiJwtConfigurationError vs CodeApiJwtError distinction lets the caller map config bugs to 500 and token problems to 401. 22 unit tests in tests/unit/test_codeapi_jwt.py cover: EdDSA + RS256 happy path, expired / wrong iss / wrong aud / wrong key / empty sub / malformed / alg-confusion / missing-required-claim rejection, and PEM / JWK / file-path key formats. New dependency: pyjwt[crypto]>=2.10.0 (pulls in cryptography). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(auth): wire CodeAPI JWT verification into SecurityMiddleware The CodeAPI JWT verifier landed in the previous commit as a standalone service. This commit makes the middleware actually use it. Auth-path priority on user-facing endpoints: 1. ``Authorization: Bearer <jwt>`` AND ``codeapi_jwt_enabled`` AND the token structurally looks like a JWT (3 base64 segments) → run the JWT verifier. - Valid: seed scope["state"] with authenticated=True, user_id=<sub>, api_key_hash="jwt:<sub-hash-prefix>", auth_principal_source="codeapi_jwt", and (when codeapi_jwt_trust_tenant_id is true) tenant_id=<tenant>. The legacy API-key path is SKIPPED. - Invalid: 401 immediately. DO NOT fall back to API-key auth with the same Bearer string. This is the downgrade-attack defence — an attacker mustn't be able to bypass JWT auth by submitting a deliberately-bad JWT and having the server quietly try the same string as an API key. - Configuration error (JWT enabled but no public key): 500. The client did nothing wrong; we just can't verify. 2. Otherwise: existing API-key path (x-api-key → Bearer api-key → ApiKey scheme → Basic → JSON body LIBRECHAT_CODE_API_KEY). The "looks like a JWT" structural check (3 dot-separated segments, each ≥4 chars) lets a plain API key submitted as ``Bearer`` keep working — we only divert to the JWT path for tokens that could plausibly be a JWT. 12 new unit tests in test_security_middleware.py cover: - _extract_bearer_jwt: disabled / wrong scheme / non-JWT-shaped / happy path classification. - _authenticate_jwt: valid token seeds expected state; tenant_id omitted when trust is off; CodeApiJwtError → 401; configuration error → 500. - End-to-end downgrade test: bad JWT 401s and the inner app is NEVER reached with the same Bearer treated as an api-key. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(api): trust JWT.sub over User-Id header in exec + upload When SecurityMiddleware verified a CodeAPI JWT, request.state.user_id is set to the JWT's `sub` claim — cryptographically authenticated. Both /exec and /upload now use a 3-tier resolution chain: 1. JWT.sub (request.state.user_id) — wins over everything else. 2. ExecRequest.user_id body field — direct-API integration. 3. User-Id / X-User-Id HTTP header — LibreChat 0.8.5 convention. The JWT override is the security-critical bit: without it, an attacker holding a valid JWT for user-A could pass user_id=victim in the body (or User-Id: victim in headers) and the orchestrator's cross-user-isolation guard would happily route them into the victim's sessions. The signed JWT is the source of truth. upload_file and upload_files_batch gain a `request: Request` parameter to access scope state; existing tests had to be updated to inject an anonymous mock_http_request fixture (resolution falls through to headers exactly as before). 3 new tests in test_api_exec.py pin the JWT precedence: - JWT.sub overrides body user_id (attacker submits user_id=victim) - JWT.sub overrides User-Id header (same threat via header) - (existing tests cover header-fallback when JWT absent) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: document AUTH_ENABLED and CODEAPI_JWT_* env vars - .env.example: stub-out the new auth toggles (commented; off by default) with one-line rationale each. - docs/CONFIGURATION.md: full Authentication section update including the auth source priority order, a new CodeAPI JWT Authentication subsection covering the LC 0.8.5 integration (env-var-by-env-var mapping to LC's signer side), the trust model (JWT.sub overrides body/header user_id), and key rotation guidance. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: fmt * feat(docker): bake every supported language into the bash image LibreChat @librechat/agents >= 3.1.74 collapsed `execute_code` and all per-language code-interpreter tools into a single `bash_tool`. The LC client no longer sends `lang: py | js | go | ...` — every code-interpreter call now arrives as `lang: bash`, and the model is expected to shell out to `python3 -c "..."`, `node -e "..."`, `go run`, etc. from inside the shell. Before this change, those calls would fail in the bash sandbox because the interpreters / compilers weren't installed. Bakes all 13 supported language runtimes into docker/bash.Dockerfile: bash, sh — bash + coreutils + jq python (+ data stack) — python3 + python-is-python3 + numpy / pandas / matplotlib / openpyxl / Pillow javascript, typescript — nodejs + npm + typescript (global) go — golang-go java — default-jdk-headless (OpenJDK 21) c, cpp — gcc, g++ php — php-cli rust — rustc, cargo r — r-base-core fortran — gfortran d — ldc (compiler) + gcc (linker) Final image is ~865 MB vs ~100 MB for the bash-only image — the trade made deliberately so the bash pod can serve every LC request rather than erroring on a missing interpreter. ENTRYPOINT pins HOME=/tmp and per-toolchain cache dirs (GOCACHE, GOPATH, CARGO_HOME, RUSTUP_HOME, JAVA_TOOL_OPTIONS=-Duser.home=/tmp, MPLCONFIGDIR) so compilers don't try to write build artefacts into the read-only sandbox home or the user-code /mnt/data dir. The dedicated per-language images (python, nodejs, go, etc.) still ship and are still served by `/exec` when callers send an explicit `lang: <code>`. Only the LC client path changed. Validation: scripts/test-bash-megaimage.sh runs the runner's exact compile-and-run command (from docker/runner/executor.go LangSpec.Args) for each of the 13 languages, asserts stdout contains "Hello, World!", and reports pass/fail per language. All 13 pass on first run against the locally-built image. Side effect: the new BASE_IMAGE build arg lets CI / local builds swap dhi.io/debian-base for debian:trixie-slim without editing the Dockerfile. Production default unchanged. Drive-by: removed an internal-fork reference from a code comment in src/services/orchestrator.py — the algorithm is documented inline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: Mint CodeAPI auth tokens * style: Format CodeAPI download route * fix: Prune CodeAPI token cache * fix: Propagate CodeAPI managed auth * test: Mock CodeAPI auth in traversal suite * fix: Pass auth context to invoked skill cache * feat: Mint CodeAPI plan context * chore: Refresh CodeAPI auth guidance * fix: Guard OpenID JWT fallback * fix: Default CodeAPI JWT tenant in single-tenant mode * chore: Update @librechat/agents to version 3.1.84 in package-lock.json and package.json files * chore: Standardize references to Code API in comments and tests
Summary
I implemented LibreChat-side CodeAPI JWT minting for AI-905 so managed CodeAPI calls receive a short-lived bearer token from canonical request context.
Change Type
Testing
npx jest --runTestsByPath src/auth/codeapi.spec.ts --runInBand --coverage=false --watch=falsefrompackages/api.npm run build:apifrompackages/api; the build completed and emitted existing package-only workspace warnings.Test Configuration:
Checklist