<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Dependencies on Brian Faust</title><link>https://wimdy.works/tags/dependencies/</link><description>Recent content in Dependencies on Brian Faust</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Mon, 01 Jan 0001 00:00:00 +0000</lastBuildDate><atom:link href="https://wimdy.works/tags/dependencies/rss.xml" rel="self" type="application/rss+xml"/><item><title>A Lockfile Gives Repeatability, Not Provenance</title><link>https://wimdy.works/thoughts/a-lockfile-gives-repeatability-not-provenance/</link><pubDate>Mon, 01 Dec 2025 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/a-lockfile-gives-repeatability-not-provenance/</guid><description>&lt;p&gt;&lt;code&gt;composer install&lt;/code&gt; exits successfully. It selects the version in the committed
lockfile, downloads an archive whose checksum matches, generates the autoloader,
and produces the same output on a second clean install.&lt;/p&gt;
&lt;p&gt;The output is &lt;code&gt;EXFILTRATED&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Nothing about that result means Composer ignored the lock. The lockfile was
updated to select the malicious package and its correct checksum. Composer did
exactly what it was told and repeated that decision.&lt;/p&gt;
&lt;p&gt;This is the useful boundary of a dependency lock. It records a resolution. It
can make later installations select the same versions, references, metadata,
and declared distribution bytes. It cannot prove who deserved to publish those
bytes, why the update was approved, what package code will do, whether new
advisories exist, or which artifact a consumer eventually executes.&lt;/p&gt;</description></item><item><title>Supply-Chain Security Begins with Who Can Change the Artifact</title><link>https://wimdy.works/thoughts/supply-chain-security-begins-with-who-can-change-the-artifact/</link><pubDate>Sat, 01 Nov 2025 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/supply-chain-security-begins-with-who-can-change-the-artifact/</guid><description>&lt;p&gt;&lt;code&gt;quote-tool.bin&lt;/code&gt; has a valid signature. Its provenance names the expected
source revision, dependency lock, workflow digest, and builder. The signature
verifies against the consumer&amp;rsquo;s trusted fixture key.&lt;/p&gt;
&lt;p&gt;The program is still malicious.&lt;/p&gt;
&lt;p&gt;In the &lt;a href="https://wimdy.works/reproductions/sec-01/"&gt;SEC-01 fixture&lt;/a&gt;
, the authorized builder changes the
artifact after the tests pass and signs the resulting digest. Signature
verification succeeds because the statement is authentic. Consumer policy
rejects the artifact because its digest does not match the independently
reproduced output.&lt;/p&gt;</description></item><item><title>Dependency Inversion Lets Policy Own the Boundary</title><link>https://wimdy.works/thoughts/dependency-inversion-principle/</link><pubDate>Tue, 01 Jun 2021 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/dependency-inversion-principle/</guid><description>&lt;p&gt;This class uses constructor injection and still points in the wrong direction:&lt;/p&gt;
&lt;figure class="code-figure"&gt;
 &lt;div class="code-block" data-copy-code&gt;
 &lt;button class="copy-code" type="button" aria-label="Copy code"&gt;copy&lt;/button&gt;&lt;span class="sr-only" data-copy-status role="status" aria-live="polite"&gt;&lt;/span&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QuoteShipment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="fm"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;GuzzleHttp\Client&lt;/span&gt; &lt;span class="nv"&gt;$http&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Shipment&lt;/span&gt; &lt;span class="nv"&gt;$shipment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Money&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/carrier/rates&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;json&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;CarrierPayload&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;fromShipment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$shipment&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;EUR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getBody&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;price_cents&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;The constructor is cleaner, but the direction is still wrong. The application
use case knows an HTTP client, carrier endpoint, payload, response shape, and
currency assumption. Moving &lt;code&gt;new Client()&lt;/code&gt; into the container made assembly
easier. It did nothing to keep carrier details out of application policy.&lt;/p&gt;</description></item><item><title>The Type a Caller Receives Defines the Role</title><link>https://wimdy.works/thoughts/the-type-a-caller-receives-defines-the-role/</link><pubDate>Sun, 01 Nov 2020 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/the-type-a-caller-receives-defines-the-role/</guid><description>&lt;p&gt;A payment driver received a client through a factory. The factory promised a
five-operation interface. The concrete client had nine additional public
methods.&lt;/p&gt;
&lt;p&gt;Those extra methods covered token charging, status checks, settlement,
cancellation, token management, payment-method lookup, and refund
cancellation. None of the callers used them. When the transport was
replaced, all nine disappeared along with more than a hundred lines of concrete
client code.&lt;/p&gt;
&lt;p&gt;The driver did not change, nor did its interface or factory interface. That is
what a narrow collaboration buys: not fewer methods everywhere, but a smaller
answer to “what may this caller rely on?”&lt;/p&gt;</description></item></channel></rss>