All posts by Martin Preisler

Waivers in openscap HTML report

XCCDF supports waivers by the means of the cdf:override element. Support for it in the openscap API has recently been greatly enhanced by Šimon Lukašík. Therefore I have looked into adding support for waivers in the HTML report.

This blog post talks about openscap master as of commit 30f9a224bc25f2127462d30ec1e4c0d499a23511.

We decided to use the term waiver instead of override. The situation looks similar to tailoring vs customization to us. Waiver should be understood by more people without even looking at any documentation.

Rule overview now shows a small label next to waived rules. This label signifies that this particular rule has at least one waiver.

waiver1

When you click on the waived rule to see the details you will be presented with description of the waiver including information on who has performed it and when. If there are more waivers they are all shown in the order they appear in the original XML file.

waiver2

I know this feature has been requested by the community for a long time so I would like to gather some feedback to get it as right as possible.

Please note that the HTML reports themselves don’t allow you to interactively perform waivers, they just show them. As of now I don’t have plans to support interactive waivers but we may implement something like that in the future.

EDIT: I have implemented a prototype that allows interactive waivers using JavaScript. The waivers are not committed yet but I plan to commit them to master next week. Take a look at https://mpreisle.fedorapeople.org/openscap/interactive_waiver.html

Suggestions welcome!

EDIT2: Based on the feedback we decided not to include interactive waiver in the openscap reports themselves. Instead I will add HTML elements to make it easier to implement it in openscap integrations. The patch of the prototype follows and can be cleanly applied on top of 30f9a224bc25f2127462d30ec1e4c0d499a23511.

diff --git a/xsl/xccdf-report-impl.xsl b/xsl/xccdf-report-impl.xsl
index 08c50cf..f7c26f5 100644
--- a/xsl/xccdf-report-impl.xsl
+++ b/xsl/xccdf-report-impl.xsl
@@ -293,9 +293,7 @@ Authors:
 <xsl:with-param name="profile" select="$profile"/>
 </xsl:call-template>
 </a>
- <xsl:if test="$ruleresult/cdf:override">
- &#160;<span class="label label-warning">waived</span>
- </xsl:if>
+ &#160;<span class="label label-warning waiver-label"><xsl:if test="not($ruleresult/cdf:override)"><xsl:attribute name="style">display: none</xsl:attribute></xsl:if>waived</span>
 </td>
 <td style="text-align: center"><xsl:value-of select="$ruleresult/@severity"/></td>
 <td class="rule-result rule-result-{$result}">
@@ -304,7 +302,7 @@ Authors:
 <xsl:with-param name="ruleresult" select="$result"/>
 </xsl:call-template>
 </xsl:variable>
- <div>
+ <div class="inner">
 <abbr title="{$result_tooltip}"><xsl:value-of select="$result"/></abbr>
 </div>
 </td>
@@ -606,7 +604,8 @@ Authors:
 <div class="panel-body">
 <table class="table table-striped table-bordered">
 <tbody>
- <tr><td class="col-md-3">Rule ID</td><td class="rule-id col-md-9"><xsl:value-of select="$item/@id"/></td></tr>
+ <xsl:variable name="itemid" select="$item/@id"/>
+ <tr><td class="col-md-3">Rule ID</td><td class="rule-id col-md-9"><xsl:value-of select="$itemid"/></td></tr>
 <tr><td>Result</td>
 <td class="rule-result rule-result-{$result}">
 <xsl:variable name="result_tooltip">
@@ -614,9 +613,17 @@ Authors:
 <xsl:with-param name="ruleresult" select="$result"/>
 </xsl:call-template>
 </xsl:variable>
- <div>
+ <div class="inner">
 <abbr title="{$result_tooltip}"><xsl:value-of select="$result"/></abbr>
 </div>
