Skip to content

Commit

Permalink
feat: parser truncates values to conform with API spec (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
Matte22 authored Jun 13, 2024
1 parent 9851635 commit e54970e
Show file tree
Hide file tree
Showing 14 changed files with 779 additions and 24 deletions.
88 changes: 64 additions & 24 deletions ReviewParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import decode from './decode.js'
const decodeHTML = function () {
return decode(arguments[1])
}

const truncateString = function (str, max) {
if (typeof str !== 'string') {
return str
}
return str.length > max ? str.slice(0, max) : str
}

const maxCommentLength = 32767
/**
* Parses data from a CKL format into a format suitable for further processing.
*
Expand All @@ -29,8 +38,6 @@ export function reviewsFromCkl(

const errorMessages = []

const maxCommentLength = 32767

const normalizeKeys = function (input) {
// lowercase and remove hyphens
if (typeof input !== 'object') return input;
Expand Down Expand Up @@ -82,6 +89,9 @@ export function reviewsFromCkl(
if (!returnObj.target.name) {
throw (new Error("No host_name in ASSET"))
}
if (returnObj.target.name.length > 255) {
throw (new Error("Asset hostname cannot be more than 255 characters", returnObj.target.name))
}
returnObj.checklists = processIStig(parsed.CHECKLIST[0].STIGS[0].iSTIG)
if (returnObj.checklists.length === 0) {
throw (new Error("STIG_INFO element has no SI_DATA for SID_NAME == stigId"))
Expand All @@ -94,9 +104,9 @@ export function reviewsFromCkl(
let obj = {
name: assetElement.HOST_NAME,
description: null,
ip: assetElement.HOST_IP || null,
fqdn: assetElement.HOST_FQDN || null,
mac: assetElement.HOST_MAC || null,
ip: assetElement?.HOST_IP ? truncateString(assetElement.HOST_IP, 255) : null,
fqdn: assetElement.HOST_FQDN ? truncateString(assetElement.HOST_FQDN, 255) : null,
mac: assetElement.HOST_MAC ? truncateString(assetElement.HOST_MAC, 255) : null,
noncomputing: assetElement.ASSET_TYPE === 'Non-Computing'
}
const metadata = {}
Expand Down Expand Up @@ -127,14 +137,15 @@ export function reviewsFromCkl(
// get benchmarkId
let stigIdElement = iStig.STIG_INFO[0].SI_DATA.filter(d => d.SID_NAME === 'stigid')?.[0]
checklist.benchmarkId = stigIdElement.SID_DATA.replace('xccdf_mil.disa.stig_benchmark_', '')
checklist.benchmarkId = truncateString(checklist.benchmarkId, 255)
// get revision data. Extract digits from version and release fields to create revisionStr, if possible.
const stigVersionData = iStig.STIG_INFO[0].SI_DATA.filter(d => d.SID_NAME === 'version')?.[0].SID_DATA
let stigVersion = stigVersionData.match(/(\d+)/)?.[1]
let stigReleaseInfo = iStig.STIG_INFO[0].SI_DATA.filter(d => d.SID_NAME === 'releaseinfo')?.[0].SID_DATA
const stigRelease = stigReleaseInfo.match(/Release:\s*(.+?)\s/)?.[1]
const stigRevisionStr = stigVersion && stigRelease ? `V${stigVersion}R${stigRelease}` : null
checklist.revisionStr = stigRevisionStr

if (checklist.benchmarkId) {
let x = processVuln(iStig.VULN, iStig.__comment)
checklist.reviews = x.reviews
Expand Down Expand Up @@ -185,7 +196,8 @@ export function reviewsFromCkl(
function generateReview(vuln, iStigComment) {
let result = resultMap[vuln.STATUS]
if (!result) return
const ruleId = getRuleIdFromVuln(vuln)
let ruleId = getRuleIdFromVuln(vuln)
ruleId = truncateString(ruleId, 45)
if (!ruleId) return

const hasComments = !!vuln.FINDING_DETAILS || !!vuln.COMMENTS
Expand All @@ -204,7 +216,7 @@ export function reviewsFromCkl(
}
}

let detail = vuln.FINDING_DETAILS.length > maxCommentLength ? vuln.FINDING_DETAILS.slice(0, maxCommentLength) : vuln.FINDING_DETAILS
let detail = vuln.FINDING_DETAILS.length > maxCommentLength ? truncateString(vuln.FINDING_DETAILS, maxCommentLength) : vuln.FINDING_DETAILS
if (!vuln.FINDING_DETAILS) {
switch (importOptions.emptyDetail) {
case 'ignore':
Expand All @@ -219,7 +231,7 @@ export function reviewsFromCkl(
}
}

let comment = vuln.COMMENTS.length > maxCommentLength ? vuln.COMMENTS.slice(0, maxCommentLength) : vuln.COMMENTS
let comment = vuln.COMMENTS.length > maxCommentLength ? truncateString(vuln.COMMENTS, maxCommentLength) : vuln.COMMENTS
if (!vuln.COMMENTS) {
switch (importOptions.emptyComment) {
case 'ignore':
Expand Down Expand Up @@ -261,7 +273,7 @@ export function reviewsFromCkl(
override = normalizeKeys(override)
if (override.afmod?.toLowerCase() === 'true') {
overrides.push({
authority: override.answerfile,
authority: truncateString(override?.answerfile, 255),
oldResult: resultMap[override.oldstatus] ?? 'unknown',
newResult: result,
remark: 'Evaluate-STIG Answer File'
Expand Down Expand Up @@ -400,10 +412,11 @@ export function reviewsFromCkl(
errorMessages.push(`Failed to parse Evaluate-STIG root XML comment for ${comment}`)
}
esRootComment = normalizeKeys(esRootComment)
const version = esRootComment?.global?.[0]?.version || esRootComment?.version
resultEngineRoot = {
type: 'script',
product: 'Evaluate-STIG',
version: esRootComment?.global?.[0]?.version || esRootComment?.version,
version: truncateString(version, 255),
time: esRootComment?.global?.[0]?.time,
checkContent: {
location: (esRootComment?.module?.[0]?.name ?? '') +
Expand Down Expand Up @@ -504,11 +517,27 @@ export function reviewsFromXccdf(
if (scapBenchmarkMap?.has(benchmarkId)) {
benchmarkId = scapBenchmarkMap.get(benchmarkId)
}
benchmarkId = truncateString(benchmarkId, 255)
const target = processTarget(testResult)
if (!target.name) {
throw (new Error('No value for <target>'))
}

if(target.name.length > 255){
throw (new Error('Asset hostname cannot be more than 255 characters', target.name))
}
if(target.fqdn){
target.fqdn = truncateString(target.fqdn, 255)
}
if(target.mac){
target.mac = truncateString(target.mac, 255)
}
if(target.ip){
target.ip = truncateString(target.ip, 255)
}
if(target.description){
target.description = truncateString(target.description, 255)
}

// resultEngine info
const testSystem = testResult['test-system']
// SCC injects a CPE WFN bound to a URN
Expand All @@ -525,6 +554,10 @@ export function reviewsFromXccdf(
product,
version
}

resultEngineTpl.version = truncateString(resultEngineTpl.version, 255)
resultEngineTpl.product = truncateString(resultEngineTpl.product, 255)

const r = processRuleResults(testResult['rule-result'], resultEngineTpl)

// Return object
Expand Down Expand Up @@ -566,7 +599,8 @@ export function reviewsFromXccdf(
function generateReview(ruleResult, resultEngineCommon) {
let result = ruleResult.result
if (!result) return
const ruleId = ruleResult.idref.replace('xccdf_mil.disa.stig_rule_', '')
let ruleId = ruleResult.idref.replace('xccdf_mil.disa.stig_rule_', '')
ruleId = truncateString(ruleId, 45)
if (!ruleId) return

const hasComments = false // or look for <remark>
Expand Down Expand Up @@ -603,18 +637,18 @@ export function reviewsFromXccdf(
if (checkContentHref || checkContentName) {
resultEngine.checkContent = {
location: checkContentHref,
component: checkContentName
component: truncateString(checkContentName, 255)
}
}

if (ruleResult.override?.length) { //overrides
const overrides = []
for (const override of ruleResult.override) {
overrides.push({
authority: override.authority,
authority: truncateString(override?.authority,255),
oldResult: override['old-result'],
newResult: override['new-result'],
remark: override['remark']
remark: truncateString(override['remark'],255)
})
}
if (overrides.length) {
Expand All @@ -640,6 +674,7 @@ export function reviewsFromXccdf(
break
}
}
detail = truncateString(detail, maxCommentLength)

let comment = ruleResult.check?.['check-content']?.comment
if (!comment) {
Expand All @@ -655,6 +690,7 @@ export function reviewsFromXccdf(
break
}
}
comment = truncateString(comment, maxCommentLength)

const review = {
ruleId,
Expand Down Expand Up @@ -780,7 +816,6 @@ export function reviewsFromCklb(
sourceRef
}) {

const maxCommentLength = 32767
const resultMap = {
not_a_finding: 'pass',
open: 'fail',
Expand Down Expand Up @@ -825,6 +860,9 @@ export function reviewsFromCklb(
if (!returnObj.target.name) {
throw (new Error("No host_name in target_data"))
}
if(returnObj.target.name.length > 255){
throw (new Error("Asset hostname cannot be more than 255 characters", returnObj.target.name))
}
returnObj.checklists = processStigs(cklb.stigs)
if (returnObj.checklists.length === 0) {
throw (new Error("stigs array is empty"))
Expand All @@ -834,10 +872,10 @@ export function reviewsFromCklb(
function processTargetData(td) {
const obj = {
name: td.host_name,
description: td.comments,
ip: td.ip_address || null,
fqdn: td.fqdn || null,
mac: td.mac_address || null,
description: td.comments ? truncateString(td.comments, 255): null,
ip: td.ip_address ? truncateString(td.ip_address, 255) : null,
fqdn: td.fqdn ? truncateString(td.fqdn, 255) : null,
mac: td.mac_address ? truncateString(td.mac_address, 255) : null,
noncomputing: td.target_type === 'Non-Computing',
metadata: {}
}
Expand Down Expand Up @@ -870,6 +908,7 @@ export function reviewsFromCklb(
// }
const checklist = { sourceRef }
checklist.benchmarkId = typeof stig?.stig_id === 'string' ? stig.stig_id.replace('xccdf_mil.disa.stig_benchmark_', '') : ''
checklist.benchmarkId = truncateString(checklist.benchmarkId, 255)
const stigVersion = '0'
const stigRelease = typeof stig?.release_info === 'string' ? stig.release_info.match(/Release:\s*(.+?)\s/)?.[1] : ''
checklist.revisionStr = checklist.benchmarkId && stigRelease ? `V${stigVersion}R${stigRelease}` : null
Expand Down Expand Up @@ -912,6 +951,7 @@ export function reviewsFromCklb(
let ruleId = rule.rule_id_src ?? rule.rule_id
if (!ruleId) return
ruleId = ruleId.endsWith('_rule') ? ruleId : ruleId + '_rule'
ruleId = truncateString(ruleId, 45)

const hasComments = !!rule.finding_details || !!rule.comments

Expand All @@ -929,7 +969,7 @@ export function reviewsFromCklb(
}
}

let detail = rule.finding_details?.length > maxCommentLength ? rule.finding_details.slice(0, maxCommentLength) : rule.finding_details
let detail = rule.finding_details?.length > maxCommentLength ? truncateString(rule.finding_details, maxCommentLength) : rule.finding_details
if (!rule.finding_details) {
switch (importOptions.emptyDetail) {
case 'ignore':
Expand All @@ -944,7 +984,7 @@ export function reviewsFromCklb(
}
}

let comment = rule.comments?.length > maxCommentLength ? rule.comments.slice(0, maxCommentLength) : rule.comments
let comment = rule.comments?.length > maxCommentLength ? truncateString(rule.comments, maxCommentLength) : rule.comments
if (!rule.comments) {
switch (importOptions.emptyComment) {
case 'ignore':
Expand Down Expand Up @@ -1062,7 +1102,7 @@ export function reviewsFromCklb(
resultEngineCommon = {
type: 'script',
product: 'Evaluate-STIG',
version: module.version,
version: truncateString(module.version, 255),
}
return resultEngineCommon
}
Expand Down
Loading

0 comments on commit e54970e

Please sign in to comment.