<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Christopher Catt]]></title><description><![CDATA[Software Engineer.]]></description><link>https://blog.chriscatt.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 12 Apr 2026 23:06:49 GMT</lastBuildDate><atom:link href="https://blog.chriscatt.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[5 Steps to Add Security Foundations to your CI/CD Pipeline]]></title><description><![CDATA[Security can be tough. Most mid to larger size companies will employ dedicated staff just to focus on security of systems and code. However, far too often are these teams understaffed or overworked. Thus, with a rising demand of security professional...]]></description><link>https://blog.chriscatt.com/5-steps-to-add-security</link><guid isPermaLink="true">https://blog.chriscatt.com/5-steps-to-add-security</guid><category><![CDATA[Security]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Christopher Catt]]></dc:creator><pubDate>Thu, 19 Aug 2021 18:02:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1629396083208/qEyLdzRwlf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Security can be tough. Most mid to larger size companies will employ dedicated staff just to focus on security of systems and code. However, far too often are these teams understaffed or overworked. Thus, with a rising demand of security professionals, as well as the increase in popularity of DevOps, DevSecOps was born. DevSecOps aims to 'shift security left' by involving security, operations and dev teams to introduce security measures earlier on within the application lifecycle.  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1622581242989/wo8WYLoOD.png" alt="Shift Left.png" /></p>
<p>In this article, I'll illustrate 5 steps that you can use to start shifting security left, into the build phase of the application lifecycle, in a DevSecOps approach. Within, I focus on using GitHub actions as my choice of CI/CD platform, however these concepts can be lifted and applied to almost any other platform of your choice.</p>
<blockquote>
<p><strong><em>📝 Note:</em></strong> The aim of this article is to be a overview of 5 security practices you can incorporate into your CI/CD process, specifically when building your application. Every application, as well as runtime environment, is different, so this is not a guaranteed guide to security. This article serves as a starting point, where you can then carry out further research. I am not a security professional, however these are all steps I have used in either a professional or personal capacity. </p>
</blockquote>
<h3 id="scanning-for-secrets">🔐 Scanning for Secrets</h3>
<p>When developing applications, there is often an abundance of credentials and secrets that are required within the project. These can range anywhere from AWS credentials for accessing their services (think DynamoDB or Kinesis streams), to API keys for third party API usage and even encryption secrets for entities such as JWT, Cookie and password encryption mechanisms. Due to the sensitive and potentially destructive nature (in the case of a malicious party gaining access to hosting environments/databases) of these secrets, they should not be committed into Git history. Files containing these secrets should be added to a repository <code>.gitignore</code> file to prevent this from happening. </p>
<p>Sometimes, however, these secrets manage to slip into code repositories. As this is a matter of when, not if, it is best to plan ahead and detect these as they are added to the repository, alerting for security visibility and tracking.</p>
<p>The following example makes use of <a target="_blank" href="https://github.com/zricethezav/gitleaks">gitLeaks</a>, however other options include <a target="_blank" href="https://github.com/Skyscanner/whispers">Whispers</a> and <a target="_blank" href="https://github.com/Yelp/detect-secrets">Yelp's Detect-Secrets</a>:</p>
<pre><code class="lang-yml"><span class="hljs-attr">name:</span> <span class="hljs-string">gitleaks</span>

<span class="hljs-attr">on:</span> [ <span class="hljs-string">push</span> , <span class="hljs-string">pull_request</span> ]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">gitleaks:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">fetch-depth:</span> <span class="hljs-string">'2'</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">gitleaks</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">zricethezav/gitleaks-action@master</span>
</code></pre>
<p>Should any secrets make it into the source code (or pre-existing secrets are discovered), the first step that should be carried out is to immediately disable the leaked key. This will prevent any malicious actor from compromising the associated account/service, giving you time to rotate the key and to remove the credential from the repository.</p>
<blockquote>
<p><strong><em>📝 Note:</em></strong> It is also worth noting that secret scanning can also be performed before commiting to a repository, using frameworks such as <a target="_blank" href="https://pre-commit.com/">pre-commit</a> or <a target="_blank" href="https://typicode.github.io/husky/#/">husky</a>, which helps shift security even further left and would be a preferred solution. However everyone's development environment is different and as such this is not always an option, but it is worth digging into.</p>
</blockquote>
<h3 id="linting-code">📄 Linting Code</h3>
<p>Linting code is the process of statically scanning code for errors such as styling or syntactical issues, to better organize and secure your application. By ensuring code follows secure standards and is formatted in a sensible fashion, repositories become easier to maintain and to detect errors (such as memory leaks or other vulnerabilities) which could compromise your application. Having a standardized styling pattern can bring other benefits too, such as a better understanding/collaboration process on the codebase and an easier debugging experience. This is a good, quick first scan that can be run to help increase security and efficiency within your pipeline, however it is not always mandatory.</p>
<p>In this snippet, <a target="_blank" href="https://github.com/marketplace/actions/hadolint-action">Hadolint</a>, a Dockerfile linter, is used to ensure standards are maintained. One such standard that Hadolint searches for, is the versioning of applications installed within containers from package managers. This is an important, lesser known tip that helps to keep maintainability, preventing Docker builds from breaking between machines because of an unknown package version upgrade. For alternatives, check out the documentation for <a target="_blank" href="https://github.com/github/super-linter">GitHub's Super-Linter</a>, which houses linters for various programming languages. </p>
<pre><code class="lang-yml"><span class="hljs-attr">name:</span> <span class="hljs-string">Hadolint</span>

