9 Implement Custom Hook Rules

Hook rules are effectively hooks into the Oracle JAF audit engine, and are called at specific phases of an audit, as opposed to a response to parsed file data for standard, node rules.

About Hook Rule Invocation

Rules that you write in response to specific phases in the lifecycle of the Oracle JAF audit are called hook rules. Unlike node rules, hook rules are not invoked in response to parsing of application file data.

Rules that you register with a type of startup, closedown, startupRP, startaudit, endaudit, closedownRP, or file correspond to specific phases in the lifecycle of the JAF audit. The lifecycle of the JAF audit is described below as an aid to understanding the sequence of hook rule invocation.

  1. Startup Phase

    Initialization, configuration analysis, and file set expansion are performed.

  2. Rule Packs Loaded

    Rules are loaded (instantiated) and evaluated by the audit engine:

    → first register() is called on all rules in a rule pack to execute rule listeners.

  3. Pre-Audit Phase

    → startup hook rules are fired.

    → startupRP hook rules are fired for each rule pack.

  4. Audit Phase

    → startaudit hook rules are fired for each file in the file set.

    {

    → file hook rules are fired.

    → now non-hook (node) rules are fired.

    }

  5. Closedown Phase

    → endaudit hook rules are fired.

    → closedownRP hook rules are fired for each rule pack.

    → closedown hook rules are fired.

Implement Custom Rules on the File Context

Use a Oracle JAF audit engine file hook when you need to create an audit rule that is invoked for each file before any other rules are fired for that file or after all rules have been fired for the file.

A file-type hook rule has the ability to conditionally terminate the audit of the file that it is invoked on. If the rule returns a boolean false, the file audit will be vetoed. Note that returning true is the same as omitting the return statement and the audit will continue.

The context.filename property contains the full file path to the file for which the hook rule was invoked. The file path for the file is always maintained with forward slashes regardless of the platform.

The context.node property specifies the first node of the DOM (for HTML and CSS) or JavaScript AST or JSON AST.

Hook Listener Type When Invoked
file Invoked after a file has been read and before any non-hook rules are fired.
endfile Invoked after all non-hook rules have been fired for the file.
startscript Invoked after an embedded JavaScript <script> has been read and before any non-hook rules are fired.
endscript Invoked after all non-hook rules have been fired for the embedded JavaScript text.

Implement Custom Rules Using the Audit Lifecycle

Use any of the various Oracle JAF audit lifecycle hooks when you need to create an audit rule that is invoked during a specific phase of the audit lifecycle.

Hook Rules for startup, closedown, startaudit, and endaudit Phases

The startup rules are called after completion of audit initialization and before any data files are read, and the closedown rules just prior to audit completion and after all files have been audited. The register context is passed to the rule's register() listener method(s). These rules may be used to initialize user data or load user support packages (but see also the startupRP hook).

If a rule registers startup, closedown, startaudit, or endaudit, the context.phase property value will reflect the respective value.

The startaudit rules are called after all startupRP rules have been fired on all the enabled rule packs, and just prior to the auditing of the file set. The context.phase property will reflect startaudit.

The endaudit rules are called on completion of the file set audit, and prior to the firing of the closedownRP rules. The context.phase property will reflect endaudit.

The startup and startaudit hook rules have the ability to conditionally terminate an audit. If the rule returns a boolean false, the audit is vetoed. Note that returning true is the same as omitting the return statement, and the audit will continue.

Hook Rules for startupRP and closedownRP Phases

These rules are called just before and just after the file auditing phase of the lifecycle. The startupRP hooks are called after any startup hooks have been fired, and the closedownRP hooks are called before the final closedown hooks are fired. These registered listeners are typically defined once in a rule pack rule to permit startup activity, such as initialization of common rule pack data, and, if required, closedown of the rule pack data.

function  register(regCtx)
{
   return {
             startupRP   : _fn,
             closedownRP : _fn
          };
}
 
function _fn(ruleCtx)
{
    // ruleCtx.phase contains "startupRP" or "closedownRP"
}

The rule pack hooks are invoked as follows.

