Skip to content

Commit 968910b

Browse files
release: v0.5.0 (M.A.R.I.A policy import + risk model, HTML report, security hardening)
Added - M.A.R.I.A policy import (--maria-import-policy, --maria-policy-url) and maria_riskscore_v1 risk-score model (weights, application context, risk profile). - Optional self-contained HTML report (--html-output / --html-out) and matching GitHub Action inputs. - Console entry point `secscore pr ...`. Changed / Fixed - PR comment renderer now honors the policy `reporting` block (max_findings_in_comment, max_reasons, include_fields) instead of fixed defaults; include_fields is now actually applied to finding lines. Security - SSRF hardening on M.A.R.I.A outbound requests (scheme/credential checks, block private/reserved targets, explicit opt-in for local URLs). - Path-access hardening for CLI and SARIF inputs (confined to workspace/CI roots). - Composite action hardened against injection (env-var interpolation + quoted arg arrays). - PR comment hardened against Markdown injection from untrusted scanner output (escaping + percent-encoded link targets). Repository - Bumped version to 0.5.0 (pyproject + secscore.__version__). - Added .gitattributes (LF) and ignored generated artifacts; stopped tracking tmp-result.json. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 8efa857 commit 968910b

19 files changed

Lines changed: 1956 additions & 289 deletions

.gitattributes

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Normalize line endings: store LF in the repository and check out LF,
2+
# so shell blocks in action.yml and CI stay valid on Linux runners
3+
# regardless of the contributor's OS or core.autocrlf setting.
4+
* text=auto eol=lf
5+
6+
# Keep Windows-native scripts as CRLF (none today, listed for clarity).
7+
*.bat text eol=crlf
8+
*.cmd text eol=crlf
9+
10+
# Treat binaries explicitly so git never touches their bytes.
11+
*.png binary
12+
*.jpg binary
13+
*.jpeg binary
14+
*.gif binary
15+
*.ico binary
16+
*.pdf binary

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ on:
44
push:
55
pull_request:
66

7+
permissions:
8+
contents: read
9+
710
jobs:
811
test:
912
runs-on: ubuntu-latest

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,13 @@ __marimo__/
212212
*.sarif
213213
pr-comment.md
214214
secscore-result.json
215+
secscore-report.html
216+
217+
# Generated at runtime by the M.A.R.I.A policy import (overwritten every run)
218+
policy/policy-maria.yml
219+
220+
# Scratch / test artifacts
221+
tmp-*
215222

