Skip to content

Commit 9f8c59b

Browse files
properly handle $dynamicRef when evaluating a subschema
This occurred in OpenAPI-Modern when trying to do this in t/parameters.t: my $result = $openapi->evaluator->evaluate( $param_obj, OpenAPI::Modern::Utilities::DEFAULT_METASCHEMA->{3.2}.'#/$defs/parameter', ); fail('parameter object is valid'), note($result), next if not $result->valid; ..and we got a 'Reference vivified' error when trying to fetch the resource corresponding to the dynamic scope uri, which erroneously had a fragment and therefore was not resolvable.
1 parent 48b5d92 commit 9f8c59b

File tree

4 files changed

+69
-2
lines changed

4 files changed

+69
-2
lines changed

Changes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
Revision history for JSON-Schema-Modern
22

33
{{$NEXT}}
4+
- fix error when navigating a $dynamicRef after initial evaluation
5+
at a subschema
46

57
0.622 2025-11-08 22:22:19Z
68
- allow export of JSON::Schema::Modern::Utilities::is_bool

lib/JSON/Schema/Modern.pm

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ sub evaluate ($self, $data, $schema_reference, $config_override = {}) {
414414
%$state,
415415
initial_schema_uri => $schema_info->{canonical_uri}, # the canonical URI as of the start of evaluation, or last $id or $ref
416416
$schema_info->%{qw(document specification_version vocabularies)},
417-
dynamic_scope => [ $schema_info->{canonical_uri} ],
417+
dynamic_scope => [ $schema_info->{canonical_uri}->clone->fragment(undef) ],
418418
annotations => [],
419419
seen => {},
420420
callbacks => $config_override->{callbacks} // {},
@@ -843,7 +843,10 @@ has _resource_index => (
843843
]],
844844
);
845845

846-
sub _get_resource { ($_[0]->{_resource_index}//{})->{$_[1]} }
846+
sub _get_resource {
847+
die 'bad resource: ', $_[1] if $_[1] =~ /#/;
848+
($_[0]->{_resource_index}//{})->{$_[1]}
849+
}
847850

848851
# does not check for duplicate entries, or for malformed uris
849852
sub _add_resources_unsafe {

lib/JSON/Schema/Modern/Vocabulary/Core.pm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ sub _eval_keyword_dynamicRef ($class, $data, $schema, $state) {
336336
# "$dynamicAnchor".
337337
foreach my $scope_uri ($state->{dynamic_scope}->@*) {
338338
my $resource = $state->{evaluator}->_get_or_load_resource($scope_uri);
339+
die 'bad dynamic scope uri: ', $scope_uri if not $resource;
339340
if (exists(($resource->{anchors}//{})->{$anchor}) and $resource->{anchors}{$anchor}{dynamic}) {
340341
$uri = Mojo::URL->new($scope_uri)->fragment($anchor);
341342
last;

t/ref.t

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,4 +1293,65 @@ subtest 'evaluate at a non-schema location' => sub {
12931293
);
12941294
};
12951295

1296+
subtest 'evaluate at a subschema, with $dynamicRef' => sub {
1297+
# from a real bug I encountered while writing a t/parameters.t test in OpenAPI-Modern!
1298+
# if we evaluate in the middle of a document, and a $dynamicRef is involved, mayhem ensues.
1299+
$js->{_resource_index} = {};
1300+
$js->add_schema({
1301+
'$id' => 'http://strict_metaschema',
1302+
'$defs' => {
1303+
schema => {
1304+
'$dynamicAnchor' => 'meta',
1305+
type => 'object', # disallows boolean
1306+
},
1307+
parameter => {
1308+
'$ref' => 'http://loose_metaschema#/$defs/parameter',
1309+
},
1310+
},
1311+
'$ref' => 'http://loose_metaschema#/intentionally/bad/reference',
1312+
});
1313+
1314+
$js->add_schema({
1315+
'$id' => 'http://loose_metaschema',
1316+
'$defs' => {
1317+
schema => {
1318+
'$dynamicAnchor' => 'meta',
1319+
type => [ 'object', 'boolean' ],
1320+
},
1321+
parameter => {
1322+
type => 'object',
1323+
properties => {
1324+
name => { type => 'string' },
1325+
schema => { '$dynamicRef' => '#meta' },
1326+
},
1327+
},
1328+
},
1329+
});
1330+
1331+
cmp_result(
1332+
$js->evaluate(
1333+
{ name => 'hi', schema => false },
1334+
'http://strict_metaschema#/$defs/parameter',
1335+
)->TO_JSON,
1336+
{
1337+
valid => false,
1338+
errors => [
1339+
{
1340+
instanceLocation => '/schema',
1341+
keywordLocation => '/$ref/properties/schema/$dynamicRef/type',
1342+
absoluteKeywordLocation => 'http://strict_metaschema#/$defs/schema/type',
1343+
error => 'got boolean, not object',
1344+
},
1345+
{
1346+
instanceLocation => '',
1347+
keywordLocation => '/$ref/properties',
1348+
absoluteKeywordLocation => 'http://loose_metaschema#/$defs/parameter/properties',
1349+
error => 'not all properties are valid',
1350+
},
1351+
],
1352+
},
1353+
'correctly navigated a $dynamicRef while evaluating in the middle of a document',
1354+
);
1355+
};
1356+
12961357
done_testing;

0 commit comments

Comments
 (0)