Skip to content

release: stage → main (VS Code release 2026-05-22)#971

Merged
kwit75 merged 243 commits into
mainfrom
stage
May 22, 2026
Merged

release: stage → main (VS Code release 2026-05-22)#971
kwit75 merged 243 commits into
mainfrom
stage

Conversation

@kwit75

@kwit75 kwit75 commented May 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

VS Code release per Rod's noon-PT ask in EU/US Dev sync today. Merges current stage HEAD into main, which fires release.yaml automatically (init → build → release → docker).

Stage HEAD

3e98006d fix(ocr): support img2table 2.0 OCRInstance API rewrite (#969) (#970)

Highlights of what ships

Sign-off

Team responses gathered in EU/US Dev sync today:

Cutting per Rod's noon-PT call with 6/7 explicit thumbs.

nihalnihalani and others added 30 commits March 30, 2026 13:58
…RCE) (#342)

* docs: add project rules for claude code

* fix(security): add module whitelist to prevent arbitrary code injection via /use endpoint

The /use endpoint accepts a module name from the HTTP query string and
passes it directly to importlib.import_module() with only lowercase/strip
normalization. This allows an attacker to load arbitrary Python modules
by sending crafted requests, potentially achieving remote code execution.

Add an ALLOWED_MODULES frozenset whitelist that restricts dynamic imports
to the 10 known service modules (chat, clients, data, dropper, pipe,
profiler, remote, services, task, task_http). Requests for any other
module name now raise ValueError, returning a 400 response.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add language identifier to markdown code fence

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(security): require authentication for profiler endpoints

All 5 profiler endpoints (/profile, /profile/start, /profile/stop,
/profile/status, /profile/report) were registered with public=True,
bypassing the AuthMiddleware entirely. This allows unauthenticated
users to start/stop profiling and read performance reports that expose
internal function names, call counts, and timing data.

Remove public=True from all profiler route registrations so they
require authentication like other protected endpoints.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: correct HTTP method in profiler docs (PUT → POST)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: remove claude.md from version control

This file is project-specific AI tooling configuration and should not
be tracked in git. Added to .gitignore instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test(security): add tests for ALLOWED_MODULES allowlist validation

Verify that:
- ALLOWED_MODULES is an immutable frozenset with the expected 10 entries
- use() rejects non-allowlisted modules and path traversal attempts
- use() accepts valid modules and calls initModule correctly
- use() normalizes module names (lower + strip)
- use() skips already-loaded modules without re-importing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(security): address CodeRabbit review feedback on test_server.py

- Fix S104: change stub host from 0.0.0.0 to 127.0.0.1
- Add return type annotation to _make_server() -> WebServer
- Track injected sys.modules mocks and clean up in teardown_module()
- Assert cached module's initModule is not re-called in reload test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: minor changes

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: stepmik <stepmikhaylov@yandex.ru>
…tore (#355)

* fix(security): prevent filter expression injection in Milvus vector store

Add _escape_milvus_str() helper to sanitize user-controlled values
before interpolation into Milvus filter expressions. Escapes single
quotes and backslashes to prevent filter injection attacks across all
query construction points in the Milvus store implementation.

* fix: address review feedback on Milvus filter injection PR

- Remove unnecessary tuple wrappers on append calls
- Fix isTable filter using wrong field (docFilter.nodeId -> docFilter.isTable)
- Use unquoted boolean for isTable filter (matches isDeleted pattern)
- Add type annotation and docstring to _escape_milvus_str

* fix: move test to nodes/test/ per project conventions
* fix(security): use secure temporary file creation in task engine

Replace insecure predictable temp file path with tempfile.mkstemp()
to prevent information disclosure and symlink attacks.

_write_task_file previously wrote pipeline config (which may contain
API keys and resolved env vars) to /tmp/<task-id>.json with default
0644 permissions. This was vulnerable to:
- World-readable files exposing sensitive pipeline configuration
- Symlink attacks due to predictable path based on task ID
- TOCTOU races from lack of O_EXCL exclusive creation

mkstemp() creates the file atomically with O_EXCL, uses a random
suffix making the path unpredictable, and defaults to 0600 permissions
(owner read/write only).

Uses await asyncio.to_thread(os.write, ...) for async compatibility.
Tests use asyncio.run() instead of deprecated get_event_loop().

* fix: address CodeRabbit findings on temp file PR

- Use os.fdopen + f.write instead of os.write to prevent partial writes
- Remove unused tempfile import in tests
- Add @skipIf(os.name == 'nt') on POSIX-specific tests

* chore: minor changes

---------

Co-authored-by: stepmik <stepmikhaylov@yandex.ru>
…pe HTML output (#362)

* fix(security): require authentication for profiler endpoints and escape HTML output

Remove public=True from all 5 profiler routes so they require authentication
via AuthMiddleware, and HTML-escape the profile report output to prevent XSS.

* fix: improve profiler XSS tests to verify actual endpoint output

* fix: revert conftest.py changes, scope mocks to test file

Remove depends and rocketride mocks from conftest.py (they break
other tests per asclearuc). Move stubs into the profiler test file
where they're needed, scoped locally.
Co-authored-by: Dmitrii Karataev <dmitriikarataev@Dmitriis-MacBook-Pro.local>
* fix(client-ts): correct ConnectErrorCallback type signature

The callback type expected (message: string) => Promise<void> but
the implementation passes Error objects and callers may return void
instead of Promise<void>. Updated to accept Error | string and
return void | Promise<void>.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(client-ts): use ConnectionException in ConnectErrorCallback type

Address maintainer feedback:
- Replace Error | string with ConnectionException from exceptions module
- Pass ConnectionException object directly to callback instead of extracting message string
- Keep void | Promise<void> return type as approved
- Fix invocation site in client.ts to construct ConnectionException when needed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(apps): migrate onConnectError handlers to accept ConnectionException

Update three call sites to match the new ConnectErrorCallback type
signature that accepts ConnectionException instead of a plain string.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(client-ts): revert formatting changes

---------

Co-authored-by: NIHAL NIHALANI <nihal.nihalani@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: stepmik <stepmikhaylov@yandex.ru>
…odes (#531)

All LLM node IGlobal classes assigned the Chat instance to `self._chat`
in `beginGlobal`, but `endGlobal` cleared `self.chat` (no underscore) —
a different attribute that was never set. This meant `endGlobal` was a
no-op: the Chat object was never explicitly released when a pipeline
stopped.

Fixed in 12 nodes: llm_anthropic, llm_bedrock, llm_deepseek, llm_gemini,
llm_ibm_watson, llm_mistral, llm_ollama, llm_openai, llm_perplexity,
llm_qwen, llm_vertex, llm_xai.

llm_vision_ollama and llm_vision_mistral were already correct.
Adds a new LLM node for GMI Cloud (api.gmi-serving.com), an OpenAI-compatible
inference platform hosting 100+ models including DeepSeek, GPT, Claude, Gemini,
Llama 4, and Qwen3 on owned H100/H200 GPU infrastructure.

## Profiles

Two model tiers are supported:

Shared (always-on) — API key only required:
DeepSeek V3.2, V3, R1, R1 Distill 32B & 1.5B, Prover V2
GPT-5.2, 5.1, 5, 4o
Claude Opus 4.5, Sonnet 4.5
Gemini 3 Pro, Gemini 3 Flash

Deploy-on-demand — endpoint URL + API key required (deploy first at
console.gmicloud.ai, then paste the provided endpoint URL):
Llama 4 Scout, Llama 4 Maverick
Qwen3 235B, 32B, 30B, Coder 480B

A custom profile allows specifying any model name and endpoint URL manually.
…580)

Replace fragile str().startswith() path traversal checks with
Path.is_relative_to() in chat and dropper modules. The string prefix
comparison could be bypassed with crafted paths like /app/static/chat-evil/.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…proach (#577)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ogger (#578)

The redactSensitiveFields function only checked for auth-key, token-key,
and apikey patterns. This missed commonly used sensitive fields like
password, secret, authorization, bearer, credential, access_token,
refresh_token, and private_key, which could be logged unredacted.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Establish baseline community guidelines for inclusive collaboration.
Intentionally kept lightweight to be expanded over time.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…nfigs (#359)

* fix(security): restrict environment variable expansion in pipeline configs

Add an allowlist of permitted env var prefixes (ROCKETRIDE_, PIPELINE_,
NODE_, ROCKET_) to _resolve_pipeline(). All other ${VAR} references are
replaced with <REDACTED> to prevent exfiltration of sensitive environment
variables (AWS keys, DB URLs, tokens) via pipeline configuration.

* chore(ai): allow ROCKETRIDE_ prefixed variables

* chore(ai): check json injection

---------

Co-authored-by: stepmik <stepmikhaylov@yandex.ru>
The URL API silently strips ports that are default-for-scheme (e.g. :443
on https), so url.port is empty for both "no port given" and
"scheme-default port given". This caused normalizeUri to always overwrite
with the default 5565 port, breaking connections through ngrok/Cloudflare
tunnels and custom reverse proxies.

Check the raw input string for an explicit port pattern before deciding
whether to apply the default port.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…#504)

* deprecation pathway

* coderabbit suggestions

* add tests

* cr

* fix build

* fix build

* Update conftest.py

* Update conftest.py

* Update conftest.py

* Update conftest.py

* simplify

* simplify
* add latest openai model profiles

* coderabbit fixes

* fix typo (we didn't introduce)

* don't change default

* Update services.json

* Update services.json
* remove gemini 3 pro (deprecated), gemini 2

* code rabbit response

* coderabbit

* Update services.json

* Update services.json
…TOWER HACKATHON] (#386)

* Add Exa search node and stable pipeline

* Harden Exa search node runtime handling

* Fix Exa fallback question parsing

* Fix Exa mock credential test wiring

* Assert Exa mock request contract

* Tighten Exa API exception types

* Document Exa node lifecycle hooks

* Handle unsafe Exa result URLs per item

* Clean up Exa backend from endpoint bag

* Unpin Exa node requests dependency

* Add comments to Exa service definition

* Add Exa search docstrings

* Parse Exa boolean config defensively

* Guard Exa error payload parsing

* revert: remove Exa node test changes

* revert: restore base test framework behavior

* chore: drop test framework whitespace diff

---------

Co-authored-by: Kaushik Sivakumar <kaushik.siva88@gmail.com>
* feat(vscode): improve stop button feedback in Pipeline Observability screen

Handle TASK_STATE.STOPPING in the control button to show "Stopping..."
with a disabled state and distinct orange styling, preventing duplicate
clicks and giving immediate visual feedback during pipeline shutdown.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(vscode): register canvas-played pipelines in sidebar menu

The PIPELINES sidebar failed to track pipelines started from the canvas
because source-component detection relied solely on config.mode being
set to "Source". The canvas editor never writes that field — only the
C++ engine adds it at execution time — so freshly saved .pipe files
from the canvas had zero recognised source components.

Three changes fix the issue:

1. PipelineFileParser.getSourceComponents now accepts an optional
   service catalog and also checks each component's provider classType
   array for "source", matching the same logic the canvas uses to
   decide which nodes get a Run button.

2. SidebarFilesProvider passes the cached service catalog to the parser
   when loading/re-parsing files, and re-parses all files when the
   catalog first arrives (servicesUpdated) so that files parsed before
   connect are retroactively enriched.

3. handleEvent now handles the "restart" apaevt_task action, which the
   server sends instead of "begin" when a pipeline is restarted. Without
   this, restarted pipelines silently dropped out of the active set.

Closes #396

#Hack-with-bay-2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tests (#561)

The stress test (4 pipelines x 32 cycles) used a 30s hard-coded timeout
that was too tight for CI runners, causing both Jest timeout errors and
"Connection closed" failures under load. Several other concurrent tests
had the same issue. Test teardown could also hang indefinitely if a
WebSocket connection failed to close cleanly.

Root causes addressed:
- Hard-coded 30s timeouts on concurrent tests replaced with
  TEST_CONFIG.timeout (120s) matching the rest of the suite
- Added single-retry with backoff in the stress test to handle transient
  "Connection closed" errors from server-side frame drops under load
- Added bounded timeouts to all afterEach teardown blocks so cleanup
  never hangs the runner
- Added forceExit to jest.config.js so Jest exits even with leaked handles
- Added pytest-timeout (120s default) in pyproject.toml to prevent
  individual Python tests from hanging indefinitely
- Removed deprecated event_loop fixture from conftest.py (replaced by
  pytest-asyncio auto mode)
- Added asyncio_mode = "auto" to pyproject.toml for consistent async
  test handling

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…urrent state (#575)

- Rename idle label from "Play" to "Run Pipeline" for clearer intent
- Add STOPPING state with "Stopping..." disabled button to prevent
  double-clicks and provide immediate visual feedback during shutdown
- Widen hover expansion to accommodate longer label text
- Smooth CSS transitions with easing functions for polished UX

Closes #398

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
anandray and others added 14 commits May 20, 2026 14:45
Top-level `permissions: { contents: write, packages: write, id-token: write }`
on nightly.yaml granted every job in the workflow the union of all writes
any one job needed, including jobs that only consume read-only inputs. The
Scorecard `TokenPermissionsID` rule flags this as the most severe form of
over-grant because top-level writes propagate to every reuse-called
workflow as the upper bound.

Drop the top-level to `contents: read` and raise per-job only where the
job actually writes:

  - build:               contents: read, packages: write
                         (forwarded to _build.yaml for NuGet/vcpkg writes
                          to ghcr.io via VCPKG_BINARY_SOURCES=...readwrite)

  - cleanup-prereleases: contents: write
                         (git push origin --delete <tag> and gh release
                          delete; the tag deletion requires repo write)

  - prerelease:          contents: write, id-token: write
                         (forwarded to _release.yaml for tag push +
                          gh release create + Sigstore keyless signing)

  - docker:              contents: read, packages: write
                         (forwarded to _docker.yaml for ghcr image push;
                          matches release.yaml's docker job pattern)

  - init:                no override, inherits top-level read
                         (_init.yaml is read-only — extracts versions
                          from package.json via jq and stamps github.sha)

The grants mirror the canonical pattern already in place in release.yaml
(committed in the prior TokenPermissionsID cleanup pass that closed #513
and #515 on _build.yaml and _init.yaml).

Closes Scorecard TokenPermissionsID alerts #566 (topLevel contents:write)
and #567 (topLevel packages:write).

The remaining 10 TokenPermissionsID alerts on this repo (#451, #452, #454,
#455, #489, #490, #604, #635, #649, #650) flag job-level writes that are
required for the job's function (ghcr image push, GitHub release publish,
artifact cleanup, model-sync commits). Those are being dismissed
separately with "won't fix" + per-alert justification — Scorecard
penalizes any write, including the unavoidable kind.
…933)

Closes the 9 mechanically-fixable Scorecard `PinnedDependenciesID`
alerts on this repo. Mutable tag references (`@v4`, `:tag`) become
immutable hash references; Dependabot will continue to bump the SHAs
as new versions ship.

GitHub Actions (7 alerts):

  sync-models.yml
    actions/checkout              v4 → 34e1148... #599
    actions/setup-python          v5 → a26af69... #600
    actions/cache                 v4 → 0057852... #601
    peter-evans/create-pull-req.  v7 → 22a9089... #602

  discord-discussions.yml
    actions/checkout              v4 → 34e1148... #644
  discord-issues.yml
    actions/checkout              v4 → 34e1148... #645
  discord-pr.yml
    actions/checkout              v4 → 34e1148... #646

Docker base images (2 alerts):

  docker/Dockerfile.engine
    ubuntu:jammy-20240808
    → @sha256:adbb90115a21969d2fe6fa7f9af4253e16d45f8d4c1e930182610c4731962658   #561

  docker/Dockerfile.mcp
    python:3.12-slim
    → @sha256:9d3abd9fc11d06998ccdbdd93b4dd49b5ad7d67fcbbc11c016eb0eb2c2194891   #471

Both digests are the OCI image index (multi-platform manifest list),
so platform resolution still happens at build time. `jammy-20240808`
is already a date-pinned snapshot tag; `3.12-slim` is a floating
upstream tag and was pinned at the digest current as of 2026-05-20.

The remaining 6 `PinnedDependenciesID` alerts (#465, #466, #467, #468,
#472, #603) flag pip/npm install commands with already-exact version
pins (`twine==6.1.0`, `@vscode/vsce@3.7.1`, `ovsx@0.10.9`, etc.).
Scorecard wants `pip install --require-hashes` or lockfile-driven
installs for these; the ergonomics of doing that for one-shot
workflow installs (and for the `./client-python` local-path install
in Dockerfile.mcp, which can't be hash-pinned at all) outweigh the
incremental supply-chain hardening over an already-exact version
constraint. Those alerts are being dismissed separately with
"won't fix" + per-alert justification.
…934)

Closes 3 Dependabot alerts on the python backend's transitive cryptography
dependency. The two per-node files that pull cryptography directly
(db_mysql/requirements.txt, text_output/requirements.txt) are already
at cryptography==46.0.7, but the baseline file at nodes/src/nodes/
requirements.txt — which Dependabot scans against — left cryptography
unmentioned, so the transitive version resolution was unpinned and
fell to whatever requests/urllib3/httpx pulled in.

Pinning the baseline closes:

  GHSA-r6ph-v2qm-q3c2 (high)   #64
    Vulnerable to a Subgroup Attack Due to Missing Subgroup Validation
    for SECT Curves. Fix: 46.0.5.

  GHSA-m959-cc7f-wv43 (low)    #65
    Incomplete DNS name constraint enforcement on peer names.
    Fix: 46.0.6.

  GHSA-p423-j2cm-9vmq (medium) #66
    Buffer overflow if non-contiguous buffers were passed to APIs.
    Fix: 46.0.7.

Bounded range (>=46.0.7,<47) matches the repo convention for
security-driven dependency floors (handlebars: ">=4.7.9 <5";
protobufjs: ">=7.5.5 <8"; the npm overrides set on root package.json).
Closes Dependabot alert #164 (GHSA-58qx-3vcg-4xpx, medium) — ws is
vulnerable to uninitialized memory disclosure on a crafted Sec-
WebSocket-Protocol header that overflows the parsing buffer. Affects
all 8.x lines below 8.20.1.

  ws  → >=8.20.1 <9   was 8.18.0 + 8.20.1 co-existing in the tree;
                      forces the 8.18.0 caller chain to 8.20.1+

Post-install resolves to ws@8.20.1 only — the 8.18.0 instance is gone.

ws has no direct entry in any package.json on this repo; it's pulled
transitively (typical sources: socket.io adapters, dev-server stacks,
websocket utilities in @rspack/core / vite plugin chains). The
override approach matches how we handled the previous transitive
overrides cluster (#914, #915, #916, #917).

Bounded range (>=fix <next-major) matches the existing repo convention.
The npm-development group bump in PR #921 broke `vsce package` on all
three Build matrix runners:

  ::error::@types/vscode ^1.120.0 greater than engines.vscode ^1.99.3.
  Consider upgrade engines.vscode or use an older @types/vscode version

vsce enforces @types/vscode ≤ engines.vscode at build time so the
shipped extension doesn't describe APIs the declared minimum VS Code
can't provide. apps/vscode/package.json's engines.vscode floor is
^1.99.3 — that floor is a product/UX choice, not something Dependabot
should ratchet up automatically through a routine group bump.

Add @types/vscode to the root npm ignores so the npm-development
group stops trying to bump it. Future @types/vscode updates land
when the team raises engines.vscode in a deliberate PR.

Matches the existing precedent for @rsbuild/*, @rslib/*, @rspack/*
(added after PR #866 tried to downgrade rsbuild across seven
workspaces because Dependabot harmonised to the older per-app pin).

Companion to the fix commit on PR #921 (dependabot/npm_and_yarn/
npm-development-a42da78f69) which pins apps/vscode/package.json's
@types/vscode to ~1.99.0 so pnpm stops floating it forward across
the 1.x line.
…938)

CodeQL js/incomplete-multi-character-sanitization (#476) flagged the
single-pass regex strip in firstSentence as leaving residual `<script`
after one substitution on inputs like `<scri<x>pt>` — the inner `<x>`
gets consumed but the outer pair re-forms a `<script>` tag.

In practice today the output of this function lands in a JSON catalog
file (.rocketride/services-catalog.json) via JSON.stringify, so any
residual HTML would be JSON-escaped before write and not rendered.
But the consumer surface may grow (the catalog could be sourced into
a webview tooltip, an LLM context window, or a markdown preview), and
loop-stripping until idempotent is cheap defense-in-depth that closes
the SAST signal at the source.

Pattern: loop the same regex until `stripped === prev`. Each pass
removes a complete `<...>` span; nested or malformed tags need at
most O(depth) passes (typically 2-3, always terminates because the
output is monotonically shorter on each non-fixed-point iteration).

Closes CodeQL alert #476.
#939)

CodeQL py/stack-trace-exposure (alerts #5 and #6) flagged the
authentication error path returning str(e) directly to the HTTP
client via HTMLResponse / PlainTextResponse. The exception text can
leak library internals — JWT verifier specifics, cryptography binding
errors, file paths in some edge cases — which is information an
attacker probing the auth endpoint can use to fingerprint the stack
and pivot.

Three call sites in _authenticate_credential_inner returned (code,
str(e)):

  - PermissionError from a registered authenticator (401)
  - Generic Exception from a registered authenticator (400)
  - Generic Exception from the built-in account fallback (400)

Now each site:
  1. Logs the actual exception via debug() — operators still see the
     full text in server logs for triage
  2. Returns a generic message to the client — "Authentication failed"
     for 401, "Bad request" for 400

The downstream _format_error helper that wraps the message into the
HTML/text/JSON response is unchanged; only the message contents
flowing into it are sanitized at the source.

The 'No authorization provided' and 'Invalid authorization provided'
branches were already generic and stay as-is.

Closes CodeQL alerts #5 and #6.
)

* fix(scripts): guard state.js dot-paths against prototype pollution

CodeQL js/prototype-pollution-utility (alert #274) flagged setState's
walk loop in scripts/lib/state.js: it splits a dot-notation key into
parts, walks them creating empty objects as needed, then assigns the
value at the leaf. Without a guard, a caller passing
setState('__proto__.polluted', 'x') would set Object.prototype.polluted
for the entire process — and updateState has the same shape.

Callers in this codebase are all in-repo build scripts (not network
input), so this is defense-in-depth rather than a live exploit. But
state.js is a shared utility used by every build/deploy script, and
guarding once at the entry of the two write paths is far cheaper than
auditing every call site.

Implementation: a single assertSafePath(parts) helper at the top of
the module, called at the entry of setState and updateState. Throws
synchronously if any path segment is one of __proto__, constructor,
prototype. The error message names the offending segment to make
debugging obvious if a legitimate caller ever stumbles into it.

deleteKeyAndPrune isn't guarded directly because it's only reachable
through setState/updateState (both now guarded). getState (read path)
is also not guarded — reads of __proto__/constructor return objects
the caller already has access to, so no pollution risk.

Closes CodeQL alert #274.

* fix(scripts): coerce path segments with String() before forbidden-key check

CodeRabbit caught an edge case in the assertSafePath guard from the
initial commit: FORBIDDEN_KEYS is a Set, and Set.has() uses identity
equality. A caller passing a String *wrapper object*
(e.g. new String('__proto__')) would fail the .has() check (different
identity from the primitive '__proto__') but still coerce to the
string '__proto__' when used as a bracket-access key — re-opening the
prototype-pollution path.

Verified locally:

  setState('__proto__.x', 1)            → throws (primitive blocked)
  setState([new String('__proto__'),
           'x'], 1)                    → BYPASS on previous commit;
                                         throws after this commit

Fix: String(rawPart) inside the loop normalizes wrappers, numbers,
and other coercible values to the same string form that property
access uses. Symbols would TypeError on String(); that's acceptable
behavior — Symbol keys never reach Object.prototype anyway, and the
TypeError surfaces the misuse synchronously.

Addresses CodeRabbit review feedback on PR #940.
…ases (#955)

PR #929 (per-job permissions scoping on nightly.yaml) missed
id-token: write on the docker job. _docker.yaml's docker job
declares:

  permissions:
    contents: read
    packages: write
    id-token: write   ← for cosign keyless Sigstore signing

GitHub validates at workflow-start that the caller's permissions
cover every permission the reusable job declares. The missing
id-token: write produced a workflow-level `startup_failure` on
every nightly run after #929 merged at 2026-05-20T21:45 — the
workflow couldn't even instantiate jobs (gh run view returns
`jobs: []`, log-not-found), and 13 consecutive runs against
develop have been failing the same way.

Mirror was modelled on release.yaml's docker job which ALSO omits
id-token: write — that's a latent bug in release.yaml too, but it
hasn't bitten because release.yaml's docker job is gated by
`if: server_tag_exists == 'false'` and only fires on fresh release
tags, so the misconfiguration only surfaces on a real release cut.
Should be fixed in a follow-up pass.

Comment in-file explains the constraint so the next person editing
this block doesn't drop it again.
Brings 24 develop commits into stage in preparation for tomorrow's VS Code
release. Highlights:

- security cleanup batch (#933, #934, #936, #937, #938, #939, #940)
- nightly workflow id-token fix (#955)
- shell injection fix in _build.yaml (#928)
- nightly per-job permission scoping (#929)
- vscode sidebar polish + env vars + autocomplete + startup fixes (#932)
- Helm chart for production deployment (#510)
- persistent cross-session memory node with Redis backend (#547)
- Cohere Rerank pipeline node (#898)
- Rsbuild upgrade + build config modernization (#905)
- engine management restructure with ioControl (#922)

Preserves 3 stage-unique commits (gdg-fixes #904, version bump,
prior develop→stage merge #907).

Follows pattern of #907.
…957)

Same latent bug as the one that broke nightly.yaml in PR #929 and was
hotfixed in #955: release.yaml's docker job omits id-token: write
even though the reusable _docker.yaml job declares it (required for
cosign keyless Sigstore signing).

Hasn't surfaced as a startup_failure because the docker job here is
gated by:

    if: needs.init.outputs.server_tag_exists == 'false'

So the docker job is only instantiated when a fresh release tag is
being created — meaning GitHub's start-time permission-coverage
validation only runs the docker job's check on a real release cut.
Every release.yaml dispatch where the tag already exists skips the
docker job entirely and the misconfiguration is invisible.

If left in place, the next fresh release (server-vX where the tag
doesn't yet exist) would fail with startup_failure the same way
nightly did. Fixing preemptively rather than waiting for the cut.

Comment in-file references the nightly outage so the next person
editing release.yaml has the breadcrumb.
* fix(builder): prevent deadlock when conditional skips a dedup branch (#925)

## Summary

- `builder test` could deadlock on `tika:submodule-build` when the source tree was already locally compiled (`serverReady=true`, `serverDownloaded=false`). The `whenNot ready` branch in `server:build-core` was pre-built with the parent's shared `seen` set, so the build-time-dedup stub referenced from `tika:submodule-test`'s pipeline waited on a completion promise whose resolver lived inside the never-executed `then`-branch.
- `buildWhenTask` now clones the `seen` set when pre-building each `when`/`whenNot` branch, so conditional-branch contents no longer pollute the parent's dedup state. If the same action is referenced both inside a conditional branch and elsewhere, both locations now build their own real subtree; runtime `completedActions` and the process-global `getOrCreateCompletion` still ensure exactly one execution.

## Type

fix

## Testing

- [ ] Tests added or updated
- [ ] Tested locally
- [ ] `./builder test` passes

Reproduction: run `builder build` once on a clean tree, then re-run `builder test` against the same unchanged tree. Before the fix this would hang at `Waiting for: tika:submodule-build`. After the fix, the test pipeline completes.

## Checklist

- [x] Commit messages follow [conventional commits](https://www.conventionalcommits.org/)
- [x] No secrets or credentials included
- [ ] Wiki updated (if applicable)
- [ ] Breaking changes documented (if applicable)

## Linked Issue

Fixes #

* fix(qdrant): correct score-space mismatch and isDeleted filter (#958)

* fix(qdrant): correct score-space mismatch and isDeleted filter

Three bugs fixed:

1. Score-space mismatch: threshold_search is a [0,1] value but was
   passed directly to Qdrant as score_threshold, which Qdrant applies
   against raw cosine scores in [-1,1]. The (score+1)/2 rescaling only
   happened afterwards in _convertToDocs, so every non-zero category
   ("Related", "Strongly Related", etc.) had an effective bar far higher
   than intended — causing zero results. Fix: inverse-transform the
   threshold before the API call for Cosine similarity.

2. Hardcoded score floor: _convertToDocs filtered score < 0.20
   regardless of user config. Replaced with self.threshold_search.

3. isDeleted filter too strict: MatchValue(False) alone excluded
   documents where the field is null or absent (e.g. documents indexed
   before soft-delete existed). Fix: nested should-filter covering
   isDeleted=False, isDeleted=null, and isDeleted missing.

Mock updated to mirror the real filter semantics (exclude only when
isDeleted is explicitly True). 11 new tests covering all three fixes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(qdrant): drop unavailable IsNull/IsEmpty filter and engine-side score_threshold

- isDeleted: replace should[MatchValue(False), IsNullCondition, IsEmptyCondition]
  with must_not[MatchValue(True)]. IsNullCondition is not available in the
  installed qdrant_client and broke CI; must_not covers False/null/absent.
- score: stop passing score_threshold to query_points (Qdrant filters it in raw
  space while threshold_search is rescaled [0,1]); the cut stays in base _addDoc.
- name the 0.20 relevance floor as MIN_RELEVANCE_SCORE.
- trim tests to honest guards (engine never receives score_threshold).

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Ariel Vernaza <ariel@lazyracoon.tech>

* fix(crewai): patch async compatibility issues for CrewAI 1.14.x hierarchical crews (#951)

Two runtime crashes when running hierarchical crews on the shared asyncio daemon
loop: (1) planning calls execute_sync() from inside the loop → RuntimeError, fixed
by offloading _handle_crew_planning to a ThreadPoolExecutor worker; (2) delegation
tools lack _arun/_aexecute async variants, fixed by patching BaseAgentTool,
DelegateWorkTool, and AskQuestionTool. Also cleans planning prompt token noise via
_CrewTool.__repr__ and delegates task description interpolation to CrewAI's native
_interpolate_inputs() mechanism.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(template): route RAG chat query through embedding before vector store

chat_1 questions were wired directly to store_1, bypassing the embedding
step. Queries must be embedded before vector similarity search so they
exist in the same space as the stored document vectors. Reuses the
existing embedding_transformer_1 node on the ingestion path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Alexandru Sclearuc <asclearuc@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Ariel Vernaza <ariel@lazyracoon.tech>
* fix(ocr): support img2table 2.0 OCRInstance API rewrite

## Summary

- img2table 2.0.0 (2026-05-10) moved `OCRInstance` out of `img2table.ocr.base` and replaced the `content` / `to_ocr_dataframe` contract with a single `of()` returning `OCRData`, breaking the OCR node with `No module named 'img2table.ocr.base'`.
- Make `ModelServerOCR` in `nodes/src/nodes/ocr/IGlobal.py` version-aware: try `img2table.ocr._types.OCRInstance` first (v2), fall back to `img2table.ocr.base.OCRInstance` (v1).
- Implement `of()` so it builds an `OCRData(records=…)` on v2 and defers to the base class on v1 (which still drives the existing `content` + `to_ocr_dataframe`); add `_format_to_v2_records` helper producing the v2 word-record dict shape.
- Add `nodes/test/ocr/test_model_server_ocr.py` covering both branches: 4 pure-helper tests, 3 v2-only `of()` tests, 1 v1-only `of()` test, 1 `content()` test on both. Loads `IGlobal.py` via `spec_from_file_location` inside a `_scoped_stubs()` context manager so `sys.modules` is snapshotted/restored — no leakage into peer tests in the same `pytest-xdist` session.

## Type

fix

## Testing

- [x] Tests added (`nodes/test/ocr/test_model_server_ocr.py` — 8 active, 1 version-skipped)
- [x] Tested locally — `./builder.cmd nodes:test --pytest-pattern=ocr --verbose` → 10 passed, 1 skipped
- [ ] `./builder test` passes

## Checklist

- [x] Commit messages follow [conventional commits](https://www.conventionalcommits.org/)
- [x] No secrets or credentials included
- [ ] Wiki updated (if applicable)
- [ ] Breaking changes documented (if applicable)

## Linked Issue

Fixes #913
@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Ignore keyword(s) in the title.

⛔ Ignored keywords (5)
  • [bot]
  • renovate
  • dependabot
  • release
  • chore(release)

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 444bbe9b-7e0a-40b5-be04-712e8db2424e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch stage

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor

No description provided.

anandray and others added 2 commits May 22, 2026 12:42
…signore (#972)

Unblocks the gitleaks check on PR #971 (release: stage to main). The
finding flagged a placeholder credential in
nodes/src/nodes/tool_exa_search/services.json at line 138 of commit
fd6b61d — the test fixture of the Exa search node (#509, 2026-04-21).

The file's inline comment two lines above the value already documents
the intent: the field is a placeholder for config-validation testing,
not a live key. The test block has since been refactored on stage to
use a cases array, so the value no longer appears in the current file.
But gitleaks scans the full main..stage commit range on PR #971 (227
commits — main hasn't moved since 2026-03-29), so the historical
commit's content is what's flagged. A later refactor doesn't clear
a historical match — only an allowlist entry does.

Fingerprint format <commit>:<path>:<rule>:<line> — gitleaks matches
this exact occurrence only, so this doesn't silence future findings.

Two known gitleaks config inconsistencies worth a follow-up (NOT
blocking this release):

  - The pipe-file-api-key rule has paths = '\.pipe(\.json)?$' which
    shouldn't match services.json, yet gitleaks attributed the
    finding to that rule.
  - The services-json-api-key rule has a 16-char minimum which an
    8-char placeholder wouldn't trigger.

Neither rule should have fired given the documented config; one of
them did. Investigate after the release lands.
- Register rocketride.sidebar.documentation.open command via vscode.env.openExternal → https://docs.rocketride.org/
- Update SF hackathon announcement title, date (June 5), and Luma link
- Remove stale RocketRide 2.4, NYC Meetup, and RAG template announcements
- Rename Community spotlight → Connect with us with updated Discord URL

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

@anandray anandray left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — composition verified, security cleanup work all lands cleanly.

Verification summary

12 security PRs from this week's cleanup batch are all in stage and composed correctly:

PR Verified in stage
#928 _build.yaml shell-injection guard commit 5181f0ed
#929 nightly.yaml per-job permissions commit 3cf1937f
#933 GHA + Docker SHA pins commit a0f305ce
#934 cryptography baseline pin cryptography>=46.0.7,<47 present in nodes/src/nodes/requirements.txt
#936 ws override "ws": ">=8.20.1 <9" in root package.json
#937 @types/vscode dependabot ignore present in .github/dependabot.yml
#938 services.ts loop-strip sanitize commit 95db6137
#939 server.py generic auth errors commit 6edbb671
#940 state.js proto-pollution guard commit 0c61de13
#955 nightly docker id-token: write verified in stage's nightly.yaml
#957 release docker id-token: write verified in stage's release.yaml

Critical: #957's release.yaml docker fix is in stage. Without it, the release.yaml dispatch this merge triggers would have hit startup_failure on the docker job (same bug that broke nightly last week). The explicit "Merge develop (pick up #957 release-docker id-token fix)" commit (14c26b66) shows the deliberate hotfix pull-forward worked.

Workflow self-check on release.yaml path

Since this PR's merge fires release.yaml, I verified the workflow itself is healthy in stage:

  • release.yaml docker job grants contents: read, packages: write, id-token: write
  • _release.yaml release job declared permissions match the caller's grant ✓
  • _docker.yaml docker job declared permissions match the caller's grant ✓

No startup_failure mode is reachable on the release publish.

Gitleaks finding — false positive, resolved via #972

The gitleaks failure on initial CI was a historical false-positive: a literal placeholder credential in the test-fixture block of nodes/src/nodes/tool_exa_search/services.json from PR #509 (Charlie's Exa search node, April 21). The file's own inline comment two lines above the value documents it as a placeholder for config-validation testing, not a live key. The string was refactored away in a later stage commit (now uses a cases array), so it only appears in the historical commit when gitleaks scans the full main..stage range.

PR #972 (merged at 19:42 UTC) added the fingerprint to .gitleaksignore to unblock this scan. CI on this PR has re-run and gitleaks now passes.

Two latent gitleaks config inconsistencies surfaced in the investigation — the pipe-file-api-key rule's paths filter doesn't appear to be applied, and the services-json-api-key rule's 16-char minimum should have suppressed the 8-char placeholder. Worth a follow-up ticket after this release lands; not blocking.

Also picked up at cut time

#975 (Ryan's sidebar docs-link wiring + announcements update, +5/-5 across 2 files) — landed on stage after the initial PR cut. Scope is VS Code UX only, no impact on the security composition above. CI re-ran on the new HEAD 98e5b498 and the Build matrix is green across all 3 platforms.

Known deferrals

  • #961 (diff jsdiff DoS override) — merged to develop after the stage cutoff. LOW severity, transitive in mocha (dev-only). Safe to defer to next stage sync, no impact on customer-facing artifacts.
  • #910 / #948 / #949 (openai/cohere/redis major bumps) — held off develop intentionally for a 24h prerelease soak before next release. Already approved, will land staggered over the next 3 days post-release.

Net

7/7 explicit team thumbs in the EU/US Dev sync + composition verified + release.yaml path proven healthy + gitleaks now clean + Build matrix green on 98e5b498. Approve.

@kwit75
kwit75 merged commit 7376d1c into main May 22, 2026
32 checks passed
@kwit75
kwit75 deleted the stage branch May 22, 2026 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

builder ci/cd CI/CD and build system docker docs Documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.