+ <!-- see openscap.js for clues about the following 2 divs, they are used
+ for interactive waivers. -->
+ <div class="js-only waiver-button">
+ <xsl:if test="$result != 'pass' and $result != 'fixed' and $result != 'notselected'">
+ <button class="waive-button btn btn-warning btn-lg" type="button" onclick="return showWaiverForm($(this).closest('.rule-detail'), '{$itemid}')">Waive</button>
+ </xsl:if>
+ </div>
+ <div class="js-only waiver-form"></div>
 </td></tr>
 <tr><td>Time</td><td><xsl:value-of select="$ruleresult/@time"/></td></tr>
 <tr><td>Severity</td><td><xsl:value-of select="$ruleresult/@severity"/></td></tr>
@@ -628,8 +635,8 @@ Authors:
 <xsl:with-param name="item" select="$item"/>
 </xsl:call-template>
 </td></tr>
- <xsl:if test="$ruleresult/cdf:override">
- <tr><td colspan="2">
+ <tr><td colspan="2" class="waivers">
+ <xsl:if test="$ruleresult/cdf:override">
 <xsl:for-each select="$ruleresult/cdf:override">
 <xsl:variable name="old-result" select="cdf:old-result/text()"/>
 
@@ -643,8 +650,8 @@ Authors:
 </small>
 </div>
 </xsl:for-each>
- </td></tr>
- </xsl:if>
+ </xsl:if>
+ </td></tr>
 <tr><td colspan="2"><div class="description">
 <p>
 <xsl:apply-templates mode="sub-testresult" select="$item/cdf:description">
diff --git a/xsl/xccdf-resources-build.sh b/xsl/xccdf-resources-build.sh
index ec5f584..089d38a 100755
--- a/xsl/xccdf-resources-build.sh
+++ b/xsl/xccdf-resources-build.sh
@@ -10,12 +10,15 @@ cat xccdf-resources/jquery.treetable.css >> $ALL_CSS
 cat xccdf-resources/jquery.treetable.theme.css >> $ALL_CSS
 cat xccdf-resources/openscap.css >> $ALL_CSS
 csstidy $ALL_CSS --template=highest $ALL_CSS_MIN
+#cp $ALL_CSS $ALL_CSS_MIN
 rm $ALL_CSS
+
 echo "" > $ALL_JS
 cat xccdf-resources/jquery.treetable.js >> $ALL_JS
 cat xccdf-resources/bootstrap.min.js >> $ALL_JS
 cat xccdf-resources/openscap.js >> $ALL_JS
 slimit $ALL_JS > $ALL_JS_MIN
+#cp $ALL_JS $ALL_JS_MIN
 rm $ALL_JS
 
 XCCDF_RESOURCES="xccdf-resources.xsl"
