Skip to content

SecScore

Actions
Security scoring engine for CI/CD pipelines. Convert SARIF findings into a single score and security decision
v0.4.0
Latest
Star (7)

CI GitHub release License Python GitHub Action

SecScore

🇺🇸 English | 🇧🇷 Português

Security Score that matters.

Security Scanner
       ↓
      SARIF
       ↓
    SecScore
       ↓
 PASS / REVIEW / FAIL

SecScore is a lightweight security scoring engine for CI/CD pipelines. It evaluates findings from security scanners and calculates a single security score for a Pull Request, allowing teams to automatically decide whether a change should PASS, require REVIEW, or FAIL.

The tool is scanner-agnostic and works with SARIF, making it compatible with most modern security scanners.


Why SecScore

Security scanners generate findings. But pipelines need decisions.

Scanner → Findings → SecScore → Score → Decision

Score: 82 / 100
Decision: REVIEW

Key Features

  • Security score for Pull Requests
  • Hard fail rules for critical vulnerabilities
  • SARIF compatible (Snyk, CodeQL, Semgrep, Checkmarx, etc.)
  • Multi-SARIF support — pass multiple scanner outputs in one run
  • Diff-aware filtering — evaluates only findings introduced in the PR
  • Suppressions by fingerprint — suppress confirmed false positives traceably
  • Optional M.A.R.I.A integration — submits SecScore decision payload (Score, Decision, Summary) after analysis
  • GitHub Action ready
  • Policy-driven security decisions
  • Lightweight and fast
  • Open source

How It Works

Security Scanner
       ↓
      SARIF
       ↓
  SecScore Parser
       ↓
  Policy Engine
       ↓
 Score Calculation
       ↓
 PASS / REVIEW / FAIL

Supported scanners:

  • Snyk
  • Semgrep
  • CodeQL
  • Checkmarx
  • Trivy
  • Any SARIF-compatible scanner

Supported Inputs

Scanner Format
Snyk SARIF
CodeQL SARIF
Semgrep SARIF
Checkmarx SARIF
Checkmarx API JSON

Installation

Clone the repository:

git clone https://github.com/cassiodeveloper/secscore
cd secscore

Install dependencies:

pip install -r requirements.txt

5-Minute Quickstart

  1. Run with SARIF and policy:
python -m secscore.cli.main pr \
  --sarif tests/fixtures/review.sarif \
  --policy policy/policy-pr.yml \
  --no-diff-aware
  1. Check outputs:
  • pr-comment.md (PR-ready markdown summary)
  • secscore-result.json (structured result)
  1. Optional: submit result to M.A.R.I.A:
python -m secscore.cli.main pr \
  --sarif tests/fixtures/review.sarif \
  --policy policy/policy-pr.yml \
  --maria-url http://localhost:5213/api/secscore/submissions \
  --maria-repository-id 11111111-2222-3333-4444-555555555555 \
  --token YOUR_MARIA_TOKEN \
  --no-diff-aware

Copy/Paste Scenarios

Use these commands to validate expected outcomes quickly:

PASS

python -m secscore.cli.main pr \
  --sarif tests/fixtures/pass.sarif \
  --policy policy/policy-pr.yml \
  --no-diff-aware

Expected: Decision: PASS

REVIEW

python -m secscore.cli.main pr \
  --sarif tests/fixtures/review.sarif \
  --policy policy/policy-pr.yml \
  --no-diff-aware

Expected: Decision: REVIEW

FAIL

python -m secscore.cli.main pr \
  --sarif tests/fixtures/fail.sarif \
  --policy policy/policy-pr.yml \
  --no-diff-aware

Expected: Decision: FAIL


Choose Input Mode

Mode When to use Required flags
SARIF (--sarif) You already generated scanner SARIF files in CI --sarif, --policy
Findings JSON (--findings) You already have normalized findings JSON --findings, --policy
Provider (--provider checkmarx) You want SecScore to fetch findings directly from provider API --provider checkmarx, provider flags, --policy

Running Locally

Single SARIF file:

python -m secscore.cli.main pr \
  --sarif examples/example-snyk.sarif \
  --policy policy/policy-pr.yml \
  --no-diff-aware

Multiple SARIF files (v0.3.0+):

python -m secscore.cli.main pr \
  --sarif semgrep.sarif,trivy.sarif \
  --policy policy/policy-pr.yml \
  --no-diff-aware

Send consolidated findings to M.A.R.I.A (token provided at invocation):

python -m secscore.cli.main pr \
  --sarif semgrep.sarif,trivy.sarif \
  --policy policy/policy-pr.yml \
  --maria-url https://demo.mariaappsec.com/api/secscore/submissions \
  --maria-repository-id 11111111-2222-3333-4444-555555555555 \
  --token YOUR_MARIA_TOKEN \
  --no-diff-aware

