{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://www.dsh.so/data/security-scan.schema.json",
  "title": "SecurityScan",
  "description": "Public JSON Schema for https://www.dsh.so/data/security-scan.json. The top-level envelope exposes generatedAt/generated metadata; scans keys are plugin ids and values are per-plugin scan records. Updated daily 00:00 UTC by the Security Report pipeline (full rescan, --force). Fields are append-only: existing fields are never removed or renamed.",
  "type": "object",
  "required": [
    "generatedAt",
    "scans"
  ],
  "additionalProperties": false,
  "properties": {
    "generated": {
      "description": "Snapshot date derived from generatedAt, for compatibility with existing consumers.",
      "type": "string"
    },
    "generatedAt": {
      "description": "ISO 8601 timestamp persisted when the pipeline generated this snapshot; never derived from web build time.",
      "type": "string"
    },
    "source": {
      "type": "string"
    },
    "schema": {
      "type": "string"
    },
    "update": {
      "type": "string"
    },
    "license": {
      "type": "object",
      "additionalProperties": true
    },
    "badgeLevels": {
      "type": "object",
      "additionalProperties": true
    },
    "count": {
      "type": "integer",
      "minimum": 0
    },
    "scans": {
      "type": "object",
      "additionalProperties": false,
      "patternProperties": {
        "^[a-z0-9]+(-[a-z0-9]+)*$": {
          "type": "object",
          "required": [
            "verdict",
            "counts",
            "filesScanned",
            "scannedAt"
          ],
          "additionalProperties": true,
          "properties": {
            "verdict": {
              "description": "Overall scan conclusion. fail = critical findings in blocking categories (secrets/network/destructive/mining); warn = non-blocking critical or warning findings; pass = no critical/warning (info allowed).",
              "enum": [
                "pass",
                "warn",
                "fail"
              ]
            },
            "counts": {
              "type": "object",
              "required": [
                "critical",
                "warning",
                "info"
              ],
              "properties": {
                "critical": {
                  "type": "integer",
                  "minimum": 0
                },
                "warning": {
                  "type": "integer",
                  "minimum": 0
                },
                "info": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "criticalByCategory": {
              "description": "Critical findings grouped by category (shell / code-exec / destructive / obfuscation / secrets / network / install / mining).",
              "type": "object",
              "additionalProperties": {
                "type": "integer",
                "minimum": 0
              }
            },
            "manifest": {
              "description": "Cordis manifest (cordis.yml / agent.cordis.yml) semantic audit counts, folded into counts above.",
              "type": "object",
              "properties": {
                "high": {
                  "type": "integer",
                  "minimum": 0
                },
                "medium": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "findings": {
              "description": "Concrete findings (rule/file/line/snippet), capped at 12 per plugin.",
              "type": "array",
              "items": {
                "type": "object",
                "required": [
                  "ruleId",
                  "severity",
                  "category",
                  "file",
                  "line",
                  "snippet"
                ],
                "properties": {
                  "ruleId": {
                    "type": "string"
                  },
                  "severity": {
                    "enum": [
                      "critical",
                      "warning",
                      "info"
                    ]
                  },
                  "category": {
                    "type": "string"
                  },
                  "file": {
                    "type": "string"
                  },
                  "line": {
                    "type": [
                      "integer",
                      "null"
                    ]
                  },
                  "snippet": {
                    "type": "string"
                  }
                }
              }
            },
            "filesScanned": {
              "description": "Number of source files scanned (capped at 15 per plugin).",
              "type": "integer",
              "minimum": 0
            },
            "scannedAt": {
              "description": "ISO 8601 timestamp when the scan ran.",
              "type": "string"
            },
            "commitSha": {
              "description": "HEAD commit SHA of the default branch at scan time — the result is ONLY valid for this revision. Badge derives 'outdated' when it differs from plugins.json latestCommitSha. Legacy records may omit this until the daily full rescan backfills it.",
              "type": [
                "string",
                "null"
              ]
            },
            "pkgVersion": {
              "description": "Plugin's own version from package.json (zero-cost: file already fetched for scanning). Legacy records may omit this until the daily full rescan backfills it.",
              "type": [
                "string",
                "null"
              ]
            },
            "pkgDsh": {
              "description": "Whether the repo declares a dsh manifest (package.json `dsh` field presence). Legacy records may omit this until the daily full rescan backfills it.",
              "type": "boolean"
            }
          }
        }
      }
    }
  }
}