feat(plugins): Ruby language support (Rails-aware) + parser recursion hardening (v0.4.0) #2

Merged
buildagent merged 1 commit from feat/ruby-language into master 2026-06-04 15:30:45 +02:00
Member

Adds a sixth indexed language — Ruby — and closes a stack-overflow DoS that affected every language plugin. Reviewed ultradeep by a multi-agent pass (correctness/security/perf/test-coverage/parity/production) with adversarial verification; all confirmed findings addressed.

Ruby plugin (crates/plugins/src/ruby.rs)

  • Detects .rb / .rake / .gemspec and the extensionless Rakefile / Gemfile.
  • Modules, classes (+ superclass TYPE refs), instance & singleton methods, top-level functions, constants (incl. parallel A, B = …), attr_* fields (symbol & string forms), require/require_relative imports, bare-call vs receiver method_call refs, mixin include/extend/prepend refs.
  • Rails-aware: has_many/has_one/belongs_to/has_and_belongs_to_many → TYPE ref to the model class, honoring class_name: (string/symbol value; colon- and hashrocket-key forms; dynamic values suppress inference) and singularizing plurals via a corrected inflector + irregular table (people→Person, sizes→Size, houses→House, …).

Security: parser recursion-depth guard (common::MAX_PARSE_DEPTH)

A crafted ~400 KB file of deeply nested literals (under the 2 MiB cap) parses to an AST deep enough to overflow the worker stack and SIGABRT the daemon — and catch_unwind can't intercept stack exhaustion, defeating the plugin sandbox. All six plugins' walk, Ruby's constant-chain recursion, and Rust's macro-token-tree recursion now bail past the cap. Confirmed by a 2 MiB-stack regression test on 20 000-deep input.

Parity wiring