<span class="hljs-attr">on:</span> [ <span class="hljs-string">push</span>, <span class="hljs-string">pull_request</span> ]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">hadolint:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span> 

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">hadolint</span> 
        <span class="hljs-attr">uses:</span> <span class="hljs-string">hadolint/hadolint-action@v1.5.0</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">dockerfile:</span> <span class="hljs-string">Dockerfile</span>
</code></pre>
<h3 id="scanning-for-known-vulnerable-components">😒 Scanning for Known Vulnerable Components</h3>
<p>Scanning for known vulnerable components, aka insecure dependencies, is a big step in reducing the potential attack vector within your application. With some applications requiring hundreds, if not thousands of dependencies (once factoring the entire dependency tree), a compromise within one could leave your application wide open to attack. The good thing, however, is that there are several tools that can be used to identify any insecure dependencies within your application, with some even generating the fixes required for you.</p>
<p><a target="_blank" href="https://dependabot.com/">Dependabot</a> is a tool directly integrated into GitHub code repositories, allowing for a configurable dependency scanning experience, with scans being able to run for multiple different package managers across multiple languages, all in the same repository. Upon detecting of a vulnerable dependency, Dependabot will then automatically open a pull request against the codebase, bumping the dependency to a fixed/secure version, without the need for a developer to carry out the upgrade.</p>
<pre><code class="lang-yml"><span class="hljs-comment"># Basic set up for two package managers</span>

<span class="hljs-attr">version:</span> <span class="hljs-number">2</span>
<span class="hljs-attr">updates:</span>

  <span class="hljs-bullet">-</span> <span class="hljs-attr">package-ecosystem:</span> <span class="hljs-string">"github-actions"</span>
    <span class="hljs-attr">directory:</span> <span class="hljs-string">"/"</span>
    <span class="hljs-attr">schedule:</span>
      <span class="hljs-attr">interval:</span> <span class="hljs-string">"weekly"</span>
    <span class="hljs-attr">labels:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"actions"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"dependencies"</span>

  <span class="hljs-bullet">-</span> <span class="hljs-attr">package-ecosystem:</span> <span class="hljs-string">"npm"</span>
    <span class="hljs-attr">directory:</span> <span class="hljs-string">"/"</span> 
    <span class="hljs-attr">schedule:</span>
      <span class="hljs-attr">interval:</span> <span class="hljs-string">"daily"</span>
    <span class="hljs-attr">labels:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"npm"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"dependencies"</span>
    <span class="hljs-attr">open-pull-requests-limit:</span> <span class="hljs-number">10</span>
