GitHub avatar

Fox's Blog

✨ AI Generated Article

SSH commit signing script explained

A walkthrough of the SSH commit‑signing helper and why I wanted

SSH commit signing script explained

This post dives into the setup-ssh-signing.sh script I published on Gist. We'll look at what each part does, how it makes repository‑local SSH commit signing painless, and, yes, why I even bothered to write it in the first place (spoiler: I just wanted my commits to look stylish).

Motivation

I’ve always loved tweaking my Git workflow, and after seeing other people with little “Verified” badges next to their commits I thought: why not me? The built‑in GPG signing is a bit heavy and global, so I ended up writing a tiny helper that:

  • creates an SSH key just for signing,
  • configures the current repository only,
  • optionally rewrites history to sign old commits,
  • and lets me ship the key between machines.

Really, the need was mostly vanity. There’s no technical requirement for signatures in my personal projects, but having a green “Verified” on a commit feels cool, and writing the script was a fun exercise in shell scripting.

I mean, signing your commits is like wearing a leather jacket to a code review -- totally unnecessary, but it makes you feel like a hacker.

What the script does

The script is a single Bash file with set -euo pipefail at the top so it fails fast. Here’s a high‑level summary of its behaviour:

  1. Generate or import a signing key
    Keys live in .git-signing/ under the directory where you run the script.
  2. Configure Git locally
    Sets gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true, and an allowedSignersFile pointing to the public key.
  3. Manage keys cross‑machine
    Support for --export-keys/--import-keys lets you move the private key between computers without touching global state.
  4. Optional history rewrite (--resign-all)
    Rewrites every commit on every branch/tag (or just those not in upstream for forks) and re‑commits them with -S, leaving other authors untouched.
  5. Utility flags
    --autostash, --autopush, --commit-date, --yes for non‑interactive mode, etc.
  6. Fork‑awareness and safety checks
    Detects upstream remote, warns before rewriting history, checks for required tools (git, ssh-keygen, zip/unzip), ensures proper permissions, and even creates a secure runtime copy of the key if filesystem permissions are too loose.

The script is idempotent: running it twice won’t regenerate your key or overwrite existing configuration.

Step‑by‑step walkthrough

Below are some of the key parts of the code with explanations.

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

