Skip to content

V2 connectorbuilder migration and CI modernization - #52

Merged
jugonzalez12 merged 4 commits into
mainfrom
jugonzalez/review-followups-runconnector
Sep 11, 2026
Merged

jugonzalez12 merged 4 commits into
mainfrom
jugonzalez/review-followups-runconnector

Conversation

@jugonzalez12

Copy link
Copy Markdown
Contributor

Follow-ups from the review of #51: move the connector onto the SDK's current entrypoint and replace the hand-rolled integration job with the shared connector test actions.

Changes

config.RunConnector and V2 resource syncers (7109cae)

  • main.go now uses config.RunConnector, which owns config decoding, the capabilities subcommand, and process exit codes (gRPC status codes: a bad DSN exits 2, an invalid argument 3, a missing grant 5).
  • RunConnector only accepts a ConnectorBuilderV2, so all ten syncers move from the V1 List/Entitlements/Grants contract to the V2 one: the page token arrives in SyncOpAttrs and the next token returns in SyncOpResults. The translation is mechanical; no syncer's logic changes. Three nil-token guards that can no longer trigger are dropped.
  • Provisioning methods (Grant, Revoke, Create, Delete, CreateAccount, Rotate) are untouched; the SDK registers them by type assertion regardless of builder version.
  • The default-capabilities option stays so ./connector capabilities keeps working without a DSN.
  • scripts/get-baton.sh is removed; the shared actions fetch baton themselves.

Integration tests through the shared actions (cbb02f3)

  • The test job's grant/revoke and create/fetch/delete steps are replaced by github-workflows/actions/sync-test@v4 and actions/account-provisioning@v4. Together they cover what the old steps did, plus idempotent double grant and double revoke, and credential rotation on the created account, which previously had no automated coverage.
  • account-provisioning requires an email. The SDK validates it as an address, and this connector names the created role after it, so the lookup uses search-method: email.
  • BATON_STORAGE_ENGINE: pebble is dropped since pebble is the default.

Verification

  • go build, go vet, golangci-lint (0 issues), gofmt, actionlint.
  • go test ./... including the six Postgres-container tests and the zero-value connector test.
  • Live smoke against a throwaway Postgres 16 through the new entrypoint: sync; grant twice and revoke twice on entitlement:role:3375:member for role:10 with the grant gone afterwards; create account with the exact flags the action sends, find it by email, rotate (password hash changed), delete, idempotent second delete, role gone. Bad DSN exits 2.
  • ./connector capabilities output is byte-identical to the committed baton_capabilities.json; re-vendoring is a no-op.

jugonzalez12 and others added 2 commits September 10, 2026 16:28
RunConnector is the SDK's current entrypoint and owns config decoding, the
capabilities subcommand, and process exit codes (gRPC status codes), but it
only accepts a ConnectorBuilderV2. All ten syncers therefore move from the V1
List/Entitlements/Grants contract to the V2 one: the page token arrives in
SyncOpAttrs and the next token rides back in SyncOpResults. The translation
is mechanical and no syncer's logic changes; three nil-token guards that can
no longer trigger are dropped. Provisioning methods are unchanged, since the
SDK registers them by type assertion regardless of builder version.

The default-capabilities option stays so `capabilities` keeps working
without a DSN.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Replace the hand-rolled grant/revoke and create/delete steps with the
sync-test and account-provisioning actions from github-workflows. Together
they cover what the old steps did plus idempotent double grant and double
revoke, and credential rotation on the created account, which had no
automated coverage before. The actions fetch the baton CLI themselves, so
the install step goes with the script the previous commit removed.

The account-provisioning action requires an email; the SDK validates it as
an address and this connector names the created role after it, so the
lookup goes by email. The storage-engine override is dropped since pebble
is the default.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment thread .github/workflows/ci.yaml
Comment thread .github/workflows/ci.yaml
Comment thread .github/workflows/ci.yaml
Comment thread cmd/baton-postgresql/main.go Outdated
@github-actions

