Skip to content

Conversation

@lovincyrus
Copy link
Contributor

@lovincyrus lovincyrus commented Feb 3, 2026

This PR restructures the Snowflake connector form to provide clearer authentication options and adds proper support for private key (JWT) authentication.

Checklist:

  • Covered by tests
  • Ran it and it works as intended
  • Reviewed the diff before requesting a review
  • Checked for unhandled edge cases
  • Linked the issues it closes
  • Checked if the docs need to be updated. If so, create a separate Linear DOCS issue
  • Intend to cherry-pick into the release branch
  • I'm proud of this work!

Replace tabs + radio hierarchy with a single radio selector offering three
authentication methods:
1. Username/Password - Traditional password authentication
2. Private Key (Recommended) - SNOWFLAKE_JWT with private key
3. Connection String - Full DSN for advanced users

This simplifies the form UX and emphasizes Snowflake's recommended JWT
approach. Fields are conditionally shown based on selected auth method.
- Change Snowflake privateKey field from text input to file upload for better UX
- Fix CredentialsInput validation to respect the accept prop instead of hardcoding .json
- Base64 encode PEM/P8 files in handleFileUpload for .env compatibility
- Snowflake backend already supports base64-encoded keys via parseRSAPrivateKey
@lovincyrus lovincyrus self-assigned this Feb 3, 2026
@lovincyrus lovincyrus marked this pull request as ready for review February 3, 2026 21:26
@royendo
Copy link
Contributor

royendo commented Feb 3, 2026

Screenshot 2026-02-03 at 18 20 10

dsn not clearing.

also, can we keep this as a normal tab? its weird that only snowflake has radio for connection_string
try [User/Password] [User/PrivateKey][Connection String]

royendo
royendo previously requested changes Feb 3, 2026
Copy link
Contributor

@royendo royendo left a comment

Choose a reason for hiding this comment

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

see above

Copy link
Contributor

@ericpgreen2 ericpgreen2 left a comment

Choose a reason for hiding this comment

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

1. Consolidate file upload encoding with schema definitions

The current implementation checks file extensions to decide encoding:

if (fileName.endsWith(".pem") || fileName.endsWith(".p8")) {
  return btoa(content);
}

This creates implicit coupling between x-accept in the schema and hardcoded logic in AddDataFormManager. If a future connector adds new file types to x-accept, someone must remember to update the encoding logic separately—they will likely forget.

Introduce a x-file-* namespace to make encoding declarative:

Property Purpose
x-file-accept Allowed extensions (rename from x-accept)
x-file-encoding Content encoding (base64, json, raw) — required for file fields
x-file-extract Extract values from parsed content into form fields

Snowflake schema:

privateKey: {
  "x-display": "file",
  "x-file-accept": ".pem,.p8",
  "x-file-encoding": "base64",
  "x-secret": true,
}

BigQuery schema (replaces hardcoded project_id extraction):

google_application_credentials: {
  "x-display": "file",
  "x-file-accept": ".json",
  "x-file-encoding": "json",
  "x-file-extract": { "project_id": "project_id" },
  "x-secret": true,
}

To support this, pass the field key through the component chain so handleFileUpload(file, fieldKey) can look up the schema property and use the declarative config. Create a processFileContent(content, field) utility that handles encoding based on schema.

2. btoa() can fail on non-Latin-1 characters

PEM files should be ASCII, but if a file has unexpected encoding (BOM, UTF-8 characters in comments), btoa() throws an uncaught exception. The JSON path has try/catch; the PEM path doesn't.

3. Verify field visibility when DSN is selected

The account, user, database, etc. fields have no x-visible-if condition. Confirm they're hidden when DSN is selected via x-grouped-fields rendering logic.


Developed in collaboration with Claude Code

Replace hardcoded file extension checks and connector-specific logic in
handleFileUpload() with declarative schema properties. Introduce x-file-*
namespace (x-file-accept, x-file-encoding, x-file-extract) to make file
processing declarative and schema-driven.

