Skip to content

Commit 3469bbf

Browse files
committed
progress
1 parent 600f273 commit 3469bbf

File tree

3 files changed

+82
-27
lines changed

3 files changed

+82
-27
lines changed

crates/pgls_diagnostics_categories/src/categories.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,28 +48,28 @@ define_categories! {
4848
"lint/safety/transactionNesting": "https://pg-language-server.com/latest/rules/transaction-nesting",
4949
// end lint rules
5050
// splinter rules start
51-
"splinter/performance/authRlsInitplan": "https://supabase.com/docs/guides/database/database-linter?lint=0003_auth_rls_initplan",
52-
"splinter/performance/duplicateIndex": "https://supabase.com/docs/guides/database/database-linter?lint=0009_duplicate_index",
53-
"splinter/performance/multiplePermissivePolicies": "https://supabase.com/docs/guides/database/database-linter?lint=0006_multiple_permissive_policies",
54-
"splinter/performance/noPrimaryKey": "https://supabase.com/docs/guides/database/database-linter?lint=0004_no_primary_key",
55-
"splinter/performance/tableBloat": "https://supabase.com/docs/guides/database/database-linter",
56-
"splinter/performance/unindexedForeignKeys": "https://supabase.com/docs/guides/database/database-linter?lint=0001_unindexed_foreign_keys",
57-
"splinter/performance/unusedIndex": "https://supabase.com/docs/guides/database/database-linter?lint=0005_unused_index",
58-
"splinter/security/authUsersExposed": "https://supabase.com/docs/guides/database/database-linter?lint=0002_auth_users_exposed",
59-
"splinter/security/extensionInPublic": "https://supabase.com/docs/guides/database/database-linter?lint=0014_extension_in_public",
60-
"splinter/security/extensionVersionsOutdated": "https://supabase.com/docs/guides/database/database-linter?lint=0022_extension_versions_outdated",
61-
"splinter/security/fkeyToAuthUnique": "https://supabase.com/docs/guides/database/database-linter",
62-
"splinter/security/foreignTableInApi": "https://supabase.com/docs/guides/database/database-linter?lint=0017_foreign_table_in_api",
63-
"splinter/security/functionSearchPathMutable": "https://supabase.com/docs/guides/database/database-linter?lint=0011_function_search_path_mutable",
64-
"splinter/security/insecureQueueExposedInApi": "https://supabase.com/docs/guides/database/database-linter?lint=0019_insecure_queue_exposed_in_api",
65-
"splinter/security/materializedViewInApi": "https://supabase.com/docs/guides/database/database-linter?lint=0016_materialized_view_in_api",
66-
"splinter/security/policyExistsRlsDisabled": "https://supabase.com/docs/guides/database/database-linter?lint=0007_policy_exists_rls_disabled",
67-
"splinter/security/rlsDisabledInPublic": "https://supabase.com/docs/guides/database/database-linter?lint=0013_rls_disabled_in_public",
68-
"splinter/security/rlsEnabledNoPolicy": "https://supabase.com/docs/guides/database/database-linter?lint=0008_rls_enabled_no_policy",
69-
"splinter/security/rlsReferencesUserMetadata": "https://supabase.com/docs/guides/database/database-linter?lint=0015_rls_references_user_metadata",
70-
"splinter/security/securityDefinerView": "https://supabase.com/docs/guides/database/database-linter?lint=0010_security_definer_view",
71-
"splinter/security/unsupportedRegTypes": "https://supabase.com/docs/guides/database/database-linter?lint=unsupported_reg_types",
72-
"splinter/unknown/unknown": "https://supabase.com/docs/guides/database/database-linter",
51+
"splinter/performance/authRlsInitplan": "https://supabase.com/docs/guides/database/database-advisors?lint=0003_auth_rls_initplan",
52+
"splinter/performance/duplicateIndex": "https://supabase.com/docs/guides/database/database-advisors?lint=0009_duplicate_index",
53+
"splinter/performance/multiplePermissivePolicies": "https://supabase.com/docs/guides/database/database-advisors?lint=0006_multiple_permissive_policies",
54+
"splinter/performance/noPrimaryKey": "https://supabase.com/docs/guides/database/database-advisors?lint=0004_no_primary_key",
55+
"splinter/performance/tableBloat": "https://supabase.com/docs/guides/database/database-advisors",
56+
"splinter/performance/unindexedForeignKeys": "https://supabase.com/docs/guides/database/database-advisors?lint=0001_unindexed_foreign_keys",
57+
"splinter/performance/unusedIndex": "https://supabase.com/docs/guides/database/database-advisors?lint=0005_unused_index",
58+
"splinter/security/authUsersExposed": "https://supabase.com/docs/guides/database/database-advisors?lint=0002_auth_users_exposed",
59+
"splinter/security/extensionInPublic": "https://supabase.com/docs/guides/database/database-advisors?lint=0014_extension_in_public",
60+
"splinter/security/extensionVersionsOutdated": "https://supabase.com/docs/guides/database/database-advisors?lint=0022_extension_versions_outdated",
61+
"splinter/security/fkeyToAuthUnique": "https://supabase.com/docs/guides/database/database-advisors",
62+
"splinter/security/foreignTableInApi": "https://supabase.com/docs/guides/database/database-advisors?lint=0017_foreign_table_in_api",
63+
"splinter/security/functionSearchPathMutable": "https://supabase.com/docs/guides/database/database-advisors?lint=0011_function_search_path_mutable",
64+
"splinter/security/insecureQueueExposedInApi": "https://supabase.com/docs/guides/database/database-advisors?lint=0019_insecure_queue_exposed_in_api",
65+
"splinter/security/materializedViewInApi": "https://supabase.com/docs/guides/database/database-advisors?lint=0016_materialized_view_in_api",
66+
"splinter/security/policyExistsRlsDisabled": "https://supabase.com/docs/guides/database/database-advisors?lint=0007_policy_exists_rls_disabled",
67+
"splinter/security/rlsDisabledInPublic": "https://supabase.com/docs/guides/database/database-advisors?lint=0013_rls_disabled_in_public",
68+
"splinter/security/rlsEnabledNoPolicy": "https://supabase.com/docs/guides/database/database-advisors?lint=0008_rls_enabled_no_policy",
69+
"splinter/security/rlsReferencesUserMetadata": "https://supabase.com/docs/guides/database/database-advisors?lint=0015_rls_references_user_metadata",
70+
"splinter/security/securityDefinerView": "https://supabase.com/docs/guides/database/database-advisors?lint=0010_security_definer_view",
71+
"splinter/security/unsupportedRegTypes": "https://supabase.com/docs/guides/database/database-advisors?lint=unsupported_reg_types",
72+
"splinter/unknown/unknown": "https://supabase.com/docs/guides/database/database-advisors",
7373
// splinter rules end
7474
;
7575
// General categories

crates/pgls_splinter/build.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@ use std::path::Path;
55
// Update this commit SHA to pull in a new version of splinter.sql
66
const SPLINTER_COMMIT_SHA: &str = "27ea2ece65464213e466cd969cc61b6940d16219";
77

8+
// Rules that work on any PostgreSQL database
9+
const GENERIC_RULES: &[&str] = &[
10+
"unindexed_foreign_keys",
11+
"no_primary_key",
12+
"unused_index",
13+
"multiple_permissive_policies",
14+
"policy_exists_rls_disabled",
15+
"rls_enabled_no_policy",
16+
"duplicate_index",
17+
"extension_in_public",
18+
"table_bloat",
19+
"extension_versions_outdated",
20+
"function_search_path_mutable",
21+
"unsupported_reg_types",
22+
];
23+
824
// Rules that require Supabase-specific infrastructure (auth schema, anon/authenticated roles, pgrst.db_schemas)
925
const SUPABASE_ONLY_RULES: &[&str] = &[
1026
"auth_users_exposed",
@@ -76,7 +92,7 @@ fn download_and_process_sql(generic_dest: &Path, supabase_dest: &Path) {
7692
// Add "!" suffix to column aliases for sqlx non-null checking
7793
processed_content = add_not_null_markers(&processed_content);
7894

79-
// Split into generic and Supabase-specific queries
95+
// Split into generic and Supabase-specific queries (validates categorization)
8096
let (generic_queries, supabase_queries) = split_queries(&processed_content);
8197

8298
// Write to destination files
@@ -129,6 +145,21 @@ fn add_not_null_markers(content: &str) -> String {
129145
result
130146
}
131147

148+
/// Extract rule name from a query fragment
149+
fn extract_rule_name_from_query(query: &str) -> String {
150+
// Look for pattern 'rule_name' as "name!"
151+
for line in query.lines() {
152+
if line.contains(" as \"name!\"") {
153+
if let Some(start) = line.rfind('\'') {
154+
if let Some(prev_quote) = line[..start].rfind('\'') {
155+
return line[prev_quote + 1..start].to_string();
156+
}
157+
}
158+
}
159+
}
160+
"unknown".to_string()
161+
}
162+
132163
fn split_queries(content: &str) -> (String, String) {
133164
// Split the union all queries based on rule names
134165
let queries: Vec<&str> = content.split("union all").collect();
@@ -142,10 +173,27 @@ fn split_queries(content: &str) -> (String, String) {
142173
.iter()
143174
.any(|rule| query.contains(&format!("'{rule}' as \"name!\"")));
144175

176+
let is_generic = GENERIC_RULES
177+
.iter()
178+
.any(|rule| query.contains(&format!("'{rule}' as \"name!\"")));
179+
145180
if is_supabase {
146181
supabase_queries.push(query);
147-
} else {
182+
} else if is_generic {
148183
generic_queries.push(query);
184+
} else {
185+
// Extract rule name for better error message
186+
let rule_name = extract_rule_name_from_query(query);
187+
panic!(
188+
"Found unknown Splinter rule that is not categorized: {rule_name:?}\n\
189+
Please add this rule to either GENERIC_RULES or SUPABASE_ONLY_RULES in build.rs.\n\
190+
\n\
191+
Guidelines:\n\
192+
- GENERIC_RULES: Rules that work on any PostgreSQL database\n\
193+
- SUPABASE_ONLY_RULES: Rules that require Supabase infrastructure (auth schema, roles, pgrst.db_schemas)\n\
194+
\n\
195+
This prevents new Supabase-specific rules from breaking linting on non-Supabase databases."
196+
);
149197
}
150198
}
151199

xtask/codegen/src/generate_splinter.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,20 @@ fn extract_rules_from_sql(content: &str) -> Result<BTreeMap<String, RuleInfo>> {
7070
let cats = categories
7171
.with_context(|| format!("Failed to find categories for rule '{name}'"))?;
7272

73+
// Convert old database-linter URLs to database-advisors
74+
let updated_url = remediation_url
75+
.map(|url| url.replace("/database-linter", "/database-advisors"))
76+
.or(Some(
77+
"https://supabase.com/docs/guides/database/database-advisors".to_string(),
78+
));
79+
7380
rules.insert(
7481
name.clone(),
7582
RuleInfo {
7683
snake_case: name.clone(),
7784
camel_case: snake_to_camel_case(&name),
7885
categories: cats,
79-
url: remediation_url,
86+
url: updated_url,
8087
},
8188
);
8289
}
@@ -90,7 +97,7 @@ fn extract_rules_from_sql(content: &str) -> Result<BTreeMap<String, RuleInfo>> {
9097
snake_case: "unknown".to_string(),
9198
camel_case: "unknown".to_string(),
9299
categories: vec!["UNKNOWN".to_string()],
93-
url: None,
100+
url: Some("https://supabase.com/docs/guides/database/database-advisors".to_string()),
94101
},
95102
);
96103

@@ -184,7 +191,7 @@ fn update_categories_file(rules: BTreeMap<String, RuleInfo>) -> Result<()> {
184191
.as_ref()
185192
.filter(|u| is_valid_url(u))
186193
.map(|u| u.as_str())
187-
.unwrap_or("https://supabase.com/docs/guides/database/database-linter");
194+
.unwrap_or("https://supabase.com/docs/guides/database/database-advisors");
188195

189196
(
190197
group.clone(),

0 commit comments

Comments
 (0)