<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>mykter.com</title>
    <description>Michael Macnair's blog.
</description>
    <link>https://mykter.com/</link>
    <atom:link href="https://mykter.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Thu, 28 May 2020 18:26:42 +0100</pubDate>
    <lastBuildDate>Thu, 28 May 2020 18:26:42 +0100</lastBuildDate>
    <generator>Jekyll v3.8.7</generator>
    
      <item>
        <title>What does the AWS security certification mean?</title>
        <description>&lt;p&gt;I recently passed the strangely titled “AWS Certified Security - Specialty” exam, woo 🎉. I guess that makes me “AWS Security - Specialty” certified? Quite a mouthful.&lt;/p&gt;

&lt;p&gt;This is what AWS &lt;a href=&quot;https://aws.amazon.com/certification/certified-security-specialty/&quot;&gt;say this means&lt;/a&gt; (numbering + split are my additions):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Abilities Validated by the Certification:&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;An understanding of specialized data classifications and AWS data protection mechanisms&lt;/li&gt;
    &lt;li&gt;An understanding of data encryption methods and AWS mechanisms to implement them&lt;/li&gt;
    &lt;li&gt;An understanding of secure Internet protocols and AWS mechanisms to implement them&lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;A working knowledge of AWS security services and features of services to provide a secure production environment&lt;/p&gt;

      &lt;hr /&gt;
    &lt;/li&gt;
    &lt;li&gt;Competency gained from two or more years of production deployment experience using AWS security services and features&lt;/li&gt;
    &lt;li&gt;Ability to make tradeoff decisions with regard to cost, security, and deployment complexity given a set of application requirements&lt;/li&gt;
    &lt;li&gt;An understanding of security operations and risk&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, note that there &lt;em&gt;isn’t&lt;/em&gt; an entry along these lines: “Ability to make effective use of AWS security features to secure a production deployment”. I think that is what many people would expect this certification to validate. Number 6 comes close, but isn’t quite as general.&lt;/p&gt;

&lt;p&gt;OK, so the certification is perhaps not quite targeted to what would make it most useful, but how well does it validate the abilities it does claim?&lt;/p&gt;

&lt;p&gt;I’ve split the list into two halves – the top set deal primarily with knowledge of AWS services, the bottom set are more about experience and capabilities.&lt;/p&gt;

&lt;h1 id=&quot;knowledge-of-aws-security-features&quot;&gt;Knowledge of AWS security features&lt;/h1&gt;

&lt;p&gt;I think the certification does a good job at 1-4. It’s a multiple choice exam that covers a fairly broad swathe of AWS products. Most of the questions in my exam had at least one distracter that was sufficiently plausible to put you on at best 50:50 odds for the question if you didn’t know your AWS security features pretty well (usually the distracters either referenced a real AWS feature or product that doesn’t &lt;em&gt;quite&lt;/em&gt; meet the requirements, or a perfect sounding feature that doesn’t actually exist).&lt;/p&gt;

&lt;p&gt;This comes with an interesting caveat due to the nature of multiple choice questions: the right answer is always staring you in the face. The exam doesn’t test the ability of candidates to come up with possible solutions to a given problem, only to select a good solution from a set of options. Does this matter in practice? I suspect it does – the majority of your AWS security challenges are not going to be of the form “which of these should I do?”, they’re either going to be “how do I do X”, or even more subtle: knowing that there is something you should be doing in a particular area in the first place.&lt;/p&gt;

&lt;h1 id=&quot;applied-security-engineering-in-an-aws-environment&quot;&gt;Applied security engineering in an AWS environment&lt;/h1&gt;
&lt;p&gt;The next set of claimed abilities are a lot harder to validate, and I don’t think the certification does a particularly good job here.&lt;/p&gt;

