Skip to content

Commit

Permalink
Disable the file loader
Browse files Browse the repository at this point in the history
Replace it with a no-op loader. Add tests to be sure it actually does
its thing; without it added to the compiler, the test returns a file not
found error! Long-term it'd be nice to prevent it from being compiled at
all; see santhosh-tekuri/boon#12 for the feature request.

While at it, update the `error!()` and `info!()` calls to include the
failure reason. The magic `:#` suffix in the format does it.
  • Loading branch information
theory committed Apr 12, 2024
1 parent e0856b4 commit 25b20f2
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 13 deletions.
45 changes: 38 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use boon::{CompileError, Compiler, Schemas};
use pgrx::prelude::*;
use pgrx::{Json, JsonB, VariadicArray};
use serde_json::Value;
use std::error::Error;

pgrx::pg_module_magic!();

Expand All @@ -24,7 +25,7 @@ macro_rules! run_compiles {
($x:expr, $y:expr) => {
match compiles($x, $y) {
Err(e) => {
info!("{e}");
info!("{e:#}");
false
}
Ok(()) => true,
Expand All @@ -36,7 +37,7 @@ macro_rules! run_compiles {
macro_rules! run_validate {
($x:expr, $y:expr, $z:expr) => {
match validate($x, $y, $z) {
Err(e) => error!("{e}"),
Err(e) => error!("{e:#}"),
Ok(ok) => ok,
}
};
Expand Down Expand Up @@ -236,6 +237,8 @@ extern "C" fn _PG_init() {
fn new_compiler(id: &str, schemas: &[Value]) -> Result<Compiler, CompileError> {
let mut compiler = Compiler::new();
compiler.set_default_draft(GUC.get().into());
// Replace file loader to prevent boon from accessing the file system.
compiler.register_url_loader("file", Box::new(FailLoader));

for (i, s) in schemas.iter().enumerate() {
let sid = if let Value::String(s) = &s["$id"] {
Expand Down Expand Up @@ -281,7 +284,7 @@ fn validate(id: &str, schemas: &[Value], instance: Value) -> Result<bool, Compil
Err(e) => Err(e),
Ok(index) => {
if let Err(e) = schemas.validate(&instance, index) {
info!("{e}");
info!("{e:#}");
return Ok(false);
}
Ok(true)
Expand All @@ -291,6 +294,18 @@ fn validate(id: &str, schemas: &[Value], instance: Value) -> Result<bool, Compil
}
}

// FailLoader always fails to load the URL for its scheme. Used to replace the
// default "file" loader to prevent boon from trying to read the file system.
struct FailLoader;

impl boon::UrlLoader for FailLoader {
fn load(&self, url: &str) -> Result<Value, Box<dyn Error>> {
Err(Box::new(boon::CompileError::UnsupportedUrlScheme {
url: url.to_string(),
}))
}
}

#[cfg(any(test, feature = "pg_test"))]
#[pg_schema]
mod tests {
Expand Down Expand Up @@ -387,7 +402,23 @@ mod tests {

// But no more.
let mut schemas = Schemas::new();
assert!(c.compile("file:test.json2", &mut schemas).is_err());
let err = c.compile("file:test.json2", &mut schemas);
assert!(err.is_err());

// Should not have attempted to read the file from the file system.
if let Err(e) = err {
assert!(e.source().is_some());
if let Some(e) = e.source() {
// We should have the unsupported scheme error from FailLoader.
assert_eq!("unsupported scheme in file:///test.json2", format!("{e}"));
} else {
// Shouldn't happen
unreachable!();
}
} else {
// Shouldn't happen
unreachable!();
}

// Test an invalid draft.
assert!(new_compiler(&id, &[json!({"$schema": "lol"})]).is_err());
Expand Down Expand Up @@ -627,7 +658,7 @@ mod tests {
.catch_when(PgSqlErrorCode::ERRCODE_INTERNAL_ERROR, |e| {
if let PostgresError(e) = e {
assert_eq!(
"file:///schema.json is not valid against metaschema",
"file:///schema.json is not valid against metaschema: jsonschema validation failed with https://json-schema.org/draft/2020-12/schema#\n- at '/type': anyOf failed\n - at '/type': value must be one of 'array', 'boolean', 'integer', 'null', 'number', 'object', 'string'\n - at '/type': want array, but got string",
e.message(),
);
}
Expand Down Expand Up @@ -693,7 +724,7 @@ mod tests {
.catch_when(PgSqlErrorCode::ERRCODE_INTERNAL_ERROR, |e| {
if let PostgresError(e) = e {
assert_eq!(
"file:///schema.json is not valid against metaschema",
"file:///schema.json is not valid against metaschema: jsonschema validation failed with https://json-schema.org/draft/2020-12/schema#\n- at '/type': anyOf failed\n - at '/type': value must be one of 'array', 'boolean', 'integer', 'null', 'number', 'object', 'string'\n - at '/type': want array, but got string",
e.message(),
);
}
Expand Down Expand Up @@ -811,7 +842,7 @@ mod tests {
.catch_when(PgSqlErrorCode::ERRCODE_INTERNAL_ERROR, |e| {
if let PostgresError(e) = e {
assert_eq!(
"file:///lol.json is not valid against metaschema",
"file:///lol.json is not valid against metaschema: jsonschema validation failed with https://json-schema.org/draft/2020-12/schema#\n- at '/type': anyOf failed\n - at '/type': value must be one of 'array', 'boolean', 'integer', 'null', 'number', 'object', 'string'\n - at '/type': want array, but got string",
e.message(),
);
}
Expand Down
14 changes: 8 additions & 6 deletions test/expected/is_valid.out
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ SELECT jsonschema_is_valid('{"type": "object"}'::jsonb);

-- Invalid schema
SELECT jsonschema_is_valid('["not a schema"]'::json);
INFO: file:///schema.json is not valid against metaschema
INFO: file:///schema.json is not valid against metaschema: jsonschema validation failed with https://json-schema.org/draft/2020-12/schema#
- at '': want boolean or object, but got array
jsonschema_is_valid
---------------------
f
(1 row)

SELECT jsonschema_is_valid('["not a schema"]'::jsonb);
INFO: file:///schema.json is not valid against metaschema
INFO: file:///schema.json is not valid against metaschema: jsonschema validation failed with https://json-schema.org/draft/2020-12/schema#
- at '': want boolean or object, but got array
jsonschema_is_valid
---------------------
f
Expand Down Expand Up @@ -72,14 +74,14 @@ SELECT jsonschema_is_valid(:'user_schema_id', :'addr_schema'::jsonb, :'user_sche

-- Invalid
SELECT jsonschema_is_valid('foo', :'addr_schema'::json);
INFO: error loading file:///Users/david/.pgenv/pgsql-16.2/data/foo
INFO: error loading file:///Users/david/.pgenv/pgsql-16.2/data/foo: unsupported scheme in file:///Users/david/.pgenv/pgsql-16.2/data/foo
jsonschema_is_valid
---------------------
f
(1 row)

SELECT jsonschema_is_valid('bar', :'addr_schema'::jsonb);
INFO: error loading file:///Users/david/.pgenv/pgsql-16.2/data/bar
INFO: error loading file:///Users/david/.pgenv/pgsql-16.2/data/bar: unsupported scheme in file:///Users/david/.pgenv/pgsql-16.2/data/bar
jsonschema_is_valid
---------------------
f
Expand All @@ -100,14 +102,14 @@ SELECT jsonschema_is_valid('nonesuch', '{"type": "object"}'::jsonb);

-- No such ID
SELECT jsonschema_is_valid('file:///nonesuch', :'addr_schema'::json);
INFO: error loading file:///nonesuch
INFO: error loading file:///nonesuch: unsupported scheme in file:///nonesuch
jsonschema_is_valid
---------------------
f
(1 row)

SELECT jsonschema_is_valid('file:///nonesuch', :'addr_schema'::jsonb);
INFO: error loading file:///nonesuch
INFO: error loading file:///nonesuch: unsupported scheme in file:///nonesuch
jsonschema_is_valid
---------------------
f
Expand Down

0 comments on commit 25b20f2

Please sign in to comment.