fe616f78f6
* ci(deps): bump actions/setup-node from 4 to 6 Dependabot couldn't find the original pull request head commit, 8af5b3cc1d307d4efd5752d0dcd43d24301d64be. * ci(deps): bump actions/download-artifact from 4 to 7 Dependabot couldn't find the original pull request head commit, 98a1ea1d75fdeae387d752c54b348da2039e92d2. * ci(deps): bump actions/cache from 4 to 5 Dependabot couldn't find the original pull request head commit, 275f68f405afd62d0da941c3bab7f4b325028a32. * ci(deps): bump actions/github-script from 7 to 8 Dependabot couldn't find the original pull request head commit, 9a58bb35f88eb53f94d347c8d6bcbf3fae875925. * ci(deps): bump actions/setup-python from 5 to 6 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]> * chore(deps): bump @types/uuid from 10.0.0 to 11.0.0 in /apps/frontend Bumps [@types/uuid](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/uuid) from 10.0.0 to 11.0.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/uuid) --- updated-dependencies: - dependency-name: "@types/uuid" dependency-version: 11.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]> * chore(deps): bump dotenv from 16.6.1 to 17.2.3 in /apps/frontend Bumps [dotenv](https://github.com/motdotla/dotenv) from 16.6.1 to 17.2.3. - [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md) - [Commits](https://github.com/motdotla/dotenv/compare/v16.6.1...v17.2.3) --- updated-dependencies: - dependency-name: dotenv dependency-version: 17.2.3 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]> * chore(deps): bump electron from 39.2.7 to 40.0.0 in /apps/frontend Bumps [electron](https://github.com/electron/electron) from 39.2.7 to 40.0.0. - [Release notes](https://github.com/electron/electron/releases) - [Commits](https://github.com/electron/electron/compare/v39.2.7...v40.0.0) --- updated-dependencies: - dependency-name: electron dependency-version: 40.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]> * chore(deps): bump @types/minimatch from 5.1.2 to 6.0.0 in /apps/frontend Bumps [@types/minimatch](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/minimatch) from 5.1.2 to 6.0.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/minimatch) --- updated-dependencies: - dependency-name: "@types/minimatch" dependency-version: 6.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]> * chore: regenerate package-lock.json for updated dependencies Sync lockfile with updated package versions: - @types/minimatch 5.1.2 → 6.0.0 - @types/uuid 10.0.0 → 11.0.0 - dotenv 16.6.1 → 17.2.3 - electron 39.2.7 → 40.0.0 Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix: update Electron version in prebuilds workflow and suppress dotenv v17 logs - Update build-prebuilds.yml ELECTRON_VERSION from 39.2.6 to 40.0.0 to match the Electron version in package.json - Add quiet: true to dotenv config to suppress redundant v17 runtime log messages Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <[email protected]>
178 lines
5.8 KiB
YAML
178 lines
5.8 KiB
YAML
name: Quality Security
|
|
|
|
# CodeQL runs on all PRs, pushes to main, and weekly schedule
|
|
# Note: CodeQL takes 20-30 min per language (40-60 min total)
|
|
# Bandit is fast (5-10 min)
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'apps/**'
|
|
- 'tests/**'
|
|
- 'pyproject.toml'
|
|
- 'package.json'
|
|
- '.github/workflows/quality-security.yml'
|
|
pull_request:
|
|
branches: [main, develop]
|
|
paths:
|
|
- 'apps/**'
|
|
- 'tests/**'
|
|
- 'pyproject.toml'
|
|
- 'package.json'
|
|
- '.github/workflows/quality-security.yml'
|
|
schedule:
|
|
- cron: '0 0 * * 1' # Weekly on Monday at midnight UTC
|
|
|
|
concurrency:
|
|
group: security-${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
security-events: write
|
|
actions: read
|
|
|
|
jobs:
|
|
codeql:
|
|
name: CodeQL (${{ matrix.language }})
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
language: [python, javascript-typescript]
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Initialize CodeQL
|
|
uses: github/codeql-action/init@v3
|
|
with:
|
|
languages: ${{ matrix.language }}
|
|
queries: +security-extended,security-and-quality
|
|
|
|
- name: Autobuild
|
|
uses: github/codeql-action/autobuild@v3
|
|
|
|
- name: Perform CodeQL Analysis
|
|
uses: github/codeql-action/analyze@v3
|
|
with:
|
|
category: "/language:${{ matrix.language }}"
|
|
|
|
# Bandit runs on all PRs - it's fast (5-10 min)
|
|
python-security:
|
|
name: Python Security (Bandit)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v6
|
|
with:
|
|
python-version: '3.12'
|
|
|
|
- name: Install Bandit
|
|
run: pip install bandit
|
|
|
|
- name: Run Bandit security scan
|
|
id: bandit
|
|
run: |
|
|
echo "::group::Running Bandit security scan"
|
|
bandit -r apps/backend/ -ll -ii -f json -o bandit-report.json || BANDIT_EXIT=$?
|
|
if [ "${BANDIT_EXIT:-0}" -gt 1 ]; then
|
|
echo "::error::Bandit scan failed with exit code $BANDIT_EXIT"
|
|
exit 1
|
|
fi
|
|
echo "::endgroup::"
|
|
|
|
- name: Analyze Bandit results
|
|
uses: actions/github-script@v8
|
|
with:
|
|
script: |
|
|
const fs = require('fs');
|
|
|
|
if (!fs.existsSync('bandit-report.json')) {
|
|
core.setFailed('Bandit report not found - scan may have failed');
|
|
return;
|
|
}
|
|
|
|
const report = JSON.parse(fs.readFileSync('bandit-report.json', 'utf8'));
|
|
const results = report.results || [];
|
|
|
|
const high = results.filter(r => r.issue_severity === 'HIGH');
|
|
const medium = results.filter(r => r.issue_severity === 'MEDIUM');
|
|
const low = results.filter(r => r.issue_severity === 'LOW');
|
|
|
|
console.log(`::group::Bandit Security Scan Results`);
|
|
console.log(`Found ${results.length} issues:`);
|
|
console.log(` HIGH: ${high.length}`);
|
|
console.log(` MEDIUM: ${medium.length}`);
|
|
console.log(` LOW: ${low.length}`);
|
|
console.log('::endgroup::');
|
|
|
|
let summary = `## Python Security Scan (Bandit)\n\n`;
|
|
summary += `| Severity | Count |\n`;
|
|
summary += `|----------|-------|\n`;
|
|
summary += `| High | ${high.length} |\n`;
|
|
summary += `| Medium | ${medium.length} |\n`;
|
|
summary += `| Low | ${low.length} |\n\n`;
|
|
|
|
if (high.length > 0) {
|
|
summary += `### High Severity Issues\n\n`;
|
|
for (const issue of high) {
|
|
summary += `- **${issue.filename}:${issue.line_number}**\n`;
|
|
summary += ` - ${issue.issue_text}\n`;
|
|
summary += ` - Test: \`${issue.test_id}\` (${issue.test_name})\n\n`;
|
|
}
|
|
}
|
|
|
|
core.summary.addRaw(summary);
|
|
await core.summary.write();
|
|
|
|
if (high.length > 0) {
|
|
core.setFailed(`Found ${high.length} high severity security issue(s)`);
|
|
} else {
|
|
console.log('No high severity security issues found');
|
|
}
|
|
|
|
# --------------------------------------------------------------------------
|
|
# Gate Job - Single check for branch protection
|
|
# --------------------------------------------------------------------------
|
|
security-summary:
|
|
name: Security Summary
|
|
runs-on: ubuntu-latest
|
|
needs: [codeql, python-security]
|
|
if: always()
|
|
timeout-minutes: 5
|
|
steps:
|
|
- name: Check security results
|
|
uses: actions/github-script@v8
|
|
with:
|
|
script: |
|
|
const codeql = '${{ needs.codeql.result }}';
|
|
const bandit = '${{ needs.python-security.result }}';
|
|
|
|
console.log('Security Check Results:');
|
|
console.log(` CodeQL: ${codeql}`);
|
|
console.log(` Bandit: ${bandit}`);
|
|
|
|
// Only 'failure' is a real failure; 'skipped' is acceptable (e.g., path filters, PR skipping CodeQL)
|
|
const acceptable = ['success', 'skipped'];
|
|
const codeqlOk = acceptable.includes(codeql);
|
|
const banditOk = acceptable.includes(bandit);
|
|
const allPassed = codeqlOk && banditOk;
|
|
|
|
if (allPassed) {
|
|
console.log('\n✅ All security checks passed');
|
|
core.summary.addRaw('## ✅ Security Checks Passed\n\nAll security scans completed successfully.');
|
|
} else {
|
|
console.log('\n❌ Some security checks failed');
|
|
core.summary.addRaw('## ❌ Security Checks Failed\n\nOne or more security scans found issues.');
|
|
core.setFailed('Security checks failed');
|
|
}
|
|
|
|
await core.summary.write();
|