Skip to content

[FP]: use a negative rule for cpe:2.3:a:sms:sms:*:*:*:*:*:*:*:* suppression matching for Maven artifacts #6349

[FP]: use a negative rule for cpe:2.3:a:sms:sms:*:*:*:*:*:*:*:* suppression matching for Maven artifacts

[FP]: use a negative rule for cpe:2.3:a:sms:sms:*:*:*:*:*:*:*:* suppression matching for Maven artifacts #6349

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,
});