练习 - 将测试作业添加到工作流

已完成

你的玩具公司的安全团队要求你验证是否只能通过 HTTPS 访问你的网站。 在本练习中,将工作流配置为运行冒烟测试来检查以符合安全团队的要求。

在此过程中,你将执行以下任务:

  • 将测试脚本添加到存储库。
  • 更新工作流定义以添加测试作业。
  • 运行工作流并观察到测试失败。
  • 修复 Bicep 文件并观察到工作流运行成功。

添加测试脚本

在此处,添加一个测试脚本,确保在使用 HTTPS 时可访问网站,而在使用不安全的 HTTP 协议时不能访问。

  1. 在 Visual Studio Code 中,在 deploy 文件夹中创建一个名为 Website.Tests.ps1 的新文件。

    Visual Studio Code 资源管理器的屏幕截图,其中显示了“deploy”文件夹和测试文件。

  2. 将以下测试代码复制并粘贴到文件中:

    param(
      [Parameter(Mandatory)]
      [ValidateNotNullOrEmpty()]
      [string] $HostName
    )
    
    Describe 'Toy Website' {
    
        It 'Serves pages over HTTPS' {
          $request = [System.Net.WebRequest]::Create("https://$HostName/")
          $request.AllowAutoRedirect = $false
          $request.GetResponse().StatusCode |
            Should -Be 200 -Because "the website requires HTTPS"
        }
    
        It 'Does not serves pages over HTTP' {
          $request = [System.Net.WebRequest]::Create("http://$HostName/")
          $request.AllowAutoRedirect = $false
          $request.GetResponse().StatusCode | 
            Should -BeGreaterOrEqual 300 -Because "HTTP is not secure"
        }
    
    }
    

    结果是一个 Pester 测试文件。 它需要一个名为 $HostName 的参数。 它针对主机名运行两个测试:

    • 尝试通过 HTTPS 连接到网站。 如果服务器以介于 200 到 299 之间的 HTTP 响应状态代码进行响应,则测试通过,这表明连接成功。
    • 尝试通过 HTTP 连接到网站。 如果服务器以 300 或更高的 HTTP 响应状态代码进行响应,则测试通过。

    就本练习而言,了解测试文件的详细信息及其工作原理并不重要。 我们在总结中提供了多个链接,以便你在感兴趣时可了解更多信息。

将 Bicep 文件的输出作为作业输出发布

前面步骤中创建的测试脚本需要一个主机名来进行测试。 Bicep 文件已包含一个输出,但需要将其发布为作业输出,才能在冒烟测试中使用它。

  1. 在 Visual Studio Code 中,打开“.github/workflows”文件夹中的“workflow.yml”文件。

  2. 在“部署”作业中,将 id 添加到 Deploy website 步骤中,以方便你参考步骤。 此外,还可以添加一个作业输出,用于复制部署步骤的 appServiceAppHostName 输出:

    deploy:
      runs-on: ubuntu-latest
      environment: Website
      needs: preview
      outputs:
        appServiceAppHostName: ${{ steps.deploy.outputs.appServiceAppHostName }}
      steps:
      - uses: actions/checkout@v3
      - uses: azure/login@v1
        name: Sign in to Azure
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      - uses: azure/arm-deploy@v1
        id: deploy
        name: Deploy website
        with:
          failOnStdErr: false
          deploymentName: ${{ github.run_number }}
          resourceGroupName: ${{ env.AZURE_RESOURCEGROUP_NAME }}
          template: ./deploy/main.bicep
          parameters: environmentType=${{ env.ENVIRONMENT_TYPE }}
    
  3. 保存文件。

向工作流添加冒烟测试作业

现可添加运行测试的冒烟测试作业。

  1. 在文件底部,为“smoke-test”作业添加以下定义:

    smoke-test:
      runs-on: ubuntu-latest
      needs: deploy
      steps:
      - uses: actions/checkout@v3
      - run: |
          $container = New-PesterContainer `
            -Path 'deploy/Website.Tests.ps1' `
            -Data @{ HostName = '${{needs.deploy.outputs.appServiceAppHostName}}' }
          Invoke-Pester `
            -Container $container `
            -CI
        name: Run smoke tests
        shell: pwsh
    

    此代码定义该作业。 该作业包含用于签出代码的步骤,以及使用 Pester 运行测试的步骤。

    作业定义使用 needs 属性来定义“部署”作业上的依赖项。 此依赖项可确保作业按你需要的顺序运行。 它还使你能够在运行冒烟测试时使用“部署”作业的输出。

    注意

    PowerShell 和 Pester 都预安装在 GitHub 托管的运行程序上。 无需执行任何特殊操作,即可在脚本步骤中使用它们。

  2. 保存文件。

