Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/workflows/security-baseline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Security baseline

# Required scanner callers stay unfiltered so every pull request receives a
# status. Scanner scope belongs in reusable workflow inputs.
on:
pull_request:
push:
branches: [main]
schedule:
- cron: "47 3 * * 1"
workflow_dispatch:

permissions:
contents: read

jobs:
gitleaks:
uses: Staros-Labs/infra/.github/workflows/reusable-security-gitleaks.yml@e3b2d2216d219115ffe796aa4cd000a5f41f8b0a
with:
report_only: true
scan_history: false
permissions:
contents: read

osv:
uses: Staros-Labs/infra/.github/workflows/reusable-security-osv.yml@e3b2d2216d219115ffe796aa4cd000a5f41f8b0a
with:
report_only: true
scan_ref: .
permissions:
contents: read

filesystem:
uses: Staros-Labs/infra/.github/workflows/reusable-security-trivy.yml@e3b2d2216d219115ffe796aa4cd000a5f41f8b0a
with:
report_only: true
scan_type: fs
scan_ref: .
scanners: vuln
severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL
generate_sbom: true
artifact_name: security-trivy-filesystem-report
permissions:
contents: read

iac:
uses: Staros-Labs/infra/.github/workflows/reusable-security-trivy.yml@e3b2d2216d219115ffe796aa4cd000a5f41f8b0a
with:
report_only: true
scan_type: fs
scan_ref: .
scanners: misconfig
severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL
artifact_name: security-trivy-iac-report
permissions:
contents: read
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,11 @@ After installing a template that requires drive access (omnibus, collector, coll

- Issues: https://github.com/Starosdev/scrutiny/issues
- Documentation: https://github.com/Starosdev/scrutiny/tree/master/docs

## GHAS-free security baseline

`.github/workflows/security-baseline.yml` runs report-only Gitleaks, OSV-Scanner, and Trivy
filesystem or IaC checks on pull requests, pushes to `main`, and a weekly schedule. Jobs call
reusable workflows in `Staros-Labs/infra` at one exact immutable 40-character commit and
produce private, short-retention artifacts for central inventory. Caller has no workflow-level
path filters, CodeQL, SARIF uploads, or `security-events`; it does not promote branch gates.
41 changes: 41 additions & 0 deletions scripts/test_security_baseline_workflow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from __future__ import annotations

import re
import unittest
from pathlib import Path

WORKFLOW = Path(__file__).parents[1] / ".github/workflows/security-baseline.yml"
IMMUTABLE_REF = re.compile(
r"^\s+uses: Staros-Labs/infra/.+@[0-9a-f]{40}$", re.MULTILINE
)
APPROVED_SHA = "e3b2d2216d219115ffe796aa4cd000a5f41f8b0a"


class SecurityBaselineWorkflowTest(unittest.TestCase):
def setUp(self) -> None:
self.source = WORKFLOW.read_text(encoding="utf-8")

def test_uses_unfiltered_report_only_reusable_scanners(self) -> None:
for event in ("pull_request:", "push:", "schedule:", "workflow_dispatch:"):
self.assertIn(f" {event}", self.source)
self.assertNotIn("paths", self.source)
self.assertNotIn("paths-ignore", self.source)

self.assertEqual(len(IMMUTABLE_REF.findall(self.source)), 4)
self.assertEqual(self.source.count(f"@{APPROVED_SHA}"), 4)
self.assertEqual(self.source.count("report_only: true"), 4)
self.assertEqual(self.source.count("contents: read"), 5)
for workflow in (
"reusable-security-gitleaks.yml",
"reusable-security-osv.yml",
"reusable-security-trivy.yml",
):
self.assertIn(f"Staros-Labs/infra/.github/workflows/{workflow}@", self.source)

def test_forbids_ghas_and_external_report_uploads(self) -> None:
for forbidden in ("github/codeql-action", "security-events", "upload-sarif"):
self.assertNotIn(forbidden, self.source)


if __name__ == "__main__":
unittest.main()