<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://heaths.dev/feed.xml" rel="self" type="application/atom+xml"/><link href="https://heaths.dev/" rel="alternate" type="text/html"/><updated>2026-04-21T20:36:19+00:00</updated><id>https://heaths.dev/feed.xml</id><title type="html">Heath Stewart’s Blog</title><subtitle>Technical posts about my decades-long experience with installation, current news and information about my current role in Azure, and tips and tricks I&apos;ve picked up along the way. Occasionally about my backpacking and mountaineering adventures with friends and family.</subtitle><author><name>Heath Stewart</name></author><entry><title type="html">Light and dark themes for my blog</title><link href="https://heaths.dev/general/2026/04/20/light-and-dark-themes-for-my-blog.html" rel="alternate" type="text/html" title="Light and dark themes for my blog"/><published>2026-04-20T06:48:45+00:00</published><updated>2026-04-20T06:48:45+00:00</updated><id>https://heaths.dev/general/2026/04/20/light-and-dark-themes-for-my-blog</id><content type="html" xml:base="https://heaths.dev/general/2026/04/20/light-and-dark-themes-for-my-blog.html"><![CDATA[<p><img src="/assets/images/kraken-theme.jpg" alt="A blog page shown in both light and dark themes side by side, using the Seattle Kraken color palette"/></p> <p>My posts will always be written by me, a human, sharing tips, personal news, and more. And though I started writing web sites before HTML 1.0 was formally standardized, I’ve never been good at design. My blog used Jekyll Minima with a few overrides and I only recently updated it to 2.5, but was envious of the theming that 3.0 has in development. Though I really haven’t touched much CSS since shortly after 2.0 was released, I knew the mechanics but wanted a little help prototyping some ideas quickly.</p> <h2 id="trying-out-themes"><a href="#trying-out-themes"></a>Trying out themes</h2> <p>It probably wasn’t obvious, but my previous color palette used Seahawks colors. I wanted to see what mixing those colors or other colors might look like for light and dark themes. With some links to the color palettes I was considering - but haven’t necessarily settled on for the foreseeable future - asked Copilot with Sonnet 4.6 to render a few. It didn’t take long - certainly faster than I’d have done it - and I was able to select a theme as a start quickly. I made a few tweaks and had it apply the changes with some color mapping instructions from the old palette.</p> <p>Having been to several of their games with my son - who loves hockey - and my wife - who merely tolerated it but got a selfie with Buoy - I choose a Kraken color palette. They put on one heck of a show at Climate Pledge Arena.</p> <p>It took a few iterations to iron out the kinks. I would verify the responsive site in Safari’s dev tools and batch several changes with explicit instructions. As with any time I use an LLM to generate code, I review and recommend changes as needed.</p> <h2 id="theme-switcher-and-responsive-fixes"><a href="#theme-switcher-and-responsive-fixes"></a>Theme switcher and responsive fixes</h2> <p>With separate light and dark themes, I next had it lay the ground work to switch themes and fix some responsive issues, like certain buttons being too long on mobile viewports so I’d change the text to “Subscribe” instead of “Subscribe on Sequoia” in the <code class="language-plaintext highlighter-rouge">sequoia-subscribe</code> component. Again, with a carefully crafted prompt, it didn’t take long to generate the necessary changes that’d probably have taken me a couple hours.</p> <p>With all changes reviewed and tested, I finally had a properly responsive and themed web site I’ve been wanting but just haven’t found the time.</p>]]></content><author><name>{&quot;twitter&quot;=&gt;&quot;mrhestew&quot;, &quot;picture&quot;=&gt;&quot;/assets/images/headshot.jpg&quot;}</name></author><category term="general"/><category term="blog"/><category term="copilot"/><category term="css"/><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://heaths.dev/assets/images/kraken-theme.jpg"/><media:content medium="image" url="https://heaths.dev/assets/images/kraken-theme.jpg" xmlns:media="http://search.yahoo.com/mrss/"/></entry><entry><title type="html">We all make mistakes</title><link href="https://heaths.dev/general/2026/04/18/we-all-make-mistakes.html" rel="alternate" type="text/html" title="We all make mistakes"/><published>2026-04-18T07:24:41+00:00</published><updated>2026-04-18T07:24:41+00:00</updated><id>https://heaths.dev/general/2026/04/18/we-all-make-mistakes</id><content type="html" xml:base="https://heaths.dev/general/2026/04/18/we-all-make-mistakes.html"><![CDATA[<p>After 15 years in Visual Studio and having shipped a few versions of the new setup engine I architected as a senior engineer at Microsoft, it was time for a change. I was a few weeks into my new job on the Azure SDK for .NET team as, among other responsibilities, the technical lead on the Key Vault SDK virtual team.</p> <p>I was also working on an idea for <a href="https://github.com/Azure/azure-sdk-for-net/blob/941cc979bf7b36cb9592888d8397f23b2b10f5bd/eng/common/TestResources/README.md">unified test resource provisioning</a> across SDKs and languages and was working with a couple different vaults in the Azure Portal: our test secrets used by all the languages, and one I had just created for some tests. Certain I had the right one selected, I was prompted <strong>Are you sure you want to delete this vault?</strong> with just <strong>Yes</strong> and <strong>No</strong> buttons, and clicked <strong>Yes</strong>.</p> <p>I was wrong.</p> <p>I deleted the shared test secrets used by Azure Pipelines and more.</p> <p>Within seconds I realized my mistake, hurried down the hall to our engineering systems team room, and echoed <a href="https://en.wikipedia.org/wiki/George_Oscar_Bluth_II">Gob Bluth</a>’s famous line, “I’ve made a huge mistake.”</p> <p>Not the best start on a new team, but what happened next is what I like to share with mentees both junior and senior.</p> <h2 id="driving-change"><a href="#driving-change"></a>Driving change</h2> <p>In the short term, we needed to restore functionality. Soft delete wasn’t enabled on the vault, so the vault was truly gone. But across all the developers, we all had enough secrets in process or machine environment variables<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup> that we could restore most of the secrets. Others we just had to regenerate and deal with as problems arose.</p> <p>In the long term, I wanted to make sure something so vital - think about a company losing production secrets on which their business depends - didn’t happen again, or at least wasn’t so easy.</p> <p>I had already developed a pretty good rapport with the Key Vault service team, and worked with them on some changes:</p> <ol> <li>The name of the vault wasn’t part of the original prompt. They added the name of the vault and changed the buttons to more descriptive <strong>Delete</strong> and <strong>Cancel</strong>.</li> <li> <p>They moved up plans to enable soft delete by default. After that change, you had to explicitly disable soft delete. Seems many customers weren’t aware of soft delete, which allows you to recover a deleted vault or vault resource for a configured number of days - the default being 90 days.</p> <p>Eventually, a change was made such that soft delete couldn’t be disabled, and purge protection could be enabled that prevented a deleted vault or vault resource from being purged for the configured number of days.</p> </li> </ol> <h2 id="final-thoughts"><a href="#final-thoughts"></a>Final thoughts</h2> <p>We all make mistakes. I was a senior at the time and not long after that was promoted to a principal engineer. I still make mistakes - perhaps not as bad and hopefully won’t - but how we deal with them and learn from them is what matters.</p> <p>Own up to the mistake and try to prevent them from happening again or to anyone else, if relevant. Seek out partners to brainstorm ideas and show a growth mindset among your peers and management. They’ve all made mistakes too.</p> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:1"> <p>We later changed how authentication was done and moved non-secrets into normal configuration variables. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div>]]></content><author><name>{&quot;twitter&quot;=&gt;&quot;mrhestew&quot;, &quot;picture&quot;=&gt;&quot;/assets/images/headshot.jpg&quot;}</name></author><category term="general"/><category term="about"/><category term="azure"/><category term="mentoring"/><category term="story"/><summary type="html"><![CDATA[After 15 years in Visual Studio and having shipped a few versions of the new setup engine I architected as a senior engineer at Microsoft, it was time for a change. I was a few weeks into my new job on the Azure SDK for .NET team as, among other responsibilities, the technical lead on the Key Vault SDK virtual team.]]></summary></entry><entry><title type="html">Making the key version required for Key Vault cryptography APIs</title><link href="https://heaths.dev/azure/2026/04/08/making-the-key-version-required-for-key-vault-cryptography-apis.html" rel="alternate" type="text/html" title="Making the key version required for Key Vault cryptography APIs"/><published>2026-04-08T05:32:00+00:00</published><updated>2026-04-08T05:32:00+00:00</updated><id>https://heaths.dev/azure/2026/04/08/making-the-key-version-required-for-key-vault-cryptography-apis</id><content type="html" xml:base="https://heaths.dev/azure/2026/04/08/making-the-key-version-required-for-key-vault-cryptography-apis.html"><![CDATA[<p>When I started on the Azure SDK team almost 7 years ago, I immediately jumped into the Azure Key Vault SDK for .NET among other responsibilities. We already had a pretty good codebase as a start lead by a former colleague who worked in Azure Key Vault prior to joining the Azure SDK team.</p> <p>Since the Key Vault service allowed an empty string for the key version for all endpoints, the KV SDKs across all languages back then - <a href="https://github.com/Azure/azure-sdk-for-net">.NET</a>, <a href="https://github.com/Azure/azure-sdk-for-java">Java</a>, <a href="https://github.com/Azure/azure-sdk-for-js">JavaScript/TypeScript</a>, and <a href="https://github.com/Azure/azure-sdk-for-python">Python</a> - we made the key version parameters in all those languages optional even though they didn’t all technically follow language guidelines for optional parameters: optional parameters go into “options bags” - an optional parameter that had a bunch of optional properties on it or, for pythonistas, <code class="language-plaintext highlighter-rouge">kwargs</code>.</p> <p>For key data operations that generally fine: an empty version means you act on the latest key version; however, for cryptography operations - encrypt, decrypt, sign, verify, wrap, and unwrap - that can inadvertently lock you out of your data. For example, if you encrypt with key version 1 and that key is rotated to version 2, you won’t be able to decrypt with version 2. You can work around this by cycling through key versions, but knowing when you found the right one isn’t always easy if you don’t know the plaintext. This is compounded when unwrapping a symmetric key because the key length is the same and, in some block ciphers, will decrypt into plaintext you can’t always validate.</p> <h2 id="required-for-rust"><a href="#required-for-rust"></a>Required for Rust</h2> <p>Since I’m the architect for the <a href="https://github.com/Azure/azure-sdk-for-rust">Azure SDK for Rust</a>, have much more experience with Azure Key Vault now, and have been working on the Key Vault SDKs for Rust, after having talked with the Key Vault service team about it, we made the key version parameter required for cryptography operations. Not only does this mean the version parameters actually follow <a href="https://azure.github.io/azure-sdk/rust_introduction.html#rust-client-methods">language guidelines</a>, but that they steer customers into the pit of success. You can still pass an empty string <code class="language-plaintext highlighter-rouge">""</code> to use the latest version but it’s not recommended.</p> <p>I’ve <a href="https://github.com/heaths/akv-cli-rs/pull/111">updated</a> the <a href="https://github.com/heaths/akv-cli-rs">akv CLI</a> accordingly to require the key version for the <code class="language-plaintext highlighter-rouge">encrypt</code> command, whether passed to <code class="language-plaintext highlighter-rouge">--version</code> or (new) passed as a key URI with version.</p> <p>Hopefully by requiring a key version for crypto functions, customers will be less likely to accidentally lock themselves out of their encrypted data.</p>]]></content><author><name>{&quot;twitter&quot;=&gt;&quot;mrhestew&quot;, &quot;picture&quot;=&gt;&quot;/assets/images/headshot.jpg&quot;}</name></author><category term="azure"/><category term="azure"/><category term="cryptography"/><category term="keyvault"/><category term="rustlang"/><summary type="html"><![CDATA[When I started on the Azure SDK team almost 7 years ago, I immediately jumped into the Azure Key Vault SDK for .NET among other responsibilities. We already had a pretty good codebase as a start lead by a former colleague who worked in Azure Key Vault prior to joining the Azure SDK team.]]></summary></entry><entry><title type="html">Cleaning up Rust made easier</title><link href="https://heaths.dev/rust/2026/03/21/cleaning-up-rust-made-easier.html" rel="alternate" type="text/html" title="Cleaning up Rust made easier"/><published>2026-03-21T06:14:00+00:00</published><updated>2026-03-21T06:14:00+00:00</updated><id>https://heaths.dev/rust/2026/03/21/cleaning-up-rust-made-easier</id><content type="html" xml:base="https://heaths.dev/rust/2026/03/21/cleaning-up-rust-made-easier.html"><![CDATA[<p>WSL distributions are installed into VHDX files that, by default, automatically expand up to the amount of drive space on which they are stored - your system drive, by default. Some toolchains like Rust tend to fill up that space pretty quickly. If you don’t delete older dependencies from <code class="language-plaintext highlighter-rouge">~/.cargo</code> often or keep <code class="language-plaintext highlighter-rouge">targets/</code> for a long time across multiple toolchain versions or target architectures, that space will fill up quickly.</p> <p>Using <a href="https://crates.io/crates/cargo-cache"><code class="language-plaintext highlighter-rouge">cargo-cache</code></a> as I <a href="/rust/2025/03/01/cleaning-up-rust.html">described previously</a> can help clean up old dependencies, and you can delete all <code class="language-plaintext highlighter-rouge">targets/</code> from repos under some directory like so:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find <span class="nt">-maxdepth</span> 2 <span class="nt">-name</span> targets <span class="nt">-execdir</span> <span class="nb">rm</span> <span class="nt">-rf</span> <span class="o">{}</span> <span class="se">\;</span>
</code></pre></div></div> <p>After that and cleaning up any other files you don’t need, log out of all your WSL sessions, close down Visual Studio Code if you have it running and connected to WSL e.g., if you started <code class="language-plaintext highlighter-rouge">code</code> from within WSL, and shut down WSL:</p> <div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">wsl</span><span class="w"> </span><span class="nt">--shutdown</span><span class="w">
</span></code></pre></div></div> <p>Now for the easier part: find the VHDX for your distro and shrink it all from within PowerShell:</p> <div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Replace "Ubuntu-24.04" with your distro name</span><span class="w">
</span><span class="nv">$path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">Get-ChildItem</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nx">HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss</span><span class="w"> </span><span class="se">`
</span><span class="w">  </span><span class="o">|</span><span class="w"> </span><span class="n">Where-Object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">GetValue</span><span class="p">(</span><span class="s2">"DistributionName"</span><span class="p">)</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="s1">'Ubuntu-24.04'</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="se">`</span><span class="w">
  </span><span class="p">)</span><span class="o">.</span><span class="nf">GetValue</span><span class="p">(</span><span class="s2">"BasePath"</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"\ext4.vhdx"</span><span class="w">
</span><span class="n">Optimize-VHDX</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nv">$path</span><span class="w">
</span></code></pre></div></div> <p>It may take a while, but after it completes you can log back into your distro. Seems WSL changed it so you don’t have to run <code class="language-plaintext highlighter-rouge">resize2fs</code> anymore - Ubuntu 24.04, at least, automatically picked up that more space was available.</p>]]></content><author><name>{&quot;twitter&quot;=&gt;&quot;mrhestew&quot;, &quot;picture&quot;=&gt;&quot;/assets/images/headshot.jpg&quot;}</name></author><category term="rust"/><category term="rustlang"/><category term="tips"/><category term="wsl"/><summary type="html"><![CDATA[WSL distributions are installed into VHDX files that, by default, automatically expand up to the amount of drive space on which they are stored - your system drive, by default. Some toolchains like Rust tend to fill up that space pretty quickly. If you don’t delete older dependencies from ~/.cargo often or keep targets/ for a long time across multiple toolchain versions or target architectures, that space will fill up quickly.]]></summary></entry><entry><title type="html">Publishing to the ATmosphere</title><link href="https://heaths.dev/atproto/2026/02/21/publishing-to-the-atmosphere.html" rel="alternate" type="text/html" title="Publishing to the ATmosphere"/><published>2026-02-21T04:00:00+00:00</published><updated>2026-02-21T04:00:00+00:00</updated><id>https://heaths.dev/atproto/2026/02/21/publishing-to-the-atmosphere</id><content type="html" xml:base="https://heaths.dev/atproto/2026/02/21/publishing-to-the-atmosphere.html"><![CDATA[<p>I’ve been reading a lot about <a href="https://atproto.com">ATProto</a> and following many accounts on <a href="https://bsky.app">Bluesky</a> like <a href="https://threddyrex.org">@threddyrex.org</a> with interest. I had been following <a href="https://standard.site">standard.site</a> as well and started thinking about how I might publish records using its lexicon to my hosted PDS. Then I discovered <a href="https://sequoia.pub">Sequoia</a>!</p> <p>It’s a CLI that works with various static-site generators to publish records into your PDS - something I was just starting to think how I wanted to tackle it. This CLI is a good start, so I’m happy to try it out, file bugs, and even submit pull requests!</p> <p>This post, if all is set up correctly, should be the first post published to the ATmosphere.</p>]]></content><author><name>{&quot;twitter&quot;=&gt;&quot;mrhestew&quot;, &quot;picture&quot;=&gt;&quot;/assets/images/headshot.jpg&quot;}</name></author><category term="atproto"/><category term="atproto"/><category term="jekyll"/><summary type="html"><![CDATA[I’ve been reading a lot about ATProto and following many accounts on Bluesky like @threddyrex.org with interest. I had been following standard.site as well and started thinking about how I might publish records using its lexicon to my hosted PDS. Then I discovered Sequoia!]]></summary></entry><entry><title type="html">Cross-compiling x64 on Aarch64</title><link href="https://heaths.dev/rust/2025/05/11/cross-compiling-x64-on-aarch64.html" rel="alternate" type="text/html" title="Cross-compiling x64 on Aarch64"/><published>2025-05-11T01:39:18+00:00</published><updated>2025-05-11T01:39:18+00:00</updated><id>https://heaths.dev/rust/2025/05/11/cross-compiling-x64-on-aarch64</id><content type="html" xml:base="https://heaths.dev/rust/2025/05/11/cross-compiling-x64-on-aarch64.html"><![CDATA[<p>Cross-compiling in Rust is generally pretty easy:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rustup target add x86_64-unknown-linux-gnu
cargo build <span class="nt">--target</span> x86_64-unknown-linux-gnu
</code></pre></div></div> <p>Of course, the targets’ compiler, headers, and libraries need to be available, but a typical install of <a href="https://www.visualstudio.com">Visual Studio</a> or gcc will support common targets. But on my new work Surface Laptop 7 arm64 I needed to compile <code class="language-plaintext highlighter-rouge">openssl-sys</code> for <a href="https://github.com/heaths/akv-cli-rs">my a project</a> and that’s when the fun began:</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>error: failed to run custom build command for `openssl-sys v0.9.102`

