ghcr-cleanup-manager 1.1.1 → 1.1.3
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.
- package/CHANGELOG.md +17 -0
- package/README.md +14 -14
- package/dist/db/_manifest-reachability.js +16 -4
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [v1.1.3] - 2026-07-01
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Digest-tag helper edges now ignore self-references from a digest-tagged artifact back to its own manifest.
|
|
15
|
+
- The visualizer details view now shows `sha256-*` tags. These tags are still hidden in the graph itself.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Visualizer docs and package-name references now consistently use `ghcr-cleanup-manager-visualizer`.
|
|
20
|
+
|
|
21
|
+
## [v1.1.2] - 2026-06-14
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Reissued v1.1.1 as v1.1.2 after a partial publish to npmjs.com.
|
|
26
|
+
|
|
10
27
|
## [v1.1.1] - 2026-06-14
|
|
11
28
|
|
|
12
29
|
### Changed
|
package/README.md
CHANGED
|
@@ -9,14 +9,14 @@ GHCR Cleanup Manager is a GHCR cleanup action for GitHub Container Registry pack
|
|
|
9
9
|
|
|
10
10
|
GHCR Cleanup Manager is a GitHub Action for:
|
|
11
11
|
|
|
12
|
-
- clean GHCR packages
|
|
13
|
-
- preview cleanup
|
|
14
|
-
- scan GHCR packages
|
|
15
|
-
- visualize GHCR package graphs
|
|
16
|
-
[
|
|
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
|
+
[visualizer](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/visualizer/README.md)
|
|
17
17
|
|
|
18
|
-
It is built for safe GHCR cleanup on
|
|
19
|
-
|
|
18
|
+
It is built for safe GHCR cleanup on OCI package graphs, including multi-arch images, attestations, cosign signatures,
|
|
19
|
+
and other referrers that simpler GHCR cleanup actions often mishandle.
|
|
20
20
|
|
|
21
21
|
[](https://github.com/ghcr-manager/ghcr-cleanup-manager/blob/main/docs/images/visualizer/graph-2images-cosign--wide.png)
|
|
22
22
|
|
|
@@ -41,7 +41,7 @@ jobs:
|
|
|
41
41
|
|
|
42
42
|
- name: Preview GHCR cleanup
|
|
43
43
|
id: ghcr-cleanup-manager
|
|
44
|
-
uses: ghcr-manager/ghcr-cleanup-manager@v1.1.
|
|
44
|
+
uses: ghcr-manager/ghcr-cleanup-manager@v1.1.3
|
|
45
45
|
with:
|
|
46
46
|
command: cleanup
|
|
47
47
|
token: ${{ github.token }}
|
|
@@ -49,7 +49,7 @@ jobs:
|
|
|
49
49
|
package: PACKAGE
|
|
50
50
|
dry-run: true
|
|
51
51
|
delete-untagged: true
|
|
52
|
-
keep-n-tagged:
|
|
52
|
+
keep-n-tagged: 10
|
|
53
53
|
exclude-tags: |
|
|
54
54
|
latest
|
|
55
55
|
upload-artifacts: true
|
|
@@ -84,7 +84,7 @@ The action supports two commands:
|
|
|
84
84
|
### Preview cleanup
|
|
85
85
|
|
|
86
86
|
```yaml
|
|
87
|
-
- uses: ghcr-manager/ghcr-cleanup-manager@v1.1.
|
|
87
|
+
- uses: ghcr-manager/ghcr-cleanup-manager@v1.1.3
|
|
88
88
|
with:
|
|
89
89
|
command: cleanup
|
|
90
90
|
token: ${{ github.token }}
|
|
@@ -95,7 +95,7 @@ The action supports two commands:
|
|
|
95
95
|
pr-.*
|
|
96
96
|
use-regex: true
|
|
97
97
|
older-than: 30 days
|
|
98
|
-
keep-n-tagged:
|
|
98
|
+
keep-n-tagged: 5
|
|
99
99
|
exclude-tags: |
|
|
100
100
|
latest
|
|
101
101
|
stable
|
|
@@ -105,14 +105,14 @@ The action supports two commands:
|
|
|
105
105
|
### Apply cleanup
|
|
106
106
|
|
|
107
107
|
```yaml
|
|
108
|
-
- uses: ghcr-manager/ghcr-cleanup-manager@v1.1.
|
|
108
|
+
- uses: ghcr-manager/ghcr-cleanup-manager@v1.1.3
|
|
109
109
|
with:
|
|
110
110
|
command: cleanup
|
|
111
111
|
token: ${{ github.token }}
|
|
112
112
|
owner: OWNER
|
|
113
113
|
package: PACKAGE
|
|
114
114
|
delete-untagged: true
|
|
115
|
-
keep-n-tagged:
|
|
115
|
+
keep-n-tagged: 10
|
|
116
116
|
upload-artifacts: true
|
|
117
117
|
scan-after-cleanup: true
|
|
118
118
|
```
|
|
@@ -127,7 +127,7 @@ off `dry-run`.
|
|
|
127
127
|
### Scan one package
|
|
128
128
|
|
|
129
129
|
```yaml
|
|
130
|
-
- uses: ghcr-manager/ghcr-cleanup-manager@v1.1.
|
|
130
|
+
- uses: ghcr-manager/ghcr-cleanup-manager@v1.1.3
|
|
131
131
|
with:
|
|
132
132
|
command: scan
|
|
133
133
|
token: ${{ github.token }}
|
|
@@ -9,7 +9,8 @@ export function rebuildManifestReachability(database, scanId) {
|
|
|
9
9
|
parentDigestsByChild.set(digest, new Set());
|
|
10
10
|
neighborDigestsByDigest.set(digest, new Set());
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
const manifestEdges = _loadManifestEdges(database, scanId);
|
|
13
|
+
for (const manifestEdge of manifestEdges) {
|
|
13
14
|
childDigestsByParent.get(manifestEdge.parent_digest)?.add(manifestEdge.child_digest);
|
|
14
15
|
parentDigestsByChild.get(manifestEdge.child_digest)?.add(manifestEdge.parent_digest);
|
|
15
16
|
neighborDigestsByDigest.get(manifestEdge.parent_digest)?.add(manifestEdge.child_digest);
|
|
@@ -55,7 +56,7 @@ export function rebuildManifestReachability(database, scanId) {
|
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
if (descendantDistancesByDigest.size !== manifestDigests.length) {
|
|
58
|
-
throw new Error(
|
|
59
|
+
throw new Error(_buildCycleErrorMessage(manifestDigests, remainingChildrenCount, manifestEdges));
|
|
59
60
|
}
|
|
60
61
|
const insertRow = database.prepare(`
|
|
61
62
|
INSERT OR REPLACE INTO manifest_reachability(
|
|
@@ -131,6 +132,7 @@ function _refreshDigestTagEdges(database, scanId) {
|
|
|
131
132
|
AND child_manifest.digest = 'sha256:' || SUBSTR(t.tag, 8, 64)
|
|
132
133
|
WHERE t.scan_id = ?
|
|
133
134
|
AND t.is_digest_tag = 1
|
|
135
|
+
AND m.digest != child_manifest.digest
|
|
134
136
|
`)
|
|
135
137
|
.run(scanId);
|
|
136
138
|
}
|
|
@@ -143,13 +145,23 @@ function _loadManifestDigests(database, scanId) {
|
|
|
143
145
|
function _loadManifestEdges(database, scanId) {
|
|
144
146
|
return database
|
|
145
147
|
.prepare(`
|
|
146
|
-
SELECT DISTINCT parent_digest, child_digest
|
|
148
|
+
SELECT DISTINCT parent_digest, child_digest, edge_kind
|
|
147
149
|
FROM manifest_edges
|
|
148
150
|
WHERE scan_id = ?
|
|
149
|
-
ORDER BY parent_digest, child_digest
|
|
151
|
+
ORDER BY parent_digest, child_digest, edge_kind
|
|
150
152
|
`)
|
|
151
153
|
.all(scanId);
|
|
152
154
|
}
|
|
155
|
+
function _buildCycleErrorMessage(manifestDigests, remainingChildrenCount, manifestEdges) {
|
|
156
|
+
const unresolvedDigests = new Set(manifestDigests.filter((digest) => (remainingChildrenCount.get(digest) ?? 0) > 0));
|
|
157
|
+
const unresolvedDigestList = Array.from(unresolvedDigests).join(", ");
|
|
158
|
+
for (const edge of manifestEdges) {
|
|
159
|
+
if (unresolvedDigests.has(edge.parent_digest) && unresolvedDigests.has(edge.child_digest)) {
|
|
160
|
+
return `manifest reachability build detected a cycle in manifest_edges; example unresolved edge: ${edge.parent_digest} --${edge.edge_kind}--> ${edge.child_digest}; unresolved digests: ${unresolvedDigestList}`;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return `manifest reachability build detected a cycle in manifest_edges; unresolved digests: ${unresolvedDigestList}`;
|
|
164
|
+
}
|
|
153
165
|
function _setMinDistance(distances, digest, distance) {
|
|
154
166
|
const currentDistance = distances.get(digest);
|
|
155
167
|
if (currentDistance === undefined || distance < currentDistance) {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "ghcr-cleanup-manager",
|
|
3
3
|
"description": "GHCR Cleanup Manager: GitHub Action and CLI for safe GitHub Container Registry cleanup and inspection.",
|
|
4
4
|
"homepage": "https://github.com/ghcr-manager/ghcr-cleanup-manager#readme",
|
|
5
|
-
"version": "v1.1.
|
|
5
|
+
"version": "v1.1.3",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"keywords": [
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"eslint": "^10.2.1",
|
|
69
69
|
"eslint-plugin-yml": "^3.4.0",
|
|
70
70
|
"globals": "^17.5.0",
|
|
71
|
-
"markdownlint-cli2": "^0.
|
|
71
|
+
"markdownlint-cli2": "^0.23.0",
|
|
72
72
|
"prettier": "^3.8.3",
|
|
73
73
|
"tsx": "^4.20.6",
|
|
74
74
|
"typescript": "^6.0.3",
|