Skip to content

Commit 9b361e9

Browse files
bieluclaude
andcommitted
fix: reject leading-zero pointer indices and report invalid schema booleans
Array tokens with a leading zero ("01", "00") no longer resolve, per RFC 6901. The uniqueItems, readOnly, writeOnly and deprecated schema fields now use GetBooleanValue, so an invalid value produces a diagnostic naming the value instead of an unhandled FormatException. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 0c63444 commit 9b361e9

3 files changed

Lines changed: 25 additions & 5 deletions

File tree

‎src/ByteBard.AsyncAPI.Readers/ParseNodes/JsonPointerExtensions.cs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ public static JsonNode Find(this JsonPointer currentPointer, JsonNode baseJsonNo
1717
{
1818
if (pointer is JsonArray sequence)
1919
{
20-
if (!int.TryParse(token, NumberStyles.None, CultureInfo.InvariantCulture, out var index) || index >= sequence.Count)
20+
// RFC 6901 array indices are "0" or digits without a leading zero.
21+
if ((token.Length > 1 && token[0] == '0')
22+
|| !int.TryParse(token, NumberStyles.None, CultureInfo.InvariantCulture, out var index)
23+
|| index >= sequence.Count)
2124
{
2225
return null;
2326
}

‎src/ByteBard.AsyncAPI.Readers/Schemas/AsyncApiJsonSchemaDeserializer.cs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public class AsyncApiJsonSchemaDeserializer
9595
"minItems", (a, n) => { a.MinItems = n.GetIntegerValue(); }
9696
},
9797
{
98-
"uniqueItems", (a, n) => { a.UniqueItems = bool.Parse(n.GetScalarValue()); }
98+
"uniqueItems", (a, n) => { a.UniqueItems = n.GetBooleanValue(); }
9999
},
100100
{
101101
"maxProperties",
@@ -124,10 +124,10 @@ public class AsyncApiJsonSchemaDeserializer
124124
"else", (a, n) => { a.Else = LoadSchema(n); }
125125
},
126126
{
127-
"readOnly", (a, n) => { a.ReadOnly = bool.Parse(n.GetScalarValue()); }
127+
"readOnly", (a, n) => { a.ReadOnly = n.GetBooleanValue(); }
128128
},
129129
{
130-
"writeOnly", (a, n) => { a.WriteOnly = bool.Parse(n.GetScalarValue()); }
130+
"writeOnly", (a, n) => { a.WriteOnly = n.GetBooleanValue(); }
131131
},
132132
{
133133
"properties", (a, n) => { a.Properties = n.CreateMap(LoadSchema); }
@@ -208,7 +208,7 @@ public class AsyncApiJsonSchemaDeserializer
208208
"externalDocs", (a, n) => { a.ExternalDocs = AsyncApiV2Deserializer.LoadExternalDocs(n); }
209209
},
210210
{
211-
"deprecated", (a, n) => { a.Deprecated = bool.Parse(n.GetScalarValue()); }
211+
"deprecated", (a, n) => { a.Deprecated = n.GetBooleanValue(); }
212212
},
213213
{
214214
"nullable", (a, n) => { a.Nullable = n.GetBooleanValue(); }

‎test/ByteBard.AsyncAPI.Tests/ReaderErrorDetails_Should.cs‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@ public void SchemaIntegerField_ReportsTheValueAndWhyItIsInvalid(string value, st
2525
error.Pointer.Should().Be("#/maxLength");
2626
}
2727

28+
[TestCase("uniqueItems")]
29+
[TestCase("readOnly")]
30+
[TestCase("writeOnly")]
31+
[TestCase("deprecated")]
32+
public void SchemaBooleanField_ReportsTheValueAndWhyItIsInvalid(string field)
33+
{
34+
var yaml = $"type: string\n{field}: 'yes please'";
35+
36+
new AsyncApiStringReader().ReadFragment<AsyncApiJsonSchema>(yaml, AsyncApiVersion.AsyncApi3_0, out var diagnostics);
37+
38+
var error = diagnostics.Errors.Should().ContainSingle().Subject;
39+
error.Message.Should().Be("Value 'yes please' could not parse to bool. Expected true or false.");
40+
error.Pointer.Should().Be($"#/{field}");
41+
}
42+
2843
[Test]
2944
public void MissingLocalReference_IsReportedOnce()
3045
{
@@ -54,6 +69,8 @@ public void MissingLocalReference_IsReportedOnce()
5469
[TestCase("/tags/-0")]
5570
[TestCase("/tags/+0")]
5671
[TestCase("/tags/ 0")]
72+
[TestCase("/tags/00")]
73+
[TestCase("/tags/01")]
5774
[TestCase("/missing")]
5875
public void Find_ReturnsNull_WhenThePointerDoesNotLeadToANode(string pointer)
5976
{

0 commit comments

Comments
 (0)