<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kostas Perperidis</title>
    <description>The latest articles on DEV Community by Kostas Perperidis (@perpk).</description>
    <link>https://dev.to/perpk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F428010%2F7a317a38-218d-4043-859b-fb0794a8b3dc.jpg</url>
      <title>DEV Community: Kostas Perperidis</title>
      <link>https://dev.to/perpk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/perpk"/>
    <language>en</language>
    <item>
      <title>GitHub Action for creating a custom OWASP dependency check report</title>
      <dc:creator>Kostas Perperidis</dc:creator>
      <pubDate>Sat, 16 Jan 2021 21:40:15 +0000</pubDate>
      <link>https://dev.to/perpk/github-action-for-creating-a-custom-owasp-dependency-check-report-5p3</link>
      <guid>https://dev.to/perpk/github-action-for-creating-a-custom-owasp-dependency-check-report-5p3</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt; can be considered as the building blocks to create automated workflows in GitHub, which definitely is a considerable option if you use GitHub as your code repository.&lt;/p&gt;

&lt;p&gt;In this post we're going to have a look into GitHub Actions and Workflows by defining a workflow and make use of readily available actions from GitHub's marketplace, as well as have a custom action invoked.&lt;/p&gt;

&lt;h2&gt;
  
  
  The example project
&lt;/h2&gt;

&lt;p&gt;We're going to have a look on a few things around the java project which we'll use as the subject of dependency checking. It is available under &lt;a href="https://github.com/perpk/a-vulnerable-project" rel="noopener noreferrer"&gt;https://github.com/perpk/a-vulnerable-project&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;It's best to fork it in order to follow along with the following sections of this guide.&lt;/p&gt;

&lt;p&gt;The project uses &lt;a href="https://gradle.org/" rel="noopener noreferrer"&gt;Gradle&lt;/a&gt; as the build tool. It's build file contains a dependency to an older version of the &lt;a href="https://spring.io/" rel="noopener noreferrer"&gt;Spring Framework&lt;/a&gt;, which happens to have a few vulnerabilities.&lt;/p&gt;

&lt;p&gt;Let's have a look at the project's buildfile.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;

&lt;span class="n"&gt;plugins&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="s1"&gt;'java'&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="s1"&gt;'org.owasp.dependencycheck'&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s1"&gt;'6.0.5'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="s1"&gt;'org.example'&lt;/span&gt;
&lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s1"&gt;'1.0-SNAPSHOT'&lt;/span&gt;

