# Validation pipeline for manifest on pull requests.

# Name of the run
name: '$(Build.DefinitionName)-$(Build.DefinitionVersion)-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)-$(Rev:r)'

trigger: none
pr: none

jobs:

# Agent phase. Process pull request changes and validate manifests.
- job: 'FileValidation'
  displayName: 'Pull Request Validation'
  pool:
    vmImage: 'windows-latest'
  variables:
    skipComponentGovernanceDetection: ${{ true }}
    runCodesignValidationInjection: ${{ false }}
  steps:

  # Downloads all the setup files and its dependencies.
  - task: AzureCLI@1
    displayName: 'Azure Setup'
    inputs:
      azureSubscription: '$(WinGet.Subscription)'
      scriptLocation: inlineScript
      inlineScript: 'az storage blob download-batch -d . --pattern * -s servicewrapper --output none'
    env:
      AZURE_STORAGE_CONNECTION_STRING: $(ValidationStorageAccountConnectionString)

  # WinGet setup
  - script: 'winget_validation_setup.cmd'
    name: 'wingetsetup'
    displayName: 'WinGet Setup'
    workingDirectory: scripts
    env:
      HOST_KEY: $(AzureFunctionHostKey)
      SMART_SCREEN_ENDPOINT: $(AzFuncSmartScreenEndpoint)
      DOMAIN_URLS_VALIDATION_ENDPOINT: $(AzFuncDomainUrlValEndpoint)
      MANIFEST_POLICY_ENDPOINT: $(AzFuncManifestPolicyEndpoint)
      SCAN_ENDPOINT: $(AzFuncScanEndpoint)
      INSTALLATION_ENDPOINT: $(AzFuncInstallationVerificationEndpoint)
      LABEL_ENDPOINT: $(AzFuncSetLabelOnPullRequestEndpoint)
      CLEANUP_ENDPOINT: $(AzFuncCleanupEndpoint)
      LABEL_KEY: $(AzureFunctionLabelKey)

  # Validates integrity of pull request.
  - task: CmdLine@2
    displayName: 'Validate Pull Request'
    inputs:
      script: 'WinGetSvcWrapper.exe process-pr --operationId %BUILD_BUILDNUMBER%'
      failOnStderr: true
    condition: succeeded()
    env:
      ValidationConnectionString: $(ValidationStorageAccountConnectionString)
      ExecutionEnvironment: $(ExecutionEnvironment)
      DIApplicationInsightKey: $(DIApplicationInsightKey)
      WinGet:AppConfig:Primary: $(AppConfigPrimary)
      WinGet:AppConfig:Secondary: $(AppConfigSecondary)

  # Validates manifest integrity.
  - task: CmdLine@2
    displayName: 'Validate Manifest'
    inputs:
      script: 'WinGetSvcWrapper.exe validate-manifests --operationId %BUILD_BUILDNUMBER%'
      failOnStderr: true
    condition: succeeded()
    env:
      ValidationConnectionString: $(ValidationStorageAccountConnectionString)
      DIApplicationInsightKey: $(DIApplicationInsightKey)
      WinGet:AppConfig:Primary: $(AppConfigPrimary)
      WinGet:AppConfig:Secondary: $(AppConfigSecondary)

# Agentless phase. Depends on previous job.
- job: 'ContentValidation'
  pool: server
  displayName: 'Manifest Content Validation'
  timeoutInMinutes: 1500
  dependsOn:
    - 'FileValidation'
  variables:
    HostKeySecret: $[ dependencies.FileValidation.outputs['wingetsetup.hostkey']]
    SmartScreenEndpointSecret: $[ dependencies.FileValidation.outputs['wingetsetup.smartScreenEndpoint']]
    DomainUrlValidationEndpointSecret: $[ dependencies.FileValidation.outputs['wingetsetup.domainUrlValidationEndpoint']]
    ManiestPolicyEndpointSecret: $[ dependencies.FileValidation.outputs['wingetsetup.manifestPolicyEndpoint']]
  steps:

  # Scans all the urls from manifest contents.
  - task: AzureFunction@1
    displayName: 'URLs Validation'
    inputs:
      function: '$(SmartScreenEndpointSecret)'
      key: '$(HostKeySecret)'
      body: |
        {
        "operationId": "$(Build.BuildNumber)",
        "BuildId": "$(Build.BuildId)",
        "PlanUrl": "$(system.CollectionUri)",
        "HubName": "$(system.HostType)",
        "ProjectId": "$(system.TeamProjectId)",
        "PlanId": "$(system.PlanId)", 
        "JobId": "$(system.JobId)", 
        "TimelineId": "$(system.TimelineId)", 
        "TaskInstanceId": "$(system.TaskInstanceId)",
        "AuthToken": "$(system.AccessToken)"
        }
      waitForCompletion: "true"

  # Domain url validations.
  - task: AzureFunction@1
    displayName: 'URL Domain validation'
    inputs:
      function: '$(DomainUrlValidationEndpointSecret)'
      key: '$(HostKeySecret)'
      body: |
        {
        "operationId": "$(Build.BuildNumber)",
        "BuildId": "$(Build.BuildId)",
        "PlanUrl": "$(system.CollectionUri)",
        "HubName": "$(system.HostType)",
        "ProjectId": "$(system.TeamProjectId)",
        "PlanId": "$(system.PlanId)", 
        "JobId": "$(system.JobId)", 
        "TimelineId": "$(system.TimelineId)", 
        "TaskInstanceId": "$(system.TaskInstanceId)",
        "AuthToken": "$(system.AccessToken)"
        }
      waitForCompletion: "true"

  # Manifest policy checks.
  - task: AzureFunction@1
    displayName: 'Manifest Policy Validation'
    inputs:
      function: '$(ManiestPolicyEndpointSecret)'
      key: '$(HostKeySecret)'
      body: |
        {
        "operationId": "$(Build.BuildNumber)",
        "BuildId": "$(Build.BuildId)",
        "PlanUrl": "$(system.CollectionUri)",
        "HubName": "$(system.HostType)",
        "ProjectId": "$(system.TeamProjectId)",
        "PlanId": "$(system.PlanId)", 
        "JobId": "$(system.JobId)", 
        "TimelineId": "$(system.TimelineId)", 
        "TaskInstanceId": "$(system.TaskInstanceId)",
        "AuthToken": "$(system.AccessToken)"
        }
      waitForCompletion: "true"

