Release Build #629
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release Build | |
| on: | |
| workflow_dispatch: | |
| permissions: {} | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # shared kong github action for security checking | |
| generate-sbom-and-upload-assets: | |
| if: startsWith(github.ref_name, 'release/') | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read # Required for actions/checkout | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| # Perform SCA / SBOM analysis for the entire monorepo code repository | |
| # Produces SCA(SBOM and CVE) report | |
| # Helps understand vulnerabilities / license compliance across third party dependencies | |
| # Automatically uploads to workflow assets | |
| # (TODO): Produce workspace/package specific SBOM. Current limitation: https://github.com/anchore/syft/issues/2574 | |
| # (TODO): needs check (block) further steps if SCA fails | |
| - id: sca-project | |
| uses: Kong/public-shared-actions/security-actions/sca@a18abf762d6e2444bcbfd20de70451ea1e3bc1b1 # v4.1.1 | |
| with: | |
| dir: . | |
| upload-sbom-release-assets: false | |
| build-and-upload-release-artifacts: | |
| if: startsWith(github.ref_name, 'release/') | |
| timeout-minutes: 45 | |
| runs-on: ${{ matrix.os }} | |
| permissions: | |
| contents: read | |
| packages: read | |
| env: | |
| INSO_PACKAGE_NAME: insomnia-inso | |
| INSO_DOCKER_TAR: inso-docker-image.tar | |
| # DIGICERT_SM_CLIENT_CERT_FILE: sm_client_cert.p12 | |
| # DIGICERT_WIN_SM_CLIENT_CERT_FILE: /d/a/insomnia-ee/insomnia-ee/sm_client_cert.p12 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: macos-latest-large | |
| csc_link_secret: DESIGNER_MAC_CSC_LINK | |
| csc_key_password_secret: DESIGNER_MAC_CSC_KEY_PASSWORD | |
| - os: windows-latest | |
| csc_link_secret: '' | |
| csc_key_password_secret: '' | |
| - os: ubuntu-24.04 | |
| csc_link_secret: '' | |
| csc_key_password_secret: '' | |
| # - os: ubuntu-24.04-arm | |
| # csc_link_secret: '' | |
| # csc_key_password_secret: '' | |
| steps: | |
| - name: Checkout branch | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Setup Node | |
| uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'npm' | |
| cache-dependency-path: package-lock.json | |
| registry-url: 'https://npm.pkg.github.com' | |
| scope: '@kong' | |
| - name: Install packages | |
| run: npm ci | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' | |
| - name: Setup Inso CLI version env var | |
| shell: bash | |
| run: | | |
| echo "INSO_VERSION=$(jq .version ./packages/${{ env.INSO_PACKAGE_NAME }}/package.json -rj)" >> $GITHUB_ENV | |
| - name: Package app (Linux ARM64 only) | |
| if: runner.os == 'Linux' && runner.arch == 'ARM64' | |
| shell: bash | |
| run: npm run app-package | |
| env: | |
| NODE_OPTIONS: '--max_old_space_size=6144' | |
| BUILD_TARGETS: AppImage,tar.gz | |
| - name: Package app (Linux X64 only) | |
| if: runner.os == 'Linux' && runner.arch == 'X64' | |
| shell: bash | |
| run: npm run app-package | |
| env: | |
| NODE_OPTIONS: '--max_old_space_size=6144' | |
| # If this step fails its possible apple has new license terms which need to be accepted by logging into https://developer.apple.com/account | |
| - name: Package app (MacOS only) | |
| if: runner.os == 'macOS' | |
| shell: bash | |
| run: npm run app-package | |
| env: | |
| NODE_OPTIONS: '--max_old_space_size=6144' | |
| APPLE_ID: ${{ runner.os == 'macOS' && secrets.DESIGNER_APPLE_ID || '' }} | |
| APPLE_APP_SPECIFIC_PASSWORD: ${{ runner.os == 'macOS' && secrets.DESIGNER_APPLE_ID_PASSWORD || '' }} | |
| APPLE_TEAM_ID: FX44YY62GV | |
| CSC_LINK: ${{ matrix.csc_link_secret != '' && secrets[matrix.csc_link_secret] || '' }} | |
| CSC_KEY_PASSWORD: ${{ matrix.csc_key_password_secret != '' && secrets[matrix.csc_key_password_secret] || '' }} | |
| - name: Setup DIGICERT_SM_CLIENT_CERT_FILE from base64 secret data | |
| if: runner.os == 'Windows' | |
| shell: bash | |
| run: | | |
| echo "${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12 | |
| - name: Set variables | |
| id: variables | |
| run: | | |
| echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV" | |
| shell: bash | |
| # This will install smctl | |
| # smctl will be used in the next step for signing | |
| - name: Setup Software Trust Manager | |
| if: runner.os == 'Windows' | |
| uses: digicert/code-signing-software-trust-action@fae23a455ba4bde62b64fd7cb2f81ade788f5a95 # v1.2.1 | |
| with: | |
| simple-signing-mode: true | |
| env: | |
| SM_HOST: ${{ vars.DIGICERT_SM_HOST }} | |
| SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} | |
| SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} | |
| # creates unpacked electron-builder contents that can be signed afterwards | |
| - name: Package unpacked app (Windows only) | |
| if: runner.os == 'Windows' | |
| shell: bash | |
| run: | | |
| # smctl credentials save ${SM_API_KEY} ${SM_CLIENT_CERT_PASSWORD} | |
| NODE_OPTIONS='--max_old_space_size=6144' npm run package:windows:unpacked -w insomnia | |
| env: | |
| SM_HOST: ${{ vars.DIGICERT_SM_HOST }} | |
| SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} | |
| SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} | |
| SM_KEYPAIR_ALIAS: ${{ secrets.DIGICERT_KEYPAIR_ALIAS }} | |
| # wraps the Insomnia.exe PE with another PE that will bootstrap particular security | |
| # features added to Windows 8 in order to stopgap CVE-2025-1353 | |
| - name: Compile secure wrapper (Windows only) | |
| if: runner.os == 'Windows' | |
| shell: bash | |
| run: ./build-secure-wrapper.sh CI | |
| - name: Move .dll and .exe files to /tosign (PowerShell) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| New-Item -Path "packages/insomnia/dist/win-unpacked/tosign" -ItemType Directory -Force | |
| Get-ChildItem -Path "packages/insomnia/dist/win-unpacked" -Filter *.dll | Move-Item -Destination "packages/insomnia/dist/win-unpacked/tosign" | |
| Get-ChildItem -Path "packages/insomnia/dist/win-unpacked" -Filter *.exe | Move-Item -Destination "packages/insomnia/dist/win-unpacked/tosign" | |
| # signs unpacked electron-builder contents, in this case only the .exe | |
| # this installs smctl as well | |
| - name: Code-sign unpacked .exe (Windows only) | |
| if: runner.os == 'Windows' | |
| uses: digicert/code-signing-software-trust-action@fae23a455ba4bde62b64fd7cb2f81ade788f5a95 # v1.2.1 | |
| with: | |
| simple-signing-mode: true | |
| # If the below 2 parameters are supplied, then smctl executable is invoked to attempt the signing. | |
| input: packages/insomnia/dist/win-unpacked/tosign | |
| keypair-alias: ${{ secrets.DIGICERT_KEYPAIR_ALIAS }} | |
| env: | |
| SM_HOST: ${{ vars.DIGICERT_SM_HOST }} | |
| SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} | |
| SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} | |
| - name: Move .dll and .exe files back to win-unpacked and delete /tosign | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| Get-ChildItem -Path "packages/insomnia/dist/win-unpacked/tosign" -Filter *.dll | Move-Item -Destination "packages/insomnia/dist/win-unpacked" | |
| Get-ChildItem -Path "packages/insomnia/dist/win-unpacked/tosign" -Filter *.exe | Move-Item -Destination "packages/insomnia/dist/win-unpacked" | |
| Remove-Item -Path "packages/insomnia/dist/win-unpacked/tosign" -Recurse -Force | |
| # re-packages the now code-signed electron-builder contents into the installer | |
| - name: Package dist app (Windows only) | |
| if: runner.os == 'Windows' | |
| shell: bash | |
| run: | | |
| NODE_OPTIONS='--max_old_space_size=6144' npm run package:windows:dist -w insomnia | |
| env: | |
| SM_HOST: ${{ vars.DIGICERT_SM_HOST }} | |
| SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} | |
| SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} | |
| SM_KEYPAIR_ALIAS: ${{ secrets.DIGICERT_KEYPAIR_ALIAS }} | |
| - name: Check squirrel exe signature (Windows only) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $version = $env:INSO_VERSION | |
| # https://github.com/electron/windows-installer/blob/main/src/index.ts#L25 (convert version to NuGet-compatible) | |
| $nupkgVersion = $version -replace "-([a-zA-Z]+)\.", '-$1' | |
| $nupkg = "insomnia-${nupkgVersion}-full.nupkg" | |
| Write-Host "scan insomnia-${nupkgVersion}-full.nupkg" | |
| 7z x "packages/insomnia/dist/squirrel-windows/${nupkg}" -o"${version}-extract" | |
| $exeFiles = Get-ChildItem -Path "${version}-extract/lib/net45" -Filter *.exe | |
| if ($exeFiles.Count -eq 0) { | |
| Write-Warning "No .exe files found in the package" | |
| exit 1 | |
| } | |
| Write-Host "Found $($exeFiles.Count) .exe file(s):" | |
| Write-Host "" | |
| foreach ($exe in $exeFiles) { | |
| Write-Host "Checking: $($exe.Name)" | |
| Write-Host " Path: $($exe.FullName)" | |
| $signature = Get-AuthenticodeSignature -FilePath $exe.FullName | |
| Write-Host " Status: $($signature.Status)" | |
| Write-Host " Signer: $($signature.SignerCertificate.Subject)" | |
| Write-Host " Timestamp: $($signature.TimeStamperCertificate.NotAfter)" | |
| if ($signature.Status -ne 'Valid') { | |
| Write-Error " ❌ Invalid signature for $($exe.Name)" | |
| exit 1 | |
| } | |
| Write-Host " ✓ Valid signature" -ForegroundColor Green | |
| } | |
| Write-Host "✓ All executables are properly signed" -ForegroundColor Green | |
| - name: Package inso | |
| run: | | |
| npm run install-libcurl-node | |
| npm run build:production -w insomnia-inso | |
| npm run package -w insomnia-inso | |
| env: | |
| VERSION: ${{ env.INSO_VERSION }} | |
| - name: Code-sign inso exe (Windows only) | |
| if: runner.os == 'Windows' | |
| uses: digicert/code-signing-software-trust-action@fae23a455ba4bde62b64fd7cb2f81ade788f5a95 # v1.2.1 | |
| with: | |
| simple-signing-mode: true | |
| # If the below 2 parameters are supplied, then smctl executable is invoked to attempt the signing. | |
| input: packages/insomnia-inso/binaries/inso.exe | |
| keypair-alias: ${{ secrets.DIGICERT_KEYPAIR_ALIAS }} | |
| env: | |
| SM_HOST: ${{ vars.DIGICERT_SM_HOST }} | |
| SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} | |
| SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} | |
| - name: Remove DigiCert client certificate after signing | |
| shell: bash | |
| run: | | |
| rm -f ${{ env.SM_CLIENT_CERT_FILE }} | |
| - name: Code-sign & create Inso CLI installer (macOS only) | |
| if: runner.os == 'macOS' | |
| run: ./src/scripts/macos-pkg.sh | |
| shell: bash | |
| working-directory: ./packages/${{ env.INSO_PACKAGE_NAME }} | |
| continue-on-error: false | |
| env: | |
| MACOS_CERTIFICATE: ${{ secrets.DESIGNER_MAC_CSC_LINK }} | |
| MACOS_CERTIFICATE_PWD: ${{ secrets.DESIGNER_MAC_CSC_KEY_PASSWORD }} | |
| PKG_NAME: inso-${{ matrix.os }}-${{ env.INSO_VERSION }} | |
| BUNDLE_ID: com.insomnia.inso | |
| VERSION: ${{ env.INSO_VERSION }} | |
| - name: Notarize Inso CLI installer (macOS only) | |
| if: runner.os == 'macOS' | |
| env: | |
| APPLE_ID: ${{ secrets.DESIGNER_APPLE_ID }} | |
| APPLE_ID_PASSWORD: ${{ secrets.DESIGNER_APPLE_ID_PASSWORD }} | |
| run: | | |
| xcrun notarytool submit \ | |
| "./packages/${{ env.INSO_PACKAGE_NAME }}/artifacts/inso-${{ matrix.os }}-${{ env.INSO_VERSION }}.pkg" \ | |
| --apple-id "$APPLE_ID" \ | |
| --password "$APPLE_ID_PASSWORD" \ | |
| --team-id FX44YY62GV \ | |
| --verbose \ | |
| --wait | |
| - name: Staple Inso CLI installer (macOS only) | |
| if: runner.os == 'macOS' | |
| run: | | |
| xcrun stapler staple \ | |
| "./packages/${{ env.INSO_PACKAGE_NAME }}/artifacts/inso-${{ matrix.os }}-${{ env.INSO_VERSION }}.pkg" | |
| - name: Notarize Inso CLI binary (macOS only) | |
| if: runner.os == 'macOS' | |
| env: | |
| APPLE_ID: ${{ secrets.DESIGNER_APPLE_ID }} | |
| APPLE_ID_PASSWORD: ${{ secrets.DESIGNER_APPLE_ID_PASSWORD }} | |
| # notarytool requires the binary to be packaged in a zip, dmg, or pkg. | |
| run: | | |
| BIN_PATH="./packages/${{ env.INSO_PACKAGE_NAME }}/binaries/inso" | |
| ZIP_PATH="$(mktemp -d)/inso.zip" | |
| ditto -c -k --keepParent "$BIN_PATH" "$ZIP_PATH" | |
| xcrun notarytool submit "$ZIP_PATH" \ | |
| --apple-id "$APPLE_ID" \ | |
| --password "$APPLE_ID_PASSWORD" \ | |
| --team-id FX44YY62GV \ | |
| --wait | |
| - name: Create Inso zip/tar/gz artifacts | |
| run: npm run artifacts -w insomnia-inso | |
| - name: Login to Docker Hub | |
| if: runner.os == 'Linux' && runner.arch == 'X64' | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 | |
| with: | |
| username: ${{ secrets.DOCKER_REGISTRY_USER }} | |
| password: ${{ secrets.DOCKER_REGISTRY_TOKEN }} | |
| - name: Create inso Docker Image artifacts | |
| if: runner.os == 'Linux' && runner.arch == 'X64' | |
| run: | | |
| DOCKER_BUILDKIT=1 docker build --tag ${{ env.INSO_PACKAGE_NAME }}:temp ./packages/${{ env.INSO_PACKAGE_NAME }} | |
| docker save ${{ env.INSO_PACKAGE_NAME }}:temp -o ./packages/${{ env.INSO_PACKAGE_NAME }}/artifacts/${{ env.INSO_DOCKER_TAR }} | |
| # Produce Docker SBOM for Inso Image | |
| # Automatically uploads to workflow assets | |
| - name: Scan inso docker artifacts | |
| id: sbom_action | |
| if: runner.os == 'Linux' && runner.arch == 'X64' | |
| uses: Kong/public-shared-actions/security-actions/scan-docker-image@29dd57c7c19389e07390c1c9fe83aef6ff0c424a # v6.1.0 | |
| with: | |
| asset_prefix: image-inso-${{ runner.os }}-${{ runner.arch }} | |
| image: ./packages/${{ env.INSO_PACKAGE_NAME }}/artifacts/${{ env.INSO_DOCKER_TAR }} | |
| upload-sbom-release-assets: false # No release is publushed yet. Uploads as workflow assets | |
| skip_cis_scan: true | |
| env: | |
| SYFT_SOURCE_NAME: ${{ env.INSO_DOCKER_TAR }} | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| if-no-files-found: ignore | |
| name: ${{ runner.os }}-${{ runner.arch }}-artifacts | |
| path: | | |
| packages/insomnia/dist/*.exe | |
| packages/insomnia/dist/*.yml | |
| packages/insomnia/dist/squirrel-windows/* | |
| packages/insomnia/dist/*.zip | |
| packages/insomnia/dist/*.dmg | |
| packages/insomnia/dist/*.snap | |
| packages/insomnia/dist/*.rpm | |
| packages/insomnia/dist/*.deb | |
| packages/insomnia/dist/*.AppImage | |
| packages/insomnia/dist/*.tar.gz | |
| packages/insomnia-inso/artifacts/* | |
| - name: Upload source assets for Sentry | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: ${{ runner.os }}-${{ runner.arch }}-sentry | |
| path: | | |
| packages/insomnia/build/**/*.js | |
| packages/insomnia/build/**/*.map | |
| !packages/insomnia/build/yarn-standalone.js | |
| update-pull-request: | |
| if: startsWith(github.ref_name, 'release/') | |
| timeout-minutes: ${{ fromJSON(vars.GHA_DEFAULT_TIMEOUT) }} | |
| needs: build-and-upload-release-artifacts | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - name: Checkout branch | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Get release version | |
| id: release_version | |
| shell: bash | |
| run: | | |
| echo "version=$(jq .version packages/insomnia/package.json -rj)" >> $GITHUB_OUTPUT | |
| echo "branch=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT | |
| - name: update-pull-request | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| PR_BODY: | | |
| # WARNING: <ins>Do not merge</ins> this PR. Use the "Publish" workflow. | |
| ## Publish workflow: | |
| When ready to publish, trigger [Publish](https://github.com/${{ github.repository }}/actions/workflows/release-publish.yml) workflow with these variables: | |
| - Release version (`version`): `${{ steps.release_version.outputs.version }}` | |
| Alternatively, you can trigger the workflow from [GitHub CLI](https://cli.github.com/): | |
| ```bash | |
| gh workflow run release-publish.yml -f version=${{ steps.release_version.outputs.version }} --repo ${{ github.repository }} | |
| ``` | |
| > Release notes will be generated automatically based on the commit messages during publish. Remove any unwanted notes manually afterwards. | |
| ## Release artifacts: | |
| Download release artifacts [here](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) | |
| <details> | |
| <summary>Edit Changelog file...</summary> | |
| You can update the changelog.md in this branch, run git log to get the latest changes: | |
| ```bash | |
| git log --no-merges --oneline --pretty=format:'* %s by @%an' --since="<last release tag>" --until="${{ steps.release_version.outputs.branch }}" | |
| ``` | |
| </details> | |
| <details> | |
| <summary>Conflicts? Merge branch step failed on the publish workflow? Try this...</summary> | |
| Run locally: | |
| ```bash | |
| # Make sure git remote is Kong/insomnia... | |
| git checkout develop | |
| git merge --no-ff release/<replaced with version> | |
| # Solve merge conflicts ... | |
| # If there's package-lock conflicts, run `npm install` and commit the package-lock changes | |
| git push | |
| ``` | |
| </details> | |
| run: | | |
| PR_NUMBER=$(gh pr list --repo "$REPO" --base develop --head "$GITHUB_REF_NAME" --state open --json number -q '.[0].number') | |
| if [ -z "$PR_NUMBER" ]; then | |
| echo "No open PR found from $GITHUB_REF_NAME into develop; skipping body update." | |
| exit 0 | |
| fi | |
| gh pr edit "$PR_NUMBER" --repo "$REPO" --body "$PR_BODY" |