This eliminates implicit coupling between CredentialsInput UI and
AddDataFormManager's encoding logic. New connectors can specify file handling
purely through schema definitions without modifying manager code.

- Create processFileContent() utility to handle base64/json/raw encoding
- Add x-file-extract to support BigQuery's auto-population of project_id
- Update schemas: Snowflake (base64 for .pem/.p8), BigQuery and GCS (json)
- Pass fieldKey through component chain; wrap at SchemaField level
- Keep legacy fallback in manager for backwards compatibility
btoa() throws if the input contains characters outside the Latin-1 range.
Add try-catch to handle files with unexpected encoding (BOM, UTF-8 in
comments, etc.) with a user-friendly error message.
@lovincyrus
Copy link
Contributor Author

1. Consolidate file upload encoding with schema definitions

The current implementation checks file extensions to decide encoding:

if (fileName.endsWith(".pem") || fileName.endsWith(".p8")) {
  return btoa(content);
}

This creates implicit coupling between x-accept in the schema and hardcoded logic in AddDataFormManager. If a future connector adds new file types to x-accept, someone must remember to update the encoding logic separately—they will likely forget.

Introduce a x-file-* namespace to make encoding declarative:

Property Purpose
x-file-accept Allowed extensions (rename from x-accept)
x-file-encoding Content encoding (base64, json, raw) — required for file fields
x-file-extract Extract values from parsed content into form fields
Snowflake schema:

privateKey: {
  "x-display": "file",
  "x-file-accept": ".pem,.p8",
  "x-file-encoding": "base64",
  "x-secret": true,
}

BigQuery schema (replaces hardcoded project_id extraction):

google_application_credentials: {
  "x-display": "file",
  "x-file-accept": ".json",
  "x-file-encoding": "json",
  "x-file-extract": { "project_id": "project_id" },
  "x-secret": true,
}

To support this, pass the field key through the component chain so handleFileUpload(file, fieldKey) can look up the schema property and use the declarative config. Create a processFileContent(content, field) utility that handles encoding based on schema.

2. btoa() can fail on non-Latin-1 characters

PEM files should be ASCII, but if a file has unexpected encoding (BOM, UTF-8 characters in comments), btoa() throws an uncaught exception. The JSON path has try/catch; the PEM path doesn't.

3. Verify field visibility when DSN is selected

The account, user, database, etc. fields have no x-visible-if condition. Confirm they're hidden when DSN is selected via x-grouped-fields rendering logic.

Developed in collaboration with Claude Code

Addressed

Replace flat radio + x-visible-if pattern with nested tabs under each
auth method option. Username/Password shows both parameter and DSN tabs,
while Private Key shows parameters directly without tabs.

Structure:
- auth_method (radio) → connection_mode (tabs for password only)
  - Password: parameters | connection string tabs
  - Private Key: parameters directly (no DSN option)

This mirrors the ClickHouse connector pattern and provides better UX
by removing irrelevant options per auth method.
@lovincyrus lovincyrus dismissed stale reviews from ericpgreen2 and royendo February 4, 2026 19:16

resolved

When switching from password to private_key auth, the connection_mode
field value (parameters or dsn) persists stale. At submit time,
filterValuesByTabGroups uses that stale value to filter which fields
are included, keeping dsn and deleting parameter fields. This causes
both connection methods to be present, triggering backend validation.

Two-part fix:
1. Add x-visible-if to connection_mode so it clears when switching
2. Skip invisible tab controls in filterValuesByTabGroups so cleared
   values don't wipe their tab children
@royendo
Copy link
Contributor

royendo commented Feb 4, 2026

@ericokuma how do you feel about the layout?

I feel the scroll to find privatekey is a bit hidden. This bleeds into another task but none of these forms should have scroll. I was originally thinking

