github-security-report 0.23.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.
Files changed (120) hide show
  1. {github_security_report-0.23.0 → github_security_report-0.23.1}/PKG-INFO +13 -4
  2. {github_security_report-0.23.0 → github_security_report-0.23.1}/README.md +10 -1
  3. {github_security_report-0.23.0 → github_security_report-0.23.1}/pyproject.toml +6 -5
  4. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/_version.py +2 -2
  5. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/modes.py +2 -2
  6. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/remediation.py +1 -1
  7. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/failures.py +1 -1
  8. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/parsers.py +2 -2
  9. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/codeql/cleanup.py +11 -2
  10. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/codeql/facts.py +20 -4
  11. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/codeql/tables.py +14 -8
  12. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/collect/run_sync.py +1 -1
  13. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/malware.py +1 -1
  14. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/posture/releases.py +1 -1
  15. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/report/aggregate.py +1 -1
  16. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/workflow_runs/store_codec.py +1 -1
  17. {github_security_report-0.23.0 → github_security_report-0.23.1}/.gitignore +0 -0
  18. {github_security_report-0.23.0 → github_security_report-0.23.1}/LICENSE +0 -0
  19. {github_security_report-0.23.0 → github_security_report-0.23.1}/LICENSES/Apache-2.0.txt +0 -0
  20. {github_security_report-0.23.0 → github_security_report-0.23.1}/scripts/README.md +0 -0
  21. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/__init__.py +0 -0
  22. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/authors.py +0 -0
  23. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/categories/__init__.py +0 -0
  24. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/categories/keys.py +0 -0
  25. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/categories/signals.py +0 -0
  26. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/categories/tables.py +0 -0
  27. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/classify.py +0 -0
  28. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/__init__.py +0 -0
  29. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/__main__.py +0 -0
  30. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/app.py +0 -0
  31. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/boundary.py +0 -0
  32. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/options.py +0 -0
  33. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/outputs.py +0 -0
  34. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/progress.py +0 -0
  35. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/publish.py +0 -0
  36. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/serialise.py +0 -0
  37. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/cli/summary.py +0 -0
  38. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/__init__.py +0 -0
  39. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/accounting.py +0 -0
  40. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/alerts.py +0 -0
  41. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/analyses.py +0 -0
  42. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/batch_errors.py +0 -0
  43. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/codeql_parsers.py +0 -0
  44. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/copilot.py +0 -0
  45. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/endpoints.py +0 -0
  46. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/errors.py +0 -0
  47. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/events.py +0 -0
  48. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/org_reads.py +0 -0
  49. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/paging.py +0 -0
  50. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/queries.py +0 -0
  51. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/reads.py +0 -0
  52. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/repo_parser.py +0 -0
  53. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/reviews.py +0 -0
  54. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/transport.py +0 -0
  55. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/workflow_runs.py +0 -0
  56. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/client/writes.py +0 -0
  57. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/code_quality.py +0 -0
  58. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/codeql/__init__.py +0 -0
  59. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/collect/__init__.py +0 -0
  60. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/collect/codeql.py +0 -0
  61. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/collect/context.py +0 -0
  62. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/collect/extras.py +0 -0
  63. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/collect/graph.py +0 -0
  64. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/collect/org.py +0 -0
  65. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/collect/protocols.py +0 -0
  66. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/collect/repo.py +0 -0
  67. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/collect/scoping.py +0 -0
  68. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/collect/workflow_runs.py +0 -0
  69. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/config/__init__.py +0 -0
  70. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/config/blocks.py +0 -0
  71. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/config/loader.py +0 -0
  72. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/config/models.py +0 -0
  73. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/config/order.py +0 -0
  74. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/config/schema.py +0 -0
  75. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/gating.py +0 -0
  76. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/gitctx.py +0 -0
  77. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/issue_presentation.py +0 -0
  78. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/issues.py +0 -0
  79. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/layout.py +0 -0
  80. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/models.py +0 -0
  81. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/ordering.py +0 -0
  82. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/posture/__init__.py +0 -0
  83. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/posture/enablement.py +0 -0
  84. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/posture/facts.py +0 -0
  85. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/posture/quality.py +0 -0
  86. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/pulls/__init__.py +0 -0
  87. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/pulls/columns.py +0 -0
  88. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/pulls/counting.py +0 -0
  89. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/pulls/presentation.py +0 -0
  90. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/pulls/table.py +0 -0
  91. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/py.typed +0 -0
  92. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/ranking.py +0 -0
  93. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/remediate/__init__.py +0 -0
  94. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/remediate/codeql.py +0 -0
  95. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/remediate/model.py +0 -0
  96. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/render/__init__.py +0 -0
  97. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/render/html.py +0 -0
  98. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/render/markdown.py +0 -0
  99. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/render/slack.py +0 -0
  100. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/render/slack_limits.py +0 -0
  101. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/render/slack_text.py +0 -0
  102. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/render/terminal.py +0 -0
  103. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/render/terminal_notices.py +0 -0
  104. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/report/__init__.py +0 -0
  105. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/report/display.py +0 -0
  106. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/report/signals.py +0 -0
  107. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/report/tables.py +0 -0
  108. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/rulesets.py +0 -0
  109. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/runner.py +0 -0
  110. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/scope.py +0 -0
  111. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/secret_patterns.py +0 -0
  112. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/severity.py +0 -0
  113. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/summary.py +0 -0
  114. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/templates/index.html.j2 +0 -0
  115. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/templates/report.html.j2 +0 -0
  116. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/workflow_runs/__init__.py +0 -0
  117. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/workflow_runs/aggregate.py +0 -0
  118. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/workflow_runs/models.py +0 -0
  119. {github_security_report-0.23.0 → github_security_report-0.23.1}/src/github_security_report/workflow_runs/store.py +0 -0
  120. {github_security_report-0.23.0 → github_security_report-0.23.1}/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.23.0
