6 Understand the JAF Audit Engine

The JAF audit engine invokes custom audit rules when Oracle JAF audits an Oracle JET app.

About the JAF Audit Engine

There are two types of custom audit rules that the Oracle JAF audit engine supports: standard rules and hook rules. The difference is that standard rules are invoked in response to the parsing by JAF of file data and hook rules are invoked in response to phases of the JAF audit lifecycle (for example, at startup, close-down, or when a file is first read).

At runtime, when Oracle JAF performs an audit, each file in the target file set is parsed by the JAF audit engine and an abstract syntax tree (AST) is created. The AST is then walked by JAF and data node events are passed to listener functions that you register in your custom audit rules.

You implement custom audit rules as JavaScript files which the JAF audit engine loads based on a configuration file that you define. At runtime, when the JAF audit engine generates the AST of the target file set, it passes context objects to the loaded rules and triggers the AST node event listeners that you implement in the rule's .js file. This allows your audit rule to respond to specific data from the audited file set.

The following reference topics on the audit engine list the available node listener types that you can use to write standard, node audit rules. The listener types correspond to AST data nodes that are specific to the file types of the JET application source.

The JAF audit engine gives your invoked custom audit rules access to a Rule context object that it passes to the rule's registered listener so you can test data and execute functionality. At the start of the audit, the audit engine passes a Register context object to the entry-point of all rules so you can get information about the audit. For details about these context objects, see these audit engine reference topics.

For details about the audit engine hook points that you can use to create hook rules, see About Hook Rule Invocation.

Understand the Structure of Custom Audit Rules

The Oracle JET Audit Framework (JAF) can be extended by the addition of custom rules that you implement. A rule is a JavaScript file that exports certain public functions.

When an audit is performed, each file in the target file set is parsed and an abstract syntax tree (AST) is created. The AST is then walked and the nodes are passed to one or more registered listener functions in the rules. Rules are implemented as JavaScript files and loaded by JAF at runtime as node.js module. JAF passes the loaded rules a context as it analyzes the AST and invokes the rule listeners.

To qualify as a valid rule, a rule must export the following four methods:

Method Description
getDescription() Returns a full detailed rule description. The description may contain HTML markup.
getName() Returns the rule name.
getShortDescription() Returns a short description/summary of the rule.
register(Object context) Called during JAF startup, this is the main entry point in the rule implementation. Declares the type of data that the rule wants to listen for together with the event handler functions. Returns an object that contains the events for the specified parsed AST data types or JAF audit lifecycle phases.

Here is a skeleton outline of a rule that you can implement to audit HTML or JSON files:

Skeleton Rule

function getName()
{
   return "my-rule-name" ;
};
 
function  getShortDescription()
{
   return "This a short description of the rule" ;
};
 
function  getDescription()
{
   return "This a much more detailed explanation of the rule, and can include markup." ;
};
 
function  register(context)
{
    // Here the rule registers the type of data that it wants to listen for, together with event handler function(s).
};
 
module.exports = {getName, getDescription, getShortDescription, register};

Note:

The rule description returned by getDescription() can contain HTML markup.

For the list of available events that your rule can listen for see:

See also:

Tip:

A skeleton rule can be easily scaffolded in the current directory using
ojaf --initrule myRuleName

If preferred, ES6 class syntax can be used.

Returning an ES6 class

class Rule {                             // (name can be anything)
     getName()               {...}
     getDescription()        {...}
     getShortDescription()   {...}
     register(regCtx)        {...}
}

module.exports = Rule;

If preferred, the following prototype inheritance format for creating a class is also acceptable, and Oracle JAF will automatically perform a new on the function:

Returning a class

var anyName = function()  {};  // (name is "internal" and can be anything)
anyName.prototype.getName = function()  {...};
anyName.prototype.getShortDescription = function()  {...};
anyName.prototype.getDescription = function()   {...};
anyName.prototype.register(context) {...};
module.exports = anyName ;

Audit Rule Entry Point Method Structure

The audit rule's main entry point is the register() function. For node rules that you define, this function is called during JAF startup and declares listener functions for specific types of data found during file set auditing. When you need to define a hook rule, use this function to declare listeners for events triggered by JAF on the audit lifecycle.

In the case of node rules, the basic purpose of a registered entry-point method implementation is to examine the data passed to it and to return one or more Issue objects, where each contains a description of the problem found. You can then choose which issues to report by using a Reporter instance. If no issues are found, the rule just returns. The method gets its data from the passed-in Register context object.

The following pseudo code sample registers an event listener for the registered listener type ojtag. The ojtag type is an example of one of many listener types that you can register specifically for HTML and JSON files. For more details about the listener function, see Audit Rule Listener Function Structure.

function register(regContext)
{

 return {
    ojtag : function(ruleContext, tagName)  // "ojtag" is an example of a registered type - it causes the
    {                                       // function to be called for each DOM element of the form <oj-xxx>
      var issue ;                       
                                        

      // analyze the data passed in the Rule context, and any other supplied args
      . . .

      if (found_a_problem)
      {
        issue =  new  ruleContext.Issue( "describe the problem found" ) ; // create new Issue object
        ruleContext.reporter.addIssue(issue, ruleContext) ;               // pass Issue to the Reporter instance
        }
    };
 }
};

The register() function sample shows that the Rule context object provides an Issue class which can be used to create an Issue instance. The Issue instance is then passed to the Reporter instance (also available from the context) where you choose one or more issues to report.

Tip:

Generally, it is best to limit the custom audit rule to listen for and to report a single issue per rule. This permits a specific diagnostic to be disabled, if required, in the JAF configuration file.

When the current file has been completely audited, JAF emits the issues in the format that you specified in the JAF configuration file.

Audit Rule Listener Function Structure

Listener functions for audit events are defined in your rule's register() function. You can declare listener functions for specific types of data found during auditing of a file to define a node rule. Alternatively, you can declare listener functions for events in the audit engine lifecycle to define hook rules.

The listener function has the following signature for a node-type rule, where some arguments are also properties of the ruleContext object.

function _fnHandler(ruleContext, arg1, arg2) { . . .
      };

In the case of a hook rule, where the registered type is an audit engine signaled event (for example, endselector), the arguments are not used.

For node rules, the arguments depend on the registered listener type.

  • where arg1 is a string representing the data node token. For example, if ruleContext.type is ojtag or tag, this would represent a string such as oj-button or div.

  • where arg2 is a string that is an optional value supplementing arg1. For example, if context.type is attr, this would represent the attribute's value, and arg1 will contain the attribute name.

Note:

For the complete list of registered listener types and a description of their arguments, see Listener Types for HTML and JSON Rules, Listener Types for JavaScript/TypeScript Rules, and Listener Types for CSS Rules. For the registered types that you can define for hook type rules, see About Hook Rule Invocation.