&lt;p&gt;Number 5: 2+ years of production deployment experience. Firstly this is an extremely hard thing to define what it even means in terms of abilities, and secondly from my sample size of one it’s demonstrably false. I have at most 0.5 years production deployment experience with AWS security services – I started working seriously with AWS about 6 months prior to taking the exam. Perhaps my background in security and fairly intense learning over the past few months is roughly equal to a ‘typical’ 2 years of production experience? If you could reliably deduce this kind of information from a multiple-choice quiz, the technical part of hiring would be a solved problem.&lt;/p&gt;

&lt;p&gt;Number 6: ability to trade off cost/security/complexity. This is &lt;em&gt;really&lt;/em&gt; hard to test in a multiple choice exam, and certainly the questions I got in my exam (they’re drawn from a big pool of questions) didn’t assess this in any meaningful way. As soon as you’re trading off various valid answers that only vary in domains like cost/complexity/security, either (a) the question has to be quite contrived and very leading, or (b) you need &lt;em&gt;way&lt;/em&gt; more context than they include about a scenario to be able to determine the ‘right’ answer, and even then you might have in mind some reasonable assumptions that make an alternative answer valid. Multiple choice questions need a clear best answer, and don’t allow for “&lt;a href=&quot;https://twitter.com/SwiftOnSecurity/status/1002403110151745536&quot;&gt;it depends&lt;/a&gt;”.&lt;/p&gt;

&lt;p&gt;Number 7: security operations and risk. I’m least confident about my assessment of this one, as it’s the area I’m most comfortable with – I don’t remember much about the questions I got in this domain. Again though, I think most of the questions were pretty basic or fairly leading.&lt;/p&gt;

&lt;h1 id=&quot;in-brief&quot;&gt;In brief&lt;/h1&gt;
&lt;p&gt;To sum up, I think the cert does a good job of testing your knowledge of AWS security services and features, and not such a good job of testing that you can use that knowledge effectively.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;br /&gt;
OK that’s it! If you too have less than 2 years production experience of AWS security but want to pass the exam, check out the &lt;a href=&quot;https://github.com/mykter/aws-security-cert-service-notes&quot;&gt;notes&lt;/a&gt; I made as I was studying. It’s a big list of all the AWS-specific security topics that cover points 1-4:&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-cards=&quot;hidden&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Just passed the AWS security specialty certification exam 🎉&lt;br /&gt;&lt;br /&gt;Here are the notes I made as I went along, briefly covering the security aspects of 60ish AWS products.&lt;a href=&quot;https://t.co/73XBs0vaXU&quot;&gt;https://t.co/73XBs0vaXU&lt;/a&gt; &lt;/p&gt;&amp;mdash; Michael Macnair (@michael_macnair) &lt;a href=&quot;https://twitter.com/michael_macnair/status/1115358910796443650?ref_src=twsrc%5Etfw&quot;&gt;April 8, 2019&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

</description>
        <pubDate>Sat, 04 May 2019 00:00:00 +0100</pubDate>
        <link>https://mykter.com/2019/05/04/aws-security-certification</link>
        <guid isPermaLink="true">https://mykter.com/2019/05/04/aws-security-certification</guid>
        
        
        <category>aws</category>
        
      </item>
    
      <item>
        <title>Streaming from a USB record player to Sonos speakers via a Raspberry Pi</title>
        <description>&lt;p&gt;I was very happy to find &lt;a href=&quot;https://github.com/coreyk/darkice-libaacplus-rpi-guide&quot;&gt;two&lt;/a&gt; &lt;a href=&quot;https://github.com/basdp/USB-Turntables-to-Sonos-with-RPi&quot;&gt;guides&lt;/a&gt; to setting up a Raspberry Pi to stream music from a turntable with a USB output, so we could listen to it on our existing Sonos speakers and via a network-connected receiver in a different room.&lt;/p&gt;

&lt;p&gt;I adapted the two guides and learned a few things along the way – this is mostly a record for my own reference, but perhaps it will be of help to someone else too.&lt;/p&gt;

