{
  "description": "ImageSync is the Schema for the imagesyncs API",
  "properties": {
    "apiVersion": {
      "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
      "type": [
        "string",
        "null"
      ]
    },
    "kind": {
      "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
      "type": [
        "string",
        "null"
      ]
    },
    "metadata": {
      "type": [
        "object",
        "null"
      ]
    },
    "spec": {
      "additionalProperties": false,
      "description": "spec defines the desired state of ImageSync",
      "properties": {
        "createDestinationRepos": {
          "description": "createDestinationRepos, when true, causes the controller to create\ndestination repositories before pushing (currently ECR only).",
          "type": [
            "boolean",
            "null"
          ]
        },
        "destination": {
          "additionalProperties": false,
          "description": "destination defines the registry to push images to.",
          "properties": {
            "auth": {
              "additionalProperties": false,
              "description": "auth configures how the controller authenticates to push images.",
              "properties": {
                "method": {
                  "description": "method specifies the authentication strategy.\n\"secret\" uses a dockerconfigjson Secret; \"ecr\" uses IRSA for AWS ECR;\n\"gar\" uses Application Default Credentials / GKE Workload Identity for\nGoogle Artifact Registry; \"anonymous\" explicitly disables authentication\nfor public/local registries.",
                  "enum": [
                    "secret",
                    "ecr",
                    "gar",
                    "anonymous"
                  ],
                  "type": "string"
                },
                "secretRef": {
                  "additionalProperties": false,
                  "description": "secretRef references a kubernetes.io/dockerconfigjson Secret.\nRequired when method is \"secret\".",
                  "properties": {
                    "name": {
                      "description": "name of the Secret",
                      "type": "string"
                    },
                    "namespace": {
                      "description": "namespace of the Secret. Defaults to the ImageSync's namespace if omitted.",
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "name"
                  ],
                  "type": [
                    "object",
                    "null"
                  ]
                }
              },
              "required": [
                "method"
              ],
              "type": "object"
            },
            "registry": {
              "description": "registry is the destination registry host\n(e.g., \"123456789012.dkr.ecr.us-gov-west-1.amazonaws.com\").",
              "type": "string"
            },
            "repositoryPrefix": {
              "description": "repositoryPrefix is prepended to image names in the destination.\nFor example, with prefix \"chainguard\", image \"go\" becomes \"chainguard/go\".",
              "type": [
                "string",
                "null"
              ]
            }
          },
          "required": [
            "auth",
            "registry"
          ],
          "type": "object"
        },
        "images": {
          "description": "images is the list of images to sync from source to destination.",
          "items": {
            "additionalProperties": false,
            "description": "ImageSpec defines a single image to sync, including which tags to copy.",
            "properties": {
              "maxTags": {
                "default": 10,
                "description": "maxTags limits how many semver-matched tags are synced (newest first).\nOnly applies when semver is set. 0 means unlimited.",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "name": {
                "description": "name is the image name relative to the source registry\n(e.g., \"go\", \"node\", \"python\").",
                "type": "string"
              },
              "semver": {
                "description": "semver is a semver constraint string for auto-discovering tags from the\nsource registry. Supports wildcards (1.x, 1.3.x), ranges (\u003e=1.22.0 \u003c1.23.0),\ntilde (~1.3.0), and caret (^1.3.0) syntax. Non-semver tags in the registry\nare silently skipped. Resolved tags are sorted by version descending (newest first).",
                "type": [
                  "string",
                  "null"
                ]
              },
              "tags": {
                "description": "tags is the list of explicit image tags to sync (e.g., [\"latest\", \"1.22\"]).\nAt least one of tags or semver must be specified.",
                "items": {
                  "type": "string"
                },
                "type": [
                  "array",
                  "null"
                ]
              }
            },
            "required": [
              "name"
            ],
            "type": "object"
          },
          "minItems": 1,
          "type": "array"
        },
        "schedule": {
          "description": "schedule is a cron expression or shorthand (e.g., \"0 */6 * * *\", \"@every 1h\")\ncontrolling how often images are synced.",
          "type": "string"
        },
        "source": {
          "additionalProperties": false,
          "description": "source defines the registry to pull images from.",
          "properties": {
            "authSecretRef": {
              "additionalProperties": false,
              "description": "authSecretRef references a kubernetes.io/dockerconfigjson Secret for pull authentication.\nOmit for public registries",
              "properties": {
                "name": {
                  "description": "name of the Secret",
                  "type": "string"
                },
                "namespace": {
                  "description": "namespace of the Secret. Defaults to the ImageSync's namespace if omitted.",
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "required": [
                "name"
              ],
              "type": [
                "object",
                "null"
              ]
            },
            "registry": {
              "description": "registry is the source registry host (e.g., \"cgr.dev/my-org\", \"docker.io/library\").\nNo scheme — just the host and optional path prefix.",
              "type": "string"
            }
          },
          "required": [
            "registry"
          ],
          "type": "object"
        },
        "validation": {
          "additionalProperties": false,
          "description": "validation configures optional pre-sync validation gates (cosign, vulnerability).\nWhen nil, no validation is performed.",
          "properties": {
            "cosign": {
              "additionalProperties": false,
              "description": "cosign configures cosign signature verification.",
              "properties": {
                "enabled": {
                  "description": "enabled activates cosign signature verification.",
                  "type": "boolean"
                },
                "keylessIssuer": {
                  "description": "keylessIssuer is the OIDC issuer for keyless (Fulcio) verification.\nRequired when publicKey is empty and enabled is true.",
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "publicKey": {
                  "description": "publicKey is a PEM-encoded cosign public key for key-based verification.\nWhen empty, keyless verification is used (requires keylessIssuer).",
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "required": [
                "enabled"
              ],
              "type": [
                "object",
                "null"
              ]
            },
            "sbomGate": {
              "additionalProperties": false,
              "description": "sbomGate requires a Software Bill of Materials (SBOM) to be attached\nas an OCI referrer before allowing sync. Supports SPDX and CycloneDX formats.",
              "properties": {
                "enabled": {
                  "description": "enabled activates SBOM gate checking.",
                  "type": "boolean"
                }
              },
              "required": [
                "enabled"
              ],
              "type": [
                "object",
                "null"
              ]
            },
            "vulnerabilityGate": {
              "additionalProperties": false,
              "description": "vulnerabilityGate configures vulnerability severity gating.",
              "properties": {
                "enabled": {
                  "description": "enabled activates vulnerability gate checking.",
                  "type": "boolean"
                },
                "maxSeverity": {
                  "default": "critical",
                  "description": "maxSeverity is the highest severity level allowed. Images with findings\nat or above this level are blocked from syncing.",
                  "enum": [
                    "critical",
                    "high",
                    "medium",
                    "low"
                  ],
                  "type": "string"
                },
                "requireCveReport": {
                  "default": true,
                  "description": "requireCveReport, when true (default), blocks sync if no SARIF vulnerability\nreport is found attached to the source image. When false, images without\nreports are allowed through.",
                  "type": [
                    "boolean",
                    "null"
                  ]
                }
              },
              "required": [
                "enabled",
                "maxSeverity"
              ],
              "type": [
                "object",
                "null"
              ]
            }
          },
          "type": [
            "object",
            "null"
          ]
        }
      },
      "required": [
        "destination",
        "images",
        "schedule",
        "source"
      ],
      "type": "object"
    },
    "status": {
      "additionalProperties": false,
      "description": "status defines the observed state of ImageSync",
      "properties": {
        "conditions": {
          "description": "conditions represent the current state of the ImageSync resource.",
          "items": {
            "additionalProperties": false,
            "description": "Condition contains details for one aspect of the current state of this API Resource.",
            "properties": {
              "lastTransitionTime": {
                "description": "lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.",
                "format": "date-time",
                "type": "string"
              },
              "message": {
                "description": "message is a human readable message indicating details about the transition.\nThis may be an empty string.",
                "maxLength": 32768,
                "type": "string"
              },
              "observedGeneration": {
                "description": "observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.",
                "format": "int64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "reason": {
                "description": "reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.",
                "maxLength": 1024,
                "minLength": 1,
                "pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
                "type": "string"
              },
              "status": {
                "description": "status of the condition, one of True, False, Unknown.",
                "enum": [
                  "True",
                  "False",
                  "Unknown"
                ],
                "type": "string"
              },
              "type": {
                "description": "type of condition in CamelCase or in foo.example.com/CamelCase.",
                "maxLength": 316,
                "pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
                "type": "string"
              }
            },
            "required": [
              "lastTransitionTime",
              "message",
              "reason",
              "status",
              "type"
            ],
            "type": "object"
          },
          "type": [
            "array",
            "null"
          ],
          "x-kubernetes-list-map-keys": [
            "type"
          ],
          "x-kubernetes-list-type": "map"
        },
        "failedImages": {
          "description": "failedImages is the number of image+tag combinations that failed to sync.",
          "type": [
            "integer",
            "null"
          ]
        },
        "images": {
          "description": "images contains per-image sync status details.",
          "items": {
            "additionalProperties": false,
            "description": "ImageSyncStatusImage records the sync status for all tags of a single image.",
            "properties": {
              "name": {
                "description": "name is the image name (e.g., \"alpine\", \"go\").",
                "type": "string"
              },
              "tags": {
                "description": "tags contains per-tag sync results.",
                "items": {
                  "additionalProperties": false,
                  "description": "TagSyncStatus records the result of syncing a single image tag.",
                  "properties": {
                    "error": {
                      "description": "error contains the failure reason if synced is false.",
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "lastSyncTime": {
                      "description": "lastSyncTime is when this specific tag was last synced.",
                      "format": "date-time",
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "sourceDigest": {
                      "description": "sourceDigest is the manifest digest of the source image (e.g., \"sha256:abc123...\").\nUsed for digest comparison to skip already-synced images.",
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "synced": {
                      "description": "synced indicates whether this tag was successfully copied.",
                      "type": "boolean"
                    },
                    "tag": {
                      "description": "tag is the image tag that was synced (e.g., \"latest\", \"1.22\").",
                      "type": "string"
                    },
                    "validationError": {
                      "description": "validationError contains the validation failure reason, if any.",
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "verified": {
                      "description": "verified indicates whether pre-sync validation passed for this tag.\nOnly meaningful when validation is configured.",
                      "type": [
                        "boolean",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "synced",
                    "tag"
                  ],
                  "type": "object"
                },
                "type": [
                  "array",
                  "null"
                ]
              }
            },
            "required": [
              "name"
            ],
            "type": "object"
          },
          "type": [
            "array",
            "null"
          ]
        },
        "lastSyncTime": {
          "description": "lastSyncTime is the timestamp of the most recent sync attempt.",
          "format": "date-time",
          "type": [
            "string",
            "null"
          ]
        },
        "nextSyncTime": {
          "description": "nextSyncTime is the calculated time of the next scheduled sync.",
          "format": "date-time",
          "type": [
            "string",
            "null"
          ]
        },
        "observedGeneration": {
          "description": "observedGeneration is the most recent generation observed by the controller.\nWhen this differs from metadata.generation, the controller syncs immediately\nregardless of schedule.",
          "format": "int64",
          "type": [
            "integer",
            "null"
          ]
        },
        "syncedImages": {
          "description": "syncedImages is the number of image+tag combinations successfully synced or already up-to-date.",
          "type": [
            "integer",
            "null"
          ]
        },
        "totalImages": {
          "description": "totalImages is the total number of image+tag combinations to sync.",
          "type": [
            "integer",
            "null"
          ]
        }
      },
      "type": [
        "object",
        "null"
      ]
    }
  },
  "required": [
    "spec"
  ],
  "type": "object"
}