From b6ddcd6d04cbb13ad7dbc362a91ba14b007e2a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Leszczy=C5=84ski?= Date: Tue, 7 Mar 2023 00:54:57 +0100 Subject: [PATCH] CI: Add cosign (#95) --- .github/workflows/check_lib.yml | 3 + .github/workflows/check_npm.yml | 29 ------ .github/workflows/prod_build_cli.yml | 77 +++++++++++---- .github/workflows/prod_build_lib.yml | 125 ++++++++++++++++++++++++- .github/workflows/prod_publish_npm.yml | 38 -------- docs/build-audit-trail.md | 1 + 6 files changed, 188 insertions(+), 85 deletions(-) delete mode 100644 .github/workflows/check_npm.yml delete mode 100644 .github/workflows/prod_publish_npm.yml create mode 100644 docs/build-audit-trail.md diff --git a/.github/workflows/check_lib.yml b/.github/workflows/check_lib.yml index 50adcc2..8816497 100644 --- a/.github/workflows/check_lib.yml +++ b/.github/workflows/check_lib.yml @@ -27,6 +27,9 @@ jobs: - name: Install dependencies (root) run: | npm --include=dev install + - name: Run npm ci + run: | + npm ci - name: Run webpack run: | cd web diff --git a/.github/workflows/check_npm.yml b/.github/workflows/check_npm.yml deleted file mode 100644 index 95f3541..0000000 --- a/.github/workflows/check_npm.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Check libhalo package - -on: - push: - paths-ignore: - - 'README.md' - - 'cli/README.md' - - 'docs/**' - pull_request: - paths-ignore: - - 'README.md' - - 'cli/README.md' - - 'docs/**' - branches: - - master - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout the repository - uses: actions/checkout@v3 - - name: Setup Node.JS - uses: actions/setup-node@v3 - with: - node-version: '16.x' - registry-url: 'https://registry.npmjs.org' - - name: Run npm ci - run: npm ci diff --git a/.github/workflows/prod_build_cli.yml b/.github/workflows/prod_build_cli.yml index 5b681e1..6f55794 100644 --- a/.github/workflows/prod_build_cli.yml +++ b/.github/workflows/prod_build_cli.yml @@ -31,16 +31,20 @@ jobs: * `halocli-linux-x64.zip` - Linux x64 build (elf; zipped) * `halocli-win-x64.zip` - Windows 64 build (exe; zipped) * `halocli-macos-x64.pkg` - MacOS x64 build (installer; signed) + + **Note:** The files `*-keyless.sig` and `*-keyless.pem` constitute a part of [build audit trail](https://github.com/arx-research/libhalo/blob/master/docs/build-audit-trail.md). - name: Store release upload URL run: | echo -n "${{ steps.create_release.outputs.upload_url }}" > release-upload-url.txt - name: Store release upload URL artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: release-upload-url path: release-upload-url.txt build_cli_tool: + permissions: + id-token: write strategy: matrix: include: @@ -95,20 +99,26 @@ jobs: run: | cd cli node_modules/.bin/pkg -t node16-macos-x64 package.json - - name: Store Entitlements.plist as artifact + - name: Store Entitlements.plist in dist if: matrix.os == 'macos-latest' - uses: actions/upload-artifact@v2 - with: - name: entitlements-macos - path: ./cli/Entitlements.plist + run: + mv ./cli/Entitlements.plist ./cli/dist/Entitlements.plist + - name: Install cosign + uses: sigstore/cosign-installer@c3667d99424e7e6047999fb6246c0da843953c65 + - name: Sign binary with cosign + run: | + echo y | cosign sign-blob ./cli/dist/${{ matrix.bin_name }} --output-certificate ./cli/dist/${{ matrix.bin_name }}.pem --output-signature ./cli/dist/${{ matrix.bin_name }}.sig - name: Store binary as artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: binary-${{ matrix.os }} - path: ./cli/dist/${{ matrix.bin_name }} + path: ./cli/dist/ sign_cli_tool: environment: production + permissions: + contents: write + id-token: write strategy: matrix: include: @@ -125,15 +135,27 @@ jobs: runs-on: ${{ matrix.os }} needs: build_cli_tool steps: + - name: Install cosign + uses: sigstore/cosign-installer@c3667d99424e7e6047999fb6246c0da843953c65 - name: Download binary from artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: binary-${{ matrix.os }} - - name: Download binary from artifact + - name: Verify signatures from previous stage + shell: bash + run: | + cosign verify-blob --cert ./${{ matrix.bin_name }}.pem --signature ./${{ matrix.bin_name }}.sig --certificate-identity "https://github.com/arx-research/libhalo/.github/workflows/prod_build_cli.yml@${GITHUB_REF}" --certificate-oidc-issuer https://token.actions.githubusercontent.com ./${{ matrix.bin_name }} + rm ./${{ matrix.bin_name }}.pem + rm ./${{ matrix.bin_name }}.sig + - name: Calculate checksum of Entitlements.plist (Mac OS) if: matrix.os == 'macos-latest' - uses: actions/download-artifact@v2 - with: - name: entitlements-macos + run: | + shasum -a 256 Entitlements.plist + - name: Verify Entitlements.plist (Mac OS) + if: matrix.os == 'macos-latest' + run: | + echo "bb1c65f6915e18f6e371a76e0b84551756a0e5037e90ef541680c95831fb52a7 Entitlements.plist" > Entitlements.plist.sum + shasum -a 256 -c Entitlements.plist.sum - name: Compress application (Linux) if: matrix.os == 'ubuntu-latest' run: | @@ -177,7 +199,7 @@ jobs: xcrun stapler staple ./halocli-macos-x64.pkg rm -rf ./root/ - name: Download release upload URL - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: release-upload-url - name: Store release upload URL output @@ -185,8 +207,11 @@ jobs: shell: bash run: | echo "release_upload_url=$(cat release-upload-url.txt)" >> "$GITHUB_OUTPUT" - - name: Upload release asset - id: upload-release-asset + - name: Sign output binaries with cosign + run: | + echo y | cosign sign-blob ./${{ matrix.out_name }} --output-certificate ./${{ matrix.out_name }}-keyless.pem --output-signature ./${{ matrix.out_name }}-keyless.sig + - name: Upload release asset (binary) + id: upload-release-asset-binary uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -195,6 +220,26 @@ jobs: asset_path: ./${{ matrix.out_name }} asset_name: ${{ matrix.out_name }} asset_content_type: application/octet-stream + - name: Upload release asset (cosign pem) + id: upload-release-asset-cosign-pem + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.out_store.outputs.release_upload_url }} + asset_path: ./${{ matrix.out_name }}-keyless.pem + asset_name: ${{ matrix.out_name }}-keyless.pem + asset_content_type: application/octet-stream + - name: Upload release asset (cosign sig) + id: upload-release-asset-cosign-sig + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.out_store.outputs.release_upload_url }} + asset_path: ./${{ matrix.out_name }}-keyless.sig + asset_name: ${{ matrix.out_name }}-keyless.sig + asset_content_type: application/octet-stream - name: Delete binary artifact if: always() uses: geekyeggo/delete-artifact@54ab544f12cdb7b71613a16a2b5a37a9ade990af diff --git a/.github/workflows/prod_build_lib.yml b/.github/workflows/prod_build_lib.yml index 505fead..2d648b2 100644 --- a/.github/workflows/prod_build_lib.yml +++ b/.github/workflows/prod_build_lib.yml @@ -26,11 +26,18 @@ jobs: prerelease: false body: | Standalone JavaScript library for usage with classic HTML applications. + + Release contents: + * `libhalo.js` - standalone JavaScript library for inclusion in classic HTML applications; + * `libhalo.js.LICENSE` - license information; + * `libhalo.cosign.zip` - build audit trail; + + **Note:** The files `*-keyless.sig` and `*-keyless.pem` constitute a part of [build audit trail](https://github.com/arx-research/libhalo/blob/master/docs/build-audit-trail.md). - name: Store release upload URL if: startsWith(github.ref, 'refs/tags/libhalo-v') run: | echo -n "${{ steps.create_release.outputs.upload_url }}" > release-upload-url.txt - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: startsWith(github.ref, 'refs/tags/libhalo-v') with: name: release-upload-url @@ -39,6 +46,9 @@ jobs: build_js_lib: name: Build libhalo and release runs-on: ubuntu-latest + permissions: + contents: write + id-token: write needs: create_release steps: - name: Checkout the repository @@ -56,7 +66,7 @@ jobs: webpack - name: Download release upload URL if: startsWith(github.ref, 'refs/tags/libhalo-v') - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: release-upload-url - name: Store release upload URL output @@ -64,6 +74,13 @@ jobs: if: startsWith(github.ref, 'refs/tags/libhalo-v') run: | echo "release_upload_url=$(cat release-upload-url.txt)" >> "$GITHUB_OUTPUT" + - name: Install cosign + uses: sigstore/cosign-installer@c3667d99424e7e6047999fb6246c0da843953c65 + - name: Sign libhalo.js with cosign + run: | + cd ./web/dist + echo y | cosign sign-blob ./libhalo.js --output-certificate ./libhalo.js-keyless.pem --output-signature ./libhalo.js-keyless.sig + cosign verify-blob --cert ./libhalo.js-keyless.pem --signature ./libhalo.js-keyless.sig --certificate-identity "https://github.com/arx-research/libhalo/.github/workflows/prod_build_lib.yml@${GITHUB_REF}" --certificate-oidc-issuer https://token.actions.githubusercontent.com ./libhalo.js - name: Upload release asset (JS bundle) id: upload-release-asset if: startsWith(github.ref, 'refs/tags/libhalo-v') @@ -86,3 +103,107 @@ jobs: asset_path: ./web/dist/libhalo.js.LICENSE.txt asset_name: libhalo.js.LICENSE.txt asset_content_type: text/plain + - name: Upload release asset (cosign pem) + id: upload-release-asset-cosign-pem + if: startsWith(github.ref, 'refs/tags/libhalo-v') + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.out_store.outputs.release_upload_url }} + asset_path: ./web/dist/libhalo.js-keyless.pem + asset_name: libhalo.js-keyless.pem + asset_content_type: application/octet-stream + - name: Upload release asset (cosign sig) + id: upload-release-asset-cosign-sig + if: startsWith(github.ref, 'refs/tags/libhalo-v') + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.out_store.outputs.release_upload_url }} + asset_path: ./web/dist/libhalo.js-keyless.sig + asset_name: libhalo.js-keyless.sig + asset_content_type: application/octet-stream + + publish_npm: + name: Publish libhalo package + environment: prod-npm + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + id-token: write + steps: + - name: Download release upload URL + if: startsWith(github.ref, 'refs/tags/libhalo-v') + uses: actions/download-artifact@v3 + with: + name: release-upload-url + - name: Store release upload URL output + id: out_store + if: startsWith(github.ref, 'refs/tags/libhalo-v') + run: | + echo "release_upload_url=$(cat release-upload-url.txt)" >> "$GITHUB_OUTPUT" + - name: Checkout the repository + uses: actions/checkout@v3 + - name: Setup Node.JS + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - name: Run npm ci + run: npm ci + - name: Get package integrity hash + run: | + PKG_HASH=$(npm publish --dry-run --json 2>/dev/null | jq --raw-output '.integrity') + echo "Package hash: ${PKG_HASH}" + echo -n "${PKG_HASH}" > "${RUNNER_TEMP}/libhalo-npm-hash.txt" + echo y | cosign sign-blob "${RUNNER_TEMP}/libhalo-npm-hash.txt" --output-certificate "${RUNNER_TEMP}/libhalo-npm-hash.txt-keyless.pem" --output-signature "${RUNNER_TEMP}/libhalo-npm-hash.txt-keyless.sig" + cosign verify-blob --cert "${RUNNER_TEMP}/libhalo-npm-hash.txt-keyless.pem" --signature "${RUNNER_TEMP}/libhalo-npm-hash.txt-keyless.sig" --certificate-identity "https://github.com/arx-research/libhalo/.github/workflows/prod_build_lib.yml@${GITHUB_REF}" --certificate-oidc-issuer https://token.actions.githubusercontent.com "${RUNNER_TEMP}/libhalo-npm-hash.txt" + - name: Publish package to npmjs + run: npm publish --json + env: + NODE_AUTH_TOKEN: ${{ secrets.RELEASE_NPM_TOKEN }} + - name: Re-setup Node.JS with GitHub pkg + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: https://npm.pkg.github.com/ + - name: Publish package to GitHub + run: npm publish --json + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload release asset (npm hash) + id: upload-release-asset-license + if: startsWith(github.ref, 'refs/tags/libhalo-v') + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.out_store.outputs.release_upload_url }} + asset_path: ${{ env.RUNNER_TEMP }}/libhalo-npm-hash.txt + asset_name: libhalo-npm-hash.txt + asset_content_type: text/plain + - name: Upload release asset (npm hash cosign pem) + id: upload-release-asset-cosign-pem + if: startsWith(github.ref, 'refs/tags/libhalo-v') + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.out_store.outputs.release_upload_url }} + asset_path: ${{ env.RUNNER_TEMP }}/libhalo-npm-hash.txt-keyless.pem + asset_name: libhalo-npm-hash.txt-keyless.pem + asset_content_type: application/octet-stream + - name: Upload release asset (npm hash cosign sig) + id: upload-release-asset-cosign-sig + if: startsWith(github.ref, 'refs/tags/libhalo-v') + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.out_store.outputs.release_upload_url }} + asset_path: ${{ env.RUNNER_TEMP }}/libhalo-npm-hash.txt-keyless.sig + asset_name: libhalo-npm-hash.txt-keyless.sig + asset_content_type: application/octet-stream diff --git a/.github/workflows/prod_publish_npm.yml b/.github/workflows/prod_publish_npm.yml deleted file mode 100644 index e168767..0000000 --- a/.github/workflows/prod_publish_npm.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Publish libhalo package - -on: - push: - tags: - - 'libhalo-v*' - -jobs: - build: - name: Publish libhalo package - environment: prod-npm - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout the repository - uses: actions/checkout@v3 - - name: Setup Node.JS - uses: actions/setup-node@v3 - with: - node-version: '16.x' - registry-url: 'https://registry.npmjs.org' - - name: Run npm ci - run: npm ci - - name: Publish package to npmjs - run: npm publish - env: - NODE_AUTH_TOKEN: ${{ secrets.RELEASE_NPM_TOKEN }} - - name: Re-setup Node.JS with GitHub pkg - uses: actions/setup-node@v3 - with: - node-version: '16.x' - registry-url: https://npm.pkg.github.com/ - - name: Publish package to GitHub - run: npm publish - env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/docs/build-audit-trail.md b/docs/build-audit-trail.md new file mode 100644 index 0000000..0c9334d --- /dev/null +++ b/docs/build-audit-trail.md @@ -0,0 +1 @@ +# LibHaLo Build Audit Trail