----- SNIP ---8&lt;
  cargo:rerun-if-env-changed=OPENSSL_DIR
  OPENSSL_DIR unset
</code></pre></div></div> <p>While there are lots of ways of getting the bits I need - like compiling source myself or downloading and extracting files to the right locations - I like the convenience of a package manager especially when it comes to installing updates. But I’m running Ubuntu 24.04 aarch64, so how do I install packages for amd64 e.g., <code class="language-plaintext highlighter-rouge">libssl-dev:amd64</code>?</p> <h2 id="configuring-sources"><a href="#configuring-sources"></a>Configuring sources</h2> <p>While I’ve had some experience managing debian package repositories e.g., in <code class="language-plaintext highlighter-rouge">/etc/apt/</code> I’ve never before had need to try to install packages for other architectures. I wasn’t even entirely sure it was supported, but a quick search got me started:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>dpkg <span class="nt">--add-architecture</span> amd64
<span class="nb">sudo </span>apt update
</code></pre></div></div> <p>But updating the package index failed: I was getting several 404s because packages weren’t available on <a href="http://ports.ubuntu.com/ubuntu-ports/">http://ports.ubuntu.com/ubuntu-ports/</a>. I was also only familiar with the one-line format and not this new format I was seeing, which `man 5 sources.list tells me is DEP822-style.</p> <p>After reading <code class="language-plaintext highlighter-rouge">sources.list(5)</code> and a bit of trial and error, I ended up with the following <code class="language-plaintext highlighter-rouge">/etc/apt/sources.list.d/ubuntu.sources</code></p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Types: deb
URIs: http://ports.ubuntu.com/ubuntu-ports/
Suites: noble noble-updates noble-backports
Components: main universe restricted multiverse
Architectures: arm64
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

