7a0da7932b
Backwards Compatibility / Verify Encryption Constants (push) Waiting to run
Backwards Compatibility / PyPI Version Compatibility (push) Waiting to run
Backwards Compatibility / Database Migration Tests (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Blocked by required conditions
Docker Tests (Consolidated) / detect-changes (push) Waiting to run
Docker Tests (Consolidated) / Build Test Image (push) Waiting to run
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Blocked by required conditions
Docker Tests (Consolidated) / Accessibility Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Unit Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Example Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / Production Image Smoke Test (push) Blocked by required conditions
Docker Tests (Consolidated) / Infrastructure Tests (push) Blocked by required conditions
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Waiting to run
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
212 lines
9.1 KiB
YAML
212 lines
9.1 KiB
YAML
name: Dockle Container Security Linting
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
workflow_call: # Called by release-gate.yml
|
|
schedule:
|
|
# Run weekly on Tuesday at 10 AM UTC (staggered with other container scans)
|
|
- cron: '0 10 * * 2'
|
|
|
|
permissions: {} # Minimal top-level for OSSF Scorecard Token-Permissions
|
|
|
|
jobs:
|
|
dockle:
|
|
name: Dockle Container Image Security
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
permissions:
|
|
contents: read
|
|
security-events: write
|
|
|
|
steps:
|
|
- name: Harden the runner (Audit all outbound calls)
|
|
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Checkout repository
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
|
|
|
|
- name: Build Docker image for scanning
|
|
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
|
|
with:
|
|
context: .
|
|
push: false
|
|
load: true
|
|
tags: local-deep-research:dockle-scan
|
|
cache-from: type=gha,scope=dockle-scan
|
|
cache-to: type=gha,mode=max,scope=dockle-scan
|
|
|
|
- name: Run Dockle security scan
|
|
id: dockle
|
|
run: |
|
|
echo "=== Running Dockle Container Image Security Scan ==="
|
|
# Run Dockle with SARIF output for GitHub Security tab
|
|
# Mount current directory to /output so SARIF file is written to host filesystem
|
|
# Exit code 1 means issues found, but we don't fail the workflow
|
|
#
|
|
# Ignored checks (false positives or intentional design):
|
|
# - CIS-DI-0001: Create a user - image uses setpriv entrypoint pattern for privilege drop
|
|
# (see scripts/ldr_entrypoint.sh which uses setpriv to switch to ldruser)
|
|
# - CIS-DI-0005: Enable Content trust for Docker - runtime env var (DOCKER_CONTENT_TRUST),
|
|
# not a Dockerfile concern; enforced at deployment time
|
|
# - CIS-DI-0008: setuid/setgid files - unix_chkpwd is standard Debian base utility
|
|
# required for PAM authentication, inherited from python:3.14-slim base image
|
|
# - DKL-DI-0005: Clear apt-get caches - already done in Dockerfile (rm -rf /var/lib/apt/lists/*),
|
|
# but base image (python:3.14-slim) layers trigger this check
|
|
#
|
|
# Accepted files (false positives):
|
|
# - unix_chkpwd: PAM utility from Debian base image
|
|
# - settings.py: Any file named settings.py (config files, not credentials)
|
|
# Without --exit-code flag, Dockle always exits 0 regardless of findings.
|
|
# Findings are reported via SARIF and enforced by the release gate
|
|
# (check-code-scanning-alerts job in release-gate.yml).
|
|
# Any non-zero exit code here means Docker itself failed (image pull error,
|
|
# socket unavailable, etc.) — a broken scanner that MUST fail the step,
|
|
# otherwise no SARIF is produced and the release gate has nothing to check.
|
|
set +e
|
|
docker run --rm \
|
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
|
-v "$(pwd):/output" \
|
|
goodwithtech/dockle:v0.4.14 \
|
|
--format sarif \
|
|
--output /output/dockle-results.sarif \
|
|
--ignore CIS-DI-0001 \
|
|
--ignore CIS-DI-0005 \
|
|
--ignore CIS-DI-0008 \
|
|
--ignore DKL-DI-0005 \
|
|
--accept-file "usr/sbin/unix_chkpwd" \
|
|
--accept-file "settings.py" \
|
|
local-deep-research:dockle-scan
|
|
DOCKLE_EXIT_CODE=$?
|
|
set -e
|
|
|
|
if [ "$DOCKLE_EXIT_CODE" -ne 0 ]; then
|
|
echo "::error::Dockle/Docker failed with exit code $DOCKLE_EXIT_CODE"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if SARIF file was created (for use in subsequent steps)
|
|
if [ -f "dockle-results.sarif" ]; then
|
|
echo "sarif_exists=true" >> "$GITHUB_OUTPUT"
|
|
# Check if SARIF contains any findings (used by summary step)
|
|
RESULT_COUNT=$(python3 -c "import json; print(len(json.load(open('dockle-results.sarif')).get('runs',[{}])[0].get('results',[])))" 2>/dev/null || echo "0")
|
|
if [ "$RESULT_COUNT" -gt 0 ]; then
|
|
echo "DOCKLE_FOUND_ISSUES=true" >> "$GITHUB_ENV"
|
|
fi
|
|
fi
|
|
|
|
- name: Run Dockle with human-readable output
|
|
if: always()
|
|
run: |
|
|
echo "=== Dockle Scan Results ==="
|
|
# Use same ignore flags as SARIF scan for consistent output
|
|
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
|
|
goodwithtech/dockle:v0.4.14 \
|
|
--format list \
|
|
--ignore CIS-DI-0001 \
|
|
--ignore CIS-DI-0005 \
|
|
--ignore CIS-DI-0008 \
|
|
--ignore DKL-DI-0005 \
|
|
--accept-file "usr/sbin/unix_chkpwd" \
|
|
--accept-file "settings.py" \
|
|
local-deep-research:dockle-scan || true
|
|
|
|
- name: Upload Dockle results to GitHub Security tab
|
|
uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
|
# Note: hashFiles() is evaluated at workflow parse time, not runtime.
|
|
# Use step output instead to check if SARIF file was created during the run.
|
|
if: always() && steps.dockle.outputs.sarif_exists == 'true'
|
|
with:
|
|
sarif_file: dockle-results.sarif
|
|
category: dockle
|
|
|
|
- name: Upload Dockle results as artifact
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always() && steps.dockle.outputs.sarif_exists == 'true'
|
|
with:
|
|
name: dockle-results
|
|
path: dockle-results.sarif
|
|
retention-days: 7 # Reduced for security
|
|
|
|
- name: Display Dockle summary
|
|
if: always()
|
|
run: |
|
|
{
|
|
echo "## 🐋 Dockle Container Image Security Summary"
|
|
echo ""
|
|
echo "### What is Dockle?"
|
|
echo "Dockle is a container image linting tool that checks for:"
|
|
echo ""
|
|
echo "#### 🎯 Security Checks:"
|
|
echo "- **Sensitive Files**: Keys, certificates, passwords in image"
|
|
echo "- **Root User**: Warning if running as root"
|
|
echo "- **Clear-text Passwords**: Detects plaintext secrets"
|
|
echo "- **CIS Benchmarks**: Container security best practices"
|
|
echo "- **Outdated Packages**: Vulnerable base images"
|
|
echo ""
|
|
echo "#### 📊 Dockle vs Hadolint:"
|
|
echo "- **Hadolint**: Checks Dockerfile source code (best practices)"
|
|
echo "- **Dockle**: Scans built container image (runtime security)"
|
|
echo "- **Both Complement**: Check different stages of container lifecycle"
|
|
echo ""
|
|
echo "#### 🔍 Scan Results:"
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
if [ "$DOCKLE_FOUND_ISSUES" = "true" ]; then
|
|
{
|
|
echo "⚠️ **Issues Found**"
|
|
echo ""
|
|
echo "Dockle detected security or best practice issues:"
|
|
echo ""
|
|
echo "**Common Issues:**"
|
|
echo "- Running as root user (consider USER directive)"
|
|
echo "- Sensitive files potentially included in image"
|
|
echo "- Missing security labels or metadata"
|
|
echo "- Outdated base image packages"
|
|
echo ""
|
|
echo "📋 **Detailed Results:**"
|
|
echo "- GitHub Security tab: SARIF results uploaded"
|
|
echo "- Artifacts: Full SARIF report available"
|
|
echo "- Check output above for human-readable format"
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
else
|
|
{
|
|
echo "✅ **No Issues Found!**"
|
|
echo ""
|
|
echo "Container image passed all Dockle security checks."
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
fi
|
|
|
|
{
|
|
echo ""
|
|
echo "#### 🔗 Resources:"
|
|
echo "- [Dockle GitHub](https://github.com/goodwithtech/dockle)"
|
|
echo "- [CIS Docker Benchmark](https://www.cisecurity.org/benchmark/docker)"
|
|
echo "- [Security Tab](https://github.com/${{ github.repository }}/security/code-scanning)"
|
|
echo ""
|
|
echo "#### 💡 Best Practices:"
|
|
echo "- Use multi-stage builds to reduce image size"
|
|
echo "- Add USER directive to run as non-root"
|
|
echo "- Don't include secrets or keys in image"
|
|
echo "- Keep base images updated"
|
|
echo "- Scan images with both Dockle (runtime) and Hadolint (build)"
|
|
echo ""
|
|
echo "#### 🔇 Ignored Checks (false positives or intentional design):"
|
|
echo "- **CIS-DI-0001** (Create a user): Uses setpriv entrypoint pattern for privilege drop"
|
|
echo "- **CIS-DI-0005** (Content trust): Runtime env var, not Dockerfile concern"
|
|
echo "- **CIS-DI-0008** (setuid/setgid): unix_chkpwd from Debian base, required for PAM"
|
|
echo "- **DKL-DI-0005** (apt-get cache): Dockerfile clears caches, base image triggers this"
|
|
echo "- **settings.py**: Any file named settings.py accepted (config files, not credentials)"
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
- name: Clean up Docker image
|
|
if: always()
|
|
run: |
|
|
docker rmi local-deep-research:dockle-scan || true
|