#
# Copyright 2021 The Sigstore Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

swagger: "2.0"
info:
  title: Rekor
  description: Rekor is a cryptographically secure, immutable transparency log for signed software releases.
  version: 1.0.0

host: rekor.sigstore.dev
schemes:
  - http

consumes:
  - application/json
produces:
  - application/json

paths:
  /api/v1/index/retrieve:
    post:
      summary: Searches index by entry metadata
      description: >
        EXPERIMENTAL - this endpoint is offered as best effort only and may be changed or removed in future releases.

        The results returned from this endpoint may be incomplete.
      deprecated: true
      operationId: searchIndex
      tags:
        - index
      parameters:
        - in: body
          name: query
          required: true
          schema:
            $ref: '#/definitions/SearchIndex'
      responses:
        200:
          description: Returns zero or more entry UUIDs from the transparency log based on search query
          schema:
            type: array
            items:
              type: string
              description: Entry UUID in transparency log
              pattern: '^([0-9a-fA-F]{64}|[0-9a-fA-F]{80})$'
        400:
          $ref: '#/responses/BadContent'
        default:
          $ref: '#/responses/InternalServerError'

  /api/v1/log:
    get:
      summary: Get information about the current state of the transparency log
      description: Returns the current root hash and size of the merkle tree used to store the log entries.
      operationId: getLogInfo
      tags:
        - tlog
      responses:
        200:
          description: A JSON object with the root hash and tree size as properties
          schema:
            $ref: '#/definitions/LogInfo'
        default:
          $ref: '#/responses/InternalServerError'

  /api/v1/log/publicKey:
    get:
      summary: Retrieve the public key that can be used to validate the signed tree head
      description: Returns the public key that can be used to validate the signed tree head
      operationId: getPublicKey
      tags:
        - pubkey
      parameters:
        - in: query
          name: treeID
          type: string
          pattern: '^[0-9]+$'
          description: The tree ID of the tree you wish to get a public key for
      produces:
        - application/x-pem-file
      responses:
        200:
          description: The public key
          schema:
            type: string
        default:
          $ref: '#/responses/InternalServerError'

  /api/v1/log/proof:
    get:
      summary: Get information required to generate a consistency proof for the transparency log
      description: Returns a list of hashes for specified tree sizes that can be used to confirm the consistency of the transparency log
      operationId: getLogProof
      tags:
        - tlog
      parameters:
        - in: query
          name: firstSize
          type: integer
          default: 1
          minimum: 1
          description: >
            The size of the tree that you wish to prove consistency from (1 means the beginning of the log)
            Defaults to 1 if not specified
        - in: query
          name: lastSize
          type: integer
          required: true
          minimum: 1
          description: The size of the tree that you wish to prove consistency to
        - in: query
          name: treeID
          type: string
          pattern: '^[0-9]+$'
          description: The tree ID of the tree that you wish to prove consistency for
      responses:
        200:
          description: All hashes required to compute the consistency proof
          schema:
            $ref: '#/definitions/ConsistencyProof'
        400:
          $ref: '#/responses/BadContent'
        default:
          $ref: '#/responses/InternalServerError'

  /api/v1/log/entries:
    post:
      summary: Creates an entry in the transparency log
      description: >
        Creates an entry in the transparency log for a detached signature, public key, and content.
      operationId: createLogEntry
      tags:
        - entries
      parameters:
        - in: body
          name: proposedEntry
          schema:
            $ref: '#/definitions/ProposedEntry'
          required: true
      responses:
        201:
          description: Returns the entry created in the transparency log
          headers:
            ETag:
              type: string
              description: UUID of log entry
            Location:
              type: string
              description: URI location of log entry
              format: uri
          schema:
            $ref: '#/definitions/LogEntry'
        400:
          $ref: '#/responses/BadContent'
        409:
          $ref: '#/responses/Conflict'
        default:
          $ref: '#/responses/InternalServerError'
    get:
      summary: Retrieves an entry and inclusion proof from the transparency log (if it exists) by index
      operationId: getLogEntryByIndex
      tags:
        - entries
      parameters:
        - in: query
          name: logIndex
          type: integer
          required: true
          minimum: 0
          description: specifies the index of the entry in the transparency log to be retrieved
      responses:
        200:
          description: the entry in the transparency log requested along with an inclusion proof
          schema:
            $ref: '#/definitions/LogEntry'
        404:
          $ref: '#/responses/NotFound'
        default:
          $ref: '#/responses/InternalServerError'

  /api/v1/log/entries/{entryUUID}:
    get:
      summary: Get log entry and information required to generate an inclusion proof for the entry in the transparency log
      description: Returns the entry, root hash, tree size, and a list of hashes that can be used to calculate proof of an entry being included in the transparency log
      operationId: getLogEntryByUUID
      tags:
        - entries
      parameters:
        - in: path
          name: entryUUID
          type: string
          required: true
          pattern: '^([0-9a-fA-F]{64}|[0-9a-fA-F]{80})$'
          description: the UUID of the entry for which the inclusion proof information should be returned
      responses:
        200:
          description: Information needed for a client to compute the inclusion proof
          schema:
            $ref: '#/definitions/LogEntry'
        404:
          $ref: '#/responses/NotFound'
        default:
          $ref: '#/responses/InternalServerError'

  /api/v1/log/entries/retrieve:
    post:
      summary: Searches transparency log for one or more log entries
      operationId: searchLogQuery
      tags:
        - entries
      parameters:
        - in: body
          name: entry
          required: true
          schema:
            $ref: '#/definitions/SearchLogQuery'
      responses:
        200:
          description: Returns zero or more entries from the transparency log, according to how many were included in request query
          schema:
            type: array
            items:
              $ref: '#/definitions/LogEntry'
        400:
          $ref: '#/responses/BadContent'
        422:
          $ref: '#/responses/UnprocessableEntity'
        default:
          $ref: '#/responses/InternalServerError'

