From 25b20f2990d55971949a340d528cf04b9eece81b Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Fri, 12 Apr 2024 15:43:09 -0400 Subject: [PATCH] Disable the file loader 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. --- src/lib.rs | 45 ++++++++++++++++++++++++++++++++------ test/expected/is_valid.out | 14 +++++++----- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1da9e54..fce3a23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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!(); @@ -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, @@ -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, } }; @@ -236,6 +237,8 @@ extern "C" fn _PG_init() { fn new_compiler(id: &str, schemas: &[Value]) -> Result { 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"] { @@ -281,7 +284,7 @@ fn validate(id: &str, schemas: &[Value], instance: Value) -> Result Err(e), Ok(index) => { if let Err(e) = schemas.validate(&instance, index) { - info!("{e}"); + info!("{e:#}"); return Ok(false); } Ok(true) @@ -291,6 +294,18 @@ fn validate(id: &str, schemas: &[Value], instance: Value) -> Result Result> { + Err(Box::new(boon::CompileError::UnsupportedUrlScheme { + url: url.to_string(), + })) + } +} + #[cfg(any(test, feature = "pg_test"))] #[pg_schema] mod tests { @@ -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()); @@ -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(), ); } @@ -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(), ); } @@ -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(), ); } diff --git a/test/expected/is_valid.out b/test/expected/is_valid.out index f7e65b7..49d96c2 100644 --- a/test/expected/is_valid.out +++ b/test/expected/is_valid.out @@ -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 @@ -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 @@ -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