Skip to content

Commit c63065e

Browse files
committed
feat(gb-9105): schema/table allow/denylist
1 parent 9a9766b commit c63065e

File tree

12 files changed

+9909
-8
lines changed

12 files changed

+9909
-8
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/postgres/CHANGELOG.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Changelog
2+
3+
All notable changes to the Grafbase PostgreSQL CLI tool will be documented in this file.
4+
5+
## [0.3.7] - 2025-05-22
6+
7+
### Added
8+
- Schema and table filtering with allowlist/denylist options
9+
- Added `schema_allowlist` and `schema_denylist` for global schema filtering
10+
- Added `table_allowlist` and `table_denylist` for filtering tables within a schema
11+
- Denylist takes precedence over allowlist when both are specified
12+
13+
## [0.3.6] - 2025-05-21
14+
15+
### Added
16+
- Support for `@derive` and `@is` directives in introspection
17+
- Added ability to define cross-database joins
18+
19+
## [0.3.5] - 2025-05-21
20+
21+
### Fixed
22+
- Fixed installer URL in documentation
23+
- Fixed typo in composite-schemas spec URL in postgres-introspection
24+
25+
## [0.3.4] - 2025-05-15
26+
27+
### Changed
28+
- Improved documentation clarity
29+
- Removed "you must build" text from documentation
30+
31+
## [0.3.3] - 2025-05-14
32+
33+
### Added
34+
- Reduced the amount of unused types in introspection output
35+
- Added more scalar types for PostgreSQL in the introspection library
36+
37+
## [0.3.2] - 2025-05-09
38+
39+
### Added
40+
- Support for cursor-based pagination in the generated schema
41+
42+
## [0.3.1] - 2025-05-07
43+
44+
### Added
45+
- Installation script for easier setup of the CLI tool
46+
47+
### Fixed
48+
- Fixed enable/disable mutations functionality
49+
- Fixed installation documentation links
50+
51+
## [0.3.0] - 2025-05-07
52+
53+
### Added
54+
- Support for PostgreSQL views
55+
- Configuration options for enabling/disabling queries or mutations
56+
- Added PostgreSQL mTLS validation support
57+
58+
### Fixed
59+
- Fixed CLI behavior when running without .env and config files
60+
61+
## [0.2.0] - 2025-05-05
62+
63+
### Added
64+
- Comprehensive README with usage examples
65+
- Release workflow for CLI binaries
66+
- Improved command-line interface
67+
- Support for lookup functionality for federation
68+
69+
## [0.1.0] - 2025-04-04
70+
71+
### Added
72+
- Initial implementation of the PostgreSQL CLI tool
73+
- Basic introspection capabilities for PostgreSQL databases
74+
- GraphQL SDL generation for tables and relationships

cli/postgres/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "grafbase-postgres"
3-
version = "0.3.6"
3+
version = "0.3.7"
44
edition = "2024"
55
license = "Apache-2.0"
66

cli/postgres/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ enable_mutations = true
127127
# Defaults to true if you omit this setting.
128128
enable_queries = true
129129

130+
# Schema allowlist: An array of schema names to include in the introspection.
131+
# If provided, only schemas in this list will be included.
132+
# If empty, all schemas will be included (unless in the denylist).
133+
schema_allowlist = []
134+
135+
# Schema denylist: An array of schema names to exclude from the introspection.
136+
# Schemas in this list will be excluded even if they appear in the allowlist.
137+
# This takes precedence over the schema_allowlist.
138+
schema_denylist = []
139+
130140
# Configure schemas for this database. Key-value from schema name to configuration.
131141
schemas = {}
132142
```
@@ -144,6 +154,16 @@ enable_mutations = true
144154
# Takes precedence over the global setting. Defaults to true if you omit this setting.
145155
enable_queries = true
146156

157+
# Table allowlist: An array of table names to include in the introspection.
158+
# If provided, only tables in this list will be included for this schema.
159+
# If empty, all tables will be included (unless in the denylist).
160+
table_allowlist = []
161+
162+
# Table denylist: An array of table names to exclude from the introspection.
163+
# Tables in this list will be excluded even if they appear in the allowlist.
164+
# This takes precedence over the table_allowlist.
165+
table_denylist = []
166+
147167
# Configure views for this schema.
148168
views = {}
149169

@@ -431,6 +451,44 @@ type User @key(fields: "id") {
431451
}
432452
```
433453

