feat(ruby-sdk): remove omitted basic auth fields from SDK API, use empty string internally#14411
feat(ruby-sdk): remove omitted basic auth fields from SDK API, use empty string internally#14411Swimburger wants to merge 4 commits intomainfrom
Conversation
… configured in IR Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 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:
|
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.
| omitted entirely. | ||
| type: feat | ||
| createdAt: "2026-03-31" | ||
| irVersion: 61 |
There was a problem hiding this comment.
🔴 irVersion not bumped to v63 — usernameOmit/passwordOmit fields are stripped before reaching the generator
The entire feature is non-functional because versions.yml declares irVersion: 61, but usernameOmit and passwordOmit were introduced in IR v63. When the CLI runs this generator, it migrates the latest IR down to v61, and the v63-to-v62 migration (packages/cli/generation/ir-migrations/src/migrations/v63-to-v62/migrateFromV63ToV62.ts:140-147) explicitly strips these fields from the BasicAuthScheme. As a result, the as unknown as Record<string, unknown> cast at RootClientGenerator.ts:126-128 will always see undefined for both usernameOmit and passwordOmit, so the omit logic never activates.
The generated seed output at seed/ruby-sdk-v2/basic-auth-optional/lib/seed/client.rb:10 confirms the bug: the constructor still requires both username: and password: as parameters, even though the test definition (test-definitions/fern/apis/basic-auth-optional/definition/api.yml:10) sets omit: true on password. The irVersion must be bumped to at least 63 in both versions.yml and seed.yml.
Per REVIEW.md: "IR version bumps must be coordinated: update irVersion in the relevant versions.yml entry."
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
The IR version mismatch (v61 vs v63) is a known limitation and out of scope for this PR per discussion with the maintainer. The generator code is forward-compatible and will activate once the IR version is bumped in a separate PR.
…instead of coarse eitherOmitted flag Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…uctor params Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…, use empty string internally Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
| const scheme = basicAuthScheme as unknown as Record<string, unknown>; | ||
| const usernameOmitted = scheme.usernameOmit === true; | ||
| const passwordOmitted = scheme.passwordOmit === true; |
There was a problem hiding this comment.
🟡 Unnecessary unsafe cast bypasses type-safe access to usernameOmit/passwordOmit
The code casts basicAuthScheme to Record<string, unknown> via as unknown as Record<string, unknown> to access usernameOmit/passwordOmit, but FernIr.BasicAuthScheme already defines these as boolean | undefined (packages/ir-sdk/src/sdk/api/resources/auth/types/BasicAuthScheme.ts:10,15). The same pattern is repeated in getAuthenticationParameters() at line 364. Using scheme.usernameOmit and scheme.passwordOmit directly would provide type safety and make it obvious that these fields are part of the IR type — which would have surfaced the irVersion mismatch as a design concern earlier.
| const scheme = basicAuthScheme as unknown as Record<string, unknown>; | |
| const usernameOmitted = scheme.usernameOmit === true; | |
| const passwordOmitted = scheme.passwordOmit === true; | |
| const usernameOmitted = basicAuthScheme.usernameOmit === true; | |
| const passwordOmitted = basicAuthScheme.passwordOmit === true; |
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Good catch — the Ruby generator imports BasicAuthScheme from @fern-fern/ir-sdk v61 which doesn't have usernameOmit/passwordOmit in its type definitions, so basicAuthScheme.usernameOmit would be a type error at compile time. The as unknown as Record<string, unknown> cast is necessary for this IR version. Once the IR version is bumped to v63+, this cast can be replaced with direct access.
Description
Refs #14378
Split from #14378 (one PR per generator).
When
usernameOmitorpasswordOmitflags are set in the IR'sBasicAuthScheme, the generated Ruby SDK now completely removes the omitted field from the constructor parameters (rather than making it optional/nilable). Internally, the omitted field is treated as an empty string when encoding theAuthorizationheader. Default behavior (both fields required) is preserved when no omit flags are set.Changes Made
RootClientGenerator.ts—getAuthenticationParameters(): Per-field omit checks viaas unknown as Record<string, unknown>cast. WhenusernameOmit/passwordOmitis true, the corresponding keyword parameter is excluded entirely from the generated constructor.RootClientGenerator.ts—getInitializeMethod(): Per-field condition and encoding logic:""directly inBase64.strict_encode64(no|| ""fallback needed since the field doesn't exist)passwordOmit: true→ condition is!username.nil?only)truecondition (header always set with":"encoded)versions.yml: New 1.1.12 entrybasic-auth-optionaltest fixture withpassword: omit: true, plus full seed output atseed/ruby-sdk-v2/basic-auth-optional/Testing
basic-auth-optionalfixtureusernameOmit/passwordOmitin its type definitions. Theas unknown as Record<string, unknown>cast reads these fields at runtime but has zero compile-time safety. Until the Ruby generator's IR version is bumped to v63+, these flags will always beundefinedat runtime, meaning the seed output still shows both fields present. The generator code is correct and forward-compatible — it will activate once the IR version is bumped separately.eitherOmitted: Previous revision used a coarseeitherOmittedflag that made both fields optional when either had the omit flag. This has been replaced with independent per-field checks — only the specifically flagged field is removed.usernameOmitandpasswordOmitare true, the condition becomestrueand the header is always set withBase64(":"). This is intentional per the spec ("internally use empty string").Link to Devin session: https://app.devin.ai/sessions/0786b963284f4799acb409d5373cde0a
Requested by: @Swimburger