Types: deb
URIs: http://archive.ubuntu.com/ubuntu/
Suites: noble noble-updates noble-backports
Components: main universe restricted multiverse
Architectures: amd64
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

Types: deb
URIs: http://ports.ubuntu.com/ubuntu-ports/
Suites: noble-security
Components: main universe restricted multiverse
Architectures: arm64
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

Types: deb
URIs: http://archive.ubuntu.com/ubuntu/
Suites: noble-security
Components: main universe restricted multiverse
Architectures: amd64
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
</code></pre></div></div> <h2 id="installing-packages"><a href="#installing-packages"></a>Installing packages</h2> <p>After a quick and finally successful <code class="language-plaintext highlighter-rouge">sudo apt update</code>, I was able to install packages:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">--yes</span> libssl-dev:amd64
</code></pre></div></div> <p>I was able to get further with my original goal of compiling <code class="language-plaintext highlighter-rouge">openssl-sys</code>, but then got an error about no linker available. I installed <code class="language-plaintext highlighter-rouge">gcc:amd64</code> and almost able to compile my crate, but the linker failed so I needed to specify the linker explicitly in <code class="language-plaintext highlighter-rouge">.cargo/config.toml</code>:</p> <div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">[</span><span class="n">tageet</span><span class="k">.</span><span class="n">aarch64-unknown-linux-gnu</span><span class="k">]</span>
<span class="n">linker</span> <span class="o">=</span><span class="w"> </span><span class="s">"aarch64-linux-gnu-gcc"</span>

