The Zurich release has arrived! Interested in new features and functionalities? Click here for more

Luke Van Epen
Tera Guru

The ServiceNow platform provides Instance Scan as a default feature and is used by the Instance Security Center to produce Cyber Security scan findings for your instance.

In this article, we will explore how we can leverage this feature to enforce standards tailored to your instance and customer requirements. Implementing controls such as:

 

  • Ensure naming conventions are upheld on custom development artifacts such as new Business Rules.
  • Check against known security vulnerabilities.
  • Provide guidance to junior developers.
  • Highlight best practice violations and recommend solutions.

 

Exploring Instance Scan's capabilities

From the docs:

"Use ServiceNow Instance Scan to interrogate your instance for configurations that indicate health issues and identify opportunities to address best practices. Instance Scan checks your existing configurations and helps you avoid creating future configuration issues. Instance Scan is a tool that can be used as a part of your development operations, release management as well as pre- and post-upgrades."

Instance Scan Documentation: https://docs.servicenow.com/bundle/tokyo-servicenow-platform/page/administer/health-scan/reference/h...

 

Some quick terms:

Check: A check is a record you create to define how the system will detect a particular misconfiguration or issue. There are 4 check types available as of Tokyo:

  • Table check: The most common type, run a filter against all records in a table, if a record matches the condition, then a finding is created for that record against the check.
  • Column type check: The second most common type, run a check against all records in the system which contain this type of field. The field types you can pick are "Script", "XML" and "HTML". An example would be to check every script field in the instance for the "eval()" pattern and mark it as a security finding.
  • Script only check: Run an arbitrary script and manually find and correlate findings. This would only be necessary if the check cannot be done with Table or Column type checks.
  • Linter checks: A special check to run on script fields, has access to a linting API for identifying coding patterns more reliably than regex. Linter checks are an advanced checking type, and the API is currently not well defined, so we will be skipping them in this article.

 

Finding: A finding record is created whenever a specific record is linked to a Check. For example, if you had a Check which found all Script Includes with an empty description field, whenever a scan is run, a Finding would be created linking each script include with that check. A new Finding is created each time a scan is run. This will become useful in our solution below.

 

Scan: A job which executes a search of the instance to find all the records which match checks and create findings for them. Scans can be executed directly from a Check, from a Suite, on a schedule, or from an Update Set.

 

Suite: A collection of similar Checks. If you've used Test Suites as part of Test Management or ATF, the concept is exactly the same.

 

 

Using Instance Scan Checks to build our development standards

Now that we know how Instance Scan works, we can start to use these tools to build out a few guidelines for developers in our instance.

 

The Check records provide us with a Category field to help us think about what kind of issues we want to prevent using these checks:

  • Upgradability - Anything which will make future upgrades harder
  • Performance - Something which will make the platform run slower, or potentially cause outages/system hangs for parts of the instance.
  • Security - Any potentially exploitable gap in instance security or something which might have been overlooked as a security measure during development.
  • Manageability - Something which makes a feature or system harder to maintain in the future, something which requires a higher level of effort than necessary to make changes to.
  • User Experience - Something that makes the user experience worse.

 

For the purposes of demonstration, in this article I'm going to establish the following controls as my instance's Standards:

  1. All Business Rule names should be in the format "(ACME) - <name here>"
  2. Business Rules and Script Includes should never have an empty Description field.
  3. "gr" should never be used as a variable name
  4. Client Side Code should never call GlideRecord or getReference
  5. No hard-coded sys_ids in Business Rules

In your instance, you would build out as many of these types of controls as you can to build a robust development pipeline.

 

First check: Enforcing a naming convention

I have used an advanced script check here to demonstrate how it works

Example check: Align to naming conventionExample check: Align to naming convention

 

Second check: Missing recommended fields

Create New Table Check on the Business Rule table with a condition Description Is Empty

Example check: No empty descriptionsExample check: No empty descriptions

 

Third check: Bad coding practice

Example Column Type check for finding cases where "gr" is being used as a variable name.

In this case we also increment the finding count for each time a new variable is declared in the script with a name like gr or gr2.

LukeVanEpen_1-1665637378395.png

Regex used:

 

 

 

/var\s*gr[0-9]?\s*=.*GlideRecord/g

 

 

 

Fourth check: Optimising code

For this kind of check, you could create 1 table check per type of client script (e.g. Catalog client script, client script, UI script etc), or you could set the table to "sys_metadata" and use an advanced script to filter down and check the relevant tables and fields which would keep all the logic contained in a single check, however would be more difficult to implement and maintain.
 

Example check: Bad client side codeExample check: Bad client side code

 

Fifth check: No hard-coded values

This one is pretty similar to the no "gr" variable names check.
Example check: No hard coded sys_idsExample check: No hard coded sys_ids

 

