1ead2dd35d
go1.20.6 (released 2023-07-11) includes a security fix to the net/http package, as well as bug fixes to the compiler, cgo, the cover tool, the go command, the runtime, and the crypto/ecdsa, go/build, go/printer, net/mail, and text/template packages. See the Go 1.20.6 milestone on our issue tracker for details. https://github.com/golang/go/issues?q=milestone%3AGo1.20.6+label%3ACherryPickApproved Full diff: https://github.com/golang/go/compare/go1.20.5...go1.20.6 These minor releases include 1 security fixes following the security policy: net/http: insufficient sanitization of Host header The HTTP/1 client did not fully validate the contents of the Host header. A maliciously crafted Host header could inject additional headers or entire requests. The HTTP/1 client now refuses to send requests containing an invalid Request.Host or Request.URL.Host value. Thanks to Bartek Nowotarski for reporting this issue. Includes security fixes for [CVE-2023-29406 ][1] and Go issue https://go.dev/issue/60374 [1]: https://github.com/advisories/GHSA-f8f7-69v5-w4vx Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
499 lines
18 KiB
YAML
499 lines
18 KiB
YAML
# reusable workflow
|
|
name: .windows
|
|
|
|
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
os:
|
|
required: true
|
|
type: string
|
|
send_coverage:
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
|
|
env:
|
|
GO_VERSION: "1.20.6"
|
|
GOTESTLIST_VERSION: v0.3.1
|
|
TESTSTAT_VERSION: v0.1.3
|
|
WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
|
|
WINDOWS_BASE_TAG_2019: ltsc2019
|
|
WINDOWS_BASE_TAG_2022: ltsc2022
|
|
TEST_IMAGE_NAME: moby:test
|
|
TEST_CTN_NAME: moby
|
|
DOCKER_BUILDKIT: 0
|
|
ITG_CLI_MATRIX_SIZE: 6
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ${{ inputs.os }}
|
|
env:
|
|
GOPATH: ${{ github.workspace }}\go
|
|
GOBIN: ${{ github.workspace }}\go\bin
|
|
BIN_OUT: ${{ github.workspace }}\out
|
|
defaults:
|
|
run:
|
|
working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
|
|
steps:
|
|
-
|
|
name: Checkout
|
|
uses: actions/checkout@v3
|
|
with:
|
|
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
|
-
|
|
name: Env
|
|
run: |
|
|
Get-ChildItem Env: | Out-String
|
|
-
|
|
name: Init
|
|
run: |
|
|
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build"
|
|
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod"
|
|
If ("${{ inputs.os }}" -eq "windows-2019") {
|
|
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
|
} ElseIf ("${{ inputs.os }}" -eq "windows-2022") {
|
|
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
|
}
|
|
-
|
|
name: Cache
|
|
uses: actions/cache@v3
|
|
with:
|
|
path: |
|
|
~\AppData\Local\go-build
|
|
~\go\pkg\mod
|
|
${{ github.workspace }}\go-build
|
|
${{ env.GOPATH }}\pkg\mod
|
|
key: ${{ inputs.os }}-${{ github.job }}-${{ hashFiles('**/vendor.sum') }}
|
|
restore-keys: |
|
|
${{ inputs.os }}-${{ github.job }}-
|
|
-
|
|
name: Docker info
|
|
run: |
|
|
docker info
|
|
-
|
|
name: Build base image
|
|
run: |
|
|
docker pull ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }}
|
|
docker tag ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }} microsoft/windowsservercore
|
|
docker build --build-arg GO_VERSION -t ${{ env.TEST_IMAGE_NAME }} -f Dockerfile.windows .
|
|
-
|
|
name: Build binaries
|
|
run: |
|
|
& docker run --name ${{ env.TEST_CTN_NAME }} -e "DOCKER_GITCOMMIT=${{ github.sha }}" `
|
|
-v "${{ github.workspace }}\go-build:C:\Users\ContainerAdministrator\AppData\Local\go-build" `
|
|
-v "${{ github.workspace }}\go\pkg\mod:C:\gopath\pkg\mod" `
|
|
${{ env.TEST_IMAGE_NAME }} hack\make.ps1 -Daemon -Client
|
|
-
|
|
name: Copy artifacts
|
|
run: |
|
|
New-Item -ItemType "directory" -Path "${{ env.BIN_OUT }}"
|
|
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\docker.exe" ${{ env.BIN_OUT }}\
|
|
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\dockerd.exe" ${{ env.BIN_OUT }}\
|
|
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\bin\gotestsum.exe" ${{ env.BIN_OUT }}\
|
|
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd.exe" ${{ env.BIN_OUT }}\
|
|
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd-shim-runhcs-v1.exe" ${{ env.BIN_OUT }}\
|
|
-
|
|
name: Upload artifacts
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: build-${{ inputs.os }}
|
|
path: ${{ env.BIN_OUT }}/*
|
|
if-no-files-found: error
|
|
retention-days: 2
|
|
|
|
unit-test:
|
|
runs-on: ${{ inputs.os }}
|
|
timeout-minutes: 120
|
|
env:
|
|
GOPATH: ${{ github.workspace }}\go
|
|
GOBIN: ${{ github.workspace }}\go\bin
|
|
defaults:
|
|
run:
|
|
working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
|
|
steps:
|
|
-
|
|
name: Checkout
|
|
uses: actions/checkout@v3
|
|
with:
|
|
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
|
-
|
|
name: Env
|
|
run: |
|
|
Get-ChildItem Env: | Out-String
|
|
-
|
|
name: Init
|
|
run: |
|
|
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build"
|
|
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod"
|
|
New-Item -ItemType "directory" -Path "bundles"
|
|
If ("${{ inputs.os }}" -eq "windows-2019") {
|
|
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
|
} ElseIf ("${{ inputs.os }}" -eq "windows-2022") {
|
|
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
|
}
|
|
-
|
|
name: Cache
|
|
uses: actions/cache@v3
|
|
with:
|
|
path: |
|
|
~\AppData\Local\go-build
|
|
~\go\pkg\mod
|
|
${{ github.workspace }}\go-build
|
|
${{ env.GOPATH }}\pkg\mod
|
|
key: ${{ inputs.os }}-${{ github.job }}-${{ hashFiles('**/vendor.sum') }}
|
|
restore-keys: |
|
|
${{ inputs.os }}-${{ github.job }}-
|
|
-
|
|
name: Docker info
|
|
run: |
|
|
docker info
|
|
-
|
|
name: Build base image
|
|
run: |
|
|
docker pull ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }}
|
|
docker tag ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }} microsoft/windowsservercore
|
|
docker build --build-arg GO_VERSION -t ${{ env.TEST_IMAGE_NAME }} -f Dockerfile.windows .
|
|
-
|
|
name: Test
|
|
run: |
|
|
& docker run --name ${{ env.TEST_CTN_NAME }} -e "DOCKER_GITCOMMIT=${{ github.sha }}" `
|
|
-v "${{ github.workspace }}\go-build:C:\Users\ContainerAdministrator\AppData\Local\go-build" `
|
|
-v "${{ github.workspace }}\go\pkg\mod:C:\gopath\pkg\mod" `
|
|
-v "${{ env.GOPATH }}\src\github.com\docker\docker\bundles:C:\gopath\src\github.com\docker\docker\bundles" `
|
|
${{ env.TEST_IMAGE_NAME }} hack\make.ps1 -TestUnit
|
|
-
|
|
name: Send to Codecov
|
|
if: inputs.send_coverage
|
|
uses: codecov/codecov-action@v3
|
|
with:
|
|
working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker
|
|
directory: bundles
|
|
env_vars: RUNNER_OS
|
|
flags: unit
|
|
-
|
|
name: Upload reports
|
|
if: always()
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: ${{ inputs.os }}-unit-reports
|
|
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
|
|
|
unit-test-report:
|
|
runs-on: ubuntu-latest
|
|
if: always()
|
|
needs:
|
|
- unit-test
|
|
steps:
|
|
-
|
|
name: Set up Go
|
|
uses: actions/setup-go@v3
|
|
with:
|
|
go-version: ${{ env.GO_VERSION }}
|
|
-
|
|
name: Download artifacts
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: ${{ inputs.os }}-unit-reports
|
|
path: /tmp/artifacts
|
|
-
|
|
name: Install teststat
|
|
run: |
|
|
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
|
-
|
|
name: Create summary
|
|
run: |
|
|
teststat -markdown $(find /tmp/artifacts -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
|
|
|
integration-test-prepare:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
matrix: ${{ steps.tests.outputs.matrix }}
|
|
steps:
|
|
-
|
|
name: Checkout
|
|
uses: actions/checkout@v3
|
|
-
|
|
name: Set up Go
|
|
uses: actions/setup-go@v3
|
|
with:
|
|
go-version: ${{ env.GO_VERSION }}
|
|
-
|
|
name: Install gotestlist
|
|
run:
|
|
go install github.com/crazy-max/gotestlist/cmd/gotestlist@${{ env.GOTESTLIST_VERSION }}
|
|
-
|
|
name: Create matrix
|
|
id: tests
|
|
working-directory: ./integration-cli
|
|
run: |
|
|
# This step creates a matrix for integration-cli tests. Tests suites
|
|
# are distributed in integration-test job through a matrix. There is
|
|
# also an override being added to the matrix like "./..." to run
|
|
# "Test integration" step exclusively.
|
|
matrix="$(gotestlist -d ${{ env.ITG_CLI_MATRIX_SIZE }} -o "./..." ./...)"
|
|
echo "matrix=$matrix" >> $GITHUB_OUTPUT
|
|
-
|
|
name: Show matrix
|
|
run: |
|
|
echo ${{ steps.tests.outputs.matrix }}
|
|
|
|
integration-test:
|
|
runs-on: ${{ inputs.os }}
|
|
timeout-minutes: 120
|
|
needs:
|
|
- build
|
|
- integration-test-prepare
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
runtime:
|
|
- builtin
|
|
- containerd
|
|
test: ${{ fromJson(needs.integration-test-prepare.outputs.matrix) }}
|
|
env:
|
|
GOPATH: ${{ github.workspace }}\go
|
|
GOBIN: ${{ github.workspace }}\go\bin
|
|
BIN_OUT: ${{ github.workspace }}\out
|
|
defaults:
|
|
run:
|
|
working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
|
|
steps:
|
|
-
|
|
name: Checkout
|
|
uses: actions/checkout@v3
|
|
with:
|
|
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
|
-
|
|
name: Env
|
|
run: |
|
|
Get-ChildItem Env: | Out-String
|
|
-
|
|
name: Download artifacts
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: build-${{ inputs.os }}
|
|
path: ${{ env.BIN_OUT }}
|
|
-
|
|
name: Init
|
|
run: |
|
|
New-Item -ItemType "directory" -Path "bundles"
|
|
If ("${{ inputs.os }}" -eq "windows-2019") {
|
|
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
|
} ElseIf ("${{ inputs.os }}" -eq "windows-2022") {
|
|
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
|
}
|
|
Write-Output "${{ env.BIN_OUT }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
|
-
|
|
# removes docker service that is currently installed on the runner. we
|
|
# could use Uninstall-Package but not yet available on Windows runners.
|
|
# more info: https://github.com/actions/virtual-environments/blob/d3a5bad25f3b4326c5666bab0011ac7f1beec95e/images/win/scripts/Installers/Install-Docker.ps1#L11
|
|
name: Removing current daemon
|
|
run: |
|
|
if (Get-Service docker -ErrorAction SilentlyContinue) {
|
|
$dockerVersion = (docker version -f "{{.Server.Version}}")
|
|
Write-Host "Current installed Docker version: $dockerVersion"
|
|
# remove service
|
|
Stop-Service -Force -Name docker
|
|
Remove-Service -Name docker
|
|
# removes event log entry. we could use "Remove-EventLog -LogName -Source docker"
|
|
# but this cmd is not available atm
|
|
$ErrorActionPreference = "SilentlyContinue"
|
|
& reg delete "HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\docker" /f 2>&1 | Out-Null
|
|
$ErrorActionPreference = "Stop"
|
|
Write-Host "Service removed"
|
|
}
|
|
-
|
|
name: Starting containerd
|
|
if: matrix.runtime == 'containerd'
|
|
run: |
|
|
Write-Host "Generating config"
|
|
& "${{ env.BIN_OUT }}\containerd.exe" config default | Out-File "$env:TEMP\ctn.toml" -Encoding ascii
|
|
Write-Host "Creating service"
|
|
New-Item -ItemType Directory "$env:TEMP\ctn-root" -ErrorAction SilentlyContinue | Out-Null
|
|
New-Item -ItemType Directory "$env:TEMP\ctn-state" -ErrorAction SilentlyContinue | Out-Null
|
|
Start-Process -Wait "${{ env.BIN_OUT }}\containerd.exe" `
|
|
-ArgumentList "--log-level=debug", `
|
|
"--config=$env:TEMP\ctn.toml", `
|
|
"--address=\\.\pipe\containerd-containerd", `
|
|
"--root=$env:TEMP\ctn-root", `
|
|
"--state=$env:TEMP\ctn-state", `
|
|
"--log-file=$env:TEMP\ctn.log", `
|
|
"--register-service"
|
|
Write-Host "Starting service"
|
|
Start-Service -Name containerd
|
|
Start-Sleep -Seconds 5
|
|
Write-Host "Service started successfully!"
|
|
-
|
|
name: Starting test daemon
|
|
run: |
|
|
Write-Host "Creating service"
|
|
If ("${{ matrix.runtime }}" -eq "containerd") {
|
|
$runtimeArg="--containerd=\\.\pipe\containerd-containerd"
|
|
echo "DOCKER_WINDOWS_CONTAINERD_RUNTIME=1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
|
}
|
|
New-Item -ItemType Directory "$env:TEMP\moby-root" -ErrorAction SilentlyContinue | Out-Null
|
|
New-Item -ItemType Directory "$env:TEMP\moby-exec" -ErrorAction SilentlyContinue | Out-Null
|
|
Start-Process -Wait -NoNewWindow "${{ env.BIN_OUT }}\dockerd" `
|
|
-ArgumentList $runtimeArg, "--debug", `
|
|
"--host=npipe:////./pipe/docker_engine", `
|
|
"--data-root=$env:TEMP\moby-root", `
|
|
"--exec-root=$env:TEMP\moby-exec", `
|
|
"--pidfile=$env:TEMP\docker.pid", `
|
|
"--register-service"
|
|
Write-Host "Starting service"
|
|
Start-Service -Name docker
|
|
Write-Host "Service started successfully!"
|
|
-
|
|
name: Waiting for test daemon to start
|
|
run: |
|
|
$tries=20
|
|
Write-Host "Waiting for the test daemon to start..."
|
|
While ($true) {
|
|
$ErrorActionPreference = "SilentlyContinue"
|
|
& "${{ env.BIN_OUT }}\docker" version
|
|
$ErrorActionPreference = "Stop"
|
|
If ($LastExitCode -eq 0) {
|
|
break
|
|
}
|
|
$tries--
|
|
If ($tries -le 0) {
|
|
Throw "Failed to get a response from the daemon"
|
|
}
|
|
Write-Host -NoNewline "."
|
|
Start-Sleep -Seconds 1
|
|
}
|
|
Write-Host "Test daemon started and replied!"
|
|
env:
|
|
DOCKER_HOST: npipe:////./pipe/docker_engine
|
|
-
|
|
name: Docker info
|
|
run: |
|
|
& "${{ env.BIN_OUT }}\docker" info
|
|
env:
|
|
DOCKER_HOST: npipe:////./pipe/docker_engine
|
|
-
|
|
name: Building contrib/busybox
|
|
run: |
|
|
& "${{ env.BIN_OUT }}\docker" build -t busybox `
|
|
--build-arg WINDOWS_BASE_IMAGE `
|
|
--build-arg WINDOWS_BASE_IMAGE_TAG `
|
|
.\contrib\busybox\
|
|
env:
|
|
DOCKER_HOST: npipe:////./pipe/docker_engine
|
|
-
|
|
name: List images
|
|
run: |
|
|
& "${{ env.BIN_OUT }}\docker" images
|
|
env:
|
|
DOCKER_HOST: npipe:////./pipe/docker_engine
|
|
-
|
|
name: Set up Go
|
|
uses: actions/setup-go@v3
|
|
with:
|
|
go-version: ${{ env.GO_VERSION }}
|
|
-
|
|
name: Test integration
|
|
if: matrix.test == './...'
|
|
run: |
|
|
.\hack\make.ps1 -TestIntegration
|
|
env:
|
|
DOCKER_HOST: npipe:////./pipe/docker_engine
|
|
GO111MODULE: "off"
|
|
TEST_CLIENT_BINARY: ${{ env.BIN_OUT }}\docker
|
|
-
|
|
name: Test integration-cli
|
|
if: matrix.test != './...'
|
|
run: |
|
|
.\hack\make.ps1 -TestIntegrationCli
|
|
env:
|
|
DOCKER_HOST: npipe:////./pipe/docker_engine
|
|
GO111MODULE: "off"
|
|
TEST_CLIENT_BINARY: ${{ env.BIN_OUT }}\docker
|
|
INTEGRATION_TESTRUN: ${{ matrix.test }}
|
|
-
|
|
name: Send to Codecov
|
|
if: inputs.send_coverage
|
|
uses: codecov/codecov-action@v3
|
|
with:
|
|
working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker
|
|
directory: bundles
|
|
env_vars: RUNNER_OS
|
|
flags: integration,${{ matrix.runtime }}
|
|
-
|
|
name: Docker info
|
|
run: |
|
|
& "${{ env.BIN_OUT }}\docker" info
|
|
env:
|
|
DOCKER_HOST: npipe:////./pipe/docker_engine
|
|
-
|
|
name: Stop containerd
|
|
if: always() && matrix.runtime == 'containerd'
|
|
run: |
|
|
$ErrorActionPreference = "SilentlyContinue"
|
|
Stop-Service -Force -Name containerd
|
|
$ErrorActionPreference = "Stop"
|
|
-
|
|
name: Containerd logs
|
|
if: always() && matrix.runtime == 'containerd'
|
|
run: |
|
|
Copy-Item "$env:TEMP\ctn.log" -Destination ".\bundles\containerd.log"
|
|
Get-Content "$env:TEMP\ctn.log" | Out-Host
|
|
-
|
|
name: Stop daemon
|
|
if: always()
|
|
run: |
|
|
$ErrorActionPreference = "SilentlyContinue"
|
|
Stop-Service -Force -Name docker
|
|
$ErrorActionPreference = "Stop"
|
|
-
|
|
# as the daemon is registered as a service we have to check the event
|
|
# logs against the docker provider.
|
|
name: Daemon event logs
|
|
if: always()
|
|
run: |
|
|
Get-WinEvent -ea SilentlyContinue `
|
|
-FilterHashtable @{ProviderName= "docker"; LogName = "application"} |
|
|
Sort-Object @{Expression="TimeCreated";Descending=$false} |
|
|
ForEach-Object {"$($_.TimeCreated.ToUniversalTime().ToString("o")) [$($_.LevelDisplayName)] $($_.Message)"} |
|
|
Tee-Object -file ".\bundles\daemon.log"
|
|
-
|
|
name: Upload reports
|
|
if: always()
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: ${{ inputs.os }}-integration-reports-${{ matrix.runtime }}
|
|
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
|
|
|
integration-test-report:
|
|
runs-on: ubuntu-latest
|
|
if: always()
|
|
needs:
|
|
- integration-test
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
runtime:
|
|
- builtin
|
|
- containerd
|
|
steps:
|
|
-
|
|
name: Set up Go
|
|
uses: actions/setup-go@v3
|
|
with:
|
|
go-version: ${{ env.GO_VERSION }}
|
|
-
|
|
name: Download artifacts
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: ${{ inputs.os }}-integration-reports-${{ matrix.runtime }}
|
|
path: /tmp/artifacts
|
|
-
|
|
name: Install teststat
|
|
run: |
|
|
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
|
-
|
|
name: Create summary
|
|
run: |
|
|
teststat -markdown $(find /tmp/artifacts -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|