Add scheduled security scan workflow

This commit is contained in:
MrSphay
2026-05-03 22:01:41 +02:00
parent a218e338bd
commit 6308417945
8 changed files with 241 additions and 1 deletions

View File

@@ -20,6 +20,7 @@ PROJECT_NAME: PROJECT_DESCRIPTION
- After pushing commits that trigger a Gitea workflow, poll the workflow run until it succeeds. If it fails or is cancelled, inspect the failing job/logs, fix the issue when in scope, push again, and repeat the workflow check loop. Fixing and pushing a workflow failure is not a stopping point.
- When the project uses `blueprint.md` and `blueprint.json` for README generation, keep the rainbow `{{ template:section-line }}` divider between major README sections. Do not replace it with plain `---` unless the target renderer cannot display inline images.
- If README blueprint files are changed, regenerate or update `README.md` in the same change and verify the generated output renders reasonably.
- For releasable projects, add or preserve `.gitea/workflows/security-scan.yml` using `files/security-scan-gitea.yml` unless the repository already has equivalent scheduled security automation.
## Commands
@@ -54,6 +55,7 @@ ARTIFACT_NAME
- Review `docs/security-review.md` before release work.
- Fill `docs/security-review.md` with actual checked commands and results when performing release-readiness work.
- Review scheduled security workflow failures before changing code. Treat matches as leads: they may be true positives, documentation examples, or test fixtures.
- Treat generated credentials and config files as sensitive.
- Keep external network calls documented.
- Prefer local processing for user data.

View File

@@ -0,0 +1,174 @@
name: Scheduled Security Scan
on:
schedule:
- cron: "17 3 * * 1"
workflow_dispatch:
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Detect project stack
id: detect
shell: bash
run: |
stacks=""
[ -f package.json ] && stacks="${stacks} node"
{ [ -f pyproject.toml ] || [ -f requirements.txt ]; } && stacks="${stacks} python"
[ -f Cargo.toml ] && stacks="${stacks} rust"
[ -f go.mod ] && stacks="${stacks} go"
{ [ -f Dockerfile ] || [ -f compose.yml ] || [ -f docker-compose.yml ]; } && stacks="${stacks} docker"
echo "stacks=${stacks:-generic}" >> "$GITHUB_OUTPUT"
echo "Detected stacks:${stacks:- generic}"
- name: Node production dependency audit
if: contains(steps.detect.outputs.stacks, 'node')
run: npm audit --omit=dev --audit-level=high
- name: Python dependency audit
if: contains(steps.detect.outputs.stacks, 'python')
shell: bash
run: |
python -m pip install --upgrade pip pip-audit
if [ -f requirements.txt ]; then
pip-audit -r requirements.txt
else
pip-audit
fi
- name: Rust dependency audit
if: contains(steps.detect.outputs.stacks, 'rust')
shell: bash
run: |
cargo install cargo-audit --locked
cargo audit
- name: Go vulnerability scan
if: contains(steps.detect.outputs.stacks, 'go')
shell: bash
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
- name: Suspicious code pattern scan
shell: bash
run: |
grep_excludes=(
--exclude-dir=.git
--exclude-dir=node_modules
--exclude-dir=dist
--exclude-dir=build
--exclude-dir=release
--exclude=security-scan.yml
)
patterns=(
'eval\s*\('
'new Function\s*\('
'dangerouslySetInnerHTML'
'innerHTML\s*='
'child_process'
'exec\s*\('
'spawn\s*\('
'shell\.openExternal'
'nodeIntegration:\s*true'
'webSecurity:\s*false'
'allowRunningInsecureContent:\s*true'
'curl .*sh'
'wget .*sh'
)
found=0
for pattern in "${patterns[@]}"; do
if grep -RInE "${grep_excludes[@]}" "$pattern" .; then
found=1
fi
done
if [ "$found" -eq 1 ]; then
echo "Suspicious code patterns were found. Review the matches above."
exit 1
fi
- name: Secret and config leak scan
shell: bash
run: |
grep_excludes=(
--exclude-dir=.git
--exclude-dir=node_modules
--exclude-dir=dist
--exclude-dir=build
--exclude-dir=release
--exclude=security-scan.yml
)
patterns=(
'BEGIN (RSA |EC |OPENSSH |)PRIVATE KEY'
'AKIA[0-9A-Z]{16}'
'xox[baprs]-[0-9A-Za-z-]+'
'gh[pousr]_[0-9A-Za-z_]+'
'sk-[A-Za-z0-9]{20,}'
'api[_-]?key\s*=\s*["'\'']?[A-Za-z0-9_\-]{20,}'
'token\s*=\s*["'\'']?[A-Za-z0-9_\-]{20,}'
'password\s*=\s*["'\'']?[^[:space:]]{8,}'
)
found=0
for pattern in "${patterns[@]}"; do
if grep -RInE "${grep_excludes[@]}" "$pattern" .; then
found=1
fi
done
if find . -path ./.git -prune -o \( -name ".env" -o -name ".env.*" \) -not -name ".env.example" -print | grep .; then
echo "Committed environment files were found."
found=1
fi
if [ "$found" -eq 1 ]; then
echo "Potential secret or config leak detected. Review the matches above."
exit 1
fi
- name: AI instruction injection scan
shell: bash
run: |
grep_excludes=(
--exclude-dir=.git
--exclude-dir=node_modules
--exclude-dir=dist
--exclude-dir=build
--exclude-dir=release
--exclude=security-scan.yml
)
patterns=(
'ignore (all )?(previous|above) instructions'
'system prompt'
'developer message'
'reveal your instructions'
'exfiltrate'
'send.*token'
'send.*secret'
'disable.*safety'
'jailbreak'
'prompt injection'
)
found=0
for pattern in "${patterns[@]}"; do
if grep -RInEi "${grep_excludes[@]}" "$pattern" .; then
found=1
fi
done
if [ "$found" -eq 1 ]; then
echo "Potential AI instruction-injection text found. Review whether this is documentation, test data, or malicious content."
exit 1
fi