</code></pre>
<p>If, instead, you would prefer a tool that you can use locally, as well as between different CI/CD providers (e.g. if in a larger, segmented organization), then I would recommend checking out <a target="_blank" href="https://owasp.org/www-project-dependency-check/">Dependency Check</a>, as it is backed by the <a target="_blank" href="https://owasp.org/">Open Web Application Security Project (OWASP)</a>. </p>
<h3 id="run-sast-scans">🔎 Run SAST Scans</h3>
<p>Static Application Security Testing, or SAST, is similar running a code linter. It scans your codebase, looking for known or custom patterns and reporting on the findings. However, where SAST differs is that instead of looking for potential styling or syntax errors, scans are run to detect insecure code. These scans commonly use pre-defined rules from industry professionals to run, with some options going the extra mile to provide links to resources explaining the risk of the issues detected. By nature, SAST scans are not context aware, so if you have addressed the security concerns to do with detected snippets elsewhere, the scan will still report a false-positive result. However, these false-positives can be an eye opener into the architectural decisions as to why these vulnerable code-snippets are in the code base, regardless of the security measures put in place. After all, even after adding layers of security, should you really be calling <code>dangerouslySetInnerHTML</code>? 🤔</p>
<p>One such SAST tool is <a target="_blank" href="https://semgrep.dev/">Semgrep</a>. Semgrep allows you to hand-pick the rules to run on the code, or alternatively to use a pre-defined collection of rules (rulesets) tailored to specific languages and/or security topics. With over 1400 rules, at the time of writing, these can be explored <a target="_blank" href="https://semgrep.dev/r">here</a>.</p>
<pre><code class="lang-yml"><span class="hljs-attr">name:</span> <span class="hljs-string">Semgrep</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-comment"># Scan changed files in PRs</span>
  [ <span class="hljs-string">pull_request</span> ] 
  <span class="hljs-comment"># Scan all files on branch</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> 
      <span class="hljs-bullet">-</span> <span class="hljs-string">"main"</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">semgrep:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-comment"># Skip any PR created by dependabot to avoid permission issues</span>
    <span class="hljs-attr">if:</span> <span class="hljs-string">(github.actor</span> <span class="hljs-type">!=</span> <span class="hljs-string">'dependabot[bot]'</span><span class="hljs-string">)</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">semgrep</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">returntocorp/semgrep-action@v1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">auditOn:</span> <span class="hljs-string">push</span> <span class="hljs-comment"># Never fail the build due to findings on push</span>
          <span class="hljs-attr">config:</span> <span class="hljs-string">&gt;- 
            p/security-audit
            p/nodejsscan
            p/expressjs            
</span>        <span class="hljs-attr">env:</span>
          <span class="hljs-attr">SEMGREP_TIMEOUT:</span> <span class="hljs-number">300</span>