Hook Listener Type When Invoked
startupRP
After completion of audit initialization and after the startup hook is fired, and before any data files are read. The rule is called once for each enabled rule pack (configuration file property rulePack). This rule may be used to initialize any user data or to load custom user support packages/services (referred to as a rule pack extension) needed by the rules, and may be associated with the rule pack by passing back the created extension by calling context.rulePack.setExtension().
// Here is a skeleton rule pack extention:
 
 context.utils.setExtension({
                              lib : get_some_lib(),
                              package : require('some package'),
                              table :  [ . . . ]
                              . . .
                            });

Any standard rule in the rule pack may retrieve the extension declared for the rule pack by calling context.rulePack.getExtension().

A startupRP hook rule has the ability to conditionally terminate an audit. If it returns a boolean false, the audit is vetoed. Note that returning true is the same as omitting the return statement and the audit will continue.

If execution of the rule is mandatory and the pack cannot tolerate this rule being disabled by the user configuration file, the $required property should be set to true in the pack's rules.json file for the rule.

closedownRP After all files have been audited and before the closedown hook is fired. This complementary rule to startupRP is called once for each enabled rule pack, and may be optionally used to handle any necessary close-down of custom support services generated via startedRP.

If execution of the rule is mandatory and the pack cannot tolerate this rule being disabled by the user configuration file, the $required property should be set to true in the pack's rules.json file for the rule.

Walkthrough of a Sample Audit Hook Rule

Audit rules that register with a listener type of startup, closedown, startupRP, startaudit, endaudit, closedownRP, or file, are called at specific phases in the Oracle JAF audit engine lifecycle. These rules are distinct from node-type rules which are called in response to parsed file data.

This walkthrough demonstrates a simple use of two audit rules that work together to classify the usage of <oj-xxx> elements in the HTML files of an application. The first rule is a standard HTML data node rule that makes use of a rulepack extension object to save the number of references to the various <oj-xxx> elements across all audited files. The second rule uses the audit engine startupRP hook to set up the counters in a rulepack extension object, and uses the closedownRP hook to display the accumulated element counts on the console upon completion of the audit.

First, we create the node rule ojtag-counter to maintain the count of <oj-xxx> element usages by registering the ojtag event listener on the parsed HTML files. To maintain the count, this rule relies on the tagStats rulepack extension object that you'll need to create just before file auditing begins by using a hook rule.

... // for clarity, the getName(), getDescription(), and getShortDescription() methods have been omitted

function register(regContext)
 {
   return { ojtag : function(ruleCtx, tagName)
                    {
                      let tagStats = ruleCtx.rulePack.getExtension().tagStats;
                      if (tagStats[tagName] === undefined)
                      {
                        // first use - create an entry for the tag
                        tagStats[tagName] = 0;
                      }
                      tagStats[tagName]++;
                    }
          };
};

Then our hook rule ojtag-count-display sets up the count at the start of the audit and displays the accumulated stats to the console at the end of the audit. This hook rule relies on the startupRP hook to create the rulepack extension object and closedownRP to display the accumulated count. These two hooks are triggered just before and just after the file auditing phase of the audit engine lifecycle.

... // for clarity, the getName(), getDescription(), and getShortDescription() methods have been omitted

function register(regCtx)
{
   return { startupRP : function(ruleCtx)
                      {
                          // Get or create an extension
                          let RPExt = ruleCtx.rulePack.getExtension() || {};
                          // Add a stats collection object to it
                          RPExt.tagStats = {};
                          // Update the extension                          
                          ruleCtx.rulePack.setExtension(RPExt);            
                      },
            closedownRP : function(ruleCtx)
                        {
                          let ojTag, tagStats = context.rulePack.getExtension().tagStats;
 
                          console.log("\n");
                          for (ojTag in tagStats)
                          {
                            console.log(`<${ojTag}> : ${tagStats[ojTag]}`);
                          }
                          console.log("\n");
                        }
        };
};

Here is typical sample output returned by these rules:

<oj-option> :     1824
<oj-label> :      1413
<oj-input-text> :  545
<oj-button>     :  447
 . . .
<oj-chart-item> :    1
<oj-chart-group> :   1
<oj-bind-dom> :      1