<span class="k">[</span><span class="n">target</span><span class="k">.</span><span class="n">x86_64-unknown-linux-gnu</span><span class="k">]</span>
<span class="n">linker</span> <span class="o">=</span><span class="w"> </span><span class="s">"x86_64-linux-gnu-gcc"</span>
</code></pre></div></div> <p>Success! …well, almost.</p> <p>When I tried a normal build e.g., <code class="language-plaintext highlighter-rouge">cargo build</code> I got pages full of compiler errors. Turns out, when I installed <code class="language-plaintext highlighter-rouge">gcc:amd64</code> it replace a few components, since <code class="language-plaintext highlighter-rouge">apt list --installed *gcc</code> showed <code class="language-plaintext highlighter-rouge">gcc-13-aarch64-linux-gnu</code> was now removable.</p> <p>After a quick search - there’s plenty of information of people wanting to cross-compile for aarch64 on amd64 - I realized I need to install a few packages at once, to effectively make sure all the right symlinks are created. I could’ve done this manually, but figured there were a number of executables I’d need to fix and would rather just let <code class="language-plaintext highlighter-rouge">apt</code> handle it:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">--yes</span> gcc-13 gcc-13-aarch64-linux-gnu gcc-13-x86-64-linux-gnu
<span class="nb">sudo ln</span> <span class="nt">-s</span> /usr/bin/x86_64-linux-gnu-gcc /usr/bin/x86_64-linux-gnu-gcc-13
</code></pre></div></div> <p>The last line was just for convenience, which <code class="language-plaintext highlighter-rouge">apt</code> did for <code class="language-plaintext highlighter-rouge">aarch64-linux-gnu-gcc</code> and, originally, when I installed <code class="language-plaintext highlighter-rouge">gcc-13-x86-64-linux-gnu</code> standalone.</p> <h2 id="cross-compiling-for-openssl-sys"><a href="#cross-compiling-for-openssl-sys"></a>Cross-compiling for openssl-sys</h2> <p>I was finally able to cross-compile <code class="language-plaintext highlighter-rouge">openssl-sys</code>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cargo build
<span class="nv">PKG_CONFIG_SYSROOT_DIR</span><span class="o">=</span>/usr/lib/x86_64-linux-gnu cargo build <span class="nt">--target</span> x86_64-unknown-linux-gnu
</code></pre></div></div>]]></content><author><name>{&quot;twitter&quot;=&gt;&quot;mrhestew&quot;, &quot;picture&quot;=&gt;&quot;/assets/images/headshot.jpg&quot;}</name></author><category term="rust"/><category term="gcc"/><category term="rustlang"/><category term="tips"/><category term="wsl"/><summary type="html"><![CDATA[Cross-compiling in Rust is generally pretty easy:]]></summary></entry><entry><title type="html">Cleaning up Rust</title><link href="https://heaths.dev/rust/2025/03/01/cleaning-up-rust.html" rel="alternate" type="text/html" title="Cleaning up Rust"/><published>2025-03-01T05:10:00+00:00</published><updated>2025-03-01T05:10:00+00:00</updated><id>https://heaths.dev/rust/2025/03/01/cleaning-up-rust</id><content type="html" xml:base="https://heaths.dev/rust/2025/03/01/cleaning-up-rust.html"><![CDATA[<p>I’m the lead developer on the <a href="https://github.com/Azure/azure-sdk-for-rust">Azure SDK for Rust</a> and have been working on it for a few years now. I also started or contribute to a number of other <a href="https://www.rust-lang.org">Rust</a> projects. With all the different crates and numerous versions of the same crate names, a lot of drive space is lost to downloaded crates and cloned - but shallow - repos. When I switch branches that might use different versions or features of crates, it also uses a lot of drive space.</p> <p>Fortunately, cleaning up all that Rust doesn’t require WD-40 and a little elbow grease. Here are a few tips:</p> <ol> <li> <p>Use <a href="https://crates.io/crates/cargo-cache">cargo-cache</a> to view information about and clean up the cargo cache:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cargo <span class="nb">install </span>cargo-cache
cargo cache <span class="nt">--info</span>
cargo cache <span class="nt">--help</span>
</code></pre></div> </div> <p>It hasn’t been updated in a while, but seems to work quite well.</p> </li> <li> <p>Delete your <code class="language-plaintext highlighter-rouge">target/</code> directory. Generally, most of the time building is spent acquiring crates anyway, but this can typically save you a lot of space, especially if you’ve been working in a repo for a while and dependencies have changed frequently.</p> </li> </ol> <h2 id="wsl"><a href="#wsl"></a>WSL</h2> <p>This can be even more problematic when working in Windows Subsystem for Linux (WSL), since the virtual hard disk (VHDX) used to default to 256GB then later 512GB, and currently 1TB. Note, however, this is only the maximum size the VHDX sees as the maximum space. Depending on your physical drive space availability, it may be less.</p> <p>In my case, recently, my old WSL Ubuntu-22.04 image thought it ran out because it only saw 256GB. Most of that was consumed by Rust and Go. You can view space using <code class="language-plaintext highlighter-rouge">du</code> from within WSL like so:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">du</span> <span class="nt">-hd1</span> <span class="nt">-t1gb</span> <span class="nb">.</span>
</code></pre></div></div> <p>If deleting repos’ <code class="language-plaintext highlighter-rouge">target/</code> directories didn’t free enough space, you can <a href="https://learn.microsoft.com/windows/wsl/disk-space">resize your VHDX</a> from an elevated shell:</p> <div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Replace 'Ubuntu-22.04' below with the name of your distro.</span><span class="w">