</code></pre>
<h3 id="collect-information-and-act-on-it">🤔 Collect Information and Act on it</h3>
<p>Finally, after performing any of these steps the most important thing to do is to act on the findings. This is crucial to ensuring the security of applications, as without acting on disclosures the whole process becomes a zero sum equation. If you find a leaked secret, or an insecure dependency, fixing it could be the difference between the application carrying on as normal and data loss/breach of GDPR - <a target="_blank" href="https://www.tessian.com/blog/biggest-gdpr-fines-2020/">which could incur eye-watering fines if this occurs with Personally Identifiable Information (PII)</a>.</p>
<h3 id="tldr">📎 TL;DR</h3>
<p>In summary, some of the key ways of introducing security (along with stability and visibility) into CI/CD can be achieved by introducing the following to your procedures and pipelines:</p>
<ul>
<li>Scan for hard-coded secrets</li>
<li>Lint for inconsistent syntax and code styling</li>
<li>Search out insecure dependencies to reduce your surface area of attack</li>
<li>Test for insecure code within your repository with SAST tools  </li>
<li>Act on your findings</li>
</ul>
<p>There is always more that can be done to improve security (such as environment scanning, DAST scanning, etc), however by introducing some basics, you are setting off in a good direction.</p>
]]></content:encoded></item><item><title><![CDATA[Jest: Mocking With AWS SDK V3]]></title><description><![CDATA[The recent V3 update to AWS's JavaScript SDK has introduced a number of benefits to developers, especially when it comes to bundle sizes and modularity. No longer are the days of having to import all operations related to DynamoDB just to put an item...]]></description><link>https://blog.chriscatt.com/jest-mocking-with-aws-sdk-v3</link><guid isPermaLink="true">https://blog.chriscatt.com/jest-mocking-with-aws-sdk-v3</guid><category><![CDATA[Jest]]></category><category><![CDATA[Testing]]></category><category><![CDATA[AWS]]></category><category><![CDATA[DynamoDB]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Christopher Catt]]></dc:creator><pubDate>Sun, 14 Feb 2021 21:51:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613325478097/iUPZFMDEQ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The recent V3 update to AWS's JavaScript SDK has introduced a number of benefits to developers, especially when it comes to bundle sizes and modularity. No longer are the days of having to import all operations related to DynamoDB just to put an item into a database. However, in AWS's refactored solution, it has become less clear to some how to properly mock these new modules. This quick article hopes to alleviate this issue, showing one way that makes mocking <a target="_blank" href="https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/welcome.html"><code>@aws-sdk</code></a> client libraries a breeze.</p>
<h3 id="setting-up-the-test-environment">🛠 Setting up the Test Environment</h3>
<blockquote>
<p><strong><em>📝 Note:</em></strong> The aim of this article is to be a quick demo of mocking the <code>@aws-sdk</code>, not a Jest integration overview. As such, I will not be going into the internals of Jest. You can do that <a target="_blank" href="https://jestjs.io/docs/en/api">here</a>.</p>
</blockquote>
<p>Before starting, make sure that you have Jest and any AWS modules that you plan to test with, installed. In this article, I will be using the DynamoDB client, however this works with any clients that make use of the <code>send()</code> function for their operations.</p>
<pre><code><span class="hljs-built_in">npm</span> install jest @aws-sdk/client-dynamodb
</code></pre><p>As standard, add the following to your <code>package.json</code> file</p>
<pre><code><span class="hljs-section">scripts: {</span>
    <span class="hljs-comment"># Rest of your scripts go here...</span>
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"jest"</span>,
}
</code></pre><p>As a demo, I will setup a file which I wish to test: <code>dynamoDBController.js</code>. For simplicity, this file will only contain one method: <code>PutItem()</code>. The base code for this is as follows:</p>
<pre><code><span class="hljs-comment">// dynamoDBController.js</span>

<span class="hljs-keyword">const</span> { 
  DynamoDBClient, 
  PutItemCommand 
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@aws-sdk/client-dynamodb"</span>);

<span class="hljs-keyword">const</span> dynamoDBClient = <span class="hljs-keyword">new</span> DynamoDBClient({ region: <span class="hljs-string">"local"</span> });

<span class="hljs-keyword">const</span> PutItem = <span class="hljs-keyword">async</span> (params) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> dynamoDBClient.send(<span class="hljs-keyword">new</span> PutItemCommand(params));
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">return</span> { statusCode: <span class="hljs-number">500</span> };
  }
};

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = { PutItem };
</code></pre><h3 id="enabling-mocking-of-aws-modules">🛠 Enabling Mocking of AWS Modules</h3>
<p>Once setup, one minor refactor to the existing code unlocks the ease of mocking. By refactoring the client initialization into a separate file, it becomes easy to mock the AWS module. In the current example, I will add a file <code>aws.js</code> to setup the DynamoDB client:</p>
<pre><code><span class="hljs-comment">// aws.js</span>

<span class="hljs-keyword">const</span> { DynamoDBClient } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@aws-sdk/client-dynamodb"</span>);

<span class="hljs-keyword">const</span> dynamoDBClient = <span class="hljs-keyword">new</span> DynamoDBClient({
  region: <span class="hljs-string">"local"</span>,
});

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = { dynamoDBClient };
</code></pre><p>And the minor adjustment to <code>dynamoDBController.js</code>:</p>
<pre><code><span class="hljs-comment">// updated dynamoDBController.js</span>

<span class="hljs-keyword">const</span> { PutItemCommand } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@aws-sdk/client-dynamodb"</span>);
<span class="hljs-keyword">const</span> { dynamoDBClient } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./aws"</span>);

<span class="hljs-keyword">const</span> PutItem = <span class="hljs-keyword">async</span> (params) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> dynamoDBClient.send(<span class="hljs-keyword">new</span> PutItemCommand(params));
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">return</span> { statusCode: <span class="hljs-number">500</span> };
  }
};

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = { PutItem };
</code></pre><p>This small change separates the external dependency initialization from the actual usage of the module, breaking up this operation into separate units, making it easier to mock and test.</p>
<h3 id="mocking-and-testing-aws-modules">🛠 Mocking and Testing AWS Modules</h3>
<p>Now that the DynamoDB module has been setup for mocking, it's time to create the test file. In a new <code>dynamoDBController.test.js</code> file, import both the local method to test as well as the initialized <code>dynamoDBClient</code>:</p>
<pre><code><span class="hljs-comment">// dynamoDBController.test.js</span>