&lt;p&gt;The changes from &lt;a href=&quot;https://github.com/coreyk/darkice-libaacplus-rpi-guide&quot;&gt;coreyk&lt;/a&gt;’s and &lt;a href=&quot;https://github.com/basdp/USB-Turntables-to-Sonos-with-RPi&quot;&gt;basdp&lt;/a&gt;’s guides are roughly:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Used Raspbian Stretch (no changes needed)&lt;/li&gt;
  &lt;li&gt;Use stock darkice binaries from the repository&lt;/li&gt;
  &lt;li&gt;darkice init script tweaks&lt;/li&gt;
  &lt;li&gt;Stream from port 80 so you don’t have to specify a port&lt;/li&gt;
  &lt;li&gt;Power control from a mobile via a URL&lt;/li&gt;
&lt;/ul&gt;

&lt;ol id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#stock-darkice&quot; id=&quot;markdown-toc-stock-darkice&quot;&gt;Stock darkice&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#darkice-init-script-tweaks&quot; id=&quot;markdown-toc-darkice-init-script-tweaks&quot;&gt;darkice init script tweaks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#default-port&quot; id=&quot;markdown-toc-default-port&quot;&gt;Default port&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#reboot-and-shutdown-from-a-mobile&quot; id=&quot;markdown-toc-reboot-and-shutdown-from-a-mobile&quot;&gt;Reboot and shutdown from a mobile&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;stock-darkice&quot;&gt;Stock darkice&lt;/h2&gt;
&lt;p&gt;coreyk compiles darkice from source, to add AAC+ support. I don’t need this, as on a local network the suggestion of doing fixed 320kbps MP3 encoding is fine.&lt;/p&gt;

&lt;p&gt;basdp provides their own .deb. This is fragile (what versions of raspbian will it work with?) and there’s no way to tell if it’s trustworthy.&lt;/p&gt;

&lt;p&gt;I had no issues with the stock darkice. This meant the only packages I needed to install were darkice and icecast2 (and vim!).&lt;/p&gt;

&lt;h2 id=&quot;darkice-init-script-tweaks&quot;&gt;darkice init script tweaks&lt;/h2&gt;
&lt;p&gt;I followed &lt;a href=&quot;https://github.com/coreyk/darkice-libaacplus-rpi-guide&quot;&gt;coreyk’s &lt;/a&gt; guide, but instead of deleting the pidfile with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rm&lt;/code&gt;, you can pass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--remove-pidfile&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start-stop-daemon&lt;/code&gt; when stopping.&lt;/p&gt;

&lt;p&gt;To get logging output from darkice, I changed the start invocation to make use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--no-close&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;LOGFILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$LOGDIR&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$NAME&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.log&quot;&lt;/span&gt;
...
start-stop-daemon &lt;span class=&quot;nt&quot;&gt;--start&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--quiet&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--make-pidfile&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--pidfile&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PIDFILE&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;--background&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--chuid&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$USER&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;$GROUP&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-close&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	    &lt;span class=&quot;nt&quot;&gt;--exec&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DAEMON&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DAEMON_OPTS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$LOGFILE&lt;/span&gt; 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Not directly related to the init script, but note that darkice is being run as nobody:nobody. This user can’t set the realtime scheduling priority requests in darkice’s configuration file, so we give the binary that capability:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;setcap &lt;span class=&quot;nv&quot;&gt;cap_sys_nice&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;+ep &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;which darkice&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;default-port&quot;&gt;Default port&lt;/h2&gt;
&lt;p&gt;Both guides suggest setting up icecast to listen on port 8000. This is fine, but makes the URL slightly ugly.&lt;/p&gt;

&lt;p&gt;With port 80, you can stream from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://vinyl.local/listen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The port can easily be changed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/darkice.cfg&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/icecast2/icecast.xml&lt;/code&gt;, the trick is to give icecast the &lt;a href=&quot;http://man7.org/linux/man-pages/man7/capabilities.7.html&quot;&gt;capability&lt;/a&gt; to bind to port 80:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;setcap &lt;span class=&quot;s1&quot;&gt;'cap_net_bind_service=+ep'&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;which icecast2&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;reboot-and-shutdown-from-a-mobile&quot;&gt;Reboot and shutdown from a mobile&lt;/h2&gt;
&lt;p&gt;To provide a clean shutdown option, I wrote this little script to listen for web requests. A shortcut to the URL alongside the Sonos app on my phone’s launcher then provides a convenient way to cleanly shut it down. I don’t know what the risk of SD card corruption is from hard power-offs, but this eases my mind.&lt;/p&gt;