</span><span class="c"># Shut down your distro.</span><span class="w">
</span><span class="n">wsl</span><span class="w"> </span><span class="nt">--shutdown</span><span class="w"> </span><span class="s1">'Ubuntu-22.04'</span><span class="w">

</span><span class="c"># Find the path to the VHDX file for your distro.</span><span class="w">
</span><span class="p">(</span><span class="n">Get-ChildItem</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nx">HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss</span><span class="w"> </span><span class="se">`
</span><span class="w">  </span><span class="o">|</span><span class="w"> </span><span class="n">Where-Object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">GetValue</span><span class="p">(</span><span class="s2">"DistributionName"</span><span class="p">)</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="s1">'Ubuntu-22.04'</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="se">`</span><span class="w">
  </span><span class="p">)</span><span class="o">.</span><span class="nf">GetValue</span><span class="p">(</span><span class="s2">"BasePath"</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"\ext4.vhdx"</span><span class="w">

</span><span class="c"># Launch diskpart and resize the disk returned above as {path}.</span><span class="w">
</span><span class="n">diskpart</span><span class="w">
</span><span class="nx">select</span><span class="w"> </span><span class="nx">vdisk</span><span class="w"> </span><span class="nx">file</span><span class="o">=</span><span class="s2">"{path}"</span><span class="w">
</span><span class="n">expand</span><span class="w"> </span><span class="nx">vdisk</span><span class="w"> </span><span class="nx">maximum</span><span class="o">=</span><span class="s2">"{size in MB}"</span><span class="w">
</span><span class="kr">exit</span><span class="w">
</span></code></pre></div></div> <p>Now log into your distro’s shell again and tell it that it has more disk space available:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Find the correct device.</span>
<span class="nb">sudo </span>mount <span class="nt">-t</span> devtmpfs none /dev 2&gt; /dev/null
mount | <span class="nb">grep </span>ext4

<span class="c"># Copy the name e.g., /dev/sdc and resize it using the same size in MB as above.</span>
<span class="nb">sudo </span>resize2fs /dev/sdb <span class="s1">'{size in MB}M'</span>
</code></pre></div></div>]]></content><author><name>{&quot;twitter&quot;=&gt;&quot;mrhestew&quot;, &quot;picture&quot;=&gt;&quot;/assets/images/headshot.jpg&quot;}</name></author><category term="rust"/><category term="rustlang"/><category term="tips"/><category term="wsl"/><summary type="html"><![CDATA[I’m the lead developer on the Azure SDK for Rust and have been working on it for a few years now. I also started or contribute to a number of other Rust projects. With all the different crates and numerous versions of the same crate names, a lot of drive space is lost to downloaded crates and cloned - but shallow - repos. When I switch branches that might use different versions or features of crates, it also uses a lot of drive space.]]></summary></entry><entry><title type="html">12 Months: Over 7000m with Strava</title><link href="https://heaths.dev/sport/2024/12/20/12-months-over-7000m.html" rel="alternate" type="text/html" title="12 Months: Over 7000m with Strava"/><published>2024-12-20T01:00:00+00:00</published><updated>2024-12-20T01:00:00+00:00</updated><id>https://heaths.dev/sport/2024/12/20/12-months-over-7000m</id><content type="html" xml:base="https://heaths.dev/sport/2024/12/20/12-months-over-7000m.html"><![CDATA[<p>A little over a year ago I went in for what I thought would be a routine physical. Unfortunately, genetics caught up with me and I had some blockage in my arteries. I wasn’t going to end up with a heart attack like my paternal grandfather (dead by heart attack) or my father, so I decided to change my lifestyle right then and there: cut back (almost none) on added sugar - hard in this country - and reduce saturated fats. I already exercised quite a bit, but decided to dedicate more to regular cycling instead of weekly hikes and one or two rides a week.</p> <p>When roads started getting icy, I decided to get a Zwift indoor trainer which I (mostly) enjoy. That gave me ample time to work on more Strava badges - the harder ones, especially.</p> <p>Around these parts, it’s hard to avoid climbing on your bike so, with already strong legs, I leaned into it: I started signing up each month for Strava’s 7,000m (22,966ft) challenge. I lost a bunch of weight and my legs got stronger to the point that training with friends and cycling teammates meant frequently having to wait for them at the top of hills. I don’t mind. Fun to get out with people and (usually) to take a break after longer climbs.</p> <p>I even finally road my first <a href="https://events.nationalmssociety.org/index.cfm?fuseaction=donorDrive.event&amp;eventID=1972">Bike MS: Deception Pass Classic</a> and set a <a href="https://www.strava.com/activities/12352769911#3267598232664522918">new course record on Strava</a>; though, I plan to socialize more next year. It’s not a race, but I wanted to push myself on my first century ride and see what I could do over 100mi and over 5,000ft.</p> <p>All this lead up to a lot of climbing over the past year to earn some badges, but more so to prove I could:</p> <p class="image-grid"><img src="https://dgalywyr863hv.cloudfront.net/challenges/4145/4145-logo-100.png" alt="January Cycling Elevation Challenge"/> <img src="https://dgalywyr863hv.cloudfront.net/challenges/4195/4195-logo-100.png" alt="February Cycling Elevation Challenge"/> <img src="https://dgalywyr863hv.cloudfront.net/challenges/4238/4238-logo-100.png" alt="March Cycling Elevation Challenge"/> <img src="https://dgalywyr863hv.cloudfront.net/challenges/4292/4292-logo-100.png" alt="April Cycling Elevation Challenge"/> <img src="https://dgalywyr863hv.cloudfront.net/challenges/4355/4355-logo-100.png" alt="May Cycling Elevation Challenge"/> <img src="https://dgalywyr863hv.cloudfront.net/challenges/4434/4434-logo-100.png" alt="June Cycling Elevation Challenge"/> <img src="https://dgalywyr863hv.cloudfront.net/challenges/4488/4488-logo-100.png" alt="July Cycling Elevation Challenge"/> <img src="https://dgalywyr863hv.cloudfront.net/challenges/4543/4543-logo-100.png" alt="August Cycling Elevation Challenge"/> <img src="https://dgalywyr863hv.cloudfront.net/challenges/4604/4604-logo-100.png" alt="September Cycling Elevation Challenge"/> <img src="https://dgalywyr863hv.cloudfront.net/challenges/4672/4672-logo-100.png" alt="October Cycling Elevation Challenge"/> <img src="https://dgalywyr863hv.cloudfront.net/challenges/4738/4738-logo-100.png" alt="November Cycling Elevation Challenge"/> <img src="https://dgalywyr863hv.cloudfront.net/challenges/4770/4770-logo-100.png" alt="December Cycling Elevation Challenge"/></p> <p>I’m on track to complete over 100km elevation and 5,000mi distance by EOY; however, after that I plan to back off a little. Cycling indoor is great exercise, but it does get a little boring. I discovered audiobooks help, but it’s also mentally exhausting and I’m burning out after an average of 4-5 rides week - most often pushing myself.</p> <p>I’ll keep going, but I plan to tank any possibility of getting the 7,000m badge in January 2025. I’ll likely go for those badges in spring and summer months as I start training for the next charity ride(s).</p>]]></content><author><name>{&quot;twitter&quot;=&gt;&quot;mrhestew&quot;, &quot;picture&quot;=&gt;&quot;/assets/images/headshot.jpg&quot;}</name></author><category term="sport"/><category term="cycling"/><category term="achievement"/><summary type="html"><![CDATA[A little over a year ago I went in for what I thought would be a routine physical. Unfortunately, genetics caught up with me and I had some blockage in my arteries. I wasn’t going to end up with a heart attack like my paternal grandfather (dead by heart attack) or my father, so I decided to change my lifestyle right then and there: cut back (almost none) on added sugar - hard in this country - and reduce saturated fats. I already exercised quite a bit, but decided to dedicate more to regular cycling instead of weekly hikes and one or two rides a week.]]></summary></entry><entry><title type="html">Helix support for TypeSpec</title><link href="https://heaths.dev/tips/2024/08/02/helix-support-for-typespec.html" rel="alternate" type="text/html" title="Helix support for TypeSpec"/><published>2024-08-02T23:19:04+00:00</published><updated>2024-08-02T23:19:04+00:00</updated><id>https://heaths.dev/tips/2024/08/02/helix-support-for-typespec</id><content type="html" xml:base="https://heaths.dev/tips/2024/08/02/helix-support-for-typespec.html"><![CDATA[<p>You can add <a href="https://typespec.io">TypeSpec</a> language support to <a href="https://helix-editor.com">Helix</a> fairly easily. I’ve done this in my profile repo and you can copy the code. I hope to get this <a href="https://github.com/helix-editor/helix">added to Helix</a> if they’ll accept an up-and-comer.</p> <h2 id="update"><a href="#update"></a>Update</h2> <p>🎉 My <a href="https://github.com/helix-editor/helix/pull/11412">pull request</a> was merged: TypeSpec is now supported out of the box in Helix! You still need to install the LSP as with any other supported language, but that’s a single, simple command. See below, or in <a href="https://github.com/helix-editor/helix/wiki/Language-Server-Configurations#typespec">their wiki</a>.</p> <h2 id="background"><a href="#background"></a>Background</h2> <p>I’ve been using <a href="https://www.vim.org"><code class="language-plaintext highlighter-rouge">vim</code></a> and before it <code class="language-plaintext highlighter-rouge">vi</code> for close to 30 years. I started my programming career in a terminal and, while I often enjoy GUI apps like <a href="https://code.visualstudio.com">Visual Studio Code</a> and am more productive when touching lots of files, I still like the efficiency of a good terminal editor.</p> <p>But <code class="language-plaintext highlighter-rouge">vim</code> is feeling rather dated. There’s clearly a lot of cruft they have to support, and much of this seems to have carried over into <a href="https://neovim.io">neovim</a>. While neovim does support tree-sitter for LSP support and has a rich ecosystem, I thought I’d give another, fairly new editor a try: Helix.</p> <p>Helix is a vim-like editor written in Rust and seems to be fairly popular with some other Rust developers. Given it doesn’t have a long legacy to support, it seems worth a try at first. So far, I’ve been loving it. <a href="https://github.com/helix-editor/helix/wiki/Language-Server-Configurations">Language support</a> is fairly easy to add and it supports a large number of languages out of the box, though you have to install the LSPs and perhaps other tools for some languages.</p> <p>One language it’s missing is <a href="https://typespec.io">TypeSpec</a>, which my team, the Azure SDK team, develops. It’s also getting used by some third-parties, and since we’re planning to generate source generation only from TypeSpec for the Azure SDKs for Rust, I’ll be using it a lot more. It’s also being reviewed more frequently by the Azure REST API Review Board, of which I’m a member.</p> <h2 id="installing-the-lsp"><a href="#installing-the-lsp"></a>Installing the LSP</h2> <p>The TypeSpec LSP is contained in the <a href="https://npmjs.org/packages/@typespec/compiler"><code class="language-plaintext highlighter-rouge">@typespec/compiler</code></a>, so all you need to do is install that globally (or otherwise discoverable in your <code class="language-plaintext highlighter-rouge">$PATH</code>):</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">install</span> <span class="nt">-g</span> @typespec/compiler
</code></pre></div></div> <h2 id="configuring-the-grammar"><a href="#configuring-the-grammar"></a>Configuring the grammar</h2> <p>You’ll need to add some configuration to your <code class="language-plaintext highlighter-rouge">languages.toml</code> configuration file e.g., <code class="language-plaintext highlighter-rouge">~/.config/helix/languages.toml</code>:</p> <div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">use-grammars</span> <span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">only</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[</span><span class="s">"typespec"</span><span class="p">]</span><span class="w"> </span><span class="p">}</span>

