<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>posts on blog.csanaadb.com</title><link>https://blog.csanaadb.com/posts/</link><description>Recent content in posts on blog.csanaadb.com</description><generator>Hugo</generator><language>en</language><lastBuildDate>Tue, 29 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.csanaadb.com/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Publishing a rotated GPG signing subkey to GitHub through the API</title><link>https://blog.csanaadb.com/posts/github-api-signing-keys/</link><pubDate>Tue, 29 Sep 2026 00:00:00 +0000</pubDate><guid>https://blog.csanaadb.com/posts/github-api-signing-keys/</guid><description>&lt;h1 id="publishing-a-rotated-gpg-signing-subkey-to-github-through-the-api"&gt;Publishing a rotated GPG signing subkey to GitHub through the API&lt;/h1&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;&#10;&lt;p&gt;In this article we will explore how we can make it easier to rotate keys we use for signing commits, using the GitHub API.&lt;/p&gt;&#10;&lt;h2 id="why-upload-the-signing-key-to-github"&gt;Why upload the signing key to GitHub&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Signing works without GitHub: the signature is in the commit or tag, and anyone with the public key can check it locally with &lt;code&gt;git tag --verify&lt;/code&gt; or &lt;code&gt;git log --show-signature&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;Without the key on the account, GitHub shows signed commits as &amp;ldquo;Unverified&amp;rdquo;: &amp;ldquo;The commit is signed but the signature could not be verified.&amp;rdquo;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;&#10;&lt;li&gt;A branch that requires signed commits rejects them: &amp;ldquo;contributors and bots can only push commits that have been signed and verified to the branch&amp;rdquo;.&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;&#10;&lt;li&gt;An uploaded key is published in 1 fixed place tied to the account, readable without logging in: &lt;code&gt;/users/&amp;lt;username&amp;gt;/ssh_signing_keys&lt;/code&gt; or &lt;code&gt;/users/&amp;lt;username&amp;gt;/gpg_keys&lt;/code&gt; (see the next section).&lt;/li&gt;&#10;&lt;li&gt;Unsigned commits show no status, unless vigilant mode is on, which marks them &amp;ldquo;Unverified&amp;rdquo; too.&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="where-others-find-the-key"&gt;Where others find the key&lt;/h2&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;Anyone can list an account&amp;rsquo;s public SSH signing keys without logging in:&lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl --silent https://api.github.com/users/&amp;lt;username&amp;gt;/ssh_signing_keys&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;The same for GPG keys:&lt;sup id="fnref:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl --silent https://api.github.com/users/&amp;lt;username&amp;gt;/gpg_keys&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;The GPG keys in armored form, ready for &lt;code&gt;gpg --import&lt;/code&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl --silent https://github.com/&amp;lt;username&amp;gt;.gpg&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ol&gt;</description></item></channel></rss>