Audit
Writing Audits for Drutiny
A Drutiny audit
is a PHP class that executes a policy
defined in YAML.
Audit classes do the heavy lifting for a policy and are ideally abstract enough
to support multiple policies. Such an example is the Module Enabled
class which checks if a module is enabled. However, the module it checks is set
by the policy. In this way, may policies can be created using the same audit
class.
Getting Started
An audit class should live under an Audit
folder in a PSR-4 directory structure
and extend from Drutiny\Audit
.
<?php
namespace Path\to\Audit;
use Drutiny\Audit;
/**
* Generic module is disabled check.
*/
class FooAssesor extends Audit {
An Audit
class requires a single method also called audit
. Its passed in a Drutiny\Sandbox\Sandbox
object which holds all tools available to running an audit.
<?php
use Drutiny\Sandbox\Sandbox;
// ...
public function audit(Sandbox $sandbox)
{
}
The Sandbox
The Sandbox object passed to the check method contains access to drivers you may use in your audit such as drush
.
<?php
/**
* @inheritDoc
*/
public function audit(Sandbox $sandbox) {
// Use drush to confirm Drupal settings deny llamas.
$config = $sandbox->drush(['format' => 'json'])
->configGet('llamas.settings', 'allowed');
$denied = $config['llamas.settings:allowed'] == FALSE;
// Confirm llamas have not accessed the site.
$lama_access = $sandbox->exec('grep llamas /var/log/apache/access.log | grep -v 403');
// Return TRUE/FALSE is the same as Audit::SUCCESS or Audit::FAILURE
return $denied && empty($lama_access);
}
Return values
The audit expects a returned value to indicate the outcome of the audit. The follow table describes the return options and their meaning.
Return Value | Purpose |
---|---|
Drutiny\Audit::SUCCESS |
The policy successfully passed the audit. |
Drutiny\Audit::PASS |
Same as Audit::SUCCESS |
Drutiny\Audit::FAILURE |
The policy failed to pass the audit. |
Drutiny\Audit::FAIL |
Same as Audit::FAILURE |
Drutiny\Audit::NOTICE |
An audit returned non-assertive information. |
Drutiny\Audit::WARNING |
An audit returned successful but with a warning. |
Drutiny\Audit::WARNING_FAIL |
An audit returned a failure but with a warning. |
Drutiny\Audit::ERROR |
An audit did not complete and returned an error. |
Drutiny\Audit::NOT_APPLICABLE |
An audit was not applicable to the target. |
Drutiny\Audit::IRRELEVANT |
An audit was irrelevant to the target and should be omitted from the overall report. |
In addition to using Return Values, audits can also return TRUE
, FALSE
and
NULL
values which correlate to Drutiny\Audit::SUCCESS
, Drutiny\Audit::FAILURE
and Drutiny\Audit::NOT_APPLICABLE
respectively.
Audit Prerequisites
In order to keep audit methods as lean as possible and to focus on evaluating the success/failure of the task at hand, Drutiny Audit classess support the ability to validate prerequisites before attempting an audit. These are called require methods.
Any protected method on an Audit class that starts with the term "require" will be considered a prerequisite to pass prior to an audit being run.
<?php
namespace Path\to\Audit;
use Drutiny\Audit;
use Drutiny\Sandbox\Sandbox;
use Drutiny\Target\DrushTarget;
class DrushVersionCheck extends Audit {
/**
* This will be called before audit().
*
* Must return TRUE to continue audit.
*/
protected function requireDrushTarget(Sandbox $sandbox)
{
return $sandbox->getTarget() instanceof DrushTarget;
}
public function audit(Sandbox $sandbox) {
Remediation
Remediation is an optional capability your Audit
can support.
To do so, it must implement Drutiny\RemediableInterface
.
When policies and profiles are run, they can optionally opt into to auto-remediation which will call the remediation
method if the audit method returns FALSE.
<?php
namespace Path\to\Audit;
use Drutiny\Audit;
use Drutiny\Sandbox\Sandbox;
use Drutiny\RemediableInterface;
/**
* Generic module is disabled check.
*/
class FooAssesor extends Audit implements RemediableInterface {
// ...
/**
* @inheritDoc
*/
public function remediate(Sandbox $sandbox) {
// This calls: drush config-set -y llamas.settings allowed 0
$sandbox->drush()->configSet('-y', 'llamas.settings', 'allowed', 0);
// Re-check now the config should have changed.
return $this->audit($sandbox);
}
Parameters
Parameters allow you to configure the audit based on the runtime environment.
For example, the page cache audit contains parameters to allow you to audit what the page cache max_age
setting should be.
Parameters are defined as annotations in the audit class. This allows policy writers to understand how to use the parameters when integrating with a specific audit.
<?php
namespace Path\to\Audit;
use Drutiny\Audit;
use Drutiny\Sandbox\Sandbox;
use Drutiny\RemediableInterface;
use Drutiny\Annotation\Param;
/**
* Generic module is disabled check.
* @Param(
* name = "foo",
* type = "string",
* description = "A measure of foo to apply to denied llamas",
* default = "baz",
* )
*/
class FooAssesor extends Audit implements RemediableInterface {
Parameters can be overwritten in policies:
# Parameters mentioned in bar.policy.yml
class: \Drutiny\path\to\FooAssesor
parameters:
foo:
type: string
description: "A measure of foo to apply to denied llamas"
default: bar
Parameters are then used inside the audit and remediation methods to allow elements of the audit to be more configurable and extensible to other implementations:
<?php
/**
* @inheritDoc
*/
public function audit(Sandbox $sandbox) {
$foo = $sandbox->getParameter('foo');
$config = $sandbox->drush(['format' => 'json'])
->configGet('llamas.settings', 'foo');
$this->setParameter('actual_foo', $config['llamas.settings:foo']);
// Return TRUE/FALSE is the same as Audit::SUCCESS or Audit::FAILURE
return $foo == $config['llamas.settings:foo'];
}
You can use $sandbox->setParameter()
to set parameters that maybe used to render the results of an audit or remediation.
Tokens
Tokens are parameters that are available to render in the output messaging of the policy. E.g. success, failure, warning and description messages. All parameters are implicitly tokens, but in addition, an audit may set parameters not used for the purposes of the audit but purely for policy messaging.
<?php
namespace Path\to\Audit;
use Drutiny\Audit;
use Drutiny\Sandbox\Sandbox;
use Drutiny\RemediableInterface;
use Drutiny\Annotation\Param;
use Drutiny\Annotation\Token;
/**
* Generic module is disabled check.
* @Param(
* name = "foo",
* type = "string",
* description = "A measure of foo to apply to denied llamas",
* default = "baz",
* )
* @Token(
* name = "actual_foo",
* type = "string",
* description = "Config setting for llamas.settings:foo"
* )
*/
class FooAssesor extends Audit implements RemediableInterface {
/**
* @inheritDoc
*/
public function audit(Sandbox $sandbox) {
$foo = $sandbox->getParameter('foo');
$config = $sandbox->drush(['format' => 'json'])
->configGet('llamas.settings', 'foo');
$this->setParameter('actual_foo', $config['llamas.settings:foo']);
// Return TRUE/FALSE is the same as Audit::SUCCESS or Audit::FAILURE
return $foo == $config['llamas.settings:foo'];
}