Skip to content

Commit

Permalink
Scan all add-ons with VT
Browse files Browse the repository at this point in the history
  • Loading branch information
seanbudd committed Jun 13, 2024
1 parent 8f72263 commit a739545
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 38 deletions.
17 changes: 11 additions & 6 deletions .github/workflows/checkAndSubmitAddonMetadata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
script: |
const addonId = "${{ steps.getAddonId.outputs.result }}"
return addonId.replace(/[^a-zA-Z0-9]/g, "")
- name: Copy add-on metadata file
- name: Copy add-on metadata file
run: |
Copy-Item ${{ steps.getAddonFileName.outputs.result }} addonMetadata.json
- name: Upload add-on
Expand Down Expand Up @@ -155,6 +155,7 @@ jobs:
issues: write
outputs:
pullRequestNumber: ${{ steps.cpr.outputs.pull-request-number }}
addonFileName: ${{ steps.getAddonFileName.outputs.addonFileName }}
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down Expand Up @@ -247,6 +248,10 @@ jobs:
uses: actions/download-artifact@v4
with:
name: addonMetadata
- name: Install Node.js
uses: actions/setup-node@v2
- name: Install glob
run: npm install glob
- name: Install virusTotal
run: choco install vt-cli
- name: Set Virus Total analysis status
Expand All @@ -255,7 +260,7 @@ jobs:
with:
script: |
const setVirusTotalAnalysisStatus = require('./.github/workflows/virusTotalAnalysis.js')
setVirusTotalAnalysisStatus({core})
setVirusTotalAnalysisStatus({core}, "${{ needs.createPullRequest.outputs.getAddonFileName }}")
- name: Upload results
id: uploadResults
if: failure()
Expand Down Expand Up @@ -313,7 +318,7 @@ jobs:
commit-message: Add reviewed add-on (${{ needs.getAddonId.outputs.addonId }})
body: |
This add-on needs to be reviewed by NV Access due to analysis failure.
Review ${{ inputs.issueNumber }} for more information.
Review #${{ inputs.issueNumber }} for more information.
author: github-actions <[email protected]>
delete-branch: true
- name: Request to keep issue opened
Expand All @@ -340,7 +345,7 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
gh pr merge ${{ inputs.issueAuthorName }}${{ inputs.issueNumber }} -b '[Automated] Merged ${{ needs.getAddonId.outputs.addonFileName }} into master (PR #${{ needs.createPullRequest.outputs.pullRequestNumber }})' -m
createReviewComment:
# jq for windows has issues parsing multiline strings (e.g. CRLF),
# use linux instead.
Expand Down Expand Up @@ -399,7 +404,7 @@ jobs:
.[\"$addonId\"].discussionId = \"$discussionId\"
| .[\"$addonId\"].discussionUrl = \"$discussionUrl\"
"
mv discussions.json discussions.old.json
jq -e "$jqCode" discussions.old.json > discussions.json
jqExitCode=$?
Expand All @@ -420,7 +425,7 @@ jobs:
jqCode="
.[\"reviewUrl\"] = $reviewUrl
"
mv $addonFilename $addonFilename.old.json
jq -e -a "$jqCode" $addonFilename.old.json > $addonFilename
jqExitCode=$?
Expand Down
55 changes: 55 additions & 0 deletions .github/workflows/virusScanAllAddons.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Scan all submitted add-ons with Virus Total

on:
workflow_dispatch:

jobs:
virusTotal-analysis:
runs-on: windows-latest
strategy:
matrix:
python-version: [ 3.11 ]
permissions:
contents: read
env:
VT_API_KEY: ${{ secrets.VT_API_KEY }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ inputs.headRef }}
- name: Install virusTotal
run: choco install vt-cli
- name: Install Node.js
uses: actions/setup-node@v2
- name: Install glob
run: npm install glob
- name: Submit add-ons with VirusTotal
uses: actions/github-script@v7
with:
script: |
const virusTotalSubmit = require('./.github/workflows/virusTotalSubmit.js')
virusTotalSubmit({core}, "./addons/*/*.json")
- name: Set Virus Total analysis status
id: setVirusTotalAnalysisStatus
uses: actions/github-script@v7
with:
script: |
const setVirusTotalAnalysisStatus = require('./.github/workflows/virusTotalAnalysis.js')
setVirusTotalAnalysisStatus({core}, "./addons/*/*.json")
- name: Upload results
id: uploadResults
if: failure()
uses: actions/upload-artifact@v4
with:
name: VirusTotal
path: vt.json
overwrite: true
- name: Upload manual approval
id: uploadManualApproval
if: failure()
uses: actions/upload-artifact@v4
with:
name: manualApproval
path: reviewedAddons.json
overwrite: true
69 changes: 37 additions & 32 deletions .github/workflows/virusTotalAnalysis.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,43 @@
module.exports = ({core}) => {
const glob = require('glob');

module.exports = ({core}, globPattern) => {
const fs = require('fs');
const { exec } = require('child_process');
const addonMetadataContents = fs.readFileSync('addonMetadata.json');
const addonMetadata = JSON.parse(addonMetadataContents);
const addonId = addonMetadata.addonId;
core.setOutput('addonId', addonId);
const sha256 = addonMetadata.sha256;
const analysisUrl = `https://www.virustotal.com/gui/file/${sha256}`;
console.log(analysisUrl);
core.setOutput('analysisUrl', analysisUrl);
const reviewedAddonsContents = fs.readFileSync('reviewedAddons.json');
const reviewedAddonsData = JSON.parse(reviewedAddonsContents);
if (reviewedAddonsData[addonId] !== undefined && reviewedAddonsData[addonId].includes(sha256)) {
core.info('VirusTotal analysis skipped');
return;
}
exec(`vt file ${sha256} -k ${process.env.VT_API_KEY} --format json`, (err, stdout, stderr) => {
console.log(`err: ${err}`);
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
const vtData = JSON.parse(stdout);
fs.writeFileSync('vt.json', stdout);
const stats = vtData[0]["last_analysis_stats"];
const malicious = stats.malicious;
if (malicious === 0) {
core.info('VirusTotal analysis succeeded');
files = glob.globSync(globPattern);
files.forEach(file => {
const addonMetadataContents = fs.readFileSync(file);
const addonMetadata = JSON.parse(addonMetadataContents);
const addonId = addonMetadata.addonId;
core.setOutput('addonId', addonId);
const sha256 = addonMetadata.sha256;
const analysisUrl = `https://www.virustotal.com/gui/file/${sha256}`;
console.log(analysisUrl);
core.setOutput('analysisUrl', analysisUrl);
const reviewedAddonsContents = fs.readFileSync('reviewedAddons.json');
const reviewedAddonsData = JSON.parse(reviewedAddonsContents);
if (reviewedAddonsData[addonId] !== undefined && reviewedAddonsData[addonId].includes(sha256)) {
core.info('VirusTotal analysis skipped');
return;
}
if (reviewedAddonsData[addonId] === undefined) {
reviewedAddonsData[addonId] = [];
}
reviewedAddonsData[addonId].push(sha256);
stringified = JSON.stringify(reviewedAddonsData, null, 2);
fs.writeFileSync('reviewedAddons.json', stringified);
core.setFailed('VirusTotal analysis failed');
exec(`vt file ${sha256} -k ${process.env.VT_API_KEY} --format json`, (err, stdout, stderr) => {
console.log(`err: ${err}`);
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
const vtData = JSON.parse(stdout);
fs.writeFileSync('vt.json', stdout);
const stats = vtData[0]["last_analysis_stats"];
const malicious = stats.malicious;
if (malicious === 0) {
core.info('VirusTotal analysis succeeded');
return;
}
if (reviewedAddonsData[addonId] === undefined) {
reviewedAddonsData[addonId] = [];
}
reviewedAddonsData[addonId].push(sha256);
stringified = JSON.stringify(reviewedAddonsData, null, 2);
fs.writeFileSync('reviewedAddons.json', stringified);
core.setFailed('VirusTotal analysis failed');
});
});
};
38 changes: 38 additions & 0 deletions .github/workflows/virusTotalSubmit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const glob = require('glob');

module.exports = ({core}, globPattern) => {
const fs = require('fs');
const { exec } = require('child_process');
files = glob.globSync(globPattern);
files.forEach(file => {
const addonMetadataContents = fs.readFileSync(file);
const addonMetadata = JSON.parse(addonMetadataContents);
const addonId = addonMetadata.addonId;
const sha256 = addonMetadata.sha256;
exec(`vt file ${sha256} -k ${process.env.VT_API_KEY} --format json`, (err, stdout, stderr) => {
if (stderr === '' || err === null) {
// File has been scanned before
return;
}
console.log(`err: ${err}`);
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
// download add-on file
exec(`curl --location --output ${addonId}.nvda-addon "${addonMetadata.URL}"`, (err, stdout, stderr) => {
if (stderr !== '' || err !== null) {
console.log(`err: ${err}`);
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
core.setFailed('Failed to download add-on file');
return;
}
// scan downloaded file
exec(`vt scan file -k ${process.env.VT_API_KEY} ${addonId}.nvda-addon`, (err, stdout, stderr) => {
console.log(`err: ${err}`);
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
})
})
});
});
};

0 comments on commit a739545

Please sign in to comment.