<span class="k">[[</span><span class="n">grammar</span><span class="k">]]</span>
<span class="n">name</span> <span class="o">=</span><span class="w"> </span><span class="s">"typespec"</span>
<span class="n">source</span> <span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">git</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"https://github.com/happenslol/tree-sitter-typespec"</span><span class="p">,</span><span class="w"> </span><span class="n">rev</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"af7a97eea5d4c62473b29655a238d4f4e055798b"</span><span class="w"> </span><span class="p">}</span>

<span class="k">[[</span><span class="n">language</span><span class="k">]]</span>
<span class="n">name</span> <span class="o">=</span><span class="w"> </span><span class="s">"typespec"</span>
<span class="n">language-id</span> <span class="o">=</span><span class="w"> </span><span class="s">"typespec"</span>
<span class="n">scope</span> <span class="o">=</span><span class="w"> </span><span class="s">"source.typespec"</span>
<span class="n">injection-regex</span> <span class="o">=</span><span class="w"> </span><span class="s">"(tsp|typespec)"</span>
<span class="n">file-types</span> <span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s">"tsp"</span><span class="p">]</span>
<span class="n">roots</span> <span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s">"tspconfig.yaml"</span><span class="p">]</span>
<span class="n">auto-format</span> <span class="o">=</span><span class="w"> </span><span class="kc">true</span>
<span class="n">comment-token</span> <span class="o">=</span><span class="w"> </span><span class="s">"//"</span>
<span class="n">block-comment-tokens</span> <span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"/*"</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"*/"</span><span class="w"> </span><span class="p">}</span>
<span class="n">indent</span> <span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">tab-width</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"  "</span><span class="w"> </span><span class="p">}</span>
<span class="n">language-servers</span> <span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s">"typespec"</span><span class="p">]</span>