<span class="hljs-keyword">const</span> { PutItem } = <span class="hljs-keyword">require</span>(<span class="hljs-string">"./dynamoDBController"</span>);
<span class="hljs-keyword">const</span> { dynamoDBClient } = <span class="hljs-keyword">require</span>(<span class="hljs-string">"./aws"</span>);
</code></pre><p>Using the Jest <code>mock</code> function, we can add the following line to mock DynamoDB module:</p>
<pre><code><span class="hljs-selector-tag">jest</span><span class="hljs-selector-class">.mock</span>(<span class="hljs-string">"./aws.js"</span>);
</code></pre><p>Now we can move onto writing the actual tests. As we are mocking the initialized client, we have access to the exposed client <code>send()</code> function, allowing us to intercept the fundamental DynamoDB call used within the <code>PutItem()</code> function. Within our test, we can intercept this call and return our own test value, by using the following command:</p>
<pre><code><span class="hljs-selector-tag">dynamoDBClient</span><span class="hljs-selector-class">.send</span><span class="hljs-selector-class">.mockResolvedValue</span>({ <span class="hljs-attribute">isMock</span>: true });
</code></pre><p>We can now write the rest of the test and call the <code>PutItem()</code> command as normal. The rest of the test is as follows:</p>
<pre><code>describe(<span class="hljs-string">"@aws-sdk/client-dynamodb mock"</span>, () =&gt; {
  it(<span class="hljs-string">"should successfully mock dynamoDBClient"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    dynamoDBClient.send.mockResolvedValue({ isMock: <span class="hljs-keyword">true</span> });

    <span class="hljs-keyword">const</span> params = {
      TableName: <span class="hljs-string">"CUSTOMER"</span>,
      Item: {
        CUSTOMER_ID: { N: <span class="hljs-string">"001"</span> },
        CUSTOMER_NAME: { S: <span class="hljs-string">"Richard Roe"</span> },
      },
    };

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> PutItem(params);

    expect(response.isMock).toEqual(<span class="hljs-keyword">true</span>);
  });
});
</code></pre><p>Running <code>npm test</code> now will result in a successful test run.</p>
<pre><code><span class="hljs-string">&gt;</span> <span class="hljs-string">jest</span>

 <span class="hljs-string">PASS</span>  <span class="hljs-string">./dynamoDBController.test.js</span>
  <span class="hljs-string">@aws-sdk/client-dynamodb</span> <span class="hljs-string">mock</span>
    <span class="hljs-string">√</span> <span class="hljs-string">should</span> <span class="hljs-string">successfully</span> <span class="hljs-string">mock</span> <span class="hljs-string">dynamoDBClient</span> <span class="hljs-string">(2</span> <span class="hljs-string">ms)</span>

<span class="hljs-attr">Test Suites:</span> <span class="hljs-number">1</span> <span class="hljs-string">passed,</span> <span class="hljs-number">1</span> <span class="hljs-string">total</span>
<span class="hljs-attr">Tests:</span>       <span class="hljs-number">1</span> <span class="hljs-string">passed,</span> <span class="hljs-number">1</span> <span class="hljs-string">total</span>
<span class="hljs-attr">Snapshots:</span>   <span class="hljs-number">0</span> <span class="hljs-string">total</span>
<span class="hljs-attr">Time:</span>        <span class="hljs-number">2.307</span> <span class="hljs-string">s,</span> <span class="hljs-string">estimated</span> <span class="hljs-number">3</span> <span class="hljs-string">s</span>
<span class="hljs-string">Ran</span> <span class="hljs-string">all</span> <span class="hljs-string">test</span> <span class="hljs-string">suites.</span>
</code></pre><p>As the <code>PutItem()</code> function also accounts for and thrown errors, it is also possible to fully test this by using the <code>mockRejectedValue()</code> function. A test demonstrating this is documented below:</p>
<pre><code>  it(<span class="hljs-string">"should throw error and return 500 status code"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    dynamoDBClient.send.mockRejectedValue(<span class="hljs-keyword">new</span> Error(<span class="hljs-string">"Async error"</span>));

    <span class="hljs-keyword">const</span> <span class="hljs-keyword">params</span> = {
      TableName: <span class="hljs-string">"CUSTOMER"</span>,
      Item: {
        CUSTOMER_ID: { N: <span class="hljs-string">"001"</span> },
        CUSTOMER_NAME: { S: <span class="hljs-string">"Richard Roe"</span> },
      },
    };

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> PutItem(<span class="hljs-keyword">params</span>);

    expect(response.statusCode).toEqual(<span class="hljs-number">500</span>);
  });
