@@ -729,8 +729,9 @@ func TestNormalizeSchema_OptionsDependencies_NestedObject(t *testing.T) {
729729func TestNormalizeSchema_OptionsDependencies_NotInRequired (t * testing.T ) {
730730 t .Parallel ()
731731
732- // Schema with options.dependencies but the field is not in the required array
733- // The transformation should still add the if/then construct but not modify required
732+ // Schema with options.dependencies but the field is NOT in the required array.
733+ // options.dependencies is for UI visibility, NOT for making fields required.
734+ // Therefore, if the field was not originally required, we should NOT add if/then for it.
734735 schema := []byte (`
735736{
736737 "type": "object",
@@ -765,10 +766,10 @@ func TestNormalizeSchema_OptionsDependencies_NotInRequired(t *testing.T) {
765766 require .True (t , ok )
766767 assert .Equal (t , []any {"mode" }, required )
767768
768- // Check that allOf with if/then is still added
769- allOf , ok := result [ "allOf" ].([] any )
770- require . True ( t , ok )
771- require . Len (t , allOf , 1 )
769+ // Check that NO allOf was added - optional_field was not in required,
770+ // so we don't need conditional requirement logic
771+ _ , hasAllOf := result [ "allOf" ]
772+ assert . False (t , hasAllOf , "allOf should NOT be added for fields that were not originally required" )
772773}
773774
774775func TestNormalizeSchema_OptionsDependencies_Validation (t * testing.T ) {
@@ -962,6 +963,167 @@ func TestNormalizeSchema_ExistingAllOfIfThen(t *testing.T) {
962963 require .NoError (t , err , "Should pass validation when append_date=1 and append_date_format is provided" )
963964}
964965
966+ func TestNormalizeSchema_OptionsDependencies_MissingDependencyField (t * testing.T ) {
967+ t .Parallel ()
968+
969+ // This test uses the actual schema from kds-team.app-orchestration-trigger-queue-v2 component.
970+ // triggerActionOnFailure is NOT in the required array.
971+ // triggerActionOnFailure has options.dependencies: { waitUntilFinish: true }
972+ // actionOnFailureSettings has options.dependencies: { triggerActionOnFailure: true }
973+ schema := []byte (`
974+ {
975+ "type": "object",
976+ "required": ["waitUntilFinish", "#kbcToken", "kbcUrl", "orchestrationId"],
977+ "properties": {
978+ "waitUntilFinish": {
979+ "type": "boolean"
980+ },
981+ "triggerActionOnFailure": {
982+ "type": "boolean",
983+ "options": {
984+ "dependencies": {
985+ "waitUntilFinish": true
986+ }
987+ }
988+ },
989+ "actionOnFailureSettings": {
990+ "type": "object",
991+ "required": ["failureConfigurationId"],
992+ "properties": {
993+ "failureConfigurationId": {
994+ "type": "string"
995+ }
996+ },
997+ "options": {
998+ "dependencies": {
999+ "triggerActionOnFailure": true
1000+ }
1001+ }
1002+ },
1003+ "#kbcToken": {
1004+ "type": "string"
1005+ },
1006+ "kbcUrl": {
1007+ "type": "string"
1008+ },
1009+ "orchestrationId": {
1010+ "type": "string"
1011+ }
1012+ }
1013+ }
1014+ ` )
1015+
1016+ // First, let's see what the normalized schema looks like
1017+ normalized , err := NormalizeSchema (schema )
1018+ require .NoError (t , err )
1019+
1020+ // Pretty print for debugging
1021+ var prettySchema map [string ]any
1022+ json .Unmarshal (normalized , & prettySchema )
1023+ prettyBytes , _ := json .MarshalIndent (prettySchema , "" , " " )
1024+ t .Logf ("Normalized schema:\n %s" , string (prettyBytes ))
1025+
1026+ // Test 1: triggerActionOnFailure field is missing entirely (fire-and-forget config)
1027+ // This should PASS - actionOnFailureSettings should NOT be required
1028+ // BUG: Currently this fails with "missing property actionOnFailureSettings"
1029+ content1 := orderedmap .FromPairs ([]orderedmap.Pair {
1030+ {
1031+ Key : "parameters" ,
1032+ Value : orderedmap .FromPairs ([]orderedmap.Pair {
1033+ {Key : "waitUntilFinish" , Value : false },
1034+ {Key : "#kbcToken" , Value : "xxx" },
1035+ {Key : "kbcUrl" , Value : "-" },
1036+ {Key : "orchestrationId" , Value : "123" },
1037+ // triggerActionOnFailure is NOT present at all
1038+ }),
1039+ },
1040+ })
1041+ err = ValidateContent (schema , content1 )
1042+ require .NoError (t , err , "Should pass when triggerActionOnFailure field is missing (undefined)" )
1043+
1044+ // Test 2: triggerActionOnFailure is explicitly false
1045+ // This should PASS - actionOnFailureSettings should NOT be required
1046+ content2 := orderedmap .FromPairs ([]orderedmap.Pair {
1047+ {
1048+ Key : "parameters" ,
1049+ Value : orderedmap .FromPairs ([]orderedmap.Pair {
1050+ {Key : "waitUntilFinish" , Value : true },
1051+ {Key : "#kbcToken" , Value : "xxx" },
1052+ {Key : "kbcUrl" , Value : "-" },
1053+ {Key : "triggerActionOnFailure" , Value : false },
1054+ {Key : "orchestrationId" , Value : "123" },
1055+ }),
1056+ },
1057+ })
1058+ err = ValidateContent (schema , content2 )
1059+ require .NoError (t , err , "Should pass when triggerActionOnFailure is explicitly false" )
1060+
1061+ // Test 3: triggerActionOnFailure is true but actionOnFailureSettings is missing
1062+ // This should PASS - actionOnFailureSettings was NOT in the required array,
1063+ // options.dependencies is only for UI visibility, not for making fields required.
1064+ content3 := orderedmap .FromPairs ([]orderedmap.Pair {
1065+ {
1066+ Key : "parameters" ,
1067+ Value : orderedmap .FromPairs ([]orderedmap.Pair {
1068+ {Key : "waitUntilFinish" , Value : true },
1069+ {Key : "#kbcToken" , Value : "xxx" },
1070+ {Key : "kbcUrl" , Value : "-" },
1071+ {Key : "triggerActionOnFailure" , Value : true },
1072+ {Key : "orchestrationId" , Value : "123" },
1073+ }),
1074+ },
1075+ })
1076+ err = ValidateContent (schema , content3 )
1077+ require .NoError (t , err , "Should pass - actionOnFailureSettings was NOT in required, options.dependencies is for visibility only" )
1078+
1079+ // Test 4: triggerActionOnFailure is true and actionOnFailureSettings is provided but missing internal required field
1080+ // This should FAIL - failureConfigurationId is required WITHIN actionOnFailureSettings
1081+ content4 := orderedmap .FromPairs ([]orderedmap.Pair {
1082+ {
1083+ Key : "parameters" ,
1084+ Value : orderedmap .FromPairs ([]orderedmap.Pair {
1085+ {Key : "waitUntilFinish" , Value : true },
1086+ {Key : "#kbcToken" , Value : "xxx" },
1087+ {Key : "kbcUrl" , Value : "-" },
1088+ {Key : "triggerActionOnFailure" , Value : true },
1089+ {Key : "orchestrationId" , Value : "123" },
1090+ {
1091+ Key : "actionOnFailureSettings" ,
1092+ Value : orderedmap .FromPairs ([]orderedmap.Pair {
1093+ // missing failureConfigurationId
1094+ }),
1095+ },
1096+ }),
1097+ },
1098+ })
1099+ err = ValidateContent (schema , content4 )
1100+ require .Error (t , err , "Should fail - failureConfigurationId is required within actionOnFailureSettings" )
1101+ assert .Contains (t , err .Error (), "failureConfigurationId" )
1102+
1103+ // Test 5: triggerActionOnFailure is true and actionOnFailureSettings is provided with required field
1104+ // This should PASS
1105+ content5 := orderedmap .FromPairs ([]orderedmap.Pair {
1106+ {
1107+ Key : "parameters" ,
1108+ Value : orderedmap .FromPairs ([]orderedmap.Pair {
1109+ {Key : "waitUntilFinish" , Value : true },
1110+ {Key : "#kbcToken" , Value : "xxx" },
1111+ {Key : "kbcUrl" , Value : "-" },
1112+ {Key : "triggerActionOnFailure" , Value : true },
1113+ {Key : "orchestrationId" , Value : "123" },
1114+ {
1115+ Key : "actionOnFailureSettings" ,
1116+ Value : orderedmap .FromPairs ([]orderedmap.Pair {
1117+ {Key : "failureConfigurationId" , Value : "456" },
1118+ }),
1119+ },
1120+ }),
1121+ },
1122+ })
1123+ err = ValidateContent (schema , content5 )
1124+ require .NoError (t , err , "Should pass when actionOnFailureSettings is provided with required fields" )
1125+ }
1126+
9651127func getTestSchema () []byte {
9661128 return []byte (`
9671129{
0 commit comments