Files

79 lines
2.8 KiB
Rust

//! Print the permission model's schema as a plain `.sql` migration.
//!
//! A consumer whose migrations are files rather than a Rust `open()`
//! call — Supabase, sqlx, plain psql — needs the same DDL as text.
//! Emitting it from the same constants the library applies is the point:
//! two hand-maintained copies of an authorisation schema will diverge,
//! and the divergence will be discovered by something going wrong.
//!
//! ```text
//! cargo run -p trusty-policy-postgres --example emit_ddl > 0001_permission_model.sql
//! ```
//!
//! Pass a table and its scope column to additionally emit the policies
//! that put that table under enforcement:
//!
//! ```text
//! cargo run -p trusty-policy-postgres --example emit_ddl -- public.calendar resource_scope
//! ```
use trusty_policy_postgres::permits::DDL_FUNCTIONS;
use trusty_policy_postgres::schema::{DDL_SCHEMA_VERSION_UPSERT, DDL_V1, SCHEMA_VERSION};
use trusty_policy_postgres::store::policy_statements;
fn main() {
println!("-- Generated by `cargo run -p trusty-policy-postgres --example emit_ddl`.");
println!("-- Source of truth is trusty-policy-postgres; edit there, regenerate here.");
println!("-- Applying this by hand and by GrantStore::open must agree, so do not");
println!("-- edit this file directly.");
println!();
for stmt in DDL_V1 {
println!("{};", stmt.trim());
println!();
}
for stmt in DDL_FUNCTIONS {
println!("{};", stmt.trim());
println!();
}
// The library upserts this with a bind parameter; a file has no
// parameters, so the version is inlined. It is a constant, not
// input.
println!(
"{};",
DDL_SCHEMA_VERSION_UPSERT
.trim()
.replace("$1", &format!("'{SCHEMA_VERSION}'"))
);
println!();
let args: Vec<String> = std::env::args().skip(1).collect();
match args.as_slice() {
[] => {
println!("-- No table given, so no policies were emitted.");
println!("-- Installing this schema protects nothing on its own: a table is");
println!("-- guarded only once it has ENABLE + FORCE ROW LEVEL SECURITY and the");
println!("-- four policies. Re-run with a table and its scope column, e.g.");
println!("-- ... --example emit_ddl -- public.calendar resource_scope");
}
[table, column] => match policy_statements(table, column) {
Ok(stmts) => {
println!("-- Enforcement for {table}({column}).");
for stmt in stmts {
println!("{stmt}");
}
}
Err(e) => {
eprintln!("error: {e}");
std::process::exit(1);
}
},
_ => {
eprintln!("usage: emit_ddl [<schema.table> <scope_column>]");
std::process::exit(2);
}
}
}