Repository navigation
CXH-2679: fix server and table privilege names in baton-mysql - #36
c1-squire-dev[bot] wants to merge 9 commits into
Conversation
Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
…apper Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
…sts into CI Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
There was a problem hiding this comment.
No blocking issues found — see the full review report
…olumn grant expansion; fail-closed slug charset - GrantServerPrivilege gains withGrant and appends " WITH GRANT OPTION" after the quoted user (MySQL grammar; matches client roles.go proxy precedent). The mapper no longer embeds the clause into the privilege slot for server scope. Database/table scope keep the embedded form. - Column-scope `grant` rejection reverted: the client's expansion of `grant` into SELECT/INSERT/UPDATE/REFERENCES (col) is valid SQL and pre-PR behavior; the syncer passes the raw slug through again. - sqlPrivilegeName now rejects any base slug not matching ^[a-z_]+$ so the fail-closed claim holds for underscore-free garbage too. Co-authored-by: Squire Bot <bot@squire.ai> Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
There was a problem hiding this comment.
No blocking issues found — see the full review report
…ION at database/table scope - columnSyncer.Grant now checks len(columnParts) != 3 like Revoke (no panic on crafted IDs like entitlement:select:column:db.tbl), with a matching test. - grantPrivilegeString fails closed (InvalidArgument) on withGrant=true at database/table scope instead of building invalid MySQL grammar; no catalog *_with_grant entitlement exists at those scopes (includeWithGrant is server-only). database.go/table.go propagate the error; comment + tests updated. Co-authored-by: Squire <squire@conductorone.com> Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
There was a problem hiding this comment.
No blocking issues found — see the full review report
…sql error prefixes; exhaustiveness default - sqlPrivilegeName: spelling override maps both the frozen catalog slug nbd_stored_user (BUGBOT-frozen, transposed) and the DB-derived ndb_stored_user spelling to MySQL's NDB_STORED_USER - add baton-mysql: prefix to the error guards this PR introduced (column.go Grant, database.go Grant/Revoke) - catalog exhaustiveness test: default case fails on unclassified resource types Co-authored-by: cf-resolve-bot-feedback <squire@ductone.io> Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
Superseded — see the current review report for commit
|
Superseded — see the current review report for commit
|
There was a problem hiding this comment.
No blocking issues found — see the full review report
…he frozen catalog; baton-mysql prefix on malformed-ID error The server syncer's Revoke path now falls back to the uppercased slug for dynamic privileges the frozen catalog does not list (e.g. TP_CONNECTION_ADMIN), keeping the spelling main sent; grants stay fail-closed. The malformed entitlement-ID error carries the baton-mysql: prefix like the rest of the file. Co-authored-by: squire <squire@conductorone.com> Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
Superseded — see the current review report for commit
|
Connector PR Review: CXH-2679: fix server and table privilege names in baton-mysqlBlocking Issues: 0 | Suggestions: 0 | Threads Resolved: 0 Review SummaryThe PR adds one mapper, This push adds The fallback is safe from SQL injection: everything reaching I scanned the full PR diff for security and correctness:
How the trusted criteria applied:
There were no prior inline findings to audit, and the incremental diff was not partial. Security IssuesNone found. Correctness IssuesNone found. SuggestionsNone. Reviewed commit: |
There was a problem hiding this comment.
No blocking issues found — see the full review report
Fixes the privilege names baton-mysql sends to GRANT and REVOKE, so grants and revokes that MySQL rejects today (errors 1149/1064/3619, and revokes that silently do nothing) work as the entitlements promise.
What was asked
CXH-2679: baton-mysql builds the SQL privilege name from its lower-case catalog keys. Multi-word privileges reached MySQL as
SHOW_DATABASESinstead ofSHOW DATABASES— grant failed with error 1149, revoke "succeeded" with only warning 3929 while the privilege stayed on the account. The_with_grantsuffix was never stripped (a case-mismatched replace), so every*_with_grantserver entitlement failed with 1064 on grant and revoke. The table path passed the key through unchanged, socreate_view/show_viewfailed with 3619. Sync already reads all of this correctly; only the provisioning path is wrong.This is a fresh implementation of #33 — same bug, reworked after that PR's review feedback.
What changed
The privilege mapper also corrects the transposed NDB stored-user spelling — both the frozen catalog slug
nbd_stored_userand the DB-derivedndb_stored_userspelling sync emits on revoke — to MySQL'sNDB_STORED_USER.One privilege-name mapper, five call sites:
pkg/connector/privileges.go(new)What changed —
sqlPrivilegeNamemaps the 13 multi-word static privileges to their space-separated SQL spellings and mapsgranttoGRANT OPTION. Single-word statics and the enumerated dynamic privileges (BACKUP_ADMIN,SYSTEM_VARIABLES_ADMIN, …) pass through unchanged, so the underscores MySQL requires stay in place.trimWithGrantSuffixstrips the_with_grantsuffix case-insensitively.resolveServerPrivilegerejectsproxyat server scope with a gRPC Unimplemented error before any SQL is built, becauseGRANT PROXY ON *.*is not valid MySQL grammar.Why — multi-word static privileges are keywords MySQL only accepts space-separated, while dynamic privileges are names registered with underscores. A blanket underscore→space replace (the database path's old shortcut) trades one error class for another, so the map is closed and anything unclassified with underscores fails with a clear error instead of guessing.
pkg/connector/server.goGrant passes the resolved SQL name plus a
withGrantflag to the client, which appendsWITH GRANT OPTIONafter the quoted user — MySQL grammar requires the clause to trail theTOclause (same shape as the existing proxy grant inpkg/client/roles.go), not to sit in the privilege slot. Revoke sends the base privilege only — revoking drops the grant option along with the privilege, matching how sync models the entitlement. The brokenextractServerPrivilegeis deleted.pkg/connector/table.go,database.go,routine.go,column.goAll four route the entitlement key through the mapper. Table gets
CREATE VIEW/SHOW VIEW. Database loses its blanket replace — byte-identical SQL for every existing database-scope privilege, andGRANT OPTIONforgrant. Routine gainscase "grant"(GRANT OPTION ON PROCEDUREis valid MySQL). Column behavior is unchanged: the client expandsgrantintoSELECT, INSERT, UPDATE, REFERENCES (col), which is valid SQL; the syncer now also guardslen(parts) != 4on Grant, matching its Revoke.Untouched on purpose
pkg/client/*keeps doing the SQL interpolation (its ToUpper is space-preserving), andpkg/connector/entitlements.go— the sync catalog: slugs, display names, entitlement IDs and counts are byte-identical, pinned by a test.How it was tested
pkg/connector: the mapper for every class (13 multi-word statics, dynamics,_with_grantcase variants,grant, fail-closed rejections); a catalog-exhaustiveness test that fails the build when a future entitlement is added without a classification; a sync-invariance test pinning the sync surface; syncer-level tests proving rejected entitlements never reach a client call; charset validation tests pinning fail-closed behavior for underscore-free garbage slugs.provisioning_mysql_test.go) grant and revoke through the real syncers against a MySQL server and assert presence/absence viaSHOW GRANTS. They are wired into the existing ci.yamltestjob — which already starts mysql:8 and exportsBATON_CONNECTION_STRING— as a newgo test ./pkg/connector/... ./pkg/client/...step, so they run on every PR. Unit tests run without a DSN.c9a4881a(including the wiredtestjob running the go test suite against mysql:8), and the review bot accepted after 5 gate passes — its objections across passes (a realWITH GRANT OPTIONgrammar bug its first CI run caught, the column-grant expansion restoration, guards, prefixes, and the NDB spelling) were each fixed or answered, and every review thread is resolved.NDB_STORED_USERspelling — both the catalog slug and the DB-derived spelling now map correctly; missingbaton-mysql:error prefixes; an exhaustiveness-test default), round 2 raised two (a revoke-only regression for dynamic privileges the frozen catalog does not list — revokes now keep the spelling main sent while grants stay fail-closed; one error prefix). All five were fixed; every review thread is answered and resolved.BACKUP_ADMINunchanged, trailingWITH GRANT OPTION,GRANT OPTIONmapping, tableCREATE VIEW/SHOW VIEW,proxyrejected before any client call, sync surface byte-identical); the end-to-end grant/revoke round-trip against a real server is exercised by the wired CI step rather than locally (no MySQL server exists in the validation environment) — 13 of 15 claims verified working, 2 honestly untestable locally, 0 broken.What to look at hardest
pkg/connector/privileges.go— the static/dynamic classification is the whole fix. A misclassification fails loudly (clear error), but a wrong multi-word mapping would still reach MySQL.proxyat server scope now returns a clear error instead of sending SQL MySQL rejects;REVOKEof a*_with_grantentitlement removes the grant option together with the privilege. Column-scopegrantis unchanged behavior — the client expands it into the four column privileges. The server syncer's revoke path deliberately falls back to the uppercased slug for dynamic privileges the frozen catalog does not list — those revokes keep the spelling main sent (sync can surface documented dynamics the catalog cannot grow without breaking the stable-slug API) — while grants stay fail-closed.Release Notes
baton-mysql grants and revokes now spell privileges the way MySQL expects: multi-word privileges (SHOW DATABASES, CREATE USER, REPLICATION CLIENT, …) work at server, database, table and routine scope,
*_with_grantentitlements grant and revoke withWITH GRANT OPTION, andgrantmaps to GRANT OPTION everywhere it is valid. Grantingproxyat server scope now returns a clear "not supported at this scope" error instead of sending SQL that MySQL rejects.*_with_grantgrants use MySQL's trailingWITH GRANT OPTIONgrammar. Column-scopegrantkeeps its pre-existing expansion into the four column privileges. Sync output is unchanged.Refs #33