Skip to content

Commit

Permalink
fix: Changing base URI when $ref is present in drafts 7 and earlier
Browse files Browse the repository at this point in the history
Signed-off-by: Dmitry Dygalo <[email protected]>
  • Loading branch information
Stranger6667 committed Sep 11, 2024
1 parent ce678a1 commit 8cb04dd
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 14 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Fixed

- Changing base URI when `$ref` is present in drafts 7 and earlier.

## [0.18.2] - 2024-09-11

### Fixed
Expand Down
4 changes: 4 additions & 0 deletions bindings/python/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Fixed

- Changing base URI when `$ref` is present in drafts 7 and earlier.

## [0.18.2] - 2024-09-11

### Fixed
Expand Down
28 changes: 21 additions & 7 deletions jsonschema/src/compilation/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
compilation::DEFAULT_SCOPE,
paths::{JSONPointer, JsonPointerNode, PathChunkRef},
resolver::Resolver,
schemas,
schemas, Draft,
};
use serde_json::Value;
use std::{borrow::Cow, sync::Arc};
Expand Down Expand Up @@ -101,12 +101,26 @@ impl<'a> CompilationContext<'a> {
#[inline]
pub(crate) fn push(&'a self, schema: &Value) -> Result<Self, ParseError> {
if let Some(id) = schemas::id_of(self.config.draft(), schema) {
Ok(CompilationContext {
base_uri: self.base_uri.with_new_scope(id)?,
config: Arc::clone(&self.config),
resolver: Arc::clone(&self.resolver),
schema_path: self.schema_path.clone(),
})
if matches!(
self.config.draft(),
Draft::Draft4 | Draft::Draft6 | Draft::Draft7
) && schema.get("$ref").is_some()
{
// If `$ref` is present, then other keywords are ignored in Drafts 7 and earlier
Ok(CompilationContext {
base_uri: self.base_uri.clone(),
config: Arc::clone(&self.config),
resolver: Arc::clone(&self.resolver),
schema_path: self.schema_path.clone(),
})
} else {
Ok(CompilationContext {
base_uri: self.base_uri.with_new_scope(id)?,
config: Arc::clone(&self.config),
resolver: Arc::clone(&self.resolver),
schema_path: self.schema_path.clone(),
})
}
} else {
Ok(CompilationContext {
base_uri: self.base_uri.clone(),
Expand Down
34 changes: 33 additions & 1 deletion jsonschema/src/keywords/ref_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ impl Validate for RefValidator {
if let Some(sub_nodes) = self.sub_nodes.read().as_ref() {
return sub_nodes.is_valid(instance);
}
dbg!(777);
if let Ok((scope, resolved)) = self.resolver.resolve_fragment(
self.config.draft(),
&self.reference,
Expand Down Expand Up @@ -157,7 +158,7 @@ pub(crate) const fn supports_adjacent_validation(draft: Draft) -> bool {

#[cfg(test)]
mod tests {
use crate::{tests_util, JSONSchema};
use crate::{tests_util, Draft, JSONSchema};
use serde_json::{json, Value};
use test_case::test_case;

Expand Down Expand Up @@ -227,6 +228,37 @@ mod tests {
tests_util::is_valid(schema, instance);
}

#[test]
fn test_ref_prevents_sibling_id_from_changing_the_base_uri() {
let schema = json!({
"id": "http://localhost:1234/sibling_id/base/",
"definitions": {
"foo": {
"id": "http://localhost:1234/sibling_id/foo.json",
"type": "string"
},
"base_foo": {
"$comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json",
"id": "foo.json",
"type": "number"
}
},
"allOf": [
{
"$comment": "$ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json",
"id": "http://localhost:1234/sibling_id/",
"$ref": "foo.json"
}
]
});
let instance = json!("a");
let compiled = JSONSchema::options()
.with_draft(Draft::Draft4)
.compile(&schema)
.expect("Invalid schema");
tests_util::is_not_valid_with(&compiled, &instance);
}

#[test_case(
&json!({
"properties": {
Expand Down
12 changes: 6 additions & 6 deletions jsonschema/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ pub(crate) mod tests_util {
use crate::ValidationError;
use serde_json::Value;

fn is_not_valid_inner(compiled: &JSONSchema, instance: &Value) {
pub(crate) fn is_not_valid_with(compiled: &JSONSchema, instance: &Value) {
assert!(
!compiled.is_valid(instance),
"{} should not be valid (via is_valid)",
Expand All @@ -153,7 +153,7 @@ pub(crate) mod tests_util {

pub(crate) fn is_not_valid(schema: &Value, instance: &Value) {
let compiled = JSONSchema::compile(schema).unwrap();
is_not_valid_inner(&compiled, instance)
is_not_valid_with(&compiled, instance)
}

#[cfg(any(feature = "draft201909", feature = "draft202012"))]
Expand All @@ -162,7 +162,7 @@ pub(crate) mod tests_util {
.with_draft(draft)
.compile(schema)
.unwrap();
is_not_valid_inner(&compiled, instance)
is_not_valid_with(&compiled, instance)
}

pub(crate) fn expect_errors(schema: &Value, instance: &Value, errors: &[&str]) {
Expand All @@ -177,7 +177,7 @@ pub(crate) mod tests_util {
)
}

fn is_valid_inner(compiled: &JSONSchema, instance: &Value) {
pub(crate) fn is_valid_with(compiled: &JSONSchema, instance: &Value) {
if let Err(mut errors) = compiled.validate(instance) {
let first = errors.next().expect("Errors iterator is empty");
panic!(
Expand All @@ -199,7 +199,7 @@ pub(crate) mod tests_util {

pub(crate) fn is_valid(schema: &Value, instance: &Value) {
let compiled = JSONSchema::compile(schema).unwrap();
is_valid_inner(&compiled, instance);
is_valid_with(&compiled, instance);
}

#[cfg(any(feature = "draft201909", feature = "draft202012"))]
Expand All @@ -208,7 +208,7 @@ pub(crate) mod tests_util {
.with_draft(draft)
.compile(schema)
.unwrap();
is_valid_inner(&compiled, instance)
is_valid_with(&compiled, instance)
}

pub(crate) fn validate(schema: &Value, instance: &Value) -> ValidationError<'static> {
Expand Down

0 comments on commit 8cb04dd

Please sign in to comment.