</code></pre><p>Running <code>npm test</code> now will yield two successful tests:</p>
<pre><code><span class="hljs-string">&gt;</span> <span class="hljs-string">jest</span>

 <span class="hljs-string">PASS</span>  <span class="hljs-string">./dynamoDBController.test.js</span>
  <span class="hljs-string">@aws-sdk/client-dynamodb</span> <span class="hljs-string">mock</span>
    <span class="hljs-string">√</span> <span class="hljs-string">should</span> <span class="hljs-string">successfully</span> <span class="hljs-string">mock</span> <span class="hljs-string">dynamoDBClient</span> <span class="hljs-string">(2</span> <span class="hljs-string">ms)</span>
    <span class="hljs-string">√</span> <span class="hljs-string">should</span> <span class="hljs-string">throw</span> <span class="hljs-string">error</span> <span class="hljs-string">and</span> <span class="hljs-string">return</span> <span class="hljs-number">500</span> <span class="hljs-string">status</span> <span class="hljs-string">code</span> <span class="hljs-string">(2</span> <span class="hljs-string">ms)</span>

<span class="hljs-attr">Test Suites:</span> <span class="hljs-number">1</span> <span class="hljs-string">passed,</span> <span class="hljs-number">1</span> <span class="hljs-string">total</span>
<span class="hljs-attr">Tests:</span>       <span class="hljs-number">2</span> <span class="hljs-string">passed,</span> <span class="hljs-number">2</span> <span class="hljs-string">total</span>
<span class="hljs-attr">Snapshots:</span>   <span class="hljs-number">0</span> <span class="hljs-string">total</span>
<span class="hljs-attr">Time:</span>        <span class="hljs-number">3.529</span> <span class="hljs-string">s</span>
<span class="hljs-string">Ran</span> <span class="hljs-string">all</span> <span class="hljs-string">test</span> <span class="hljs-string">suites.</span>
</code></pre><h3 id="preventing-race-conditions-and-mock-data-leakage-in-your-tests">🛠 Preventing Race Conditions and Mock Data Leakage in your Tests</h3>
<p>If your tests are sending multiple call to the mocked AWS modules, it is good practice to add a Jest call to the <code>beforeEach()</code> so that any mocked return values can be reset before each test. This lets you dynamically code different responses for each individual test, as well as preventing test data leakage and race conditions. To do this, simply append the following snippet before the start of your test blocks:</p>
<pre><code>beforeEach(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
  dynamoDBClient.send.mockReset();
});
</code></pre><h3 id="conclusion">🤔 Conclusion</h3>
<p>The V3 update to the AWS JavaScript SDK is great. It reduces bundle sizes and increases modularity. Upgrading to it is great for developers and packages. Refactoring existing tests for methods moving this new major version does not have to be hard, especially when you embrace the modular first approach of the new SDK. </p>
]]></content:encoded></item><item><title><![CDATA[Docker Security - What I Learned From Creating My First Full-Stack App After University]]></title><description><![CDATA[The One Thing That University Didn't Teach 🤔
Docker. It's everywhere. From hosting simple applications to running the micro-services required by your favorite streaming platforms. This magical technology unfortunately did not make the cut for the Un...]]></description><link>https://blog.chriscatt.com/docker-security-what-i-learned-from-creating-my-first-full-stack-app-after-university</link><guid isPermaLink="true">https://blog.chriscatt.com/docker-security-what-i-learned-from-creating-my-first-full-stack-app-after-university</guid><category><![CDATA[Docker]]></category><category><![CDATA[Security]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Junior developer ]]></category><dc:creator><![CDATA[Christopher Catt]]></dc:creator><pubDate>Mon, 10 Aug 2020 19:47:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1597087698847/XDr3w_5L-.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="the-one-thing-that-university-didn-t-teach-">The One Thing That University Didn&#39;t Teach 🤔</h3>
<p>Docker. It&#39;s everywhere. From hosting simple applications to running the micro-services required by your favorite streaming platforms. This magical technology unfortunately did not make the cut for the University course I attended. As such, it has been my hobby to containerize and manage small applications in the effort to help me learn more about this technology. I have personally run into each of following Docker security conundrums and have learnt by developing and experimenting, as most junior developers should. </p>
<h3 id="problem-1-vulnerabilities">Problem #1 - Vulnerabilities</h3>
<p>After developing my first full-stack app with Node.js, I naturally decided that I would bundle and containerize the application to allow for better portability and distribution. So the first thing I wrote, much like many other developers, is the conventional <code>FROM node</code>.</p>
<p>Did you see the problem? No? Neither did I at first, but the people at <a target='_blank' rel='noopener'  href="https://snyk.io/">Snyk</a> did. By using the <code>node</code> base image, I had inadvertently inherited a large number of pre-existing vulnerabilities found within the base image. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1597078122646/BdLr41ztH.png" alt="Number of OS Vulnerabilities by Docker Image"></p>
<h3 id="solution-">Solution ✔</h3>
<p>By changing to a more secure base image, such as <code>ubuntu</code>, instantly the number or vulnerabilities drop dramatically. Taking the <code>node</code> image for example, by simply building Node from source within a Ubuntu 20.04 base, the number of vulnerabilities shoot down from nearly 600, to a small amount of only 23 (as report by Snyk).
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1597079794840/_Ond3LlJM.png" alt="Vulnerabilities Found By Snyk Using a Ubuntu Base Image"></p>
<p>This can be achieved simply, using the following as a baseline for your Dockerfile:</p>
<pre><code>FROM ubuntu:latest

# <span class="hljs-keyword">Install</span> Node.js <span class="hljs-keyword">and</span> dependencies
RUN apt-<span class="hljs-keyword">get</span> <span class="hljs-keyword">update</span> -yq \
    &amp;&amp; apt-<span class="hljs-keyword">get</span> <span class="hljs-keyword">install</span> curl gnupg -yq \
    &amp;&amp; curl -sL https://deb.nodesource.com/setup_14.x | bash \
    &amp;&amp; apt-<span class="hljs-keyword">get</span> <span class="hljs-keyword">install</span> nodejs -yq 

# Copy <span class="hljs-keyword">and</span> Setup App
WORKDIR /app
COPY . /app
RUN npm <span class="hljs-keyword">install</span>

# Expose Port <span class="hljs-keyword">and</span> Run 
EXPOSE <span class="hljs-number">5000</span>
CMD [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"start"</span>]
</code></pre><h3 id="problem-2-execution-within-a-container">Problem #2 - Execution Within A Container</h3>
<p>The next problem that arises is the use of the <em>Root</em> user within a Docker container. By default, if a user is not specified, commands executed within a container (as well as running applications within the container) are run as root. This opens up vulnerabilities that could <em>potentially</em> give backdoor root access into the host system 🙅‍♂️. You don&#39;t need to be a security expert to see how bad this can be.</p>
<h3 id="solution-">Solution ✔</h3>
<p>By utilizing the <code>USER</code> directive, you can easily create and swap to a <em>less-privileged</em> user to execute the application. It is best to do this near the end of the Dockerfile, allowing for the application to be set up correctly (without any file permission errors). Using the Dockerfile described previously, this would look like the following:</p>
<pre><code>
...

# Copy and Setup App
WORKDIR /app
COPY . /app
RUN npm <span class="hljs-keyword">install</span>

# Expose Port 
EXPOSE <span class="hljs-number">5000</span>

# <span class="hljs-keyword">Create</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">Change</span> <span class="hljs-keyword">to</span> <span class="hljs-keyword">User</span> <span class="hljs-string">'app'</span> <span class="hljs-keyword">and</span> Run
<span class="hljs-keyword">USER</span> app
CMD [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"start"</span>]
</code></pre><h3 id="problem-3-saving-files-to-host">Problem #3 - Saving Files to Host</h3>
<p>So you&#39;ve used a more secure base image and swapped to a less-privileged user, but you want to write data to the host to persist across the container life-cycle, such as configuration data? No problem, you just specify a <strong>Bind Mount</strong> or <strong>Volume</strong> by using the <code>docker run -v</code> command. Simple.</p>
<p>But wait. We&#39;ve swapped to a less-privileged user that doesn&#39;t have write permission to the host machine. How do we perform this simple operation now, without risking the security of the application? This was a question that I was stuck on for a good deal of time when containerizing my application. Until I found a helpful answer on Stack Overflow.</p>
<h3 id="solution-">Solution ✔</h3>
<p>This <a target='_blank' rel='noopener'  href="https://stackoverflow.com/a/29799703">answer</a>, written by Dimitris, kindly explains that the docker container should fix any file permissions for mounted directories, before running the application, and points towards the implementation of the <a target='_blank' rel='noopener'  href="https://github.com/docker-library/redis">Reddis Docker container</a>. From instecting this repository (along with some further reading), it became clear the power of the <code>ENTRYPOINT</code> command. By using the entrypoint of the Dockerfile to run a script, instead of running the application, the container can be started with directories mounted (make note, this is key), with operations being performed immediately before application start. </p>
<p>Say you have a configuration folder within the container at <code>/app/config</code>, the Dockerfile to achieve this, based on the previous <code>ubuntu</code> image generated, is as follows:</p>
<pre><code>FROM ubuntu:latest

# Add User/Group 'app'
RUN groupadd -r app \
    &amp;&amp; useradd -r -s /bin/false -g app app 

# <span class="hljs-keyword">Install</span> Node.js <span class="hljs-keyword">and</span> dependencies
RUN apt-<span class="hljs-keyword">get</span> <span class="hljs-keyword">update</span> -yq \
    &amp;&amp; apt-<span class="hljs-keyword">get</span> <span class="hljs-keyword">install</span> curl gnupg gosu -yq \
    &amp;&amp; curl -sL https://deb.nodesource.com/setup_14.x | bash \
    &amp;&amp; apt-<span class="hljs-keyword">get</span> <span class="hljs-keyword">install</span> nodejs -yq \
    &amp;&amp; chown -R app:app /app

# Copy <span class="hljs-keyword">and</span> Setup App
WORKDIR /app
VOLUME /app/config
COPY . /app
RUN npm <span class="hljs-keyword">install</span> \
    &amp;&amp; chmod +x docker-entrypoint.sh

ENTRYPOINT [<span class="hljs-string">"./docker-entrypoint.sh"</span>]

EXPOSE <span class="hljs-number">5000</span>
CMD [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"start"</span>]
</code></pre><p>To note, the new internal user must be created at the beginning of the file, using the base image OS&#39;s way of creating a user, to ensure permissions are handled successfully. Also, <code>gosu</code> is installed to handle the step-down to the less-privileged user. The contents of the <code>docker-entrypoint.sh</code> are found below:</p>
<pre><code><span class="hljs-meta">#!/bin/bash
</span>
<span class="hljs-comment"># Exit if a process exits with an error code</span>
<span class="hljs-built_in">set</span> <span class="hljs-_">-e</span>

<span class="hljs-comment"># if 'CMD' Directive in Dockerfile begins with 'npm'</span>
<span class="hljs-keyword">if</span> [ <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span> = <span class="hljs-string">'npm'</span> ]; <span class="hljs-keyword">then</span>

    <span class="hljs-comment"># Make Owner of Configuration Folder/Files Newly Created User</span>
    chown -R app:app /app/config

    <span class="hljs-comment"># Optional</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Finished Fixing Permissions"</span>

    <span class="hljs-comment"># Change User to 'app' and Run 'CMD' in Dockerfile</span>
    <span class="hljs-built_in">exec</span> gosu app <span class="hljs-string">"<span class="hljs-variable">$@</span>"</span>

<span class="hljs-keyword">fi</span>

<span class="hljs-comment"># Change Process to PID 1 for Monitoring</span>
<span class="hljs-built_in">exec</span> <span class="hljs-string">"<span class="hljs-variable">$@</span>"</span>
</code></pre><p>Breaking down the file above, the following functionality is achieved:</p>
<ul>
<li>Checks if the <code>CMD</code> directive within the Dockerfile begins with &#39;npm&#39;. This allows for the potential of different flows for different environments, e.g. <code>Development</code> or <code>Production</code></li>
<li>Changes the now <strong>mounted</strong>  configuration folders&#39; permissions to the &#39;app&#39; user we created earlier, enabling write permissions to the mounted host folder (remember, the folder was mounted within the Dockerfile. This script executes when the container has just started, not on build or extraction)</li>
<li>Uses <code>gosu</code> to change user to that of &#39;app&#39; and execute the Dockerfiles&#39; <code>CMD</code> directive as this user (hence, the application is run as &#39;app&#39;)</li>
</ul>
<p>By using the <code>docker-entrypoint.sh</code> script, the <strong>mounted</strong> configuration folder has it&#39;s ownership changed to the created user, with the application run as said user. This allows the application to write files to the configuration folder to the host machine, without any permissions errors. Allowing for the storage of vital data, without compromising the security of the host/Docker container.</p>
<h3 id="the-takeaway">The Takeaway</h3>
<p>There are may ways in which one can improve the security of Docker containers, for the benefit of both the host and the container itself. These are only the initial steps anyone should take to help lock-down their container, with a main point to ensure security being enforcing correct security guidelines when developing the application itself. The container could be the <em>Fort Knox</em> of containers, yet with application code not being developed securely, security risks are still a very big possibility.</p>
]]></content:encoded></item></channel></rss>