fix(grants): order READ before WRITE on bulk stage grants#23
Merged
noel merged 1 commit intoJun 18, 2026
Merged
Conversation
_create_stage_privilege_refs only linked grants on a single named stage (on_type == STAGE), so bulk ALL/FUTURE stage grants got no WRITE -> READ dependency. At apply time the same-level grants for a role run concurrently and WRITE could reach Snowflake before READ, failing with "Privilege order violation for the future grants on stage." Also collect grants whose items_type is STAGE and key reads/writes by the full scope (on_type, on, grant_type, items_type) so only grants over the same set of stages get linked. Covers all ALL/FUTURE x DATABASE/SCHEMA combinations. Add unit coverage for all four bulk scopes plus cross-scope non-linking, and an integration test that applies READ/WRITE across all four scopes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
|
Thanks for the thorough fix and excellent PR description, Keller! The root cause analysis and test coverage are great. |
Contributor
|
@kellerbrown deployed a new version with this change. |
Contributor
Author
Thank you! Wanted to also give you a heads up that although the README.md links to the issues for the repo, it seems contributors outside of Datacoves are unable to create them. Loving what your team is doing with Snowcap thus far. Sent you a request to connect on LinkedIn. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Snowflake refuses to grant
WRITEon a stage to a role that does not alreadyhold
READon it. The privileges have to be granted in order, or together. Thisrule also covers
ALL/FUTUREgrants:Snowcap already accounts for this with
Blueprint._create_stage_privilege_refs,which makes every
WRITEgrant depend on the matchingREADgrant so the twoland at different dependency levels and apply in the right order. But it only
catches grants on a single named stage. Bulk grants over
ALL/FUTUREstagesare missed, and the apply fails.
Root cause
_create_stage_privilege_refscollects grants by checkingon_type == STAGE:That only holds for a grant on a specific stage (
GRANT WRITE ON STAGE db.sc.s).For a bulk grant the parser puts the container in
on_typeand the stage initems_type:on_typeitems_typeWRITE ON STAGE db.sc.sSTAGENoneWRITE ON ALL STAGES IN DATABASE dbDATABASESTAGEWRITE ON FUTURE STAGES IN SCHEMA db.scSCHEMASTAGESo bulk stage grants never enter
stage_grants, noWRITE -> READdependency iscreated, and the two grants end up at the same dependency level. At apply time
same-level grants for a role run concurrently (
execute_commands_in_parallel),so
WRITEcan reach Snowflake beforeREADand the statement fails.Fix
Also collect grants whose
items_typeisSTAGE, and group reads and writes bythe full scope so only grants over the same set of stages get linked:
The existing
WRITE -> READpass is unchanged; it now runs over bulk grants too.This covers all
ALL/FUTURE×DATABASE/SCHEMAcombinations.Testing
All CI gates pass:
ruff check snowcap/,mypytypecheck, and the full unitsuite (
pytest --ignore=tests/integration, 1533 passed). The existingsingle-named-stage integration test
(
test_stage_read_write_privilege_execution_order) still passes against a liveaccount, confirming no regression on that path.
Unit test
Added
test_blueprint_bulk_stage_read_write_orderingintests/test_blueprint.py.The fix is container- and grant-type-agnostic (it keys on
items_type == STAGE),so the test asserts the
WRITE -> READdependency for all fourALL/FUTURE×DATABASE/SCHEMAcombinations afterBlueprint._finalize, andasserts distinct scopes do not cross-link (a
WRITEonly depends on theREADover its exact same scope). Verified it fails onmain(bulkWRITEcarries no
READdependency) and passes with the fix.Integration test
Added
test_bulk_stage_read_write_privilege_execution_orderintests/integration/test_blueprint.py(markedrequires_snowflake). It appliesREAD/WRITEacross all fourALL/FUTURE×DATABASE/SCHEMAscopes to arole and asserts the apply succeeds. Confirmed end-to-end: on
mainthe applyraises the real Snowflake error —
003511 (23001): Privilege order violation for the future grants on stage. READ should be granted before/simultaneously with WRITE— and with the fix the same apply succeeds.