VirusTotal #24
This file contains hidden or 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: VirusTotal | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| release_tag: | |
| description: "Release tag - eg v1.0-v1.18-r2 (default: latest)" | |
| required: false | |
| type: string | |
| env: | |
| HAS_VT_API_KEY: ${{ secrets.VIRUSTOTAL_API_KEY != '' }} | |
| permissions: | |
| contents: write | |
| jobs: | |
| scan-release-assets: | |
| name: Scan release assets with VirusTotal | |
| runs-on: ubuntu-latest | |
| steps: | |
| - | |
| name: Setup | |
| if: env.HAS_VT_API_KEY == 'true' | |
| id: setup | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| TAG_NAME="$(printf '%s' '${{ inputs.release_tag }}' | xargs)" | |
| if [ -z "$TAG_NAME" ]; then | |
| TAG_NAME="$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName --jq '.tagName')" | |
| fi | |
| printf 'Using tag: %s\n' "$TAG_NAME" | |
| echo "tag-name=$TAG_NAME" >>"$GITHUB_OUTPUT" | |
| - | |
| name: Checkout | |
| if: env.HAS_VT_API_KEY == 'true' | |
| uses: actions/checkout@v6 | |
| - | |
| name: Create assets directory | |
| if: env.HAS_VT_API_KEY == 'true' | |
| run: mkdir release-assets | |
| - | |
| name: Download release assets | |
| if: env.HAS_VT_API_KEY == 'true' | |
| working-directory: release-assets | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh release view "${{ steps.setup.outputs.tag-name }}" --repo "$GITHUB_REPOSITORY" --json assets --jq '.assets[].url' | while read -r url; do | |
| echo "Downloading $url" | |
| gh api -H 'Accept: application/octet-stream' "$url" >"$(basename "$url")" | |
| done | |
| echo 'Assets downloaded:' | |
| ls -l | |
| - | |
| name: Build assets list | |
| if: env.HAS_VT_API_KEY == 'true' | |
| id: build-assets-list | |
| run: | | |
| printf 'assets<<EOF\n' >>"$GITHUB_OUTPUT" | |
| ./service/list-assets.sh release-assets >>"$GITHUB_OUTPUT" | |
| printf 'EOF\n' >>"$GITHUB_OUTPUT" | |
| cat "$GITHUB_OUTPUT" | |
| - | |
| name: Submit to VirusTotal | |
| if: env.HAS_VT_API_KEY == 'true' | |
| id: submit | |
| uses: crazy-max/ghaction-virustotal@v4 | |
| with: | |
| vt_api_key: ${{ secrets.VIRUSTOTAL_API_KEY }} | |
| update_release_body: false | |
| request_rate: 4 | |
| files: ${{ steps.build-assets-list.outputs.assets }} | |
| - | |
| name: Update release body with VirusTotal report | |
| if: steps.submit.outputs.analysis | |
| uses: actions/github-script@v8 | |
| env: | |
| TAG_NAME: ${{ steps.setup.outputs.tag-name }} | |
| ANALYSIS_RESULT: ${{ steps.submit.outputs.analysis }} | |
| with: | |
| script: | | |
| const MARKER_START = '<!-- virustotal -->'; | |
| const MARKER_END = '<!-- /virustotal -->'; | |
| const tagName = process.env.TAG_NAME; | |
| const analysisResult = (process.env.ANALYSIS_RESULT || '').trim(); | |
| if (analysisResult === '') { | |
| core.setFailed('Analysis output is empty'); | |
| return; | |
| } | |
| const {owner, repo} = context.repo; | |
| const release = await github.rest.repos.getReleaseByTag({ | |
| owner, | |
| repo, | |
| tag: tagName, | |
| }); | |
| const originalBody = release.data.body || ''; | |
| if (originalBody.trim() === '') { | |
| core.setFailed('Release body is empty'); | |
| return; | |
| } | |
| let detailsLines = []; | |
| const analysisLines = analysisResult | |
| .split(',') | |
| .map(line => line.trim()) | |
| .filter(line => line !== '') | |
| ; | |
| analysisLines.forEach(analysisLine => { | |
| const match = analysisLine.match(/^\s*(.+?)\s*=\s*(https?:\/\/\S+)\s*$/); | |
| if (!match) { | |
| core.warning(`Skipping invalid analysis line: ${analysisLine}`); | |
| return; | |
| } | |
| const [_, filename, analysisURL] = match; | |
| detailsLines.push(`* [${filename}](${analysisURL})`); | |
| }); | |
| if (detailsLines.length === 0) { | |
| core.warning('No valid analysis lines found, skipping update.'); | |
| return; | |
| } | |
| const newBody = originalBody.replace(/[\r\n]+$/, '') + `\n\n${MARKER_START}\n## VirusTotal Analysis\n\n${detailsLines.join('\n')}\n\n${MARKER_END}\n`; | |
| core.startGroup('New release body'); | |
| console.log(newBody); | |
| core.endGroup(); | |
| if (originalBody.includes(MARKER_START) && originalBody.includes(MARKER_END)) { | |
| core.notice('Release body already contains VirusTotal analysis, skipping update.'); | |
| return; | |
| } | |
| await github.rest.repos.updateRelease({ | |
| owner, | |
| repo, | |
| release_id: release.data.id, | |
| body: newBody, | |
| }); |