Creating Liquid Gateway Themes

This page contains:

The structure of a theme

The theme that you upload to Dradis (more on that later) will be in the form of a zip file. Inside that zip file will be a folder called theme with the subfolder structure seen below.

For the sake of this guide, we will focus mostly on the two Liquid files, application.liquid and show.liquid. These files are essentially HTML files with Liquid Drops (dynamic content) added in. Once you think of the Liquid files as HTML, you should be able to use the CSS and JavaScript files as normal.

The application.liquid file from the layouts subfolder controls the header, navbar, and footer content for your Gateway layout. It likely won't contain many drops, maybe a team name or a project name. But, it will contain one important drop: {{ content_for_layout }}. This drop is where all of the more detailed project information inside of show.liquidfrom inside the templates > projects subfolder will be displayed.

Theme information

The other important file is the settings_schema.json file from the config subfolder. This file controls the values (like the theme name) that you'll see when you upload the theme to your instance.

[
  {
    "theme_info": {
      "author": "James Tiberius Kirk",
      "name": "My Brand New Theme Name",
      "version": "1.2.3"
    }
  }
]

The values for author, name, and version can be changed as needed.

Liquid Drops

Like we just discussed, Liquid Drops are the way that you can insert dynamic content from your Dradis instance into the HTML template. Drops use the {{ }} syntax. So, if you open up any of the Liquid files from your theme, everything inside {{ }} are drops.

We have drops available for most content types inside of your Dradis project:

Conditionals

You can use Liquid to create if statements in projects. For example, if you use multiple templates and your project content has to suit several of them at once, for example for multiple languages, then you can use a conditional like this:

{% if document_properties.dradis.lang == 'en' %}
#[Title]#
Testing

#[Description]#
This is a test
{% elsif document_properties.dradis.lang == 'fr' %}
#[Title]#
Essai

#[DescriptionFR]#
C'est un test
{% endif %}

In the example above, if the dradis.lang document property is set to en then the project will export in English; if it is set to fr it will export in French.

Content Blocks

Content Blocks are found on the Report Content page of your project.

The following drops are available:

{{ content_block.author }}
{{ content_block.block_group }}
{{ content_block.content }}
{{ content_block.fields['Field Name'] }}

Here's an example to include a specific Content Block in your Gateway layout:

{% for content_block in content_blocks %}
  {% if content_block.fields contains 'Type' and content_block.fields['Type'] == 'Conclusions' %}
    {% if content_block.fields contains 'Title' %}
      {{ content_block.fields['Title'] }}
    {% else %}
      <p>Title field is missing</p>
    {% endif %}

    {% if content_block.fields contains 'Description' %}
      {{ content_block.fields['Description'] | markup }}
    {% else %}
      <p>Description field is missing</p>
    {% endif %}
  {% endif %}
{% endfor %}

Deliverables

Deliverables are files that can be uploaded to Gateway and made available to your Contributors for download.

The following drops are available:

{{ deliverable.byte_size }}
{{ deliverable.created_at }}
{{ deliverable.filename }}
{{ deliverable.id }}
{{ deliverable.type }}
{{ deliverable.url }}

Here's an example that makes the deliverables available for download:

{% if deliverables.size > 0 %}
  {% for deliverable in deliverables %}
    <a href="{{ deliverable.url }}">{{ deliverable.filename }}</a>
  {% endfor %}
{% else %}
  <p>There are no deliverables uploaded for this project yet.</p>
{% endif %}

Document Properties

Document Properties are found on the Report Content page of your project.

The following drops are available:

{{ document_properties.dradis.example }}

For example, if you have a Document Property called dradis.client, you can pull it into your Gateway layout with the following syntax:

{% if document_properties.available_properties contains 'dradis.client' %}
  <p>{{ document_properties.dradis.client }}</p>
{% else %}
  <p>No dradis.client document property defined</p>
{% endif %}

Evidence

Evidence contain details that change from one instance of the Issue to the next: port number, specific versions, output of tools (e.g. the list of SSL ciphers, etc.). For more on Issues vs Evidence, please check out the Adding Issues and Evidence guide.

The following drops are available:

{{ evidence.content }}
{{ evidence.fields['Field Name'] }}
{{ evidence.id }}
{{ evidence.issue }}
{{ evidence.title }}

Evidence cannot be accessed on their own. For example {% for e in evidence %} won't work but {% for e in issue.evidence %} and {% for e in node.evidence %} will work when iterating through issues or nodes respectively.

To show a count of Evidence for a specific Issue:

{% if issues.size > 0 %}
  {% for issue in issues %}
    <p>{{ issue.title }} has {{ issue.evidence.size }} instances of Evidence</p>
  {% endfor %}
{% else %}
  <p>There are no issues for this project yet.</p>
{% endif %}

To show the content of your Evidence (by Node):

{% if nodes.size > 0 %}
  {% assign evidence_count = 0 %}
  {% for node in nodes %}
    {% for evidence in node.evidence %}
      {% assign evidence_count = evidence_count | plus: 1 %}
      <p>{{ node.label }}</p>
      <p>{{ evidence.content | markup }}</p>
    {% endfor %}
  {% endfor %}
  {% if evidence_count < 1 %}
    <p>There is no evidence for any of the nodes yet.</p>
  {% endif %}
{% else %}
  <p>There are no nodes for this project yet.</p>
{% endif %}

Issues

Issues are specific vulnerabilites in your project. Evidence can be associated with each Issue. For more on Issues vs Evidence, please check out the Adding Issues and Evidence guide.

The following drops are available:

{{ issue.affected }}
{{ issue.evidence }}
{{ issue.fields['Field Name'] }}
{{ issue.id }}
{{ issue.tags }}
{{ issue.text }}
{{ issue.title }}

