Skip to content

Commit c055ddb

Browse files
committed
feat: add JSON Schema validation and CI data integrity checks
Adds schema definitions and automated validation for all five data files: Schemas (schemas/*.schema.json): - Enforce required fields (id, name, status where applicable) - Constrain orbit_type and status to known enum values - Validate ISO 8601 date format on all date fields - Require numeric types for mass_kg, power_watts, altitude_km - Reject unknown fields (additionalProperties: false) Validation script (scripts/validate_schemas.js): - Zero-dependency beyond ajv (devDependency only, not runtime) - Runs locally: npm run validate - Exits 0 on success, 1 on any schema violation CI workflow (.github/workflows/validate_data.yml): - Triggers on any PR or push to master that touches data/ or schemas/ - Runs on ubuntu-latest with Node 20 - Fails the PR if any data file violates its schema All five data files currently pass validation (confirmed pre-commit).
1 parent 332530b commit c055ddb

8 files changed

Lines changed: 212 additions & 1 deletion
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Validate Data
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "data/**"
7+
- "schemas/**"
8+
push:
9+
branches:
10+
- master
11+
paths:
12+
- "data/**"
13+
- "schemas/**"
14+
15+
jobs:
16+
validate:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- name: Set up Node.js
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: "20"
25+
26+
- name: Install dependencies
27+
run: npm install
28+
29+
- name: Validate data files against schemas
30+
run: node scripts/validate_schemas.js

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
"repository": "isro.vercel.app",
77
"author": "isro",
88
"license": "MIT",
9+
"scripts": {
10+
"validate": "node scripts/validate_schemas.js"
11+
},
912
"dependencies": {},
10-
"devDependencies": {}
13+
"devDependencies": {
14+
"ajv": "^8.17.1"
15+
}
1116
}

schemas/centres.schema.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "Centres",
4+
"type": "object",
5+
"required": ["centres"],
6+
"additionalProperties": false,
7+
"properties": {
8+
"centres": {
9+
"type": "array",
10+
"items": {
11+
"type": "object",
12+
"required": ["id", "name"],
13+
"additionalProperties": false,
14+
"properties": {
15+
"id": { "type": "integer", "minimum": 1 },
16+
"name": { "type": "string", "minLength": 1 },
17+
"place": { "type": ["string", "null"] },
18+
"state": { "type": ["string", "null"] }
19+
}
20+
}
21+
}
22+
}
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "Customer Satellites",
4+
"type": "object",
5+
"required": ["customer_satellites"],
6+
"additionalProperties": false,
7+
"properties": {
8+
"customer_satellites": {
9+
"type": "array",
10+
"items": {
11+
"type": "object",
12+
"required": ["id"],
13+
"additionalProperties": false,
14+
"properties": {
15+
"id": { "type": "integer", "minimum": 1 },
16+
"country": { "type": ["string", "null"] },
17+
"launch_date": { "type": ["string", "null"], "pattern": "^\\d{4}-\\d{2}-\\d{2}$" },
18+
"mass_kg": { "type": ["number", "null"], "minimum": 0 },
19+
"launcher": { "type": ["string", "null"] }
20+
}
21+
}
22+
}
23+
}
24+
}

schemas/launchers.schema.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "Launchers",
4+
"type": "object",
5+
"required": ["launchers"],
6+
"additionalProperties": false,
7+
"properties": {
8+
"launchers": {
9+
"type": "array",
10+
"items": {
11+
"type": "object",
12+
"required": ["id"],
13+
"additionalProperties": false,
14+
"properties": {
15+
"id": { "type": "integer", "minimum": 1 },
16+
"vehicle_family": {
17+
"type": ["string", "null"],
18+
"enum": ["SLV", "ASLV", "PSLV", "GSLV", "GSLV Mk III", "LVM-3", "RLV", "Scramjet-TD", null]
19+
}
20+
}
21+
}
22+
}
23+
}
24+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "Spacecraft Missions",
4+
"type": "object",
5+
"required": ["spacecraft_missions"],
6+
"additionalProperties": false,
7+
"properties": {
8+
"spacecraft_missions": {
9+
"type": "array",
10+
"items": {
11+
"type": "object",
12+
"required": ["id", "name", "status"],
13+
"additionalProperties": false,
14+
"properties": {
15+
"id": { "type": "integer", "minimum": 1 },
16+
"name": { "type": "string", "minLength": 1 },
17+
"mission_type": { "type": ["string", "null"] },
18+
"launch_date": { "type": ["string", "null"], "pattern": "^\\d{4}-\\d{2}-\\d{2}$" },
19+
"launch_site": { "type": ["string", "null"] },
20+
"launch_vehicle": { "type": ["string", "null"] },
21+
"orbit": { "type": ["string", "null"] },
22+
"orbit_type": { "type": ["string", "null"], "enum": ["LEO", "SSO", "GEO", "Lunar", "Interplanetary", "Failed", null] },
23+
"altitude_km": { "type": ["number", "null"], "minimum": 0 },
24+
"inclination_deg": { "type": ["number", "null"], "minimum": 0, "maximum": 180 },
25+
"mass_kg": { "type": ["number", "null"], "minimum": 0 },
26+
"power_watts": { "type": ["number", "null"], "minimum": 0 },
27+
"mission_life": { "type": ["string", "null"] },
28+
"status": { "type": "string", "enum": ["active", "decommissioned", "failed", "unknown"] },
29+
"payloads": { "type": ["string", "null"] },
30+
"stabilization": { "type": ["string", "null"] },
31+
"propulsion": { "type": ["string", "null"] }
32+
}
33+
}
34+
}
35+
}
36+
}

schemas/spacecrafts.schema.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "Spacecrafts",
4+
"type": "object",
5+
"required": ["spacecrafts"],
6+
"additionalProperties": false,
7+
"properties": {
8+
"spacecrafts": {
9+
"type": "array",
10+
"items": {
11+
"type": "object",
12+
"required": ["id", "name"],
13+
"additionalProperties": false,
14+
"properties": {
15+
"id": { "type": "integer", "minimum": 1 },
16+
"name": { "type": "string", "minLength": 1 },
17+
"launch_date": { "type": ["string", "null"], "pattern": "^\\d{4}-\\d{2}-\\d{2}$" },
18+
"launch_vehicle": { "type": ["string", "null"] },
19+
"mission_type": { "type": ["string", "null"] },
20+
"orbit_type": { "type": ["string", "null"], "enum": ["LEO", "SSO", "GEO", "Lunar", "Interplanetary", "Failed", null] },
21+
"mass_kg": { "type": ["number", "null"], "minimum": 0 },
22+
"status": { "type": ["string", "null"], "enum": ["active", "decommissioned", "failed", "unknown", null] }
23+
}
24+
}
25+
}
26+
}
27+
}

scripts/validate_schemas.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Validates all data files against their JSON Schemas.
4+
* Run: node scripts/validate_schemas.js
5+
* Exit code 0 = all valid, 1 = validation errors found.
6+
*/
7+
8+
const Ajv = require("ajv");
9+
const path = require("path");
10+
const fs = require("fs");
11+
12+
const ajv = new Ajv({ allErrors: true });
13+
14+
const FILES = [
15+
{ data: "data/spacecrafts.json", schema: "schemas/spacecrafts.schema.json" },
16+
{ data: "data/launchers.json", schema: "schemas/launchers.schema.json" },
17+
{ data: "data/customer_satellites.json", schema: "schemas/customer_satellites.schema.json" },
18+
{ data: "data/centres.json", schema: "schemas/centres.schema.json" },
19+
{ data: "data/spacecraft_missions.json", schema: "schemas/spacecraft_missions.schema.json" },
20+
];
21+
22+
const root = path.resolve(__dirname, "..");
23+
let allValid = true;
24+
25+
for (const { data: dataFile, schema: schemaFile } of FILES) {
26+
const data = JSON.parse(fs.readFileSync(path.join(root, dataFile), "utf8"));
27+
const schema = JSON.parse(fs.readFileSync(path.join(root, schemaFile), "utf8"));
28+
const validate = ajv.compile(schema);
29+
const valid = validate(data);
30+
31+
if (valid) {
32+
console.log(`✓ ${dataFile}`);
33+
} else {
34+
console.error(`✗ ${dataFile}`);
35+
for (const err of validate.errors) {
36+
console.error(` ${err.instancePath || "(root)"} ${err.message}`);
37+
}
38+
allValid = false;
39+
}
40+
}
41+
42+
process.exit(allValid ? 0 : 1);

0 commit comments

Comments
 (0)