<span class="k">[</span><span class="n">language-server</span><span class="k">.</span><span class="n">typespec</span><span class="k">]</span>
<span class="n">command</span> <span class="o">=</span><span class="w"> </span><span class="s">"tsp-server"</span>
<span class="n">args</span> <span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s">"--stdio"</span><span class="p">]</span>
</code></pre></div></div> <h3 id="compilation"><a href="#compilation"></a>Compilation</h3> <p>Once that configuration is in place, you need to actually compile the parser. Helix has made that easy:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hg <span class="nt">-g</span> fetch
hg <span class="nt">-g</span> build
</code></pre></div></div> <h2 id="rich-language-support"><a href="#rich-language-support"></a>Rich language support</h2> <p>Now that helix is configured to start and use the TypeSpec LSP for any files with a <code class="language-plaintext highlighter-rouge">.tsp</code> file extension with an ancestor <code class="language-plaintext highlighter-rouge">tspconfig.yaml</code> configuration file, you need to tell it what to do with that information.</p> <p>To support syntax highlighting; selection of functions, arguments, models, etc.; and proper indentation, copy files from <a href="https://github.com/heaths/helix/tree/main/runtime/queries/typespec">https://github.com/heaths/helix/tree/main/runtime/queries/typespec</a> into the <code class="language-plaintext highlighter-rouge">runtime/queries/typespec</code> subdirectory of your helix configuration directory.</p> <h2 id="demo"><a href="#demo"></a>Demo</h2> <p>What do you get after all that?</p> <p><a href="https://asciinema.org/a/DvpTtI9bx9N0tQiMinM114t0a"><img src="https://asciinema.org/a/DvpTtI9bx9N0tQiMinM114t0a.svg" alt="asciicast"/></a></p>]]></content><author><name>{&quot;twitter&quot;=&gt;&quot;mrhestew&quot;, &quot;picture&quot;=&gt;&quot;/assets/images/headshot.jpg&quot;}</name></author><category term="tips"/><category term="azure"/><category term="typespec"/><category term="helix"/><summary type="html"><![CDATA[You can add TypeSpec language support to Helix fairly easily. I’ve done this in my profile repo and you can copy the code. I hope to get this added to Helix if they’ll accept an up-and-comer.]]></summary></entry><entry><title type="html">Using 1Password for git SSH signatures in WSL</title><link href="https://heaths.dev/tips/2023/05/19/using-1password-for-git-ssh-signatures-in-wsl.html" rel="alternate" type="text/html" title="Using 1Password for git SSH signatures in WSL"/><published>2023-05-19T17:02:00+00:00</published><updated>2023-05-19T17:02:00+00:00</updated><id>https://heaths.dev/tips/2023/05/19/using-1password-for-git-ssh-signatures-in-wsl</id><content type="html" xml:base="https://heaths.dev/tips/2023/05/19/using-1password-for-git-ssh-signatures-in-wsl.html"><![CDATA[<p>1Password allows developers to sign <a href="https://developer.1password.com/docs/ssh/git-commit-signing">git commits using SSH</a> by setting up <a href="https://developer.1password.com/docs/ssh/agent">their own SSH agent</a>. Doing this in your host platform e.g., Windows, is relatively straight forward but if you want to set this up in Windows Subsystem for Linux (WSL) there is additional configuration you need to perform.</p> <p>While there are many different ways to configure this, many have you set up a service or autorun program but I want neither of those affecting Windows boot and login performance for something I don’t use often throughout the course of every day. Fortunately, I found one <a href="https://dev.to/d4vsanchez/use-1password-ssh-agent-in-wsl-2j6m">one such article</a> that accomplished exactly what I wanted using <code class="language-plaintext highlighter-rouge">socat</code> and <code class="language-plaintext highlighter-rouge">npiperelay</code>.</p> <p>I made a few modifications including how to acquire <code class="language-plaintext highlighter-rouge">npiperelay</code> given changes to the Go toolset.</p> <h2 id="1-acquire-npiperelay"><a href="#1-acquire-npiperelay"></a>1. Acquire npiperelay</h2> <p>You need to acquire <code class="language-plaintext highlighter-rouge">npiperelay</code> in Windows. You can download it from <a href="https://github.com/jstarks/npiperelay/releases/latest">https://github.com/jstarks/npiperelay/releases/latest</a> into a directory in your <code class="language-plaintext highlighter-rouge">PATH</code> environment variable or, if you have Go installed, run:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go <span class="nb">install </span>github.com/jstarks/npiperelay@latest
</code></pre></div></div> <h2 id="2-install-socat"><a href="#2-install-socat"></a>2. Install socat</h2> <p>Next you need to install <code class="language-plaintext highlighter-rouge">socat</code> in your WSL distribution. I’m assuming you are using some Debian-based distro e.g., Ubuntu. If you are using another distro, please use appropriate commands.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update
apt <span class="nb">install</span> <span class="nt">-y</span> socat
</code></pre></div></div> <h2 id="3-create-startup-script"><a href="#3-create-startup-script"></a>3. Create startup script</h2> <p>You’ll need to create a bash script that will start when you log into your distro. I’m assuming bash below.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> ~/.1password
<span class="nb">touch</span> ~/.1password/agent <span class="o">&amp;&amp;</span> <span class="nb">chmod</span> +x ~/.1password/agent
</code></pre></div></div> <p>Open <em>~/.1password/agent</em> and paste the following content:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/bash</span>

