1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
/*!
Test Postgres-compatible statements against a set of CORS-like rules.
## Why
Postgres has a rich `ROLE` system for managing privileges around data in a database.
But those privileges are often too permissive by default, and are difficult to restrict with by statement or function name.
[`postguard`](#) provides a [`Guard`] statement analyzer for protecting databases from malicious or invalid queries.
This [`Guard`] can be used in any Rust application that has access to statements (perhaps from untrusted sources) before they are run.
Under the hood, [`postguard`](#) uses the [`libpg_query`](https://github.com/pganalyze/libpg_query) library to parse queries down to a syntax tree
before checking the entire tree for disallowed nodes.
## Usage
```rust
use postguard::{AllowedFunctions, AllowedStatements, Command, Guard};
// If AllowedFunctions and AllowedStatements both are set to their 'All' variants
// then no parsing is done and all statements pass the guard
#[test]
fn it_does_nothing_by_default() {
Guard::new(AllowedStatements::All, AllowedFunctions::All)
.guard("create table test (id serial primary key)")
.expect("all statements are permitted by default");
}
// Statements are checked against the list of allowed statements when a 'List' variant
// is provided. Statement-checking is done recursively, so nested disallowed statements
// are also caught by the guard
#[test]
fn it_restricts_statements() {
let statement_guard = Guard::new(AllowedStatements::List(vec![Command::Select]));
statement_guard
.guard("create table test (id serial primary key)")
.expect_err("privileged statements are restricted");
statement_guard
.guard("select * from items")
.expect("select statements are permitted");
statement_guard
.guard("insert into items default values")
.expect_err("commands in top-level queries are restricted");
statement_guard
.guard("
with cte as (
insert into items default values
returning id
)
select * from cte
")
.expect_err("disallowed commands in nested queries or expressions are restricted");
}
// Functions are also guarded by name. To disallow all functions, leave the 'List' empty.
#[test]
fn it_restricts_functions() {
let statement_guard = Guard::new(
AllowedStatements::List(vec![Command::Select]),
AllowedFunctions::List(vec!["uuid_generate_v4".to_string()])
);
statement_guard
.guard("select pg_sleep(1)")
.expect_err("built-in functions and stored procs are restricted");
statement_guard
.guard("select uuid_generate_v4() as id")
.expect("allowed functions are permitted");
}
```
*/
#![deny(missing_docs, unreachable_pub)]
mod error;
mod guard;
#[cfg(test)]
mod test;
pub use error::*;
pub use guard::*;