To show all of the Issues in your project with their content:

{% if issues.size > 0 %}
  {% for issue in issues %}
    <h1>{{ issue.title }}</h1>
    <p>Affected Hosts:</p>
    <ul>
      {% for affected in issue.affected %}
        <li>{{ affected.label }}</li>
      {% endfor %}
    </ul>
    <p>{{ issue.text | markup }}</p>
  {% endfor %}
{% else %}
  <p>There are no issues for this project yet.</p>
{% endif %}

To display just one specific Issue field:

{% if issues.size > 0 %}
  {% for issue in issues %}
    {% if issue.fields contains 'Description' %}
      {{ issue.fields['Description'] | markup }}
    {% else %}
      <p>Description field is missing</p>
    {% endif %}
  {% endfor %}
{% else %}
  <p>There are no issues for this project yet.</p>
{% endif %}

Comments

Comments are added to pieces of data inside of your Dradis project. Currently, you can display Issue comments in your Gateway themes. Your contributors will be able to see any public comments and leave their own.

The following drops are available:

{{ comments issue }}

To show the comments for each Issue:

{% if issues.size > 0 %}
  {% for issue in issues %}
    {% comments issue %}
  {% endfor %}
{% else %}
  <p>There are no issues in this project yet.</p>
{% endif %}

Nodes

Nodes are used to structure your project. They can be thought of as project folders or specific hosts/IPs.

The following drops are available:

{{ node.evidence }}
{{ node.id }}
{{ node.label }}
{{ node.notes }}

To show the content of your Evidence by Node:

{% if nodes.size > 0 %}
  {% assign evidence_count = 0 %}
  {% for node in nodes %}
    {% for evidence in node.evidence %}
      {% assign evidence_count = evidence_count | plus: 1 %}
      <p>{{ node.label }}</p>
      <p>{{ evidence.content | markup }}</p>
    {% endfor %}
  {% endfor %}
  {% if evidence_count < 1 %}
    <p>There is no evidence for any of the nodes yet.</p>
  {% endif %}
{% else %}
  <p>There are no nodes for this project yet.</p>
{% endif %}

Notes

Notes are used primarily for content that you don't want to export into your reports. But, some external tools will create Notes with scan or port data inside of them that you may want to display in your Gateway layout.

The following drops are available:

{{ note.fields['Field Name'] }}
{{ note.id }}
{{ note.text }}
{{ note.title }}
{{ note.updated_at }}

To show all of the Notes in your project with their content:

{% for node in nodes %}
  {% if node.notes.size > 0 %}
    {% for note in node.notes %}
      <h1>{{ note.title }}</h1>
      <p>{{ note.text | markup }}</p>
    {% endfor %}
  {% else %}
    <p>There are no Notes for this Node yet.</p>
  {% endif %}
{% endfor %}

To display one specific field from a specific Type of Note:

{% for node in nodes %}
  {% if node.notes.size > 0 %}
    {% for note in node.notes %}
      {% if note.fields contains 'Type' and note.fields['Type'] == 'Port' %}
        {% if note.fields contains 'Description' %}
          {{ note.fields['Description'] | markup }}
        {% else %}
          <p>Description field is missing</p>
        {% endif %}
      {% endif %}
    {% endfor %}
  {% else %}
    <p>There are no Notes for this Node yet.</p>
  {% endif %}
{% endfor %}

Paths

Paths will likely be used in the page header and inside of the application.liquid file. Paths lead to other places in the app.

The following drops are available:

{{ paths.home }}
{{ paths.logout }}
{{ paths.projects }}

To create links that log the user out or return them to the Projects page in Gateway:

<a href="{{ paths.projects }}">Projects</a>
<a href="{{ paths.logout }}">Logout</a>

Project

You can also access project-level data. For example, you likely want to display the Project's name inside of Gateway (unless you want to use a specific Document Property.

The following drops are available:

{{ project.authors }}
{{ project.id }}
{{ project.name }}
{{ project.updated_at }}

To display when the project was last updated (in a specific date format!):

<p>{{ project.updated_at | date: '%B %d, %Y %l:%M%P' }}</p>

To display the photos of all of the users associated with the project:

{% for author in project.authors %}
  <img src="{{ author | avatar_url }}" class="avatar" title="{{ author.name }}" alt="{{ author.name }}"></img>
{% endfor %}

Tags

Tags are used to categorize Issues. The default tags are Critical, High, Medium, Low, and Info.

The following drops are available:

{{ tag.color }}
{{ tag.display_name }}
{{ tag.id }}
{{ tag.name }}
{{ tag.tag_issues }}

To display a list of the tags and the count of Issues that have that tag:

{% for tag in tags %}
  <p>{{ tag.display_name }}: {{ tag.tag_issues.size }}</p>
{% endfor %}

Teams

Each project can be associated with a Team.

The following drops are available:

{{ team.name }}

To display the Team's name in Gateway:

<p>{{ team.name }}</p>

Users

The users are the Testers who have access to the project.

The following drops are available:

{{ user.avatar }}
{{ user.email }}
{{ user.id }}
{{ user.name }}

To display information about the testers assigned to the project:

{% for user in project.authors %}
  <p>{{ user.name }}</p>
{% endfor %}

Next help article: Using Liquid Gateway Themes →

Streamline InfoSec Project Delivery

Learn practical tips to reduce the overhead that drags down security assessment delivery with this 5-day course. These proven, innovative, and straightforward techniques will optimize all areas of your next engagement including:

  • Scoping
  • Scheduling
  • Project Planning
  • Delivery
  • Intra-team Collaboration
  • Reporting and much more...

Your email is kept private. We don't do the spam thing.