# Copyright 2020 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import json
from datetime import datetime

DEPS = [
    'flutter/repo_util',
    'flutter/flutter_deps',
    'recipe_engine/cipd',
    'recipe_engine/context',
    'recipe_engine/path',
    'recipe_engine/platform',
    'recipe_engine/properties',
    'recipe_engine/raw_io',
    'recipe_engine/step',
]

# This recipe builds the cosign CIPD package.
def RunSteps(api):
  env = {}
  env_prefixes = {}
  api.flutter_deps.required_deps(
      env, env_prefixes, api.properties.get('dependencies', [])
  )

  cosign_default_dir = api.path['start_dir'].join('cosign')

  cosign_download_uris = GetLatestCosignDownloadUris(api)

  for platform in ['darwin', 'linux', 'windows']:
    cosign_dir = cosign_default_dir.join(platform)

    DownloadCosignArtifacts(api, cosign_dir, platform, cosign_download_uris)

    with api.context(env=env, env_prefixes=env_prefixes):
      VerifyCosignArtifactSignature(api, cosign_dir, platform)

    UploadCosignToCipd(api, cosign_dir, platform)


def GetLatestCosignDownloadUris(api):
  """Gets the list of latest sigstore/cosign binary urls.

  Queries Github for a list of cosign releases, then picks the latest release,
  queries the artifacts for that release, and returns a list of cosign binary
  urls for that release.

  Args:
    api: luci api object.
  """
  cosign_releases_raw_response = api.step('Get cosign releases from github',
        cmd=['curl', 'https://api.github.com/repos/sigstore/cosign/releases'],
        stdout=api.raw_io.output_text()
        ).stdout
  cosign_releases = json.loads(cosign_releases_raw_response)

  latest_release = max(
    cosign_releases,
    key=lambda release: datetime.strptime(
      release.get('published_at'), '%Y-%m-%dT%H:%M:%SZ')
  ).get('url')

  release_artifacts_raw_response = api.step(
        'Get artifacts from sigstore/cosign for a specific release version',
        cmd=['curl', latest_release],
        stdout=api.raw_io.output_text()
        ).stdout
  release_artifacts = json.loads(release_artifacts_raw_response)

  release_artifacts_download_uris = list(
    map(
      lambda asset:
      asset.get('browser_download_url'),
      release_artifacts.get('assets')
    )
  )

  return release_artifacts_download_uris

def DownloadCosignArtifacts(api, cosign_dir, platform, cosign_download_uris):
  """Downloads the latest cosign binary, certificate, and signature.

  Takes a list of cosign download uris and finds the binary, certificate, and
  signature urls based on the platform. Then, the three files are downloaded to
  the cosign directory.

  Args:
    api: luci api object.
    cosign_dir(str): the folder where the cosign binary/certificate/signature
      will be downloaded.
    platform(str): the platform of the binary that needs to be downloaded
      (windows, linux, darwin)
    cosign_download_uris(list(str)): a list of all the download uris for a
      specific cosign release.
  """
  exe = '.exe' if platform == 'windows' else ''
  cosign_base_name = 'cosign-%s-amd64%s' % (platform, exe)

  cosign_binary_download_uri = next(
    filter(
      lambda uri:
      uri.endswith(cosign_base_name),
      cosign_download_uris
    )
  )

  cosign_certificate_download_uri = next(
    filter(
      lambda uri:
      uri.endswith('%s-keyless.pem' % cosign_base_name),
      cosign_download_uris
    )
  )

  cosign_signature_download_uri = next(
    filter(
      lambda uri:
      uri.endswith('%s-keyless.sig' % cosign_base_name),
      cosign_download_uris
    )
  )

  api.step(
    'Download %s cosign binary' % platform,
    [
      'curl', '-L', cosign_binary_download_uri,
      '-o', cosign_dir.join('bin', 'cosign%s' % exe),
      '--create-dirs'
    ],
    infra_step=True
  )

  api.step(
    'Download %s cosign certificate' % platform,
    [
      'curl', '-L', cosign_certificate_download_uri,
      '-o', cosign_dir.join("certificate", "cosign-cert%s.pem" % exe),
      '--create-dirs'
    ],
    infra_step=True
  )

  api.step(
    'Download %s cosign signature' % platform,
    [
      'curl', '-L', cosign_signature_download_uri,
      '-o', cosign_dir.join("certificate", "cosign-sig%s.sig" % exe),
      '--create-dirs'
    ],
    infra_step=True
  )

  if platform == 'linux' or platform == 'darwin':
    api.step(
      'Make %s cosign binary executable' % platform,
      [
        'chmod',
        '755',
        cosign_dir.join('bin', 'cosign%s' % exe)
      ]
    )