454+
### Schema and Table Filtering
455+
456+
You can control which database schemas and tables are included in the introspection process using allowlist and denylist options.
457+
458+
#### Schema Filtering
459+
460+
You can include or exclude specific database schemas using the following options:
461+
462+
- `schema_allowlist`: An array of schema names to include. If provided, only schemas in this list will be included in the introspection.
463+
- `schema_denylist`: An array of schema names to exclude. Schemas in this list will be excluded from introspection, even if they appear in the allowlist.
464+
465+
```toml
466+
# Example of schema filtering in config.toml
467+
extension_url = "https://grafbase.com/extensions/postgres/0.4.7"
468+
schema_allowlist = ["public", "app"]
469+
schema_denylist = ["internal"]
470+
```
471+
472+
#### Table Filtering
473+
474+
Within each schema, you can include or exclude specific tables using these options:
475+
476+
- `table_allowlist`: An array of table names to include. If provided, only tables in this list will be included for that schema.
477+
- `table_denylist`: An array of table names to exclude. Tables in this list will be excluded, even if they appear in the allowlist.
478+
479+
```toml
480+
# Example of table filtering in config.toml
481+
extension_url = "https://grafbase.com/extensions/postgres/0.4.7"
482+
483+
[schemas.public]
484+
table_allowlist = ["users", "posts"]
485+
486+
[schemas.internal]
487+
table_denylist = ["audit_logs", "system_metrics"]
488+
```
489+
490+
When both allowlist and denylist are specified, the denylist takes precedence. For example, if a table is included in both `table_allowlist` and `table_denylist`, it will be excluded from the introspection.
491+
434492
## License
435493

436494
Apache-2.0

cli/postgres/install.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ if [[ ${OS:-} = Windows_NT ]]; then
66
exit 1
77
fi
88

9-
LATEST_VERSION="0.3.6"
9+
LATEST_VERSION="0.3.7"
1010

1111
# Reset
1212
Color_Off=''

crates/postgres-introspection/src/config.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ pub struct Config {
3535
/// Configuration details for each schema within the database, keyed by schema name.
3636
#[serde(default)]
3737
pub schemas: BTreeMap<String, SchemaConfig>,
38+
/// Optional list of schemas to include in the GraphQL schema.
39+
/// If this list is populated, only schemas in this list will be included.
40+
/// If empty, all schemas will be included.
41+
#[serde(default)]
42+
pub schema_allowlist: Vec<String>,
43+
/// Optional list of schemas to exclude from the GraphQL schema.
44+
/// If this list is populated, schemas in this list will be excluded even if they are in the allowlist.
45+
/// This takes precedence over the allowlist.
46+
#[serde(default)]
47+
pub schema_denylist: Vec<String>,
3848
}
3949

4050
impl Config {
@@ -84,6 +94,24 @@ impl Config {
8494
.unwrap_or(self.enable_queries)
8595
}
8696
}
97+
98+
pub fn is_schema_included(&self, schema: &str) -> bool {
99+
!self.schema_denylist.contains(&schema.to_string())
100+
&& (self.schema_allowlist.is_empty() || self.schema_allowlist.contains(&schema.to_string()))
101+
}
102+
103+
/// Determines whether a table is included in the GraphQL schema based on the configuration.
104+
/// A table is included if:
105+
/// 1. It's not in the schema's table_denylist
106+
/// 2. Either the schema's table_allowlist is empty or the table is in the allowlist
107+
pub fn is_table_included(&self, schema: &str, table: &str) -> bool {
108+
let Some(schema_config) = self.schemas.get(schema) else {
109+
return true;
110+
};
111+
112+
!schema_config.table_denylist.contains(&table.to_string())
113+
&& (schema_config.table_allowlist.is_empty() || schema_config.table_allowlist.contains(&table.to_string()))
114+
}
87115
}
88116

89117
/// Returns the default database name.
@@ -110,6 +138,16 @@ pub struct SchemaConfig {
110138
/// Configuration overrides for each table within the schema, keyed by table name.
111139
#[serde(default)]
112140
pub tables: BTreeMap<String, TableConfig>,
141+
/// Optional list of tables to include in the GraphQL schema.
142+
/// If this list is populated, only tables in this list will be included.
143+
/// If empty, all tables will be included.
144+
#[serde(default)]
145+
pub table_allowlist: Vec<String>,
146+
/// Optional list of tables to exclude from the GraphQL schema.
147+
/// If this list is populated, tables in this list will be excluded even if they are in the allowlist.
148+
/// This takes precedence over the allowlist.
149+
#[serde(default)]
150+
pub table_denylist: Vec<String>,
113151
}
114152

115153
#[derive(Deserialize, Debug)]