3
+ Version: 0.23.1
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
@@ -15,15 +15,15 @@ Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python
16
16
  Classifier: Programming Language :: Python :: 3
17
17
  Classifier: Programming Language :: Python :: 3 :: Only
18
- Classifier: Programming Language :: Python :: 3.10
19
18
  Classifier: Programming Language :: Python :: 3.11
20
19
  Classifier: Programming Language :: Python :: 3.12
21
20
  Classifier: Programming Language :: Python :: 3.13
22
21
  Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Programming Language :: Python :: 3.15
23
23
  Classifier: Topic :: Security
24
24
  Classifier: Topic :: Software Development :: Quality Assurance
25
25
  Classifier: Typing :: Typed
26
- Requires-Python: >=3.10
26
+ Requires-Python: >=3.11
27
27
  Requires-Dist: httpx[http2]==0.28.1
28
28
  Requires-Dist: jinja2==3.1.6
29
29
  Requires-Dist: jsonschema==4.26.0
@@ -2128,6 +2128,13 @@ cause:
2128
2128
 
2129
2129
  <!-- markdownlint-enable MD013 -->
2130
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
+
2131
2138
  Deleting removes a configuration's analyses, which clears GitHub's *"Code
2132
2139
  Scanning results may be out of date"* warning but also removes its alert
2133
2140
  history. A deletion is therefore **refused**, in a dry run as in an apply,
@@ -2135,7 +2142,9 @@ when:
2135
2142
 
2136
2143
  - no current configuration scans its language: the stale results are then