&lt;p&gt;It’s called from /etc/rc.local so it should always be running when the Pi is. This also means it runs as root - not generally a good idea for a web server, to say the least, but in this case it’s quite convenient as that gives it permission to shutdown and reboot.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/env python3
&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;http.server&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BaseHTTPRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HTTPServer&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;urllib&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;subprocess&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# HTTPRequestHandler class
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BaseHTTPRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;parsed_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlparse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parsed_path&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'/reboot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'/restart'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Rebooting...&quot;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Popen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;shutdown&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-r&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;now&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# will run concurrently
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parsed_path&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'/halt'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'/shutdown'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'/stop'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Shutting down...&quot;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Popen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;shutdown&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-h&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;now&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# will run concurrently
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Not found. Available paths: /reboot, /halt&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;

        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Content-type'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'text/html'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end_headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Send response to client as utf8
&lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;utf8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# bind to all addresses, unprivileged port
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;server_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;httpd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HTTPServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'running server...'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;httpd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;serve_forever&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Sat, 02 Feb 2019 00:00:00 +0000</pubDate>
        <link>https://mykter.com/2019/02/02/streaming-vinyl-raspberry-pi</link>
        <guid isPermaLink="true">https://mykter.com/2019/02/02/streaming-vinyl-raspberry-pi</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>Patching node packages</title>
        <description>&lt;p&gt;An investigation into managing patches for node libraries.&lt;/p&gt;

&lt;p&gt;I’m developing an &lt;a href=&quot;https://www.github.com/mykter/TagTime-desktop&quot;&gt;electron application&lt;/a&gt;, and whilst using a third party library came across a &lt;a href=&quot;https://github.com/moroshko/react-autosuggest/pull/164&quot;&gt;missing feature&lt;/a&gt; that upstream don’t want to implement. It can be implemented with a trivial one-line change, but I found the real difficulty was working out how to manage this patch. This isn’t an uncommon scenario, but I’d found very few people talking about how to manage such situations.&lt;/p&gt;

&lt;p&gt;This post goes over the various options I considered and ultimately makes a recommendation on what approach to use when.&lt;/p&gt;

&lt;h2 id=&quot;local-copy&quot;&gt;Local copy&lt;/h2&gt;

&lt;p&gt;You could copy the entire module into your project, and commit it with your fix. Gross.&lt;/p&gt;

&lt;h2 id=&quot;fork&quot;&gt;Fork&lt;/h2&gt;

&lt;p&gt;You could fork the module and make the changes in the fork. npm &lt;a href=&quot;https://docs.npmjs.com/cli/install&quot;&gt;supports&lt;/a&gt; installing a module directly from a git repo, so that’s straightforward. This is the usual approach to this problem and in many cases is probably the best solution.&lt;/p&gt;

&lt;p&gt;The downside is tools will no longer detect your dependency: say goodbye to npm, &lt;a href=&quot;http://greenkeeper.io/&quot;&gt;greenkeeper&lt;/a&gt;, or &lt;a href=&quot;https://snyk.io&quot;&gt;snyk&lt;/a&gt; notifications about updates or vulnerabilities in that module, for example. I’d quite like to have my cake and eat it too – I want to track upstream without having to remember to do something different for a special subset of dependencies.&lt;/p&gt;

&lt;h2 id=&quot;post-install-patch&quot;&gt;post-install patch&lt;/h2&gt;

&lt;p&gt;npm will run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postinstall&lt;/code&gt; script if it’s specified in package.json. You could use this to apply a patch to the installed module. At first glance this is neat – it happens at the right time, and requires minimal maintenance – just add a patch file to the repo and tweak package.json.&lt;/p&gt;

