Skip to content

Commit

Permalink
fix: Return "Unknown specification" error on https-prefixed `$schem…
Browse files Browse the repository at this point in the history
…a` for Draft 4, 5, 6

Signed-off-by: Dmitry Dygalo <dmitry@dygalo.dev>
  • Loading branch information
Stranger6667 committed Oct 29, 2024
1 parent 832d7d1 commit a2eb0ff
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 7 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

- Return "Unknown specification" error on `https`-prefixed `$schema` for Draft 4, 5, 6. [#629](https://github.com/Stranger6667/jsonschema/issues/629)

## [0.26.0] - 2024-10-26

**Important:** This release contains breaking changes. See the [Migration Guide](MIGRATION.md) for details on transitioning to the new API.
Expand Down
4 changes: 4 additions & 0 deletions crates/jsonschema-py/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Fixed

- Return "Unknown specification" error on `https`-prefixed `$schema` for Draft 4, 5, 6. [#629](https://github.com/Stranger6667/jsonschema/issues/629)

### Performance

- Speedup Python -> Rust data serialization.
Expand Down
7 changes: 7 additions & 0 deletions crates/jsonschema-py/tests-py/test_jsonschema.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,13 @@ def test_invalid_value(method):
getattr(schema, method)(object())


def test_invalid_schema_keyword():
# Note `https`, not `http`
schema = {"$schema": "https://json-schema.org/draft-07/schema"}
with pytest.raises(ValidationError, match="Unknown specification: https://json-schema.org/draft-07/schema"):
validator_for(schema)


def test_error_message():
schema = {"properties": {"foo": {"type": "integer"}}}
instance = {"foo": None}
Expand Down
2 changes: 1 addition & 1 deletion crates/jsonschema/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ pub(crate) fn build_validator(
mut config: ValidationOptions,
schema: &Value,
) -> Result<Validator, ValidationError<'static>> {
let draft = config.draft_for(schema);
let draft = config.draft_for(schema)?;
let resource_ref = draft.create_resource_ref(schema);
let resource = draft.create_resource(schema.clone());
let base_uri = resource.id().unwrap_or(DEFAULT_ROOT_URL).to_string();
Expand Down
13 changes: 13 additions & 0 deletions crates/jsonschema/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,19 @@ mod tests {
assert!(validate_fn(&schema, &invalid_instance).is_err());
}

#[test]
fn test_invalid_schema_keyword() {
let schema = json!({
// Note `https`, not `http`
"$schema": "https://json-schema.org/draft-07/schema",
});
let error = crate::validator_for(&schema).expect_err("Should fail");
assert_eq!(
error.to_string(),
"Unknown specification: https://json-schema.org/draft-07/schema"
);
}

#[test_case(Draft::Draft4)]
#[test_case(Draft::Draft6)]
#[test_case(Draft::Draft7)]
Expand Down
12 changes: 6 additions & 6 deletions crates/jsonschema/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,28 +55,28 @@ impl ValidationOptions {
pub(crate) fn draft(&self) -> Draft {
self.draft.unwrap_or_default()
}
pub(crate) fn draft_for(&self, contents: &Value) -> Draft {
pub(crate) fn draft_for(&self, contents: &Value) -> Result<Draft, ValidationError<'static>> {
// Preference:
// - Explicitly set
// - Autodetected
// - Default
if let Some(draft) = self.draft {
draft
Ok(draft)
} else {
let default = Draft::default();
match default.detect(contents) {
Ok(draft) => draft,
Ok(draft) => Ok(draft),
Err(referencing::Error::UnknownSpecification { specification }) => {
// Try to retrieve the specification and detect its draft
if let Ok(Ok(retrieved)) = uri::from_str(&specification)
.map(|uri| self.retriever.retrieve(&uri.borrow()))
{
default.detect(&retrieved).unwrap_or_default()
Ok(default.detect(&retrieved)?)
} else {
default
Err(referencing::Error::UnknownSpecification { specification }.into())
}
}
_ => default,
Err(error) => Err(error.into()),
}
}
}
Expand Down

0 comments on commit a2eb0ff

Please sign in to comment.