[FP]: use a negative rule for cpe:2.3:a:sms:sms:*:*:*:*:*:*:*:* suppression matching for Maven artifacts #6349
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: False Positive Approvals | |
on: | |
issue_comment: | |
types: [ created ] | |
permissions: {} | |
jobs: | |
update_suppression: | |
permissions: | |
contents: write # to push changes in repo (jamesives/github-pages-deploy-action) | |
issues: write | |
name: Update Suppression Rules | |
if: ${{ !github.event.issue.pull_request && | |
contains(github.event.issue.labels.*.name, 'FP Report') && | |
contains(github.event.comment.body,'approved') && | |
(github.event.comment.user.login == 'jeremylong' || | |
github.event.comment.user.login == 'aikebah' || | |
github.event.comment.user.login == 'nhumblot' || | |
github.event.comment.user.login == 'chadlwilson') }} | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
ref: generatedSuppressions | |
- uses: actions/setup-node@v4.1.0 | |
- run: | | |
npm install fast-xml-parser@4.0.9 | |
npm install fs | |
- name: Commit Suppression Rule | |
id: fp-ops-commit | |
uses: actions/github-script@v7.0.1 | |
with: | |
script: | | |
const { execSync } = require("child_process"); | |
const { XMLParser } = require("fast-xml-parser"); | |
const fs = require('fs'); | |
console.log('evaluating issue #' + context.issue.number); | |
const { data: comments } = await github.rest.issues.listComments({ | |
issue_number: context.issue.number, | |
owner: context.issue.owner, | |
repo: context.issue.repo, | |
}) | |
console.log('author0: ' + comments[0].user.login); | |
console.log('comments0: ' + comments[0].body); | |
let botComments = comments.filter(comment => | |
comment.user.login === 'github-actions[bot]' && | |
comment.body.includes('<suppress base="true">') && | |
comment.body.includes('Suppression rule:') | |
) | |
console.log('bot comments: ' + botComments); | |
if (botComments.length<=0) { | |
console.log('Suppression rule from github-actions not found'); | |
core.setOutput('publish', 'false'); | |
//using core.setFailed() ended execution and the check for failure below (to post a message did not work) | |
core.setOutput('failed', 'true'); | |
return; | |
} | |
let lastComment = botComments[botComments.length-1]; | |
let data = lastComment.body.split('```'); | |
let suppression = data[data.length-2].substring(3).trim(); | |
console.log("suppression rule: " + suppression); | |
const options = { | |
ignoreAttributes : true | |
}; | |
const parser = new XMLParser(options); | |
let proposedRule = parser.parse(suppression); | |
let commitComment = proposedRule.suppress.notes.trim(); | |
commitComment = commitComment.replace(/[[\]{}`'";|\/\\]/g, ''); | |
console.log("commit comment: " + commitComment); | |
//validate we haven't already suppressed this one. | |
const generatedSuppressions = fs.readFileSync('generatedSuppressions.xml', 'utf8'); | |
let found = false; | |
let previousReportNotes = ''; | |
if (!(generatedSuppressions && generatedSuppressions.trim() === '')) { | |
let rules = parser.parse(generatedSuppressions); | |
for (r of rules.suppress) { | |
if (proposedRule.suppress.packageUrl === r.packageUrl && | |
proposedRule.suppress.cpe === r.cpe) { | |
found = true; | |
previousReportNotes = r.notes.trim(); | |
break; | |
} | |
} | |
} | |
if (found) { | |
let prevIssue = previousReportNotes.split('#')[1].trim(); | |
github.rest.issues.createComment({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: 'Suppress already exists in `generatedSuppressions` branch. See issue #' + prevIssue + '.', | |
}); | |
github.rest.issues.addLabels({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
labels: ['duplicate'] | |
}); | |
github.rest.issues.update({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
state: 'closed', | |
}); | |
core.setOutput('publish', 'false'); | |
} else { | |
fs.appendFileSync('generatedSuppressions.xml', '\n' + suppression.trim(), function (err) { | |
if (err) throw err; | |
console.log('Suppression rule added'); | |
}); | |
if (!fs.existsSync('./suppressions')){ | |
fs.mkdirSync('./suppressions'); | |
} | |
fs.appendFileSync('suppressions/publishedSuppressions.xml', '<?xml version="1.0" encoding="UTF-8"?>\n<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">' + generatedSuppressions + '\n' + suppression.trim() + '\n</suppressions>', function (err) { | |
if (err) throw err; | |
console.log('publishedSuppressions.xml created'); | |
}); | |
fs.appendFileSync('.git/config', ` | |
[user] | |
name = github-actions[bot] | |
email = 41898282+github-actions[bot]@users.noreply.github.com | |
`, err => { | |
if (err) throw err; | |
}); | |
execSync('git commit -m "fix(fp): ' + commitComment + '" generatedSuppressions.xml;git push origin generatedSuppressions', (err, stdout, stderr) => { | |
if (err) throw err; | |
console.log('committed suppression rule'); | |
}); | |
github.rest.issues.createComment({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: 'Suppress rule has been added to the `generatedSuppressions` branch.', | |
}); | |
github.rest.issues.update({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
state: 'closed', | |
}); | |
core.setOutput('publish', 'true'); | |
} | |
- name: Publish Updated Suppressions | |
if: ${{ steps.fp-ops-commit.outputs.publish == 'true' }} | |
uses: JamesIves/github-pages-deploy-action@v4.7.2 | |
with: | |
branch: gh-pages | |
folder: suppressions | |
target-folder: suppressions | |
- name: Message failure | |
if: ${{ failure() || steps.fp-ops-commit.outputs.failed }} | |
uses: actions/github-script@v7.0.1 | |
with: | |
script: | | |
github.rest.issues.createComment({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: 'Failed to automatically generate and publish the suppression rule!\n\n' + 'Link to action run: ' + context.serverUrl + '/' + context.repo.owner + '/' + context.repo.repo + '/actions/runs/' + context.runId, | |
}); |