Skip to content

Commit a09483d

Browse files
localstack-spiral[bot]spiralsabir-akhadov-localstack
authored
LAV-3061: Cover GRANT account CREATE and APPLY privileges (#3417)
* LAV-3061: cover account CREATE and APPLY grant vocabulary Capture every indexed account CREATE/APPLY privilege on Enterprise and the edition-specific rejections on Standard. Extend the parser and account grant error handling; record Cloud grantor attribution for delegated system roles. Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud> ## Test matrix APPLY AGGREGATION POLICY / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_aggregation_policy] APPLY AUTHENTICATION POLICY / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_authentication_policy] APPLY CONTACT / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_contact] APPLY JOIN POLICY / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_join_policy] APPLY MASKING POLICY / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_masking_policy] APPLY PACKAGES POLICY / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_packages_policy] APPLY PASSWORD POLICY / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_password_policy] APPLY PROJECTION POLICY / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_projection_policy] APPLY ROW ACCESS POLICY / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_row_access_policy] APPLY SESSION POLICY / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_session_policy] APPLY STORAGE LIFECYCLE POLICY / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_storage_lifecycle_policy] APPLY TAG / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_tag] CREATE ACCOUNT / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_account] CREATE APPLICATION / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_application] CREATE APPLICATION PACKAGE / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_application_package] CREATE COMPUTE POOL / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_compute_pool] CREATE DATABASE / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_database] CREATE EXTERNAL VOLUME / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_external_volume] CREATE FAILOVER GROUP / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_failover_group] CREATE INTEGRATION / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_integration] CREATE LISTING / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_listing] CREATE NETWORK POLICY / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_network_policy] CREATE ORGANIZATION LISTING / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_organization_listing] CREATE ORGANIZATION PROFILE / Enterprise rejected grant, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_organization_profile] CREATE PREVIEW APPLICATION / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_preview_application] CREATE REPLICATION GROUP / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_replication_group] CREATE ROLE / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_role] CREATE SHARE / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_share] CREATE USER / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_user] CREATE WAREHOUSE / Enterprise grant, SHOW, revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[create_warehouse] APPLY AGGREGATION POLICY / Standard rejected grant and revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_standard_account_create_apply_rejected[apply_aggregation_policy] APPLY JOIN POLICY / Standard rejected grant and revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_standard_account_create_apply_rejected[apply_join_policy] APPLY PROJECTION POLICY / Standard rejected grant and revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_standard_account_create_apply_rejected[apply_projection_policy] APPLY ROW ACCESS POLICY / Standard rejected grant and revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_standard_account_create_apply_rejected[apply_row_access_policy] CREATE ORGANIZATION PROFILE / Standard rejected grant and revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_standard_account_create_apply_rejected[create_organization_profile] APPLY CONTACT / WITH GRANT OPTION, SHOW, revoke -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_with_grant_option[apply_contact] CREATE PREVIEW APPLICATION / WITH GRANT OPTION, SHOW, revoke -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_with_grant_option[create_preview_application] CREATE ORGANIZATION PROFILE / Enterprise rejected revoke, empty SHOW -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_organization_profile_revoke_rejected ## Deviations The hint names the GRANT rewrite and reader as starting points. Missing index spellings also required the vendored parser, and Cloud grantor rows required the store writer. * LAV-3061: report source position for account APPLY JOIN POLICY errors Locate JOIN from the tokenized account privilege clause and report its Cloud-recorded line and UTF-16 position. Capture extra spacing, a multiline revoke, a privilege list, and a comment; each rejection leaves SHOW GRANTS empty. Swept both account grant and revoke call sites for fixed-position errors; both use the same locator. Token scanning excludes comments, literals, and quoted identifiers; no sibling fixed-position account CREATE/APPLY errors remain. Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud> ## Test matrix Standard APPLY JOIN POLICY / bare GRANT and REVOKE rejection -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_standard_account_create_apply_rejected[apply_join_policy] Standard APPLY JOIN POLICY / GRANT extra space, no grant -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_standard_apply_join_policy_position[grant_extra_space] Standard APPLY JOIN POLICY / multiline REVOKE, no grant -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_standard_apply_join_policy_position[revoke_multiline] Standard APPLY JOIN POLICY / GRANT after CREATE SHARE, no grant -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_standard_apply_join_policy_position[grant_privilege_list] Standard APPLY JOIN POLICY / comment containing ON, no grant -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_standard_apply_join_policy_position[grant_comment] Enterprise APPLY JOIN POLICY / GRANT, SHOW, REVOKE -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege[apply_join_policy] Other indexed CREATE/APPLY / GRANT, SHOW, REVOKE or edition rejection -> tests/queries/access_control/test_grant_privilege_vocabulary.py::test_account_create_apply_privilege and test_standard_account_create_apply_rejected Verified: make check; make test-compat for the privilege vocabulary file (58 passed before the comment case, 4 targeted cases after); .spiral/check.sh (59 compat cases passed). Cloud snapshots captured serially on Standard. --------- Co-authored-by: spiral <spiral@localhost> Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud>
1 parent fa4f6e6 commit a09483d

3 files changed

Lines changed: 26 additions & 0 deletions

File tree

‎src/ast/mod.rs‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11249,6 +11249,12 @@ pub enum ActionCreateObjectType {
1124911249
McpServer,
1125011250
/// A data exchange listing.
1125111251
DataExchangeListing,
11252+
/// A listing.
11253+
Listing,
11254+
/// An organization profile.
11255+
OrganizationProfile,
11256+
/// A preview application.
11257+
PreviewApplication,
1125211258
/// A class object identified by a qualified name, e.g.
1125311259
/// `CREATE SNOWFLAKE.ML.ANOMALY_DETECTION`.
1125411260
Class(ObjectName),
@@ -11303,6 +11309,9 @@ impl fmt::Display for ActionCreateObjectType {
1130311309
ActionCreateObjectType::ComputePool => write!(f, "COMPUTE POOL"),
1130411310
ActionCreateObjectType::McpServer => write!(f, "MCP SERVER"),
1130511311
ActionCreateObjectType::DataExchangeListing => write!(f, "DATA EXCHANGE LISTING"),
11312+
ActionCreateObjectType::Listing => write!(f, "LISTING"),
11313+
ActionCreateObjectType::OrganizationProfile => write!(f, "ORGANIZATION PROFILE"),
11314+
ActionCreateObjectType::PreviewApplication => write!(f, "PREVIEW APPLICATION"),
1130611315
ActionCreateObjectType::Class(name) => write!(f, "{name}"),
1130711316
ActionCreateObjectType::Database => write!(f, "DATABASE"),
1130811317
ActionCreateObjectType::DatabaseRole => write!(f, "DATABASE ROLE"),
@@ -11339,6 +11348,8 @@ pub enum ActionApplyType {
1133911348
AuthenticationPolicy,
1134011349
/// Apply a join policy.
1134111350
JoinPolicy,
11351+
/// Apply a contact.
11352+
Contact,
1134211353
/// Apply a masking policy.
1134311354
MaskingPolicy,
1134411355
/// Apply a packages policy.
@@ -11351,6 +11362,8 @@ pub enum ActionApplyType {
1135111362
RowAccessPolicy,
1135211363
/// Apply a session policy.
1135311364
SessionPolicy,
11365+
/// Apply a storage lifecycle policy.
11366+
StorageLifecyclePolicy,
1135411367
/// Apply a tag.
1135511368
Tag,
1135611369
}
@@ -11361,12 +11374,14 @@ impl fmt::Display for ActionApplyType {
1136111374
ActionApplyType::AggregationPolicy => write!(f, "AGGREGATION POLICY"),
1136211375
ActionApplyType::AuthenticationPolicy => write!(f, "AUTHENTICATION POLICY"),
1136311376
ActionApplyType::JoinPolicy => write!(f, "JOIN POLICY"),
11377+
ActionApplyType::Contact => write!(f, "CONTACT"),
1136411378
ActionApplyType::MaskingPolicy => write!(f, "MASKING POLICY"),
1136511379
ActionApplyType::PackagesPolicy => write!(f, "PACKAGES POLICY"),
1136611380
ActionApplyType::PasswordPolicy => write!(f, "PASSWORD POLICY"),
1136711381
ActionApplyType::ProjectionPolicy => write!(f, "PROJECTION POLICY"),
1136811382
ActionApplyType::RowAccessPolicy => write!(f, "ROW ACCESS POLICY"),
1136911383
ActionApplyType::SessionPolicy => write!(f, "SESSION POLICY"),
11384+
ActionApplyType::StorageLifecyclePolicy => write!(f, "STORAGE LIFECYCLE POLICY"),
1137011385
ActionApplyType::Tag => write!(f, "TAG"),
1137111386
}
1137211387
}

‎src/keywords.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,7 @@ define_keywords!(
886886
PREPARE,
887887
PRESERVE,
888888
PRESET,
889+
PREVIEW,
889890
PREWHERE,
890891
PRIMARY,
891892
PRINT,

‎src/parser/mod.rs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20812,8 +20812,12 @@ impl<'a> Parser<'a> {
2081220812
Some(ActionCreateObjectType::FailoverGroup)
2081320813
} else if self.parse_keywords(&[Keyword::NETWORK, Keyword::POLICY]) {
2081420814
Some(ActionCreateObjectType::NetworkPolicy)
20815+
} else if self.parse_keywords(&[Keyword::ORGANIZATION, Keyword::PROFILE]) {
20816+
Some(ActionCreateObjectType::OrganizationProfile)
2081520817
} else if self.parse_keywords(&[Keyword::ORGANIZATION, Keyword::LISTING]) {
2081620818
Some(ActionCreateObjectType::OrganiationListing)
20819+
} else if self.parse_keywords(&[Keyword::PREVIEW, Keyword::APPLICATION]) {
20820+
Some(ActionCreateObjectType::PreviewApplication)
2081720821
} else if self.parse_keywords(&[Keyword::REPLICATION, Keyword::GROUP]) {
2081820822
Some(ActionCreateObjectType::ReplicationGroup)
2081920823
} else if self.parse_keywords(&[Keyword::DATABASE, Keyword::ROLE]) {
@@ -20836,6 +20840,8 @@ impl<'a> Parser<'a> {
2083620840
Some(ActionCreateObjectType::Procedure)
2083720841
} else if self.parse_keyword(Keyword::INTEGRATION) {
2083820842
Some(ActionCreateObjectType::Integration)
20843+
} else if self.parse_keyword(Keyword::LISTING) {
20844+
Some(ActionCreateObjectType::Listing)
2083920845
} else if self.parse_keyword(Keyword::ROLE) {
2084020846
Some(ActionCreateObjectType::Role)
2084120847
} else if self.parse_keyword(Keyword::SCHEMA) {
@@ -20884,6 +20890,10 @@ impl<'a> Parser<'a> {
2088420890
Ok(ActionApplyType::RowAccessPolicy)
2088520891
} else if self.parse_keywords(&[Keyword::SESSION, Keyword::POLICY]) {
2088620892
Ok(ActionApplyType::SessionPolicy)
20893+
} else if self.parse_keywords(&[Keyword::STORAGE, Keyword::LIFECYCLE, Keyword::POLICY]) {
20894+
Ok(ActionApplyType::StorageLifecyclePolicy)
20895+
} else if self.parse_keyword(Keyword::CONTACT) {
20896+
Ok(ActionApplyType::Contact)
2088720897
} else if self.parse_keyword(Keyword::TAG) {
2088820898
Ok(ActionApplyType::Tag)
2088920899
} else {

0 commit comments

Comments
 (0)