Skip to content

Package

Package #124

Workflow file for this run

name: Package
on:
workflow_dispatch:
inputs:
run:
description: 'The CI workflow run to package'
required: true
validate-dependency:
description: 'Validate that the CI workflow ran to completion'
type: boolean
required: false
default: true
jetsocat-nuget-version:
description: 'Jetsocat nuget package version'
required: false
workflow_call:
inputs:
dispatch:
description: "Marker to indicate that the workflow was dispatched via workflow_call"
type: string
required: false
default: "workflow_call"
ref:
description: "The commit SHA to build"
required: false
type: string
jobs:
preflight:
name: Preflight
runs-on: ubuntu-20.04
outputs:
run: ${{ steps.get-run.outputs.run }}
commit: ${{ steps.get-commit.outputs.commit }}
dl-strategy: ${{ steps.get-dl-strategy.outputs.dl-strategy }}
version: ${{ steps.get-version.outputs.version }}
steps:
## workflow_dispatch: CI run artifacts are downloaded using `gh` (specifying the CI workflow run_id)
## workflow_call: CI run artifacts are downloaded using actions/download-artifact (using the current run_id)
- name: Get download strategy
id: get-dl-strategy
shell: pwsh
run: |
if ('${{ inputs.dispatch }}') {
echo "dl-strategy=action" >> $Env:GITHUB_OUTPUT
} else {
echo "dl-strategy=cli" >> $Env:GITHUB_OUTPUT
}
## workflow_dispatch: The run_id is read from the inputs
## workflow_call: The run_id is the current run_id
- name: Get run
id: get-run
shell: pwsh
run: |
if ('${{ github.event.inputs.run }}') {
echo "run=${{ github.event.inputs.run }}" >> $Env:GITHUB_OUTPUT
} else {
echo "run=${{ github.run_id }}" >> $Env:GITHUB_OUTPUT
}
## To consistently repackage the CI artifacts, we must use the same commit that produced the artifacts
##
## workflow_dispatch: Lookup the SHA from the given run_id
## workflow_call: Use the input SHA; otherwise lookup the SHA from the current run_id
- name: Get commit
id: get-commit
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CI_RUN: ${{ steps.get-run.outputs.run }}
run: |
$Ref = '${{ inputs.ref }}'
if (-Not $Ref) {
$Run = gh api /repos/$Env:GITHUB_REPOSITORY/actions/runs/$Env:CI_RUN | ConvertFrom-Json
if ($($Run.head_branch) -Ne "master") {
echo "::notice::specified run is not on master"
}
$ValidateDependency = $false
if ('${{ github.event.inputs.validate-dependency }}') {
$ValidateDependency = [System.Convert]::ToBoolean('${{ github.event.inputs.validate-dependency }}')
}
if ($ValidateDependency) {
if (($($Run.status) -Ne "completed") -Or ($($Run.conclusion) -Ne "success")) {
echo "::error::specified run is either not complete or not successful"
exit 1
}
}
$Ref = $($Run.head_sha)
}
echo "commit=$Ref" >> $Env:GITHUB_OUTPUT
echo "::notice::Packaging artifacts built from commit $Ref in run ${{ steps.get-run.outputs.run }}"
- name: Checkout ${{ github.repository }}
uses: actions/checkout@v3
with:
ref: ${{ steps.get-commit.outputs.commit }}
- name: Upload version artifact
uses: actions/upload-artifact@v3
with:
name: version
path: VERSION
- name: Upload docker file artifacts
uses: actions/upload-artifact@v3
with:
name: docker
path: package/**/Dockerfile
- name: Upload changelog artifacts
uses: actions/upload-artifact@v3
with:
name: changelog
path: CHANGELOG.md
- name: Get version
id: get-version
shell: pwsh
run: |
$Version = Get-Content VERSION -TotalCount 1
echo "version=$Version" >> $Env:GITHUB_OUTPUT
codesign:
name: Codesign
runs-on: ${{ matrix.runner }}
environment: publish-prod
needs: preflight
strategy:
matrix:
project: [ jetsocat, devolutions-gateway ]
os: [ windows, macos, linux ]
include:
- os: windows
runner: windows-2022
- os: macos
runner: macos-latest
- os: linux
runner: ubuntu-20.04
exclude:
- project: devolutions-gateway
os: macos
- project: devolutions-gateway
os: linux
steps:
- name: Checkout ${{ github.repository }}
uses: actions/checkout@v3
with:
ref: ${{ needs.preflight.outputs.commit }}
- name: Download artifacts (action)
if: needs.preflight.outputs.dl-strategy == 'action'
uses: actions/download-artifact@v3
with:
name: ${{ matrix.project }}
path: ${{ runner.temp }}/${{ matrix.project }}
- name: Download artifacts (cli)
if: needs.preflight.outputs.dl-strategy == 'cli'
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
$Destination = Join-Path ${{ runner.temp }} ${{ matrix.project }}
gh run download ${{ needs.preflight.outputs.run }} -n ${{ matrix.project }} -D "$Destination"
## Delete the files that we won't operate on to prevent them being re-uploaded
## This ensures consistency of the artifact since we are operating in a matrix
- name: Manage artifacts
shell: pwsh
run: |
$Destination = Join-Path ${{ runner.temp }} ${{ matrix.project }}
if ('${{ matrix.project }}' -Eq 'jetsocat') {
Get-ChildItem "$Destination" -Exclude ${{ matrix.os }} | Remove-Item -Recurse
}
- name: Install AzureSignTool
if: matrix.os == 'windows'
run: |
dotnet tool install --global AzureSignTool
- name: Configure certificates (macOS)
if: matrix.os == 'macos'
env:
DEVELOPER_ID_CERTIFICATE: ${{ secrets.APPLE_APP_DEV_ID_APP_CERTIFICATE }}
DEVELOPER_ID_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_APP_DEV_ID_APP_CERTIFICATE_PASSWORD }}
run: |
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
KEYCHAIN_PASSWORD=Price2011
DEVELOPER_ID_CERTIFICATE_PATH=$RUNNER_TEMP/dev_id_cert.p12
echo -n "$DEVELOPER_ID_CERTIFICATE" | base64 --decode --output $DEVELOPER_ID_CERTIFICATE_PATH
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security import $DEVELOPER_ID_CERTIFICATE_PATH -P "$DEVELOPER_ID_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
- name: Configure runner (Windows)
if: matrix.os == 'windows'
run: |
echo "C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
$WixToolsetItem = Get-ChildItem -Path "C:\Program Files (x86)\" -Filter "WiX Toolset v*" | Select-Object -First 1
echo "C:\Program Files (x86)\$($WixToolsetItem.Name)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Sign executables
if: matrix.os == 'windows' || matrix.os == 'macos'
shell: pwsh
run: |
$Pattern = switch ('${{ matrix.project }}') {
'devolutions-gateway' { 'DevolutionsGateway_*.exe' }
'jetsocat' { 'jetsocat_*' }
}
Get-ChildItem -Path ${{ runner.temp }} -Recurse -Include "$Pattern" | % {
if ('${{ matrix.os }}' -Eq 'windows') {
$Params = @('sign',
'-kvt', '${{ secrets.AZURE_TENANT_ID }}',
'-kvu', '${{ secrets.CODE_SIGNING_KEYVAULT_URL }}',
'-kvi', '${{ secrets.CODE_SIGNING_CLIENT_ID }}',
'-kvs', '${{ secrets.CODE_SIGNING_CLIENT_SECRET }}',
'-kvc', '${{ secrets.CODE_SIGNING_CERTIFICATE_NAME }}',
'-tr', '${{ vars.CODE_SIGNING_TIMESTAMP_SERVER }}',
'-v')
AzureSignTool @Params $_.FullName
} elseif ('${{ matrix.os }}' -Eq 'macos') {
$SignCmd = $(@(
'codesign',
'--timestamp',
'--options=runtime',
'-s', '"Developer ID Application: Devolutions inc. (N592S9ASDB)"',
'-v',
$_.FullName
)) -Join ' '
Write-Host $SignCmd
Invoke-Expression $SignCmd
} else {
echo "::debug::nothing to do for ${{ matrix.os }}"
}
}
- name: Download web client artifacts (action)
if: needs.preflight.outputs.dl-strategy == 'action' && matrix.os == 'windows' && matrix.project == 'devolutions-gateway'
uses: actions/download-artifact@v3
with:
name: webapp-client
path: webapp/client
- name: Download web client artifacts (cli)
if: needs.preflight.outputs.dl-strategy == 'cli' && matrix.os == 'windows' && matrix.project == 'devolutions-gateway'
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
$Destination = Join-Path "webapp" "client"
gh run download ${{ needs.preflight.outputs.run }} -n webapp-client -D "$Destination"
- name: Add msbuild to PATH
if: matrix.os == 'windows' && matrix.project == 'devolutions-gateway'
uses: microsoft/[email protected]
- name: Regenerate MSI
if: matrix.project == 'devolutions-gateway'
shell: pwsh
run: |
$PackageRoot = Join-Path ${{ runner.temp }} devolutions-gateway
$Env:DGATEWAY_EXECUTABLE = Get-ChildItem -Path $PackageRoot -Recurse -Include '*DevolutionsGateway*.exe' | Select -First 1
$Env:DGATEWAY_PSMODULE_PATH = Join-Path $PackageRoot PowerShell DevolutionsGateway
$Env:DGATEWAY_WEBCLIENT_PATH = Join-Path "webapp" "client" | Resolve-Path
Get-ChildItem -Path (Join-Path $PackageRoot PowerShell "*.zip") -Recurse | % {
Remove-Item $_.FullName -Force
}
./ci/tlk.ps1 package -PackageOption generate
- name: Sign msi runtime
if: matrix.project == 'devolutions-gateway'
shell: pwsh
working-directory: package/WindowsManaged/Release
run: |
Get-ChildItem -Path .\* -Include "*.exe" | % {
$Params = @('sign',
'-kvt', '${{ secrets.AZURE_TENANT_ID }}',
'-kvu', '${{ secrets.CODE_SIGNING_KEYVAULT_URL }}',
'-kvi', '${{ secrets.CODE_SIGNING_CLIENT_ID }}',
'-kvs', '${{ secrets.CODE_SIGNING_CLIENT_SECRET }}',
'-kvc', '${{ secrets.CODE_SIGNING_CERTIFICATE_NAME }}',
'-tr', '${{ vars.CODE_SIGNING_TIMESTAMP_SERVER }}',
'-v')
AzureSignTool @Params $_.FullName
}
- name: Repackage
if: matrix.project == 'devolutions-gateway'
shell: pwsh
run: |
$PackageRoot = Join-Path ${{ runner.temp }} devolutions-gateway
$Env:DGATEWAY_PACKAGE = Get-ChildItem -Path $PackageRoot -Recurse -Include '*DevolutionsGateway*.msi' | Where-Object { $_.Name -NotLike "*legacy*"} | Select -First 1
./ci/tlk.ps1 package -PackageOption assemble
- name: Sign packages
if: matrix.project == 'devolutions-gateway'
shell: pwsh
run: |
Get-ChildItem -Path ${{ runner.temp }} -Recurse -Include '*.msi' | % {
$Params = @('sign',
'-kvt', '${{ secrets.AZURE_TENANT_ID }}',
'-kvu', '${{ secrets.CODE_SIGNING_KEYVAULT_URL }}',
'-kvi', '${{ secrets.CODE_SIGNING_CLIENT_ID }}',
'-kvs', '${{ secrets.CODE_SIGNING_CLIENT_SECRET }}',
'-kvc', '${{ secrets.CODE_SIGNING_CERTIFICATE_NAME }}',
'-tr', '${{ vars.CODE_SIGNING_TIMESTAMP_SERVER }}',
'-d', 'Devolutions Gateway',
'-v')
AzureSignTool @Params $_.FullName
}
- name: Verification
if: matrix.os == 'windows' || matrix.os == 'macos'
shell: pwsh
run: |
$RootPath = Join-Path ${{ runner.temp }} ${{ matrix.project }} ${{ matrix.os }}
if ('${{ matrix.os }}' -Eq 'windows') {
Get-ChildItem -Path $RootPath -Recurse -Include ('*.exe', '*.msi') | % {
signtool verify /pa "$($_.FullName)"
if ($LastExitCode -Ne 0) {
echo "::error::failed to verify the signature of $($_.FullName)"
exit 1
}
}
} elseif ('${{ matrix.os }}' -Eq 'macos') {
Get-ChildItem -Path $RootPath -Recurse -Include 'jetsocat_*' | % {
codesign -dvvv "$($_.FullName)"
if ($LastExitCode -Ne 0) {
echo "::error::failed to verify the signature of $($_.FullName)"
exit 1
}
}
}
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.project }}
path: ${{ runner.temp }}/${{ matrix.project }}
if-no-files-found: error
web-app:
name: Web App
runs-on: ubuntu-latest
needs: [preflight]
steps:
- name: Checkout ${{ github.repository }}
uses: actions/checkout@v3
with:
ref: ${{ needs.preflight.outputs.commit }}
- name: Download artifacts (action)
if: needs.preflight.outputs.dl-strategy == 'action'
uses: actions/download-artifact@v3
with:
name: webapp-client
- name: Download artifacts (cli)
if: needs.preflight.outputs.dl-strategy == 'cli'
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh run download ${{ needs.preflight.outputs.run }} -n webapp-client
- name: Create tarball
run: tar -czvf devolutions_gateway_webapp_${{ needs.preflight.outputs.version }}.tar.gz webapp-client
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: webapp-client
path: devolutions_gateway_webapp_${{ needs.preflight.outputs.version }}.tar.gz
if-no-files-found: error
nuget:
name: Nuget
runs-on: ubuntu-latest
needs: [preflight, codesign]
steps:
- name: Checkout ${{ github.repository }}
uses: actions/checkout@v3
with:
ref: ${{ needs.preflight.outputs.commit }}
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: jetsocat
path: jetsocat/nuget/bin
- name: Rename artifacts
shell: pwsh
working-directory: jetsocat/nuget/bin
run: |
# Backward compatibility with prior nuspec versions
Get-ChildItem -Directory -Recurse "x86_64" | Rename-Item -NewName "x64"
# Remove version number and architecture from binary name
Get-ChildItem -File -Recurse | Rename-Item -NewName "jetsocat"
cd windows
Get-ChildItem -File -Recurse | Rename-Item -NewName "jetsocat.exe"
- name: Set package metadata
shell: pwsh
working-directory: jetsocat/nuget
run: |
$Version = '${{ github.event.inputs.jetsocat-nuget-version }}'
if ([string]::IsNullOrWhitespace($Version)) {
$Version = Get-Date -Format "yyyy.M.d"
}
$Nuspec = (Resolve-Path "Devolutions.Jetsocat.nuspec")
$Xml = [xml] (Get-Content $Nuspec)
Select-Xml -xml $Xml -XPath //package/metadata/version | % { $_.Node.'#text' = "$Version" }
Select-Xml -xml $Xml -XPath //package/metadata/description | % { $_.Node.'#text' = "Websocket toolkit for jet protocol related operations" }
$Xml.Save($Nuspec)
- name: Build package
shell: pwsh
working-directory: jetsocat/nuget
run: |
Install-Module -Name ZipIt -Force
& 'nuget' 'pack' 'Devolutions.Jetsocat.nuspec'
$NugetPackage = (Get-Item ".\*.nupkg" | Select-Object -First 1) | Resolve-Path -Relative
Set-ZipItUnixFilePermissions $NugetPackage -FilePattern "native/jetsocat$" -FilePermissions "r-xr-xr-x"
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: jetsocat-nuget
path: jetsocat/nuget/*.nupkg
if-no-files-found: error
generate-sbom:
name: Upload SBOM
runs-on: ubuntu-latest
needs: preflight
steps:
- name: Checkout ${{ github.repository }}
uses: actions/checkout@v3
with:
ref: ${{ needs.preflight.outputs.commit }}
- name: Check out Devolutions/actions
uses: actions/checkout@v3
with:
repository: Devolutions/actions
ref: v1
token: ${{ secrets.DEVOLUTIONSBOT_TOKEN }}
path: ./.github/workflows
- name: Install Devolutions Toolbox
uses: ./.github/workflows/toolbox-install
with:
github_token: ${{ secrets.DEVOLUTIONSBOT_TOKEN }}
- name: Generate SBOM
uses: ./.github/workflows/cdxgen
- name: Save SBOM
uses: actions/upload-artifact@v3
with:
name: bom.xml
path: bom.xml
- name: Upload SBOM to Dependency-Track
uses: ./.github/workflows/dtrack-upload-sbom
with:
api_key: ${{ secrets.DTRACK_AUTOMATION_API_KEY }}
autocreate: 'true'
bom_filename: bom.xml
project_name: devolutions-gateway
project_version: ${{ needs.preflight.outputs.version }}
server_hostname: 'dtrack-api.devolutions.com'