216223
# Allow SARIF examples
217224
!examples/*.sarif

CHANGELOG.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,59 @@ The format is based on semantic versioning and follows a simple chronological re
66

77
---
88

9+
## v0.5.0 — 2026-07
10+
11+
### Added
12+
13+
* Console entry point for installed environments:
14+
`secscore pr ...` can now be used instead of `python -m secscore.cli.main pr ...`.
15+
* Optional HTML report output generated from the standard JSON result:
16+
`--html-output true` and `--html-out secscore-report.html`.
17+
* GitHub Action inputs `html_output` and `html_out` for publishing the visual report as a workflow artifact.
18+
* HTML report polish: dark/light toggle, risk summary, linked findings and artifacts,
19+
copy JSON path action, collapsible execution parameters, and report footer metadata.
20+
* Optional **M.A.R.I.A policy import** with `--maria-import-policy` and `--maria-policy-url`,
21+
allowing SecScore to sync repository risk policy before scoring.
22+
* M.A.R.I.A risk score model support (`maria_riskscore_v1`) including risk weights,
23+
application context, and risk profile multipliers.
24+
25+
### Changed
26+
27+
* Package version bumped to `0.5.0`.
28+
* GitHub Action now documents the workflow permissions needed for checks, PR comments,
29+
and labels.
30+
* CI workflow now declares explicit least-privilege read access with `permissions: contents: read`.
31+
* PR comment renderer now honors the policy `reporting` block
32+
(`max_findings_in_comment`, `max_reasons`, `include_fields`) instead of always
33+
falling back to fixed defaults.
34+
35+
### Fixed
36+
37+
* `include_fields` in the policy `reporting` block is now actually applied when
38+
rendering finding lines (location and metadata fields), instead of being ignored.
39+
40+
### Security
41+
42+
* Hardened M.A.R.I.A outbound requests against server-side request forgery by validating
43+
URL schemes, rejecting embedded credentials, and blocking local/private/reserved network
44+
targets by default. Private/local URLs require explicit trusted opt-in with
45+
`SECSCORE_ALLOW_PRIVATE_MARIA_URLS=true`.
46+
* Hardened CLI and SARIF file handling against uncontrolled path access by resolving paths
47+
and requiring them to stay inside the current workspace or approved CI roots.
48+
* Hardened the GitHub composite action against code injection by moving input interpolation
49+
into environment variables and passing CLI arguments through quoted Bash arrays.
50+
* Hardened the PR comment against Markdown injection from untrusted scanner output by
51+
escaping finding titles, paths and metadata, and percent-encoding link targets.
52+
53+
### Repository
54+
55+
* Added `.gitattributes` enforcing LF line endings so the composite action's Bash steps
56+
stay valid on Linux runners regardless of contributor OS.
57+
* Ignored generated artifacts (`secscore-report.html`, runtime `policy/policy-maria.yml`,
58+
`tmp-*`) and stopped tracking `tmp-result.json`.
59+
60+
---
61+
962
## v0.4.0 — 2026-04
1063

1164
### Added

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @cassiodeveloper

README.md

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ Install dependencies:
107107

108108
```
109109
pip install -r requirements.txt
110+
pip install -e .
110111
```
111112

112113
---
@@ -116,7 +117,7 @@ pip install -r requirements.txt
116117
1. Run with SARIF and policy:
117118

118119
```bash
119-
python -m secscore.cli.main pr \
120+
secscore pr \
120121
--sarif tests/fixtures/review.sarif \
121122
--policy policy/policy-pr.yml \
122123
--no-diff-aware
@@ -125,11 +126,12 @@ python -m secscore.cli.main pr \
125126
2. Check outputs:
126127
- `pr-comment.md` (PR-ready markdown summary)
127128
- `secscore-result.json` (structured result)
129+
- Optional: `secscore-report.html` (visual report generated when `--html-output true`)
128130

129131
3. Optional: submit result to M.A.R.I.A:
130132

131133
```bash
132-
python -m secscore.cli.main pr \
134+
SECSCORE_ALLOW_PRIVATE_MARIA_URLS=true secscore pr \
133135
--sarif tests/fixtures/review.sarif \
134136
--policy policy/policy-pr.yml \
135137
--maria-url http://localhost:5213/api/secscore/submissions \
@@ -147,7 +149,7 @@ Use these commands to validate expected outcomes quickly:
147149
### PASS
148150

149151
```bash
150-
python -m secscore.cli.main pr \
152+
secscore pr \
151153
--sarif tests/fixtures/pass.sarif \
152154
--policy policy/policy-pr.yml \
153155
--no-diff-aware
@@ -158,7 +160,7 @@ Expected: `Decision: PASS`
158160
### REVIEW
159161

160162
```bash
161-
python -m secscore.cli.main pr \
163+
secscore pr \
162164
--sarif tests/fixtures/review.sarif \
163165
--policy policy/policy-pr.yml \
164166
--no-diff-aware
@@ -169,7 +171,7 @@ Expected: `Decision: REVIEW`
169171
### FAIL
170172

171173
```bash
172-
python -m secscore.cli.main pr \
174+
secscore pr \
173175
--sarif tests/fixtures/fail.sarif \
174176
--policy policy/policy-pr.yml \
175177
--no-diff-aware
@@ -194,7 +196,7 @@ Expected: `Decision: FAIL`
194196
Single SARIF file:
195197

196198
```
197-
python -m secscore.cli.main pr \
199+
secscore pr \
198200
--sarif examples/example-snyk.sarif \
199201
--policy policy/policy-pr.yml \
200202
--no-diff-aware
@@ -203,7 +205,7 @@ python -m secscore.cli.main pr \
203205
Multiple SARIF files (v0.3.0+):
204206

205207
```
206-
python -m secscore.cli.main pr \
208+
secscore pr \
207209
--sarif semgrep.sarif,trivy.sarif \
208210
--policy policy/policy-pr.yml \
209211
--no-diff-aware
@@ -212,7 +214,7 @@ python -m secscore.cli.main pr \
212214
Send consolidated findings to M.A.R.I.A (token provided at invocation):
213215

214216
```bash
215-
python -m secscore.cli.main pr \
217+
secscore pr \
216218
--sarif semgrep.sarif,trivy.sarif \
217219
--policy policy/policy-pr.yml \
218220
--maria-url https://demo.mariaappsec.com/api/secscore/submissions \
@@ -226,10 +228,18 @@ For `/api/secscore/submissions`, SecScore auto-fills required submission fields
226228
You can override them with:
227229
`--maria-submission-key`, `--maria-commit-sha`, `--maria-branch-name`, `--maria-pipeline-name`, `--maria-pipeline-run-id`, `--maria-pull-request-id`.
228230

231+
### M.A.R.I.A policy import behavior
232+
233+
- When M.A.R.I.A integration is configured (`--maria-url`, `--maria-repository-id`, `--token`/`--maria-token`),
234+
SecScore imports policy from M.A.R.I.A by default.
235+
- The imported policy is saved on every run to `policy/policy-maria.yml`.
236+
- The execution then uses `policy/policy-maria.yml` as the effective policy.
237+
- Use `--maria-import-policy false` to keep using the local policy file from `--policy`.
238+
229239
For local PR testing without opening a real PR:
230240

231241
```bash
232-
SECSCORE_PULL_REQUEST_ID=local-pr-001 python -m secscore.cli.main pr \
242+
SECSCORE_ALLOW_PRIVATE_MARIA_URLS=true SECSCORE_PULL_REQUEST_ID=local-pr-001 secscore pr \
233243
--sarif semgrep.sarif \
234244
--policy policy/policy-pr.yml \
235245
--maria-url http://localhost:5213/api/secscore/submissions \
@@ -252,10 +262,36 @@ Score: 85 / 100
252262
Decision: PASS
253263
```
254264

265+
Generate a visual HTML report from the standard JSON output:
266+
267+
```bash
268+
secscore pr \
269+
--sarif tests/fixtures/review.sarif \
270+
--policy policy/policy-pr.yml \
271+
--no-diff-aware \
272+
--html-output true
273+
```
274+
275+
The JSON result is always generated. When HTML output is enabled, SecScore also writes
276+
`secscore-report.html` by default. Use `--html-out custom-report.html` to choose another path.
277+
255278
---
256279

257280
## GitHub Action
258281

282+
Recommended workflow permissions:
283+
284+
```yaml
285+
permissions:
286+
contents: read
287+
checks: write
288+
pull-requests: write
289+
issues: write
290+
```
291+
292+
SecScore needs `contents: read` to access the repository, `checks: write` to create the status check,
293+
and `issues: write`/`pull-requests: write` to upsert PR comments and manage the review label.
294+
259295
Minimal example:
260296

261297
```yaml
@@ -281,6 +317,24 @@ Multiple scanners (v0.3.0+):
281317
maria-token: ${{ secrets.MARIA_TOKEN }}
282318
```
283319

320+
Generate and publish the HTML report as a workflow artifact:
321+
322+
```yaml
323+
- name: Run SecScore
324+
uses: cassiodeveloper/secscore@v1
325+
with:
326+
sarif: results.sarif
327+
html_output: "true"
328+
329+
- name: Upload SecScore report
330+
uses: actions/upload-artifact@v4
331+
with:
332+
name: secscore-report
333+
path: |
334+
secscore-result.json
335+
secscore-report.html
336+
```
337+
284338
Disable diff-aware:
285339

286340
```yaml

0 commit comments

Comments
 (0)