definitions:
  ProposedEntry:
    type: object
    discriminator: kind
    properties:
      kind:
        type: string
    required:
      - kind

  rekord:
    type: object
    description: Rekord object
    allOf:
    - $ref: '#/definitions/ProposedEntry'
    - properties:
        apiVersion:
          type: string
          pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
        spec:
          type: object
          $ref: 'pkg/types/rekord/rekord_schema.json'
      required:
        - apiVersion
        - spec
      additionalProperties: false

  hashedrekord:
    type: object
    description: Hashed Rekord object
    allOf:
    - $ref: '#/definitions/ProposedEntry'
    - properties:
        apiVersion:
          type: string
          pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
        spec:
          type: object
          $ref: 'pkg/types/hashedrekord/hashedrekord_schema.json'
      required:
        - apiVersion
        - spec
      additionalProperties: false

  rpm:
    type: object
    description: RPM package
    allOf:
    - $ref: '#/definitions/ProposedEntry'
    - properties:
        apiVersion:
          type: string
          pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
        spec:
          type: object
          $ref: 'pkg/types/rpm/rpm_schema.json'
      required:
        - apiVersion
        - spec
      additionalProperties: false

  tuf:
    type: object
    description: TUF metadata
    allOf:
    - $ref: '#/definitions/ProposedEntry'
    - properties:
        apiVersion:
          type: string
          pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
        spec:
          type: object
          $ref: 'pkg/types/tuf/tuf_schema.json'
      required:
        - apiVersion
        - spec
      additionalProperties: false

  alpine:
    type: object
    description: Alpine package
    allOf:
    - $ref: '#/definitions/ProposedEntry'
    - properties:
        apiVersion:
          type: string
          pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
        spec:
          type: object
          $ref: 'pkg/types/alpine/alpine_schema.json'
      required:
        - apiVersion
        - spec
      additionalProperties: false

  helm:
    type: object
    description: Helm chart
    allOf:
    - $ref: '#/definitions/ProposedEntry'
    - properties:
        apiVersion:
          type: string
          pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
        spec:
          type: object
          $ref: 'pkg/types/helm/helm_schema.json'
      required:
        - apiVersion
        - spec

  intoto:
    type: object
    description: Intoto object
    allOf:
    - $ref: '#/definitions/ProposedEntry'
    - properties:
        apiVersion:
          type: string
          pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
        spec:
          type: object
          $ref: 'pkg/types/intoto/intoto_schema.json'
      required:
        - apiVersion
        - spec
      additionalProperties: false

  cose:
    type: object
    description: COSE object
    allOf:
    - $ref: '#/definitions/ProposedEntry'
    - properties:
        apiVersion:
          type: string
          pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
        spec:
          type: object
          $ref: 'pkg/types/cose/cose_schema.json'
      required:
        - apiVersion
        - spec
      additionalProperties: false

  jar:
    type: object
    description: Java Archive (JAR)
    allOf:
    - $ref: '#/definitions/ProposedEntry'
    - properties:
        apiVersion:
          type: string
          pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
        spec:
          type: object
          $ref: 'pkg/types/jar/jar_schema.json'
      required:
        - apiVersion
        - spec
      additionalProperties: false

  rfc3161:
    type: object
    description: RFC3161 Timestamp
    allOf:
    - $ref: '#/definitions/ProposedEntry'
    - properties:
        apiVersion:
          type: string
          pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
        spec:
          type: object
          $ref: 'pkg/types/rfc3161/rfc3161_schema.json'
      required:
        - apiVersion
        - spec
      additionalProperties: false

  dsse:
    type: object
    description: DSSE envelope
    allOf:
    - $ref: '#/definitions/ProposedEntry'
    - properties:
        apiVersion:
          type: string
          pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
        spec:
          type: object
          $ref: 'pkg/types/dsse/dsse_schema.json'
      required:
        - apiVersion
        - spec
      additionalProperties: false

  LogEntry:
    type: object
    additionalProperties:
      type: object
      properties:
        logID:
          type: string
          pattern: '^[0-9a-fA-F]{64}$'
          description: This is the SHA256 hash of the DER-encoded public key for the log at the time the entry was included in the log
        logIndex:
          type: integer
          minimum: 0
        body:
          type: object
          additionalProperties: true
        integratedTime:
          type: integer
          description: The time the entry was added to the log as a Unix timestamp in seconds
        attestation:
          type: object
          properties:
            data:
              format: byte

          format: byte
        verification:
          type: object
          properties:
            inclusionProof:
              $ref: '#/definitions/InclusionProof'
            signedEntryTimestamp:
              type: string
              format: byte
              # To verify the signedEntryTimestamp:
                # 1. Remove the Verification object from the JSON Document
                # 2. Canonicalize the remaining JSON document by following RFC 8785 rules
                # 3. Verify the canonicalized payload and signedEntryTimestamp against rekor's public key
              description: Signature over the logID, logIndex, body and integratedTime.
      required:
        - "logID"
        - "logIndex"
        - "body"
        - "integratedTime"

  SearchIndex:
    type: object
    properties:
      email:
        type: string
        format: email
      publicKey:
        type: object
        properties:
          format:
            type: string
            enum: ['pgp','x509','minisign', 'ssh', 'tuf']
          content:
            type: string
            format: byte
        required:
          - "format"
      hash:
        type: string
        pattern: '^(sha512:)?[0-9a-fA-F]{128}$|^(sha256:)?[0-9a-fA-F]{64}$|^(sha1:)?[0-9a-fA-F]{40}$'
      operator:
        type: string
        enum: ['and','or']

  SearchLogQuery:
    type: object
    properties:
      entryUUIDs:
        type: array
        minItems: 1
        maxItems: 10
        items:
          type: string
          pattern: '^([0-9a-fA-F]{64}|[0-9a-fA-F]{80})$'
      logIndexes:
        type: array
        minItems: 1
        maxItems: 10
        items:
          type: integer
          minimum: 0
      entries:
        type: array
        minItems: 1
        maxItems: 10
        items:
          $ref: '#/definitions/ProposedEntry'

  LogInfo:
    type: object
    properties:
      rootHash:
        type: string
        description: The current hash value stored at the root of the merkle tree
        pattern: '^[0-9a-fA-F]{64}$'
      treeSize:
        type: integer
        description: The current number of nodes in the merkle tree
        minimum: 1
      signedTreeHead:
        type: string
        format: signedCheckpoint
        description: The current signed tree head
      treeID:
        type: string
        description: The current treeID
        pattern: '^[0-9]+$'
      inactiveShards:
        type: array
        items:
          $ref: '#/definitions/InactiveShardLogInfo'

    required:
      - rootHash
      - treeSize
      - signedTreeHead
      - treeID
  InactiveShardLogInfo:
    type: object
    properties:
      rootHash:
        type: string
        description: The current hash value stored at the root of the merkle tree
        pattern: '^[0-9a-fA-F]{64}$'
      treeSize:
        type: integer
        description: The current number of nodes in the merkle tree
        minimum: 1
      signedTreeHead:
        type: string
        format: signedCheckpoint
        description: The current signed tree head
      treeID:
        type: string
        description: The current treeID
        pattern: '^[0-9]+$'
    required:
      - rootHash
      - treeSize
      - signedTreeHead
      - treeID

  ConsistencyProof:
    type: object
    properties:
      rootHash:
        type: string
        description: The hash value stored at the root of the merkle tree at the time the proof was generated
        pattern: '^[0-9a-fA-F]{64}$'
      hashes:
        type: array
        items:
          type: string
          description: SHA256 hash value expressed in hexadecimal format
          pattern: '^[0-9a-fA-F]{64}$'
    required:
      - rootHash
      - hashes

  InclusionProof:
    type: object
    properties:
      logIndex:
        type: integer
        description: The index of the entry in the transparency log
        minimum: 0
      rootHash:
        description: The hash value stored at the root of the merkle tree at the time the proof was generated
        type: string
        pattern: '^[0-9a-fA-F]{64}$'
      treeSize:
        type: integer
        description: The size of the merkle tree at the time the inclusion proof was generated
        minimum: 1
      hashes:
        description: A list of hashes required to compute the inclusion proof, sorted in order from leaf to root
        type: array
        items:
          type: string
          description: SHA256 hash value expressed in hexadecimal format
          pattern: '^[0-9a-fA-F]{64}$'
      checkpoint:
        type: string
        format: signedCheckpoint
        description: The checkpoint (signed tree head) that the inclusion proof is based on
    required:
      - logIndex
      - rootHash
      - treeSize
      - hashes
      - checkpoint

  Error:
    type: object
    properties:
      code:
        type: integer
      message:
        type: string

responses:
  BadContent:
    description: The content supplied to the server was invalid
    schema:
      $ref: "#/definitions/Error"
  Conflict:
    description: The request conflicts with the current state of the transparency log
    schema:
      $ref: "#/definitions/Error"
    headers:
      Location:
        type: string
        format: uri
  NotFound:
    description: The content requested could not be found
  InternalServerError:
    description: There was an internal error in the server while processing the request
    schema:
      $ref: "#/definitions/Error"
  UnprocessableEntity:
    description: The server understood the request but is unable to process the contained instructions
    schema:
      $ref: "#/definitions/Error"
