github-security-report 0.9.0__tar.gz → 0.10.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {github_security_report-0.9.0 → github_security_report-0.10.0}/PKG-INFO +1 -1
- {github_security_report-0.9.0 → github_security_report-0.10.0}/pyproject.toml +4 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/_version.py +2 -2
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/categories.py +2 -1
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/models.py +65 -14
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/severity.py +12 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/.gitignore +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/LICENSE +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/LICENSES/Apache-2.0.txt +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/README.md +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/scripts/README.md +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/__init__.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/classify.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/cli.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/client.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/collect.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/config.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/gating.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/gitctx.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/posture.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/py.typed +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/remediate.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/render/__init__.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/render/html.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/render/markdown.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/render/slack.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/render/terminal.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/report.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/rulesets.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/runner.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/scope.py +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/templates/index.html.j2 +0 -0
- {github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/templates/report.html.j2 +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github-security-report
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Security and quality reporting across GitHub organisations
|
|
5
5
|
Project-URL: Homepage, https://github.com/lfreleng-actions/github-security-report-action
|
|
6
6
|
Project-URL: Repository, https://github.com/lfreleng-actions/github-security-report-action
|
|
@@ -136,6 +136,10 @@ skip_empty = true
|
|
|
136
136
|
|
|
137
137
|
[tool.mypy]
|
|
138
138
|
python_version = "3.10"
|
|
139
|
+
# The whole first-party tree, so a bare 'mypy' checks what the pre-commit hook
|
|
140
|
+
# checks. Tests are deliberately included: they are held to the same standard
|
|
141
|
+
# as the package.
|
|
142
|
+
files = ["src", "tests", "scripts"]
|
|
139
143
|
warn_return_any = true
|
|
140
144
|
warn_unused_configs = true
|
|
141
145
|
disallow_untyped_defs = false
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.10.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 10, 0)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -93,7 +93,8 @@ _CATEGORIES: dict[CategoryKey, CategoryMeta] = {
|
|
|
93
93
|
url="https://github.com/ossf/scorecard",
|
|
94
94
|
description=(
|
|
95
95
|
"OpenSSF Scorecard supply-chain health scores (a lower score is "
|
|
96
|
-
"weaker)
|
|
96
|
+
"weaker). Ranked by the worst severity rung present in the table "
|
|
97
|
+
"(most findings at that rung first), then weakest score first."
|
|
97
98
|
),
|
|
98
99
|
),
|
|
99
100
|
CategoryKey.ZIZMOR: CategoryMeta(
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/models.py
RENAMED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
Encodes the Phase 0 design (see ``docs/BRIEF.md`` and
|
|
6
6
|
``docs/phase0-findings.md``): the six ranked signals, the four-state per-report
|
|
7
7
|
classification, severity counts with hierarchical worst-first ordering, and the
|
|
8
|
-
ranking rules (alert tables sort by severity descending; Scorecard by
|
|
9
|
-
ascending).
|
|
8
|
+
ranking rules (alert tables sort by severity descending; Scorecard by its worst
|
|
9
|
+
populated severity rung descending, then by score ascending).
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -16,7 +16,7 @@ from dataclasses import dataclass, field
|
|
|
16
16
|
from enum import Enum
|
|
17
17
|
|
|
18
18
|
from github_security_report.categories import CategoryKey, CategoryMeta, category_meta
|
|
19
|
-
from github_security_report.severity import Severity
|
|
19
|
+
from github_security_report.severity import RUNGS_WORST_FIRST, Severity
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class SignalType(str, Enum):
|
|
@@ -66,7 +66,13 @@ class SignalType(str, Enum):
|
|
|
66
66
|
|
|
67
67
|
@property
|
|
68
68
|
def sort_ascending(self) -> bool:
|
|
69
|
-
"""
|
|
69
|
+
"""Whether lower is worse for this signal's primary metric.
|
|
70
|
+
|
|
71
|
+
True only for Scorecard, whose aggregate score runs the opposite way to
|
|
72
|
+
a finding count (lower == weaker). The score is Scorecard's *secondary*
|
|
73
|
+
key: ``rank_offenders`` leads on the worst severity rung present in the
|
|
74
|
+
table and uses the score to order repositories within that rung.
|
|
75
|
+
"""
|
|
70
76
|
return self is SignalType.SCORECARD
|
|
71
77
|
|
|
72
78
|
|
|
@@ -177,6 +183,22 @@ class SeverityCounts:
|
|
|
177
183
|
def total(self) -> int:
|
|
178
184
|
return self.critical + self.high + self.medium + self.low + self.informational
|
|
179
185
|
|
|
186
|
+
def at(self, rung: Severity) -> int:
|
|
187
|
+
"""The count at exactly one severity rung.
|
|
188
|
+
|
|
189
|
+
Attribute access rather than a ``by_rung`` lookup, so the ranking hot
|
|
190
|
+
path does not build a dict per comparison.
|
|
191
|
+
"""
|
|
192
|
+
if rung is Severity.CRITICAL:
|
|
193
|
+
return self.critical
|
|
194
|
+
if rung is Severity.HIGH:
|
|
195
|
+
return self.high
|
|
196
|
+
if rung is Severity.MEDIUM:
|
|
197
|
+
return self.medium
|
|
198
|
+
if rung is Severity.LOW:
|
|
199
|
+
return self.low
|
|
200
|
+
return self.informational
|
|
201
|
+
|
|
180
202
|
def at_or_above(self, cutoff: Severity) -> int:
|
|
181
203
|
"""Count of findings whose severity is at least ``cutoff``.
|
|
182
204
|
|
|
@@ -185,14 +207,12 @@ class SeverityCounts:
|
|
|
185
207
|
category's ``fail_severity`` cutoff. Findings below the cutoff (e.g.
|
|
186
208
|
informational-only) do not count towards a failure.
|
|
187
209
|
"""
|
|
188
|
-
by_rung
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
return sum(count for rung, count in by_rung.items() if rung >= cutoff)
|
|
210
|
+
return sum(count for rung, count in self.by_rung.items() if rung >= cutoff)
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def by_rung(self) -> dict[Severity, int]:
|
|
214
|
+
"""Per-severity counts keyed by rung, in worst-first iteration order."""
|
|
215
|
+
return {rung: self.at(rung) for rung in RUNGS_WORST_FIRST}
|
|
196
216
|
|
|
197
217
|
@property
|
|
198
218
|
def weighted(self) -> int:
|
|
@@ -236,12 +256,41 @@ class RepoSignal:
|
|
|
236
256
|
return self.state is RepoState.OFFENDER
|
|
237
257
|
|
|
238
258
|
|
|
259
|
+
# The rungs eligible to lead the Scorecard ordering, worst-first.
|
|
260
|
+
# ``INFORMATIONAL`` is deliberately absent: it is the non-actionable rung, so it
|
|
261
|
+
# never displaces the score as the primary key.
|
|
262
|
+
LEAD_RUNGS: tuple[Severity, ...] = tuple(
|
|
263
|
+
rung for rung in RUNGS_WORST_FIRST if rung is not Severity.INFORMATIONAL
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def lead_rung(offenders: list[RepoSignal]) -> Severity | None:
|
|
268
|
+
"""The worst severity rung any offender actually carries.
|
|
269
|
+
|
|
270
|
+
Returns ``None`` when no offender carries a finding at Low or above, in
|
|
271
|
+
which case there is no severity tier worth leading on.
|
|
272
|
+
"""
|
|
273
|
+
return next(
|
|
274
|
+
(rung for rung in LEAD_RUNGS if any(s.counts.at(rung) for s in offenders)),
|
|
275
|
+
None,
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
|
|
239
279
|
def rank_offenders(signals: list[RepoSignal]) -> list[RepoSignal]:
|
|
240
280
|
"""Sort offenders worst-first for a single signal.
|
|
241
281
|
|
|
242
282
|
Alert-based signals sort by the hierarchical severity key descending, with
|
|
243
|
-
total as a tiebreaker.
|
|
244
|
-
|
|
283
|
+
total as a tiebreaker.
|
|
284
|
+
|
|
285
|
+
Scorecard sorts on two tiers: the count at the worst severity rung present
|
|
286
|
+
anywhere in the table (descending), then the aggregate score (ascending,
|
|
287
|
+
lower == worse). The leading rung cascades -- Critical, else High, else
|
|
288
|
+
Medium, else Low -- so the rung that actually discriminates between
|
|
289
|
+
repositories leads, and a lone Critical can never be buried mid-table by a
|
|
290
|
+
weaker repository with a lower score. When no offender carries a finding at
|
|
291
|
+
Low or above, the score alone orders the table.
|
|
292
|
+
|
|
293
|
+
Repo name breaks remaining ties, ascending.
|
|
245
294
|
|
|
246
295
|
Numeric components are negated so the whole sort runs ascending (no
|
|
247
296
|
``reverse=True``); that keeps the name tiebreaker correctly ascending even
|
|
@@ -252,9 +301,11 @@ def rank_offenders(signals: list[RepoSignal]) -> list[RepoSignal]:
|
|
|
252
301
|
return []
|
|
253
302
|
signal = offenders[0].signal
|
|
254
303
|
if signal.sort_ascending:
|
|
304
|
+
rung = lead_rung(offenders)
|
|
255
305
|
return sorted(
|
|
256
306
|
offenders,
|
|
257
307
|
key=lambda s: (
|
|
308
|
+
-s.counts.at(rung) if rung is not None else 0,
|
|
258
309
|
s.score if s.score is not None else float("inf"),
|
|
259
310
|
s.repo.name,
|
|
260
311
|
),
|
|
@@ -52,6 +52,18 @@ class Severity(IntEnum):
|
|
|
52
52
|
return self.name.lower()
|
|
53
53
|
|
|
54
54
|
|
|
55
|
+
# The canonical worst-first rung order, for the severity columns and for every
|
|
56
|
+
# worst-first ranking. Declared once so display order and ranking order cannot
|
|
57
|
+
# drift apart.
|
|
58
|
+
RUNGS_WORST_FIRST: tuple[Severity, ...] = (
|
|
59
|
+
Severity.CRITICAL,
|
|
60
|
+
Severity.HIGH,
|
|
61
|
+
Severity.MEDIUM,
|
|
62
|
+
Severity.LOW,
|
|
63
|
+
Severity.INFORMATIONAL,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
55
67
|
# Direct names on the security-severity scale (CodeQL, Scorecard, Dependabot).
|
|
56
68
|
_SECURITY_NAMES: dict[str, Severity] = {
|
|
57
69
|
"critical": Severity.CRITICAL,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/cli.py
RENAMED
|
File without changes
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/client.py
RENAMED
|
File without changes
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/collect.py
RENAMED
|
File without changes
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/config.py
RENAMED
|
File without changes
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/gating.py
RENAMED
|
File without changes
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/gitctx.py
RENAMED
|
File without changes
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/posture.py
RENAMED
|
File without changes
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/report.py
RENAMED
|
File without changes
|
|
File without changes
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/runner.py
RENAMED
|
File without changes
|
{github_security_report-0.9.0 → github_security_report-0.10.0}/src/github_security_report/scope.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|