&lt;p&gt;One hiccup is the availability of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;patch&lt;/code&gt; – it’s a unix command. Fortunately git exposes patch functionality under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git apply&lt;/code&gt; and any development platform will have git installed if your application is managed in git.&lt;/p&gt;

&lt;p&gt;However: whilst this will work for the &lt;em&gt;first&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt;, subsequent invocations (for example after updating any other module, or in a CI system that caches &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules&lt;/code&gt;) will try and apply the patch again to the already-patched module, which will fail because patches aren’t idempotent.&lt;/p&gt;

&lt;p&gt;You could work around this by making the script leave a marker behind, say adding a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&amp;lt;myproject&amp;gt;.patched&lt;/code&gt; file in the module’s root or similar. This loses some of the cleanliness of the approach, but it could work.&lt;/p&gt;

&lt;p&gt;Update: it turns out about a year before I wrote this &lt;a href=&quot;https://github.com/ds300/patch-package&quot;&gt;patch-package&lt;/a&gt; was released which uses this approach in a very nice manner, and I just didn’t find it when doing my research. It allows you to make the fix directly in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules&lt;/code&gt;, and will then generate the patch for you and apply it to future installs.&lt;/p&gt;

&lt;h2 id=&quot;theres-a-module-for-that&quot;&gt;There’s a module for that&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/node_modules_patches&quot;&gt;node_module_patches&lt;/a&gt; gets around the idempotence issue by overwriting entire files instead of applying a standard patch. You set up a mirror-hierarchy of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules_patches&lt;/code&gt;, any files in there are copied over the top of the original ones, and it displays a diff for the user. You could (should?) run this from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postinstall&lt;/code&gt; as well.&lt;/p&gt;

&lt;p&gt;This might be a reasonable halfway-house, but I don’t like the “commit a random file from another project into your repo” and I &lt;em&gt;really&lt;/em&gt; don’t like that you could totally break your dependency and not notice. Because it’s not a proper patch, the module could change in any way and this will happily overwrite the file. It’s on the user to decide that the diff doesn’t look right any more. Yuk.&lt;/p&gt;

&lt;h2 id=&quot;build-system-patch&quot;&gt;Build system patch&lt;/h2&gt;

&lt;p&gt;A tool like grunt, gulp, or webpack could implement the same behaviour as the postinstall script described above by having one of the build steps apply a patch. I see two options: directly patch the installed module in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules&lt;/code&gt;, or exploit node’s search behaviour to create a (patched) copy of the module. Directly patching the installed module has the same issue as using post-intstall in that patches aren’t idempotent.&lt;/p&gt;

&lt;p&gt;The latter option is more promising. In my case, I’m already using gulp to build my code; the output goes into an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app&lt;/code&gt; directory. If the patched package is placed under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app/node_modules/&lt;/code&gt; it will get picked up by node in preference to the original in the application root.&lt;/p&gt;

&lt;p&gt;The approach I’ve taken is to create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;patches&lt;/code&gt; directory, which contains a directory for each package that needs patching. These directories contain one or more patch files that will be applied to that package.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/kaa/gulp-apply-patch&quot;&gt;gulp-apply-patch&lt;/a&gt; plugin fits the bill nicely for this task. Here’s the relevant part of my gulpfile, I’m fairly happy with how simple it is:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;patch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;gulp-apply-patch&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BASE_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BUILD_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;BASE_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PATCHES_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;BASE_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;patches&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NODE_MODULES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;BASE_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;node_modules&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PATCHED_MODULES_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;BUILD_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;node_modules&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;patch&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Get all the directories in the patches folder&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to_patch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readdirSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PATCHES_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;statSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PATCHES_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isDirectory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// If there's only a single entry in the patches directory, the {set glob}&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// syntax won't match, so add a dummy entry to work around that&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;to_patch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;nonexistent_dummy_package&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Convert the patch directories into a glob that matches all the files&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// from the corersponding source packages.&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;globs_to_patch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NODE_MODULES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/{&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to_patch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;}/**/*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;globs_to_patch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NODE_MODULES&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// copy only the modules that have patches&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;patch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PATCHES_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/**/*.patch&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PATCHED_MODULES_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This has some nice properties:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The change being made is explicit, as there’s a patch file in the repo.&lt;/li&gt;
  &lt;li&gt;When upstream changes, either the patch will continue to apply and all is probably well (diff line numbers and context lines haven’t changed), or it will fail to apply and you know to check and update.&lt;/li&gt;
  &lt;li&gt;From the perspective of tools looking at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt;, you’re using the standard upstream library. Everything works normally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main downside compared to the fork approach is maintaining a patch file is more work compared to maintaining a forked repo. You can’t just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt;, unless you combine both approaches and generate the patch from a fork. It is also slightly higher risk, as after an upstream change the patch might still successfully apply, but it now breaks the package in a way that would have been picked up had you run the package’s tests after pulling the changes into a forked repo.&lt;/p&gt;

