fix(grant): stop phantom CREATE for database-role-to-database-role grants - #75
Conversation
…ants Snowflake reports a DATABASE_ROLE grantee unqualified when it's in the same database as the granting role, but the manifest side always compares against a fully qualified DB.ROLE string. That mismatch made fetch_database_role_grant and list_database_role_grants never find the existing grant, so plan re-issued it as a no-op CREATE on every run. - fetch_database_role_grant and both list_database_role_grants paths now qualify-then-compare grantee names via a shared _database_role_grantee_fqn() helper instead of comparing raw strings. - _fetch_grants_from_account_usage now normalizes GRANTED_ON the same way it already normalizes GRANTED_TO (DATABASE_ROLE -> DATABASE ROLE), fixing a dead filter that made the ACCOUNT_USAGE path for list_database_role_grants always return zero results.
Review of PR #75No issues found. What the change does: Fix: new helper Verification:
No correctness, security, or architecture-fit concerns found in this diff. |
…base param FQN.database is Optional[ResourceName]; the helper's parameter was typed as the non-optional ResourceName, which mypy flagged at both call sites in fetch_database_role_grant where fqn.database is passed straight through.
Review of PR #75No issues found. The change is a narrowly-scoped, well-tested bug fix. What it does: Correctness check: verified Tests: |
Summary
snowcap planreported a phantom+ CREATEfor every database-role-to-database-role grant on every run, because Snowflake reports aDATABASE_ROLEgrantee unqualified when it's in the same database as the granting role, while the manifest side always builds a fully qualifiedDB.ROLEstring for comparison. Root cause and repro are in the original bug report; see commit message for the fix breakdown.fetch_database_role_grantand bothlist_database_role_grantspaths (SHOW fallback and ACCOUNT_USAGE) now qualify-then-compare grantee names via a shared_database_role_grantee_fqn()helper instead of comparing raw strings._fetch_grants_from_account_usagenow normalizesGRANTED_ONthe same way it already normalizesGRANTED_TO(DATABASE_ROLE->DATABASE ROLE), fixing a dead filter that made the ACCOUNT_USAGE path forlist_database_role_grantsalways return zero results, plus a dead qualification branch that leftNAMEunqualified.Test plan
OTHERDB.ROLEmust not matchDB.ROLE), the account-role regression case, both list paths individually, AU/SHOW path agreement, and an end-to-end check that the fetched FQN equals the FQN the manifest builds for the same declared grant.python -m pytest tests/ --ignore=tests/integration(2215 passed, 1 skipped, 1 xfailed).