name: Security on: push: branches: [main] pull_request: branches: [main] schedule: - cron: '0 9 * * 1' # Weekly on Monday permissions: contents: read jobs: secrets-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Detect secrets uses: trufflesecurity/trufflehog@main with: path: ./ # Lob (a direct-mail API this project does not use) matches any # `test_`-prefixed identifier of ~35 chars and reports it verified, # because Lob test keys authenticate unconditionally. Every pytest # function named at that length trips it — the first was # `test_updates_an_existing_device_in_place`. extra_args: --exclude-detectors=Lob dependency-audit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - name: NPM Audit # --omit=dev: only ship-time deps gate the build. Dev-only tooling # (shadcn CLI and its transitive tree: hono, fast-uri, …) is never # bundled or served, so its advisories must not fail release CI. # # Wrapped so a registry outage retries instead of failing the PR; an # advisory still fails on the first attempt. See the script's header. working-directory: frontend run: "$GITHUB_WORKSPACE/.github/scripts/audit-with-retry.sh npm audit --omit=dev --audit-level=high" - uses: actions/setup-python@v5 with: python-version: '3.11' - name: Pip audit # pip-audit queries PyPI's advisory API and fails the same way npm does # when it cannot reach it, so it gets the same wrapper. run: | pip install pip-audit "$GITHUB_WORKSPACE/.github/scripts/audit-with-retry.sh" pip-audit -r backend/requirements.txt