GitHub Actions scan test tool ZIPs before USB release by quarantining uploaded archives in a repository, validating and extracting them in an isolated runner, scanning both the ZIP and its contents with updated anti-malware signatures, and producing a hash-based release manifest. For MA.L2-3.7.4, the workflow should fail closed: no technician should receive a USB-release authorization unless the scan completed successfully, the evidence is retained, and an assigned approver accepts the release package.
NIST SP 800-171 Rev. 2 and CMMC 2.0 Level 2 practice MA.L2-3.7.4 require an organization to check media containing diagnostic and test programs for malicious code before use on organizational systems that process, store, or transmit CUI. This workflow does not eliminate the need for a human to prepare the removable media, but it creates a controlled technical gate before that person copies vendor diagnostics, firmware utilities, test executables, or troubleshooting scripts to a USB device.
What can be automated, and what still requires a person?
A GitHub Actions workflow can enforce the repeatable technical checks that are easiest to demonstrate to an assessor: archive validation, malware-signature updates, anti-malware scanning, SHA-256 hashing, evidence generation, retention, and approval workflow routing. It can also prevent an unscanned ZIP from being promoted to a “USB-ready” artifact.
It cannot confirm that a technician copied only the approved files to the correct physical USB device, that the USB device remains under physical control, or that the files were not changed after download. Those activities belong in the media-handling procedure. The person preparing the media should compare the ZIP hash on the release manifest to the hash of the file being copied, label the device with the release ticket, and record the destination system and technician.
| Activity | Automation status | Evidence retained |
|---|---|---|
| Validate ZIP structure and block unsafe paths | Automated | Workflow log and failed-job record |
| Update ClamAV signatures and scan archive contents | Automated | Scanner version, update log, and scan log |
| Calculate SHA-256 hashes | Automated | Release manifest |
| Approve use of a vendor diagnostic tool | Human approval | GitHub Environment approval and service ticket |
| Copy approved files to USB and verify hash | Human execution with documented verification | Technician attestation in ticket |
How can GitHub Actions scan test tool ZIPs before USB release?
Create a restricted repository such as security/test-tool-intake. Vendor files should be added only to an incoming/ folder through a controlled pull request or a service-account upload process. Do not allow technicians to download ZIPs directly from email or vendor portals and bypass the repository; that breaks the evidence chain needed to show that the media was checked before use.
What should the scanning script validate?
The script below scans the original ZIP and every extracted file. It rejects password-protected archives, path traversal entries, and archives whose uncompressed contents exceed 1 GB. The size limit is a practical defense against accidental or malicious archive bombs; adjust it only through documented change control if a legitimate vendor package requires more space.
#!/usr/bin/env bash
set -euo pipefail
shopt -s nullglob
mkdir -p evidence extracted
: > evidence/manifest.tsv
: > evidence/scan.log
echo -e "sha256\tfile\tworkflow_run\tcommit" > evidence/manifest.tsv
files=(incoming/*.zip)
if [ "${#files[@]}" -eq 0 ]; then
echo "No ZIP files found in incoming/" >&2
exit 2
fi
for zipfile in "${files[@]}"; do
base="$(basename "$zipfile" .zip)"
target="extracted/$base"
python3 - "$zipfile" <<'PY'
import sys, zipfile
archive = sys.argv[1]
with zipfile.ZipFile(archive) as z:
total = 0
for item in z.infolist():
name = item.filename.replace("\\", "/")
if item.flag_bits & 0x1:
raise SystemExit("Encrypted ZIP rejected: " + archive)
if name.startswith("/") or "../" in name.split("/"):
raise SystemExit("Unsafe ZIP path rejected: " + name)
total += item.file_size
if total > 1073741824:
raise SystemExit("ZIP exceeds 1 GB extracted-size limit: " + archive)
PY
unzip -t "$zipfile" > "evidence/${base}-zip-test.log"
rm -rf "$target"
mkdir -p "$target"
unzip -q "$zipfile" -d "$target"
sha256sum "$zipfile" | awk -v run="$GITHUB_RUN_ID" -v commit="$GITHUB_SHA" \
'{print $1 "\t" $2 "\t" run "\t" commit}' >> evidence/manifest.tsv
set +e
clamscan --recursive --infected --no-summary "$zipfile" "$target" \
>> evidence/scan.log 2>&1
result=$?
set -e
if [ "$result" -ne 0 ]; then
echo "Malware scan failed for $zipfile with ClamAV exit code $result" >&2
exit "$result"
fi
done
clamscan -V > evidence/clamav-version.txt
git rev-parse HEAD > evidence/source-commit.txt
echo "All diagnostic and test-tool ZIPs scanned clean."
ClamAV returns 0 for clean, 1 when malware is found, and 2 for an operational error. Treating both 1 and 2 as failures is important for MA.L2-3.7.4: an unavailable scanner or failed signature update is not evidence that the tool is safe.
What does the GitHub Actions workflow look like?
name: Scan test-tool ZIPs
on:
pull_request:
paths:
- "incoming/**/*.zip"
push:
branches: [main]
paths:
- "incoming/**/*.zip"
workflow_dispatch:
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Check out controlled source
uses: actions/checkout@v4
- name: Install and update ClamAV
run: |
sudo apt-get update
sudo apt-get install -y clamav clamav-freshclam unzip
sudo freshclam | tee evidence-freshclam.log
- name: Scan diagnostic and test-tool archives
run: |
mkdir -p evidence
mv evidence-freshclam.log evidence/freshclam.log
bash .github/scripts/scan-test-tool-zips.sh
- name: Retain scan evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: scan-evidence-$
path: evidence/
retention-days: 365
if-no-files-found: warn
usb-release-gate:
needs: scan
runs-on: ubuntu-24.04
environment: usb-release
steps:
- name: Authorize clean package for USB preparation
run: |
echo "Approved workflow run: $GITHUB_RUN_ID"
echo "Technician must verify SHA-256 before copying to USB."
Configure the usb-release GitHub Environment with required reviewers from compliance and IT operations. A successful scan job alone should not permit release; the environment approval documents that the vendor tool is expected, the associated ticket is valid, and the receiving technician is authorized to prepare removable media.
How should this be integrated into CI/CD and scheduled jobs?
Use the pull-request trigger to scan every proposed ZIP before it reaches the protected main branch. Require the scan workflow as a branch-protection status check. For emergency vendor troubleshooting, use workflow_dispatch, require the incident or change ticket number in the run description, and prohibit direct commits to main.
Add a scheduled rescan for archives that remain approved but unused. Signature databases change, so a ZIP that was clean when received may warrant reassessment before a delayed field deployment. A weekly schedule is appropriate for most mid-market firms; rescan immediately when a significant vendor advisory, malware alert, or antivirus-engine issue affects the tool category.
on:
schedule:
- cron: "17 3 * * 1"
workflow_dispatch:
For a scheduled job, scan the retained approved ZIPs again and create a new manifest rather than overwriting the earlier evidence. This preserves the original intake result and demonstrates ongoing diligence if the package remains staged for future use.
What monitoring and alerting hooks should compliance require?
Send failed workflow notifications to the security operations mailbox or ticketing platform, not only to the developer who uploaded the file. GitHub can notify repository teams, while a webhook or GitHub Actions integration can open a ServiceNow or Jira ticket containing the run URL, file name, SHA-256 hash, scanner result, and vendor reference.
- Alert immediately when ClamAV detects a signature match or the scanner exits with code
2. - Alert when an archive is encrypted, malformed, oversized, or contains unsafe extraction paths.
- Alert when the workflow cannot update malware signatures within the defined maintenance window.
- Review monthly whether any USB-release approvals occurred without a matching service or change ticket.
Retention should align with the organization’s CMMC assessment-evidence policy. A one-year artifact retention period is a reasonable operational baseline, but retain the release manifest and linked ticket longer when required by contract, incident history, or internal records policy.
How should failures and exceptions be handled?
The most important design decision is to fail closed. A failed scan must not create a USB-ready artifact, must not reach the approval environment, and must not be worked around by copying the ZIP from a workstation that received it through email.
| Failure mode | Required response | Release decision |
|---|---|---|
| Malware signature match | Quarantine repository branch, notify security, preserve logs, contact vendor through approved channel. | Reject package. |
| ClamAV update or scan engine failure | Investigate runner, network, or signature service; rerun only after the scanner is operational. | Block pending successful rescan. |
| Password-protected vendor ZIP | Obtain an unencrypted transfer or documented password through a separate approved channel. | Block until contents can be scanned. |
| Urgent operational need | Require documented risk acceptance from the designated authority and use an alternate verified source where possible. | Do not bypass MA.L2-3.7.4 scanning. |
For the compliance officer, the key audit trail is straightforward: the source ZIP, its hash, scan date, signature-update record, scan result, workflow identifier, approver, release ticket, and technician’s confirmation that the approved hash was copied to the USB device. That evidence directly supports the MA.L2-3.7.4 objective that media containing diagnostic and test programs are checked for malicious code before they are used in CUI environments.
Make this workflow a required gate for every vendor diagnostic-media request and test its evidence trail during your next internal CMMC readiness review.