&lt;h2 id=&quot;monkey-patch&quot;&gt;Monkey patch&lt;/h2&gt;

&lt;p&gt;Thanks to the wonder that is javascript we could use the original module unmodified, but at run-time try and fix it up to have the behaviour we want. Depending on the patch this &lt;em&gt;could&lt;/em&gt; be trivial and relatively clean – perhaps an ‘internal’ integer should have a different value. It could be really ugly if, say, a large function needs a slight logic change – the whole function will need to be replaced, implying your patching code has to have a complete copy of said function.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;eslint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;disable&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// monkey patch to make it do the right thing&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;originalModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Good luck getting that to type-check in TypeScript!&lt;/p&gt;

&lt;p&gt;This feels fragile, kind of like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_module_patches&lt;/code&gt; – you might well only know when it breaks when you (or your users) hit the bugs at run time.&lt;/p&gt;

&lt;h2 id=&quot;other-languages&quot;&gt;Other languages&lt;/h2&gt;

&lt;p&gt;How is this solved in other languages?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://getcomposer.org/&quot;&gt;Composer&lt;/a&gt; is a package manager for php, partly inspired by npm. There is a plugin for composer called &lt;a href=&quot;https://github.com/cweagans/composer-patches&quot;&gt;composer-patches&lt;/a&gt; which does exactly what I’m looking for: it applies a patch to dependencies as they are installed by composer. Because it’s integrated with the package manager, it avoids the issue with using npm’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postinstall&lt;/code&gt; script described previously – the patches are only applied when the module is installed. It goes further than this and supports dependencies applying patches to their own dependenciesto their own dependencies – this seems a little problematic, as it encourages creating libraries that need patches to be applied, which in turn forces any users of your library to use composer-patches as well. Neither npm nor yarn support plugins.&lt;/p&gt;

&lt;p&gt;Go has some particular problems with the fork approach, because dependencies include their full path: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import &quot;github.com/a/b&quot;&lt;/code&gt;. These can be &lt;a href=&quot;https://blog.gopheracademy.com/advent-2017/managing-dependencies-forks-and-code-patches-with-dep/&quot;&gt;worked around&lt;/a&gt;, but that’s all I’ve found on this topic.&lt;/p&gt;

&lt;p&gt;The tradition in ruby seems to be monkey patching.&lt;/p&gt;

&lt;p&gt;I couldn’t see anything beyond the fork approach mentioned for python or rust.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Forking is the most robust approach, and you should probably do this. However if you’d like your existing dependency management tools to continue working with this patched dependency, there are a few options.&lt;/p&gt;

&lt;p&gt;Update: you should probably just use &lt;a href=&quot;https://github.com/ds300/patch-package&quot;&gt;patch-package&lt;/a&gt;, a robust install-time patching tool.&lt;/p&gt;

&lt;p&gt;It may be worth considering monkey patching - is your change small, easy to implement at runtime, and when upstream changes likely to either be robust or fail noisily? This could be the simplest approach.&lt;/p&gt;

&lt;p&gt;In preference to monkey patching I would probably recommend applying a source code patch as part of a build step. It’s relatively robust, easy to manage, and less fiddly than trying to monkey patch.&lt;/p&gt;

&lt;p&gt;Hopefully this will save someone the time I spent searching for something like this post! If you have any thoughts on the subject, or decide to re-implement my solution as a gulp plugin, please let me know!&lt;/p&gt;

</description>
        <pubDate>Fri, 09 Feb 2018 00:00:00 +0000</pubDate>
        <link>https://mykter.com/2018/02/09/patching-node-packages</link>
        <guid isPermaLink="true">https://mykter.com/2018/02/09/patching-node-packages</guid>
        
        
        <category>node.js</category>
        
        <category>electron</category>
        
      </item>
    
      <item>
        <title>afl-fuzz on ppc</title>
        <description>&lt;p&gt;afl-fuzz gives you great fuzzer coverage for very little investment of development time. Its primary target platform is Linux on x86 / x86-64, however since the introduction of LLVM mode / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-clang-fast&lt;/code&gt;, &lt;a href=&quot;https://github.com/rc0r/afl-fuzz/tree/master/llvm_mode&quot;&gt;the docs&lt;/a&gt; (link is to an unofficial mirror) offer some hope for those of us working on less mainstream architectures:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The instrumentation is CPU-independent. At least in principle, you should
be able to rely on it to fuzz programs on non-x86 architectures (after
building afl-fuzz with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AFL_NO_X86=1&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is, however, the grand total of the documentation available for using afl on other architectures. I’m pleased to report that it works in practice as well as principle, though it’s not straight forward. Here is what I did to start fuzzing with afl when cross compiling for PowerPC targets (ppc &amp;amp; ppc64).&lt;/p&gt;

&lt;p&gt;(Update 2017-07-17: minor improvements and a cleaner approach that doesn’t involve installing afl.)&lt;/p&gt;

&lt;ol id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#prerequisites&quot; id=&quot;markdown-toc-prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#aside-cross-compilation-with-clang&quot; id=&quot;markdown-toc-aside-cross-compilation-with-clang&quot;&gt;Aside: cross compilation with clang&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cross-compile-afl-fuzz-and-the-afl-runtime&quot; id=&quot;markdown-toc-cross-compile-afl-fuzz-and-the-afl-runtime&quot;&gt;Cross compile afl-fuzz and the afl runtime&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#usage&quot; id=&quot;markdown-toc-usage&quot;&gt;Usage&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#summary&quot; id=&quot;markdown-toc-summary&quot;&gt;Summary&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;For this to work you need to be able to compile the software to be fuzzed with vanilla clang and successfully run it on the target. How you do this depends on your software, see below for some difficulties I encountered.&lt;/p&gt;

&lt;p&gt;Then you need to compile the afl LLVM mode compilers in the usual fashion for your host system, we’re going to put it in a directory called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-cross&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
&lt;span class=&quot;nb&quot;&gt;tar &lt;/span&gt;xzf afl-latest.tgz
&lt;span class=&quot;nb&quot;&gt;mv &lt;/span&gt;afl-2.46b afl-cross
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;afl-cross
make &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; llvm_mode&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;aside-cross-compilation-with-clang&quot;&gt;Aside: cross compilation with clang&lt;/h2&gt;
&lt;p&gt;This isn’t afl specific, but is another problem I needed to solve before I could use afl’s LLVM mode compiler.&lt;/p&gt;

&lt;p&gt;On the one hand, cross compiling with clang is a breeze because it has built in support for it - you don’t need to compile a dedicated cross-compiler for the job. On the other hand….&lt;/p&gt;

&lt;p&gt;With gcc cross compilation we normally specify two different paths - the sysroot for the target headers, and the path to the host’s cross compilation tools. clang doesn’t support this concept properly, having only the concept of the sysroot where it expects everything to be. As clang doesn’t have full support for cross compiling to ppc, it still needs to use your cross-tools version of ld and as. To fix this you can use the undocumented &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-B&lt;/code&gt; switch which instructs clang to search for its guts there first, before its standard paths. Very unsatisfactory, but it does work. You get an invocation that looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;clang &lt;span class=&quot;nt&quot;&gt;-target&lt;/span&gt; magic-target-triple &lt;span class=&quot;nt&quot;&gt;-B&lt;/span&gt; /path/to/cross/tools/dir &lt;span class=&quot;nt&quot;&gt;-mcpu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;mycpu&amp;gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;--sysroot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/path/to/sysroot &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; myExec myExec.c&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Actually working out the correct magic-target-triple was far harder than it should have been. Hopefully &lt;a href=&quot;http://llvm.org/devmtg/2014-04/PDFs/LightningTalks/2014-3-31_ClangTargetSupport_LighteningTalk.pdf&quot;&gt;these improvements&lt;/a&gt; to clang will be implemented to help you enumerate the supported targets - until then, searching + guessing was all I had. 32bit ppc target triples seem to take the form &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;powerpc-&amp;lt;vendor&amp;gt;-linux&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you’re cross compiling for a target that has full support in LLVM then this should be a lot easier.&lt;/p&gt;

&lt;h2 id=&quot;cross-compile-afl-fuzz-and-the-afl-runtime&quot;&gt;Cross compile afl-fuzz and the afl runtime&lt;/h2&gt;
&lt;p&gt;Now we need two things that are compiled to run on the ppc target: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-fuzz&lt;/code&gt; (and any other utilities like afl-analyze); and the tiny blob of afl code that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-clang-fast&lt;/code&gt; will add to every object you compile - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-llvm-rt.o&lt;/code&gt; (and potentially its 64bit companion). Unpack another copy of afl into a new directory, let’s call it &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-target&lt;/code&gt;. The appropriate invocation will look something like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nb&quot;&gt;tar &lt;/span&gt;xzf afl-latest.tgz
&lt;span class=&quot;nb&quot;&gt;mv &lt;/span&gt;afl-2.46b afl-target
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;afl-target
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;clang&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-O3 -funroll-loops -target magic-target-triple &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;
-m32 -mcpu=&amp;lt;mycpu&amp;gt; --sysroot=/path/to/my/sysroot -B /path/to/cross/tools/dir&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;AFL_NO_X86&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 make &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; llvm_mode &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;(I’m using export to avoid repeating CFLAGS for each make command, and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;( subshell )&lt;/code&gt; so the export doesn’t taint the parent.)&lt;/p&gt;

&lt;p&gt;Note that the final step in the Makefile is to run a test by compiling something and executing it - this will fail, because the host architecture is different to the target. That’s fine.&lt;/p&gt;

&lt;p&gt;Now replace the cross-compiler’s version of this object with the target one, so our cross compiling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-clang-fast&lt;/code&gt; injects the right code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;afl-target/afl-llvm-rt&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; afl-cross/&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;
&lt;p&gt;At this point everything just works. Cross compile your target software, e.g. with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CC=&quot;/path/to/afl-cross/afl-clang-fast&quot; CFLAGS=&quot;&amp;lt;all-the-flags&amp;gt;&quot; ./configure &amp;amp;&amp;amp; make&lt;/code&gt;; copy the instrumented binaries to the target; copy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-fuzz&lt;/code&gt; from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-target&lt;/code&gt; directory to the target; and fuzz in the normal way.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;You can use afl on non-x86 targets, but need to (a) be able to cross compile for your target with clang, and (b) compile the target architecture variant of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-llvm-rt*.o&lt;/code&gt; for use by the host version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-clang-fast&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afl-fuzz&lt;/code&gt; and other utilities compiled for the target can then be copied on to the target, enabling you to start torturing non-x86 software.&lt;/p&gt;

</description>
        <pubDate>Wed, 27 Apr 2016 00:00:00 +0100</pubDate>
        <link>https://mykter.com/2016/04/27/afl-on-ppc</link>
        <guid isPermaLink="true">https://mykter.com/2016/04/27/afl-on-ppc</guid>
        
        
        <category>fuzzing</category>
        
      </item>
    
  </channel>
</rss>
