Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for VirusTotal #61

Merged
merged 6 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 97 additions & 2 deletions .github/workflows/checkAndSubmitAddonMetadata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ on:
issueTitle:
required: true
type: string
secrets:
virusTotalApiKey:
required: true

jobs:
getAddonId:
Expand Down Expand Up @@ -225,11 +228,103 @@ jobs:
uses: peter-evans/close-issue@v3
with:
issue-number: ${{ inputs.issueNumber }}
codeQL-analysis:

virusTotal-analysis:
needs: createPullRequest
runs-on: windows-latest
strategy:
matrix:
python-version: [ 3.11 ]
permissions:
contents: read
issues: write
env:
API_KEY: ${{ secrets.virusTotalApiKey }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download add-on metadata
uses: actions/download-artifact@v4
with:
name: addonMetadata
- name: Install virusTotal
run: choco install vt-cli
seanbudd marked this conversation as resolved.
Show resolved Hide resolved
- name: Set Virus Total analysis status
id: setVirusTotalAnalysisStatus
uses: actions/github-script@v7
with:
script: |
const setVirusTotalAnalysisStatus = require('./.github/workflows/virusTotalAnalysis.js')
setVirusTotalAnalysisStatus({core})
- 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
- name: Warn if analysis fails
if: failure()
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ inputs.issueNumber }}
body: |
VirusTotal has flagged this add-on as malicious.
You can open this link and [see the results of the analysis](${{ steps.setVirusTotalAnalysisStatus.outputs.analysisUrl }}).
Please contact the flagged security vendors to get them to review and unflag the false positive.
Please ask here or email [email protected] if you need assistance with this process.
codeQL-analysis:
needs: [createPullRequest]
uses: ./.github/workflows/codeql-analysis.yml
createManualApproval:
needs: [getAddonId, virusTotal-analysis, codeQL-analysis]
if: ${{ always() && contains(join(needs.*.result, ','), 'failure') }}
runs-on: windows-latest
strategy:
matrix:
python-version: [ 3.11 ]
permissions:
contents: write
issues: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Create pull request
id: cpr
uses: peter-evans/create-pull-request@v6
with:
add-paths: reviewedAddons.json
title: Add reviewed add-on (${{ needs.getAddonId.outputs.addonId }})
branch: reviewedAddon${{ github.event.issue.number }}
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.
author: github-actions <[email protected]>
delete-branch: true
- name: Request to keep issue opened
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ inputs.issueNumber }}
body: |
Please, don't close this issue.
Wait until #${{ steps.cpr.outputs.pull-request-number }} is merged.
mergeToMaster:
needs: [getAddonId, createPullRequest, codeQL-analysis]
needs: [getAddonId, createPullRequest, codeQL-analysis, virusTotal-analysis]
permissions:
contents: write
pull-requests: write
Expand Down
21 changes: 7 additions & 14 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ jobs:
runs-on: windows-latest
permissions:
actions: read
contents: write
contents: read
security-events: write
issues: write
pull-requests: write
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -69,18 +68,14 @@ jobs:
name: results-${{ matrix.language }}
path: results/*.sarif
overwrite: true
- name: Create pull request
id: cpr
- name: Upload manual approval
id: uploadManualApproval
if: failure()
uses: peter-evans/create-pull-request@v6
uses: actions/upload-artifact@v4
with:
add-paths: reviewedAddons.json
title: Add reviewed add-on (${{ steps.setSecurityAnalysisStatus.outputs.addonId }})
branch: reviewedAddon${{ github.event.issue.number }}
commit-message: Add reviewed add-on (${{ steps.setSecurityAnalysisStatus.outputs.addonId }})
body: "This add-on needs to be reviewed by NV Access due to security analysis failure"
author: github-actions <[email protected]>
delete-branch: true
name: manualApproval
path: reviewedAddons.json
overwrite: true
- name: Warn if analysis fails
if: failure()
uses: peter-evans/create-or-update-comment@v4
Expand All @@ -95,8 +90,6 @@ jobs:
Please review the warnings and consider fixing this in the add-on.
If you can provide more context on the failure in the submission, please do.
See the [submission guide](https://github.com/nvaccess/addon-datastore/blob/master/docs/submitters/submissionGuide.md) for more details.
Please, don't close this issue.
Wait until #${{ steps.cpr.outputs.pull-request-number }} is merged.
analyze:
name: Analyze add-on
needs: analyzeExcludingWarnings
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/sendJsonFile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ jobs:
with:
name: addon
path: addon.nvda-addon
- name: Install VirusTotal
run: choco install vt-cli
- name: Scan add-on with VirusTotal
env:
API_KEY: ${{ secrets.virusTotalApiKey }}
run: vt scan file -k $env:API_KEY addon.nvda-addon
call-workflow-passing-data:
needs: check-addon
uses: ./.github/workflows/checkAndSubmitAddonMetadata.yml
Expand All @@ -98,3 +104,5 @@ jobs:
issueAuthorId: ${{ github.event.issue.user.id }}
issueAuthorName: ${{ github.event.issue.user.login }}
issueTitle: ${{ github.event.issue.title }}
secrets:
virusTotalApiKey: ${{ secrets.virusTotalApiKey }}
38 changes: 38 additions & 0 deletions .github/workflows/virusTotalAnalysis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module.exports = ({core}) => {
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.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');
});
};
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ The add-on store includes the following security measures:
- The checksum allows NVDA to ensure that add-on releases are immutable.
- [Code scanning with CodeQL](https://docs.github.com/en/code-security/code-scanning/introduction-to-code-scanning/about-code-scanning-with-codeql) can detect vulnerabilities in Python and JavaScript code included in submitted add-ons.
- NV Access can manage [code scanning alerts](https://docs.github.com/en/code-security/code-scanning/managing-code-scanning-alerts/about-code-scanning-alerts), available from the Code scanning link from the [Security page](https://github.com/nvaccess/addon-datastore/security).
- [Virus Total](https://www.virustotal.com/) is used to scan submitted add-ons.
If malicious content is detected, the add-on will not be automatically included in the store.
Please contact the flagged security vendors to get them to review and unflag the false positive.
Please email [email protected] if you need assistance with this process.


### Human review process / code audit
Expand Down