{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://fortproof.dev/schemas/evidence/evidence-manifest.schema.json",
  "title": "Evidence manifest (produced inside an approved reusable security workflow)",
  "description": "Status: DESIGNED. Written by the reusable workflow as evidence-manifest.json, attested with actions/attest (predicate type below), uploaded as artifact 'aap-evidence-<tool>'. The platform treats every field as UNTRUSTED until verified against the GitHub API (run, referenced_workflows, head_sha) and the attestation.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schema_version",
    "predicate_type",
    "evidence_type",
    "repository",
    "commit_sha",
    "ref",
    "run",
    "tool",
    "result",
    "files",
    "produced_at"
  ],
  "properties": {
    "schema_version": {
      "const": "1.0"
    },
    "predicate_type": {
      "const": "https://fortproof.dev/attestation/evidence/v1"
    },
    "evidence_type": {
      "enum": [
        "scan.sast",
        "scan.sca",
        "scan.secrets",
        "scan.iac",
        "scan.container",
        "sbom",
        "provenance.attestation",
        "scan.malicious_package",
        "scan.workflow_hardening",
        "test.security",
        "scan.dast",
        "scan.api",
        "deploy.record"
      ]
    },
    "repository": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "full_name",
        "id"
      ],
      "properties": {
        "full_name": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_.-]+(/[A-Za-z0-9_.-]+)+$",
          "description": "owner/repo (GitHub) or group/subgroup/project (GitLab)"
        },
        "id": {
          "type": "integer",
          "description": "Numeric repository ID: stable across renames, cross-checked against the webhook payload"
        },
        "visibility": {
          "enum": [
            "public",
            "private",
            "internal"
          ]
        }
      }
    },
    "commit_sha": {
      "type": "string",
      "pattern": "^[0-9a-f]{40}$"
    },
    "ref": {
      "type": "string",
      "maxLength": 255
    },
    "pull_request": {
      "type": [
        "integer",
        "null"
      ]
    },
    "artifact": {
      "type": "object",
      "description": "Present for artifact-bound evidence (container scan, build SBOM, provenance, deploy record)",
      "additionalProperties": false,
      "required": [
        "digest"
      ],
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 512
        },
        "digest": {
          "type": "string",
          "pattern": "^sha256:[0-9a-f]{64}$"
        }
      }
    },
    "environment": {
      "type": "object",
      "description": "For DAST/API/deploy evidence: which deployed environment was tested or deployed to",
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 100
        },
        "target_url": {
          "type": "string",
          "format": "uri",
          "maxLength": 2048
        },
        "authenticated": {
          "type": "boolean"
        }
      }
    },
    "run": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "attempt",
        "workflow_ref",
        "event",
        "runner_environment"
      ],
      "properties": {
        "id": {
          "type": "integer"
        },
        "attempt": {
          "type": "integer",
          "minimum": 1
        },
        "workflow_ref": {
          "type": "string",
          "maxLength": 512
        },
        "job_workflow_ref": {
          "type": "string",
          "maxLength": 512,
          "description": "The reusable workflow path@ref that produced this manifest"
        },
        "event": {
          "type": "string",
          "maxLength": 64
        },
        "runner_environment": {
          "enum": [
            "github-hosted",
            "self-hosted-ephemeral",
            "self-hosted"
          ]
        }
      }
    },
    "tool": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "name",
        "version"
      ],
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 64
        },
        "version": {
          "type": "string",
          "maxLength": 64
        },
        "policy_ref": {
          "type": "string",
          "maxLength": 256,
          "description": "Ruleset / query suite / policy bundle and version"
        },
        "binary_sha256": {
          "type": "string",
          "pattern": "^[0-9a-f]{64}$"
        }
      }
    },
    "result": {
      "enum": [
        "pass",
        "fail",
        "findings",
        "inconclusive",
        "error"
      ]
    },
    "summary": {
      "type": "object",
      "description": "Tool-specific normalised summary; the platform recomputes counts from raw files and ignores mismatches here",
      "maxProperties": 50
    },
    "files": {
      "type": "array",
      "minItems": 1,
      "maxItems": 50,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "path",
          "sha256",
          "media_type"
        ],
        "properties": {
          "path": {
            "type": "string",
            "pattern": "^[A-Za-z0-9._/-]+$",
            "maxLength": 255,
            "not": {
              "pattern": "(^/|\\.\\.)"
            }
          },
          "sha256": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "media_type": {
            "enum": [
              "application/sarif+json",
              "application/vnd.cyclonedx+json",
              "application/spdx+json",
              "application/json",
              "application/xml",
              "text/plain"
            ]
          },
          "size_bytes": {
            "type": "integer",
            "minimum": 0,
            "maximum": 209715200
          }
        }
      }
    },
    "produced_at": {
      "type": "string",
      "format": "date-time"
    }
  }
}