验证并提交工作流定义

  1. 验证“workflow.yml”文件是否如以下代码所示:

    name: deploy-toy-website-test
    concurrency: toy-company
    
    on:
      push:
        branches:
          - main
    
    permissions:
      id-token: write
      contents: read
    
    env:
      AZURE_RESOURCEGROUP_NAME: ToyWebsiteTest
      ENVIRONMENT_TYPE: Test
    
    jobs:
      lint:
        runs-on: ubuntu-latest
        steps:
        - uses: actions/checkout@v3
        - name: Run Bicep linter
          run: az bicep build --file deploy/main.bicep
    
      validate:
        runs-on: ubuntu-latest
        steps:
        - uses: actions/checkout@v3
        - uses: azure/login@v1
          name: Sign in to Azure
          with:
            client-id: ${{ secrets.AZURE_CLIENT_ID }}
            tenant-id: ${{ secrets.AZURE_TENANT_ID }}
            subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
        - uses: azure/arm-deploy@v1
          name: Run preflight validation
          with:
            deploymentName: ${{ github.run_number }}
            resourceGroupName: ${{ env.AZURE_RESOURCEGROUP_NAME }}
            template: ./deploy/main.bicep
            parameters: environmentType=${{ env.ENVIRONMENT_TYPE }}
            deploymentMode: Validate
    
      preview:
        runs-on: ubuntu-latest
        needs: [lint, validate]
        steps:
        - uses: actions/checkout@v3
        - uses: azure/login@v1
          name: Sign in to Azure
          with:
            client-id: ${{ secrets.AZURE_CLIENT_ID }}
            tenant-id: ${{ secrets.AZURE_TENANT_ID }}
            subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
        - uses: azure/arm-deploy@v1
          name: Run what-if
          with:
            failOnStdErr: false
            resourceGroupName: ${{ env.AZURE_RESOURCEGROUP_NAME }}
            template: deploy/main.bicep
            parameters: >
              environmentType=${{ env.ENVIRONMENT_TYPE }}
            additionalArguments: --what-if
    
      deploy:
        runs-on: ubuntu-latest
        environment: Website
        needs: preview
        outputs:
          appServiceAppHostName: ${{ steps.deploy.outputs.appServiceAppHostName }}
        steps:
        - uses: actions/checkout@v3
        - uses: azure/login@v1
          name: Sign in to Azure
          with:
            client-id: ${{ secrets.AZURE_CLIENT_ID }}
            tenant-id: ${{ secrets.AZURE_TENANT_ID }}
            subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
        - uses: azure/arm-deploy@v1
          id: deploy
          name: Deploy website
          with:
            failOnStdErr: false
            deploymentName: ${{ github.run_number }}
            resourceGroupName: ${{ env.AZURE_RESOURCEGROUP_NAME }}
            template: ./deploy/main.bicep
            parameters: environmentType=${{ env.ENVIRONMENT_TYPE }}
    
      smoke-test:
        runs-on: ubuntu-latest
        needs: deploy
        steps:
        - uses: actions/checkout@v3
        - run: |
            $container = New-PesterContainer `
              -Path 'deploy/Website.Tests.ps1' `
              -Data @{ HostName = '${{needs.deploy.outputs.appServiceAppHostName}}' }
            Invoke-Pester `
              -Container $container `
              -CI
          name: Run smoke tests
          shell: pwsh
    

    如果你的文件看起来不一样,请更新它,使其与此示例一致,然后保存。

  2. 通过在 Visual Studio Code 终端中运行以下命令来提交更改并将其推送到 Git 存储库:

    git add .
    git commit -m "Add test job"
    git push
    