github-actions Bot commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Connector PR Review: V2 connectorbuilder migration and CI modernization

Blocking Issues: 0 | Suggestions: 1 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base a5b669ffc425.
Review mode: incremental since 99b6536
View review run

Review Summary

The new commit addresses both prior findings: NewClientDatabasesPool no longer logs the pool-construction failure at Error before returning it, so exit.LogExit is now the only logger, and ClientDatabasesPool.Get routes its pgxpool.ConnectConfig failure through classifyConnectError — backed by a new testcontainers integration test asserting that a real REVOKE CONNECT yields SQLSTATE 42501 mapped to codes.PermissionDenied, with the *pgconn.PgError still reachable in the chain. I re-scanned the full PR diff for security and correctness: the V2 SyncOpAttrs / SyncOpResults migration matches the vendored SDK interfaces, dropping the now-impossible pToken == nil guards is correct, the SDK nil-checks a nil *SyncOpResults before dereferencing it, and the graceful per-database skip in databaseSyncer.List still works because classifyConnectError keeps the *pgconn.PgError reachable via errors.As. One non-blocking log-level suggestion remains, on unchanged code inside the function this commit touched.

Security Issues

None found. The new CI action inputs match the v4 sync-test and account-provisioning signatures, the bad-credentials override is genuinely required because BATON_DSN is not matched by is_credential_var, and SQLSTATE 28P01 correctly maps to exit 16. pgx connect errors carry the host, user and database name but never the password, so the new error wrapping does not widen secret exposure.

Correctness Issues

None found.

Suggestions

  • pkg/postgres/client.go:69 — the Error-level log for an invalid cached database connection fires on a condition that Get immediately self-heals (close, evict, reconnect); per criteria L2/L4 a recoverable, handled condition should be Warn, not Error.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/postgres/client.go`:
- Around line 69: ClientDatabasesPool.Get logs at Error level with the message "database
  connection is invalid" when ValidateConnection on the cached client fails, but the very
  next lines close the pool, delete it from the cache, and transparently establish a fresh
  connection. A stale pooled connection is an expected runtime condition, not a connector
  bug, and the connector does not stop. Per the repo log-level criteria (L2: Error is for
  upstream 5xx and genuine connector bugs; L4: handled skip-and-recover is Warn), downgrade
  this call to l.Warn with the same fields (zap.String database, zap.Error err) so it does
  not create alert noise or permanently retained OTEL error spans on every pool refresh.
  Keep the existing client.db.Close() and delete(p.databases, dbModel.Name) calls unchanged.

Reviewed head SHA a5cec08, base SHA a5b669f. The machine-readable review-state marker could not be written this run because the CI shell blocked every JSON-bearing command form; the next run will fall back to a full review.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No blocking issues found.

Review follow-ups on the shared-actions change.

- postgres.New attaches a gRPC status to connection failures the server
  attributes to the client's authorization: SQLSTATE class 28 maps to
  Unauthenticated (exit 16) and 42501 to PermissionDenied (exit 7). The
  original pgx error stays in the chain.
- ci.yaml hands the sync-test auth-error check a bad DSN through
  bad-credentials; it was skipping because BATON_DSN is not
  credential-shaped. Document why the shared actions' unpinned baton CLI
  is acceptable for reading this connector's c1z files.
- getConnector no longer logs the error it returns; RunConnector prints
  it on exit and the pool constructor already logs the failure.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment thread cmd/baton-postgresql/main.go Outdated
Comment thread pkg/postgres/client.go

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No blocking issues found.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No blocking issues found.

@jugonzalez12
jugonzalez12 marked this pull request as ready for review September 11, 2026 17:21
@jugonzalez12
jugonzalez12 merged commit 9801d0d into main Sep 11, 2026
12 of 13 checks passed
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.

3 participants