The header establishes safety and documents the goal. The next chunk parses CLI options (--name, --email, --repo, etc.) with a while [[ $# -gt 0 ]]; do case … esac done loop. Mandatory identity fields are enforced later:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

Key generation happens under $LAUNCH_DIR/.git-signing. If a key already exists the script leaves it alone; --import-keys can populate the directory from a ZIP file.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

After ensuring the private key is usable (ssh-keygen -Y sign …), the script writes a tiny allowed_signers file containing the public key and sets the Git local config accordingly:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

If you request history rewriting with --resign-all, the script builds a git filter-branch command that re‑commits eligible commits with -S. It respects fork state by optionally skipping commits already present in upstream.

The final output prints the public key and instructions for adding it to GitHub’s Signing Key section, along with a quick test recipe.

Why commit signing?

This is the part where I admit I didn’t need it. My repositories don’t require provenance for anything I publish, and I’m not using signed tags for releases. The “why” is:

  • because I could,
  • because it looks neat (have you seen the badge?),
  • because it gave me an excuse to experiment with git filter-branch and shell scripting,
  • and because it’s another piece of “I built this myself” content for the blog.

In short: it was just for show, but that’s half the fun of tinkering with tooling.

Usage examples

# initial setup in current repo
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# export keys to use on another machine
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# import keys on second machine
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# rewrite history and push
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

Final thoughts

This script is a small utility, but it encapsulates a few nice ideas:

  • keep cryptographic keys local and per‑repo,
  • never touch global config unless you ask for it,
  • provide simple import/export and history rewriting,
  • and document the whole process in a blog post because why not.

If you’re tempted to add signatures to your own commits, give it a spin! And if you’re just here for the style points, same. 😎

✨ AI Generated Article

Script de signature SSH expliqué

Décortiquage du helper de signature de commits SSH et pourquoi je

Script de signature SSH pour commits -- explication

Cet article décortique le script setup-ssh-signing.sh que j'ai publié sur Gist. On va voir ce que chaque partie fait, comment ça rend la signature SSH locale à un dépot complètement indolore, et, oui, pourquoi j'ai même pris la peine de l'écrire (spoiler : je voulais juste que mes commits aient de la gueule).

Motivation

J'ai toujours adoré bricoler mon workflow Git, et après avoir vu des gens avec des petits badges « Verified » à côté de leurs commits, je me suis dit : pourquoi pas moi ? La signature GPG intégrée est un lourde et globale, alors j'ai fini par écrire un petit helper qui :

  • crée une clé SSH dédiée à la signature,
  • configure uniquement le dépôt courant,
  • réécrit éventuellement l'historique pour signer les vieux commits,
  • et permet de transporter la clé entre machines.

Franchement, le besoin était surtout de la vanity. Y'a pas d'exigence technique de signature dans mes projets perso, mais voir un badge vert « Verified » sur un commit, ça fait son petit effet, et écrire le script était un kiff en shell.

Bon, signer ses commits, c'est un peu comme mettre un blouson en cuir pour une review de code -- totalement inutile, mais ça te donne l'impression d'être un hacker.

Ce que fait le script

Le script est un seul fichier Bash avec set -euo pipefail en haut pour planter vite fait bien fait. Voilà un résumé de ce qu'il fait :

  1. Générer ou importer une clé de signature
    Les clés atterrissent dans .git-signing/ dans le dossier où tu lances le script.
  2. Configurer Git localement
    Il positionne gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true, et un allowedSignersFile qui pointe vers la clé publique.
  3. Gérer les clés entre machines
    Grâce à --export-keys / --import-keys, tu peux balader ta clé privée d'un ordi à l'autre sans toucher à la config globale.
  4. Réécriture d'historique optionnelle (--resign-all)
    Réécrit tous les commits de toutes les branches/tags (ou seulement ceux pas dans upstream pour les forks) et les re-signe avec -S, sans toucher aux autres auteurs.
  5. Flags utilitaires
    --autostash, --autopush, --commit-date, --yes pour le mode non interactif, etc.
  6. Détection de fork et vérifications de sécurité
    Il détecte le remote upstream, prévient avant de réécrire l'historique, vérifie les outils requis (git, ssh-keygen, zip/unzip), s'assure des bonnes permissions, et crée même une copie sécurisée de la clé si les permissions du filesystem sont trop permissives.

Le script est idempotent : le lancer deux fois ne regénère pas ta clé et n'écrase pas la config existante.

Déroulé pas à pas

Voici quelques extraits clés du code avec leurs explications.

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

L'en-tête pose la sécurité et documente l'objectif. Le morceau suivant parse les options CLI (--name, --email, --repo, etc.) avec une boucle while [[ $# -gt 0 ]]; do case … esac done. Les champs d'identité obligatoires sont vérifiés plus tard :

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

La génération de clé se fait dans $LAUNCH_DIR/.git-signing. Si une clé existe déjà, le script la laisse tranquille ; --import-keys permet de remplir le dossier depuis un ZIP.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

Après avoir vérifié que la clé privée est utilisable (ssh-keygen -Y sign …), le script écrit un petit fichier allowed_signers contenant la clé publique et positionne la config Git locale :

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

Si tu demandes la réécriture d'historique avec --resign-all, le script construit une commande git filter-branch qui re-signe les commits éligibles avec -S. Il respecte l'état du fork en sautant optionnellement les commits déjà présents dans upstream.

Le résultat final affiche la clé publique et les instructions pour l'ajouter dans la section Signing Key de GitHub, avec une petite recette de test.

Pourquoi signer ses commits ?

C'est le moment où j'avoue que je n'en avais pas besoin. Mes dépôts n'exigent aucune provenance pour ce que je publie, et je n'utilise pas les tags signés pour les releases. Le « pourquoi » c'est :

  • parce que je pouvais,
  • parce que ça rend bien (t'as vu le badge ?),
  • parce que ça m'a donné une excuse pour expérimenter avec git filter-branch et le shell,
  • et parce que c'est un énième « j'ai construit ça moi-même » pour le blog.

Bref, c'était juste pour frimer, mais c'est ça qui est sympa quand on bricole ses outils.

Exemples d'utilisation

# configuration initiale dans le dépôt courant
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# exporter les clés pour une autre machine
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# importer les clés sur une deuxième machine
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# réécrire l'historique et pousser
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

Dernières réflexions

Ce script est un petit utilitaire, mais il contient quelques idées sympas :

  • garder les clés cryptographiques locales et par dépôt,
  • ne jamais toucher à la config globale sauf si tu le demandes,
  • fournir un import/export simple et la réécriture d'historique,
  • et documenter tout le processus dans un article de blog, parce que pourquoi pas.

Si l'envie te prend d'ajouter des signatures à tes propres commits, essaie-le ! Et si t'es juste là pour le style, pareil. 😎

✨ AI Generated Article

SSH 提交签名脚本详解

SSH 提交签名辅助工具的详细解析,以及为什么我想要有格调的提交。

SSH 提交签名脚本详解

这篇文章深入解析了我发布在 Gist 上的 setup-ssh-signing.sh 脚本。我们来看看每部分的作用、它如何让仓库级别的 SSH 提交签名变得轻松无痛,以及,是的,我为什么一开始要费劲写它(剧透:我只是想让我的提交看起来很酷)。

动机

我一直喜欢折腾我的 Git 工作流,看到别人提交记录旁边那个小小的"已验证"徽章后我想:为什么我不能有呢?内置的 GPG 签名有点重而且全局生效,于是我干脆写了一个小工具:

  • 专门创建一把用于签名的 SSH 密钥
  • 仅配置当前仓库
  • 可选择重写历史来签署旧提交
  • 支持在多台机器间迁移密钥

说实话,主要是虚荣心。我的个人项目在技术上并不需要签名,但提交上有绿色的"已验证"就是很酷,写这个脚本也是 Shell 脚本编程的一次有趣练习。

我是说,给你的提交签名就像穿着皮夹克去参加代码审查----完全没必要,但它让你感觉自己像个黑客。

脚本的功能

这个脚本是一个单独的 Bash 文件,顶部加上 set -euo pipefail,出错即停。以下是它的高层行为概述:

  1. 生成或导入签名密钥 密钥存放在运行脚本所在目录下的 .git-signing/ 中。
  2. 本地配置 Git 设置 gpg.format=ssh、user.signingkey、commit.gpgsign=true、tag.gpgSign=true,并将 allowedSignersFile 指向公钥。
  3. 跨机器管理密钥 支持 --export-keys/--import-keys,让你无需触及全局配置就能在不同电脑之间迁移私钥。
  4. 可选的历史重写(--resign-all) 重写所有分支/标签上的每个提交(或对于 fork,仅重写不在 upstream 中的提交),用 -S 重新签署,同时保留其他作者的提交不变。
  5. 实用选项 --autostash、--autopush、--commit-date、--yes(非交互模式)等。
  6. Fork 感知与安全检查 检测 upstream 远程仓库,重写历史前给出警告,检查所需工具(git、ssh-keygen、zip/unzip),确保权限正确,甚至在文件系统权限过松时创建一个安全的密钥运行时副本。

脚本是幂等的:运行两次不会重新生成密钥或覆盖现有配置。

逐步解析

以下是代码中一些关键部分的解释。

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

开头部分确立了安全性并说明了目标。下一段用 while [[ $# -gt 0 ]]; do case … esac done 循环解析 CLI 选项(--name、--email、--repo 等)。必填的身份信息在后面强制执行:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

密钥生成在 $LAUNCH_DIR/.git-signing 目录下。如果密钥已存在,脚本则保留现有密钥;--import-keys 可以从 ZIP 文件中填充该目录。

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

在确保私钥可用后(ssh-keygen -Y sign …),脚本写入一个包含公钥的 allowed_signers 文件,并设置相应的 Git 本地配置:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

如果你使用 --resign-all 请求重写历史,脚本会构建一个 git filter-branch 命令,用 -S 重新签署符合条件的提交。它还能感知 fork 状态,可选择跳过 upstream 中已有的提交。

最终输出会打印公钥和将其添加到 GitHub 签名密钥部分的说明,以及一个快速测试方法。

为什么要提交签名?

这部分是我承认其实我并不需要它。我的仓库不要求对发布的任何内容进行来源验证,我也不对发布版使用签署标签。"为什么"的答案是:

  • 因为我可以,
  • 因为看起来很酷(你看到那个徽章了吗?),
  • 因为它给了我一个折腾 git filter-branch 和 Shell 脚本编程的借口,
  • 因为这是又一个"我自己做的"博客素材。

简而言之:纯粹是为了好看,但这也正是摆弄工具的一半乐趣所在。

使用示例

# 在当前仓库中进行初始设置
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# 导出密钥以在另一台机器上使用
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# 在第二台机器上导入密钥
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# 重写历史并推送
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

最后的话

这个小工具虽然简单,但它蕴含了几个不错的设计理念:

  • 将加密密钥保持本地化、按仓库管理
  • 除非你主动要求,否则绝不触碰全局配置
  • 提供简单的导入/导出和历史重写功能
  • 把整个过程写成一篇博客文章----为什么不呢?

如果你也想给自己的提交添加签名,试试看吧!如果你只是来看炫酷风格的,一样欢迎。😎

✨ AI Generated Article

SSHコミット署名スクリプトの解説

SSHコミット署名ヘルパーのウォークスルーと、なぜスタイリッシュなコミットにこだわったのか。

SSHコミット署名スクリプトの解説

この記事では、Gistで公開したsetup-ssh-signing.shスクリプトを詳しく見ていく。各部分が何をするのか、どうやってリポジトリローカルなSSHコミット署名を簡単にするのか、そしてそもそもなぜこんなのを書いたのか(ネタバレ:コミットをスタイリッシュに見せたかっただけ)を説明する。

モチベーション

Gitのワークフローをカスタマイズするのがずっと大好きで、他の人がコミットの横に「Verified」バッジをつけてるのを見て、俺もやりたいと思ったんだ。組み込みのGPG署名はちょっと重いしグローバル設定が必要だから、小さなヘルパースクリプトを書いた:

  • 署名専用のSSHキーを作成
  • 現在のリポジトリだけに設定
  • オプションで履歴を書き換えて過去のコミットに署名
  • キーをマシン間で移行可能にする

正直、必要性はほとんど虚栄心だった。個人プロジェクトで署名が必要な技術的理由は何もない。でもコミットに緑色の「Verified」がついてるとカッコいいし、スクリプトを書くのはシェルスクリプトの面白い練習にもなった。

つまり、コミットに署名するってのは、コードレビューに革ジャン着ていくようなものだ--まったく必要ないけど、ハッカーになった気分になれる。

スクリプトの機能

このスクリプトは単一のBashファイルで、先頭にset -euo pipefailがあって、エラーが起きたら即座に停止する。動作の概要は以下の通り:

  1. 署名キーを生成またはインポート
    キーはスクリプトを実行したディレクトリの.git-signing/に保存される。
  2. Gitをローカル設定
    gpg.format=ssh、user.signingkey、commit.gpgsign=true、tag.gpgSign=true、そして公開鍵を指すallowedSignersFileを設定する。
  3. キーをマシン間で管理
    --export-keys/--import-keysで、グローバル設定に触れずに秘密鍵を別のコンピュータに移動できる。
  4. オプションの履歴書き換え(--resign-all)
    全ブランチ・全タグの全コミット(フォークの場合はupstreamにないものだけ)を書き換え、-Sで再コミットする。他の作者のコミットはそのまま。
  5. ユーティリティフラグ
    --autostash、--autopush、--commit-date、--yes(非対話モード)など。
  6. フォーク検出と安全対策
    upstreamリモートを検出し、履歴書き換え前に警告し、必要なツール(git、ssh-keygen、zip/unzip)をチェックし、適切なパーミッションを確保し、必要に応じてキーの安全なランタイムコピーも作成する。

スクリプトは冪等性がある:2回実行してもキーが再生成されたり既存の設定が上書きされたりしない。

ステップバイステップ解説

以下がコードの主要部分とその説明だ。

#!/usr/bin/env bash
set -euo pipefail

# 管理されたリポジトリローカルな方法でSSHコミット署名を設定する。
# - キーファイルはスクリプトを実行したディレクトリに作成される。
# - Git設定は現在のリポジトリのみにローカル設定される。

ヘッダーで安全性を確立し、目標をドキュメント化している。次のチャンクはCLIオプション(--name、--email、--repoなど)をwhile [[ $# -gt 0 ]]; do case … esac doneループでパースする。必須のIDフィールドは後で検証される:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

キー生成は$LAUNCH_DIR/.git-signingで行われる。キーが既にあればそのままにして、--import-keysでZIPファイルから取り込める:

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

秘密鍵が使えることを確認した後(ssh-keygen -Y sign …)、スクリプトは小さなallowed_signersファイルに公開鍵を書き込み、Gitのローカル設定を行う:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

--resign-allで履歴書き換えを要求すると、スクリプトは適合するコミットを-Sで再コミットするgit filter-branchコマンドを構築する。フォーク状態を考慮して、必要に応じてupstreamに既存のコミットをスキップする。

最後に公開鍵と、GitHubのSigning Keyセクションに追加する手順を出力し、簡単なテスト方法も示す。

なぜコミット署名?

ここが「実は必要なかった」って認める部分だ。俺のリポジトリは公開するものに由来証明を必要としないし、リリースに署名タグも使ってない。「なぜ」の理由は:

  • できたから
  • 見た目がきれいだから(バッジ見たことある?)
  • git filter-branchやシェルスクリプトを試す口実になったから
  • そしてブログの「俺が作ったもの」コンテンツのもう一つになるから

要するに:見せびらかしのためだけだけど、それがツールいじりの楽しさの半分だよね。

使用例

# 現在のリポジトリで初期セットアップ
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# 別のマシンで使うためにキーをエクスポート
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# 2台目のマシンでキーをインポート
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# 履歴を書き換えてプッシュ
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

最後に

このスクリプトは小さなユーティリティだが、いくつかの良いアイデアを凝縮している:

  • 暗号キーをローカルかつリポジトリごとに管理する
  • 頼まれもしないのにグローバル設定を触らない
  • シンプルなインポート/エクスポートと履歴書き換えを提供する
  • そしてその全プロセスをブログ記事に書く--なぜならそれがいいから

自分のコミットに署名を追加したくなったら、試してみてね!スタイルポイント目当てで来た人も、同じく。😎

✨ AI Generated Article

SSH 커밋 서명 스크립트 설명

SSH 커밋 서명 헬퍼의 분석과 내가 스타일리시한 커밋을 원했던 이유

SSH 커밋 서명 스크립트 설명

이 글은 내가 Gist에 올린 setup-ssh-signing.sh 스크립트를 자세히 살펴본다. 각 부분이 무엇을 하는지, 어떻게 저장소-로컬 SSH 커밋 서명을 간편하게 만드는지, 그리고 솔직히 말해서 내가 왜 이걸 만들었는지까지 살펴볼 거야 (스포일러: 그냥 내 커밋을 스타일리시하게 만들고 싶었어).

동기

나는 항상 내 Git 워크플로우를 조정하는 걸 좋아했어. 다른 사람들의 커밋 옆에 있는 작은 "Verified" 배지를 보고 나는 생각했지: 왜 나는 안 돼? 기본 제공 GPG 서명은 좀 무겁고 전역 설정이라서, 결국 작은 헬퍼를 만들게 됐어:

  • 서명 전용 SSH 키 생성
  • 현재 저장소만 설정
  • 선택적으로 과거 커밋에 서명하도록 히스토리 재작성
  • 키를 다른 기기로 옮길 수 있게 내보내기/가져오기 지원

사실, 필요성은 대부분 허영심이었어. 내 개인 프로젝트에 서명이 기술적으로 필요한 건 아니지만, 커밋에 초록색 "Verified"가 있는 건 멋져 보이고, 스크립트를 작성하는 것 자체가 셸 스크립팅의 재미있는 연습이었어.

그러니까, 커밋에 서명하는 건 코드 리뷰에 가죽 자켓 입고 가는 거랑 비슷해 -- 완전 불필요하지만, 해커 된 기분이 들어.

스크립트가 하는 일

이 스크립트는 단일 Bash 파일이고, 상단에 set -euo pipefail이 있어서 실패 시 빠르게 중단돼. 대략적인 동작은 이렇다:

  1. 서명 키 생성 또는 가져오기 스크립트를 실행한 디렉토리의 .git-signing/에 키가 저장돼.
  2. 로컬 Git 설정 gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true, 그리고 공개 키를 가리키는 allowedSignersFile을 설정해.
  3. 크로스-머신 키 관리 --export-keys/--import-keys 옵션으로 개인 키를 전역 상태를 건드리지 않고 다른 컴퓨터로 옮길 수 있어.
  4. 선택적 히스토리 재작성 (--resign-all) 모든 브랜치/태그의 모든 커밋을 재작성하고 -S 플래그로 다시 커밋해. 다른 작성자는 건드리지 않아.
  5. 유틸리티 플래그 --autostash, --autopush, --commit-date, --yes 등 비대화형 모드 지원.
  6. 포크 인식 및 안전 검사 upstream 리모트 감지, 히스토리 재작성 전 경고, 필수 도구(git, ssh-keygen, zip/unzip) 확인, 권한 확인, 파일시스템 권한이 너무 느슨하면 보안 런타임 복사본 생성.

스크립트는 멱등적이다: 두 번 실행해도 키를 다시 생성하거나 기존 설정을 덮어쓰지 않아.

단계별 분석

다음은 설명과 함께 코드의 주요 부분들이다.

#!/usr/bin/env bash
set -euo pipefail

# 통제된 저장소-로컬 방식으로 SSH 커밋 서명을 설정한다.
# - 키 파일은 이 스크립트가 실행된 디렉토리에 생성된다.
# - Git 설정은 현재 저장소에만 로컬로 기록된다.

헤더는 안전성을 확보하고 목표를 문서화한다. 다음 청크는 while [[ $# -gt 0 ]]; do case … esac done 루프로 CLI 옵션(--name, --email, --repo 등)을 파싱한다. 필수 신원 필드는 나중에 확인된다:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

키 생성은 $LAUNCH_DIR/.git-signing에서 이루어진다. 키가 이미 존재하면 스크립트는 그대로 두고, --import-keys로 ZIP 파일에서 디렉토리를 채울 수 있다.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

개인 키를 사용할 수 있는지 확인한 후(ssh-keygen -Y sign …), 스크립트는 공개 키를 포함한 작은 allowed_signers 파일을 작성하고 Git 로컬 설정을 구성한다:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

--resign-all로 히스토리 재작성을 요청하면, 스크립트는 git filter-branch 명령을 만들어 자격이 되는 커밋을 -S로 다시 커밋한다. 포크 상태를 존중하여 선택적으로 upstream에 이미 있는 커밋은 건너뛴다.

마지막 출력은 공개 키와 GitHub의 Signing Key 섹션에 추가하는 방법, 그리고 빠른 테스트 레시피를 보여준다.

왜 커밋 서명인가?

이제 솔직히 말할 부분이다. 사실 필요하지 않았다. 내 저장소는 내가 게시하는 어떤 것에도 출처 증명이 필요하지 않고, 릴리스에 서명된 태그를 사용하지도 않는다. "왜"의 이유는:

  • 할 수 있으니까,
  • 깔끔해 보이니까 (배지 본 적 있어?),
  • git filter-branch와 셸 스크립팅을 실험할 핑계가 생겼으니까,
  • 그리고 블로그에 올릴 "내가 직접 만든" 콘텐츠가 하나 더 생겼으니까.

요약하자면: 그냥 보여주기용이었지만, 도구를 가지고 노는 재미의 절반은 그런 거야.

사용 예시

# 현재 저장소에 초기 설정
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# 다른 기기에서 사용할 키 내보내기
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# 두 번째 기기에서 키 가져오기
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# 히스토리 재작성 및 푸시
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

마지막 생각

이 스크립트는 작은 유틸리티지만, 몇 가지 좋은 아이디어를 담고 있어:

  • 암호화 키를 로컬 및 저장소별로 유지
  • 요청하지 않으면 전역 설정을 절대 건드리지 않음
  • 간단한 가져오기/내보내기 및 히스토리 재작성 제공
  • 왜 안 되겠어, 라는 마인드로 전체 과정을 블로그 글로 문서화

커밋에 서명을 추가하고 싶다면, 한번 사용해 봐! 그리고 그냥 스타일 포인트 때문에 온 거라면, 나랑 같은 생각이야. 😎

✨ AI Generated Article

SSH commit imzalama scripti açıklaması

SSH commit imzalama yardımcısının adım adım açıklaması ve neden şık

SSH commit imzalama scripti açıklaması

Bu yazı, Gist üzerinde yayınladığım setup-ssh-signing.sh scriptini derinlemesine inceliyor. Her bir parçanın ne yaptığına, repository bazlı SSH commit imzalamayı nasıl acısız hale getirdiğine ve evet, neden bunu yazma zahmetine girdiğime bakacağız (spoiler: sadece commit'lerimin şık görünmesini istedim).

Motivasyon

Git iş akışımı özelleştirmeyi her zaman sevmişimdir ve başkalarının commit'lerinin yanındaki küçük "Doğrulandı" rozetlerini gördükten sonra düşündüm: neden ben de yapmıyorum? Yerleşik GPG imzalama biraz ağır ve genel olduğu için, ufak bir yardımcı script yazmaya karar verdim:

  • sadece imzalama için bir SSH anahtarı oluşturur,
  • yalnızca mevcut repository'i yapılandırır,
  • isteğe bağlı olarak eski commit'leri imzalamak için geçmişi yeniden yazar,
  • ve anahtarı makineler arasında taşımana izin verir.

Aslında ihtiyaç tamamen kibirden ibaretti. Kişisel projelerimde imzaların teknik bir gerekliliği yok, ama commit'te yeşil bir "Doğrulandı" rozeti görmek havalı hissettiriyor ve scripti yazmak da shell script yazma açısından eğlenceli bir alıştırmaydı.

Yani, commit'lerini imzalamak, kod incelemesine deri ceketle gitmek gibi -- tamamen gereksiz, ama kendini hacker gibi hissettiriyor.

Script ne yapıyor

Script, başında set -euo pipefail olan tek bir Bash dosyası, böylece hata durumunda hemen duruyor. İşte davranışının yüksek seviyeli özeti:

  1. İmza anahtarı oluştur veya içe aktar
    Anahtarlar, scripti çalıştırdığın dizinin altındaki .git-signing/ klasöründe yaşar.
  2. Git'i yerel olarak yapılandır
    gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true ve genel anahtarı gösteren bir allowedSignersFile ayarlar.
  3. Anahtarları makineler arasında yönet
    --export-keys/--import-keys desteği, özel anahtarı genel duruma dokunmadan bilgisayarlar arasında taşımanı sağlar.
  4. İsteğe bağlı geçmiş yeniden yazma (--resign-all)
    Her branch/tag'deki her commit'i (veya fork'lar için upstream'de olmayanları) yeniden imzalar ve diğer yazarlara dokunmadan -S ile yeniden commit'ler.
  5. Yardımcı flag'ler
    --autostash, --autopush, --commit-date, --yes (etkileşimsiz mod) vb.
  6. Fork farkındalığı ve güvenlik kontrolleri
    upstream remote'u algılar, geçmişi yeniden yazmadan önce uyarır, gerekli araçları (git, ssh-keygen, zip/unzip) kontrol eder, doğru izinleri sağlar ve hatta dosya sistemi izinleri çok gevşekse anahtarın güvenli bir çalışma zamanı kopyasını oluşturur.

Script idempotenttir: iki kere çalıştırmak anahtarını yeniden oluşturmaz veya varolan yapılandırmayı üzerine yazmaz.

Adım adım inceleme

Aşağıda kodun açıklamalı bazı önemli kısımları var.

#!/usr/bin/env bash
set -euo pipefail

# SSH commit imzalamayı kontrollü, repo-bazlı bir şekilde yapılandır.
# - Anahtar dosyaları bu scriptin çalıştırıldığı dizinde oluşturulur.
# - Git yapılandırması sadece mevcut repository'e yerel olarak yazılır.

Başlık güvenliği sağlar ve hedefi belgeler. Sonraki kısım, CLI seçeneklerini (--name, --email, --repo vb.) bir while [[ $# -gt 0 ]]; do case … esac done döngüsüyle ayrıştırır. Zorunlu kimlik alanları daha sonra kontrol edilir:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

Anahtar oluşturma $LAUNCH_DIR/.git-signing altında gerçekleşir. Eğer anahtar zaten varsa script ona dokunmaz; --import-keys bir ZIP dosyasından dizini doldurabilir.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

Özel anahtarın kullanılabilir olduğundan emin olduktan sonra (ssh-keygen -Y sign …), script genel anahtarı içeren ufak bir allowed_signers dosyası yazar ve Git yerel yapılandırmasını buna göre ayarlar:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

--resign-all ile geçmiş yeniden yazmayı talep edersen, script uygun commit'leri -S ile yeniden imzalayan bir git filter-branch komutu oluşturur. Fork durumuna saygı göstererek, isteğe bağlı olarak upstream'de zaten var olan commit'leri atlar.

Son çıktı, genel anahtarı ve onu GitHub'ın İmzalama Anahtarı bölümüne ekleme talimatlarını, hızlı bir test tarifiyle birlikte yazdırır.

Neden commit imzalamalı?

İşte ihtiyacım olmadığını itiraf ettiğim kısım. Repolarım yayınladığım hiçbir şey için kaynak doğrulaması gerektirmiyor ve sürümler için imzalı tag kullanmıyorum. "Neden" şu:

  • çünkü yapabilirdim,
  • çünkü şık görünüyor (rozeti gördün mü?),
  • çünkü bana git filter-branch ve shell script ile deney yapma bahanesi verdi,
  • ve çünkü bu, blog için bir "bunu kendim yaptım" içeriği daha.

Kısacası: sadece gösteriş içindi, ama araçlarla oynamanın eğlencesinin yarısı da bu zaten.

Kullanım örnekleri

# mevcut repoda ilk kurulum
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Adın Soyadın" \
                       --email "[email protected]"

# anahtarları başka bir makinede kullanmak için dışa aktar
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# ikinci makinede anahtarları içe aktar
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Adın Soyadın" --email "[email protected]"

# geçmişi yeniden yaz ve pushla
./setup-ssh-signing.sh --repo ./my-repo --name "Adın Soyadın" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

Son düşünceler

Bu script küçük bir yardımcı, ama içinde birkaç güzel fikir barındırıyor:

  • kriptografik anahtarları yerel ve repo bazlı tut,
  • istemedikçe genel yapılandırmaya dokunma,
  • basit içe/dışa aktarma ve geçmiş yeniden yazma sun,
  • ve neden olmasın diye tüm süreci bir blog yazısında belgele.

Eğer kendi commit'lerine imza eklemek istersen, dene bir şans! Ve eğer sadece stil puanları için buradaysan, aynı şekilde. 😎

✨ AI Generated Article

Script di firma commit SSH spiegato

Una panoramica dell'helper per la firma dei commit SSH e perché

Script di firma commit SSH spiegato

Questo post analizza lo script setup-ssh-signing.sh che ho pubblicato su Gist. Vedremo cosa fa ogni parte, come rende semplice la firma SSH dei commit a livello di repository e, sì, perché mi sono preso la briga di scriverlo (spoiler: volevo solo che i miei commit avessero un aspetto stiloso).

Motivazione

Ho sempre amato ottimizzare il mio flusso di lavoro Git, e dopo aver visto altre persone con quei piccoli badge "Verified" accanto ai commit ho pensato: perché non io? La firma GPG integrata è un po' pesante e globale, quindi ho finito per scrivere un piccolo helper che:

  • crea una chiave SSH solo per la firma,
  • configura solo il repository corrente,
  • riscrive opzionalmente la storia per firmare i vecchi commit,
  • e mi permette di trasportare la chiave tra macchine diverse.

In realtà, il bisogno era principalmente vanità. Non c'è alcun requisito tecnico per le firme nei miei progetti personali, ma avere un badge verde "Verified" su un commit è figo, e scrivere lo script è stato un esercizio divertente di shell scripting.

Cioè, firmare i tuoi commit è come indossare un giubbotto di pelle a una code review -- totalmente inutile, ma ti fa sentire un hacker.

Cosa fa lo script

Lo script è un singolo file Bash con set -euo pipefail all'inizio in modo che fallisca rapidamente. Ecco un riassunto ad alto livello del suo comportamento:

  1. Genera o importa una chiave per la firma Le chiavi vivono in .git-signing/ nella directory in cui esegui lo script.
  2. Configura Git localmente Imposta gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true, e un allowedSignersFile che punta alla chiave pubblica.
  3. Gestisce le chiavi tra macchine diverse Il supporto per --export-keys/--import-keys ti permette di spostare la chiave privata tra computer senza toccare lo stato globale.
  4. Riscrittura opzionale della storia (--resign-all) Riscrive ogni commit su ogni branch/tag (o solo quelli non in upstream per i fork) e li ricommite con -S, lasciando intatti gli altri autori.
  5. Flag di utilità --autostash, --autopush, --commit-date, --yes per modalità non interattiva, ecc.
  6. Consapevolezza dei fork e controlli di sicurezza Rileva il remote upstream, avverte prima di riscrivere la storia, controlla gli strumenti necessari (git, ssh-keygen, zip/unzip), garantisce i permessi corretti, e crea persino una copia sicura della chiave in fase di esecuzione se i permessi del filesystem sono troppo permissivi.

Lo script è idempotente: eseguirlo due volte non rigenera la tua chiave né sovrascrive la configurazione esistente.

Analisi passo dopo passo

Qui sotto ci sono alcune delle parti chiave del codice con spiegazioni.

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

L'intestazione stabilisce la sicurezza e documenta l'obiettivo. Il blocco successivo analizza le opzioni CLI (--name, --email, --repo, ecc.) con un loop while [[ $# -gt 0 ]]; do case … esac done. I campi di identità obbligatori vengono imposti più avanti:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

La generazione della chiave avviene in $LAUNCH_DIR/.git-signing. Se una chiave esiste già, lo script la lascia stare; --import-keys può popolare la directory da un file ZIP.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

Dopo essersi assicurato che la chiave privata sia utilizzabile (ssh-keygen -Y sign …), lo script scrive un piccolo file allowed_signers contenente la chiave pubblica e imposta la configurazione Git locale di conseguenza:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

Se richiedi la riscrittura della storia con --resign-all, lo script costruisce un comando git filter-branch che ricommite i commit idonei con -S. Rispetta lo stato del fork saltando opzionalmente i commit già presenti in upstream.

L'output finale stampa la chiave pubblica e le istruzioni per aggiungerla alla sezione Signing Key di GitHub, insieme a una rapida ricetta di test.

Perché firmare i commit?

Questa è la parte in cui ammetto che non ne avevo bisogno. I miei repository non richiedono provenienza per nulla di ciò che pubblico, e non uso tag firmati per le release. Il "perché" è:

  • perché potevo,
  • perché è carino da vedere (hai visto il badge?),
  • perché mi ha dato una scusa per sperimentare con git filter-branch e shell scripting,
  • e perché è un altro pezzo di "l'ho costruito io" per il blog.

In breve: era solo per mostrarlo, ma è metà del divertimento quando si armeggia con gli strumenti.

Esempi di utilizzo

# configurazione iniziale nel repo corrente
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# esporta le chiavi per usarle su un'altra macchina
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# importa le chiavi su una seconda macchina
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# riscrivi la storia e fai push
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

Considerazioni finali

Questo script è un piccolo strumento, ma racchiude alcune idee interessanti:

  • tenere le chiavi crittografiche locali e per-repo,
  • non toccare mai la configurazione globale a meno che non lo chieda esplicitamente,
  • fornire semplici funzioni di import/export e riscrittura della storia,
  • e documentare l'intero processo in un post del blog, perché no.

Se sei tentato di aggiungere firme ai tuoi commit, provalo! E se sei qui solo per lo stile, stesso identico motivazione. 😎

✨ AI Generated Article

SSH-Commit-Signing-Skript erklärt

Eine Erklärung des SSH-Commit-Signing-Helfers und warum ich

SSH-Commit-Signing-Skript erklärt

Dieser Beitrag taucht in das setup-ssh-signing.sh-Skript ein, das ich auf Gist veröffentlicht habe. Wir schauen uns an, was jeder Teil macht, wie es repository-lokales SSH-Commit-Signing schmerzfrei macht und, ja, warum ich überhaupt die Mühe gemacht habe, es zu schreiben (Spoiler: Ich wollte einfach, dass meine Commits stylisch aussehen).

Motivation

Ich habe es immer geliebt, meinen Git-Workflow zu optimieren, und nachdem ich andere Leute mit kleinen „Verified“-Badges neben ihren Commits gesehen habe, dachte ich mir: warum nicht ich? Das integrierte GPG-Signing ist etwas schwerfällig und global, also habe ich einen kleinen Helfer geschrieben, der:

  • einen SSH-Key nur zum Signieren erstellt,
  • nur das aktuelle Repository konfiguriert,
  • optional die Historie umschreibt, um alte Commits zu signieren,
  • und mir erlaubt, den Key zwischen Maschinen zu verschieben.

Ehrlich gesagt, das Bedürfnis war hauptsächlich Eitelkeit. Es gibt keine technische Notwendigkeit für Signaturen in meinen persönlichen Projekten, aber ein grünes „Verified“ auf einem Commit fühlt sich cool an, und das Skript zu schreiben war eine unterhaltsame Übung in Shell-Scripting.

Ich meine, seine Commits zu signieren ist wie das Tragen einer Lederjacke zu einem Code-Review – völlig unnötig, aber es gibt dir das Gefühl, ein Hacker zu sein.

Was das Skript macht

Das Skript ist eine einzelne Bash-Datei mit set -euo pipefail oben, damit es schnell abbricht. Hier ist eine Zusammenfassung seines Verhaltens:

  1. Signier-Key erstellen oder importieren
    Die Keys liegen in .git-signing/ im Verzeichnis, in dem du das Skript ausführst.
  2. Git lokal konfigurieren
    Setzt gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true und eine allowedSignersFile, die auf den öffentlichen Key zeigt.
  3. Keys maschinenübergreifend verwalten
    Unterstützung für --export-keys/--import-keys erlaubt dir, den privaten Key zwischen Computern zu verschieben, ohne den globalen Status zu berühren.
  4. Optionale Historie-Umschreibung (--resign-all)
    Schreibt jeden Commit auf jedem Branch/Tag um (oder nur die, die nicht in upstream sind, bei Forks) und signiert sie mit -S, wobei andere Autoren unberührt bleiben.
  5. Utility-Flags
    --autostash, --autopush, --commit-date, --yes für nicht-interaktiven Modus, etc.
  6. Fork-Bewusstsein und Sicherheitschecks
    Erkennt upstream-Remote, warnt vor dem Umschreiben der Historie, prüft auf benötigte Tools (git, ssh-keygen, zip/unzip), stellt korrekte Berechtigungen sicher und erstellt bei Bedarf eine sichere Runtime-Kopie des Keys, wenn die Dateisystemberechtigungen zu locker sind.

Das Skript ist idempotent: Zweimaliges Ausführen regeneriert weder deinen Key noch überschreibt es bestehende Konfiguration.

Schritt-für-Schritt-Erklärung

Hier sind einige der wichtigsten Code-Teile mit Erklärungen.

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

Der Kopf sorgt für Sicherheit und dokumentiert das Ziel. Der nächste Block parst CLI-Optionen (--name, --email, --repo, etc.) mit einer while [[ $# -gt 0 ]]; do case … esac done-Schleife. Pflichtfelder für die Identität werden später durchgesetzt:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

Die Generierung der Keys findet unter $LAUNCH_DIR/.git-signing statt. Wenn bereits ein Key existiert, lässt das Skript ihn in Ruhe; --import-keys kann das Verzeichnis aus einer ZIP-Datei befüllen.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

Nachdem sichergestellt ist, dass der private Key verwendbar ist (ssh-keygen -Y sign …), schreibt das Skript eine kleine allowed_signers-Datei mit dem öffentlichen Key und setzt die lokale Git-Konfiguration entsprechend:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

Wenn du die Historie mit --resign-all umschreiben möchtest, baut das Skript einen git filter-branch-Befehl, der berechtigte Commits mit -S neu signiert. Es respektiert den Fork-Status, indem es optional Commits überspringt, die bereits in upstream sind.

Die endgültige Ausgabe zeigt den öffentlichen Key und Anweisungen zum Hinzufügen zu GitHub's Signing Key-Abschnitt, zusammen mit einem kurzen Test-Rezept.

Warum Commit-Signing?

Dies ist der Teil, in dem ich zugebe, dass ich es nicht brauchte. Meine Repositories benötigen keine Herkunftsnachweise für alles, was ich veröffentliche, und ich verwende keine signierten Tags für Releases. Das „Warum“ ist:

  • weil ich es konnte,
  • weil es ordentlich aussieht (hast du das Badge gesehen?),
  • weil es mir einen Grund gab, mit git filter-branch und Shell-Scripting zu experimentieren,
  • und weil es ein weiteres „Das habe ich selbst gebaut“-Stück Content für den Blog ist.

Kurz gesagt: Es war nur für die Show, aber das ist die halbe Miete beim Tüfteln an Tools.

Anwendungsbeispiele

# initial setup in current repo
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# export keys to use on another machine
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# import keys on second machine
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# rewrite history and push
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

Abschließende Gedanken

Dieses Skript ist ein kleines Utility, aber es beinhaltet ein paar nette Ideen:

  • kryptografische Keys lokal und pro-Repository halten,
  • niemals die globale Konfiguration berühren, es sei denn, du verlangst es,
  • einfachen Import/Export und Historie-Umschreibung bereitstellen,
  • und den gesamten Prozess in einem Blogbeitrag dokumentieren, weil nicht.

Wenn du Lust hast, deinen eigenen Commits Signaturen hinzuzufügen, probier es aus! Und wenn du nur wegen der Style-Punkte hier bist, same. 😎

✨ AI Generated Article

Скрипт подписи коммитов SSH -- объяснение

Разбор помощника для подписи коммитов через SSH и почему я хотел

Скрипт подписи коммитов SSH -- объяснение

В этом посте мы разберём скрипт setup-ssh-signing.sh, который я опубликовал в Gist. Посмотрим, что делает каждая часть, как он упрощает локальную подпись коммитов через SSH в рамках репозитория и, да, почему я вообще решил его написать (спойлер: я просто хотел, чтобы мои коммиты выглядели стильно).

Мотивация

Мне всегда нравилось настраивать свой Git-воркфлоу, и после того, как я увидел у других людей маленькие значки «Verified» рядом с коммитами, я подумал: а почему не я? Встроенная GPG-подпись немного тяжеловесна и глобальна, поэтому в итоге я написал маленький помощник, который:

  • создаёт SSH-ключ только для подписи,
  • настраивает только текущий репозиторий,
  • опционально переписывает историю, подписывая старые коммиты,
  • и позволяет переносить ключ между машинами.

На самом деле, причина была в тщеславии. В моих личных проектах нет технической необходимости в подписях, но иметь зелёный «Verified» на коммите -- это круто, а написание скрипта было весёлым упражнением в шелл-скриптинге.

То есть, подписывать свои коммиты -- это как носить кожаную куртку на код-ревью: совершенно необязательно, но чувствуешь себя хакером.

Что делает скрипт

Скрипт -- это один Bash-файл с set -euo pipefail в начале, чтобы он быстро завершался при ошибках. Вот краткое описание его поведения:

  1. Создать или импортировать ключ подписи Ключи хранятся в .git-signing/ в директории, откуда ты запускаешь скрипт.
  2. Настроить Git локально Устанавливает gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true и allowedSignersFile, указывающий на публичный ключ.
  3. Управление ключами между машинами Поддержка --export-keys/--import-keys позволяет переносить приватный ключ между компьютерами без изменения глобального состояния.
  4. Опциональное переписывание истории (--resign-all) Переписывает каждый коммит на каждой ветке/теге (или только те, которых нет в upstream для форков) и подписывает их с помощью -S, не трогая других авторов.
  5. Дополнительные флаги --autostash, --autopush, --commit-date, --yes для неинтерактивного режима и т.д.
  6. Осведомлённость о форках и проверки безопасности Обнаруживает удалённый репозиторий upstream, предупреждает перед переписыванием истории, проверяет наличие необходимых инструментов (git, ssh-keygen, zip/unzip), обеспечивает правильные разрешения и даже создаёт безопасную копию ключа для выполнения, если разрешения файловой системы слишком свободные.

Скрипт идемпотентен: запуск дважды не пересоздаст ключ и не перезапишет существующую конфигурацию.

Пошаговый разбор

Ниже приведены некоторые ключевые части кода с пояснениями.

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

Заголовок устанавливает безопасность и документирует цель. Следующий блок разбирает опции CLI (--name, --email, --repo и т.д.) через цикл while [[ $# -gt 0 ]]; do case … esac done. Обязательные поля личности проверяются позже:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

Генерация ключа происходит в $LAUNCH_DIR/.git-signing. Если ключ уже существует, скрипт его не трогает; --import-keys может заполнить директорию из ZIP-файла.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

После проверки, что приватный ключ можно использовать (ssh-keygen -Y sign …), скрипт записывает крошечный файл allowed_signers, содержащий публичный ключ, и устанавливает локальную конфигурацию Git:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

Если ты запрашиваешь переписывание истории с помощью --resign-all, скрипт собирает команду git filter-branch, которая подписывает подходящие коммиты с помощью -S. Он учитывает состояние форка, опционально пропуская коммиты, уже присутствующие в upstream.

Финальный вывод показывает публичный ключ и инструкции по добавлению его в раздел Signing Key на GitHub, а также небольшой рецепт для тестирования.

Зачем подписывать коммиты?

Это та часть, где я признаю, что мне это было не нужно. Мои репозитории не требуют подтверждения происхождения для того, что я публикую, и я не использую подписанные теги для релизов. «Почему» таково:

  • потому что я мог,
  • потому что это выглядит круто (ты видел значок?),
  • потому что это дало мне повод поэкспериментировать с git filter-branch и шелл-скриптингом,
  • и потому что это ещё один контент «я сделал это сам» для блога.

Короче: это было просто для понтов, но в этом и половина веселья от возни с инструментами.

Примеры использования

# initial setup in current repo
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# export keys to use on another machine
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# import keys on second machine
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# rewrite history and push
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

Мысли напоследок

Этот скрипт -- небольшая утилита, но в ней воплощено несколько хороших идей:

  • хранить криптографические ключи локально и в рамках одного репозитория,
  • никогда не трогать глобальную конфигурацию без явного запроса,
  • предоставлять простой импорт/экспорт и переписывание истории,
  • и документировать весь процесс в блоге -- а почему бы и нет.

Если тебя тоже тянет добавить подписи к своим коммитам -- попробуй! А если ты здесь просто за стилем -- тоже норм. 😎

✨ AI Generated Article

Script de firma de commits SSH explicado

Un recorrido por el ayudante de firma de commits SSH y por qué

Script de firma de commits SSH explicado

Este artículo explora el script setup-ssh-signing.sh que publiqué en Gist. Veremos qué hace cada parte, cómo hace que la firma de commits SSH local al repositorio sea sencilla y, sí, por qué me molesté en escribirlo en primer lugar (spoiler: solo quería que mis commits se vieran con estilo).

Motivación

Siempre me ha encantado ajustar mi flujo de trabajo de Git, y después de ver a otras personas con pequeñas insignias «Verified» junto a sus commits pensé: ¿por qué yo no? La firma GPG integrada es un poco pesada y global, así que terminé escribiendo un pequeño ayudante que:

  • crea una clave SSH solo para firmar,
  • configura solo el repositorio actual,
  • opcionalmente reescribe el historial para firmar commits antiguos,
  • y permite transferir la clave entre máquinas.

En realidad, la necesidad era principalmente vanidad. No hay ningún requisito técnico para las firmas en mis proyectos personales, pero tener un «Verified» verde en un commit se siente genial, y escribir el script fue un ejercicio divertido de scripting en shell.

Digo, firmar tus commits es como usar una chaqueta de cuero en una revisión de código -- totalmente innecesario, pero te hace sentir como un hacker.

Lo que hace el script

El script es un solo archivo Bash con set -euo pipefail al principio para que falle rápido. Aquí hay un resumen de alto nivel de su comportamiento:

  1. Generar o importar una clave de firma
    Las claves viven en .git-signing/ en el directorio donde ejecutas el script.
  2. Configurar Git localmente
    Establece gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true, y un allowedSignersFile que apunta a la clave pública.
  3. Gestionar claves entre máquinas
    Soporte para --export-keys/--import-keys que te permite mover la clave privada entre computadoras sin tocar el estado global.
  4. Reescritura opcional del historial (--resign-all)
    Reescribe cada commit en cada rama/tag (o solo aquellos no presentes en upstream para forks) y los vuelve a firmar con -S, dejando a otros autores intactos.
  5. Flags de utilidad
    --autostash, --autopush, --commit-date, --yes para modo no interactivo, etc.
  6. Detección de forks y verificaciones de seguridad
    Detecta el remoto upstream, advierte antes de reescribir el historial, verifica las herramientas necesarias (git, ssh-keygen, zip/unzip), asegura los permisos adecuados, e incluso crea una copia segura de la clave en tiempo de ejecución si los permisos del sistema de archivos son demasiado permisivos.

El script es idempotente: ejecutarlo dos veces no regenerará tu clave ni sobrescribirá la configuración existente.

Explicación paso a paso

A continuación se muestran algunas de las partes clave del código con explicaciones.

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

El encabezado establece seguridad y documenta el objetivo. El siguiente bloque analiza las opciones de CLI (--name, --email, --repo, etc.) con un bucle while [[ $# -gt 0 ]]; do case … esac done. Los campos de identidad obligatorios se validan más adelante:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

La generación de claves ocurre en $LAUNCH_DIR/.git-signing. Si ya existe una clave, el script la deja intacta; --import-keys puede poblar el directorio desde un archivo ZIP.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

Después de asegurarse de que la clave privada es usable (ssh-keygen -Y sign …), el script escribe un pequeño archivo allowed_signers que contiene la clave pública y establece la configuración local de Git correspondiente:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

Si solicitas la reescritura del historial con --resign-all, el script construye un comando git filter-branch que vuelve a firmar los commits elegibles con -S. Respeta el estado del fork omitiendo opcionalmente los commits ya presentes en upstream.

El resultado final imprime la clave pública y las instrucciones para agregarla a la sección Signing Key de GitHub, junto con una receta rápida de prueba.

¿Por qué firmar commits?

Esta es la parte donde admito que no lo necesitaba. Mis repositorios no requieren procedencia para nada de lo que publico, y no uso tags firmados para releases. El «por qué» es:

  • porque podía,
  • porque se ve bonito (¿has visto la insignia?),
  • porque me dio una excusa para experimentar con git filter-branch y scripting en shell,
  • y porque es otra pieza de contenido «yo mismo construí esto» para el blog.

En resumen: era solo por apariencia, pero esa es la mitad de la diversión de jugar con herramientas.

Ejemplos de uso

# configuración inicial en el repositorio actual
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Tu Nombre" \
                       --email "[email protected]"

# exportar claves para usar en otra máquina
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# importar claves en una segunda máquina
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Tu Nombre" --email "[email protected]"

# reescribir historial y hacer push
./setup-ssh-signing.sh --repo ./my-repo --name "Tu Nombre" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

Reflexiones finales

Este script es una pequeña utilidad, pero encapsula algunas ideas interesantes:

  • mantener las claves criptográficas locales y por repositorio,
  • nunca tocar la configuración global a menos que lo pidas,
  • proporcionar importación/exportación simple y reescritura de historial,
  • y documentar todo el proceso en una entrada de blog porque ¿por qué no?

Si te sientes tentado a agregar firmas a tus propios commits, ¡pruébalo! Y si solo estás aquí por los puntos de estilo, igual. 😎

✨ AI Generated Article

Script de assinatura SSH explicado

Detalhamento do helper de assinatura de commits SSH e por que eu

Script de assinatura SSH para commits -- explicação

Este artigo detalha o script setup-ssh-signing.sh que publiquei no Gist. Vamos ver o que cada parte faz, como ele torna a assinatura SSH local a um repositório completamente indolor, e, sim, por que eu me dei ao trabalho de escrevê-lo (spoiler: eu só queria que meus commits tivessem estilo).

Motivação

Sempre adorei mexer no meu workflow Git, e depois de ver pessoas com selinhos «Verified» ao lado dos commits, pensei: por que eu não? A assinatura GPG integrada é pesada e global, então acabei escrevendo um pequeno helper que:

  • cria uma chave SSH dedicada à assinatura,
  • configura apenas o repositório atual,
  • opcionalmente reescreve o histórico para assinar commits antigos,
  • e permite transportar a chave entre máquinas.

Francamente, a necessidade era mais vaidade. Não tenho exigência técnica de assinatura nos meus projetos pessoais, mas ver um selo verde «Verified» em um commit dá um certo gosto, e escrever o script foi um prazer em shell.

Bem, assinar seus commits é como vestir uma jaqueta de couro para uma review de código -- totalmente inútil, mas faz você se sentir um hacker.

O que o script faz

O script é um único arquivo Bash com set -euo pipefail no topo para falhar rápido e de uma vez. Aqui está um resumo do que ele faz:

  1. Gerar ou importar uma chave de assinatura
    As chaves vão para .git-signing/ no diretório onde você executa o script.
  2. Configurar Git localmente
    Ele define gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true, e um allowedSignersFile que aponta para a chave pública.
  3. Gerenciar chaves entre máquinas
    Com --export-keys / --import-keys, você pode levar sua chave privada de um computador para outro sem mexer na configuração global.
  4. Reescrita opcional de histórico (--resign-all)
    Reescreve todos os commits de todos os branches/tags (ou apenas os que não estão no upstream para forks) e os reassina com -S, sem alterar outros autores.
  5. Flags utilitárias
    --autostash, --autopush, --commit-date, --yes para modo não interativo, etc.
  6. Detecção de fork e verificações de segurança
    Ele detecta o remote upstream, avisa antes de reescrever o histórico, verifica as ferramentas necessárias (git, ssh-keygen, zip/unzip), garante permissões corretas, e até cria uma cópia segura da chave se as permissões do filesystem forem muito permissivas.

O script é idempotente: executá-lo duas vezes não regenera sua chave nem sobrescreve a configuração existente.

Passo a passo

Aqui estão alguns trechos chave do código com suas explicações.

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

O cabeçalho estabelece segurança e documenta o objetivo. A parte seguinte faz o parsing das opções CLI (--name, --email, --repo, etc.) com um loop while [[ $# -gt 0 ]]; do case … esac done. Os campos obrigatórios de identidade são verificados mais adiante:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

A geração de chave acontece em $LAUNCH_DIR/.git-signing. Se uma chave já existir, o script a deixa em paz; --import-keys permite preencher o diretório a partir de um ZIP.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

Após verificar que a chave privada é utilizável (ssh-keygen -Y sign …), o script escreve um pequeno arquivo allowed_signers contendo a chave pública e define a configuração Git local:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

Se você solicitar a reescrita de histórico com --resign-all, o script constrói um comando git filter-branch que reassina os commits elegíveis com -S. Ele respeita o estado do fork pulando opcionalmente os commits já presentes no upstream.

O resultado final exibe a chave pública e as instruções para adicioná-la na seção Signing Key do GitHub, com uma pequena receita de teste.

Por que assinar seus commits?

É aqui que admito que não precisava disso. Meus repositórios não exigem proveniência para o que publico, e não uso tags assinadas para releases. O «porquê» é:

  • porque eu podia,
  • porque fica bonito (viu o selo?),
  • porque me deu uma desculpa para experimentar com git filter-branch e shell,
  • e porque é mais um «eu construí isso» para o blog.

Resumindo, foi só para ostentar, mas é isso que é legal quando a gente mexe nas próprias ferramentas.

Exemplos de uso

# configuração inicial no repositório atual
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# exportar as chaves para outra máquina
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# importar as chaves em uma segunda máquina
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# reescrever o histórico e push
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

Últimas reflexões

Este script é um pequeno utilitário, mas contém algumas ideias legais:

  • manter as chaves criptográficas locais e por repositório,
  • nunca mexer na configuração global a menos que você peça,
  • fornecer importação/exportação simples e reescrita de histórico,
  • e documentar todo o processo em um artigo de blog, porque não.

Se bater a vontade de adicionar assinaturas aos seus próprios commits, experimente! E se você só está aqui pelo estilo, também vale. 😎

✨ AI Generated Article

Skrip Penandatanganan SSH Dijelaskan

Menguraikan helper penandatanganan komit SSH dan mengapa saya ingin

Skrip Penandatanganan SSH untuk Komit -- Penjelasan

Artikel ini menguraikan skrip setup-ssh-signing.sh yang saya publikasikan di Gist. Kita akan lihat apa yang dilakukan setiap bagian, bagaimana cara membuat penandatanganan SSH lokal untuk sebuah repositori menjadi sangat mudah, dan, ya, mengapa saya repot-repot menulisnya (spoiler: saya hanya ingin komit saya terlihat keren).

Motivasi

Saya selalu suka mengutak-atik alur kerja Git saya, dan setelah melihat orang-orang dengan lencana « Verified » kecil di samping komit mereka, saya berpikir: kenapa bukan saya? Penandatanganan GPG bawaan terasa berat dan global, jadi saya akhirnya menulis helper kecil yang:

  • membuat kunci SSH khusus untuk penandatanganan,
  • hanya mengonfigurasi repositori saat ini,
  • opsionalnya menulis ulang riwayat untuk menandatangani komit lama,
  • dan memungkinkan membawa kunci antar mesin.

Sejujurnya, kebutuhannya lebih karena gaya. Tidak ada persyaratan teknis penandatanganan di proyek pribadi saya, tetapi melihat lencana hijau « Verified » pada komit itu terasa keren, dan menulis skripnya adalah kesenangan tersendiri di shell.

Baik, menandatangani komit itu seperti memakai jaket kulit untuk review kode -- sama sekali tidak berguna, tetapi membuatmu merasa seperti seorang hacker.

Apa yang Dilakukan Skrip

Skrip ini adalah satu file Bash dengan set -euo pipefail di atas agar cepat gagal jika ada masalah. Berikut ringkasan apa yang dilakukannya:

  1. Membuat atau mengimpor kunci penandatanganan
    Kunci ditempatkan di .git-signing/ dalam direktori tempat kamu menjalankan skrip.
  2. Mengonfigurasi Git secara lokal
    Mengatur gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true, dan allowedSignersFile yang mengarah ke kunci publik.
  3. Mengelola kunci antar mesin
    Dengan --export-keys / --import-keys, kamu bisa membawa kunci privat dari satu komputer ke komputer lain tanpa menyentuh konfigurasi global.
  4. Penulisan ulang riwayat opsional (--resign-all)
    Menulis ulang semua komit di semua cabang/tag (atau hanya yang tidak ada di upstream untuk fork) dan menandatanganinya ulang dengan -S, tanpa mengubah penulis lain.
  5. Flag utilitas
    --autostash, --autopush, --commit-date, --yes untuk mode non-interaktif, dll.
  6. Deteksi fork dan pemeriksaan keamanan
    Mendeteksi remote upstream, memperingatkan sebelum menulis ulang riwayat, memeriksa alat yang diperlukan (git, ssh-keygen, zip/unzip), memastikan izin yang benar, dan bahkan membuat salinan aman kunci jika izin filesystem terlalu longgar.

Skrip ini idempoten: menjalankannya dua kali tidak akan membuat ulang kunci atau menimpa konfigurasi yang sudah ada.

Penjelasan Langkah demi Langkah

Berikut beberapa cuplikan kunci dari kode beserta penjelasannya.

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

Header ini menetapkan keamanan dan mendokumentasikan tujuan. Bagian berikutnya mem-parsing opsi CLI (--name, --email, --repo, dll.) dengan loop while [[ $# -gt 0 ]]; do case … esac done. Bidang identitas wajib diperiksa nanti:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

Pembuatan kunci terjadi di $LAUNCH_DIR/.git-signing. Jika kunci sudah ada, skrip akan membiarkannya; --import-keys memungkinkan mengisi direktori dari file ZIP.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

Setelah memverifikasi bahwa kunci privat dapat digunakan (ssh-keygen -Y sign …), skrip menulis file allowed_signers kecil yang berisi kunci publik dan mengatur konfigurasi Git lokal:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

Jika kamu meminta penulisan ulang riwayat dengan --resign-all, skrip akan menyusun perintah git filter-branch yang menandatangani ulang komit yang memenuhi syarat dengan -S. Skrip ini menghormati status fork dengan secara opsional melewati komit yang sudah ada di upstream.

Hasil akhirnya menampilkan kunci publik dan petunjuk untuk menambahkannya di bagian Signing Key GitHub, lengkap dengan resep pengujian kecil.

Mengapa Menandatangani Komit?

Inilah saatnya saya mengakui bahwa saya tidak membutuhkannya. Repositori saya tidak memerlukan provenans untuk apa yang saya publikasikan, dan saya tidak menggunakan tag yang ditandatangani untuk rilis. « Mengapa » nya adalah:

  • karena saya bisa,
  • karena terlihat bagus (lihat lencananya?),
  • karena ini memberi saya alasan untuk bereksperimen dengan git filter-branch dan shell,
  • dan karena ini adalah satu lagi « saya membuat ini sendiri » untuk blog.

Singkatnya, ini hanya untuk pamer, tetapi itulah yang menyenangkan saat mengutak-atik alat sendiri.

Contoh Penggunaan

# konfigurasi awal di repositori saat ini
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# mengekspor kunci untuk mesin lain
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# mengimpor kunci di mesin kedua
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# menulis ulang riwayat dan push
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

Pemikiran Terakhir

Skrip ini adalah utilitas kecil, tetapi mengandung beberapa ide menarik:

  • menyimpan kunci kriptografis secara lokal dan per repositori,
  • tidak pernah menyentuh konfigurasi global kecuali kamu memintanya,
  • menyediakan impor/ekspor sederhana dan penulisan ulang riwayat,
  • dan mendokumentasikan seluruh proses dalam artikel blog, karena kenapa tidak.

Jika kamu tertarik untuk menambahkan tanda tangan ke komitmu sendiri, cobalah! Dan jika kamu hanya di sini untuk gayanya, sama saja. 😎

✨ AI Generated Article

SSH हस्ताक्षर स्क्रिप्ट समझाया गया

SSH कमिट हस्ताक्षर हेल्पर का विश्लेषण और मैं स्टाइलिश कमिट क्यों चाहता था।

SSH कमिट हस्ताक्षर स्क्रिप्ट -- व्याख्या

यह लेख मेरे द्वारा Gist पर प्रकाशित setup-ssh-signing.sh स्क्रिप्ट की विस्तृत व्याख्या करता है। हम देखेंगे कि प्रत्येक भाग क्या करता है, यह कैसे SSH हस्ताक्षर को रिपॉजिटरी-स्तर पर पूरी तरह से सरल बना देता है, और हाँ, मैंने इसे लिखने की जहमत क्यों उठाई (स्पॉइलर: मैं बस चाहता था कि मेरे कमिट शानदार दिखें)।

प्रेरणा

मुझे हमेशा अपने Git वर्कफ़्लो को ट्वीक करना पसंद रहा है, और जब मैंने लोगों को उनके कमिट के बगल में छोटे "Verified" बैज देखे, तो मैंने सोचा: क्यों न मैं भी? GPG हस्ताक्षर प्रणाली बोझिल और वैश्विक है, इसलिए मैंने एक छोटा हेल्पर लिखा जो:

  • हस्ताक्षर के लिए एक समर्पित SSH कुंजी बनाता है,
  • केवल वर्तमान रिपॉजिटरी को कॉन्फ़िगर करता है,
  • वैकल्पिक रूप से पुराने कमिट पर हस्ताक्षर करने के लिए इतिहास को फिर से लिखता है,
  • और कुंजी को मशीनों के बीच स्थानांतरित करने की अनुमति देता है।

सच कहूँ तो, यह मुख्य रूप से दिखावा था। मेरे व्यक्तिगत प्रोजेक्ट्स में हस्ताक्षर की कोई तकनीकी आवश्यकता नहीं है, लेकिन कमिट पर हरा "Verified" बैज देखना अच्छा लगता है, और स्क्रिप्ट लिखना शेल में एक मज़ेदार अनुभव था।

खैर, अपने कमिट पर हस्ताक्षर करना कुछ हद तक कोड समीक्षा के लिए चमड़े की जैकेट पहनने जैसा है -- पूरी तरह से अनावश्यक, लेकिन आपको एक हैकर जैसा महसूस कराता है।

स्क्रिप्ट क्या करती है

स्क्रिप्ट एक एकल Bash फ़ाइल है जिसमें शीर्ष पर set -euo pipefail है ताकि तेज़ी से विफल हो सके। यहाँ इसका सारांश है:

  1. हस्ताक्षर कुंजी उत्पन्न या आयात करना
    कुंजियाँ उस निर्देशिका में .git-signing/ फ़ोल्डर में बनाई जाती हैं जहाँ आप स्क्रिप्ट चलाते हैं।
  2. Git को स्थानीय रूप से कॉन्फ़िगर करना
    यह gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true, और एक allowedSignersFile सेट करता है जो सार्वजनिक कुंजी की ओर इंगित करता है।
  3. मशीनों के बीच कुंजी प्रबंधित करना
    --export-keys / --import-keys के माध्यम से, आप अपनी निजी कुंजी को वैश्विक कॉन्फ़िगरेशन को छुए बिना एक कंप्यूटर से दूसरे में ले जा सकते हैं।
  4. वैकल्पिक इतिहास पुनर्लेखन (--resign-all)
    सभी शाखाओं/टैग्स (या केवल वे जो फ़ॉर्क के लिए upstream में नहीं हैं) के सभी कमिट को फिर से लिखता है और अन्य लेखकों को छुए बिना -S के साथ पुनः हस्ताक्षरित करता है।
  5. उपयोगिता फ़्लैग
    --autostash, --autopush, --commit-date, --yes (नॉन-इंटरैक्टिव मोड के लिए), आदि।
  6. फ़ॉर्क डिटेक्शन और सुरक्षा जाँच
    यह upstream रिमोट का पता लगाता है, इतिहास को फिर से लिखने से पहले चेतावनी देता है, आवश्यक टूल्स (git, ssh-keygen, zip/unzip) की जाँच करता है, सही अनुमतियाँ सुनिश्चित करता है, और फ़ाइलसिस्टम की अनुमतियाँ बहुत उदार होने पर कुंजी की एक सुरक्षित प्रति भी बनाता है।

स्क्रिप्ट आइडेम्पोटेंट है: इसे दो बार चलाने से आपकी कुंजी पुनः उत्पन्न नहीं होगी और मौजूदा कॉन्फ़िगरेशन ओवरराइट नहीं होगा।

चरण-दर-चरण विवरण

यहाँ कोड के कुछ मुख्य अंश और उनके स्पष्टीकरण दिए गए हैं।

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

शीर्षक सुरक्षा सुनिश्चित करता है और उद्देश्य का दस्तावेज़ीकरण करता है। अगला भाग CLI विकल्पों (--name, --email, --repo, आदि) को while [[ $# -gt 0 ]]; do case … esac done लूप के साथ पार्स करता है। अनिवार्य पहचान फ़ील्ड की जाँच बाद में की जाती है:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

कुंजी निर्माण $LAUNCH_DIR/.git-signing में होता है। यदि कुंजी पहले से मौजूद है, तो स्क्रिप्ट उसे छोड़ देती है; --import-keys फ़ोल्डर को ZIP से भरने की अनुमति देता है।

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

निजी कुंजी के उपयोग योग्य होने की पुष्टि (ssh-keygen -Y sign …) के बाद, स्क्रिप्ट एक छोटी allowed_signers फ़ाइल लिखती है जिसमें सार्वजनिक कुंजी होती है और स्थानीय Git कॉन्फ़िगरेशन सेट करती है:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

यदि आप --resign-all के साथ इतिहास पुनर्लेखन का अनुरोध करते हैं, तो स्क्रिप्ट एक git filter-branch कमांड बनाती है जो पात्र कमिट को -S के साथ पुनः हस्ताक्षरित करती है। यह फ़ॉर्क स्थिति का सम्मान करते हुए वैकल्पिक रूप से upstream में पहले से मौजूद कमिट को छोड़ देता है।

अंतिम परिणाम सार्वजनिक कुंजी और GitHub के Signing Key अनुभाग में जोड़ने के निर्देशों के साथ एक छोटी परीक्षण रेसिपी प्रदर्शित करता है।

कमिट पर हस्ताक्षर क्यों करें?

यह वह क्षण है जब मैं स्वीकार करता हूँ कि मुझे इसकी आवश्यकता नहीं थी। मेरे रिपॉजिटरीज़ प्रकाशन के लिए किसी प्रमाणीकरण की आवश्यकता नहीं रखते, और मैं रिलीज़ के लिए हस्ताक्षरित टैग का उपयोग नहीं करता। "क्यों" इस प्रकार है:

  • क्योंकि मैं कर सकता था,
  • क्योंकि यह अच्छा दिखता है (बैज देखा?),
  • क्योंकि इसने मुझे git filter-branch और शेल के साथ प्रयोग करने का बहाना दिया,
  • और क्योंकि यह ब्लॉग के लिए एक और "मैंने इसे स्वयं बनाया" है।

संक्षेप में, यह सिर्फ दिखावे के लिए था, लेकिन जब आप अपने उपकरणों के साथ छेड़छाड़ करते हैं तो यही मज़ेदार है।

उपयोग उदाहरण

# वर्तमान रिपॉजिटरी में प्रारंभिक कॉन्फ़िगरेशन
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# दूसरी मशीन के लिए कुंजी निर्यात करना
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# दूसरी मशीन पर कुंजी आयात करना
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# इतिहास को फिर से लिखना और पुश करना
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

अंतिम विचार

यह स्क्रिप्ट एक छोटी उपयोगिता है, लेकिन इसमें कुछ अच्छे विचार शामिल हैं:

  • क्रिप्टोग्राफ़िक कुंजियों को स्थानीय और रिपॉजिटरी-विशिष्ट रखना,
  • जब तक आप न कहें, वैश्विक कॉन्फ़िगरेशन को कभी न छूना,
  • सरल आयात/निर्यात और इतिहास पुनर्लेखन प्रदान करना,
  • और पूरी प्रक्रिया को एक ब्लॉग पोस्ट में दस्तावेज़ित करना, क्यों नहीं।

यदि आप अपने कमिट में हस्ताक्षर जोड़ने का मन बनाएँ, तो इसे आज़माएँ! और यदि आप सिर्फ स्टाइल के लिए यहाँ हैं, तो वही बात। 😎

✨ AI Generated Article

شرح سكريبت التوقيع SSH

تحليل مساعد توقيع commits SSH ولماذا أردت commits أنيقة.

سكريبت توقيع SSH للـ commits -- شرح

هذا المقال يحلل السكريبت setup-ssh-signing.sh الذي نشرته على Gist. سنرى ما يفعله كل جزء، كيف يجعل التوقيع SSH المحلي لمستودع أمرًا سلسًا تمامًا، ونعم، لماذا تكبدت عناء كتابته (تنبيه: كنت أريد فقط أن تكون لـ commits الخاصة بي شكلاً رائعًا).

الدافع

لطالما أحببت تعديل سير عمل Git الخاص بي، وبعد رؤية أشخاص بشعارات «Verified» صغيرة بجانب commitsهم، قلت في نفسي: لماذا لا أنا؟ التوقيع GPG المدمج ثقيل وعمومي، لذا انتهى بي الأمر بكتابة مساعد صغير يقوم بـ:

  • إنشاء مفتاح SSH مخصص للتوقيع،
  • تكوين المستودع الحالي فقط،
  • إعادة كتابة التاريخ اختياريًا لتوقيع الـ commits القديمة،
  • والسماح بنقل المفتاح بين الأجهزة.

بصراحة، كانت الحاجة للتباهي بشكل أساسي. لا توجد متطلبات تقنية للتوقيع في مشاريعي الشخصية، لكن رؤية شارة خضراء «Verified» على commit يعطي تأثيرًا لطيفًا، وكانت كتابة السكريبت متعة في shell.

حسنًا، توقيع commitsك يشبه ارتداء سترة جلدية لمراجعة كود -- غير ضروري تمامًا، لكنه يجعلك تشعر وكأنك هاكر.

ما يفعله السكريبت

السكريبت هو ملف Bash واحد مع set -euo pipefail في الأعلى ليتوقف بسرعة وبشكل نظيف. إليك ملخص ما يفعله:

  1. توليد أو استيراد مفتاح توقيع
    يتم وضع المفاتيح في .git-signing/ داخل المجلد حيث تشغّل السكريبت.
  2. تكوين Git محليًا
    يضبط gpg.format=ssh وuser.signingkey وcommit.gpgsign=true وtag.gpgSign=true وملف allowedSignersFile يشير إلى المفتاح العام.
  3. إدارة المفاتيح بين الأجهزة
    بفضل --export-keys / --import-keys، يمكنك نقل مفتاحك الخاص من جهاز لآخر دون لمس الإعدادات العامة.
  4. إعادة كتابة التاريخ اختياريًا (--resign-all)
    يعيد كتابة جميع commits كل الفروع/الوسوم (أو فقط تلك غير الموجودة في upstream للـ forks) ويعيد توقيعها باستخدام -S، دون التأثير على المؤلفين الآخرين.
  5. خيارات مساعدة
    --autostash و--autopush و--commit-date و--yes للوضع غير التفاعلي، إلخ.
  6. كشف الـ fork والتحقق الأمني
    يكتشف الـ remote upstream، ويحذر قبل إعادة كتابة التاريخ، ويتحقق من الأدوات المطلوبة (git وssh-keygen وzip/unzip)، ويتأكد من الصلاحيات الصحيحة، بل وينسخ المفتاح بشكل آمن إذا كانت صلاحيات نظام الملفات متساهلة جدًا.

السكريبت متطابق (idempotent): تشغيله مرتين لا يعيد توليد مفتاحك ولا يمسح الإعدادات الموجودة.

الشرح خطوة بخطوة

إليك بعض المقتطفات الرئيسية من الكود مع شروحاتها.

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

الرأس يضع الأمان ويوثق الهدف. الجزء التالي يحلل خيارات CLI (--name و--email و--repo، إلخ) باستخدام حلقة while [[ $# -gt 0 ]]; do case … esac done. يتم التحقق من حقول الهوية الإلزامية لاحقًا:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

توليد المفتاح يتم في $LAUNCH_DIR/.git-signing. إذا كان المفتاح موجودًا بالفعل، يتركه السكريبت كما هو؛ --import-keys يسمح بملء المجلد من ملف ZIP.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

بعد التحقق من أن المفتاح الخاص قابل للاستخدام (ssh-keygen -Y sign …)، يكتب السكريبت ملف allowed_signers صغيرًا يحتوي على المفتاح العام ويضبط إعدادات Git المحلية:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

إذا طلبت إعادة كتابة التاريخ باستخدام --resign-all، يبني السكريبت أمر git filter-branch الذي يعيد توقيع الـ commits المؤهلة بـ -S. يحترم حالة الـ fork بتخطي الـ commits الموجودة بالفعل في upstream اختياريًا.

النتيجة النهائية تعرض المفتاح العام وتعليمات لإضافته في قسم Signing Key على GitHub، مع وصفة اختبار صغيرة.

لماذا توقع commitsك؟

هذه هي اللحظة التي أعترف فيها أنني لم أكن بحاجة لذلك. مستودعاتي لا تتطلب أي إثبات مصدر لما أنشره، ولا أستخدم الوسوم الموقعة للإصدارات. «السبب» هو:

  • لأنني استطعت،
  • لأنها تبدو جيدة (هل رأيت الشارة؟)،
  • لأنها أعطتني عذرًا لأجرب git filter-branch وshell،
  • ولأنها مجرد «لقد بنيت هذا بنفسي» أخرى للمدونة.

باختصار، كان فقط للتباهي، لكن هذا هو الجميل عندما تعدّل أدواتك الخاصة.

أمثلة الاستخدام

# إعداد أولي في المستودع الحالي
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# تصدير المفاتيح لجهاز آخر
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# استيراد المفاتيح على جهاز ثانٍ
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# إعادة كتابة التاريخ والدفع
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

أفكار أخيرة

هذا السكريبت أداة صغيرة، لكنها تحتوي على بعض الأفكار الجميلة:

  • الاحتفاظ بالمفاتيح المشفرة محليًا ولكل مستودع،
  • عدم لمس الإعدادات العامة أبدًا إلا إذا طلبت ذلك،
  • توفير استيراد/تصدير بسيط وإعادة كتابة التاريخ،
  • وتوثيق العملية بأكملها في مقال مدونة، لأنه لم لا.

إذا راودتك الرغبة في إضافة توقيعات إلى commitsك الخاصة، جربه! وإذا كنت هنا فقط من أجل الشكل، نفس الشيء. 😎

✨ AI Generated Article

Script ký commit SSH được giải thích

Phân tích helper ký commit SSH và tại sao tôi muốn commit có phong cách.

Script ký commit SSH -- giải thích chi tiết

Bài viết này phân tích script setup-ssh-signing.sh mà tôi đã đăng trên Gist. Chúng ta sẽ xem từng phần làm gì, cách nó giúp việc ký SSH trong một kho lưu trữ cục bộ trở nên hoàn toàn dễ dàng, và, đúng vậy, tại sao tôi lại mất công viết nó (spoiler: tôi chỉ muốn commit của mình trông ngầu thôi).

Động lực

Tôi luôn thích mày mò workflow Git của mình, và sau khi thấy người khác có huy hiệu « Verified » nhỏ xinh bên cạnh commit, tôi tự nhủ: sao mình không thử nhỉ? Ký GPG tích hợp sẵn thì nặng nề và mang tính toàn cục, nên cuối cùng tôi đã viết một helper nhỏ có thể:

  • tạo một khoá SSH riêng để ký,
  • chỉ cấu hình kho lưu trữ hiện tại,
  • tuỳ chọn viết lại lịch sử để ký các commit cũ,
  • và cho phép mang khoá giữa các máy.

Thú thật, nhu cầu chủ yếu là để làm đẹp. Không có yêu cầu kỹ thuật nào về chữ ký trong các dự án cá nhân của tôi, nhưng thấy một huy hiệu xanh « Verified » trên commit thì cũng oách lắm, và viết script này cũng là một niềm vui với shell.

Ừ thì, ký commit cũng giống như mặc áo khoác da đi review code -- hoàn toàn vô dụng, nhưng làm bạn có cảm giác như một hacker.

Script làm gì

Script là một file Bash duy nhất với set -euo pipefail ở đầu để lỗi là dừng ngay. Đây là tóm tắt những gì nó làm:

  1. Tạo hoặc nhập khoá ký
    Khoá được đặt trong .git-signing/ ở thư mục bạn chạy script.
  2. Cấu hình Git cục bộ
    Nó đặt gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true, và allowedSignersFile trỏ tới khoá công khai.
  3. Quản lý khoá giữa các máy
    Nhờ --export-keys / --import-keys, bạn có thể mang khoá riêng từ máy này sang máy khác mà không cần động tới cấu hình toàn cục.
  4. Viết lại lịch sử tuỳ chọn (--resign-all)
    Viết lại tất cả commit trên mọi nhánh/tag (hoặc chỉ những commit chưa có trong upstream đối với fork) và ký lại bằng -S, mà không ảnh hưởng đến tác giả khác.
  5. Cờ tiện ích
    --autostash, --autopush, --commit-date, --yes cho chế độ không tương tác, v.v.
  6. Phát hiện fork và kiểm tra bảo mật
    Nó phát hiện remote upstream, cảnh báo trước khi viết lại lịch sử, kiểm tra công cụ cần thiết (git, ssh-keygen, zip/unzip), đảm bảo quyền truy cập đúng, và thậm chí tạo bản sao an toàn của khoá nếu quyền filesystem quá thoáng.

Script có tính idempotent: chạy hai lần sẽ không tạo lại khoá hay ghi đè cấu hình hiện có.

Phân tích từng bước

Dưới đây là một số đoạn mã chính kèm giải thích.

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

Phần mở đầu đặt tính bảo mật và ghi lại mục đích. Đoạn tiếp theo phân tích các cờ CLI (--name, --email, --repo, v.v.) bằng vòng lặp while [[ $# -gt 0 ]]; do case … esac done. Các trường định danh bắt buộc được kiểm tra sau:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

Việc tạo khoá diễn ra trong $LAUNCH_DIR/.git-signing. Nếu khoá đã tồn tại, script sẽ để yên; --import-keys cho phép nạp thư mục từ file ZIP.

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

Sau khi xác nhận khoá riêng có thể dùng được (ssh-keygen -Y sign …), script ghi một file allowed_signers nhỏ chứa khoá công khai và đặt cấu hình Git cục bộ:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

Nếu bạn yêu cầu viết lại lịch sử với --resign-all, script xây dựng lệnh git filter-branch để ký lại các commit đủ điều kiện bằng -S. Nó tôn trọng trạng thái fork bằng cách tuỳ chọn bỏ qua các commit đã có trong upstream.

Kết quả cuối cùng hiển thị khoá công khai và hướng dẫn thêm nó vào phần Signing Key trên GitHub, kèm một công thức kiểm thử nhỏ.

Tại sao nên ký commit?

Đây là lúc tôi thú nhận rằng tôi không hề cần nó. Kho lưu trữ của tôi không yêu cầu xác thực nguồn gốc cho những gì tôi xuất bản, và tôi cũng không dùng tag đã ký cho bản phát hành. « Tại sao » là:

  • vì tôi có thể,
  • vì nó đẹp (thấy huy hiệu chưa?),
  • vì nó cho tôi cơ hội để thử nghiệm với git filter-branch và shell,
  • và vì nó là một « tự tay tôi xây dựng » nữa cho blog.

Tóm lại, chỉ để khoe thôi, nhưng đó mới là cái hay khi ta tự mày mò công cụ của mình.

Ví dụ sử dụng

# thiết lập ban đầu trong kho lưu trữ hiện tại
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# xuất khoá sang máy khác
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# nhập khoá trên máy thứ hai
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# viết lại lịch sử và đẩy lên
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

Suy nghĩ cuối cùng

Script này là một tiện ích nhỏ, nhưng nó chứa một vài ý tưởng hay:

  • giữ khoá mật mã cục bộ và theo từng kho lưu trữ,
  • không bao giờ động tới cấu hình toàn cục trừ khi bạn yêu cầu,
  • cung cấp import/export đơn giản và viết lại lịch sử,
  • và ghi lại toàn bộ quá trình trong một bài blog, bởi sao không nhỉ.

Nếu bạn muốn thêm chữ ký vào commit của mình, hãy thử nó! Và nếu bạn chỉ ở đây vì phong cách, cũng vậy luôn. 😎

✨ AI Generated Article

อธิบายสคริปต์เซ็นชื่อ SSH

เจาะลึก helper สำหรับเซ็นชื่อคอมมิต SSH และว่าทำไมฉันถึงอยากได้คอมมิตที่ดูเท่

สคริปต์เซ็นชื่อ SSH สำหรับคอมมิต -- คำอธิบาย

บทความนี้เจาะลึกสคริปต์ setup-ssh-signing.sh ที่ผมเผยแพร่บน Gist เราจะมาดูกันว่าแต่ละส่วนทำอะไร, ทำให้การเซ็นชื่อ SSH เฉพาะพื้นที่ในรีโพสิทอรี่เป็นเรื่องง่ายดาย และ, ใช่แล้ว, ทำไมผมถึงเสียเวลามาเขียนมัน (สปอยเลอร์: ฉันแค่อยากให้คอมมิตของฉันดู เท่)

แรงจูงใจ

ฉันชอบปรับแต่ง Git workflow ของฉันมาตลอด และหลังจากเห็นคนอื่นมีป้าย "Verified" เล็ก ๆ ข้างคอมมิตของพวกเขา ฉันก็เลยคิดว่า: ทำไมฉันไม่ได้ล่ะ? GPG ในตัวมันดูยุ่งยากและเป็นระบบ global ฉันก็เลยเขียน helper เล็ก ๆ ที่:

  • สร้างคีย์ SSH ที่ใช้สำหรับเซ็นชื่อโดยเฉพาะ
  • ตั้งค่าเฉพาะรีโพสิทอรี่ปัจจุบัน
  • เขียนประวัติใหม่เพื่อเซ็นชื่อคอมมิตเก่า (ถ้าต้องการ)
  • และให้คุณสามารถย้ายคีย์ระหว่างเครื่องได้

เอาจริง ๆ ความต้องการหลักคือ vanity ไม่มีข้อกำหนดทางเทคนิคให้ต้องเซ็นชื่อในโปรเจกต์ส่วนตัวของฉัน แต่เห็นป้ายเขียว "Verified" บนคอมมิตมันก็เท่ดี และการเขียนสคริปต์นี้มันสนุกดีเหมือนกัน

ว่าแต่ เซ็นชื่อคอมมิตก็เหมือนใส่แจ็กเก็ตหนังเวลาไปรีวิวโค้ด -- ไร้ประโยชน์โดยสิ้นเชิง แต่ทำให้คุณรู้สึกเหมือนเป็นแฮกเกอร์

สคริปต์ทำอะไร

สคริปต์เป็นไฟล์ Bash เดียวที่มี set -euo pipefail ไว้ข้างบนเพื่อให้หยุดทำงานทันทีเมื่อมีข้อผิดพลาด นี่คือสรุปว่ามันทำอะไร:

  1. สร้างหรือนำเข้าคีย์เซ็นชื่อ
    คีย์ต่าง ๆ จะถูกเก็บใน .git-signing/ ในโฟลเดอร์ที่คุณรันสคริปต์
  2. ตั้งค่า Git ในเครื่อง
    มันจะตั้งค่า gpg.format=ssh, user.signingkey, commit.gpgsign=true, tag.gpgSign=true, และ allowedSignersFile ที่ชี้ไปยังคีย์สาธารณะ
  3. จัดการคีย์ระหว่างเครื่อง
    ด้วย --export-keys / --import-keys คุณสามารถย้ายคีย์ส่วนตัวจากเครื่องหนึ่งไปอีกเครื่องหนึ่งได้โดยไม่ต้องแตะ config global
  4. เขียนประวัติใหม่ (optional) (--resign-all)
    เขียนคอมมิตทั้งหมดในทุก branch/tag (หรือเฉพาะที่ไม่ได้อยู่ใน upstream สำหรับ fork) และเซ็นชื่อใหม่ด้วย -S โดยไม่กระทบผู้แต่งคนอื่น
  5. Flags อำนวยความสะดวก
    --autostash, --autopush, --commit-date, --yes สำหรับโหมดไม่ต้องยืนยัน ฯลฯ
  6. การตรวจจับ fork และตรวจสอบความปลอดภัย
    มันตรวจจับ remote upstream, เตือนก่อนเขียนประวัติใหม่, ตรวจสอบเครื่องมือที่จำเป็น (git, ssh-keygen, zip/unzip), ตรวจสอบสิทธิ์ที่ถูกต้อง, และสร้างสำเนาคีย์ที่ปลอดภัยถ้าสิทธิ์ของ filesystem เปิดกว้างเกินไป

สคริปต์เป็น idempotent: รันสองครั้งจะไม่สร้างคีย์ใหม่หรือทับการตั้งค่าที่มีอยู่

ทีละขั้นตอน

นี่คือบางส่วนสำคัญของโค้ดพร้อมคำอธิบาย

#!/usr/bin/env bash
set -euo pipefail

# Configure SSH commit signing in a controlled, repo-local way.
# - Key files are created in the directory where this script is launched.
# - Git config is written locally to the current repository only.

ส่วนหัวกำหนดความปลอดภัยและอธิบายวัตถุประสงค์ ส่วนถัดไปแยกวิเคราะห์ตัวเลือก CLI (--name, --email, --repo, ฯลฯ) ด้วยลูป while [[ $# -gt 0 ]]; do case … esac done ฟิลด์ข้อมูลประจำตัวที่จำเป็นจะถูกตรวจสอบในภายหลัง:

if [[ -z "$NAME" || -z "$EMAIL" ]]; then
  echo "Error: missing identity. Provide --name and --email." >&2
  exit 1
fi

การสร้างคีย์จะทำใน $LAUNCH_DIR/.git-signing ถ้ามีคีย์อยู่แล้ว สคริปต์จะไม่แตะมัน; --import-keys จะใช้เติมโฟลเดอร์จาก ZIP

mkdir -p "$KEY_DIR"

if [[ -n "$IMPORT_ZIP_PATH" ]]; then
  import_keys_from_zip "$IMPORT_ZIP_PATH"
fi

if [[ ! -f "$KEY_PATH" ]]; then
  ssh-keygen -t ed25519 -N "" -C "$EMAIL signing key" -f "$KEY_PATH" >/dev/null
  echo "Generated signing key: $KEY_PATH"
else
  echo "Signing key already exists: $KEY_PATH"
fi

หลังจากตรวจสอบว่าคีย์ส่วนตัวใช้งานได้ (ssh-keygen -Y sign …) สคริปต์จะเขียนไฟล์ allowed_signers เล็ก ๆ ที่มีคีย์สาธารณะ และตั้งค่า Git config ในเครื่อง:

git -C "$REPO_DIR" config --local gpg.format ssh
git -C "$REPO_DIR" config --local user.signingkey "$RUNTIME_KEY_PATH"
git -C "$REPO_DIR" config --local gpg.ssh.allowedSignersFile "$ALLOWED_SIGNERS"
git -C "$REPO_DIR" config --local commit.gpgsign true
git -C "$REPO_DIR" config --local tag.gpgSign true

ถ้าคุณขอเขียนประวัติใหม่ด้วย --resign-all สคริปต์จะสร้างคำสั่ง git filter-branch ที่เซ็นชื่อคอมมิตที่เข้าเงื่อนไขอีกครั้งด้วย -S มันคำนึงถึงสถานะ fork โดยข้ามคอมมิตที่อยู่ใน upstream แล้ว (ถ้าต้องการ)

ผลลัพธ์สุดท้ายจะแสดงคีย์สาธารณะและคำแนะนำในการเพิ่มมันในส่วน Signing Key ของ GitHub พร้อมคำสั่งทดสอบ

ทำไมต้องเซ็นชื่อคอมมิต?

นี่คือตอนที่ฉันสารภาพว่าฉันไม่จำเป็นต้องทำเลย รีโพสิทอรี่ของฉันไม่มีข้อกำหนดเรื่องแหล่งที่มาสำหรับสิ่งที่ฉันเผยแพร่ และผมไม่ได้ใช้แท็กเซ็นชื่อสำหรับรีลีส "ทำไม" ก็คือ:

  • เพราะฉันทำได้
  • เพราะมันดูดี (เห็นป้ายนั่นไหม?)
  • เพราะมันเป็นข้ออ้างให้ฉันได้ลองเล่น git filter-branch และ shell
  • และเพราะมันเป็นอีกหนึ่ง "ฉันสร้างของสิ่งนี้เอง" สำหรับบล็อก

สรุปคือ แค่จะอวด แต่ที่สนุกคือตอนได้ปรับแต่งเครื่องมือของตัวเอง

ตัวอย่างการใช้งาน

# ตั้งค่าเริ่มต้นในรีโพสิทอรี่ปัจจุบัน
chmod +x ./setup-ssh-signing.sh
./setup-ssh-signing.sh --name "Your Name" \
                       --email "[email protected]"

# ส่งออกคีย์สำหรับเครื่องอื่น
./setup-ssh-signing.sh --export-keys ./my-signing-keys.zip

# นำเข้าคีย์บนเครื่องที่สอง
./setup-ssh-signing.sh --import-keys ./my-signing-keys.zip --repo ./my-repo \
                       --name "Your Name" --email "[email protected]"

# เขียนประวัติใหม่และพุช
./setup-ssh-signing.sh --repo ./my-repo --name "Your Name" --email "[email protected]" \
                       --resign-all --autostash --autopush --yes

ความคิดสุดท้าย

สคริปต์นี้เป็นยูทิลิตี้เล็ก ๆ แต่มีไอเดียเจ๋ง ๆ อยู่บ้าง:

  • เก็บคีย์เข้ารหัสในเครื่องแยกตามรีโพสิทอรี่
  • ไม่แตะ config global เลยยกเว้นคุณขอ
  • มี import/export ง่าย ๆ และเขียนประวัติใหม่
  • และบันทึกกระบวนการทั้งหมดในบทความบล็อก เผื่อไว้ก็ดี

ถ้าอยากลองเพิ่มเซ็นชื่อให้คอมมิตของคุณ ลองดูสิ! และถ้าคุณแค่เข้ามาเพราะสไตล์ ก็เหมือนกัน 😎

Related Articles