1use serde_json::Value;
12
13const K8S_DEPLOYMENT: &str = r#"
15{
16 "$schema": "http://json-schema.org/draft-07/schema#",
17 "type": "object",
18 "required": ["apiVersion", "kind", "metadata", "spec"],
19 "properties": {
20 "apiVersion": { "type": "string", "const": "apps/v1" },
21 "kind": { "type": "string", "const": "Deployment" },
22 "metadata": {
23 "type": "object",
24 "required": ["name"],
25 "properties": {
26 "name": { "type": "string" },
27 "namespace": { "type": "string" },
28 "labels": { "type": "object", "additionalProperties": { "type": "string" } },
29 "annotations": { "type": "object", "additionalProperties": { "type": "string" } }
30 }
31 },
32 "spec": {
33 "type": "object",
34 "required": ["selector", "template"],
35 "properties": {
36 "replicas": { "type": "integer", "minimum": 0 },
37 "selector": {
38 "type": "object",
39 "required": ["matchLabels"],
40 "properties": {
41 "matchLabels": { "type": "object", "additionalProperties": { "type": "string" } }
42 }
43 },
44 "template": {
45 "type": "object",
46 "required": ["metadata", "spec"],
47 "properties": {
48 "metadata": {
49 "type": "object",
50 "properties": {
51 "labels": { "type": "object", "additionalProperties": { "type": "string" } }
52 }
53 },
54 "spec": {
55 "type": "object",
56 "required": ["containers"],
57 "properties": {
58 "containers": {
59 "type": "array",
60 "items": {
61 "type": "object",
62 "required": ["name", "image"],
63 "properties": {
64 "name": { "type": "string" },
65 "image": { "type": "string" },
66 "ports": {
67 "type": "array",
68 "items": {
69 "type": "object",
70 "properties": {
71 "containerPort": { "type": "integer" },
72 "protocol": { "type": "string", "enum": ["TCP", "UDP"] }
73 }
74 }
75 },
76 "resources": {
77 "type": "object",
78 "properties": {
79 "limits": { "type": "object" },
80 "requests": { "type": "object" }
81 }
82 },
83 "env": {
84 "type": "array",
85 "items": {
86 "type": "object",
87 "required": ["name"],
88 "properties": {
89 "name": { "type": "string" },
90 "value": { "type": "string" }
91 }
92 }
93 },
94 "livenessProbe": { "type": "object" },
95 "readinessProbe": { "type": "object" }
96 }
97 }
98 },
99 "initContainers": { "type": "array" },
100 "volumes": { "type": "array" },
101 "restartPolicy": { "type": "string", "enum": ["Always", "OnFailure", "Never"] }
102 }
103 }
104 }
105 },
106 "strategy": {
107 "type": "object",
108 "properties": {
109 "type": { "type": "string", "enum": ["RollingUpdate", "Recreate"] }
110 }
111 }
112 }
113 }
114 }
115}
116"#;
117
118const K8S_SERVICE: &str = r#"
120{
121 "$schema": "http://json-schema.org/draft-07/schema#",
122 "type": "object",
123 "required": ["apiVersion", "kind", "metadata", "spec"],
124 "properties": {
125 "apiVersion": { "type": "string", "const": "v1" },
126 "kind": { "type": "string", "const": "Service" },
127 "metadata": {
128 "type": "object",
129 "required": ["name"],
130 "properties": {
131 "name": { "type": "string" },
132 "namespace": { "type": "string" }
133 }
134 },
135 "spec": {
136 "type": "object",
137 "required": ["ports"],
138 "properties": {
139 "type": { "type": "string", "enum": ["ClusterIP", "NodePort", "LoadBalancer", "ExternalName"] },
140 "selector": { "type": "object", "additionalProperties": { "type": "string" } },
141 "ports": {
142 "type": "array",
143 "items": {
144 "type": "object",
145 "required": ["port"],
146 "properties": {
147 "name": { "type": "string" },
148 "port": { "type": "integer", "minimum": 1, "maximum": 65535 },
149 "targetPort": { "oneOf": [{ "type": "integer" }, { "type": "string" }] },
150 "protocol": { "type": "string", "enum": ["TCP", "UDP", "SCTP"] },
151 "nodePort": { "type": "integer", "minimum": 30000, "maximum": 32767 }
152 }
153 }
154 },
155 "clusterIP": { "type": "string" },
156 "externalName": { "type": "string" }
157 }
158 }
159 }
160}
161"#;
162
163const K8S_CONFIGMAP: &str = r#"
165{
166 "$schema": "http://json-schema.org/draft-07/schema#",
167 "type": "object",
168 "required": ["apiVersion", "kind", "metadata"],
169 "properties": {
170 "apiVersion": { "type": "string", "const": "v1" },
171 "kind": { "type": "string", "const": "ConfigMap" },
172 "metadata": {
173 "type": "object",
174 "required": ["name"],
175 "properties": {
176 "name": { "type": "string" },
177 "namespace": { "type": "string" }
178 }
179 },
180 "data": { "type": "object", "additionalProperties": { "type": "string" } },
181 "binaryData": { "type": "object", "additionalProperties": { "type": "string" } },
182 "immutable": { "type": "boolean" }
183 }
184}
185"#;
186
187const K8S_SECRET: &str = r#"
189{
190 "$schema": "http://json-schema.org/draft-07/schema#",
191 "type": "object",
192 "required": ["apiVersion", "kind", "metadata"],
193 "properties": {
194 "apiVersion": { "type": "string", "const": "v1" },
195 "kind": { "type": "string", "const": "Secret" },
196 "metadata": {
197 "type": "object",
198 "required": ["name"],
199 "properties": {
200 "name": { "type": "string" },
201 "namespace": { "type": "string" }
202 }
203 },
204 "type": { "type": "string" },
205 "data": { "type": "object", "additionalProperties": { "type": "string" } },
206 "stringData": { "type": "object", "additionalProperties": { "type": "string" } },
207 "immutable": { "type": "boolean" }
208 }
209}
210"#;
211
212const GITLAB_CI: &str = r#"
214{
215 "$schema": "http://json-schema.org/draft-07/schema#",
216 "type": "object",
217 "properties": {
218 "stages": {
219 "type": "array",
220 "items": { "type": "string" }
221 },
222 "variables": { "type": "object" },
223 "default": { "type": "object" },
224 "workflow": { "type": "object" }
225 },
226 "additionalProperties": {
227 "oneOf": [
228 { "type": "object" },
229 { "type": "array" }
230 ]
231 },
232 "patternProperties": {
233 "^[a-zA-Z_][a-zA-Z0-9_-]*$": {
234 "type": "object",
235 "properties": {
236 "stage": { "type": "string" },
237 "script": {
238 "oneOf": [
239 { "type": "string" },
240 { "type": "array", "items": { "type": "string" } }
241 ]
242 },
243 "image": { "type": "string" },
244 "only": { "type": "array" },
245 "except": { "type": "array" },
246 "rules": { "type": "array" },
247 "extends": { "type": "string" }
248 }
249 }
250 }
251}
252"#;
253
254const DOCKER_COMPOSE: &str = r#"
256{
257 "$schema": "http://json-schema.org/draft-07/schema#",
258 "type": "object",
259 "required": ["services"],
260 "properties": {
261 "version": { "type": "string" },
262 "services": {
263 "type": "object",
264 "additionalProperties": {
265 "type": "object",
266 "properties": {
267 "image": { "type": "string" },
268 "build": {
269 "oneOf": [
270 { "type": "string" },
271 { "type": "object" }
272 ]
273 },
274 "ports": {
275 "type": "array",
276 "items": {
277 "oneOf": [
278 { "type": "integer" },
279 { "type": "string" }
280 ]
281 }
282 },
283 "environment": {
284 "oneOf": [
285 { "type": "array" },
286 { "type": "object" }
287 ]
288 },
289 "volumes": { "type": "array" },
290 "depends_on": {
291 "oneOf": [
292 { "type": "array" },
293 { "type": "object" }
294 ]
295 },
296 "networks": { "type": "array" },
297 "restart": { "type": "string" }
298 }
299 }
300 },
301 "volumes": { "type": "object" },
302 "networks": { "type": "object" }
303 }
304}
305"#;
306
307const GITHUB_ACTIONS: &str = r#"
309{
310 "$schema": "http://json-schema.org/draft-07/schema#",
311 "type": "object",
312 "required": ["on", "jobs"],
313 "properties": {
314 "name": { "type": "string" },
315 "on": {
316 "oneOf": [
317 { "type": "string" },
318 { "type": "array" },
319 { "type": "object" }
320 ]
321 },
322 "env": { "type": "object" },
323 "defaults": { "type": "object" },
324 "concurrency": { "type": "object" },
325 "jobs": {
326 "type": "object",
327 "additionalProperties": {
328 "type": "object",
329 "required": ["runs-on"],
330 "properties": {
331 "runs-on": {
332 "oneOf": [
333 { "type": "string" },
334 { "type": "array" }
335 ]
336 },
337 "needs": {
338 "oneOf": [
339 { "type": "string" },
340 { "type": "array" }
341 ]
342 },
343 "if": { "type": "string" },
344 "steps": {
345 "type": "array",
346 "items": {
347 "type": "object",
348 "properties": {
349 "name": { "type": "string" },
350 "run": { "type": "string" },
351 "uses": { "type": "string" },
352 "with": { "type": "object" },
353 "env": { "type": "object" },
354 "if": { "type": "string" }
355 }
356 }
357 },
358 "env": { "type": "object" },
359 "outputs": { "type": "object" },
360 "timeout-minutes": { "type": "integer" }
361 }
362 }
363 }
364 }
365}
366"#;
367
368const BUNDLED_SCHEMAS: &[(&str, &str)] = &[
370 ("k8s/deployment", K8S_DEPLOYMENT),
371 ("k8s/service", K8S_SERVICE),
372 ("k8s/configmap", K8S_CONFIGMAP),
373 ("k8s/secret", K8S_SECRET),
374 ("gitlab-ci", GITLAB_CI),
375 ("docker-compose", DOCKER_COMPOSE),
376 ("github-actions", GITHUB_ACTIONS),
377];
378
379pub fn get_bundled_schema(schema_type: &str) -> Option<Value> {
381 for (key, schema_str) in BUNDLED_SCHEMAS {
382 if *key == schema_type {
383 return serde_json::from_str(schema_str).ok();
384 }
385 }
386 None
387}
388
389pub fn list_bundled_schemas() -> Vec<&'static str> {
391 BUNDLED_SCHEMAS.iter().map(|(key, _)| *key).collect()
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397
398 #[test]
399 fn test_get_bundled_schema_k8s_deployment() {
400 let schema = get_bundled_schema("k8s/deployment");
401 assert!(schema.is_some());
402 let schema = schema.unwrap();
403 assert_eq!(schema["properties"]["kind"]["const"], "Deployment");
404 }
405
406 #[test]
407 fn test_get_bundled_schema_gitlab_ci() {
408 let schema = get_bundled_schema("gitlab-ci");
409 assert!(schema.is_some());
410 let schema = schema.unwrap();
411 assert!(schema["properties"]["stages"].is_object());
412 }
413
414 #[test]
415 fn test_get_bundled_schema_unknown() {
416 let schema = get_bundled_schema("unknown/type");
417 assert!(schema.is_none());
418 }
419
420 #[test]
421 fn test_list_bundled_schemas() {
422 let schemas = list_bundled_schemas();
423 assert!(schemas.contains(&"k8s/deployment"));
424 assert!(schemas.contains(&"gitlab-ci"));
425 assert_eq!(schemas.len(), 7);
426 }
427
428 #[test]
429 fn test_all_schemas_valid_json() {
430 for (key, schema_str) in BUNDLED_SCHEMAS {
431 let result: Result<Value, _> = serde_json::from_str(schema_str);
432 assert!(result.is_ok(), "Schema {} is not valid JSON", key);
433 }
434 }
435}