From 114de75e73105c0ea658c337f341c4053d8190dc Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 6 Jul 2026 09:59:03 +0000 Subject: [PATCH] chore: add auto-import of GPG public key in devcontainer setup --- .devcontainer/README.md | 26 +++++++++ .devcontainer/devcontainer.json | 2 + .devcontainer/export-signing-key.sh | 81 +++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100755 .devcontainer/export-signing-key.sh diff --git a/.devcontainer/README.md b/.devcontainer/README.md index dce9d3357d..f59a27cb8d 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -88,6 +88,32 @@ git commit -S -m "your message" # -S optional if commit.gpgsign is true git push ``` +### Easiest rebuild-safe import flow + +This devcontainer auto-imports a public key from `.git/signing.pub` on start. +If present, it runs `gpg --import .git/signing.pub` and removes the file after a +successful import. + +So the easiest setup is: + +```bash +# on the HOST, from repo root (auto-uses git user.signingkey) +./.devcontainer/export-signing-key.sh + +# or pass a key explicitly +./.devcontainer/export-signing-key.sh +``` + +The helper auto-selects `gpg2`/`gpg` based on where your key is visible, which +avoids host setups where the two binaries use different keyrings. + +After **Rebuild Container** (or next container start), verify in the container: + +```bash +gpg --list-secret-keys --keyid-format=long +git commit -S -m "test signed commit" +``` + ### Manually importing your public key If `git commit -S` fails with `gpg: signing failed: No secret key`, the forwarded diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 87a48b64f9..39f9bcaade 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -55,5 +55,7 @@ "postCreateCommand": "pnpm install --frozen-lockfile", + "postStartCommand": "if [ -f .git/signing.pub ]; then gpg --import .git/signing.pub && rm .git/signing.pub; fi", + "runArgs": ["--cap-drop=ALL", "--security-opt=no-new-privileges:true", "--pids-limit=512"] } diff --git a/.devcontainer/export-signing-key.sh b/.devcontainer/export-signing-key.sh new file mode 100755 index 0000000000..8f8b09ffc9 --- /dev/null +++ b/.devcontainer/export-signing-key.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Export your GPG public key to .git/signing.pub so the devcontainer can auto-import it. +# Usage: +# ./.devcontainer/export-signing-key.sh +# ./.devcontainer/export-signing-key.sh + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" +OUTPUT_FILE="${REPO_ROOT}/.git/signing.pub" + +KEY_ID="${1:-$(git config --global user.signingkey || true)}" +if [[ -z "${KEY_ID}" ]]; then + echo "No key ID provided and git user.signingkey is not set." + echo "Set it with: git config --global user.signingkey " + echo "Or run: ./.devcontainer/export-signing-key.sh " + exit 1 +fi + +available_bins=() +for candidate in gpg2 gpg; do + if command -v "${candidate}" >/dev/null 2>&1; then + available_bins+=("${candidate}") + fi +done + +if [[ ${#available_bins[@]} -eq 0 ]]; then + echo "Neither gpg nor gpg2 is available on PATH." + exit 1 +fi + +has_secret_key() { + local bin="$1" + "${bin}" --list-secret-keys --with-colons "${KEY_ID}" 2>/dev/null | grep -q '^sec' +} + +try_export() { + local bin="$1" + "${bin}" --armor --export "${KEY_ID}" > "${OUTPUT_FILE}" + [[ -s "${OUTPUT_FILE}" ]] +} + +selected_bin="" +for bin in "${available_bins[@]}"; do + if has_secret_key "${bin}"; then + selected_bin="${bin}" + break + fi +done + +if [[ -z "${selected_bin}" ]]; then + selected_bin="${available_bins[0]}" +fi + +rm -f "${OUTPUT_FILE}" +if ! try_export "${selected_bin}"; then + for bin in "${available_bins[@]}"; do + if [[ "${bin}" == "${selected_bin}" ]]; then + continue + fi + if try_export "${bin}"; then + selected_bin="${bin}" + break + fi + done +fi + +if [[ ! -s "${OUTPUT_FILE}" ]]; then + rm -f "${OUTPUT_FILE}" + echo "Failed to export public key for ${KEY_ID}." + echo "Tried binaries: ${available_bins[*]}" + echo "Check key visibility with:" + echo " gpg --list-secret-keys --keyid-format=long" + echo " gpg2 --list-secret-keys --keyid-format=long" + exit 1 +fi + +echo "Exported public key ${KEY_ID} to ${OUTPUT_FILE}" +echo "Using: ${selected_bin}" +echo "Rebuild/start the devcontainer to auto-import it."