From 6e8ad2f0b549a60ddf8925bd298f6ea9b15b56d7 Mon Sep 17 00:00:00 2001 From: Alex Daines Date: Thu, 22 May 2025 10:47:58 -0400 Subject: [PATCH 1/2] Fix Document enumeration to handle Dictionary types, resolving WebAuthn serialization errors --- .../304ac42f-43cd-4862-bab4-413ad22e17b1.json | 9 +++++++++ sdk/src/Core/Amazon.Runtime/Documents/Document.cs | 8 +++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 generator/.DevConfigs/304ac42f-43cd-4862-bab4-413ad22e17b1.json diff --git a/generator/.DevConfigs/304ac42f-43cd-4862-bab4-413ad22e17b1.json b/generator/.DevConfigs/304ac42f-43cd-4862-bab4-413ad22e17b1.json new file mode 100644 index 000000000000..ca6fba737b7b --- /dev/null +++ b/generator/.DevConfigs/304ac42f-43cd-4862-bab4-413ad22e17b1.json @@ -0,0 +1,9 @@ +{ + "core": { + "changeLogMessages": [ + "Fixed Document.cs serialization issue that caused WebAuthn operations to fail when response contained Dictionary structures" + ], + "type": "patch", + "updateMinimum": true + } + } \ No newline at end of file diff --git a/sdk/src/Core/Amazon.Runtime/Documents/Document.cs b/sdk/src/Core/Amazon.Runtime/Documents/Document.cs index 16c100907e00..73d4aff3d5f3 100644 --- a/sdk/src/Core/Amazon.Runtime/Documents/Document.cs +++ b/sdk/src/Core/Amazon.Runtime/Documents/Document.cs @@ -285,7 +285,13 @@ public override bool Equals(object obj) #region Collection Initializers IEnumerator IEnumerable.GetEnumerator() { - return AsList().GetEnumerator(); + if (Type == DocumentType.List) + return AsList().GetEnumerator(); + + if (Type == DocumentType.Dictionary) + return AsDictionary().Values.GetEnumerator(); + + return new[]{this}.AsEnumerable().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() From 8540386ff9ddb230a878d77d541afd5daf898adb Mon Sep 17 00:00:00 2001 From: Alex Daines Date: Thu, 22 May 2025 14:50:20 -0400 Subject: [PATCH 2/2] Add unit tests for Document enumeration with Dictionary support --- .../Custom/Runtime/Documents/DocumentTests.cs | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/sdk/test/UnitTests/Custom/Runtime/Documents/DocumentTests.cs b/sdk/test/UnitTests/Custom/Runtime/Documents/DocumentTests.cs index c73563aeec16..b6781c5eead5 100644 --- a/sdk/test/UnitTests/Custom/Runtime/Documents/DocumentTests.cs +++ b/sdk/test/UnitTests/Custom/Runtime/Documents/DocumentTests.cs @@ -267,5 +267,140 @@ private void AssertIsDocumentType(Document doc, DocumentType t) else Assert.IsFalse(doc.IsString()); } + + /// + /// Tests that enumerating a Dictionary type Document works correctly + /// This tests the fix for WebAuthn serialization errors + /// + [TestMethod] + [TestCategory("UnitTest")] + [TestCategory("Runtime")] + public void EnumerateDictionaryDocument() + { + // Create a dictionary document + var doc = new Document + { + {"key1", "value1"}, + {"key2", 42}, + {"key3", true} + }; + + // Ensure we can enumerate the document as IEnumerable + var values = new List(); + foreach (var item in (IEnumerable)doc) + { + values.Add(item); + } + + // Should enumerate dictionary values + Assert.AreEqual(3, values.Count); + Assert.IsTrue(values.Any(v => v.IsString() && v.AsString() == "value1")); + Assert.IsTrue(values.Any(v => v.IsInt() && v.AsInt() == 42)); + Assert.IsTrue(values.Any(v => v.IsBool() && v.AsBool() == true)); + } + + /// + /// Tests that enumerating a List type Document still works correctly + /// + [TestMethod] + [TestCategory("UnitTest")] + [TestCategory("Runtime")] + public void EnumerateListDocument() + { + // Create a list document + var doc = new Document("value1", 42, true); + + // Ensure we can enumerate the document + var values = new List(); + foreach (var item in (IEnumerable)doc) + { + values.Add(item); + } + + // Should enumerate list items in order + Assert.AreEqual(3, values.Count); + Assert.IsTrue(values[0].IsString() && values[0].AsString() == "value1"); + Assert.IsTrue(values[1].IsInt() && values[1].AsInt() == 42); + Assert.IsTrue(values[2].IsBool() && values[2].AsBool() == true); + } + + /// + /// Tests that enumerating non-collection type Documents returns the document itself + /// + [TestMethod] + [TestCategory("UnitTest")] + [TestCategory("Runtime")] + public void EnumerateNonCollectionDocument() + { + // Test with various non-collection types + var stringDoc = new Document("test"); + var intDoc = new Document(42); + var boolDoc = new Document(true); + var nullDoc = new Document(); + + // Each should enumerate to a single item - itself + var stringValues = ((IEnumerable)stringDoc).ToList(); + Assert.AreEqual(1, stringValues.Count); + Assert.AreEqual(stringDoc, stringValues[0]); + + var intValues = ((IEnumerable)intDoc).ToList(); + Assert.AreEqual(1, intValues.Count); + Assert.AreEqual(intDoc, intValues[0]); + + var boolValues = ((IEnumerable)boolDoc).ToList(); + Assert.AreEqual(1, boolValues.Count); + Assert.AreEqual(boolDoc, boolValues[0]); + + var nullValues = ((IEnumerable)nullDoc).ToList(); + Assert.AreEqual(1, nullValues.Count); + Assert.AreEqual(nullDoc, nullValues[0]); + } + + /// + /// Tests that LINQ operations work correctly on Dictionary documents + /// This specifically tests the WebAuthn scenario + /// + [TestMethod] + [TestCategory("UnitTest")] + [TestCategory("Runtime")] + public void LinqOperationsOnDictionaryDocument() + { + // Create a complex dictionary document similar to WebAuthn responses + var doc = new Document + { + {"credentialId", "abc123"}, + {"publicKey", "key-data"}, + {"signCount", 5}, + {"userVerified", true}, + {"attestationObject", new Document + { + {"fmt", "packed"}, + {"authData", "auth-data-bytes"} + } + } + }; + + // Cast to IEnumerable to use LINQ operations + var enumerable = (IEnumerable)doc; + + // Test that we can use LINQ operations + var count = enumerable.Count(); + Assert.AreEqual(5, count); + + // Test FirstOrDefault + var first = enumerable.FirstOrDefault(); + Assert.IsNotNull(first); + + // Test Any + Assert.IsTrue(enumerable.Any()); + + // Test Where (filtering) + var stringValues = enumerable.Where(d => d.IsString()).ToList(); + Assert.IsTrue(stringValues.Count >= 2); // At least credentialId and publicKey + + // Test Select (projection) + var types = enumerable.Select(d => d.Type).ToList(); + Assert.AreEqual(5, types.Count); + } } } \ No newline at end of file