ghcr-cleanup-manager 1.1.0

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 (152) hide show
  1. package/CHANGELOG.md +356 -0
  2. package/LICENSE +21 -0
  3. package/README.md +262 -0
  4. package/dist/cleanup-summary/_cleanup-summary-markdown.d.ts +5 -0
  5. package/dist/cleanup-summary/_cleanup-summary-markdown.js +224 -0
  6. package/dist/cleanup-summary/_cleanup-summary.d.ts +56 -0
  7. package/dist/cleanup-summary/_cleanup-summary.js +59 -0
  8. package/dist/cleanup-summary/index.d.ts +2 -0
  9. package/dist/cleanup-summary/index.js +2 -0
  10. package/dist/cli/_args.d.ts +7 -0
  11. package/dist/cli/_args.js +41 -0
  12. package/dist/cli/_cleanup-command.d.ts +1 -0
  13. package/dist/cli/_cleanup-command.js +142 -0
  14. package/dist/cli/_db-merge-command.d.ts +1 -0
  15. package/dist/cli/_db-merge-command.js +41 -0
  16. package/dist/cli/_github-output.d.ts +10 -0
  17. package/dist/cli/_github-output.js +13 -0
  18. package/dist/cli/_json-output.d.ts +1 -0
  19. package/dist/cli/_json-output.js +11 -0
  20. package/dist/cli/_logger.d.ts +10 -0
  21. package/dist/cli/_logger.js +26 -0
  22. package/dist/cli/_older-than.d.ts +5 -0
  23. package/dist/cli/_older-than.js +42 -0
  24. package/dist/cli/_planner-options.d.ts +20 -0
  25. package/dist/cli/_planner-options.js +83 -0
  26. package/dist/cli/_scan-command.d.ts +1 -0
  27. package/dist/cli/_scan-command.js +39 -0
  28. package/dist/cli/_tag-selector-resolver.d.ts +3 -0
  29. package/dist/cli/_tag-selector-resolver.js +132 -0
  30. package/dist/cli/index.d.ts +2 -0
  31. package/dist/cli/index.js +52 -0
  32. package/dist/config/_service-constants.d.ts +3 -0
  33. package/dist/config/_service-constants.js +3 -0
  34. package/dist/config/index.d.ts +9 -0
  35. package/dist/config/index.js +9 -0
  36. package/dist/core/_digest-tag.d.ts +2 -0
  37. package/dist/core/_digest-tag.js +12 -0
  38. package/dist/core/_github-package-owner.d.ts +11 -0
  39. package/dist/core/_github-package-owner.js +45 -0
  40. package/dist/core/_http-error.d.ts +6 -0
  41. package/dist/core/_http-error.js +33 -0
  42. package/dist/core/_types.d.ts +54 -0
  43. package/dist/core/_types.js +8 -0
  44. package/dist/core/index.d.ts +6 -0
  45. package/dist/core/index.js +4 -0
  46. package/dist/db/_cleanup-run-writer.d.ts +10 -0
  47. package/dist/db/_cleanup-run-writer.js +113 -0
  48. package/dist/db/_db-merge-cleanup-copy.d.ts +7 -0
  49. package/dist/db/_db-merge-cleanup-copy.js +172 -0
  50. package/dist/db/_db-merge-history.d.ts +2 -0
  51. package/dist/db/_db-merge-history.js +15 -0
  52. package/dist/db/_db-merge-repository.d.ts +8 -0
  53. package/dist/db/_db-merge-repository.js +95 -0
  54. package/dist/db/_db-merge-scan-copy.d.ts +10 -0
  55. package/dist/db/_db-merge-scan-copy.js +70 -0
  56. package/dist/db/_db-merge-types.d.ts +44 -0
  57. package/dist/db/_db-merge-types.js +1 -0
  58. package/dist/db/_github-actions-run-url.d.ts +1 -0
  59. package/dist/db/_github-actions-run-url.js +9 -0
  60. package/dist/db/_manifest-reachability.d.ts +2 -0
  61. package/dist/db/_manifest-reachability.js +158 -0
  62. package/dist/db/_scan-writer.d.ts +20 -0
  63. package/dist/db/_scan-writer.js +184 -0
  64. package/dist/db/_schema.d.ts +2 -0
  65. package/dist/db/_schema.js +19 -0
  66. package/dist/db/_snapshot-repository.d.ts +24 -0
  67. package/dist/db/_snapshot-repository.js +86 -0
  68. package/dist/db/_sql-placeholders.d.ts +2 -0
  69. package/dist/db/_sql-placeholders.js +16 -0
  70. package/dist/db/index.d.ts +10 -0
  71. package/dist/db/index.js +13 -0
  72. package/dist/db/planner/_planner-direct-target-root-options.d.ts +11 -0
  73. package/dist/db/planner/_planner-direct-target-root-options.js +1 -0
  74. package/dist/db/planner/_planner-direct-target-root-tag-filters.d.ts +7 -0
  75. package/dist/db/planner/_planner-direct-target-root-tag-filters.js +41 -0
  76. package/dist/db/planner/_planner-direct-target-roots-combined-sql.d.ts +7 -0
  77. package/dist/db/planner/_planner-direct-target-roots-combined-sql.js +189 -0
  78. package/dist/db/planner/_planner-direct-target-roots-combined.d.ts +4 -0
  79. package/dist/db/planner/_planner-direct-target-roots-combined.js +10 -0
  80. package/dist/db/planner/_planner-direct-target-roots-tagged.d.ts +4 -0
  81. package/dist/db/planner/_planner-direct-target-roots-tagged.js +117 -0
  82. package/dist/db/planner/_planner-direct-target-roots.d.ts +8 -0
  83. package/dist/db/planner/_planner-direct-target-roots.js +17 -0
  84. package/dist/db/planner/_planner-direct-target-tags.d.ts +6 -0
  85. package/dist/db/planner/_planner-direct-target-tags.js +54 -0
  86. package/dist/db/planner/_planner-latest-scan.d.ts +10 -0
  87. package/dist/db/planner/_planner-latest-scan.js +20 -0
  88. package/dist/db/planner/_planner-output.d.ts +5 -0
  89. package/dist/db/planner/_planner-output.js +111 -0
  90. package/dist/db/planner/_planner-plan-artifacts-blocked-roots-sql.d.ts +1 -0
  91. package/dist/db/planner/_planner-plan-artifacts-blocked-roots-sql.js +110 -0
  92. package/dist/db/planner/_planner-plan-artifacts-closure-sql.d.ts +1 -0
  93. package/dist/db/planner/_planner-plan-artifacts-closure-sql.js +188 -0
  94. package/dist/db/planner/_planner-plan-artifacts-supported-untag-only-sql.d.ts +1 -0
  95. package/dist/db/planner/_planner-plan-artifacts-supported-untag-only-sql.js +86 -0
  96. package/dist/db/planner/_planner-plan-artifacts.d.ts +7 -0
  97. package/dist/db/planner/_planner-plan-artifacts.js +109 -0
  98. package/dist/db/planner/_planner-repository.d.ts +44 -0
  99. package/dist/db/planner/_planner-repository.js +105 -0
  100. package/dist/db/planner/_planner-sql.d.ts +12 -0
  101. package/dist/db/planner/_planner-sql.js +46 -0
  102. package/dist/db/planner/_planner-tag-selectors.d.ts +8 -0
  103. package/dist/db/planner/_planner-tag-selectors.js +57 -0
  104. package/dist/db/planner/_planner-types.d.ts +144 -0
  105. package/dist/db/planner/_planner-types.js +49 -0
  106. package/dist/db/planner/index.d.ts +3 -0
  107. package/dist/db/planner/index.js +2 -0
  108. package/dist/execute/_http.d.ts +7 -0
  109. package/dist/execute/_http.js +48 -0
  110. package/dist/execute/_manifest-detach.d.ts +4 -0
  111. package/dist/execute/_manifest-detach.js +31 -0
  112. package/dist/execute/_package-version-delete-client.d.ts +4 -0
  113. package/dist/execute/_package-version-delete-client.js +34 -0
  114. package/dist/execute/_package-version-page-client.d.ts +14 -0
  115. package/dist/execute/_package-version-page-client.js +64 -0
  116. package/dist/execute/_package-version-tag-source-client.d.ts +12 -0
  117. package/dist/execute/_package-version-tag-source-client.js +65 -0
  118. package/dist/execute/_plan-executor.d.ts +3 -0
  119. package/dist/execute/_plan-executor.js +69 -0
  120. package/dist/execute/_registry-manifest-client.d.ts +12 -0
  121. package/dist/execute/_registry-manifest-client.js +79 -0
  122. package/dist/execute/_registry-token-client.d.ts +4 -0
  123. package/dist/execute/_registry-token-client.js +37 -0
  124. package/dist/execute/_types.d.ts +34 -0
  125. package/dist/execute/_types.js +1 -0
  126. package/dist/execute/_untag-client.d.ts +2 -0
  127. package/dist/execute/_untag-client.js +30 -0
  128. package/dist/execute/index.d.ts +5 -0
  129. package/dist/execute/index.js +3 -0
  130. package/dist/ingest/github/_manifest-client.d.ts +14 -0
  131. package/dist/ingest/github/_manifest-client.js +108 -0
  132. package/dist/ingest/github/_manifest-ingest.d.ts +3 -0
  133. package/dist/ingest/github/_manifest-ingest.js +90 -0
  134. package/dist/ingest/github/_manifest-kind.d.ts +26 -0
  135. package/dist/ingest/github/_manifest-kind.js +65 -0
  136. package/dist/ingest/github/_package-metadata-load.d.ts +5 -0
  137. package/dist/ingest/github/_package-metadata-load.js +45 -0
  138. package/dist/ingest/github/_package-version-page-load.d.ts +13 -0
  139. package/dist/ingest/github/_package-version-page-load.js +55 -0
  140. package/dist/ingest/github/_packages-client.d.ts +10 -0
  141. package/dist/ingest/github/_packages-client.js +76 -0
  142. package/dist/ingest/github/_parallel-paginated-ingest.d.ts +12 -0
  143. package/dist/ingest/github/_parallel-paginated-ingest.js +49 -0
  144. package/dist/ingest/github/_registry-token-client.d.ts +6 -0
  145. package/dist/ingest/github/_registry-token-client.js +67 -0
  146. package/dist/ingest/github/_shared.d.ts +28 -0
  147. package/dist/ingest/github/_shared.js +70 -0
  148. package/dist/ingest/github/index.d.ts +11 -0
  149. package/dist/ingest/github/index.js +29 -0
  150. package/package.json +78 -0
  151. package/resources/sql/schema/001_schema.sql +222 -0
  152. package/resources/sql/views/001_v_latest_scan_per_package.sql +27 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,356 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
