-
Notifications
You must be signed in to change notification settings - Fork 1.6k
ci(release): integrate Kokoro code signing into release workflow #3528
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -107,7 +107,7 @@ steps: | |
| script: | | ||
| #!/usr/bin/env bash | ||
| export VERSION=v$(cat ./cmd/version.txt) | ||
| gcloud storage cp toolbox.linux.amd64 gs://$_BUCKET_NAME/$VERSION/linux/amd64/toolbox | ||
| gcloud storage cp toolbox.linux.amd64 gs://$_UNSIGNED_BUCKET_NAME/$VERSION/linux/amd64/toolbox | ||
|
|
||
| - id: "build-linux-amd64-geminicli" | ||
| name: golang:1 | ||
|
|
@@ -174,7 +174,7 @@ steps: | |
| script: | | ||
| #!/usr/bin/env bash | ||
| export VERSION=v$(cat ./cmd/version.txt) | ||
| gcloud storage cp toolbox.darwin.arm64 gs://$_BUCKET_NAME/$VERSION/darwin/arm64/toolbox | ||
| gcloud storage cp toolbox.darwin.arm64 gs://$_UNSIGNED_BUCKET_NAME/$VERSION/darwin/arm64/toolbox | ||
|
|
||
| - id: "build-darwin-arm64-geminicli" | ||
| name: golang:1 | ||
|
|
@@ -248,7 +248,7 @@ steps: | |
| script: | | ||
| #!/usr/bin/env bash | ||
| export VERSION=v$(cat ./cmd/version.txt) | ||
| gcloud storage cp toolbox.darwin.amd64 gs://$_BUCKET_NAME/$VERSION/darwin/amd64/toolbox | ||
| gcloud storage cp toolbox.darwin.amd64 gs://$_UNSIGNED_BUCKET_NAME/$VERSION/darwin/amd64/toolbox | ||
|
|
||
| - id: "build-darwin-amd64-geminicli" | ||
| name: golang:1 | ||
|
|
@@ -315,7 +315,7 @@ steps: | |
| script: | | ||
| #!/usr/bin/env bash | ||
| export VERSION=v$(cat ./cmd/version.txt) | ||
| gcloud storage cp toolbox.windows.amd64 gs://$_BUCKET_NAME/$VERSION/windows/amd64/toolbox.exe | ||
| gcloud storage cp toolbox.windows.amd64 gs://$_UNSIGNED_BUCKET_NAME/$VERSION/windows/amd64/toolbox.exe | ||
|
|
||
| - id: "build-windows-amd64-geminicli" | ||
| name: golang:1 | ||
|
|
@@ -375,7 +375,7 @@ steps: | |
| script: | | ||
| #!/usr/bin/env bash | ||
| export VERSION=v$(cat ./cmd/version.txt) | ||
| gcloud storage cp toolbox.windows.arm64 gs://$_BUCKET_NAME/$VERSION/windows/arm64/toolbox.exe | ||
| gcloud storage cp toolbox.windows.arm64 gs://$_UNSIGNED_BUCKET_NAME/$VERSION/windows/arm64/toolbox.exe | ||
|
|
||
| - id: "build-windows-arm64-geminicli" | ||
| name: golang:1 | ||
|
|
@@ -407,14 +407,88 @@ steps: | |
| export VERSION=v$(cat ./cmd/version.txt) | ||
| gcloud storage cp toolbox.geminicli.windows.arm64 gs://$_BUCKET_NAME/geminicli/$VERSION/windows/arm64/toolbox.exe | ||
|
|
||
| - id: "trigger-linux-signing" | ||
| name: "gcr.io/$PROJECT_ID/stubby-caller" | ||
| waitFor: | ||
| - "store-linux-amd64" | ||
| script: | | ||
| #!/usr/bin/env bash | ||
| export VERSION=v$(cat ./cmd/version.txt) | ||
| stubby call blade:kokoro-api KokoroApi.Build <<EOF | ||
| full_job_name: "toolbox/linux/release_sign" | ||
| input_file_paths: "/bigstore/$_UNSIGNED_BUCKET_NAME/$VERSION/linux/amd64/toolbox" | ||
| EOF | ||
|
|
||
| - id: "trigger-macos-signing" | ||
| name: "gcr.io/$PROJECT_ID/stubby-caller" | ||
| waitFor: | ||
| - "store-darwin-arm64" | ||
| - "store-darwin-amd64" | ||
| script: | | ||
| #!/usr/bin/env bash | ||
| export VERSION=v$(cat ./cmd/version.txt) | ||
| stubby call blade:kokoro-api KokoroApi.Build <<EOF | ||
| full_job_name: "toolbox/macos/release_sign" | ||
| input_file_paths: "/bigstore/$_UNSIGNED_BUCKET_NAME/$VERSION/darwin/arm64/toolbox" | ||
| input_file_paths: "/bigstore/$_UNSIGNED_BUCKET_NAME/$VERSION/darwin/amd64/toolbox" | ||
| EOF | ||
|
|
||
| - id: "trigger-windows-signing" | ||
| name: "gcr.io/$PROJECT_ID/stubby-caller" | ||
| waitFor: | ||
| - "store-windows-amd64" | ||
| - "store-windows-arm64" | ||
| script: | | ||
| #!/usr/bin/env bash | ||
| export VERSION=v$(cat ./cmd/version.txt) | ||
| stubby call blade:kokoro-api KokoroApi.Build <<EOF | ||
| full_job_name: "toolbox/windows/release_sign" | ||
| input_file_paths: "/bigstore/$_UNSIGNED_BUCKET_NAME/$VERSION/windows/amd64/toolbox.exe" | ||
| input_file_paths: "/bigstore/$_UNSIGNED_BUCKET_NAME/$VERSION/windows/arm64/toolbox.exe" | ||
| EOF | ||
|
|
||
| - id: "download-signed-binaries" | ||
| name: "gcr.io/cloud-builders/gcloud:latest" | ||
| waitFor: | ||
| - "trigger-linux-signing" | ||
| - "trigger-windows-signing" | ||
| - "trigger-macos-signing" | ||
| script: | | ||
| #!/usr/bin/env bash | ||
| set -eo pipefail | ||
| export VERSION=v$(cat ./cmd/version.txt) | ||
|
|
||
| EXPECTED_FILES=( | ||
| "$VERSION/linux/amd64/toolbox" | ||
| "$VERSION/linux/amd64/toolbox.sig" | ||
| "$VERSION/darwin/arm64/toolbox" | ||
| "$VERSION/darwin/amd64/toolbox" | ||
| "$VERSION/windows/amd64/toolbox.exe" | ||
| "$VERSION/windows/arm64/toolbox.exe" | ||
| ) | ||
|
|
||
| echo "Waiting for Kokoro to sign and upload all binaries to gs://$_BUCKET_NAME..." | ||
| for f in "${EXPECTED_FILES[@]}"; do | ||
| until gcloud storage stat "gs://$_BUCKET_NAME/$f" >/dev/null 2>&1; do | ||
| echo "Waiting for gs://$_BUCKET_NAME/$f..." | ||
| sleep 30 | ||
| done | ||
| echo "Found signed file gs://$_BUCKET_NAME/$f!" | ||
| done | ||
|
Comment on lines
+470
to
+477
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a timeout limit to the polling loop in the echo "Waiting for Kokoro to sign and upload all binaries to gs://$_BUCKET_NAME..."
for f in "${EXPECTED_FILES[@]}"; do
attempts=0
max_attempts=40 # 20 minutes per file
until gcloud storage stat "gs://$_BUCKET_NAME/$f" >/dev/null 2>&1; do
if [ $attempts -ge $max_attempts ]; then
echo "Error: Timeout waiting for gs://$_BUCKET_NAME/$f" >&2
exit 1
fi
echo "Waiting for gs://$_BUCKET_NAME/$f..."
sleep 30
attempts=$((attempts + 1))
done
echo "Found signed file gs://$_BUCKET_NAME/$f!"
done |
||
|
|
||
| echo "Downloading signed binaries to local workspace..." | ||
| gcloud storage cp "gs://$_BUCKET_NAME/$VERSION/linux/amd64/toolbox" toolbox.linux.amd64 | ||
| gcloud storage cp "gs://$_BUCKET_NAME/$VERSION/darwin/arm64/toolbox" toolbox.darwin.arm64 | ||
| gcloud storage cp "gs://$_BUCKET_NAME/$VERSION/darwin/amd64/toolbox" toolbox.darwin.amd64 | ||
| gcloud storage cp "gs://$_BUCKET_NAME/$VERSION/windows/amd64/toolbox.exe" toolbox.windows.amd64 | ||
| gcloud storage cp "gs://$_BUCKET_NAME/$VERSION/windows/arm64/toolbox.exe" toolbox.windows.arm64 | ||
|
|
||
| echo "All signed binaries have been successfully downloaded." | ||
|
|
||
| - id: "publish-npm-to-ar" | ||
| name: node:20 | ||
| waitFor: | ||
| - "build-linux-amd64" | ||
| - "build-darwin-arm64" | ||
| - "build-darwin-amd64" | ||
| - "build-windows-amd64" | ||
| - "build-windows-arm64" | ||
| - "download-signed-binaries" | ||
| script: | | ||
| #!/usr/bin/env bash | ||
| bash .ci/publish_npm_to_ar.sh | ||
|
|
@@ -432,11 +506,7 @@ steps: | |
| - id: "publish-pypi-to-ar" | ||
| name: python:3.12 | ||
| waitFor: | ||
| - "build-linux-amd64" | ||
| - "build-darwin-arm64" | ||
| - "build-darwin-amd64" | ||
| - "build-windows-amd64" | ||
| - "build-windows-arm64" | ||
| - "download-signed-binaries" | ||
| script: | | ||
| #!/usr/bin/env bash | ||
| bash .ci/publish_pypi_to_ar.sh | ||
|
|
@@ -467,6 +537,7 @@ substitutions: | |
| _AR_HOSTNAME: ${_REGION}-docker.pkg.dev | ||
| _AR_REPO_NAME: toolbox | ||
| _BUCKET_NAME: mcp-toolbox-for-databases | ||
| _UNSIGNED_BUCKET_NAME: mcp-toolbox-for-databases-unsigned | ||
| _ASSETS_BUCKET: toolbox-build-assets | ||
| _DOCKER_URI: ${_AR_HOSTNAME}/${PROJECT_ID}/${_AR_REPO_NAME}/toolbox | ||
| _PUSH_LATEST: "false" # Substituted in trigger | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,35 +1,73 @@ | ||
| <!-- This file has been used in local_quickstart.md, local_quickstart_go.md & local_quickstart_js.md --> | ||
| <!-- [START configure_toolbox] --> | ||
|
|
||
| In this section, we will download Toolbox, configure our tools in a | ||
| `tools.yaml`, and then run the Toolbox server. | ||
|
|
||
| 1. Download the latest version of Toolbox as a binary: | ||
| 1. Download the latest version of Toolbox as a binary: | ||
|
|
||
| {{< notice tip >}} | ||
| Select the | ||
| [correct binary](https://github.com/googleapis/mcp-toolbox/releases) | ||
| corresponding to your OS and CPU architecture. | ||
| Select the | ||
| [correct binary](https://github.com/googleapis/mcp-toolbox/releases) | ||
| corresponding to your OS and CPU architecture. | ||
| {{< /notice >}} | ||
| <!-- {x-release-please-start-version} --> | ||
| <!-- {x-release-please-start-version} --> | ||
|
|
||
| ```bash | ||
| export OS="linux/amd64" # one of linux/amd64, darwin/arm64, darwin/amd64, windows/amd64, or windows/arm64 | ||
| curl -O https://storage.googleapis.com/mcp-toolbox-for-databases/v1.5.0/$OS/toolbox | ||
| ``` | ||
|
Comment on lines
16
to
19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the user selects export OS="linux/amd64" # one of linux/amd64, darwin/arm64, darwin/amd64, windows/amd64, or windows/arm64
export EXE="" && [ "${OS%%/*}" = "windows" ] && EXE=".exe"
curl -O https://storage.googleapis.com/mcp-toolbox-for-databases/v1.5.0/$OS/toolbox$EXE |
||
| <!-- {x-release-please-end} --> | ||
|
|
||
| 1. Make the binary executable: | ||
| <!-- {x-release-please-end} --> | ||
|
|
||
| 1. [Optional] Verify the downloaded binary's authenticity and integrity: | ||
|
|
||
| We recommend verifying the digital signature of the downloaded binary before running it. | ||
|
|
||
| {{< tabpane persist=header >}} | ||
| {{< tab header="Linux" lang="bash" >}} | ||
|
|
||
| # 1. Download the detached GPG signature file (.sig) | ||
|
|
||
| curl -O https://storage.googleapis.com/mcp-toolbox-for-databases/v1.5.0/$OS/toolbox.sig | ||
|
Comment on lines
+30
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrap the GPG signature download URL in # 1. Download the detached GPG signature file (.sig)
<!-- {x-release-please-start-version} -->
curl -O https://storage.googleapis.com/mcp-toolbox-for-databases/v1.5.0/$OS/toolbox.sig
<!-- {x-release-please-end} --> |
||
|
|
||
| # 2. Import Google's public GPG signing key | ||
|
|
||
| curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | gpg --import | ||
|
|
||
| # 3. Verify the signature against the downloaded binary | ||
|
|
||
| gpg --verify toolbox.sig toolbox | ||
| {{< /tab >}} | ||
| {{< tab header="macOS" lang="bash" >}} | ||
|
|
||
| # Verify the code signature | ||
|
|
||
| codesign -v --verbose=4 toolbox | ||
|
|
||
| {{< /tab >}} | ||
| {{< tab header="Windows" lang="powershell" >}} | ||
|
|
||
| # Verify the Authenticode digital signature | ||
|
|
||
| Get-AuthenticodeSignature .\toolbox.exe | Format-List | ||
|
|
||
| {{< /tab >}} | ||
| {{< /tabpane >}} | ||
|
|
||
| 1. Make the binary executable (on Linux and macOS): | ||
|
|
||
| ```bash | ||
| chmod +x toolbox | ||
| ``` | ||
|
|
||
| 1. Write the following into a `tools.yaml` file. Be sure to update any fields | ||
| such as `user`, `password`, or `database` that you may have customized in the | ||
| previous step. | ||
| 1. Write the following into a `tools.yaml` file. Be sure to update any fields | ||
| such as `user`, `password`, or `database` that you may have customized in the | ||
| previous step. | ||
|
|
||
| {{< notice tip >}} | ||
| In practice, use environment variable replacement with the format ${ENV_NAME} | ||
| instead of hardcoding your secrets into the configuration file. | ||
| In practice, use environment variable replacement with the format ${ENV_NAME} | ||
| instead of hardcoding your secrets into the configuration file. | ||
| {{< /notice >}} | ||
|
|
||
| ```yaml | ||
|
|
@@ -69,7 +107,7 @@ In this section, we will download Toolbox, configure our tools in a | |
| type: postgres-sql | ||
| source: my-pg-source | ||
| description: >- | ||
| Book a hotel by its ID. If the hotel is successfully booked, returns a NULL, raises an error if not. | ||
| Book a hotel by its ID. If the hotel is successfully booked, returns a NULL, raises an error if not. | ||
| parameters: | ||
| - name: hotel_id | ||
| type: string | ||
|
|
@@ -120,14 +158,15 @@ In this section, we will download Toolbox, configure our tools in a | |
|
|
||
| For more info on tools, check out the `Resources` section of the docs. | ||
|
|
||
| 1. Run the Toolbox server, pointing to the `tools.yaml` file created earlier: | ||
| 1. Run the Toolbox server, pointing to the `tools.yaml` file created earlier: | ||
|
|
||
| ```bash | ||
| ./toolbox --config "tools.yaml" | ||
| ``` | ||
| ```bash | ||
| ./toolbox --config "tools.yaml" | ||
| ``` | ||
|
|
||
| {{< notice note >}} | ||
|
|
||
| {{< notice note >}} | ||
| Toolbox enables dynamic reloading by default. To disable, use the | ||
| `--disable-reload` flag. | ||
| Toolbox enables dynamic reloading by default. To disable, use the | ||
| `--disable-reload` flag. | ||
| {{< /notice >}} | ||
|
Comment on lines
+161
to
171
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Standardize the indentation of the nested blocks under the list item to 4 spaces. The current 8-space indentation for the code block and notice tags, combined with 4-space indentation for the notice body, is inconsistent and can cause rendering issues in Hugo: 1. Run the toolbox server, pointing to the `tools.yaml` file created earlier:
```bash
./toolbox --config "tools.yaml"
```
{{< notice note >}}
toolbox enables dynamic reloading by default. To disable, use the
`--disable-reload` flag.
{{< /notice >}}References
|
||
| <!-- [END configure_toolbox] --> | ||
| <!-- [END configure_toolbox] --> | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To prevent the CI build from hanging indefinitely if Kokoro fails or takes too long to sign the binaries, add a maximum attempt limit (timeout) to the polling loops.