def VerifyCosignArtifactSignature(api, cosign_dir, platform):
  """Verifies the cosign artifact is legitimate

  Uses the cosign release signature and certificate to ensure that the cosign
  binary is legitimate. This is done using the current version of cosign in
  CIPD.

  Args:
    api: luci api object.
    cosign_dir(str): the folder where the cosign binary/certificate/signature
      is located.
    platform(str): the platform of the binary (windows, linux, darwin)
  """
  exe = '.exe' if platform == 'windows' else ''

  api.step(
    'Verify %s cosign binary is legitimate' % platform,
    [
      'cosign',
      'verify-blob',
      '--cert',
      cosign_dir.join("certificate", "cosign-cert%s.pem" % exe),
      '--signature',
      cosign_dir.join("certificate", "cosign-sig%s.sig" % exe),
      cosign_dir.join("bin", "cosign%s" % exe)
    ]
  )


def UploadCosignToCipd(api, cosign_dir, platform):
  """Uploads cosign to CIPD.

  Upload the cosign binary, certificate, and signature to CIPD and adds the
  latest tag to this version.

  Args:
    api: luci api object.
    cosign_dir(str): the folder where the cosign binary/certificate/signature
      is located.
    platform(str): the platform of the binary (windows, linux, darwin)
  """
  cipd_platform = 'mac' if platform == 'darwin' else platform
  cipd_package_name = 'flutter/tools/cosign/%s-amd64' % cipd_platform
  cipd_zip_path = 'cosign.zip'
  api.cipd.build(cosign_dir, cipd_zip_path, cipd_package_name)
  api.cipd.register(cipd_package_name, cipd_zip_path, refs=['latest'])


def GenTests(api):
  yield api.test(
    'cosign',
    api.properties(cosign_version='v1.0'),
    api.platform('linux', 64),
    api.step_data(
        'Get cosign releases from github',
        stdout=api.raw_io.output_text('''
        [
          {
            "url": "https://api.github.com/releases/1",
            "published_at": "2022-06-03T14:08:35Z"
          },
          {
            "url": "https://api.github.com/releases/2",
            "published_at": "2022-06-02T14:08:35Z"
          }
        ]
        ''')
    ) +
    api.step_data(
        'Get artifacts from sigstore/cosign for a specific release version',
        stdout=api.raw_io.output_text('''
        {
          "assets":[
            {
              "browser_download_url":"cosign-linux-amd64"
            },
            {
              "browser_download_url":"cosign-linux-amd64-keyless.pem"
            },
            {
              "browser_download_url":"cosign-linux-amd64-keyless.sig"
            },
            {
              "browser_download_url":"cosign-darwin-amd64"
            },
            {
              "browser_download_url":"cosign-darwin-amd64-keyless.pem"
            },
            {
              "browser_download_url":"cosign-darwin-amd64-keyless.sig"
            },
            {
              "browser_download_url":"cosign-windows-amd64.exe"
            },
            {
              "browser_download_url":"cosign-windows-amd64.exe-keyless.pem"
            },
            {
              "browser_download_url":"cosign-windows-amd64.exe-keyless.sig"
            },
            {
              "browser_download_url":"some-other-artifact"
            }
          ]
        }
        ''')
      )
    )