2137
2144
  the only record of it, so add scanning for the language first (the refusal
2138
- 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;
2139
2148
  - it would help close an open alert. This is judged across **every deletion
2140
2149
  planned in the repository**, not one at a time: an alert held by two stale
2141
2150
  configurations would close if both went, so both are refused, although
@@ -2084,6 +2084,13 @@ cause:
2084
2084
 
2085
2085
  <!-- markdownlint-enable MD013 -->
2086
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
+
2087
2094
  Deleting removes a configuration's analyses, which clears GitHub's *"Code
2088
2095
  Scanning results may be out of date"* warning but also removes its alert
2089
2096
  history. A deletion is therefore **refused**, in a dry run as in an apply,
@@ -2091,7 +2098,9 @@ when:
2091
2098
 
2092
2099
  - no current configuration scans its language: the stale results are then
2093
2100
  the only record of it, so add scanning for the language first (the refusal
2094
- 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;
2095
2104
  - it would help close an open alert. This is judged across **every deletion
2096
2105
  planned in the repository**, not one at a time: an alert held by two stale
2097
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.10"
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.10"
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.10"
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 = "py310"
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.23.0'
22
- __version_tuple__ = version_tuple = (0, 23, 0)
21
+ __version__ = version = '0.23.1'
22
+ __version_tuple__ = version_tuple = (0, 23, 1)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -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.timezone.utc)
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.timezone.utc)
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.timezone.utc)
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.
@@ -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 asyncio.TimeoutError:
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.timezone.utc)
69
- return max(0.0, (when - dt.datetime.now(dt.timezone.utc)).total_seconds())
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. Whether a deletion would close an open alert needs a network read,
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 config.language is None or config.language not in current:
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
- _ORPHANED_CAUSES = frozenset(
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.timezone.utc)
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 comes first: the setup still exists and still
139
- runs, so whatever its state, the reader's next step is its failing logs.
140
- ``stale_days`` is the threshold the configuration was found stale by,
141
- which also decides whether another configuration is current.
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
- return _default_setup_cause(config, facts)
147
- return _advanced_setup_cause(config, facts, stale_days)
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(
@@ -89,7 +89,7 @@ class RepoRunSync:
89
89
 
90
90
  def _date(when: dt.datetime) -> str:
91
91
  """The calendar date GitHub's ``created`` filter takes."""
92
- return when.astimezone(dt.timezone.utc).date().isoformat()
92
+ return when.astimezone(dt.UTC).date().isoformat()
93
93
 
94
94
 
95
95
  def _merge(
@@ -72,7 +72,7 @@ def _age_days(value: object, now: dt.datetime) -> int | None:
72
72
  except ValueError:
73
73
  return None
74
74
  if when.tzinfo is None:
75
- when = when.replace(tzinfo=dt.timezone.utc)
75
+ when = when.replace(tzinfo=dt.UTC)
76
76
  return max((now - when).days, 0)
77
77
 
78
78
 
@@ -18,7 +18,7 @@ from github_security_report.report import TableRow, TableSection
18
18
 
19
19
  # Aware sentinel so releases lacking a publish timestamp sort oldest (last) when
20
20
  # ordering most-recent-first, without ever comparing a naive and aware value.
21
- _MIN_AWARE = dt.datetime.min.replace(tzinfo=dt.timezone.utc)
21
+ _MIN_AWARE = dt.datetime.min.replace(tzinfo=dt.UTC)
22
22
 
23
23
 
24
24
  def _age_days(when: dt.datetime | None, now: dt.datetime) -> int | None:
@@ -225,7 +225,7 @@ def build_org_report(
225
225
  because organisation feature gating found no supporting workflows; such a
226
226
  section renders as a single skip line on every surface.
227
227
  """
228
- when = generated_at or dt.datetime.now(dt.timezone.utc)
228
+ when = generated_at or dt.datetime.now(dt.UTC)
229
229
  by_signal: dict[SignalType, list[RepoSignal]] = {s: [] for s in SIGNAL_ORDER}
230
230
  for sig in repo_signals:
231
231
  by_signal.setdefault(sig.signal, []).append(sig)
@@ -33,7 +33,7 @@ def _encode_datetime(value: dt.datetime) -> str:
33
33
  """
34
34
  if value.tzinfo is None or value.utcoffset() is None:
35
35
  raise ValueError(f"datetime {value!r} must be timezone-aware")
36
- return value.astimezone(dt.timezone.utc).isoformat(timespec="microseconds")
36
+ return value.astimezone(dt.UTC).isoformat(timespec="microseconds")
37
37
 
38
38
 
39
39
  def _decode_datetime(text: str | None) -> dt.datetime | None: