Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions helm/values.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"additionalProperties": true,
"properties": {
"global": {
"type": "object",
"properties": {
"databaseType": {
"type": "string",
"enum": ["internal", "external"]
},
"storageClass": {
"type": "string"
}
}
},
"replicaCount": {
"type": "integer",
"minimum": 1
},
"autoscaling": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"minReplicas": {
"type": "integer",
"minimum": 1
},
"maxReplicas": {
"type": "integer",
"minimum": 1
},
"targetCPUUtilizationPercentage": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
}
},
"ingress": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"host": {
"type": "string"
}
}
},
"externalDatabase": {
"type": "object",
"properties": {
"host": {
"type": "string"
}
}
},
"persistence": {
"type": "object",
"properties": {
"repositories": {
"type": "object",
"properties": {
"size": {
"type": "string",
"pattern": "^[0-9]+[KMGT]i?$"
},
"retainOnDelete": {
"type": "boolean"
}
}
}
}
},
"ssh": {
"type": "object",
"properties": {
"serviceType": {
"type": "string",
"enum": ["LoadBalancer", "NodePort", "ClusterIP"]
}
}
}
},
"if": {
"properties": {
"ingress": {
"properties": {
"enabled": {
"const": true
}
}
}
},
"required": ["ingress"]
},
"then": {
"properties": {
"ingress": {
"required": ["host"],
"properties": {
"host": {
"minLength": 1
}
}
}
}
},
"allOf": [
{
"if": {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 [critical] トップレベルの if/thenallOf を併用するとセマンティクスが壊れる

JSON Schema draft-07 ではキーワードは独立して評価されます。if/then をトップレベルに直書きしつつ allOf も存在する場合、両者は問題なく共存しますが、トップレベルの if/thenallOf 内に入っていないため、外側の iffalse の場合(ingress が存在しないか enabledtrue でない場合)に then は無視されます。これ自体はドラフト-07 の仕様通りですが、より重大な問題は allOf と同階層に if/then を置く構造の一貫性のなさです。PRD では「外部DBのif/thenallOf 経由」と明示されているのに、ingress の if/then だけがトップレベルに分離されており、将来ルールを追加する際に allOf と混在して管理が困難になります。両方を allOf に統一すべきです。

該当箇所:

  "if": {
    "properties": {
      "ingress": {
        "properties": {
          "enabled": {
            "const": true
          }
        }
      }
    },
    "required": ["ingress"]
  },
  "then": { ... },
  "allOf": [ { "if": ..., "then": ... } ]
@@ -93,25 +93,30 @@
-  "if": {
-    "properties": {
-      "ingress": {
-        "properties": {
-          "enabled": {
-            "const": true
-          }
-        }
-      }
-    },
-    "required": ["ingress"]
-  },
-  "then": {
-    "properties": {
-      "ingress": {
-        "required": ["host"],
-        "properties": {
-          "host": {
-            "minLength": 1
-          }
-        }
-      }
-    }
-  },
   "allOf": [
+    {
+      "if": {
+        "properties": {
+          "ingress": {
+            "properties": { "enabled": { "const": true } }
+          }
+        },
+        "required": ["ingress"]
+      },
+      "then": {
+        "properties": {
+          "ingress": {
+            "required": ["host"],
+            "properties": { "host": { "minLength": 1 } }
+          }
+        }
+      }
+    },
     {

code.schema.if_then_allof_conflict | confidence: 0.92

"properties": {
"global": {
"properties": {
"databaseType": {
"const": "external"
}
}
}
}
},
"then": {
"properties": {
"externalDatabase": {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [high] allOf 内の外部DB if 条件に required: ["global"] がなく、global キーが存在しない場合も条件が通過してしまう

JSON Schema では properties 内のキーワードはそのプロパティが存在する場合にのみ検証されます。globalvalues.yaml に含まれていない場合、ifproperties.global スキーマは「適用対象なし→ true」と評価されてしまい、thenexternalDatabase.host required が誤って発動するリスクがあります。

ingress側(トップレベル if)では "required": ["ingress"] が付与されているのに、allOf 内の external DB 側 if には同等の "required": ["global"] が欠落しています。

該当箇所:

      "if": {
        "properties": {
          "global": {
            "properties": {
              "databaseType": {
                "const": "external"
              }
            }
          }
        }
      },

実際には global.databaseType"external"明示されていない限り then は発動しないため誤検知の頻度は低いですが、global キーが丸ごと省略された values では iftrue になり externalDatabase.host が要求されてしまいます。

@@ -116,7 +116,8 @@
       "if": {
         "properties": {
           "global": {
             "properties": {
               "databaseType": { "const": "external" }
             }
           }
-        }
+        },
+        "required": ["global"]
       },

code.schema.if_condition_missing_required | confidence: 0.88

"required": ["host"],
"properties": {
"host": {
"minLength": 1
}
}
}
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 [critical] external モード時に externalDatabase オブジェクト欠落を検証できない

PRD は global.databaseTypeexternal のとき externalDatabase.host 欠落を helm install 時に拒否することを要求していますが、then ブロックは properties.externalDatabase 内の required: ["host"] だけを定義しています。JSON Schema draft-07 では、ルートに externalDatabase キーが存在しない場合、そのサブスキーマは適用されず、required も評価されません。したがって global.databaseType: external だけを渡し externalDatabase を丸ごと省略した values は、このスキーマを通過します。

該当箇所:

      "then": {
        "properties": {
          "externalDatabase": {
            "required": ["host"],
            "properties": {
              "host": {
                "minLength": 1
              }
            }
          }
        }
      }

ingress 側は ifrequired: ["ingress"] を付け、theningress.required: ["host"] としているため、オブジェクト存在時の必須チェックは機能します。external 側にも同様に then 直下へ required: ["externalDatabase"] が必要です。

@@ -129,6 +129,7 @@
       "then": {
+        "required": ["externalDatabase"],
         "properties": {
           "externalDatabase": {
             "required": ["host"],

code.logic.conditional_required_gap | confidence: 0.93

]
}
Loading