<span class="nb">export </span><span class="nv">SSH_AUTH_SOCK</span><span class="o">=</span><span class="nv">$HOME</span>/.1password/agent.sock

<span class="nv">ALREADY_RUNNING</span><span class="o">=</span><span class="si">$(</span>ps <span class="nt">-auxww</span> | <span class="nb">grep</span> <span class="nt">-q</span> <span class="s1">'[n]piperelay.exe -ei -s //./pipe/openssh-ssh-agent'</span><span class="p">;</span> <span class="nb">echo</span> <span class="nv">$?</span><span class="si">)</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nv">$ALREADY_RUNNING</span> <span class="o">!=</span> <span class="s1">'0'</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
    if</span> <span class="o">[[</span> <span class="nt">-S</span> <span class="nv">$SSH_AUTH_SOCK</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
        </span><span class="nb">rm</span> <span class="nv">$SSH_AUTH_SOCK</span>
    <span class="k">fi</span>

    <span class="o">(</span>setsid socat UNIX-LISTEN:<span class="nv">$SSH_AUTH_SOCK</span>,fork EXEC:<span class="s1">'npiperelay.exe -ei -s //./pipe/openssh-ssh-agent'</span>,nofork &amp;<span class="o">)</span> <span class="o">&gt;</span> /dev/null 2&gt;&amp;1
<span class="k">fi</span>
</code></pre></div></div> <h2 id="4-run-script-on-login"><a href="#4-run-script-on-login"></a>4. Run script on login</h2> <p>To run the script when you log in interactively, edit your appropriate profile e.g., <em>.bashrc</em> for bash:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">.</span> ~/.1password/agent
</code></pre></div></div> <p>You can restart your login session or just source <em>~/.1password/agent</em> yourself.</p> <h2 id="5-test"><a href="#5-test"></a>5. Test</h2> <p>Assuming you have already configured 1Password’s SSH agent using the instructions at the beginning of this post, you can test and reset any git repository you have handy e.g.,</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> ~/src/some-project
<span class="nb">echo test</span> <span class="o">&gt;</span> test.txt
git add <span class="nt">-A</span>
git commit <span class="nt">-am</span><span class="s1">'test'</span> <span class="nt">-S</span>
git show <span class="nt">--show-signature</span>
</code></pre></div></div> <h3 id="unknown-signer"><a href="#unknown-signer"></a>Unknown signer</h3> <p>If the <code class="language-plaintext highlighter-rouge">git show --show-signature</code> command about shows an unknown or invalid signer, be sure you have your <code class="language-plaintext highlighter-rouge">allowed_signers</code> set up for git. Unlike GPG that can use counter signatures to validate identities, SSH signatures need explicit approval:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> <span class="nt">-p</span> ~/.config/git/
<span class="nb">cat</span> ~/.ssh/identity_rsa.pub <span class="o">&gt;</span> ~/.config/git/allowed_signers
git config <span class="nt">--global</span> gpg.ssh.allowedsignersfile <span class="nv">$HOME</span>/.config/git/allowed_signers
</code></pre></div></div> <h3 id="blocks-tunneling-into-other-hosts"><a href="#blocks-tunneling-into-other-hosts"></a>Blocks tunneling into other hosts</h3> <p>If you are also using SSH to tunnel into other hosts, you should configure SSH separately for github.com:</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Host *
    IdentityFile ~/.ssh/id_rsa.pub

Host github.com
    IdentityAgent ~/.1password/agent.sock
    IdentitiesOnly yes
</code></pre></div></div>]]></content><author><name>{&quot;twitter&quot;=&gt;&quot;mrhestew&quot;, &quot;picture&quot;=&gt;&quot;/assets/images/headshot.jpg&quot;}</name></author><category term="tips"/><category term="git"/><category term="ssh"/><category term="wsl"/><summary type="html"><![CDATA[1Password allows developers to sign git commits using SSH by setting up their own SSH agent. Doing this in your host platform e.g., Windows, is relatively straight forward but if you want to set this up in Windows Subsystem for Linux (WSL) there is additional configuration you need to perform.]]></summary></entry></feed>