github-security-report 0.22.0__tar.gz → 0.23.1__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.22.0/README.md → github_security_report-0.23.1/PKG-INFO +95 -6
- github_security_report-0.22.0/PKG-INFO → github_security_report-0.23.1/README.md +51 -50
- {github_security_report-0.22.0 → github_security_report-0.23.1}/pyproject.toml +6 -5
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/_version.py +2 -2
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/categories/__init__.py +10 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/modes.py +2 -2
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/remediation.py +1 -1
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/serialise.py +9 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/failures.py +1 -1
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/parsers.py +2 -2
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/codeql/cleanup.py +11 -2
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/codeql/facts.py +20 -4
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/codeql/tables.py +14 -8
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/collect/extras.py +30 -3
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/collect/run_sync.py +1 -1
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/config/blocks.py +27 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/config/models.py +17 -1
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/config/schema.py +13 -2
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/malware.py +1 -1
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/posture/releases.py +1 -1
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/report/aggregate.py +6 -6
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/workflow_runs/store_codec.py +1 -1
- {github_security_report-0.22.0 → github_security_report-0.23.1}/.gitignore +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/LICENSE +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/LICENSES/Apache-2.0.txt +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/scripts/README.md +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/authors.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/categories/keys.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/categories/signals.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/categories/tables.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/classify.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/__main__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/app.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/boundary.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/options.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/outputs.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/progress.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/publish.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/cli/summary.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/accounting.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/alerts.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/analyses.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/batch_errors.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/codeql_parsers.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/copilot.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/endpoints.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/errors.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/events.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/org_reads.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/paging.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/queries.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/reads.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/repo_parser.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/reviews.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/transport.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/workflow_runs.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/client/writes.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/code_quality.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/codeql/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/collect/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/collect/codeql.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/collect/context.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/collect/graph.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/collect/org.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/collect/protocols.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/collect/repo.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/collect/scoping.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/collect/workflow_runs.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/config/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/config/loader.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/config/order.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/gating.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/gitctx.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/issue_presentation.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/issues.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/layout.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/models.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/ordering.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/posture/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/posture/enablement.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/posture/facts.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/posture/quality.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/pulls/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/pulls/columns.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/pulls/counting.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/pulls/presentation.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/pulls/table.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/py.typed +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/ranking.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/remediate/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/remediate/codeql.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/remediate/model.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/render/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/render/html.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/render/markdown.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/render/slack.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/render/slack_limits.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/render/slack_text.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/render/terminal.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/render/terminal_notices.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/report/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/report/display.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/report/signals.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/report/tables.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/rulesets.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/runner.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/scope.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/secret_patterns.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/severity.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/summary.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/templates/index.html.j2 +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/templates/report.html.j2 +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/workflow_runs/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/workflow_runs/aggregate.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/workflow_runs/models.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/workflow_runs/store.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.1}/src/github_security_report/workflow_runs/tables.py +0 -0
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: github-security-report
|
|
3
|
+
Version: 0.23.1
|
|
4
|
+
Summary: Security and quality reporting across GitHub organisations
|
|
5
|
+
Project-URL: Homepage, https://github.com/lfreleng-actions/github-security-report-action
|
|
6
|
+
Project-URL: Repository, https://github.com/lfreleng-actions/github-security-report-action
|
|
7
|
+
Project-URL: Issues, https://github.com/lfreleng-actions/github-security-report-action/issues
|
|
8
|
+
Author-email: The Linux Foundation <mwatkins@linuxfoundation.org>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: codeql,dependabot,github,github-actions,linux-foundation,reporting,scorecard,secret-scanning,security,zizmor
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
23
|
+
Classifier: Topic :: Security
|
|
24
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Requires-Dist: httpx[http2]==0.28.1
|
|
28
|
+
Requires-Dist: jinja2==3.1.6
|
|
29
|
+
Requires-Dist: jsonschema==4.26.0
|
|
30
|
+
Requires-Dist: pyyaml==6.0.3
|
|
31
|
+
Requires-Dist: rich==15.0.0
|
|
32
|
+
Requires-Dist: typer==0.27.3
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: mypy==2.4.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-asyncio==1.4.1; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest-cov==7.1.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest==9.1.1; extra == 'dev'
|
|
38
|
+
Requires-Dist: respx==0.23.1; extra == 'dev'
|
|
39
|
+
Requires-Dist: ruff==0.17.3; extra == 'dev'
|
|
40
|
+
Requires-Dist: syrupy==6.1.1; extra == 'dev'
|
|
41
|
+
Requires-Dist: types-jsonschema==4.26.0.20261006; extra == 'dev'
|
|
42
|
+
Requires-Dist: types-pyyaml==6.0.12.20250915; extra == 'dev'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
1
45
|
<!--
|
|
2
46
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
47
|
# SPDX-FileCopyrightText: 2026 The Linux Foundation
|
|
@@ -156,7 +200,8 @@ tables (org mode):
|
|
|
156
200
|
enabled count out of the applicable count per language, such as
|
|
157
201
|
`python 30/32 · go 5/5 · javascript-typescript 10/12`. See
|
|
158
202
|
[ADR-0006](docs/adr/0006-github-code-quality.md); hide it with the
|
|
159
|
-
`code_quality` render toggle
|
|
203
|
+
`code_quality` render toggle, or leave fixture repositories out of it alone
|
|
204
|
+
with its `exclude` patterns (see [Per-category exclusions](#per-category-exclusions)).
|
|
160
205
|
- **Workflow Failures** — repositories whose GitHub Actions workflows failed
|
|
161
206
|
in the window, ranked by failed runs. The motivating case is the bulk
|
|
162
207
|
Dependabot merge whose integration tests need credentials, so they run
|
|
@@ -488,10 +533,11 @@ governs that line on every surface:
|
|
|
488
533
|
|
|
489
534
|
Hiding the line changes nothing else: every count is unaffected, and the report
|
|
490
535
|
header's repository count already leaves excluded repositories out. So a clean
|
|
491
|
-
category reads `All Clean` once no Excluded line qualifies it.
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
536
|
+
category reads `All Clean` once no Excluded line qualifies it. Every category
|
|
537
|
+
reports the organisation's own list unless it excludes repositories of its own
|
|
538
|
+
(see [Per-category exclusions](#per-category-exclusions)), so with
|
|
539
|
+
`conditional-hide` the line survives only beneath such a category. The
|
|
540
|
+
`report.json` artifact always lists the exclusions.
|
|
495
541
|
|
|
496
542
|
Archived and test repositories are excluded from analysis by default. Opt them
|
|
497
543
|
back in with `report.include_archived` / `report.include_test` in the config, or
|
|
@@ -642,6 +688,40 @@ table with qualitative columns has no enabled list to name. These categories
|
|
|
642
688
|
render as a name list rather than a one-column table on every surface. The
|
|
643
689
|
`report.json` artifact is unaffected.
|
|
644
690
|
|
|
691
|
+
### Per-category exclusions
|
|
692
|
+
|
|
693
|
+
A category can leave repositories out that every other category still reports,
|
|
694
|
+
with `report.categories.<key>.exclude`: a list of regular expressions searched
|
|
695
|
+
against the repository name, case-insensitively, so `^test-` drops every
|
|
696
|
+
repository whose name starts with `test-` and `^fixture$` drops exactly
|
|
697
|
+
`fixture`. The motivating case is Code Quality, which is billed per committer:
|
|
698
|
+
an organisation that reports its test repositories (`include_test`) still has
|
|
699
|
+
no reason to pay for scanning them, and wants the section to list only the
|
|
700
|
+
repositories worth switching on:
|
|
701
|
+
|
|
702
|
+
```json
|
|
703
|
+
{
|
|
704
|
+
"report": {
|
|
705
|
+
"include_test": true,
|
|
706
|
+
"categories": {
|
|
707
|
+
"code_quality": { "exclude": ["^test-"] }
|
|
708
|
+
}
|
|
709
|
+
},
|
|
710
|
+
"organizations": [{ "name": "lfreleng-actions" }]
|
|
711
|
+
}
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
An excluded repository is neither a row nor a count in that category, and
|
|
715
|
+
`remediate --category code_quality` never writes to it. It is not dropped
|
|
716
|
+
silently: the category's **Excluded** footer line names it alongside the
|
|
717
|
+
organisation's own `exclude` list, and `report.json` carries the category's full
|
|
718
|
+
list under `category_excluded`. Under `excluded_display: conditional-hide` that
|
|
719
|
+
footer line is exactly the one that stays. An organisation's own `exclude` list
|
|
720
|
+
replaces the inherited one rather than adding to it, as every other
|
|
721
|
+
`categories` key does; a pattern that does not compile is a configuration
|
|
722
|
+
error. `exclude` applies to `code_quality` only; setting it on any other
|
|
723
|
+
category is a configuration error, since no other table yet applies it.
|
|
724
|
+
|
|
645
725
|
### Per-category row ordering
|
|
646
726
|
|
|
647
727
|
Each table ships a sensible default ordering — largest backlog first, stalest
|
|
@@ -2048,6 +2128,13 @@ cause:
|
|
|
2048
2128
|
|
|
2049
2129
|
<!-- markdownlint-enable MD013 -->
|
|
2050
2130
|
|
|
2131
|
+
"Analyses failing" is reported only while the setup still exists and still
|
|
2132
|
+
runs. When the setup is gone or blocked (default setup off or no longer
|
|
2133
|
+
listing the language, workflow removed, superseded by default setup) that
|
|
2134
|
+
cause stands even if the newest attempt errored: default setup drops a
|
|
2135
|
+
language whose last run found no code for it, and that run uploads an error,
|
|
2136
|
+
but nothing can upload under the category again, so there is no run to fix.
|
|
2137
|
+
|
|
2051
2138
|
Deleting removes a configuration's analyses, which clears GitHub's *"Code
|
|
2052
2139
|
Scanning results may be out of date"* warning but also removes its alert
|
|
2053
2140
|
history. A deletion is therefore **refused**, in a dry run as in an apply,
|
|
@@ -2055,7 +2142,9 @@ when:
|
|
|
2055
2142
|
|
|
2056
2143
|
- no current configuration scans its language: the stale results are then
|
|
2057
2144
|
the only record of it, so add scanning for the language first (the refusal
|
|
2058
|
-
names it, and **CodeQL: Language Coverage** lists the gap)
|
|
2145
|
+
names it, and **CodeQL: Language Coverage** lists the gap). A language
|
|
2146
|
+
default setup itself dropped is exempt: nothing lists it as a gap, so
|
|
2147
|
+
nothing would ever call for scanning it again;
|
|
2059
2148
|
- it would help close an open alert. This is judged across **every deletion
|
|
2060
2149
|
planned in the repository**, not one at a time: an alert held by two stale
|
|
2061
2150
|
configurations would close if both went, so both are refused, although
|
|
@@ -1,47 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: github-security-report
|
|
3
|
-
Version: 0.22.0
|
|
4
|
-
Summary: Security and quality reporting across GitHub organisations
|
|
5
|
-
Project-URL: Homepage, https://github.com/lfreleng-actions/github-security-report-action
|
|
6
|
-
Project-URL: Repository, https://github.com/lfreleng-actions/github-security-report-action
|
|
7
|
-
Project-URL: Issues, https://github.com/lfreleng-actions/github-security-report-action/issues
|
|
8
|
-
Author-email: The Linux Foundation <mwatkins@linuxfoundation.org>
|
|
9
|
-
License-Expression: Apache-2.0
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Keywords: codeql,dependabot,github,github-actions,linux-foundation,reporting,scorecard,secret-scanning,security,zizmor
|
|
12
|
-
Classifier: Development Status :: 3 - Alpha
|
|
13
|
-
Classifier: Intended Audience :: Developers
|
|
14
|
-
Classifier: Operating System :: OS Independent
|
|
15
|
-
Classifier: Programming Language :: Python
|
|
16
|
-
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
-
Classifier: Topic :: Security
|
|
24
|
-
Classifier: Topic :: Software Development :: Quality Assurance
|
|
25
|
-
Classifier: Typing :: Typed
|
|
26
|
-
Requires-Python: >=3.10
|
|
27
|
-
Requires-Dist: httpx[http2]==0.28.1
|
|
28
|
-
Requires-Dist: jinja2==3.1.6
|
|
29
|
-
Requires-Dist: jsonschema==4.26.0
|
|
30
|
-
Requires-Dist: pyyaml==6.0.3
|
|
31
|
-
Requires-Dist: rich==15.0.0
|
|
32
|
-
Requires-Dist: typer==0.27.3
|
|
33
|
-
Provides-Extra: dev
|
|
34
|
-
Requires-Dist: mypy==2.4.0; extra == 'dev'
|
|
35
|
-
Requires-Dist: pytest-asyncio==1.4.1; extra == 'dev'
|
|
36
|
-
Requires-Dist: pytest-cov==7.1.0; extra == 'dev'
|
|
37
|
-
Requires-Dist: pytest==9.1.1; extra == 'dev'
|
|
38
|
-
Requires-Dist: respx==0.23.1; extra == 'dev'
|
|
39
|
-
Requires-Dist: ruff==0.17.3; extra == 'dev'
|
|
40
|
-
Requires-Dist: syrupy==6.1.1; extra == 'dev'
|
|
41
|
-
Requires-Dist: types-jsonschema==4.26.0.20261006; extra == 'dev'
|
|
42
|
-
Requires-Dist: types-pyyaml==6.0.12.20250915; extra == 'dev'
|
|
43
|
-
Description-Content-Type: text/markdown
|
|
44
|
-
|
|
45
1
|
<!--
|
|
46
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
47
3
|
# SPDX-FileCopyrightText: 2026 The Linux Foundation
|
|
@@ -200,7 +156,8 @@ tables (org mode):
|
|
|
200
156
|
enabled count out of the applicable count per language, such as
|
|
201
157
|
`python 30/32 · go 5/5 · javascript-typescript 10/12`. See
|
|
202
158
|
[ADR-0006](docs/adr/0006-github-code-quality.md); hide it with the
|
|
203
|
-
`code_quality` render toggle
|
|
159
|
+
`code_quality` render toggle, or leave fixture repositories out of it alone
|
|
160
|
+
with its `exclude` patterns (see [Per-category exclusions](#per-category-exclusions)).
|
|
204
161
|
- **Workflow Failures** — repositories whose GitHub Actions workflows failed
|
|
205
162
|
in the window, ranked by failed runs. The motivating case is the bulk
|
|
206
163
|
Dependabot merge whose integration tests need credentials, so they run
|
|
@@ -532,10 +489,11 @@ governs that line on every surface:
|
|
|
532
489
|
|
|
533
490
|
Hiding the line changes nothing else: every count is unaffected, and the report
|
|
534
491
|
header's repository count already leaves excluded repositories out. So a clean
|
|
535
|
-
category reads `All Clean` once no Excluded line qualifies it.
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
492
|
+
category reads `All Clean` once no Excluded line qualifies it. Every category
|
|
493
|
+
reports the organisation's own list unless it excludes repositories of its own
|
|
494
|
+
(see [Per-category exclusions](#per-category-exclusions)), so with
|
|
495
|
+
`conditional-hide` the line survives only beneath such a category. The
|
|
496
|
+
`report.json` artifact always lists the exclusions.
|
|
539
497
|
|
|
540
498
|
Archived and test repositories are excluded from analysis by default. Opt them
|
|
541
499
|
back in with `report.include_archived` / `report.include_test` in the config, or
|
|
@@ -686,6 +644,40 @@ table with qualitative columns has no enabled list to name. These categories
|
|
|
686
644
|
render as a name list rather than a one-column table on every surface. The
|
|
687
645
|
`report.json` artifact is unaffected.
|
|
688
646
|
|
|
647
|
+
### Per-category exclusions
|
|
648
|
+
|
|
649
|
+
A category can leave repositories out that every other category still reports,
|
|
650
|
+
with `report.categories.<key>.exclude`: a list of regular expressions searched
|
|
651
|
+
against the repository name, case-insensitively, so `^test-` drops every
|
|
652
|
+
repository whose name starts with `test-` and `^fixture$` drops exactly
|
|
653
|
+
`fixture`. The motivating case is Code Quality, which is billed per committer:
|
|
654
|
+
an organisation that reports its test repositories (`include_test`) still has
|
|
655
|
+
no reason to pay for scanning them, and wants the section to list only the
|
|
656
|
+
repositories worth switching on:
|
|
657
|
+
|
|
658
|
+
```json
|
|
659
|
+
{
|
|
660
|
+
"report": {
|
|
661
|
+
"include_test": true,
|
|
662
|
+
"categories": {
|
|
663
|
+
"code_quality": { "exclude": ["^test-"] }
|
|
664
|
+
}
|
|
665
|
+
},
|
|
666
|
+
"organizations": [{ "name": "lfreleng-actions" }]
|
|
667
|
+
}
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
An excluded repository is neither a row nor a count in that category, and
|
|
671
|
+
`remediate --category code_quality` never writes to it. It is not dropped
|
|
672
|
+
silently: the category's **Excluded** footer line names it alongside the
|
|
673
|
+
organisation's own `exclude` list, and `report.json` carries the category's full
|
|
674
|
+
list under `category_excluded`. Under `excluded_display: conditional-hide` that
|
|
675
|
+
footer line is exactly the one that stays. An organisation's own `exclude` list
|
|
676
|
+
replaces the inherited one rather than adding to it, as every other
|
|
677
|
+
`categories` key does; a pattern that does not compile is a configuration
|
|
678
|
+
error. `exclude` applies to `code_quality` only; setting it on any other
|
|
679
|
+
category is a configuration error, since no other table yet applies it.
|
|
680
|
+
|
|
689
681
|
### Per-category row ordering
|
|
690
682
|
|
|
691
683
|
Each table ships a sensible default ordering — largest backlog first, stalest
|
|
@@ -2092,6 +2084,13 @@ cause:
|
|
|
2092
2084
|
|
|
2093
2085
|
<!-- markdownlint-enable MD013 -->
|
|
2094
2086
|
|
|
2087
|
+
"Analyses failing" is reported only while the setup still exists and still
|
|
2088
|
+
runs. When the setup is gone or blocked (default setup off or no longer
|
|
2089
|
+
listing the language, workflow removed, superseded by default setup) that
|
|
2090
|
+
cause stands even if the newest attempt errored: default setup drops a
|
|
2091
|
+
language whose last run found no code for it, and that run uploads an error,
|
|
2092
|
+
but nothing can upload under the category again, so there is no run to fix.
|
|
2093
|
+
|
|
2095
2094
|
Deleting removes a configuration's analyses, which clears GitHub's *"Code
|
|
2096
2095
|
Scanning results may be out of date"* warning but also removes its alert
|
|
2097
2096
|
history. A deletion is therefore **refused**, in a dry run as in an apply,
|
|
@@ -2099,7 +2098,9 @@ when:
|
|
|
2099
2098
|
|
|
2100
2099
|
- no current configuration scans its language: the stale results are then
|
|
2101
2100
|
the only record of it, so add scanning for the language first (the refusal
|
|
2102
|
-
names it, and **CodeQL: Language Coverage** lists the gap)
|
|
2101
|
+
names it, and **CodeQL: Language Coverage** lists the gap). A language
|
|
2102
|
+
default setup itself dropped is exempt: nothing lists it as a gap, so
|
|
2103
|
+
nothing would ever call for scanning it again;
|
|
2103
2104
|
- it would help close an open alert. This is judged across **every deletion
|
|
2104
2105
|
planned in the repository**, not one at a time: an alert held by two stale
|
|
2105
2106
|
configurations would close if both went, so both are refused, although
|
|
@@ -14,7 +14,7 @@ authors = [
|
|
|
14
14
|
]
|
|
15
15
|
license = "Apache-2.0"
|
|
16
16
|
readme = "README.md"
|
|
17
|
-
requires-python = ">=3.
|
|
17
|
+
requires-python = ">=3.11"
|
|
18
18
|
classifiers = [
|
|
19
19
|
"Development Status :: 3 - Alpha",
|
|
20
20
|
"Intended Audience :: Developers",
|
|
@@ -22,11 +22,11 @@ classifiers = [
|
|
|
22
22
|
"Programming Language :: Python",
|
|
23
23
|
"Programming Language :: Python :: 3",
|
|
24
24
|
"Programming Language :: Python :: 3 :: Only",
|
|
25
|
-
"Programming Language :: Python :: 3.10",
|
|
26
25
|
"Programming Language :: Python :: 3.11",
|
|
27
26
|
"Programming Language :: Python :: 3.12",
|
|
28
27
|
"Programming Language :: Python :: 3.13",
|
|
29
28
|
"Programming Language :: Python :: 3.14",
|
|
29
|
+
"Programming Language :: Python :: 3.15",
|
|
30
30
|
"Topic :: Software Development :: Quality Assurance",
|
|
31
31
|
"Topic :: Security",
|
|
32
32
|
"Typing :: Typed",
|
|
@@ -144,7 +144,7 @@ show_missing = true
|
|
|
144
144
|
skip_empty = true
|
|
145
145
|
|
|
146
146
|
[tool.mypy]
|
|
147
|
-
python_version = "3.
|
|
147
|
+
python_version = "3.11"
|
|
148
148
|
# The whole first-party tree, so a bare 'mypy' checks what the pre-commit hook
|
|
149
149
|
# checks. Tests are deliberately included: they are held to the same standard
|
|
150
150
|
# as the package.
|
|
@@ -156,7 +156,7 @@ ignore_missing_imports = true
|
|
|
156
156
|
exclude = ["src/github_security_report/_version.py"]
|
|
157
157
|
|
|
158
158
|
[tool.basedpyright]
|
|
159
|
-
pythonVersion = "3.
|
|
159
|
+
pythonVersion = "3.11"
|
|
160
160
|
pythonPlatform = "All"
|
|
161
161
|
typeCheckingMode = "standard"
|
|
162
162
|
exclude = ["src/github_security_report/_version.py"]
|
|
@@ -190,7 +190,7 @@ reportIndexIssue = false
|
|
|
190
190
|
reportArgumentType = false
|
|
191
191
|
|
|
192
192
|
[tool.ruff]
|
|
193
|
-
target-version = "
|
|
193
|
+
target-version = "py311"
|
|
194
194
|
line-length = 88
|
|
195
195
|
exclude = ["src/github_security_report/_version.py"]
|
|
196
196
|
|
|
@@ -199,6 +199,7 @@ select = ["E", "W", "F", "I", "B", "C4", "UP", "SIM"]
|
|
|
199
199
|
ignore = [
|
|
200
200
|
"E501", # line length handled by formatter
|
|
201
201
|
"B008", # function calls in argument defaults (Typer pattern)
|
|
202
|
+
"UP042", # StrEnum changes str()/format() of members; keep (str, Enum)
|
|
202
203
|
]
|
|
203
204
|
|
|
204
205
|
[tool.ruff.lint.per-file-ignores]
|
|
@@ -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.23.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 23, 1)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -24,6 +24,7 @@ from github_security_report.categories.signals import SIGNAL_CATEGORIES
|
|
|
24
24
|
from github_security_report.categories.tables import TABLE_CATEGORIES
|
|
25
25
|
|
|
26
26
|
__all__ = [
|
|
27
|
+
"EXCLUDABLE_CATEGORIES",
|
|
27
28
|
"NESTED_CATEGORIES",
|
|
28
29
|
"REPO_LIST_CATEGORIES",
|
|
29
30
|
"CategoryKey",
|
|
@@ -76,6 +77,15 @@ REPO_LIST_CATEGORIES: frozenset[CategoryKey] = frozenset(
|
|
|
76
77
|
)
|
|
77
78
|
|
|
78
79
|
|
|
80
|
+
# Categories that take an ``exclude`` list of their own, dropping repositories
|
|
81
|
+
# from that one category while every other still reports them. A repository
|
|
82
|
+
# excluded this way is counted on the category's Excluded footer line, so the
|
|
83
|
+
# omission stays visible, and remediation never writes it. Only the categories
|
|
84
|
+
# whose builders apply the list are named: the schema refuses it anywhere else,
|
|
85
|
+
# where it would validate and then do nothing.
|
|
86
|
+
EXCLUDABLE_CATEGORIES: frozenset[CategoryKey] = frozenset({CategoryKey.CODE_QUALITY})
|
|
87
|
+
|
|
88
|
+
|
|
79
89
|
def orderable_categories() -> tuple[CategoryMeta, ...]:
|
|
80
90
|
"""Categories an ordering list may name, in registry order.
|
|
81
91
|
|
|
@@ -214,7 +214,7 @@ async def _run_org(cfg: Config, options: OrgRunOptions, *, console: Console) ->
|
|
|
214
214
|
summaries as the collections ended would have stacked them all above the
|
|
215
215
|
first report.
|
|
216
216
|
"""
|
|
217
|
-
now = dt.datetime.now(dt.
|
|
217
|
+
now = dt.datetime.now(dt.UTC)
|
|
218
218
|
collected = await _collect_reports(cfg, console=console, now=now, options=options)
|
|
219
219
|
if collected is None:
|
|
220
220
|
return 2
|
|
@@ -285,7 +285,7 @@ async def _run_repo(
|
|
|
285
285
|
if not token:
|
|
286
286
|
console.print(f"[red]No token in ${token_env}[/red]")
|
|
287
287
|
return 2
|
|
288
|
-
now = dt.datetime.now(dt.
|
|
288
|
+
now = dt.datetime.now(dt.UTC)
|
|
289
289
|
# One repository, so the live line has no counter to drive; the spinner
|
|
290
290
|
# and the request counts still cover the probes and the run listing.
|
|
291
291
|
tracker = make_tracker(console, no_progress=no_progress)
|
|
@@ -55,7 +55,7 @@ async def _run_remediate(
|
|
|
55
55
|
auto-discovered config file, printed under each org's divider. Returns 2
|
|
56
56
|
for a bad selection, 1 when any write failed, else 0.
|
|
57
57
|
"""
|
|
58
|
-
now = dt.datetime.now(dt.
|
|
58
|
+
now = dt.datetime.now(dt.UTC)
|
|
59
59
|
failures = 0
|
|
60
60
|
# One live line per organisation, kept up through the writes too: the
|
|
61
61
|
# paced CodeQL cleanup is otherwise a silent second per deletion.
|
|
@@ -83,6 +83,15 @@ def _org_to_dict(org: OrgReport, hidden: Collection[CategoryKey] = ()) -> dict:
|
|
|
83
83
|
"partial": org.partial,
|
|
84
84
|
# Repositories explicitly excluded from analysis (per-org exclude list).
|
|
85
85
|
"excluded": [r.full_name for r in org.excluded_repos],
|
|
86
|
+
# Categories excluding repositories of their own (a category's
|
|
87
|
+
# `exclude` patterns), each with its full list: the organisation's
|
|
88
|
+
# exclusions above plus the category's. Absent categories report the
|
|
89
|
+
# organisation's list alone.
|
|
90
|
+
"category_excluded": {
|
|
91
|
+
key.value: [r.full_name for r in repos]
|
|
92
|
+
for key, repos in org.category_excluded.items()
|
|
93
|
+
if key not in suppressed
|
|
94
|
+
},
|
|
86
95
|
# Every category below, in the order the rendered surfaces drew it.
|
|
87
96
|
# The keyed structure that follows is stable regardless, but a consumer
|
|
88
97
|
# building its own view can reproduce the published layout instead of
|
|
@@ -52,7 +52,7 @@ async def _endpoint_diagnostics(url: str) -> str:
|
|
|
52
52
|
)
|
|
53
53
|
ips = sorted({str(info[4][0]) for info in infos})
|
|
54
54
|
addr = ", ".join(ips) if ips else "no addresses"
|
|
55
|
-
except
|
|
55
|
+
except TimeoutError:
|
|
56
56
|
addr = "unresolved (timed out)"
|
|
57
57
|
except OSError as exc:
|
|
58
58
|
detail = exc.strerror or str(exc) or "resolution failed"
|
|
@@ -65,8 +65,8 @@ def _parse_retry_after(value: str | None) -> float | None:
|
|
|
65
65
|
if when is None:
|
|
66
66
|
return None
|
|
67
67
|
if when.tzinfo is None:
|
|
68
|
-
when = when.replace(tzinfo=dt.
|
|
69
|
-
return max(0.0, (when - dt.datetime.now(dt.
|
|
68
|
+
when = when.replace(tzinfo=dt.UTC)
|
|
69
|
+
return max(0.0, (when - dt.datetime.now(dt.UTC)).total_seconds())
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
def _next_page_url(resp: httpx.Response) -> str | None:
|
|
@@ -21,7 +21,10 @@ A deletion is *refused* while no current configuration scans its language.
|
|
|
21
21
|
The stale results are then the only record of that language, and removing
|
|
22
22
|
them would turn "scanned, but out of date" into "never scanned" without
|
|
23
23
|
anything having improved. Add scanning for the language first; the refusal
|
|
24
|
-
names it.
|
|
24
|
+
names it. The refusal does not apply when default setup itself dropped the
|
|
25
|
+
language: its language list is the only inventory the report has, so nothing
|
|
26
|
+
would ever call for scanning it again, and Language Coverage shows no gap to
|
|
27
|
+
close. Whether a deletion would close an open alert needs a network read,
|
|
25
28
|
so the remediator checks that separately before any write.
|
|
26
29
|
"""
|
|
27
30
|
|
|
@@ -148,8 +151,14 @@ def _plan_one(
|
|
|
148
151
|
return CleanupItem(facts.repo, config, cause, CleanupAction.REENABLE_WORKFLOW)
|
|
149
152
|
if not cause.orphaned:
|
|
150
153
|
return None
|
|
154
|
+
# Default setup no longer lists a removed language, so no current
|
|
155
|
+
# configuration can scan it and none is expected to: the coverage
|
|
156
|
+
# refusal would ask for scanning that the setup has ruled out.
|
|
157
|
+
uncovered = cause is not StaleCause.LANGUAGE_REMOVED and (
|
|
158
|
+
config.language is None or config.language not in current
|
|
159
|
+
)
|
|
151
160
|
refusal = None
|
|
152
|
-
if
|
|
161
|
+
if uncovered:
|
|
153
162
|
refusal = (
|
|
154
163
|
f"no current configuration scans {config.language or 'its language'}; "
|
|
155
164
|
"add scanning for it first"
|
|
@@ -94,7 +94,8 @@ class StaleCause(str, Enum):
|
|
|
94
94
|
"""
|
|
95
95
|
|
|
96
96
|
# The setup still runs, but its newest attempt errored: never deleted,
|
|
97
|
-
# since fixing the run is what brings the scan back.
|
|
97
|
+
# since fixing the run is what brings the scan back. Yields to a cause
|
|
98
|
+
# whose setup is gone (see ``setup_gone``): there is no run to fix.
|
|
98
99
|
ANALYSES_FAILING = "Analyses failing; check the latest run"
|
|
99
100
|
DEFAULT_SETUP_DISABLED = "Default setup disabled; orphaned"
|
|
100
101
|
LANGUAGE_REMOVED = "Language removed from default setup"
|
|
@@ -127,6 +128,21 @@ class StaleCause(str, Enum):
|
|
|
127
128
|
"""
|
|
128
129
|
return self in _ORPHANED_CAUSES
|
|
129
130
|
|
|
131
|
+
@property
|
|
132
|
+
def setup_gone(self) -> bool:
|
|
133
|
+
"""Whether the setup behind the configuration is gone or blocked.
|
|
134
|
+
|
|
135
|
+
Default setup off or no longer listing the language, the workflow
|
|
136
|
+
file removed, or advanced uploads rejected while default setup is on:
|
|
137
|
+
no attempt of any kind can follow, so an errored newest attempt is
|
|
138
|
+
the setup's last act, not a run anybody can fix, and this cause
|
|
139
|
+
outranks "analyses failing". The one orphaned cause left out is
|
|
140
|
+
superseded-within-workflow: that is inferred from a sibling's
|
|
141
|
+
activity, not the setup's own state, and a fresh errored attempt
|
|
142
|
+
under this category shows the workflow still uploads to it.
|
|
143
|
+
"""
|
|
144
|
+
return self in _SETUP_GONE_CAUSES
|
|
145
|
+
|
|
130
146
|
@property
|
|
131
147
|
def reenable_workflow(self) -> bool:
|
|
132
148
|
"""Whether re-enabling the workflow is the fix, rather than deleting.
|
|
@@ -138,16 +154,16 @@ class StaleCause(str, Enum):
|
|
|
138
154
|
return self is StaleCause.WORKFLOW_INACTIVE
|
|
139
155
|
|
|
140
156
|
|
|
141
|
-
|
|
157
|
+
_SETUP_GONE_CAUSES = frozenset(
|
|
142
158
|
{
|
|
143
159
|
StaleCause.DEFAULT_SETUP_DISABLED,
|
|
144
160
|
StaleCause.LANGUAGE_REMOVED,
|
|
145
161
|
StaleCause.WORKFLOW_REMOVED,
|
|
146
|
-
StaleCause.SUPERSEDED_IN_WORKFLOW,
|
|
147
162
|
StaleCause.SUPERSEDED,
|
|
148
163
|
StaleCause.SUPERSEDED_DISABLED,
|
|
149
164
|
}
|
|
150
165
|
)
|
|
166
|
+
_ORPHANED_CAUSES = _SETUP_GONE_CAUSES | {StaleCause.SUPERSEDED_IN_WORKFLOW}
|
|
151
167
|
|
|
152
168
|
|
|
153
169
|
@dataclass(frozen=True)
|
|
@@ -206,7 +222,7 @@ class CodeQLConfiguration:
|
|
|
206
222
|
|
|
207
223
|
# Aware sentinel so a configuration that never succeeded sorts ahead of every
|
|
208
224
|
# dated one, without comparing a naive and an aware value.
|
|
209
|
-
_NEVER = dt.datetime.min.replace(tzinfo=dt.
|
|
225
|
+
_NEVER = dt.datetime.min.replace(tzinfo=dt.UTC)
|
|
210
226
|
|
|
211
227
|
|
|
212
228
|
@dataclass(frozen=True)
|
|
@@ -135,16 +135,22 @@ def stale_cause(
|
|
|
135
135
|
) -> StaleCause:
|
|
136
136
|
"""Why a stale configuration stopped scanning, as far as the API can tell.
|
|
137
137
|
|
|
138
|
-
An errored newest attempt
|
|
139
|
-
runs
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
An errored newest attempt is the cause while the setup still exists and
|
|
139
|
+
still runs: whatever its state, the reader's next step is its failing
|
|
140
|
+
logs. It is not the cause once the setup is gone or blocked. Default
|
|
141
|
+
setup drops a language whose last run found no code for it, and that
|
|
142
|
+
run uploads an error; reading the error as the cause would leave a
|
|
143
|
+
configuration that can never upload again waiting for a fix that cannot
|
|
144
|
+
come. ``stale_days`` is the threshold the configuration was found stale
|
|
145
|
+
by, which also decides whether another configuration is current.
|
|
142
146
|
"""
|
|
143
|
-
if config.failing:
|
|
144
|
-
return StaleCause.ANALYSES_FAILING
|
|
145
147
|
if config.setup is SetupType.DEFAULT:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
+
cause = _default_setup_cause(config, facts)
|
|
149
|
+
else:
|
|
150
|
+
cause = _advanced_setup_cause(config, facts, stale_days)
|
|
151
|
+
if config.failing and not cause.setup_gone:
|
|
152
|
+
return StaleCause.ANALYSES_FAILING
|
|
153
|
+
return cause
|
|
148
154
|
|
|
149
155
|
|
|
150
156
|
def build_stale_configurations_table(
|
|
@@ -20,6 +20,7 @@ import asyncio
|
|
|
20
20
|
import logging
|
|
21
21
|
|
|
22
22
|
from github_security_report import codeql, layout, malware, posture
|
|
23
|
+
from github_security_report.categories import CategoryKey
|
|
23
24
|
from github_security_report.code_quality import CodeQualitySetup, applicable_languages
|
|
24
25
|
from github_security_report.collect.codeql import collect_codeql_facts
|
|
25
26
|
from github_security_report.collect.context import (
|
|
@@ -45,7 +46,7 @@ from github_security_report.pulls import (
|
|
|
45
46
|
build_assigned_pull_requests_table,
|
|
46
47
|
build_pull_requests_table,
|
|
47
48
|
)
|
|
48
|
-
from github_security_report.report import OrgReport
|
|
49
|
+
from github_security_report.report import OrgReport, TableSection
|
|
49
50
|
|
|
50
51
|
log = logging.getLogger(__name__)
|
|
51
52
|
|
|
@@ -122,6 +123,31 @@ async def _posture_for_repo(repo: Repo, ctx: OrgCollectContext) -> RepoPosture:
|
|
|
122
123
|
)
|
|
123
124
|
|
|
124
125
|
|
|
126
|
+
def _build_code_quality(
|
|
127
|
+
report: OrgReport, postures: list[RepoPosture], report_cfg: ReportConfig
|
|
128
|
+
) -> tuple[TableSection, dict[str, tuple[str, ...]]]:
|
|
129
|
+
"""The Code Quality table and its remediation plan, less the excluded.
|
|
130
|
+
|
|
131
|
+
A repository the category's own ``exclude`` patterns match is dropped
|
|
132
|
+
before the table is built, so it is neither a row nor a count nor a
|
|
133
|
+
remediation target, and is recorded as excluded for this category alone:
|
|
134
|
+
its footer then lists it alongside the organisation's own exclusions,
|
|
135
|
+
while every other category still reports the repository.
|
|
136
|
+
"""
|
|
137
|
+
kept: list[RepoPosture] = []
|
|
138
|
+
dropped: list[Repo] = []
|
|
139
|
+
for p in postures:
|
|
140
|
+
if report_cfg.category_excludes(CategoryKey.CODE_QUALITY, p.repo.name):
|
|
141
|
+
dropped.append(p.repo)
|
|
142
|
+
else:
|
|
143
|
+
kept.append(p)
|
|
144
|
+
if dropped:
|
|
145
|
+
report.category_excluded[CategoryKey.CODE_QUALITY] = sorted(
|
|
146
|
+
(*report.excluded_repos, *dropped), key=lambda r: r.name
|
|
147
|
+
)
|
|
148
|
+
return posture.build_code_quality_table(kept), posture.code_quality_writes(kept)
|
|
149
|
+
|
|
150
|
+
|
|
125
151
|
async def _attach_author_tables(
|
|
126
152
|
report: OrgReport,
|
|
127
153
|
in_scope: list[Repo],
|
|
@@ -251,8 +277,9 @@ async def attach_extra_tables(
|
|
|
251
277
|
sweep_readable=ctx.sweep_status.get("dependabot") == 200,
|
|
252
278
|
generated_at=report.generated_at,
|
|
253
279
|
)
|
|
254
|
-
report.code_quality =
|
|
255
|
-
|
|
280
|
+
report.code_quality, report.code_quality_writes = _build_code_quality(
|
|
281
|
+
report, postures, report_cfg
|
|
282
|
+
)
|
|
256
283
|
report.codeql_tables = codeql.build_codeql_tables(
|
|
257
284
|
codeql_facts, stale_days=report_cfg.codeql_stale_days
|
|
258
285
|
)
|