运行工作流并评审测试结果

  1. 在浏览器中,转到你的工作流。

  2. 选择工作流的最新运行。

    等待工作流完成“Lint 分析”、“验证”和“预览”作业。 虽然 GitHub Actions 会使用最新状态自动更新页面,但仍建议偶尔刷新页面。

  3. 依次选择“评审部署”按钮、“网站”环境和“批准和部署”

    等待工作流运行完成。

  4. 请注意,“部署”作业成功完成。 “冒烟测试”作业完成时出现错误。

    GitHub 界面的屏幕截图,其中显示了工作流运行作业。其中“冒烟测试”作业报告失败。

  5. 选择“冒烟测试”作业以查看其详细信息。

  6. 请注意,“冒烟测试”输出显示运行了两个测试。 一个通过,一个失败。 失败的测试被列为“玩具网站。不通过 HTTP 提供页面”。

    GitHub 界面的屏幕截图,其中显示工作流运行的测试结果,并突出显示了失败的测试。

    此文本表明该网站未正确配置,无法满足安全团队的要求。

更新 Bicep 文件

现在,你已确定你的 Bicep 定义不符合安全团队的要求,接下来,你可以修复它。

  1. 在 Visual Studio Code 中,打开 deploy 文件夹中的 main.bicep 文件。

  2. 找到 Azure 应用服务应用的定义,并更新它,在其 properties 区域中包含 httpsOnly 属性:

    resource appServiceApp 'Microsoft.Web/sites@2022-03-01' = {
      name: appServiceAppName
      location: location
      properties: {
        serverFarmId: appServicePlan.id
        httpsOnly: true
        siteConfig: {
          appSettings: [
            {
              name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
              value: applicationInsights.properties.InstrumentationKey
            }
            {
              name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
              value: applicationInsights.properties.ConnectionString
            }
          ]
        }
      }
    }
    
  3. 保存文件。

  4. 通过在 Visual Studio Code 终端中运行以下命令来提交更改并将其推送到 Git 存储库:

    git add .
    git commit -m "Configure HTTPS on website"
    git push
    

再次运行工作流

  1. 在浏览器中,转到你的工作流运行。

  2. 选择最近的运行。

    等待工作流完成“Lint 分析”、“验证”和“预览”作业。 虽然 GitHub 会使用最新状态自动更新页面,但仍建议偶尔刷新页面。

  3. 选择“预览”作业,然后再次评审 What-if 结果。

    请注意,What-if 命令已检测到 httpsOnly 属性值发生了更改:

    Resource and property changes are indicated with these symbols:
      - Delete
      + Create
      ~ Modify
      = Nochange
      * Ignore
    
    The deployment will update the following scope:
    
    Scope: /subscriptions/***/resourceGroups/ToyWebsiteTest
    
      ~ Microsoft.OperationalInsights/workspaces/workspace-abcdefghijklm [2022-10-01]
        - properties.retentionInDays: 30
        - properties.sku:
    
            name: "pergb2018"
    
        - properties.workspaceCapping:
    
            dailyQuotaGb: -1.0
    
      ~ Microsoft.Web/sites/toy-website-abcdefghijklm [2022-03-01]
        + properties.siteConfig.localMySqlEnabled:   false
        + properties.siteConfig.netFrameworkVersion: "v4.6"
        ~ properties.httpsOnly:                      false => true
    
      = Microsoft.Insights/components/toywebsite [2020-02-02]
      = Microsoft.Storage/storageAccounts/mystorageabcdefghijklm [2022-09-01]
      = Microsoft.Web/serverfarms/toy-website [2022-03-01]
      * microsoft.alertsmanagement/smartDetectorAlertRules/Failure Anomalies - toywebsite
    
    Resource changes: 2 to modify, 3 no change, 1 to ignore.
    
  4. 返回到工作流运行。

  5. 依次选择“评审部署”按钮、“网站”环境和“批准和部署”

    等待工作流运行完成。

  6. 请注意,整个工作流成功完成,包括“冒烟测试”作业。 这一成功表明这两个测试都已通过。

    GitHub 界面的屏幕截图,其中显示了成功的工作流运行。

清理资源

完成练习后,你可以移除资源,以便不再为这些资源付费。

在 Visual Studio Code 终端中,运行以下命令:

az group delete --resource-group ToyWebsiteTest --yes --no-wait

资源组将在后台删除。

Remove-AzResourceGroup -Name ToyWebsiteTest -Force