# Agentless phase. Depends on previous job.
- job: 'InstallerValidation'
  pool: server
  displayName: 'Installer Validation'
  timeoutInMinutes: 1500
  dependsOn:
    - 'FileValidation'
    - 'ContentValidation'
  variables:
    HostKeySecret: $[ dependencies.FileValidation.outputs['wingetsetup.hostkey']]
    ScanEndpointSecret: $[ dependencies.FileValidation.outputs['wingetsetup.scanEndpoint']]
    InstallationEndpointSecret: $[ dependencies.FileValidation.outputs['wingetsetup.installationEndpoint']]
  steps:

  # Scan installers in manifests.
  - task: AzureFunction@1
    displayName: 'Installers Scan'
    inputs:
      function: '$(ScanEndpointSecret)'
      key: '$(HostKeySecret)'
      body: |
        {
        "operationId": "$(Build.BuildNumber)",
        "BuildId": "$(Build.BuildId)",
        "PlanUrl": "$(system.CollectionUri)",
        "HubName": "$(system.HostType)",
        "ProjectId": "$(system.TeamProjectId)",
        "PlanId": "$(system.PlanId)", 
        "JobId": "$(system.JobId)", 
        "TimelineId": "$(system.TimelineId)", 
        "TaskInstanceId": "$(system.TaskInstanceId)",
        "AuthToken": "$(system.AccessToken)"
        }
      waitForCompletion: "true"

  # Validates installation.
  - task: AzureFunction@1
    displayName: 'Installation Validation'
    inputs:
      function: '$(InstallationEndpointSecret)'
      key: '$(HostKeySecret)'
      body: |
        {
        "operationId": "$(Build.BuildNumber)",
        "BuildId": "$(Build.BuildId)",
        "PlanUrl": "$(system.CollectionUri)",
        "HubName": "$(system.HostType)",
        "ProjectId": "$(system.TeamProjectId)",
        "PlanId": "$(system.PlanId)", 
        "JobId": "$(system.JobId)", 
        "TimelineId": "$(system.TimelineId)", 
        "TaskInstanceId": "$(system.TaskInstanceId)",
        "AuthToken": "$(system.AccessToken)"
        }
      waitForCompletion: "true"

# Agentless phase. Runs even if previous jobs failed. 
- job: 'postvalidation'
  pool: server
  displayName: 'Post Validation'
  dependsOn:
    - 'FileValidation'
    - 'ContentValidation'
    - 'InstallerValidation'
  condition: succeededOrFailed()
  variables:
    HostKeySecret: $[ dependencies.FileValidation.outputs['wingetsetup.hostkey']]
    LabelKeySecret : $[ dependencies.FileValidation.outputs['wingetsetup.labelkey']]
    LabelEndpointSecret: $[ dependencies.FileValidation.outputs['wingetsetup.labelEndpoint']]
    RepositoryId: $[ dependencies.FileValidation.outputs['wingetsetup.repoId']]
    CleanupEndpointSecret: $[ dependencies.filevalidation.outputs['wingetsetup.cleanupEndpoint']]
  steps:

  # Set label in GitHub PullRequest.
  - task: AzureFunction@1
    displayName: 'Set Label'
    condition: eq(variables['WinGet.RepositoryType'], 'GitHub')
    inputs:
      function: '$(LabelEndpointSecret)'
      key: '$(LabelKeySecret)'
      body: |
        {
        "operationId": "$(Build.BuildNumber)",
        "PlanUrl": "$(system.CollectionUri)",
        "BuildId": "$(Build.BuildId)",
        "HubName": "$(system.HostType)",
        "ProjectId": "$(system.TeamProjectId)",
        "PlanId": "$(system.PlanId)", 
        "JobId": "$(system.JobId)", 
        "TimelineId": "$(system.TimelineId)", 
        "TaskInstanceId": "$(system.TaskInstanceId)",
        "AuthToken": "$(system.AccessToken)",
        "BuildRepositoryId": "$(RepositoryId)",
        "PullRequestNumber": "$(System.PullRequest.PullRequestNumber)",
        }
      waitForCompletion: "true"

  # Cleanup resources.
  - task: AzureFunction@1
    displayName: 'Validation cleanup'
    inputs:
      function: '$(CleanupEndpointSecret)'
      key: '$(HostKeySecret)'
      body: |
        {
        "operationId": "$(Build.BuildNumber)",
        "PlanUrl": "$(system.CollectionUri)",
        "BuildId": "$(Build.BuildId)",
        "HubName": "$(system.HostType)",
        "ProjectId": "$(system.TeamProjectId)",
        "PlanId": "$(system.PlanId)", 
        "JobId": "$(system.JobId)", 
        "TimelineId": "$(system.TimelineId)", 
        "TaskInstanceId": "$(system.TaskInstanceId)",
        "AuthToken": "$(system.AccessToken)"
        }
      waitForCompletion: "true"