For /api/secscore/submissions, SecScore auto-fills required submission fields (Score, Decision, Summary, CommitSha, BranchName, PipelineName, PipelineRunId, SubmissionKey). You can override them with: --maria-submission-key, --maria-commit-sha, --maria-branch-name, --maria-pipeline-name, --maria-pipeline-run-id, --maria-pull-request-id.

For local PR testing without opening a real PR:

SECSCORE_PULL_REQUEST_ID=local-pr-001 python -m secscore.cli.main pr \
  --sarif semgrep.sarif \
  --policy policy/policy-pr.yml \
  --maria-url http://localhost:5213/api/secscore/submissions \
  --maria-repository-id 11111111-2222-3333-4444-555555555555 \
  --token YOUR_MARIA_TOKEN \
  --no-diff-aware

In GitHub Actions, SecScore auto-detects the pull request number from the pull_request event. Other CI variables supported: CI_MERGE_REQUEST_IID, CI_MERGE_REQUEST_ID, SYSTEM_PULLREQUEST_PULLREQUESTID, and BITBUCKET_PR_ID.

Note: use --no-diff-aware when running locally without a full git history. In CI, diff-aware is enabled by default and requires fetch-depth: 0 in the checkout step.

Example output:

Score: 85 / 100
Decision: PASS

GitHub Action

Minimal example:

- uses: actions/checkout@v4
  with:
    fetch-depth: 0

- name: Run SecScore
  uses: cassiodeveloper/secscore@v1
  with:
    sarif: results.sarif

Multiple scanners (v0.3.0+):

- name: Run SecScore
  uses: cassiodeveloper/secscore@v1
  with:
    sarif: "semgrep.sarif,trivy.sarif"
    maria-url: "https://demo.mariaappsec.com/api/secscore/submissions"
    maria-repository-id: "11111111-2222-3333-4444-555555555555"
    maria-token: ${{ secrets.MARIA_TOKEN }}

Disable diff-aware:

- name: Run SecScore
  uses: cassiodeveloper/secscore@v1
  with:
    sarif: results.sarif
    no_diff_aware: "true"

Policy-Driven Security

Minimal policy

base_score: 100

penalties:
  critical: 40
  high: 20
  medium: 7
  low: 2

hard_fails:
  - id: SAST_CRITICAL_HIGH_CONF
    when:
      domain: sast
      severity_in: ["critical", "high"]
      is_new: true
    reason: "New critical/high SAST finding"

Recommended policy (example)

scoring:
  base_score: 100
  penalties:
    critical: 40
    high: 20
    medium: 7
    low: 2
  multipliers:
    confidence:
      high: 1.0
      medium: 0.8
      low: 0.5

decision:
  pass_min_score: 85
  review_min_score: 51

hard_fails:
  - id: CRITICAL_NEW
    when:
      severity_in: ["critical"]
      is_new: true
    reason: "New critical finding"

ignore_paths:
  - "node_modules/**"
  - "dist/**"

Suppressing false positives by fingerprint (v0.3.0+)

suppressions:
  deny_fingerprints:
    - "abc123def456"   # confirmed false positive — XSS in test helper

Obtain the fingerprint from secscore-result.json > hard_fails[].finding_fingerprint.


Troubleshooting

  • 404 Not Found on M.A.R.I.A: endpoint path is wrong; use /api/secscore/submissions.
  • 400 Bad Request on M.A.R.I.A: payload contract mismatch (required submission fields missing/invalid).
  • 401 Unauthorized on M.A.R.I.A: invalid token format/value for that environment.
  • 403 Forbidden on M.A.R.I.A: token valid but missing scope/resource access to the target repository.
  • Diff-aware skipped warning: expected locally without full git history; use --no-diff-aware.

Examples

Example SARIF files:

examples/
  example-snyk.sarif
  example-checkmarx.sarif

Example workflows:

examples/workflows/
  example-minimal.yml
  example-snyk.yml
  example-checkmarx.yml
  example-checkmarx-api.yml
  example-multi-scanner.yml

Project Structure

secscore/
  adapters/
  cli/
  core/
  normalizers/
  utils/

examples/
policy/
schema/

Security

If you discover a vulnerability in this project, please report it responsibly.

SECURITY.md


Contributing

Contributions are welcome. Please read:

CONTRIBUTING.md


License

This project is licensed under the PolyForm Noncommercial License 1.0.0.

Free for non-commercial use. Commercial use — including incorporation into a paid product, service, or platform — requires explicit permission from the author.

LICENSE · polyformproject.org/licenses/noncommercial/1.0.0


Philosophy

Security scanners generate noise.

SecScore focuses on what actually matters:

clear, automated security decisions in CI/CD pipelines.

SecScore is not certified by GitHub. It is provided by a third-party and is governed by separate terms of service, privacy policy, and support documentation.

About

Security scoring engine for CI/CD pipelines. Convert SARIF findings into a single score and security decision
v0.4.0
Latest

SecScore is not certified by GitHub. It is provided by a third-party and is governed by separate terms of service, privacy policy, and support documentation.