Regex used:

 

 

 

/"[a-z0-9]{32}"/g​

 

 

 

Adding the Checks to a Suite

I will create a suite which will contain my 5 checks via Instance Scan > Suites and use the Edit button under Checks to add the newly created checks

Adding checks to a suite for groupingAdding checks to a suite for grouping

 

 

 

Checking your Update Set's files using Instance Scan

Luckily for us, this is a UI Action called Scan Update Set already present on the Update Set table found in the Related Links section:

LukeVanEpen_0-1665638699312.png

 

 

Forcing Scans before allowing code to be committed

Since there is already a feature for scanning update sets, we can now enforce that update sets are scanned by using a Before Update Business Rule to check for scan results before an update set can be marked as Completed.

 

Create a new Business rule such as the one below:

 

LukeVanEpen_1-1665638891951.png

 

Advanced script:

 

 

 

(function executeRule(current, previous /*null when async*/) {

	var targets = new GlideRecord("scan_target");
	targets.setLimit(1);
	targets.orderByDesc("sys_created_on");
	targets.addQuery("record_id", current.getUniqueValue());
	targets.addQuery("table",current.getTableName());
	targets.query();
	if(!targets.hasNext()){
		current.setAbortAction(true);
		gs.addErrorMessage("You must complete a scan and address findings before completing this update set");
	} else {
		targets.next();
		var combo = new GlideRecord("scan_combo");
		combo.setLimit(1);
		combo.orderByDesc("sys_created_on");
		combo.addQuery("targets","CONTAINS",targets.getUniqueValue());
		combo.query();
		combo.next();
		
		var results = new GlideRecord("scan_result");
		results.get("combo", combo.getUniqueValue());
		
		var findings = new GlideRecord("scan_finding");
		findings.addQuery("result", results.getUniqueValue());
		findings.addQuery("priority","IN","1,2");
		findings.query();
		if(findings.next()){
			current.setAbortAction(true);
			gs.addErrorMessage("Your update set contains unresolved critical findings, please address them before completing this update set")
		}
	}
	
	
})(current, previous);

 

 

 

What is the script doing?

First of all, we will check whether any scan findings exist where this update set is the target. If none are found, that means the admin hasn't scanned their set yet, so we will block the update with a message telling them to run the scan.

 

Secondly, if there is result, then we need to jump through a couple tables which join the results together so that we can test whether the results of the scan are to our liking.

In this example, we are blocking the update if any Priority 1 or 2 findings exist in the most recent scan of the update set.

 

As mentioned earlier, a new set of findings is created each time a scan is run, we can use this in our Business Rule to limit our script to only search for the findings on the most recent scan. This means if a developer runs the scan and fails the test with P1 or P2 findings, they can fix the findings, scan the update set again, and then they will be allowed to complete their update set.

 

Additional configuration and considerations

The Category field on checks can be extended to suit your use cases. For example you might add a "Completeness" category which is for focusing on completely filling out a record with recommended fields.

 

As part of Instance Scan there exists a table called Scan Task where a record can be assigned to an admin to remediate a scan finding. You could incorporate these tasks into your automation solution to distribute the remediation efforts between multiple developers.

 

Loading up your instance with existing scans

No need to re-invent the wheel, the SN Dev program has already compiled a list of Instance Scan checks which you can download to your instance at the link below:

https://github.com/ServiceNowDevProgram/example-instancescan-checks 

 

You can use these as a baseline or inspiration for building up your own instance quality controls

Comments
Vijaya Rajoli
Tera Explorer

Very nice article

HugoFirst
Kilo Sage

Excellent article!  I wasn't aware of the instance scan capability and I just now found that we have 87 checks defined out of the box.  I found an existing suite and ran it on my dev instance.  Still waiting on the results.  Great job Luke!

Hima Pallela1
Tera Guru

How do I import this into my PDI? I tried to import from Studio by proving below URL, my personal git userid and pwd. but it throws an error. Please advise

 

https://github.com/ServiceNowDevProgram/example-instancescan-checks.git'

 

{"error.message":"Repository authentication failed, check credentials. Make sure the user has both read and write access","exception.message":"org.eclipse.jgit.api.errors.TransportException: https:\/\/github.com\/ServiceNowDevProgram\/example-instancescan-checks.git: not authorized","exception.class":"com.glide.sourcecontrol.SourceControlException","error.code":"1001"}

Luke Van Epen
Tera Guru

@Hima Pallela1  you need to Fork the repo before you can import it into your instance, however the majority of these checks are now included in the baseline platform so you should no longer need to download them from the GitHub repo.

Version history
Last update:
‎11-06-2022 08:04 PM
Updated by:
Contributors