[ User/Pass ] [ User/PrivateKey] [ Connection String] but there isnt a lot of width to support that.
Another option is redesigning the radios all together but that can be done in a later PR.

@ericokuma
Copy link
Contributor

@ericokuma how do you feel about the layout?

I feel the scroll to find privatekey is a bit hidden. This bleeds into another task but none of these forms should have scroll. I was originally thinking

[ User/Pass ] [ User/PrivateKey] [ Connection String] but there isnt a lot of width to support that. Another option is redesigning the radios all together but that can be done in a later PR.

I think the best solution here is to group the radios together or put the options into a dropdown selector.

@ericokuma
Copy link
Contributor

ericokuma commented Feb 6, 2026

Copy link
Contributor

@ericpgreen2 ericpgreen2 left a comment

Choose a reason for hiding this comment

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

1. Remove the legacy file-handling fallback in AddDataFormManager.ts

Lines 496-513 contain a legacy code path that handles .pem/.p8 files with a hardcoded btoa() call, and BigQuery JSON parsing with a hardcoded project_id extraction. Now that all file-upload fields use the new x-file-encoding/x-file-extract annotations (BigQuery, GCS, and Snowflake), this code is unreachable for any current schema. Keeping it around risks divergence — if someone adds a new connector, they might follow the old pattern instead of the new one. I'd remove it entirely and let the schema annotations be the single mechanism.

2. Dead config: privateKey in connection_mode.x-tab-group.parameters

snowflake.ts:48privateKey appears in the connection_mode tab group's parameters list, but it has x-visible-if: { auth_method: "private_key" }, so it's always filtered out when connection_mode is visible (which requires auth_method: "password"). It's functionally harmless but confusing to read — worth removing from that array.

3. Design: auth method selection

Radio buttons are the wrong form element for a choice that reveals different sub-forms. Both options remain fully visible after selection, which adds noise and doesn't communicate that you're choosing between two distinct setup paths. A tabs or dropdown pattern would better match the interaction — both fully hide the non-selected content.

4. Design: field ordering

The field ordering doesn't match how Snowflake users think: Account → Auth → Compute → Data → Permissions. Consider reordering to: Account Identifier → Authentication → Warehouse → Database → Schema (optional) → Role (optional). This reduces backtracking when copy/pasting from the Snowflake UI.

5. Design: account identifier affordances

Account Identifier is the #1 failure point for Snowflake connections. An inline hint like abc12345.us-east-1 vs abc12345 with "Don't include https://" would prevent common mistakes.

6. Test coverage

file-encoding.ts is pure logic with clear edge cases (non-Latin-1 content, invalid JSON, missing extract keys, raw pass-through) — it would be a good candidate for unit tests.


Developed in collaboration with Claude Code

lovincyrus and others added 2 commits February 10, 2026 11:36
…feedback

- Convert auth_method from radio+nested tabs to single-level tabs with
  three options: User/Password, Private Key, Connection String
- Remove connection_mode field (no longer needed)
- Remove dead privateKey from old connection_mode tab group
- Reorder fields to match Snowflake mental model:
  Account → Auth → Warehouse → Database → Schema → Role
- Add account identifier hint to prevent common mistakes
- Add x-visible-if to DSN field so it clears when switching tabs
- Remove legacy file-handling fallback in AddDataFormManager
- Update findRadioEnumKey to also find tabs-based enum selectors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover all edge cases: base64 encoding, non-Latin-1 rejection, JSON
parsing/normalization, invalid JSON, x-file-extract mapping, missing
extract keys, raw pass-through, and getFileAccept fallback logic.

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

@royendo royendo left a comment

Choose a reason for hiding this comment

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

UI wise, this looks good.

I dont have a key atm to test Snowflake so if you can confirm the new upload works, then good to go.

@lovincyrus lovincyrus merged commit b54ab9d into main Feb 10, 2026
11 checks passed
@lovincyrus lovincyrus deleted the cyrus/snowflake-private-key branch February 10, 2026 23:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants