feat(connector): Snowflake create — password, key-pair, OAuth SSO, OAuth individual#17
Conversation
Adds the `ana connector create snowflake password` leaf under the existing two-level dialect/auth-mode Group tree. - `configEnvelope` grows a top-level `authStrategy` field and a `snowflake` pointer sibling to `postgres`, matching the captured wire shape (`config.authStrategy` + `config.snowflake.*`, see `api-catalog/POST_connector.create.snowflake.password.json`). - `snowflakeSpec` covers all four Snowflake auth modes in one struct; every credential field is `omitempty`. Server discriminates by populated field + envelope `authStrategy`. - `newSnowflakeCreateGroup` declares dialect-common flags (`--name`, `--locator`, `--database`, `--warehouse`, `--schema`, `--role`) via the Phase 2 inheritable `Flags` closure so future auth-mode leaves (`keypair`, `oauth-sso`, `oauth-individual`) inherit them. - Password leaf mirrors the Postgres-password canonical pattern 1:1: `Flagger` for `--help` rendering, explicit empty-string rejection, `resolvePassword` for stdin, `RenderOutput` for JSON/typed dispatch.
Adds the `ana connector create snowflake keypair` leaf. Shares authStrategy=service_role with password mode; server discriminates by populated credential field (`privateKey` vs `password`). - Private key is read from `--private-key-file` (PEM-encoded PKCS#8). File path, not stdin — multi-line keys are typically already on disk and file-upload mirrors the web UI's control. - `--user` is still required: Snowflake binds RSA public keys to a user. - Optional `--private-key-passphrase` / `--private-key-passphrase-stdin` for encrypted PKCS#8 keys. `resolveOptionalPassphrase` returns "" when neither is set so `omitempty` drops the field from the wire body. - Tests mirror the Snowflake password + Postgres password pattern 1:1 plus file-lifecycle cases (missing file, empty file, passphrase via flag or stdin, passphrase absent). Wire shape matches `api-catalog/POST_connector.create.snowflake.keypair.json`.
Prep for the OAuth leaves, which need the same stdin-or-flag secret handling but for `--oauth-client-secret` / `--client-secret` / `--pat`. The body is identical; only the error-message flag name varies. - Add `flagName string` as the first parameter; error messages now read `--<name>-stdin set but stdin was empty` and `--<name> or --<name>-stdin is required`. - All three existing call sites (postgres password, snowflake password, update) pass `"password"` — behavior unchanged. - `cli.ReadPassword` stays the backend, so JWT-sized buffer and whitespace-preservation semantics carry over to every secret kind.
Adds `ana connector create snowflake oauth-sso` (authStrategy=oauth_sso, shared-token OAuth). - Required: --oauth-client-id + secret (via --oauth-client-secret or --oauth-client-secret-stdin). No username/password/privateKey. - Server accepts the row in pending-OAuth state; CLI cannot receive the browser redirect at /auth/snowflake/callback, so the success output reminds the user to complete the handshake at app.textql.com. - Uses the renamed resolveSecret helper for the OAuth client secret. Wire shape matches api-catalog/POST_connector.create.snowflake.oauth-sso.json.
Adds `ana connector create snowflake oauth-individual` (authStrategy=per_member_oauth). Wire fields are identical to oauth-sso — only the authStrategy differs. Unlike oauth-sso, no up-front browser handshake is needed: each member authenticates lazily at their first query, so the CLI just creates the row. Wire shape matches api-catalog/POST_connector.create.snowflake.oauth-individual.json.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (8)
📝 WalkthroughWalkthroughAdds Snowflake connector creation subtree (password, keypair, OAuth SSO, per-member OAuth) to the CLI and generalizes secret handling by replacing Changes
Sequence Diagram(s)sequenceDiagram
participant User as User (stdin/CLI)
participant CLI as ana connector CLI
participant Client as Deps.Unary (Client)
participant Service as Connector Service
User->>CLI: run "ana connector create snowflake <mode> --flags" (may use --*-stdin)
CLI->>User: read stdin line (if --*-stdin set)
CLI->>Client: Unary(CreateConnector request JSON)
Client->>Service: POST /CreateConnector
Service-->>Client: Response (connectorId, name, type)
Client-->>CLI: return response
CLI->>User: render output (JSON or formatted text)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/connector/create_snowflake_oauth_sso.go`:
- Around line 36-40: The Help text currently hardcodes app.textql.com; update
the code to use the active profile endpoint instead: add a dependency in
connector.Deps that exposes a loader function following the auth package
LoadCfg/SaveCfg pattern to retrieve the active endpoint, then have
snowflakeOAuthSSOCmd.Help build its URL using that endpoint rather than a
hardcoded host, and update the success message printed after connector creation
(the post-create success output in the same file) to use the same loaded
endpoint. Ensure the new dep is wired into the command initialization and used
where the OAuth redirect URL is shown.
In `@internal/connector/types.go`:
- Around line 44-62: The snowflakeSpec struct is currently defined in types.go
and should be moved to a dialect-specific file to preserve the package's
per-dialect type boundary; create a new file (e.g., types_snowflake.go) in
package connector and move the snowflakeSpec type declaration there (preserving
its json tags and exact field names: Locator, Database, Warehouse, Schema, Role,
Username, Password, PrivateKey, PrivateKeyPassphrase, OAuthClientID,
OAuthClientSecret), remove the definition from types.go, run go vet/go build to
ensure no references break, and keep the type unexported as snowflakeSpec.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: fb6a306c-8212-47ed-9215-b9dcecd515c1
⛔ Files ignored due to path filters (6)
README.mdis excluded by!**/*.mddocs/CLAUDE.mdis excluded by!**/docs/**,!**/*.mddocs/ci-scope.mdis excluded by!**/docs/**,!**/*.mddocs/cli-readiness.mdis excluded by!**/docs/**,!**/*.mddocs/windows-smartscreen.mdis excluded by!**/docs/**,!**/*.mdinternal/connector/CLAUDE.mdis excluded by!**/*.md
📒 Files selected for processing (14)
internal/connector/create.gointernal/connector/create_postgres.gointernal/connector/create_postgres_password_test.gointernal/connector/create_snowflake.gointernal/connector/create_snowflake_keypair.gointernal/connector/create_snowflake_keypair_test.gointernal/connector/create_snowflake_oauth_individual.gointernal/connector/create_snowflake_oauth_individual_test.gointernal/connector/create_snowflake_oauth_sso.gointernal/connector/create_snowflake_oauth_sso_test.gointernal/connector/create_snowflake_password.gointernal/connector/create_snowflake_password_test.gointernal/connector/types.gointernal/connector/update.go
Hardcoded https://app.textql.com in snowflake oauth-sso Help and success output directed users at the wrong environment on non-prod / self-hosted profiles. Thread the resolved endpoint through connector.Deps and format the success note from it.
Moves postgresSpec and snowflakeSpec out of types.go into dedicated types_postgres.go and types_snowflake.go. types.go keeps only shared wire shapes (createReq, updateReq, configEnvelope, createResp, getConnectorResp). Scales cleanly as new dialects land.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Summary
connector createauth-mode leaves under the Phase 2 inheritable-flags Group pattern (mirrorscreate_postgres.go).ana connector create snowflake {password|keypair|oauth-sso|oauth-individual}.resolvePassword→resolveSecretso non-password secrets (OAuth client secret, private-key passphrase) flow through one helper.internal/connector/CLAUDE.mdto nav hints, slimREADME.md(relocate CI-scope + Windows-SmartScreen details todocs/), and flip the Snowflake row indocs/cli-readiness.mdfrom 🟦 → 🟢 with the OAuth footnote corrected to match the pending-row-then-browser-activation model actually shipped.Gaps flagged for follow-up
e2e/) is Postgres-only. Snowflake smoke coverage needs aDialectSpecrefactor ofe2e/harness/resources.go+ newANA_E2E_SF_*env vars. Shipping as its own PR.connector update) unblocked and queued.Summary by CodeRabbit
New Features
Refactor