github-security-report 0.22.0__tar.gz → 0.23.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.22.0 → github_security_report-0.23.0}/PKG-INFO +42 -6
- {github_security_report-0.22.0 → github_security_report-0.23.0}/README.md +41 -5
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/_version.py +2 -2
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/categories/__init__.py +10 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/serialise.py +9 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/collect/extras.py +30 -3
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/config/blocks.py +27 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/config/models.py +17 -1
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/config/schema.py +13 -2
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/report/aggregate.py +5 -5
- {github_security_report-0.22.0 → github_security_report-0.23.0}/.gitignore +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/LICENSE +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/LICENSES/Apache-2.0.txt +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/pyproject.toml +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/scripts/README.md +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/authors.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/categories/keys.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/categories/signals.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/categories/tables.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/classify.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/__main__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/app.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/boundary.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/modes.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/options.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/outputs.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/progress.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/publish.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/remediation.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/cli/summary.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/accounting.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/alerts.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/analyses.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/batch_errors.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/codeql_parsers.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/copilot.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/endpoints.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/errors.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/events.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/failures.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/org_reads.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/paging.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/parsers.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/queries.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/reads.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/repo_parser.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/reviews.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/transport.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/workflow_runs.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/client/writes.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/code_quality.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/codeql/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/codeql/cleanup.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/codeql/facts.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/codeql/tables.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/collect/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/collect/codeql.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/collect/context.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/collect/graph.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/collect/org.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/collect/protocols.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/collect/repo.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/collect/run_sync.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/collect/scoping.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/collect/workflow_runs.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/config/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/config/loader.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/config/order.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/gating.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/gitctx.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/issue_presentation.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/issues.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/layout.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/malware.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/models.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/ordering.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/posture/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/posture/enablement.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/posture/facts.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/posture/quality.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/posture/releases.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/pulls/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/pulls/columns.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/pulls/counting.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/pulls/presentation.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/pulls/table.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/py.typed +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/ranking.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/remediate/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/remediate/codeql.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/remediate/model.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/render/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/render/html.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/render/markdown.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/render/slack.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/render/slack_limits.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/render/slack_text.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/render/terminal.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/render/terminal_notices.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/report/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/report/display.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/report/signals.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/report/tables.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/rulesets.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/runner.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/scope.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/secret_patterns.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/severity.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/summary.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/templates/index.html.j2 +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/templates/report.html.j2 +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/workflow_runs/__init__.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/workflow_runs/aggregate.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/workflow_runs/models.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/workflow_runs/store.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/workflow_runs/store_codec.py +0 -0
- {github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/workflow_runs/tables.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: github-security-report
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.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
|
|
@@ -200,7 +200,8 @@ tables (org mode):
|
|
|
200
200
|
enabled count out of the applicable count per language, such as
|
|
201
201
|
`python 30/32 · go 5/5 · javascript-typescript 10/12`. See
|
|
202
202
|
[ADR-0006](docs/adr/0006-github-code-quality.md); hide it with the
|
|
203
|
-
`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)).
|
|
204
205
|
- **Workflow Failures** — repositories whose GitHub Actions workflows failed
|
|
205
206
|
in the window, ranked by failed runs. The motivating case is the bulk
|
|
206
207
|
Dependabot merge whose integration tests need credentials, so they run
|
|
@@ -532,10 +533,11 @@ governs that line on every surface:
|
|
|
532
533
|
|
|
533
534
|
Hiding the line changes nothing else: every count is unaffected, and the report
|
|
534
535
|
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
|
-
|
|
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.
|
|
539
541
|
|
|
540
542
|
Archived and test repositories are excluded from analysis by default. Opt them
|
|
541
543
|
back in with `report.include_archived` / `report.include_test` in the config, or
|
|
@@ -686,6 +688,40 @@ table with qualitative columns has no enabled list to name. These categories
|
|
|
686
688
|
render as a name list rather than a one-column table on every surface. The
|
|
687
689
|
`report.json` artifact is unaffected.
|
|
688
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
|
+
|
|
689
725
|
### Per-category row ordering
|
|
690
726
|
|
|
691
727
|
Each table ships a sensible default ordering — largest backlog first, stalest
|
|
@@ -156,7 +156,8 @@ tables (org mode):
|
|
|
156
156
|
enabled count out of the applicable count per language, such as
|
|
157
157
|
`python 30/32 · go 5/5 · javascript-typescript 10/12`. See
|
|
158
158
|
[ADR-0006](docs/adr/0006-github-code-quality.md); hide it with the
|
|
159
|
-
`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)).
|
|
160
161
|
- **Workflow Failures** — repositories whose GitHub Actions workflows failed
|
|
161
162
|
in the window, ranked by failed runs. The motivating case is the bulk
|
|
162
163
|
Dependabot merge whose integration tests need credentials, so they run
|
|
@@ -488,10 +489,11 @@ governs that line on every surface:
|
|
|
488
489
|
|
|
489
490
|
Hiding the line changes nothing else: every count is unaffected, and the report
|
|
490
491
|
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
|
-
|
|
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.
|
|
495
497
|
|
|
496
498
|
Archived and test repositories are excluded from analysis by default. Opt them
|
|
497
499
|
back in with `report.include_archived` / `report.include_test` in the config, or
|
|
@@ -642,6 +644,40 @@ table with qualitative columns has no enabled list to name. These categories
|
|
|
642
644
|
render as a name list rather than a one-column table on every surface. The
|
|
643
645
|
`report.json` artifact is unaffected.
|
|
644
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
|
+
|
|
645
681
|
### Per-category row ordering
|
|
646
682
|
|
|
647
683
|
Each table ships a sensible default ordering — largest backlog first, stalest
|
|
@@ -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.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 23, 0)
|
|
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
|
|
|
@@ -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
|
|
@@ -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
|
)
|
|
@@ -11,6 +11,7 @@ with a usable error. Those parsers live here; the top-level loader in
|
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
|
+
import re
|
|
14
15
|
from collections.abc import Mapping
|
|
15
16
|
from dataclasses import replace
|
|
16
17
|
from types import MappingProxyType
|
|
@@ -227,6 +228,27 @@ def _require_reachable_warning(
|
|
|
227
228
|
)
|
|
228
229
|
|
|
229
230
|
|
|
231
|
+
def _exclude_patterns_from(key: str, raw: list[str]) -> tuple[re.Pattern[str], ...]:
|
|
232
|
+
"""Compile a category's ``exclude`` list, naming the pattern that fails.
|
|
233
|
+
|
|
234
|
+
Compiled once here rather than on every repository, and rejected at load
|
|
235
|
+
time rather than mid-run: a pattern that does not compile would otherwise
|
|
236
|
+
surface only after the whole organisation had been read. An oversized
|
|
237
|
+
repeat count raises ``OverflowError`` and deep nesting ``RecursionError``
|
|
238
|
+
rather than ``re.error``, so those are caught too.
|
|
239
|
+
"""
|
|
240
|
+
patterns: list[re.Pattern[str]] = []
|
|
241
|
+
for text in raw:
|
|
242
|
+
try:
|
|
243
|
+
patterns.append(re.compile(text, re.IGNORECASE))
|
|
244
|
+
except (re.error, OverflowError, RecursionError) as exc:
|
|
245
|
+
raise ConfigError(
|
|
246
|
+
f"report.categories.{key}.exclude pattern {text!r} is not a "
|
|
247
|
+
f"valid regular expression: {exc}"
|
|
248
|
+
) from exc
|
|
249
|
+
return tuple(patterns)
|
|
250
|
+
|
|
251
|
+
|
|
230
252
|
def _categories_from(
|
|
231
253
|
data: dict, base: Mapping[str, CategoryToggle]
|
|
232
254
|
) -> Mapping[str, CategoryToggle]:
|
|
@@ -267,5 +289,10 @@ def _categories_from(
|
|
|
267
289
|
repo_list=(
|
|
268
290
|
RepoList(raw["repo_list"]) if "repo_list" in raw else current.repo_list
|
|
269
291
|
),
|
|
292
|
+
exclude=(
|
|
293
|
+
_exclude_patterns_from(key, raw["exclude"])
|
|
294
|
+
if "exclude" in raw
|
|
295
|
+
else current.exclude
|
|
296
|
+
),
|
|
270
297
|
)
|
|
271
298
|
return MappingProxyType(merged)
|
|
@@ -10,6 +10,7 @@ defaults they fall back to. Construction from raw JSON lives in
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import datetime as dt
|
|
13
|
+
import re
|
|
13
14
|
from collections.abc import Mapping
|
|
14
15
|
from dataclasses import dataclass, field
|
|
15
16
|
from types import MappingProxyType
|
|
@@ -94,7 +95,10 @@ class CategoryToggle:
|
|
|
94
95
|
ordering of a generic table with a list of column names; ``None`` keeps the
|
|
95
96
|
ordering the table's builder chose. ``repo_list`` overrides which side of a
|
|
96
97
|
boolean feature category is named (see :class:`RepoList`); ``None`` falls
|
|
97
|
-
back to the report-wide ``repo_list``.
|
|
98
|
+
back to the report-wide ``repo_list``. ``exclude`` drops the repositories
|
|
99
|
+
whose name matches any of its regular expressions from this one category
|
|
100
|
+
(see :data:`~github_security_report.categories.EXCLUDABLE_CATEGORIES`);
|
|
101
|
+
they are reported on its Excluded footer line rather than dropped silently.
|
|
98
102
|
"""
|
|
99
103
|
|
|
100
104
|
enabled: bool = True
|
|
@@ -103,6 +107,7 @@ class CategoryToggle:
|
|
|
103
107
|
top_n: int | None = None
|
|
104
108
|
sort: tuple[str, ...] | None = None
|
|
105
109
|
repo_list: RepoList | None = None
|
|
110
|
+
exclude: tuple[re.Pattern[str], ...] = ()
|
|
106
111
|
|
|
107
112
|
def shows_on(self, output: str) -> bool:
|
|
108
113
|
"""Whether this category renders on ``output`` (cli/slack/markdown/html)."""
|
|
@@ -404,6 +409,17 @@ class ReportConfig:
|
|
|
404
409
|
return toggle.repo_list
|
|
405
410
|
return self.repo_list
|
|
406
411
|
|
|
412
|
+
def category_excludes(self, key: CategoryKey, name: str) -> bool:
|
|
413
|
+
"""Whether category ``key`` drops repository ``name`` by its own list.
|
|
414
|
+
|
|
415
|
+
Patterns are searched rather than fully matched, so ``^test-`` reads
|
|
416
|
+
as the prefix it looks like, and compiled case-insensitively, since
|
|
417
|
+
GitHub repository names are. False for an unconfigured category: only
|
|
418
|
+
the organisation's ``exclude`` list removes a repository everywhere.
|
|
419
|
+
"""
|
|
420
|
+
toggle = self.categories.get(key.value)
|
|
421
|
+
return toggle is not None and any(p.search(name) for p in toggle.exclude)
|
|
422
|
+
|
|
407
423
|
|
|
408
424
|
@dataclass(frozen=True)
|
|
409
425
|
class OrgConfig:
|
|
@@ -9,6 +9,7 @@ weekdays), the error raised on invalid input, and ``CONFIG_SCHEMA`` itself.
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
from github_security_report.categories import (
|
|
12
|
+
EXCLUDABLE_CATEGORIES,
|
|
12
13
|
REPO_LIST_CATEGORIES,
|
|
13
14
|
CategoryMeta,
|
|
14
15
|
all_categories,
|
|
@@ -81,8 +82,9 @@ def _category_schema(meta: CategoryMeta) -> dict:
|
|
|
81
82
|
"""The schema for one category's block under ``report.categories``.
|
|
82
83
|
|
|
83
84
|
``repo_list`` is offered only to the boolean feature categories, the only
|
|
84
|
-
ones with an enabled list to name
|
|
85
|
-
|
|
85
|
+
ones with an enabled list to name, and ``exclude`` only to the categories
|
|
86
|
+
whose builders apply it: anywhere else either would validate and then do
|
|
87
|
+
nothing, so it is left out and the schema rejects it by name.
|
|
86
88
|
"""
|
|
87
89
|
properties: dict = {
|
|
88
90
|
"enabled": {"type": "boolean"},
|
|
@@ -110,6 +112,15 @@ def _category_schema(meta: CategoryMeta) -> dict:
|
|
|
110
112
|
}
|
|
111
113
|
if meta.key in REPO_LIST_CATEGORIES:
|
|
112
114
|
properties["repo_list"] = {"enum": REPO_LIST_VALUES}
|
|
115
|
+
if meta.key in EXCLUDABLE_CATEGORIES:
|
|
116
|
+
# Regular expressions searched against the repository name, case-
|
|
117
|
+
# insensitively; a match drops the repository from this category only
|
|
118
|
+
# and lists it on the category's Excluded footer line. The loader
|
|
119
|
+
# rejects a pattern that does not compile, which JSON Schema cannot.
|
|
120
|
+
properties["exclude"] = {
|
|
121
|
+
"type": "array",
|
|
122
|
+
"items": {"type": "string", "minLength": 1},
|
|
123
|
+
}
|
|
113
124
|
return {"type": "object", "additionalProperties": False, "properties": properties}
|
|
114
125
|
|
|
115
126
|
|
|
@@ -59,11 +59,11 @@ class OrgReport:
|
|
|
59
59
|
# organisation's baseline: every category reports it unless
|
|
60
60
|
# ``category_excluded`` gives that category a list of its own.
|
|
61
61
|
excluded_repos: list[Repo] = field(default_factory=list)
|
|
62
|
-
# Exclusions for a category that differ from the organisation baseline
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
62
|
+
# Exclusions for a category that differ from the organisation baseline:
|
|
63
|
+
# the baseline plus the repositories the category's own ``exclude``
|
|
64
|
+
# patterns dropped (see ``categories.EXCLUDABLE_CATEGORIES``). Absent keys
|
|
65
|
+
# inherit ``excluded_repos``. This is what the conditional-hide footer
|
|
66
|
+
# setting compares against the baseline.
|
|
67
67
|
category_excluded: dict[CategoryKey, list[Repo]] = field(default_factory=dict)
|
|
68
68
|
# Extra Dependabot posture tables rendered as sub-sections beneath the
|
|
69
69
|
# Dependabot signal heading (alerts not enabled, security updates not
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.22.0 → github_security_report-0.23.0}/src/github_security_report/gating.py
RENAMED
|
File without changes
|
{github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/gitctx.py
RENAMED
|
File without changes
|
|
File without changes
|
{github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/issues.py
RENAMED
|
File without changes
|
{github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/layout.py
RENAMED
|
File without changes
|
|
File without changes
|
{github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.22.0 → github_security_report-0.23.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.22.0 → github_security_report-0.23.0}/src/github_security_report/runner.py
RENAMED
|
File without changes
|
{github_security_report-0.22.0 → github_security_report-0.23.0}/src/github_security_report/scope.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|