qualified_name_separator (::), project-root markers (Gemfile/*.gemspec), entry-point basenames (main.rb/config.ru/Rakefile), ctags ground-truth mapping, init template + extension allowlist, README (six languages + Rails note + matrix row). gap_fill polyglot/empty-file tests now cover Ruby.

Tests

25 Ruby unit tests; e2e (e2e_ruby_project, find_references on class type, Rails association incl. belongs_to singular path, method-vs-bare-call parity, qualified_name, resolution schema); correctness_ruby 5-layer cross-validation; project-root marker tests. Full workspace suite green.

Pre-existing, unrelated: path_display::strip_verbatim_path_preserves_components asserts Windows path semantics and fails on Linux — fails identically on the released v0.3.2 tag; untouched here.

Bumps workspace to 0.4.0 (new indexed language → minor).

🤖 Generated with Claude Code

Adds a sixth indexed language — **Ruby** — and closes a stack-overflow DoS that affected **every** language plugin. Reviewed ultradeep by a multi-agent pass (correctness/security/perf/test-coverage/parity/production) with adversarial verification; all confirmed findings addressed. ## Ruby plugin (`crates/plugins/src/ruby.rs`) - Detects `.rb` / `.rake` / `.gemspec` and the extensionless `Rakefile` / `Gemfile`. - Modules, classes (+ superclass TYPE refs), instance & singleton methods, top-level functions, constants (incl. parallel `A, B = …`), `attr_*` fields (symbol & string forms), `require`/`require_relative` imports, bare-call vs receiver `method_call` refs, mixin `include`/`extend`/`prepend` refs. - **Rails-aware:** `has_many`/`has_one`/`belongs_to`/`has_and_belongs_to_many` → TYPE ref to the model class, honoring `class_name:` (string/symbol value; colon- and hashrocket-key forms; dynamic values suppress inference) and singularizing plurals via a corrected inflector + irregular table (`people→Person`, `sizes→Size`, `houses→House`, …). ## Security: parser recursion-depth guard (`common::MAX_PARSE_DEPTH`) A crafted ~400 KB file of deeply nested literals (under the 2 MiB cap) parses to an AST deep enough to overflow the worker stack and SIGABRT the daemon — and `catch_unwind` can't intercept stack exhaustion, defeating the plugin sandbox. **All six plugins'** `walk`, Ruby's constant-chain recursion, and Rust's macro-token-tree recursion now bail past the cap. Confirmed by a 2 MiB-stack regression test on 20 000-deep input. ## Parity wiring `qualified_name_separator` (`::`), project-root markers (`Gemfile`/`*.gemspec`), entry-point basenames (`main.rb`/`config.ru`/`Rakefile`), ctags ground-truth mapping, init template + extension allowlist, README (six languages + Rails note + matrix row). `gap_fill` polyglot/empty-file tests now cover Ruby. ## Tests 25 Ruby unit tests; e2e (`e2e_ruby_project`, find_references on class type, Rails association incl. `belongs_to` singular path, method-vs-bare-call parity, `qualified_name`, resolution schema); `correctness_ruby` 5-layer cross-validation; project-root marker tests. Full workspace suite green. > Pre-existing, unrelated: `path_display::strip_verbatim_path_preserves_components` asserts Windows path semantics and fails on Linux — fails identically on the released v0.3.2 tag; untouched here. Bumps workspace to **0.4.0** (new indexed language → minor). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(plugins): Ruby language support (Rails-aware) + parser recursion hardening
Some checks failed
CI / cargo fmt (pull_request) Failing after 18s
CI / cargo clippy (pull_request) Has been skipped
CI / cargo test (pull_request) Has been skipped
CI / cargo fmt (push) Failing after 18s
CI / cargo clippy (push) Has been skipped
CI / cargo test (push) Has been skipped
Release Build / Generate Version (push) Successful in 21s
Release Build / Build linux-x86_64 (push) Successful in 5m9s
Release Build / Build linux-aarch64 (push) Successful in 5m32s
Release Build / Build windows-x86_64 (push) Successful in 5m40s
Release Build / Create Forgejo Release (push) Failing after 1m3s
8b245d1a48
Adds a sixth indexed language, Ruby, and closes a class of
stack-overflow DoS across every language plugin.

Ruby plugin (crates/plugins/src/ruby.rs):
- Detects .rb / .rake / .gemspec and the extensionless Rakefile / Gemfile.
- Extracts modules, classes (+ superclass TYPE refs), instance &
  singleton methods, top-level functions, constants (incl. parallel
  `A, B = ...`), attr_accessor/reader/writer fields (symbol & string
  forms), require/require_relative imports, bare-call vs receiver
  method_call refs, and mixin include/extend/prepend module refs.
- Rails-aware: has_many/has_one/belongs_to/has_and_belongs_to_many emit
  a TYPE ref to the associated model class, honoring `class_name:`
  (string/symbol value, colon- and hashrocket-key forms; dynamic values
  suppress inference) and singularizing plural names via a corrected
  inflector + irregular-plural table (people→Person, sizes→Size, …).

Wiring/parity: registered in all_plugins; qualified_name_separator
("::"); project-root markers (Gemfile / *.gemspec); entry-point
basenames (main.rb / config.ru / Rakefile); ctags ground-truth mapping;
init template + ground-truth extension allowlist; README (six languages
+ Rails note + matrix row). Cross-language gap_fill (polyglot, empty
file) now covers Ruby.

Security — parser recursion-depth guard (common::MAX_PARSE_DEPTH=512):
A crafted ~400 KB file of deeply nested literals (well under the 2 MiB
cap) parses to an AST deep enough to overflow the worker stack and
SIGABRT the daemon — and catch_unwind cannot intercept stack
exhaustion, defeating the plugin sandbox. Every plugin's walk (rust,
python, typescript, csharp, php, ruby), Ruby's constant-chain recursion,
and Rust's macro-token-tree recursion now bail past the depth cap.
Confirmed via a 2 MiB-stack regression test on 20000-deep input.

Tests: 25 Ruby unit tests; e2e (e2e_ruby_project, find_references on
class type, Rails association incl. belongs_to singular path,
method-vs-bare-call parity, qualified_name, resolution schema);
correctness_ruby 5-layer cross-validation; project-root marker tests.
Full workspace suite green (pre-existing Windows-only path_display test
excepted — fails identically on v0.3.2, unrelated).

Bumps workspace to 0.4.0 (new indexed language → minor).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
buildagent deleted branch feat/ruby-language 2026-06-04 15:30:45 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
h-dv/code-index!2
No description provided.