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 7cebb1e
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 8 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"
}
]
}
25 changes: 17 additions & 8 deletions stix2validator/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

from collections.abc import Iterable
import copy
import functools
import io
from itertools import chain
import os
import pathlib
import re
import sys
from urllib import parse, request
Expand Down Expand Up @@ -553,11 +553,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 +569,22 @@ 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)
if os.path.isabs(schema_path_uri) 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 +594,10 @@ def load_validator(schema_path, schema):
Returns:
An instance of Draft202012Validator.
"""
schema_path = pathlib.Path(schema_path).as_uri()
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 +703,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 7cebb1e

Please sign in to comment.