6
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [v1.1.0] - 2026-06-14
11
+
12
+ ### Changed
13
+
14
+ - Renamed the project from ghcr-manager to ghcr-cleanup-manager because the old repo name was not showing up in GitHub
15
+ Marketplace searches for "ghcr clean" and "ghcr cleanup".
16
+ - Kept the current behavior unchanged for this release; this version is intended as the first release under the new
17
+ name.
18
+
19
+ ## [v1.0.8] - 2026-06-11
20
+
21
+ ### Changed
22
+
23
+ - Marketplace-facing action metadata and README opening copy now lead more directly with GHCR cleanup terminology.
24
+ - User-facing docs and related metadata now use the product name `GHCR Cleanup Manager` more consistently.
25
+ - The main README's visualizer demo section now also points to Docker-based visualizer usage.
26
+
27
+ ## [v1.0.7] - 2026-06-08
28
+
29
+ ### Added
30
+
31
+ - Added a release-published Docker image for `ghcr-cleanup-manager-visualizer` on GHCR, tagged as `vX.Y.Z`, `vX`, and
32
+ `latest`.
33
+
34
+ ### Changed
35
+
36
+ - The visualizer release image now defaults to container-friendly startup behavior and is smoke-tested through the real
37
+ server entrypoint during release publishing.
38
+
39
+ ### Fixed
40
+
41
+ - Cleanup now blocks selected `sha-tag` helper roots when they still point into retained manifests, so signature helper
42
+ artifacts needed by surviving images are no longer deleted as ordinary untagged roots.
43
+ - `exclude-tags` in cleanup is now tag-scoped instead of root-scoped, so excluding one sibling tag no longer silently
44
+ protects the whole root from partial untagging.
45
+
46
+ ## [v1.0.6] - 2026-06-07
47
+
48
+ ### Fixed
49
+
50
+ - Fixed the published `ghcr-cleanup-manager-visualizer` npm package so the visualizer UI loads correctly when run via
51
+ `npx ghcr-cleanup-manager-visualizer`.
52
+
53
+ ## [v1.0.5] - 2026-06-07
54
+
55
+ ### Fixed
56
+
57
+ - Fixed the published `ghcr-cleanup-manager-visualizer` npm package so `npx ghcr-cleanup-manager-visualizer` starts the
58
+ visualizer server correctly.
59
+
60
+ ## [v1.0.4] - 2026-06-06
61
+
62
+ ### Added
63
+
64
+ - Added user-facing cleanup behavior documentation, including the tag-based protection model, graph-aware cleanup
65
+ explanation, and digest-pull caveats.
66
+ - Added a visualizer grid toggle so graphs can be aligned for screenshots.
67
+
68
+ ### Changed
69
+
70
+ - Visualizer screenshots and graph-related docs were refreshed.
71
+ - The visualizer graph area now uses a simpler, cleaner white background.
72
+ - Cleanup summary Markdown now uses an updated index icon label in its rendered output.
73
+
74
+ ### Fixed
75
+
76
+ - Fixed the published `ghcr-cleanup-manager-visualizer` npm package so `npx ghcr-cleanup-manager-visualizer` runs
77
+ correctly under Node.
78
+
79
+ ## [v1.0.3] - 2026-06-05
80
+
81
+ ### Changed
82
+
83
+ - Added npm package keywords for both `ghcr-cleanup-manager` and `ghcr-cleanup-manager-visualizer` to improve package
84
+ discovery.
85
+
86
+ ## [v1.0.2] - 2026-06-05
87
+
88
+ ### Fixed
89
+
90
+ - Visualizer compare mode now prefers the older/base scan for manifest details and labels, so unchanged manifests keep
91
+ platform metadata such as `arch:` even when the newer scan no longer has the descriptor context.
92
+
93
+ ## [v1.0.1] - 2026-06-05
94
+
95
+ ### Fixed
96
+
97
+ - The GitHub release job now grants correct permissions.
98
+
99
+ ## [v1.0.0] - 2026-06-05
100
+
101
+ `v1.0.0` is the first stable `v1.x` release of `ghcr-cleanup-manager`.
102
+
103
+ This milestone reflects the current project shape after repeated live testing, cleanup-planner tuning, visualizer
104
+ refinement, and a full documentation pass.
105
+
106
+ ### Added
107
+
108
+ - Added one merged graph-scenario SQLite database to the GitHub release assets as
109
+ `ghcr-cleanup-manager-release-scenarios.sqlite`, so users can explore real before/after cleanup cases immediately in
110
+ the visualizer.
111
+ - Added dedicated user docs for live test scenarios, package setup, and the workflow-to-visualizer path.
112
+
113
+ ### Changed
114
+
115
+ - The release workflow now builds and attaches the merged scenario DB as part of the GitHub release publish flow.
116
+ - Visualizer docs are now centered on one canonical `visualizer/README.md`, with richer screenshots and a release-asset
117
+ quick-demo path.
118
+ - README and companion docs now explain the stable action/CLI/visualizer workflows more directly, including permission
119
+ guidance for dry-runs versus live cleanup and explicit Node.js 24 requirements for local npm installs.
120
+ - Visualizer node labeling was clarified so manifest metadata is easier to interpret during graph inspection.
121
+
122
+ ## [0.9.10] - 2026-06-04
123
+
124
+ ### Changed
125
+
126
+ - Cleanup planning for large package databases is much faster while preserving the existing cleanup behavior.
127
+ - On a large validation package with more than 100k manifests, dry-run planning and summary generation dropped from more
128
+ than 20 minutes to roughly 15 seconds.
129
+
130
+ ### Fixed
131
+
132
+ - Internal GHCR validation workflows now avoid GitHub's "cannot delete the last tagged version" failure mode during
133
+ temporary-tag cleanup.
134
+
135
+ ## [0.9.9] - 2026-05-30
136
+
137
+ No additional user-facing changes were introduced beyond `0.9.8`.
138
+
139
+ This version number exists because a release attempt consumed `0.9.9` on npm.org, so later publishes must continue from
140
+ a newer version.
141
+
142
+ ## [0.9.8] - 2026-06-03
143
+
144
+ ### Added
145
+
146
+ - Added dedicated graph-matrix GHCR scenarios and workflows to exercise shared-image, multi-arch, cosign, and
147
+ attestation cleanup cases in isolation.
148
+ - Added a local manifest-graph visualizer with browser UI for `ghcr-cleanup-manager` SQLite databases, including
149
+ manifest details, zoom controls, one-hop expansion, and scan-to-scan compare mode.
150
+ - Added a separately publishable npm package, `ghcr-cleanup-manager-visualizer`, plus user-facing visualizer
151
+ documentation.
152
+ - Added repo-local manual visualizer demo scripts for seeding and updating GHCR packages during graph investigation.
153
+
154
+ ### Changed
155
+
156
+ - Cleanup planning was reworked around the current graph model, including direct SQL-backed tagged/untagged root
157
+ selection, graph-scoped closure walking, and refined `untag-only` vs `fully-deletable` decisions for complex
158
+ multi-arch, cosign, and attestation shapes.
159
+ - Large planner SQL bodies were split into smaller internal modules, and direct-target root selection logic was split
160
+ into smaller planner helpers.
161
+ - Orphaned digest-tag resolution now uses a direct latest-scan query instead of relying on older helper views.
162
+ - Manifest platform display now derives from descriptor data in the visualizer instead of relying on manifest-level
163
+ platform fields.
164
+ - Cross-architecture terminology is now consistently named `multi-arch` across runtime, tests, and docs.
165
+ - The root action and public CLI surface are now centered on `scan` and `cleanup` only.
166
+
167
+ ### Fixed
168
+
169
+ - Fixed digest-tag helper-edge direction and root-detection behavior so helper-tagged artifacts no longer interfere with
170
+ normal cleanup root semantics.
171
+ - Fixed shared-graph cleanup handling so selected indexes and helper-linked artifacts are deleted or retained according
172
+ to surviving real tags instead of simplistic descendant-only closure rules.
173
+
174
+ ### Removed
175
+
176
+ - The public `untag` CLI command, root-action mode, and dedicated direct-untag workflow coverage were removed. Internal
177
+ tag detachment for partial-tag cleanup matches remains part of `cleanup`.
178
+ - Several older cleanup helper views were removed after the planner rewrite moved the live logic into direct SQL query
179
+ paths.
180
+
181
+ ## [0.9.7] - 2026-05-23
182
+
183
+ ### Added
184
+
185
+ - The root action now prepares `cleanup` and `untag` CLI arguments through `tools/prepare-action-args.mjs`, keeping
186
+ printed and executed argument lists aligned.
187
+ - Cleanup planning now traverses recursively beyond `sha256-*` helper-tag manifest links as well, if deeper helper
188
+ chains ever occur.
189
+
190
+ ### Changed
191
+
192
+ - Cleanup dry-run output and GitHub step summaries were reworked to explain the plan more clearly, including a filters
193
+ table and clearer counts for tags, images, and cross-arch manifests.
194
+ - Informational manifest classification was tuned so only real multi-arch roots are labeled `multi_arch_manifest`, while
195
+ helper-tagged indexes remain `index_manifest`.
196
+ - `merge-run-artifacts` now uses a simpler current-run download flow with direct artifact download handling.
197
+ - Cleanup selected-tag audit and DB-merge metadata handling were tightened alongside the summary/output refactor.
198
+
199
+ ### Fixed
200
+
201
+ - `delete-orphaned-images` now carries orphaned `sha256-*` digest-tag targets through planner selection instead of
202
+ dropping them at the normal non-digest tag boundary.
203
+ - Fully deletable cleanup execution now deletes the planned closure package versions instead of deleting only the root
204
+ package version.
205
+
206
+ ## [0.9.6] - 2026-05-21
207
+
208
+ ### Added
209
+
210
+ - Cleanup audit now persists concrete selected tags in `cleanup_selected_tags`.
211
+ - Cleanup schema docs now include a readable cleanup-decision view plus example SQL queries for audit inspection.
212
+ - GHCR digest-tag helper relations are now modeled explicitly in scan data and manifest reachability.
213
+
214
+ ### Changed
215
+
216
+ - Cleanup summary JSON now exposes derived affected manifests for fully deletable roots.
217
+ - Cleanup Markdown now reads displayed counts from the summary arrays instead of carrying duplicate count fields.
218
+ - Cleanup decision audit fields are now constrained more tightly in SQLite and TypeScript, including `selection_mode`,
219
+ `selection_reason`, and related block reason codes.
220
+ - Digest-tag helper artifacts are now classified on `tags.is_digest_tag` and excluded from normal user-facing tag
221
+ selection and output.
222
+ - Digest-tag helper terminology was simplified across code and SQL surfaces.
223
+ - Schema docs now include a table of contents and collapsible example query blocks for easier GitHub browsing.
224
+
225
+ ### Fixed
226
+
227
+ - Fixed remote action path handling for artifact upload and merge helper actions.
228
+ - Cleanup reachability now follows digest-tag helper edges recursively, matching helper-artifact cascades more closely.
229
+
230
+ ## [0.9.5] - 2026-05-21
231
+
232
+ ### Changed
233
+
234
+ - Renamed `upload-db-artifact` to `upload-artifacts`.
235
+ - Raised cleanup summary defaults to 100 matched tags and 100 roots per section.
236
+
237
+ ## [0.9.4] - 2026-05-21
238
+
239
+ ### Changed
240
+
241
+ - The root action now exposes `summary-json-path` instead of `summary-json`, so command summaries are consumed by file
242
+ path rather than as a large action output payload.
243
+
244
+ ### Fixed
245
+
246
+ - The GitHub Action now passes cleanup and untag summary JSON between steps by file path instead of large environment
247
+ payloads, avoiding GitHub template-memory and argument-length failures on large cleanup runs.
248
+
249
+ ## [0.9.3] - 2026-05-21
250
+
251
+ ### Changed
252
+
253
+ - Cleanup selector planning now composes tagged and untagged selector families in one SQL-backed planner path.
254
+ - Cleanup CLI help and docs now describe the composed selector model, including tagged selectors combined with
255
+ `delete-untagged`.
256
+
257
+ ### Fixed
258
+
259
+ - `exclude-tag` now works correctly when a tagged selector family is combined with `delete-untagged`.
260
+
261
+ ## [0.9.2] - 2026-05-21
262
+
263
+ ### Changed
264
+
265
+ - The action input is now `token`, and the repo now uses `GITHUB_TOKEN` consistently in docs and helper scripts.
266
+
267
+ ## [0.9.1] - 2026-05-21
268
+
269
+ ### Fixed
270
+
271
+ - The GitHub Action now installs, builds, and runs from its own checkout path instead of the caller repository path.
272
+
273
+ ## [0.9.0] - 2026-05-21
274
+
275
+ `0.9.0` is the first stable pre-`1.0` release of `ghcr-cleanup-manager`.
276
+
277
+ ### Added
278
+
279
+ - `cleanup` as the main GHCR maintenance flow for both the GitHub Action and the companion CLI.
280
+ - `untag` as a direct tag-removal mode that works without a scan database.
281
+ - `db-merge` and `merge-run-artifacts` support for combining scan databases across packages and workflow runs.
282
+ - Support for both organization-owned and user-owned GitHub Container Registry packages.
283
+ - Cleanup summary JSON output plus GitHub step summary rendering for action runs.
284
+ - Broad live and scenario-based workflow coverage for cleanup, untag, and cross-owner behavior.
285
+ - User-facing documentation for action usage, CLI usage, DB merge workflows, schema orientation, and SQL recipes.
286
+
287
+ ### Changed
288
+
289
+ - The GitHub Action now builds and runs the repo-local CLI directly instead of installing `ghcr-cleanup-manager` from
290
+ npm at runtime.
291
+ - The primary maintenance surface is now `cleanup` with `dry-run` semantics, with `scan` and `untag` as supporting
292
+ command modes.
293
+ - The action input and artifact flow were refined around scan databases, cleanup summaries, and optional post-cleanup
294
+ rescan behavior.
295
+ - Documentation was reorganized around action-first usage, with deeper companion docs for CLI and database workflows.
296
+ - Release validation and workflow gating were tightened around exact version references, changelog readiness, and live
297
+ scenario checks.
298
+
299
+ ### Removed
300
+
301
+ - Built-in database artifact encryption and decryption support.
302
+
303
+ ### Fixed
304
+
305
+ - Digest-selector scenario handling and related workflow wiring for `ghcr-cleanup-manager`.
306
+ - Latest-scan based verification for cleanup and untag test flows.
307
+ - User-owner cleanup workflow behavior and related test setup details.
308
+ - Numerous workflow, artifact-handling, and planner-audit edge cases discovered during pre-release hardening.
309
+
310
+ ## [0.0.6] - 2026-04-30
311
+
312
+ ### Changed
313
+
314
+ - Internal workflow/debug wiring.
315
+
316
+ ## [0.0.5] - 2026-04-30
317
+
318
+ ### Changed
319
+
320
+ - Publish to npmjs by trusted publisher
321
+
322
+ ## [0.0.4] - 2026-04-30
323
+
324
+ ### Changed
325
+
326
+ - Publish to npmjs
327
+
328
+ ## [0.0.3] - 2026-04-30
329
+
330
+ ### Changed
331
+
332
+ - Released on GitHub marketplace as public action
333
+
334
+ ## [0.0.1] - 2026-04-30
335
+
336
+ ### Added
337
+
338
+ - Initial public release of `ghcr-cleanup-manager` as a GitHub Action plus companion CLI.
339
+ - GHCR scan flow that loads package versions, tags, manifests, descriptors, and manifest graph edges into SQLite.
340
+ - Manifest reachability precomputation (`manifest_reachability`) for fast graph-based analysis queries.
341
+ - Raw payload storage for GitHub package-version items and GHCR manifests (`package_version_payloads`,
342
+ `manifest_payloads`).
343
+ - Scan lifecycle tracking with scan history (`package_scans`) and status transitions (`running|completed|failed`).
344
+ - Immutable per-scan UUID (`package_scans.scan_uuid`) for robust duplicate detection across merged databases.
345
+ - Optional action artifact upload for scan DB export (`upload-db-artifact`, optional retention override).
346
+ - Manual workflow for interactive scan runs (`.github/workflows/manual-run.yml`).
347
+ - Missing-manifest investigation SQL recipes (`docs/queries/missing-manifests-queries.md`) and schema/terminology docs.
348
+
349
+ ### Changed
350
+
351
+ - Enforced stricter repository conventions:
352
+ - source/test tree mirroring
353
+ - cross-folder imports via folder `index.ts`
354
+ - internal source naming (`_*.ts`)
355
+ - Hardened CI/workflows with explicit token permissions and immutable action reference checks.
356
+ - Refined action/runtime flow to focus on scan + DB export behavior for this release.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stefan Kuhn
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,262 @@
1
+ # GHCR Cleanup Manager
2
+
3
+ [![GitHub Marketplace](https://img.shields.io/badge/marketplace-ghcr--cleanup--manager-blue?logo=github&labelColor=333&style=flat-square)](https://github.com/marketplace/actions/ghcr-manager)
4
+ [![Release](https://img.shields.io/github/v/release/ghcr-manager/ghcr-cleanup-manager?style=flat-square)](https://github.com/ghcr-manager/ghcr-cleanup-manager/releases)
5
+ [![Immutable Releases](https://img.shields.io/badge/releases-immutable-blue?labelColor=333)](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/immutable-releases)
6
+ [![Tests](https://img.shields.io/github/actions/workflow/status/ghcr-manager/ghcr-cleanup-manager/.github/workflows/ci_change-validation.yml?branch=main&label=test&style=flat-square)](https://github.com/ghcr-manager/ghcr-cleanup-manager/actions/workflows/ci_change-validation.yml)
7
+
8
+ GHCR Cleanup Manager is a GHCR cleanup action for GitHub Container Registry packages.
9
+
10
+ GHCR Cleanup Manager is a GitHub Action for:
11
+
12
+ - clean GHCR packages: including tagged and untagged images
13
+ - preview cleanup: with `dry-run` before making changes
14
+ - scan GHCR packages: into SQLite database artifacts
15
+ - visualize GHCR package graphs: and their changes with the
16
+ [ghcr-cleanup-manager-visualizer](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/visualizer/README.md)
17
+
18
+ It is built for safe GHCR cleanup on real OCI package graphs, including multi-arch images, attestations, cosign
19
+ signatures, and other referrers that simpler GHCR cleanup actions often mishandle.
20
+
21
+ [![Example compare view: red-bordered manifests are present in the older scan and removed in the newer one.](https://raw.githubusercontent.com/ghcr-manager/ghcr-cleanup-manager/main/docs/images/visualizer/graph-2images-cosign--wide.png "Example compare view: red-bordered manifests are present in the older scan and removed in the newer one.")](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/docs/images/visualizer/graph-2images-cosign--wide.png)
22
+
23
+ _Example graph compare view: red-bordered manifests are present in the older scan and removed in the newer one._
24
+
25
+ ## Quick Start
26
+
27
+ For a first run, start with `cleanup` in `dry-run` mode.
28
+
29
+ ```yaml
30
+ jobs:
31
+ cleanup:
32
+ runs-on: ubuntu-latest
33
+ permissions:
34
+ contents: read
35
+ packages: read
36
+ actions: write
37
+ concurrency:
38
+ group: ghcr-cleanup-manager__OWNER__PACKAGE
39
+ steps:
40
+ - uses: actions/checkout@v6
41
+
42
+ - name: Preview GHCR cleanup
43
+ id: ghcr-cleanup-manager
44
+ uses: ghcr-manager/ghcr-cleanup-manager@v1.1.0
45
+ with:
46
+ command: cleanup
47
+ token: ${{ github.token }}
48
+ owner: OWNER
49
+ package: PACKAGE
50
+ dry-run: true
51
+ delete-untagged: true
52
+ keep-n-tagged: "10"
53
+ exclude-tags: |
54
+ latest
55
+ upload-artifacts: true
56
+ ```
57
+
58
+ > Permission notes:
59
+ >
60
+ > - `scan` and `cleanup` dry-runs need `packages: read`
61
+ > - live `cleanup` that mutates GHCR needs `packages: write`
62
+ > - artifact upload needs `actions: write`
63
+
64
+ After the run:
65
+
66
+ 1. Open the GitHub step summary for the action run.
67
+ 2. Review which tags matched and which roots would be deleted, untagged, or blocked.
68
+ 3. Only download the DB artifact if you need deeper inspection.
69
+
70
+ ## Commands
71
+
72
+ The action supports two commands:
73
+
74
+ - `cleanup`: Cleans using filters; use `dry-run` to preview the result
75
+ - `scan`: Scans one package and uploads the resulting DB artifact
76
+
77
+ ### Purpose of commands
78
+
79
+ - `cleanup`: Normal entry point for registry maintenance
80
+ - `scan`: For investigation and audit
81
+
82
+ ## Common Usage
83
+
84
+ ### Preview cleanup
85
+
86
+ ```yaml
87
+ - uses: ghcr-manager/ghcr-cleanup-manager@v1.1.0
88
+ with:
89
+ command: cleanup
90
+ token: ${{ github.token }}
91
+ owner: OWNER
92
+ package: PACKAGE
93
+ dry-run: true
94
+ delete-tags: |
95
+ pr-.*
96
+ use-regex: true
97
+ older-than: 30 days
98
+ keep-n-tagged: "5"
99
+ exclude-tags: |
100
+ latest
101
+ stable
102
+ upload-artifacts: true
103
+ ```
104
+
105
+ ### Apply cleanup
106
+
107
+ ```yaml
108
+ - uses: ghcr-manager/ghcr-cleanup-manager@v1.1.0
109
+ with:
110
+ command: cleanup
111
+ token: ${{ github.token }}
112
+ owner: OWNER
113
+ package: PACKAGE
114
+ delete-untagged: true
115
+ keep-n-tagged: "10"
116
+ upload-artifacts: true
117
+ scan-after-cleanup: true
118
+ ```
119
+
120
+ If `scan-after-cleanup` is `true`, `cleanup` performs a second scan so the uploaded DB reflects post-mutation state.
121
+
122
+ Note: the second scan only runs if cleanup actually makes changes.
123
+
124
+ Live cleanup permission note: change the workflow permission from `packages: read` to `packages: write` before turning
125
+ off `dry-run`.
126
+
127
+ ### Scan one package
128
+
129
+ ```yaml
130
+ - uses: ghcr-manager/ghcr-cleanup-manager@v1.1.0
131
+ with:
132
+ command: scan
133
+ token: ${{ github.token }}
134
+ owner: OWNER
135
+ package: PACKAGE
136
+ ```
137
+
138
+ `scan` always uploads a DB artifact.
139
+
140
+ ## Inputs
141
+
142
+ <!-- markdownlint-disable MD013 MD060 -->
143
+
144
+ | Input | Description | Cmds | Required | Default |
145
+ | ---------------------------- | ----------------------------------- | ---- | -------- | ------------------------------ |
146
+ | `command` | `scan` or `cleanup` | all | Yes | |
147
+ | `token` | GitHub token for API calls | all | Yes | `${{ github.token }}` |
148
+ | `owner` | Package owner | all | Yes | |
149
+ | `package` | Package name | all | Yes | |
150
+ | `db-path` | Local SQLite DB path | s,c | No | |
151
+ | `upload-artifacts` | Upload DB and summary artifacts | s,c | No | `false` |
152
+ | `scan-after-cleanup` | Run a second scan after cleanup | c | No | `false` |
153
+ | `db-artifact-retention-days` | Override artifact retention days | s,c | No | `${{ github.retention_days }}` |
154
+ | `delete-tags` | Newline-separated tags to delete | c | No | |
155
+ | `exclude-tags` | Newline-separated tags to exclude | c | No | |
156
+ | `keep-n-tagged` | Keep newest tagged roots | c | No | |
157
+ | `keep-n-untagged` | Keep newest untagged roots | c | No | |
158
+ | `delete-untagged` | Delete untagged roots | c | No | `false` |
159
+ | `delete-ghost-images` | Delete ghost multi-arch roots | c | No | `false` |
160
+ | `delete-partial-images` | Delete partial multi-arch roots | c | No | `false` |
161
+ | `delete-orphaned-images` | Delete orphaned digest-derived tags | c | No | `false` |
162
+ | `older-than` | Age cutoff for cleanup selectors | c | No | |
163
+ | `use-regex` | Use regex for cleanup tag selectors | c | No | `false` |
164
+ | `dry-run` | Show changes without mutating GHCR | c | No | `false` |
165
+ | `log-level` | CLI log level | all | No | `info` |
166
+
167
+ <!-- markdownlint-enable MD013 MD060 -->
168
+
169
+ `Cmds`: `s` = `scan`, `c` = `cleanup`
170
+
171
+ Cleanup command notes:
172
+
173
+ - Tagged selector families may be combined with `delete-untagged`.
174
+ - `exclude-tags` requires at least one tagged selector family.
175
+ - `delete-untagged` and `keep-n-untagged` cannot be combined.
176
+ - `older-than` takes one integer plus one unit.
177
+ - Supported `older-than` units: `minutes`, `hours`, `days`, `weeks`, `months`, `years`.
178
+ - Example values: `30 days`, `2 hours`, `1 month`.
179
+
180
+ ## Outputs
181
+
182
+ | Output | Description |
183
+ | ------------------- | ------------------------------------ |
184
+ | `db-path` | SQLite DB path on the runner |
185
+ | `summary-json-path` | Summary JSON file path for `cleanup` |
186
+
187
+ ## Artifacts
188
+
189
+ When artifacts are enabled:
190
+
191
+ - `scan` always uploads one SQLite DB artifact
192
+ - `cleanup` optionally uploads the DB artifact and a cleanup summary JSON artifact
193
+
194
+ Current naming:
195
+
196
+ | Artifact type | Filename pattern |
197
+ | -------------------- | --------------------------------------------------- |
198
+ | scan or cleanup DB | `${OWNER}__${PACKAGE}.sqlite` |
199
+ | cleanup summary JSON | `${OWNER}__${PACKAGE}.sqlite--cleanup-summary.json` |
200
+
201
+ ## Documentation Map
202
+
203
+ - [GitHub Action usage](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/docs/action-usage.md): action
204
+ commands, including `cleanup` and `scan`
205
+ - [Cleanup behavior](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/docs/cleanup-behavior.md): how
206
+ cleanup protects retained tags and handles shared graphs
207
+ - [ghcr-cleanup-manager-visualizer](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/visualizer/README.md):
208
+ local graph inspection and scan-to-scan comparison
209
+ - [Multi-package workflows](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/docs/db-merge-workflows.md):
210
+ cleaning up multiple packages with one combined DB
211
+ - [SQLite schema guide](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/docs/schema-description.md):
212
+ practical explanation of the SQLite schema
213
+ - [CLI usage](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/docs/cli-usage.md): companion CLI usage
214
+
215
+ ## Explore A Real Scenario DB
216
+
217
+ The release assets also include one merged SQLite DB from GHCR Cleanup Manager's live scenario workflows. You can use it
218
+ as a quick visualizer demo and as a compact way to inspect dozens of real cleanup and graph cases.
219
+
220
+ ```sh
221
+ curl -LO https://github.com/ghcr-manager/ghcr-cleanup-manager/releases/latest/download/ghcr-cleanup-manager([^/s]*.sqlite)
222
+ npx ghcr-cleanup-manager-visualizer --db ./ghcr-cleanup-manager([^/s]*.sqlite)
223
+ ```
224
+
225
+ Docker image available:
226
+ [visualizer Docker usage](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/visualizer/README.md#docker).
227
+
228
+ For a first look in the visualizer, start with:
229
+
230
+ - owner: `ghcr-cleanup-manager-test`
231
+ - package: select one with `2images` or `2multiarch` in the name
232
+ - tag search: `image` or `multiarch`
233
+
234
+ For more details, see [visualizer](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/visualizer/README.md)
235
+ and [test-scenarios](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/docs/test/scenarios.md).
236
+
237
+ ## Cleanup Behavior
238
+
239
+ Cleanup is tag-based for both selection and protection. Use tags to say what should be cleaned up, and use retained tags
240
+ to keep image and multi-arch graphs protected.
241
+
242
+ Manifests reachable from retained tags stay protected. Manifests no longer reachable from any retained tag may be
243
+ removed during cleanup. If you pull images by digest, make sure those digests are still reachable through tags that your
244
+ cleanup rules keep.
245
+
246
+ For the full explanation and graph examples, see
247
+ [cleanup-behavior](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/docs/cleanup-behavior.md).
248
+
249
+ ## Project
250
+
251
+ Main project and issue tracker:
252
+
253
+ - Repository: <https://github.com/ghcr-manager/ghcr-cleanup-manager>
254
+ - Issues: <https://github.com/ghcr-manager/ghcr-cleanup-manager/issues>
255
+
256
+ ## Similar Tools
257
+
258
+ - [ghcr-manager/ghcr-untag-action](https://github.com/ghcr-manager/ghcr-untag-action): focused tag removal without the
259
+ broader scan and cleanup workflow.
260
+ - [dataaxiom/ghcr-cleanup-action](https://github.com/dataaxiom/ghcr-cleanup-action): another GHCR cleanup action with a
261
+ similar problem focus.
262
+ - [mkoepf/ghcrctl](https://github.com/mkoepf/ghcrctl): CLI tooling for working with GHCR packages and graph deletions.
@@ -0,0 +1,5 @@
1
+ import type { CleanupSummary } from "./_cleanup-summary.js";
2
+ export declare function renderCleanupSummaryMarkdown(summary: CleanupSummary, options: {
3
+ maxDirectTargetTags?: number;
4
+ maxRootsPerSection?: number;
5
+ }): string;