&lt;span class="n"&gt;repositories&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mavenCentral&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;dependencyCheck&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"JSON"&lt;/span&gt;
    &lt;span class="n"&gt;failBuildOnCVSS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;plugins&lt;/code&gt; block contains the plugin we are going to use to perform the dependencies check on our project (&lt;em&gt;Details on gradle plugins can be found &lt;a href="https://plugins.gradle.org/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and the documentation on the plugin is available &lt;a href="https://jeremylong.github.io/DependencyCheck/dependency-check-gradle/index.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;). &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;dependencyCheck&lt;/code&gt; block contains some configuration for the plugin. Here we only want to set the output format which we'll later parse from in our GitHub action and when we want the build to fail. The trigger for this is whether there are any high and above (&lt;em&gt;critical&lt;/em&gt;) vulnerabilities detected. The score according to &lt;a href="https://owasp.org/www-community/OWASP_Risk_Rating_Methodology" rel="noopener noreferrer"&gt;OWASP&lt;/a&gt; technically defines the severity of a vulnerability.&lt;/p&gt;

&lt;p&gt;Now you can create a branch and edit the &lt;code&gt;build.gradle&lt;/code&gt; file by adding a &lt;code&gt;dependencies&lt;/code&gt; block at the bottom like this one&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;

&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;runtime&lt;/span&gt; &lt;span class="nl"&gt;group:&lt;/span&gt; &lt;span class="s1"&gt;'org.springframework'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;name:&lt;/span&gt; &lt;span class="s1"&gt;'spring-core'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;version:&lt;/span&gt; &lt;span class="s1"&gt;'2.0'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;At this point you can give it a shot and run the &lt;code&gt;dependencyCheckAnalyze&lt;/code&gt; task locally via the following command on the root directory of the project.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

./gradlew dependencyCheckAnalyze


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The build will fail since there are vulnerabilities which have scores equal or above the value we set for &lt;code&gt;failBuildOnCVSS&lt;/code&gt; in our &lt;code&gt;build.gradle&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Let's check whether our GitHub Workflow does the same at this point. Push your newly created branch and create a pull request.&lt;/p&gt;

&lt;p&gt;Right after the pull request is created the workflow is started and after a few moments the verdict for the check arrives, which as expected failed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxilb1z61cknjzxvqx34i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxilb1z61cknjzxvqx34i.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking the 'Details' link leads us to a detailed overview of the workflow execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqi2sqp6vdk56nq6v3bad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqi2sqp6vdk56nq6v3bad.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Expanding the step with the error should have the same error in the displayed log as the one you encountered when you ran it locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dissecting the workflow
&lt;/h2&gt;

&lt;p&gt;Now the highlight of the example project, the workflow file. It's a yaml file which can be found under &lt;code&gt;.github/workflows/dependencyCheckReport.yml&lt;/code&gt;. Here's the content and some details below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Java CI with Gradle&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;depCheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up JDK &lt;/span&gt;&lt;span class="m"&gt;1.8&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.8&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eskatos/gradle-command-action@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dependencyCheckAnalyze&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Pretty concise, isn't it? Let's inspect it from top to bottom! &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The 1st block declares when this workflow shall be triggered. Here it is on each pull request which targets the main branch. That makes sense, since we don't want to have security issues on our main branch.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;jobs&lt;/code&gt; block contains all job declarations for the current workflow. For the time being we have just one job, which performs the execution in its entirety. &lt;/li&gt;
&lt;li&gt;A job has one to several steps. In our example we start with a step which uses an existing action from the &lt;a href="https://github.com/marketplace/actions/checkout" rel="noopener noreferrer"&gt;GitHub Marketplace&lt;/a&gt;. The particular action checks out the code from our project from its repository. &lt;/li&gt;
&lt;li&gt;Following the checkout another readily available action is used to setup java. This action also accepts a parameter with the particular version of java to set up.&lt;/li&gt;
&lt;li&gt;At the end, we use another action from the GitHub's marketplace which helps us run Gradle commands. In our scenario, we need to run &lt;code&gt;dependencyCheckAnalyze&lt;/code&gt; to trigger the OWASP analysis on the project's dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Custom Action
&lt;/h2&gt;

&lt;p&gt;For now we have the output of the dependency analysis dumped on stdout. What if we'd like to have a concise report containing all vulnerable dependencies alongside with their vulnerabilities and their severity in a printable format, at best also sorted by severity in descending order?&lt;/p&gt;

&lt;p&gt;If that's what we want, chances are we need to implement something by ourselves and have it called in our workflow.&lt;br&gt;
Here you can also fork this repo &lt;a href="https://github.com/perpk/owasp-report-custom-render" rel="noopener noreferrer"&gt;https://github.com/perpk/owasp-report-custom-render&lt;/a&gt;&lt;br&gt;
where such an action is already implemented.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anatomy of the Action
&lt;/h3&gt;

&lt;p&gt;The centerpiece of the action is the &lt;code&gt;action.yml&lt;/code&gt; file, available at the action's project root directory.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Owasp&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Report&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Custom&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Renderer"&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Render&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;OWASP&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Report&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;few&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;informations&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;as&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;an&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;overview&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pdf"&lt;/span&gt;
&lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;owasp-json-report&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;owasp&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;report&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dependencies&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;their&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;vulnerabilities&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;JSON&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;format"&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;using&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node12"&lt;/span&gt;
  &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;index.js"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Following the name and a general description the inputs of the action are defined. The inputs are named parameters which as we're going to see next are used in the action's source code to retrieve parameters passed from within a workflow.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;runs&lt;/code&gt; block defines the runner for our action. Here we have a &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node.JS&lt;/a&gt; action. The &lt;code&gt;main&lt;/code&gt; keyword defines the file to execute.&lt;/p&gt;

&lt;p&gt;We'll now have a glance at &lt;code&gt;index.js&lt;/code&gt; which implements our entrypoint (so to speak).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@actions/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ... some more imports&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;work&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;owaspReportJsonFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dumpHtmlToFS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;owaspReportData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;owaspJsonReportReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;owaspReportJsonFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createHtmlOverview&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;owaspReportData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dumpHtmlToFS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;writePdfReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFailed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;owasp-json-report&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There's an import of the package &lt;a href="https://www.npmjs.com/package/@actions/core" rel="noopener noreferrer"&gt;&lt;code&gt;@actions/core&lt;/code&gt;&lt;/a&gt; which provides core functions for actions. In the code above, it's used for error handling and to read an input, as visible in the last line. The input we want to read here is the json report as generated by the &lt;code&gt;dependencyCheckAnalyze&lt;/code&gt; Gradle task which is run by the workflow. Our action expects the json report to be available at the same directory as index.js is.&lt;/p&gt;

&lt;p&gt;The action itself will first create the report in HTML and then finally transform it to PDF. There are libraries available to directly generate PDF but I find it more convenient to create a reusable, intermediate format as HTML. I also find it easier to do it this way rather than dealing with the API of a PDF library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Invoking the Action in the Workflow
&lt;/h3&gt;

&lt;p&gt;We now will change our workflow by invoking our action, pass a parameter to it and access its result. &lt;/p&gt;

&lt;p&gt;First we will need to have the json report generated by &lt;code&gt;dependencyCheckAnalyze&lt;/code&gt; at hand, since we want to pass it as a parameter to our action. In order to make it available for the next job in our workflow, we need to have it in the GitHub provided storage. To do so we'll use the action &lt;a href="https://github.com/marketplace/actions/upload-a-build-artifact" rel="noopener noreferrer"&gt;&lt;code&gt;actions/upload-artifact&lt;/code&gt;&lt;/a&gt; from GitHub's marketplace.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Backup JSON Report&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dependency-check-report.json&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./build/reports/dependency-check-report.json&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Adding this snippet to the bottom of our workflow file will invoke the &lt;code&gt;upload-artifact&lt;/code&gt; action which will take the report from the specified path and store it with the given name.&lt;/p&gt;

&lt;p&gt;Then, we need to define another job which shall run after the 1st one has completed. It is necessary to wait since we need the json report to proceed with transforming it to PDF.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

  &lt;span class="na"&gt;owasp_report&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;depCheck&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-20.04&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create a report with an overview of the vulnerabilities per dependency&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Since our action isn't available in the Marketplace, we'll need to check it out from its repository in the first step of the newly created job. As a second step after the checkout, we need to fetch the previously uploaded json report. The path defines where the file shall be downloaded to. In our case it's sufficient to do that in the current directory, which happens to also be the directory where the action's sources are checked out at.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;perpk/owasp-report-custom-render&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/download-artifact@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dependency-check-report.json&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We now can invoke the actual action. This happens via the uses keyword. It must have a reference to the directory where the &lt;code&gt;action.yml&lt;/code&gt; file is located. In our case it's the current directory.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Report Creation&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;owasp-json-report&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dependency-check-report.json&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The last thing to do is to get the PDF report as generated by the action and upload it and thus have it available for further distribution.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload overview report&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Owasp Overview Report&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;owasp-report-overview.pdf&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We now can commit/push our changes to the workflow file, create another pull request and lay back and enjoy the miracle of automation! (slightly exaggerated 😛)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcr49g1uk7d0zdmuf97hp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcr49g1uk7d0zdmuf97hp.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oops! Since we have a condition to fail the build based on the vulnerability score, our report generation job didn't execute at all.&lt;/p&gt;

&lt;p&gt;The solution to that is rather simple. Job execution can be combined with conditions. In our case we'd like to execute the report generation no matter what. To do so, we'll jam in another line right below the &lt;code&gt;needs&lt;/code&gt; keyword in our workflow.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

  &lt;span class="na"&gt;owasp_report&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;depCheck&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;always()&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Since the &lt;code&gt;dependencyCheckAnalyze&lt;/code&gt; step is failing, all subsequent steps aren't executed. Therefore we'll also add the condition to the first step following the failing one.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Backup JSON Report&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;always()&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dependency-check-report.json&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./build/reports/dependency-check-report.json&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That should do the trick and the workflow should succeed.&lt;br&gt;
The entry 'Owasp Overview Report' contains a zip, which includes the generated PDF. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F91j8ljnfq1epdfrarzi4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F91j8ljnfq1epdfrarzi4.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was a brief overview about GitHub Actions and Workflows. Glad to receive some feedback :D Thanks for reading!&lt;/p&gt;

</description>
      <category>security</category>
      <category>github</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
