GitHub Actions
Integrate Musha into GitHub Actions to scan every push and pull request.
Full workflow
Create .github/workflows/musha.yml in your repository:
name: Musha Security Scan
on:
push:
branches: [main, master, develop]
pull_request:
jobs:
musha-scan:
name: Security scan
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2 # needed to detect changed files vs HEAD~1
- name: Package repository
run: |
tar -czf scan.tar.gz \
--exclude='.git' \
--exclude='node_modules' \
--exclude='vendor' \
--exclude='.terraform' \
--exclude='target' \
--exclude='dist' \
--exclude='build' \
.
- name: Upload to Musha
run: |
curl -fsS -X POST "${{ vars.MUSHA_API_URL }}/v1/scans" \
-H "Authorization: Bearer ${{ secrets.MUSHA_API_KEY }}" \
-F "files=@scan.tar.gz" \
-F "project_id=${{ vars.MUSHA_PROJECT_ID }}" \
-F "branch=${{ github.head_ref || github.ref_name }}" \
-F "pr_id=${{ github.event.pull_request.number }}" \
-F "commit_hash=${{ github.sha }}" \
-F "scan_type=full"
Variables and secrets
Configure these in GitHub → Repository settings → Secrets and variables → Actions:
| Name | Type | Description |
|---|---|---|
MUSHA_API_URL | Variable | https://api.mushasec.com |
MUSHA_PROJECT_ID | Variable | Your project UUID from the Musha dashboard |
MUSHA_API_KEY | Secret | API key created in Settings → API Keys |
PR comment behavior
When the workflow runs on a pull request (github.event.pull_request.number is set), Musha posts a comment to the PR with the scan results. The comment is updated on each new push to the PR branch.
The comment includes:
- Overall pass ✅ / fail ❌ based on your
block_severitysetting - Count of blocking, non-blocking, accepted, and technical debt findings
- Direct links to the Security dashboard for triage
Customizing what gets scanned
Scan type
scan_type=full runs SCA + IaC + Secrets. You can narrow it down:
| Value | What runs |
|---|---|
full | SCA + IaC + Secrets (recommended) |
sca | Dependencies only |
iac | Infrastructure only |
secrets | Secrets only |
sca,iac | Dependencies + Infrastructure |
Scanning only changed files (recommended for PR scans)
To avoid blocking PRs for pre-existing vulnerabilities, package only the files changed in the PR:
- name: Get changed files
if: github.event_name == 'pull_request'
run: |
CHANGED=$(git diff --name-only HEAD~1 HEAD | jq -R . | jq -s . -c)
echo "CHANGED_FILES=$CHANGED" >> $GITHUB_ENV
- name: Package changed files only
if: github.event_name == 'pull_request'
run: |
git diff --name-only HEAD~1 HEAD | xargs tar -czf scan.tar.gz --
- name: Package full repo
if: github.event_name != 'pull_request'
run: tar -czf scan.tar.gz --exclude='.git' --exclude='node_modules' .
- name: Upload to Musha
run: |
curl -fsS -X POST "${{ vars.MUSHA_API_URL }}/v1/scans" \
-H "Authorization: Bearer ${{ secrets.MUSHA_API_KEY }}" \
-F "files=@scan.tar.gz" \
-F "project_id=${{ vars.MUSHA_PROJECT_ID }}" \
-F "branch=${{ github.head_ref || github.ref_name }}" \
-F "pr_id=${{ github.event.pull_request.number }}" \
-F "commit_hash=${{ github.sha }}" \
-F "scan_type=full" \
-F "changed_files=${CHANGED_FILES:-[]}"
When changed_files is provided, Musha only analyzes manifests in or near the changed files. Vulnerabilities in files you didn't touch are marked as Technical Debt and never block the PR.
Troubleshooting
curl: (22) The requested URL returned error: 401 — The API key is invalid or expired. Regenerate it in Settings → API Keys.
curl: (22) The requested URL returned error: 403 — The API key doesn't have access to this project, or your subscription is expired.
curl: (22) The requested URL returned error: 429 — You've hit the scan rate limit (50 scans/hour per tenant). Wait and retry.