From 899b2398b68afee6da80d243096ba691709fa231 Mon Sep 17 00:00:00 2001 From: d-oit <6849456+d-oit@users.noreply.github.com> Date: Tue, 11 Aug 2026 21:04:54 +0200 Subject: [PATCH] feat(ci): add security-scan workflow template --- .../security-scan.properties.json | 6 ++ .github/workflow-templates/security-scan.yml | 91 +++++++++++++++++++ src/lib/__tests__/workflows.test.ts | 24 +++++ 3 files changed, 121 insertions(+) create mode 100644 .github/workflow-templates/security-scan.properties.json create mode 100644 .github/workflow-templates/security-scan.yml diff --git a/.github/workflow-templates/security-scan.properties.json b/.github/workflow-templates/security-scan.properties.json new file mode 100644 index 00000000..176235bf --- /dev/null +++ b/.github/workflow-templates/security-scan.properties.json @@ -0,0 +1,6 @@ +{ + "name": "Security Scan", + "description": "Runs shellcheck, gitleaks secret detection (with TruffleHog fallback), and Trivy filesystem scans. Results appear in the GitHub Security tab.", + "iconName": "example-icon", + "categories": ["Security", "Continuous integration"] +} diff --git a/.github/workflow-templates/security-scan.yml b/.github/workflow-templates/security-scan.yml new file mode 100644 index 00000000..414c23e8 --- /dev/null +++ b/.github/workflow-templates/security-scan.yml @@ -0,0 +1,91 @@ +--- +name: Security Scan + +# Runs security scans on every push and PR: shellcheck, secret detection, +# and filesystem vulnerability scanning. Results land in the Security tab. + +# yamllint disable-line rule:truthy +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + # Weekly Sunday scan + - cron: '0 0 * * 0' + workflow_dispatch: + +permissions: + contents: read + security-events: write + +jobs: + shellcheck: + name: Shell Script Security Analysis + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0 + with: + severity: warning + format: tty + check_together: 'yes' + scandir: './scripts' + + secret-detection: + name: Secret Detection + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + + - name: Secret Detection with GitLeaks + id: gitleaks + # v2.3.9 pinned: v3+ requires a paid GITLEAKS_LICENSE secret + uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2.3.9 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Fallback Secret Scan with TruffleHog + if: steps.gitleaks.outcome == 'failure' + uses: trufflesecurity/trufflehog@6f3c981e7b77f235fd2702dd74af25fc4b72bf11 # v3.96.0 + with: + path: ./ + base: "" + head: HEAD + extra_args: --debug --only-verified + continue-on-error: true + + trivy-fs: + name: Trivy Filesystem Security Scan + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Run Trivy vulnerability scanner in fs mode + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 + with: + scan-type: 'fs' + scan-ref: '.' + severity: 'CRITICAL,HIGH,MEDIUM' + format: 'sarif' + output: 'trivy-results.sarif' + exit-code: '0' + ignore-unfixed: true + hide-progress: true + + - name: Upload Trivy SARIF + if: always() + uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 + with: + sarif_file: trivy-results.sarif + category: trivy-fs diff --git a/src/lib/__tests__/workflows.test.ts b/src/lib/__tests__/workflows.test.ts index 1ef2936a..475df6c3 100644 --- a/src/lib/__tests__/workflows.test.ts +++ b/src/lib/__tests__/workflows.test.ts @@ -336,5 +336,29 @@ describe('GitHub Actions Workflows', () => { expect(properties.name).toBe('Dependabot Auto-Merge') expect(properties.description.length).toBeGreaterThan(0) }) + + it('should have a valid security-scan template with properties file', () => { + const templatePath = join( + process.cwd(), + '.github/workflow-templates/security-scan.yml' + ) + expect(existsSync(templatePath)).toBe(true) + const template = parse(readFileSync(templatePath, 'utf-8')) + expect(template).toBeDefined() + expect(template.name).toBe('Security Scan') + expect(template.jobs).toHaveProperty('shellcheck') + expect(template.jobs).toHaveProperty('secret-detection') + expect(template.jobs).toHaveProperty('trivy-fs') + + const propertiesPath = join( + process.cwd(), + '.github/workflow-templates/security-scan.properties.json' + ) + const properties = JSON.parse( + readFileSync(propertiesPath, 'utf-8') + ) as { name: string; description: string } + expect(properties.name).toBe('Security Scan') + expect(properties.description.length).toBeGreaterThan(0) + }) }) }) \ No newline at end of file