diff --git a/xsl/xccdf-resources/openscap.css b/xsl/xccdf-resources/openscap.css
index 2e0f8e4..6521c84 100644
--- a/xsl/xccdf-resources/openscap.css
+++ b/xsl/xccdf-resources/openscap.css
@@ -1,11 +1,13 @@
 tr.rule-overview-needs-attention td a { color: #d9534f }
 
-td.rule-result div, span.rule-result { text-align: center; font-weight: bold; color: #fff; background: #808080 }
-td.rule-result-fail div, span.rule-result-fail { background: #d9534f }
-td.rule-result-error div, span.rule-result-error { background: #d9534f }
-td.rule-result-unknown div, span.rule-result-unknown { background: #f0ad4e }
-td.rule-result-pass div, span.rule-result-pass { background: #5cb85c }
-td.rule-result-fixed div, span.rule-result-fixed { background: #5cb85c }
+td.rule-result div.inner, span.rule-result { text-align: center; font-weight: bold; color: #fff; background: #808080 }
+td.rule-result-fail div.inner, span.rule-result-fail { background: #d9534f }
+td.rule-result-error div.inner, span.rule-result-error { background: #d9534f }
+td.rule-result-unknown div.inner, span.rule-result-unknown { background: #f0ad4e }
+td.rule-result-pass div.inner, span.rule-result-pass { background: #5cb85c }
+td.rule-result-fixed div.inner, span.rule-result-fixed { background: #5cb85c }
+
+td.rule-result div.waiver-button { float: right }
 
 .js-only { display: none }
 
diff --git a/xsl/xccdf-resources/openscap.js b/xsl/xccdf-resources/openscap.js
index f76645b..70e87b3 100644
--- a/xsl/xccdf-resources/openscap.js
+++ b/xsl/xccdf-resources/openscap.js
@@ -9,6 +9,7 @@ function openRuleDetailsDialog(rule_result_id)
 
 var clone = $("#rule-detail-" + rule_result_id).clone();
 clone.attr("id", "");
+ clone.data("idm_id", "rule-detail-" + rule_result_id);
 clone.children(".panel-heading").append(closebutton);
 closebutton.css( { "float" : "right" } );
 closebutton.css( { "margin-top" : "-=20px" } );
@@ -108,7 +109,122 @@ function ruleSearch()
 $("#search-matches").html("No rules match your search criteria!");
 }
 
-$(document).ready( function() {
+waiverCallback = function(rule_id, authority, datetime, new_result, remark)
+{
+ //alert(rule_id);
+ //alert(datetime);
+ //alert(new_result);
+ //alert(remark);
+
+ return "";
+}
+
+if (typeof waiverCallback === "undefined")
+ waiverCallback = null;
+
+if (typeof waiverDefaultAuthority === "undefined")
+ waiverDefaultAuthority = "Undefined Authority";
+
+function injectNewWaiver(rule_detail, rule_id, authority, datetime, new_result, remark)
+{
+ var previous_result = rule_detail.find(".rule-result .inner abbr").html();
+
+ rule_detail.removeClass();
+ rule_detail.addClass("panel panel-default rule-detail rule-detail-" + new_result);
+
+ var waiver_div = rule_detail.find("div.waiver-button");
+ waiver_div.hide();
+
+ var rule_result = rule_detail.find("td.rule-result");
+ rule_result.removeClass();
+ rule_result.addClass("rule-result");
+ rule_result.addClass("rule-result-" + new_result);
+ rule_result.find(".inner").html("<abbr>" + new_result + "</abbr>");
+
+ var waivers_div = rule_detail.find("td.waivers");
+ var new_waiver_div = $('<div class="alert alert-warning waiver">This rule has been waived by <strong>' + authority + '</strong> at <strong>' + datetime + '</strong>.<blockquote>' + remark + '</blockquote><small>The previous result was <span class="rule-result rule-result-' + previous_result + '">&#160;' + previous_result + '&#160;</span>.</small></div>');
+
+ waivers_div.append(new_waiver_div);
+
+ if (rule_detail.data("idm_id"))
+ {
+ rule_detail_lookup = $("#" + rule_detail.data("idm_id"));
+ injectNewWaiver(rule_detail_lookup, rule_id, authority, datetime, new_result, remark);
+ return;
+ }
+
+ var idm_base = $(rule_detail).attr("id").substring(12);
+ var rule_overview_leaf = $("#rule-overview-leaf-" + idm_base);
+
+ rule_overview_leaf.removeClass();
+ rule_overview_leaf.addClass("rule-overview-leaf rule-overview-leaf-" + new_result);
+ rule_overview_leaf.find(".waiver-label").show();
+
+ var rule_result_overview = rule_overview_leaf.find(".rule-result");
+ rule_result_overview.removeClass();
+ rule_result_overview.addClass("rule-result rule-result-" + new_result);
+ rule_result_overview.find("div").html("<abbr>" + new_result + "</abbr>");
+}
+
+function submitWaiverForm(rule_detail, rule_id, waiver_form)
+{
+ var now = new Date();
+ var datetime = now.toISOString();
+ var authority = waiver_form.find(".waiver-authority").val();
+ var new_result = waiver_form.find(".waiver-new-result option:selected").val();
+ var remark = waiver_form.find(".waiver-remark").val();
+
+ var result = waiverCallback(rule_id, authority, datetime, new_result, remark);
+ if (result == "")
+ {
+ hideWaiverForm(rule_detail, rule_id);
+ injectNewWaiver(rule_detail, rule_id, authority, datetime, new_result, remark);
+ }
+ else
+ {
+ // TODO: Show error
+ }
+
+ return false;
+}
+
+function showWaiverForm(rule_detail, rule_id)
+{
+ var waiver_div = rule_detail.find("div.waiver-button");
+ waiver_div.hide();
+ var waiver_form_div = rule_detail.find("div.waiver-form");
+
+ var waiver_form = $('<form role="form"/>');
+ var authority = $('<div class="form-group"><label class="control-label">Authority</label><input type="text" class="waiver-authority form-control" value="' + waiverDefaultAuthority + '"/></div>');
+ waiver_form.append(authority);
+ var new_result = $('<div class="form-group"><label class="control-label">New result</label><select class="waiver-new-result form-control"><option>pass</option><option>notapplicable</option></select></div>');
+ waiver_form.append(new_result);
+ var remark = $('<div class="form-group"><label class="control-label">Remark</label><textarea class="waiver-remark form-control"/></div>');
+ waiver_form.append(remark);
+ var ok_button = $('<button type="button" class="btn btn-primary btn-sm">Confirm</button>');
+ ok_button.click(function(){
+ return submitWaiverForm(rule_detail, rule_id, waiver_form);
+ });
+ waiver_form.append(ok_button);
+ var cancel_button = $('<button type="button" class="btn btn-default btn-sm">Cancel</button>');
+ cancel_button.click(function(){
+ return hideWaiverForm(rule_detail, rule_id);
+ });
+ waiver_form.append(cancel_button);
+ waiver_form_div.append(waiver_form);
+}
+
+function hideWaiverForm(rule_detail, rule_id)
+{
+ var waiver_div = rule_detail.find("div.waiver-button");
+ waiver_div.show();
+ var waiver_form_div = rule_detail.find("div.waiver-form");
+ waiver_form_div.empty();
+
+ return false;
+}
+
+$(document).ready(function(){
 $("#result-details").hide();
 $(".js-only").show();
 $(".toggle-rule-display").each(function(){

Don’t forget to run xccdf-build-resources.sh after applying the patch!

h.264 HTML5 video in Firefox on Fedora 20

Please check out rpmfusion.org for all the usual disclaimers. Some of the software needed for h.264 is for non-commercial use only and/or patent encumbered.

Fedora now ships with Firefox 31 that has gstreamer1 support enabled. That means that you can finally use HTML5 h264 video on youtube and vimeo if you install a few codecs. This snippet should work even on freshly installed Fedora 20.

This post should apply to other Linux distributions as well but the packages names will be different. Type about:buildconfig into the address bar in Firefox. If it contains –enable-gstreamer=1.0 you are good to go.

# only if you don't have rpmfusion enabled already
yum localinstall http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm

yum install gstreamer1-libav gstreamer1-vaapi gstreamer1-plugins-{good,good-extras,ugly} -y

# only if you want bad plugins
# yum install gstreamer1-plugins-bad-free gstreamer1-plugins-bad-freeworld -y

Now restart Firefox and test the h264 support. You can use https://www.youtube.com/html5 for testing, the h264 bar should be green. Or try looking at any vimeo video.

If your firefox does not play h.264 videos at this point, check that you really installed gstreamer1 plugins and not the “gstreamer 0.10”. These are prefixed with just gstreamer- in Fedora.

UPDATE: This works on Fedora 21 as well.
UPDATE: This works on Fedora 22 as well.
UPDATE: This works on Fedora 23 as well.
UPDATE: This works on Fedora 24 as well.

Lenovo T440s Fedora 20 notes

All of this should apply to all T440s models but I have specifically tested it on a model with Samsung SSD and Intel 7260 dual band wifi.

Scary options in BIOS

All these remote management, anti-theft and device location options really just fuel my paranoia. Turned them all off. I try to setup all my machines to be disposable, device recovery is very unlikely anyway.

Good options in BIOS

You can nicely lock it down with a supervisor password and disallow booting from any device other than the internal SSD. There is an option to disallow firmware flashing. Getting the laptop apart to wipe the settings is quite a pain so I think this does help a bit.

UEFI boot and GPT

Before installing Fedora, go to the BIOS/UEFI setup menu and switch to the Startup tab. Look for “UEFI/Legacy boot” and set it to “UEFI only”. I have also disabled CSM but I don’t think it affects anything with Fedora 20.

I couldn’t get the local pxeboot running with UEFI so I had to resort to a USB flash drive. Had no problems getting the machine to boot the USB drive. Fedora 20 x86_64 install ISO was used mainly because I already had it downloaded from before.

Pay close attention to partitioning in Anaconda. If you want TRIM/discard select Standard Partitioning. Don’t worry about having to type your password multiple times for multiple encrypted standard partitions. Anaconda will do what you want by default – a single password opens all your encrypted partitions.

Despite everyone raging on the internet about SSD alignment it seems very unlikely that partitioning tools would do a bad job by default. In my case the internal Samsung SSD exported its geometry correctly and Anaconda had done proper partition alignment. You can check this using parted:

sudo parted /dev/sda
# interactive interface of parted follows
align-check opt
# now you can cycle through all the partitions
# all are aligned in my case

The rest of the installation process is a breeze, everything seems to work out of the box.

Is UEFI worth the hassle? Probably not, I was mainly curious. The boot seems a bit faster but I have no solid data.

TRIM/discard and HDD encryption

TRIM may help with SSD performance. It’s probably overkill and very overrated but for the sake of learning about it I opted to set it up. Be advised that enabling it may leak structure information about how you use your drives – especially how much free space you got. See http://asalor.blogspot.cz/2011/08/trim-dm-crypt-problems.html for more details. Now that all the disclaimers are done, let us set up discard for encrypted drives.

The actual process was very simple, first you need to tell cryptsetup to allow discard to be enabled. Open /etc/crypttab and add “luks,discard” to each drive that is relevant. The end result should look like this:

luks-................... UUID=................... none luks,discard

I am not entirely sure if adding luks is necessary here but I do it anyway. The “luks” option forces LUKS mode. Now you can enable the discard option in /etc/fstab, add “discard” to the list of options in the relevant mount points. The end result should look something like this:

$some_device_depending_on_your_setup /mount/point ext4 defaults,noatime,noadirtime,discard,x-systemd.device-timeout=0 1 2

To make these changes effective on next boot you have to regenerate initramfs.

mount /boot
dracut --force

Testing with fstrim:

sudo fstrim /
sudo fstrim /home

Getting the function keys to work

If you use a big bulky desktop environment like KDE or Gnome this may already work out of the box. I use i3wm so I have to set it up manually.

Install the necessary dependencies:

sudo yum install xbacklight pulseaudio-utils

This is what I put into my i3config, should be easy to adapt for other window managers. It’s a bit messy and I may improve it later but it gets the job done for now. It has basic support for volume up, volume down, mute toggle, brightness up and brightness down.

bindsym XF86AudioLowerVolume exec /usr/bin/pactl set-sink-volume 0 -- '-5%' && notify-send --urgency=low --expire-time=1000 "`pactl list sinks | grep "Volume: " | grep -v "Base" | tr -d '\t'`"
bindsym XF86AudioRaiseVolume exec /usr/bin/pactl set-sink-volume 0 -- '+5%' && notify-send --urgency=low --expire-time=1000 "`pactl list sinks | grep "Volume: " | grep -v "Base" | tr -d '\t'`"
bindsym XF86AudioMute exec /usr/bin/pactl set-sink-mute 0 toggle && notify-send --urgency=low --expire-time=1000 `pactl list sinks | grep "Mute: " |  tr -d '\t'`

bindsym XF86MonBrightnessUp exec /usr/bin/xbacklight -inc 10 && notify-send --urgency=low --expire-time=1000 "Backlight `xbacklight`%"
bindsym XF86MonBrightnessDown exec /usr/bin/xbacklight -dec 10 && notify-send --urgency=low --expire-time=1000 "Backlight `xbacklight`%"

Get more out of the battery

Append the following to /etc/rc.d/rc.local:

echo '1500' > /proc/sys/vm/dirty_writeback_centisecs
echo 'min_power' > /sys/class/scsi_host/host0/link_power_management_policy
echo 'min_power' > /sys/class/scsi_host/host1/link_power_management_policy
echo 'min_power' > /sys/class/scsi_host/host2/link_power_management_policy
# some people have problems with this and get hissing noises
# I don't so I enable power save even for Intel HDA Audio
echo '1' > /sys/module/snd_hda_intel/parameters/power_save'
echo '0' > /proc/sys/kernel/nmi_watchdog'
echo 'auto' > /sys/bus/usb/devices/2-6/power/control'
echo 'auto' > /sys/bus/usb/devices/2-7/power/control'
echo 'auto' > /sys/bus/pci/devices/0000:00:1f.3/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:00.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:03.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:02.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:16.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:16.3/power/control
echo 'auto' > /sys/bus/pci/devices/0000:03:00.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:02:00.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:1f.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:1d.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:1c.1/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:1c.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:1b.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:14.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:19.0/power/control
echo 'auto' > /sys/bus/pci/devices/0000:00:1f.2/power/control
# your ethernet may be called differently
ethtool -s em1 wol d

Creating the file will automatically enable the rc-local.service unit in systemd. There is no need to enable it manually. You can verify this by running:

systemctl show rc-local.service

You can get amazing battery life out of this machine. 15+ hours is not a problem with moderate usage (with internal and 6 cell battery).

The LCD panel woes

The Full HD IPS T440s ship with 2 different LCD panels – AUO and LG. You can look up which one you got by grepping /var/log/Xorg.0.log. If it contains LP140WF1 you got what everyone considers the worse display – the LG. B140HAN01.2 is the AUO. You can read a lot of endless first world problem style whining about this here.

Outstanding issues

DisplayPort MST

All the video output ports on the dockstation are mirrored.
https://bugzilla.redhat.com/show_bug.cgi?id=1086978

As a workaround you can use the mini DisplayPort on the laptop itself even when the laptop is docked. The VGA port on the laptop unfortunately cannot be used. From what I can tell it is disabled when you put the laptop into the dockstation. Makes sense but why isn’t the miniDP disabled?

dockstation audio jack

https://bugzilla.redhat.com/show_bug.cgi?id=1101386

Use the laptop combo audio port as a workaround. Works even when docked.

Fingerprint reader

… but who cares?

If bluetooth doesn’t work and the device doesn’t show up in `lsusb` it could be because you disabled the Fingerprint reader. Enable it to get bluetooth back. This issue could be specific to my firmware version 2.27.

TODO

  • Toggle all radio off with the wifi function key – just binding the key to nmcli radio all off works but doesn’t toggle
  • SecureBoot

openscap HTML report redesign – part 2

I have started a discussion about openscap HTML report redesign.

Gathered feedback

This was gathered from comments on the referenced blog post, the openscap, scap-workbench and scap-security-guide mailing lists.

  • search through XCCDF rules (identifiers, title, ID, description, …) – implemented
  • filter by XCCDF result – implemented
  • use HTML anchors, speed up navigation between result details and result overview (jquery popup?) – implemented
  • too many colors in the introduction section – hopefully fixed
  • organize rule results into groups, display rule overview as a tree – implemented
  • show severity in rule overview – implemented
  • report fail and error rules by severity in addition to the standard XCCDF score system – TODO
  • sort by severity in rule overview – TODO
  • sort by identifiers in rule overview – TODO
  • false positive waiving, other means to pass feedback about why rule fails – probably out of scope, would need a new file format to store the waivers

xslt-devel branch

I have created a new branch in the openscap repository where I am continuing with this effort. Instead of a prototype HTML the repo has working XSLTs. Keep in mind that the branch breaks openscap tests and you can’t generate HTML report using the oscap tool command line. Instead you have to use xsltproc directly for now.

https://git.fedorahosted.org/cgit/openscap.git/log/?h=xslt-devel

Screenshots

htmlreport1
A mild change in color scheme, nothing you see here is set in stone though
htmlreport2
Rule overview is not a hierarchy, shows groups and counts failed rules in each group
htmlreport3
When you click on a rule a modal dialog with more details is shown, you no longer need to jump around the document
htmlreport4
You can hide all the failing rules to feel happier!
htmlreport6
Tree nodes in rule overview can be collapsed and expanded by clicking on them
htmlreport5
Simple keyword searching is implemented for XCCDF rules

Generated sample

All the usual disclaimers apply. This is not the final version, a lot more than is necessary is bundled, not everything works.

Open the out.html file in a reasonably modern web browser.

openscap-xsl-prototype-part2.tar.gz

More feedback?

Would appreciate feedback again. I plan to continue working on this next week.

openscap HTML report redesign

We have received many requests to change our HTML report in some way. In this post I will try to summarize what it is people want to change and try to come up with a proposal for our new HTML report.

I started with the HTML report but the plan is to update both report and guide generators. They share a lot of code even today, it makes sense to update them both.

Problems with the current approach

openscap uses docbook as an intermediary format. This means that when generating guides or reports, the XCCDF is transformed into docbook using XSLT, that docbook is then transformed into XHTML. This causes several problems.

XCCDF allows XHTML in description, front-matter, rear-matter and others. We have to convert XHTML to pseudo-docbook and then back to XHTML. Data is inevitably lost during this transformation because docbook cannot possibly support all of XHTML.

Furthermore, the maintenance costs of such an arrangement are enormous. The XSLTs are big and hard to navigate through.

I believe benefits gained from using docbook are very small if there are any at all. There are serious issues when trying to generate PDF from our docbook guide/report which leads me to believe that nobody is using alternative output formats.

Current openscap HTML report
Current openscap HTML report

Requested features

Our users have requested several features and changes. I tried to gather some of them and list them here. If you have other suggestions please leave a comment!

  • Rule filtering – for example to hide all passed rules
  • Rule sorting – for example by severity, to form a remediation priority queue
  • Rule full-text search – type CVEs, CCEs, titles, parts of descriptions, filter rules by them
  • Custom branding  – allow downstreams to insert their own logo
  • Generate guide just for the chosen profile – as opposed to generating guide for the default profile
  • Online XSLT used on demand for XCCDFs – could be hosted on open-scap.org and can be used to create reports on demand, OVAL details will be omitted if this arrangement is used

Must-have features

  • Basic functionality even without any JavaScript in a modern HTML5-capable browser
  • Provide all info we currently provide in our HTML report – especially OVAL details in failed rules
  • “media: print” support
  • Proper XHTML passthrough for description, front-matter, rear-matter and other XCCDF elements that allow XHTML

Design proposal

In my opinion we should base the new HTML guide and report on HTML5 and either Pattern Fly or Bootstrap, the project it’s based on.  This should give us a starting point for visuals and usability. The new XSLT will no longer generate any docbook. Users that want PDF reports can generate them from the resulting HTML5.

The main problem with this is that we have to either bundle a lot of JavaScript and CSS, or fetch them from some remote site. From my estimates we would have to bundle ~200 kB with each guide and report. That seems quite excessive. I will try to bring the number down.

If that effort fails a reasonable compromise might be to bundle CSS and fetch JavaScript remotely if available. This means that open-scap.org would have to reliably host JavaScript resources for reports and guides. These would have to be frozen and versioned with diligence. Please note that even if the browser fails to load the JavaScript the basic functionality would still be available.

Prototype 1

What follows is a preliminary prototype. Not all planned functionality has been implemented.

I have used jQuery dataTables for search and sorting functionality. It supports pagination but I am unsure whether we want to use that or not.

Screenshots for the impatient:

screenshot1
Top of the HTML report prototype
screenshot2
Example of a failed rule “panel”
screenshot3
Example of a passed rule “panel”

Full archive of all the code for the rest:

openscap-xsl-prototype.tar.gz

Plans

I would like to get some feedback from the community before I continue with this research. If the feedback is positive I plan to start an experimental branch in the openscap upstream repository with the actual XSLTs.

I can make no promises but the ambitious plan is to have a new HTML report and guide in openscap 1.1.0.

See part 2.