crates/postgres-introspection/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ mod tables;
2323
pub async fn introspect(conn: &mut sqlx::PgConnection, config: Config) -> anyhow::Result<String> {
2424
let mut database_definition = DatabaseDefinition::new(config.database_name.clone());
2525

26-
schemas::introspect_database(conn, &mut database_definition).await?;
26+
schemas::introspect_database(conn, &config, &mut database_definition).await?;
2727
enums::introspect_database(conn, &mut database_definition).await?;
28-
tables::introspect_database(conn, &mut database_definition).await?;
28+
tables::introspect_database(conn, &config, &mut database_definition).await?;
2929
columns::introspect_database(conn, &config, &mut database_definition).await?;
3030
foreign_keys::introspect_database(conn, &config, &mut database_definition).await?;
3131
keys::introspect_database(conn, &config, &mut database_definition).await?;

crates/postgres-introspection/src/schemas.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
use grafbase_database_definition::DatabaseDefinition;
22
use sqlx::{PgConnection, Row};
33

4+
use crate::config::Config;
5+
46
pub(crate) async fn introspect_database(
57
conn: &mut PgConnection,
8+
config: &Config,
69
database_definition: &mut DatabaseDefinition,
710
) -> anyhow::Result<()> {
811
let query = "SELECT nspname AS name FROM pg_namespace WHERE nspname <> ALL ($1) ORDER BY name";
@@ -13,7 +16,11 @@ pub(crate) async fn introspect_database(
1316
.await?;
1417

1518
for row in rows {
16-
database_definition.push_schema(row.get(0));
19+
let schema_name: String = row.get(0);
20+
21+
if config.is_schema_included(&schema_name) {
22+
database_definition.push_schema(row.get(0));
23+
}
1724
}
1825

1926
Ok(())

crates/postgres-introspection/src/tables.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use crate::config::Config;
12
use grafbase_database_definition::{DatabaseDefinition, RelationKind, Table};
23
use sqlx::{PgConnection, Row};
34

45
pub(crate) async fn introspect_database(
56
conn: &mut PgConnection,
7+
config: &Config,
68
database_definition: &mut DatabaseDefinition,
79
) -> anyhow::Result<()> {
810
let query = indoc::indoc! {r#"
@@ -30,7 +32,15 @@ pub(crate) async fn introspect_database(
3032
.await?;
3133

3234
for row in rows {
33-
let Some(schema_id) = database_definition.get_schema_id(row.get(1)) else {
35+
let schema_name: String = row.get(1);
36+
let table_name: String = row.get(0);
37+
38+
let Some(schema_id) = database_definition.get_schema_id(&schema_name) else {
39+
continue;
40+
};
41+
42+
// Skip tables that are not in the allowlist or are in the denylist
43+
if !config.is_table_included(&schema_name, &table_name) {
3444
continue;
3545
};
3646

@@ -41,7 +51,7 @@ pub(crate) async fn introspect_database(
4151
_ => unreachable!(),
4252
};
4353

44-
let mut table = Table::<String>::new(schema_id, row.get(0), kind, None);
54+
let mut table = Table::<String>::new(schema_id, table_name, kind, None);
4555

4656
if let Some(description) = row.get(2) {
4757
table.set_description(description);

extensions/postgres/CHANGELOG.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Changelog
2+
3+
All notable changes to the Postgres extension will be documented in this file.
4+
5+
## [0.4.9] - 2025-05-21
6+
7+
### Fixed
8+
- Fixed issue with aliases in queries and mutations
9+
10+
## [0.4.8] - 2025-05-21
11+
12+
### Added
13+
- Support for `@derive` and `@is` directives in introspection
14+
- Added ability to define cross-database joins
15+
16+
## [0.4.7] - 2025-05-16
17+
18+
### Fixed
19+
- Fixed typo in composite-schemas spec URL
20+
- Fixed cursor generation to not generate cursors when not needed
21+
22+
## [0.4.6] - 2025-05-15
23+
24+
### Fixed
25+
- Fixed naming issue in pagination filters
26+
- Fixed ordering for next/previous cursors when moving backwards
27+
- Fixed newlines with long base64 cursors
28+
- Improved population of hasNextPage and hasPreviousPage
29+
30+
## [0.4.5] - 2025-05-14
31+
32+
### Added
33+
- Added more scalar types for Postgres
34+
- Reduced the amount of unused types in introspection
35+
36+
## [0.4.4] - 2025-05-09
37+
38+
### Added
39+
- Added support for proper cursor-based pagination
40+
41+
## [0.4.3] - 2025-05-07
42+
43+
### Fixed
44+
- Fixed enable/disable mutations functionality
45+
46+
## [0.4.2] - 2025-05-07
47+
48+
### Fixed
49+
- Fixed Windows build issues
50+
51+
## [0.4.1] - 2025-05-06
52+
53+
### Added
54+
- Added PostgreSQL mTLS validation
55+
56+
## [0.4.0] - 2025-05-05
57+
58+
### Added
59+
- Added support for PostgreSQL views
60+
- Configuration options for enabling/disabling queries or mutations
61+
62+
## [0.3.0] - 2025-04-28
63+
64+
### Added
65+
- Added lookup support for federation
66+
- Improved extension description
67+
68+
## [0.2.0] - 2025-04-25
69+
70+
### Changed
71+
- Various tweaks for consistency in API design
72+
73+
## [0.1.1] - 2025-04-04
74+
75+
### Added
76+
- Initial public release with basic functionality
77+
78+
## [0.1.0] - 2025-04-04
79+
80+
### Added
81+
- Initial implementation of the Postgres extension

0 commit comments

Comments
 (0)