Skip to content

Commit

Permalink
Add support to relative custom schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
ostefano committed Apr 4, 2024
1 parent 17da855 commit 05c56f1
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 7 deletions.
13 changes: 13 additions & 0 deletions stix2validator/test/v21/misc_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
'test_examples', 'tlp-amber.json')
CUSTOM_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
'test_schemas')
RELATIVE = os.path.join(os.path.dirname(os.path.realpath(__file__)),
'test_examples', 'tool.json')
RELATIVE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
'test_schemas')
IDENTITY = os.path.join(os.path.dirname(os.path.realpath(__file__)),
'test_examples', 'identity.json')
IDENTITY_CUSTOM = os.path.join(os.path.dirname(os.path.realpath(__file__)),
Expand Down Expand Up @@ -76,6 +80,15 @@ def test_validate_file_custom(caplog):
assert 'STIX JSON: Valid' in caplog.text


def test_validate_file_custom_relative(caplog):
caplog.set_level('INFO')
results = validate_file(RELATIVE, options=ValidationOptions(schema_dir=RELATIVE_DIR))
assert results.is_valid

print_results(results)
assert 'STIX JSON: Valid' in caplog.text


def test_validate_file_warning(caplog):
results = validate_file(IDENTITY_CUSTOM)
assert results.is_valid
Expand Down
12 changes: 12 additions & 0 deletions stix2validator/test/v21/test_examples/tool.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"type": "tool",
"spec_version": "2.1",
"id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"created": "2016-04-06T20:03:48.000Z",
"modified": "2016-04-06T20:03:48.000Z",
"tool_types": [ "remote-access"],
"name": "VNC",
"foo_value": "bizz",
"bar_value": "buzz"
}
7 changes: 7 additions & 0 deletions stix2validator/test/v21/test_schemas/bar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"properties": {
"bar_value": {
"type": "string"
}
}
}
15 changes: 15 additions & 0 deletions stix2validator/test/v21/test_schemas/tool.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"allOf": [
{
"properties": {
"foo_value": {
"type": "string"
}
},
"required": ["foo_value"]
},
{
"$ref": "bar.json"
}
]
}
31 changes: 24 additions & 7 deletions stix2validator/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from collections.abc import Iterable
import copy
import functools
import io
from itertools import chain
import os
Expand Down Expand Up @@ -553,11 +554,12 @@ def patch_schema(schema_data: dict, schema_path: str) -> dict:
return schema_data


def retrieve_from_filesystem(schema_path_uri: str) -> Resource:
def retrieve_from_filesystem(schema_path_uri: str, schema_dir: str) -> Resource:
"""Callback to retrieve a schema given its path.
Args:
schema_path_uri: the schema URI.
schema_dir: the optional directory of local schemas.
Returns:
A resource loaded with the content.
Expand All @@ -568,14 +570,23 @@ def retrieve_from_filesystem(schema_path_uri: str) -> Resource:
schema = patch_schema(schema, schema_path_uri)
return Resource.from_contents(schema)
else:
schema_path = from_uri_to_path(schema_path_uri)
schema_path = pathlib.Path(schema_path_uri)
if schema_path.is_absolute() or schema_path_uri.startswith("file://"):
is_relative = False
schema_path = from_uri_to_path(schema_path_uri)
else:
is_relative = True
schema_path = from_uri_to_path(os.path.join(schema_dir, schema_path_uri))
with open(schema_path, "r") as f:
schema = json.load(f)
schema = patch_schema(schema, schema_path)
return Resource.from_contents(schema)
if is_relative:
return Resource.opaque(schema)
else:
return Resource.from_contents(schema)


def load_validator(schema_path, schema):
def load_validator(schema_path, schema, schema_dir):
"""Create a JSON schema validator for the given schema.
Args:
Expand All @@ -585,10 +596,16 @@ def load_validator(schema_path, schema):
Returns:
An instance of Draft202012Validator.
"""
schema_path = pathlib.Path(schema_path).as_uri()
schema_path = pathlib.Path(schema_path)
if schema_path.is_absolute():
schema_path = schema_path.as_uri()
else:
schema_path = schema_path
schema_path = str(schema_path)
schema = patch_schema(schema, schema_path)
retrieve_callback = functools.partial(retrieve_from_filesystem, schema_dir=schema_dir)
registry = Registry(
retrieve=retrieve_from_filesystem
retrieve=retrieve_callback
).with_resource(schema_path, DRAFT202012.create_resource(schema))
validator = STIXValidator(schema, registry=registry, format_checker=Draft202012Validator.FORMAT_CHECKER)
return validator
Expand Down Expand Up @@ -694,7 +711,7 @@ def _get_error_generator(name, obj, schema_dir=None, version=DEFAULT_VER, defaul
}

# Don't use custom validator; only check schemas, no additional checks
validator = load_validator(schema_path, schema)
validator = load_validator(schema_path, schema, schema_dir)
try:
error_gen = validator.iter_errors(obj)
except schema_exceptions.RefResolutionError:
Expand Down

0 comments on commit 05c56f1

Please sign in to comment.