ghcr-manager 0.9.9 → 0.9.10
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 +13 -0
- package/README.md +4 -4
- package/dist/db/planner/_planner-direct-target-roots-combined-sql.js +21 -24
- package/dist/db/planner/_planner-direct-target-roots-combined.js +1 -1
- package/dist/db/planner/_planner-plan-artifacts-blocked-roots-sql.d.ts +1 -1
- package/dist/db/planner/_planner-plan-artifacts-blocked-roots-sql.js +22 -12
- package/dist/db/planner/_planner-plan-artifacts-closure-sql.d.ts +1 -1
- package/dist/db/planner/_planner-plan-artifacts-closure-sql.js +20 -27
- package/dist/db/planner/_planner-plan-artifacts.js +1 -1
- package/package.json +2 -1
- package/resources/sql/schema/001_schema.sql +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.9.10] - 2026-06-04
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Cleanup planning for large package databases is much faster while preserving the existing cleanup behavior.
|
|
15
|
+
- On a large validation package with more than 100k manifests, dry-run planning and summary generation dropped from more
|
|
16
|
+
than 20 minutes to roughly 15 seconds.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Internal GHCR validation workflows now avoid GitHub's "cannot delete the last tagged version" failure mode during
|
|
21
|
+
temporary-tag cleanup.
|
|
22
|
+
|
|
10
23
|
## [0.9.9] - 2026-05-30
|
|
11
24
|
|
|
12
25
|
No additional user-facing changes were introduced beyond `0.9.8`.
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ jobs:
|
|
|
32
32
|
|
|
33
33
|
- name: Preview GHCR cleanup
|
|
34
34
|
id: ghcr-manager
|
|
35
|
-
uses: ghcr-manager/ghcr-manager@0.9.
|
|
35
|
+
uses: ghcr-manager/ghcr-manager@0.9.10
|
|
36
36
|
with:
|
|
37
37
|
command: cleanup
|
|
38
38
|
token: ${{ github.token }}
|
|
@@ -69,7 +69,7 @@ The action supports two commands:
|
|
|
69
69
|
### Preview cleanup
|
|
70
70
|
|
|
71
71
|
```yaml
|
|
72
|
-
- uses: ghcr-manager/ghcr-manager@0.9.
|
|
72
|
+
- uses: ghcr-manager/ghcr-manager@0.9.10
|
|
73
73
|
with:
|
|
74
74
|
command: cleanup
|
|
75
75
|
token: ${{ github.token }}
|
|
@@ -90,7 +90,7 @@ The action supports two commands:
|
|
|
90
90
|
### Apply cleanup
|
|
91
91
|
|
|
92
92
|
```yaml
|
|
93
|
-
- uses: ghcr-manager/ghcr-manager@0.9.
|
|
93
|
+
- uses: ghcr-manager/ghcr-manager@0.9.10
|
|
94
94
|
with:
|
|
95
95
|
command: cleanup
|
|
96
96
|
token: ${{ github.token }}
|
|
@@ -109,7 +109,7 @@ Note: the second scan only runs if cleanup actually makes changes.
|
|
|
109
109
|
### Scan one package
|
|
110
110
|
|
|
111
111
|
```yaml
|
|
112
|
-
- uses: ghcr-manager/ghcr-manager@0.9.
|
|
112
|
+
- uses: ghcr-manager/ghcr-manager@0.9.10
|
|
113
113
|
with:
|
|
114
114
|
command: scan
|
|
115
115
|
token: ${{ github.token }}
|
|
@@ -4,6 +4,7 @@ export function buildCombinedDirectTargetRootsQuery(scanId, options, selectedTag
|
|
|
4
4
|
if (options.cutoffTimestamp) {
|
|
5
5
|
baseParams.push(options.cutoffTimestamp);
|
|
6
6
|
}
|
|
7
|
+
baseParams.push(scanId, scanId);
|
|
7
8
|
const taggedBranchEnabled = options.deleteTagsRequested || options.keepNTagged !== undefined ? 1 : 0;
|
|
8
9
|
const deleteTagsRequested = options.deleteTagsRequested ? 1 : 0;
|
|
9
10
|
const deleteOrphanedImages = options.deleteOrphanedImages ? 1 : 0;
|
|
@@ -41,35 +42,31 @@ export function buildCombinedDirectTargetRootsQuery(scanId, options, selectedTag
|
|
|
41
42
|
WHERE m.scan_id = ?
|
|
42
43
|
${cutoffSql}
|
|
43
44
|
),
|
|
44
|
-
tag_counts AS (
|
|
45
|
-
SELECT
|
|
46
|
-
t.version_id,
|
|
47
|
-
COUNT(t.tag) AS tag_count
|
|
48
|
-
FROM tags t
|
|
49
|
-
WHERE t.scan_id = ?
|
|
50
|
-
AND t.is_digest_tag = 0
|
|
51
|
-
GROUP BY t.version_id
|
|
52
|
-
),
|
|
53
|
-
parented_digests AS (
|
|
54
|
-
SELECT DISTINCT me.child_digest
|
|
55
|
-
FROM manifest_edges me
|
|
56
|
-
WHERE me.scan_id = ?
|
|
57
|
-
AND me.edge_kind != 'digest-tag-referrer'
|
|
58
|
-
),
|
|
59
45
|
root_candidates AS (
|
|
60
46
|
SELECT
|
|
61
47
|
bm.version_id,
|
|
62
48
|
bm.root_digest,
|
|
63
49
|
bm.root_manifest_kind,
|
|
64
50
|
bm.created_at,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
51
|
+
(
|
|
52
|
+
SELECT COUNT(*)
|
|
53
|
+
FROM tags t
|
|
54
|
+
WHERE t.scan_id = ?
|
|
55
|
+
AND t.version_id = bm.version_id
|
|
56
|
+
AND t.is_digest_tag = 0
|
|
57
|
+
) AS tag_count,
|
|
58
|
+
CASE
|
|
59
|
+
WHEN EXISTS (
|
|
60
|
+
SELECT 1
|
|
61
|
+
FROM manifest_edges me
|
|
62
|
+
WHERE me.scan_id = ?
|
|
63
|
+
AND me.child_digest = bm.root_digest
|
|
64
|
+
AND me.edge_kind != 'digest-tag-referrer'
|
|
65
|
+
)
|
|
66
|
+
THEN 1
|
|
67
|
+
ELSE 0
|
|
68
|
+
END AS has_ancestor
|
|
68
69
|
FROM base_manifests bm
|
|
69
|
-
LEFT JOIN tag_counts tc
|
|
70
|
-
ON tc.version_id = bm.version_id
|
|
71
|
-
LEFT JOIN parented_digests pd
|
|
72
|
-
ON pd.child_digest = bm.root_digest
|
|
73
70
|
),
|
|
74
71
|
selected_tags AS (
|
|
75
72
|
${selectedTagsSql}
|
|
@@ -102,7 +99,7 @@ export function buildCombinedDirectTargetRootsQuery(scanId, options, selectedTag
|
|
|
102
99
|
LEFT JOIN excluded_versions ev
|
|
103
100
|
ON ev.version_id = rc.version_id
|
|
104
101
|
WHERE (
|
|
105
|
-
rc.
|
|
102
|
+
rc.tag_count > 0
|
|
106
103
|
OR (? = 1 AND COALESCE(mtc.matched_tag_count, 0) > 0)
|
|
107
104
|
)
|
|
108
105
|
AND ev.version_id IS NULL
|
|
@@ -156,7 +153,7 @@ export function buildCombinedDirectTargetRootsQuery(scanId, options, selectedTag
|
|
|
156
153
|
ORDER BY rc.created_at DESC, rc.version_id DESC, rc.root_digest DESC
|
|
157
154
|
) AS recency_rank
|
|
158
155
|
FROM root_candidates rc
|
|
159
|
-
WHERE rc.
|
|
156
|
+
WHERE rc.tag_count = 0
|
|
160
157
|
AND rc.has_ancestor = 0
|
|
161
158
|
AND (? = 1 OR ? = 1)
|
|
162
159
|
),
|
|
@@ -5,6 +5,6 @@ export function listCombinedDirectTargetRoots(sql, scanId, options) {
|
|
|
5
5
|
const { selectedTagsSql, selectedParams, excludedVersionsSql, excludedParams } = buildDirectTargetRootTagFilters(sql, scanId, options);
|
|
6
6
|
const { query, baseParams, tailParams } = buildCombinedDirectTargetRootsQuery(scanId, options, selectedTagsSql, excludedVersionsSql);
|
|
7
7
|
return sql
|
|
8
|
-
.all(query, [...baseParams,
|
|
8
|
+
.all(query, [...baseParams, ...selectedParams, ...excludedParams, ...tailParams])
|
|
9
9
|
.map(mapPlanRootRow);
|
|
10
10
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const _LIST_BLOCKED_ROOTS_SQL = "\n WITH
|
|
1
|
+
export declare const _LIST_BLOCKED_ROOTS_SQL = "\n WITH selected_root_graphs AS (\n SELECT\n dtr.root_version_id,\n dtr.root_digest,\n dtr.root_manifest_kind,\n manifest_graphs.graph_id\n FROM temp_direct_target_roots dtr\n CROSS JOIN manifest_graphs\n WHERE manifest_graphs.scan_id = ?\n AND manifest_graphs.digest = dtr.root_digest\n ),\n selected_graphs AS (\n SELECT DISTINCT\n selected_root_graphs.graph_id\n FROM selected_root_graphs\n ),\n retained_tagged_manifests AS (\n SELECT DISTINCT\n manifest_graphs.graph_id,\n m.version_id AS tagged_version_id,\n m.digest AS tagged_digest\n FROM selected_graphs\n CROSS JOIN manifest_graphs\n CROSS JOIN manifests m\n JOIN tags t\n ON t.scan_id = m.scan_id\n AND t.version_id = m.version_id\n AND t.is_digest_tag = 0\n WHERE manifest_graphs.scan_id = m.scan_id\n AND selected_graphs.graph_id = manifest_graphs.graph_id\n AND manifest_graphs.digest = m.digest\n AND m.scan_id = ?\n AND NOT EXISTS (\n SELECT 1\n FROM temp_direct_target_roots dtr\n WHERE dtr.root_digest = m.digest\n )\n ),\n ranked_blocks AS (\n SELECT\n root_graph.root_version_id AS blocked_version_id,\n root_graph.root_digest AS blocked_digest,\n retained.tagged_version_id AS blocking_version_id,\n retained.tagged_digest AS blocking_digest,\n root_graph.root_digest AS overlap_digest,\n root_graph.root_manifest_kind AS overlap_manifest_kind,\n 'overlap-with-retained-root' AS block_reason,\n ROW_NUMBER() OVER (\n PARTITION BY root_graph.root_digest, retained.tagged_digest\n ORDER BY\n retained_overlap.min_distance,\n root_graph.root_digest\n ) AS rn\n FROM selected_root_graphs root_graph\n JOIN retained_tagged_manifests retained\n ON retained.graph_id = root_graph.graph_id\n AND retained.tagged_digest <> root_graph.root_digest\n JOIN manifest_reachability retained_overlap\n ON retained_overlap.scan_id = ?\n AND retained_overlap.ancestor_digest = retained.tagged_digest\n AND retained_overlap.descendant_digest = root_graph.root_digest\n )\n SELECT\n blocked_version_id,\n blocked_digest,\n blocking_version_id,\n blocking_digest,\n overlap_digest,\n overlap_manifest_kind,\n block_reason\n FROM ranked_blocks\n WHERE rn = 1\n ORDER BY blocked_digest, blocking_digest, overlap_digest\n";
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
export const _LIST_BLOCKED_ROOTS_SQL = `
|
|
2
|
-
WITH
|
|
3
|
-
SELECT
|
|
2
|
+
WITH selected_root_graphs AS (
|
|
3
|
+
SELECT
|
|
4
|
+
dtr.root_version_id,
|
|
5
|
+
dtr.root_digest,
|
|
6
|
+
dtr.root_manifest_kind,
|
|
4
7
|
manifest_graphs.graph_id
|
|
5
8
|
FROM temp_direct_target_roots dtr
|
|
6
9
|
CROSS JOIN manifest_graphs
|
|
7
10
|
WHERE manifest_graphs.scan_id = ?
|
|
8
11
|
AND manifest_graphs.digest = dtr.root_digest
|
|
9
12
|
),
|
|
13
|
+
selected_graphs AS (
|
|
14
|
+
SELECT DISTINCT
|
|
15
|
+
selected_root_graphs.graph_id
|
|
16
|
+
FROM selected_root_graphs
|
|
17
|
+
),
|
|
10
18
|
retained_tagged_manifests AS (
|
|
11
|
-
SELECT
|
|
19
|
+
SELECT DISTINCT
|
|
20
|
+
manifest_graphs.graph_id,
|
|
12
21
|
m.version_id AS tagged_version_id,
|
|
13
22
|
m.digest AS tagged_digest
|
|
14
23
|
FROM selected_graphs
|
|
@@ -30,26 +39,27 @@ export const _LIST_BLOCKED_ROOTS_SQL = `
|
|
|
30
39
|
),
|
|
31
40
|
ranked_blocks AS (
|
|
32
41
|
SELECT
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
root_graph.root_version_id AS blocked_version_id,
|
|
43
|
+
root_graph.root_digest AS blocked_digest,
|
|
35
44
|
retained.tagged_version_id AS blocking_version_id,
|
|
36
45
|
retained.tagged_digest AS blocking_digest,
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
root_graph.root_digest AS overlap_digest,
|
|
47
|
+
root_graph.root_manifest_kind AS overlap_manifest_kind,
|
|
39
48
|
'overlap-with-retained-root' AS block_reason,
|
|
40
49
|
ROW_NUMBER() OVER (
|
|
41
|
-
PARTITION BY
|
|
50
|
+
PARTITION BY root_graph.root_digest, retained.tagged_digest
|
|
42
51
|
ORDER BY
|
|
43
52
|
retained_overlap.min_distance,
|
|
44
|
-
|
|
53
|
+
root_graph.root_digest
|
|
45
54
|
) AS rn
|
|
46
|
-
FROM
|
|
55
|
+
FROM selected_root_graphs root_graph
|
|
47
56
|
JOIN retained_tagged_manifests retained
|
|
48
|
-
ON retained.
|
|
57
|
+
ON retained.graph_id = root_graph.graph_id
|
|
58
|
+
AND retained.tagged_digest <> root_graph.root_digest
|
|
49
59
|
JOIN manifest_reachability retained_overlap
|
|
50
60
|
ON retained_overlap.scan_id = ?
|
|
51
61
|
AND retained_overlap.ancestor_digest = retained.tagged_digest
|
|
52
|
-
AND retained_overlap.descendant_digest =
|
|
62
|
+
AND retained_overlap.descendant_digest = root_graph.root_digest
|
|
53
63
|
)
|
|
54
64
|
SELECT
|
|
55
65
|
blocked_version_id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const _LIST_CLOSURE_MANIFESTS_SQL = "\n WITH selected_graphs AS (\n SELECT DISTINCT\n manifest_graphs.graph_id\n FROM temp_direct_target_roots dtr\n CROSS JOIN manifest_graphs\n WHERE manifest_graphs.scan_id = ?\n AND manifest_graphs.digest = dtr.root_digest\n ),\n retained_tagged_manifests AS (\n SELECT DISTINCT\n m.
|
|
1
|
+
export declare const _LIST_CLOSURE_MANIFESTS_SQL = "\n WITH selected_graphs AS (\n SELECT DISTINCT\n manifest_graphs.graph_id\n FROM temp_direct_target_roots dtr\n CROSS JOIN manifest_graphs\n WHERE manifest_graphs.scan_id = ?\n AND manifest_graphs.digest = dtr.root_digest\n ),\n retained_tagged_manifests AS (\n SELECT DISTINCT\n m.digest\n FROM selected_graphs\n CROSS JOIN manifest_graphs\n CROSS JOIN manifests m\n JOIN tags t\n ON t.scan_id = m.scan_id\n AND t.version_id = m.version_id\n AND t.is_digest_tag = 0\n WHERE manifest_graphs.scan_id = m.scan_id\n AND selected_graphs.graph_id = manifest_graphs.graph_id\n AND manifest_graphs.digest = m.digest\n AND m.scan_id = ?\n AND NOT EXISTS (\n SELECT 1\n FROM temp_direct_target_roots dtr\n WHERE dtr.root_digest = m.digest\n )\n ),\n retained_manifests AS (\n SELECT\n retained.digest\n FROM retained_tagged_manifests retained\n\n UNION\n\n SELECT\n mr.descendant_digest AS digest\n FROM retained_tagged_manifests retained\n CROSS JOIN manifest_reachability mr\n WHERE mr.scan_id = ?\n AND mr.ancestor_digest = retained.digest\n AND mr.min_distance > 0\n ),\n direct_target_closure AS (\n SELECT\n dtr.root_digest AS source_digest,\n dtr.root_digest AS member_digest,\n 0 AS hops_from_root\n FROM temp_direct_target_roots dtr\n\n UNION ALL\n\n SELECT\n dtr.root_digest AS source_digest,\n mr.descendant_digest AS member_digest,\n mr.min_distance AS hops_from_root\n FROM temp_direct_target_roots dtr\n CROSS JOIN manifest_reachability mr\n WHERE mr.scan_id = ?\n AND mr.ancestor_digest = dtr.root_digest\n AND mr.min_distance > 0\n ),\n closure_seed AS (\n SELECT\n dtc.source_digest,\n dtc.member_digest,\n dtc.hops_from_root\n FROM direct_target_closure dtc\n WHERE dtc.hops_from_root = 0\n OR NOT EXISTS (\n SELECT 1\n FROM retained_manifests retained\n WHERE retained.digest = dtc.member_digest\n )\n ),\n undirected_edges AS (\n SELECT\n me.parent_digest AS source_digest,\n me.child_digest AS target_digest\n FROM selected_graphs\n CROSS JOIN manifest_graphs parent_graph\n CROSS JOIN manifest_edges me INDEXED BY idx_manifest_edges_scan_parent\n WHERE parent_graph.scan_id = me.scan_id\n AND selected_graphs.graph_id = parent_graph.graph_id\n AND parent_graph.digest = me.parent_digest\n AND me.scan_id = ?\n AND NOT EXISTS (\n SELECT 1\n FROM retained_manifests retained\n WHERE retained.digest = me.parent_digest\n OR retained.digest = me.child_digest\n )\n\n UNION\n\n SELECT\n me.child_digest AS source_digest,\n me.parent_digest AS target_digest\n FROM selected_graphs\n CROSS JOIN manifest_graphs child_graph\n CROSS JOIN manifest_edges me INDEXED BY idx_manifest_edges_scan_child\n WHERE child_graph.scan_id = me.scan_id\n AND selected_graphs.graph_id = child_graph.graph_id\n AND child_graph.digest = me.child_digest\n AND me.scan_id = ?\n AND NOT EXISTS (\n SELECT 1\n FROM retained_manifests retained\n WHERE retained.digest = me.parent_digest\n OR retained.digest = me.child_digest\n )\n ),\n delete_component_members AS (\n SELECT\n seed.source_digest,\n seed.member_digest\n FROM closure_seed seed\n\n UNION\n\n SELECT\n walk.source_digest,\n edge.target_digest AS member_digest\n FROM delete_component_members walk\n JOIN undirected_edges edge\n ON edge.source_digest = walk.member_digest\n WHERE NOT EXISTS (\n SELECT 1\n FROM retained_manifests retained\n WHERE retained.digest = edge.target_digest\n )\n ),\n source_seed_hops AS (\n SELECT\n seed.source_digest,\n MAX(seed.hops_from_root) AS max_seed_hops\n FROM closure_seed seed\n GROUP BY seed.source_digest\n ),\n descendant_hops AS (\n SELECT\n dtc.source_digest,\n dtc.member_digest,\n MIN(dtc.hops_from_root) AS min_hops_from_root\n FROM direct_target_closure dtc\n WHERE dtc.hops_from_root > 0\n GROUP BY dtc.source_digest, dtc.member_digest\n )\n SELECT\n dtr.root_version_id AS source_version_id,\n walk.source_digest,\n MIN(member_manifest.version_id) AS member_version_id,\n walk.member_digest,\n MIN(member_manifest.manifest_kind) AS member_manifest_kind,\n CASE\n WHEN walk.member_digest = walk.source_digest\n THEN 0\n WHEN descendant_hops.min_hops_from_root IS NOT NULL\n THEN descendant_hops.min_hops_from_root\n ELSE source_seed_hops.max_seed_hops + 1\n END AS hops_from_root,\n CASE\n WHEN walk.member_digest = walk.source_digest\n THEN 'root'\n WHEN descendant_hops.min_hops_from_root IS NOT NULL\n THEN 'descendant'\n ELSE 'connected'\n END AS member_role\n FROM delete_component_members walk\n JOIN temp_direct_target_roots dtr\n ON dtr.root_digest = walk.source_digest\n JOIN manifests member_manifest\n ON member_manifest.scan_id = ?\n AND member_manifest.digest = walk.member_digest\n JOIN source_seed_hops\n ON source_seed_hops.source_digest = walk.source_digest\n LEFT JOIN descendant_hops\n ON descendant_hops.source_digest = walk.source_digest\n AND descendant_hops.member_digest = walk.member_digest\n GROUP BY\n dtr.root_version_id,\n walk.source_digest,\n walk.member_digest,\n descendant_hops.min_hops_from_root,\n source_seed_hops.max_seed_hops\n ORDER BY walk.source_digest, hops_from_root, walk.member_digest\n";
|
|
@@ -9,7 +9,6 @@ export const _LIST_CLOSURE_MANIFESTS_SQL = `
|
|
|
9
9
|
),
|
|
10
10
|
retained_tagged_manifests AS (
|
|
11
11
|
SELECT DISTINCT
|
|
12
|
-
m.version_id,
|
|
13
12
|
m.digest
|
|
14
13
|
FROM selected_graphs
|
|
15
14
|
CROSS JOIN manifest_graphs
|
|
@@ -30,55 +29,40 @@ export const _LIST_CLOSURE_MANIFESTS_SQL = `
|
|
|
30
29
|
),
|
|
31
30
|
retained_manifests AS (
|
|
32
31
|
SELECT
|
|
33
|
-
retained.version_id,
|
|
34
32
|
retained.digest
|
|
35
33
|
FROM retained_tagged_manifests retained
|
|
36
34
|
|
|
37
35
|
UNION
|
|
38
36
|
|
|
39
37
|
SELECT
|
|
40
|
-
|
|
41
|
-
m.digest
|
|
38
|
+
mr.descendant_digest AS digest
|
|
42
39
|
FROM retained_tagged_manifests retained
|
|
43
40
|
CROSS JOIN manifest_reachability mr
|
|
44
|
-
CROSS JOIN manifests m
|
|
45
41
|
WHERE mr.scan_id = ?
|
|
46
42
|
AND mr.ancestor_digest = retained.digest
|
|
47
43
|
AND mr.min_distance > 0
|
|
48
|
-
AND m.scan_id = ?
|
|
49
|
-
AND m.digest = mr.descendant_digest
|
|
50
44
|
),
|
|
51
45
|
direct_target_closure AS (
|
|
52
46
|
SELECT
|
|
53
|
-
dtr.root_version_id AS source_version_id,
|
|
54
47
|
dtr.root_digest AS source_digest,
|
|
55
|
-
dtr.root_version_id AS member_version_id,
|
|
56
48
|
dtr.root_digest AS member_digest,
|
|
57
|
-
dtr.root_manifest_kind AS member_manifest_kind,
|
|
58
49
|
0 AS hops_from_root
|
|
59
50
|
FROM temp_direct_target_roots dtr
|
|
60
51
|
|
|
61
52
|
UNION ALL
|
|
62
53
|
|
|
63
54
|
SELECT
|
|
64
|
-
dtr.root_version_id AS source_version_id,
|
|
65
55
|
dtr.root_digest AS source_digest,
|
|
66
|
-
|
|
67
|
-
m.digest AS member_digest,
|
|
68
|
-
m.manifest_kind AS member_manifest_kind,
|
|
56
|
+
mr.descendant_digest AS member_digest,
|
|
69
57
|
mr.min_distance AS hops_from_root
|
|
70
58
|
FROM temp_direct_target_roots dtr
|
|
71
59
|
CROSS JOIN manifest_reachability mr
|
|
72
|
-
CROSS JOIN manifests m
|
|
73
60
|
WHERE mr.scan_id = ?
|
|
74
61
|
AND mr.ancestor_digest = dtr.root_digest
|
|
75
62
|
AND mr.min_distance > 0
|
|
76
|
-
AND m.scan_id = ?
|
|
77
|
-
AND m.digest = mr.descendant_digest
|
|
78
63
|
),
|
|
79
64
|
closure_seed AS (
|
|
80
65
|
SELECT
|
|
81
|
-
dtc.source_version_id,
|
|
82
66
|
dtc.source_digest,
|
|
83
67
|
dtc.member_digest,
|
|
84
68
|
dtc.hops_from_root
|
|
@@ -101,6 +85,12 @@ export const _LIST_CLOSURE_MANIFESTS_SQL = `
|
|
|
101
85
|
AND selected_graphs.graph_id = parent_graph.graph_id
|
|
102
86
|
AND parent_graph.digest = me.parent_digest
|
|
103
87
|
AND me.scan_id = ?
|
|
88
|
+
AND NOT EXISTS (
|
|
89
|
+
SELECT 1
|
|
90
|
+
FROM retained_manifests retained
|
|
91
|
+
WHERE retained.digest = me.parent_digest
|
|
92
|
+
OR retained.digest = me.child_digest
|
|
93
|
+
)
|
|
104
94
|
|
|
105
95
|
UNION
|
|
106
96
|
|
|
@@ -114,10 +104,15 @@ export const _LIST_CLOSURE_MANIFESTS_SQL = `
|
|
|
114
104
|
AND selected_graphs.graph_id = child_graph.graph_id
|
|
115
105
|
AND child_graph.digest = me.child_digest
|
|
116
106
|
AND me.scan_id = ?
|
|
107
|
+
AND NOT EXISTS (
|
|
108
|
+
SELECT 1
|
|
109
|
+
FROM retained_manifests retained
|
|
110
|
+
WHERE retained.digest = me.parent_digest
|
|
111
|
+
OR retained.digest = me.child_digest
|
|
112
|
+
)
|
|
117
113
|
),
|
|
118
114
|
delete_component_members AS (
|
|
119
115
|
SELECT
|
|
120
|
-
seed.source_version_id,
|
|
121
116
|
seed.source_digest,
|
|
122
117
|
seed.member_digest
|
|
123
118
|
FROM closure_seed seed
|
|
@@ -125,19 +120,15 @@ export const _LIST_CLOSURE_MANIFESTS_SQL = `
|
|
|
125
120
|
UNION
|
|
126
121
|
|
|
127
122
|
SELECT
|
|
128
|
-
walk.source_version_id,
|
|
129
123
|
walk.source_digest,
|
|
130
|
-
|
|
124
|
+
edge.target_digest AS member_digest
|
|
131
125
|
FROM delete_component_members walk
|
|
132
126
|
JOIN undirected_edges edge
|
|
133
127
|
ON edge.source_digest = walk.member_digest
|
|
134
|
-
JOIN manifests m
|
|
135
|
-
ON m.scan_id = ?
|
|
136
|
-
AND m.digest = edge.target_digest
|
|
137
128
|
WHERE NOT EXISTS (
|
|
138
129
|
SELECT 1
|
|
139
130
|
FROM retained_manifests retained
|
|
140
|
-
WHERE retained.digest =
|
|
131
|
+
WHERE retained.digest = edge.target_digest
|
|
141
132
|
)
|
|
142
133
|
),
|
|
143
134
|
source_seed_hops AS (
|
|
@@ -157,7 +148,7 @@ export const _LIST_CLOSURE_MANIFESTS_SQL = `
|
|
|
157
148
|
GROUP BY dtc.source_digest, dtc.member_digest
|
|
158
149
|
)
|
|
159
150
|
SELECT
|
|
160
|
-
|
|
151
|
+
dtr.root_version_id AS source_version_id,
|
|
161
152
|
walk.source_digest,
|
|
162
153
|
MIN(member_manifest.version_id) AS member_version_id,
|
|
163
154
|
walk.member_digest,
|
|
@@ -177,6 +168,8 @@ export const _LIST_CLOSURE_MANIFESTS_SQL = `
|
|
|
177
168
|
ELSE 'connected'
|
|
178
169
|
END AS member_role
|
|
179
170
|
FROM delete_component_members walk
|
|
171
|
+
JOIN temp_direct_target_roots dtr
|
|
172
|
+
ON dtr.root_digest = walk.source_digest
|
|
180
173
|
JOIN manifests member_manifest
|
|
181
174
|
ON member_manifest.scan_id = ?
|
|
182
175
|
AND member_manifest.digest = walk.member_digest
|
|
@@ -186,7 +179,7 @@ export const _LIST_CLOSURE_MANIFESTS_SQL = `
|
|
|
186
179
|
ON descendant_hops.source_digest = walk.source_digest
|
|
187
180
|
AND descendant_hops.member_digest = walk.member_digest
|
|
188
181
|
GROUP BY
|
|
189
|
-
|
|
182
|
+
dtr.root_version_id,
|
|
190
183
|
walk.source_digest,
|
|
191
184
|
walk.member_digest,
|
|
192
185
|
descendant_hops.min_hops_from_root,
|
|
@@ -47,7 +47,7 @@ export class PlannerPlanArtifacts {
|
|
|
47
47
|
}
|
|
48
48
|
#listClosureManifests(scanId) {
|
|
49
49
|
return this.#sql
|
|
50
|
-
.all(_LIST_CLOSURE_MANIFESTS_SQL, [scanId, scanId, scanId, scanId, scanId, scanId, scanId
|
|
50
|
+
.all(_LIST_CLOSURE_MANIFESTS_SQL, [scanId, scanId, scanId, scanId, scanId, scanId, scanId])
|
|
51
51
|
.map(mapClosureManifestRow);
|
|
52
52
|
}
|
|
53
53
|
#listBlockedRoots(scanId) {
|
package/package.json
CHANGED
|
@@ -204,10 +204,16 @@ CREATE INDEX IF NOT EXISTS idx_cleanup_runs_scan_id ON cleanup_runs(scan_id);
|
|
|
204
204
|
CREATE INDEX IF NOT EXISTS idx_cleanup_protected_root_blocks_run_blocked
|
|
205
205
|
ON cleanup_protected_root_blocks(cleanup_run_id, blocked_digest);
|
|
206
206
|
CREATE INDEX IF NOT EXISTS idx_tags_scan_version ON tags(scan_id, version_id);
|
|
207
|
+
CREATE INDEX IF NOT EXISTS idx_tags_scan_version_nondigest
|
|
208
|
+
ON tags(scan_id, version_id)
|
|
209
|
+
WHERE is_digest_tag = 0;
|
|
207
210
|
CREATE INDEX IF NOT EXISTS idx_manifest_descriptors_scan_child ON manifest_descriptors(scan_id, child_digest);
|
|
208
211
|
CREATE INDEX IF NOT EXISTS idx_manifest_edges_scan_parent ON manifest_edges(scan_id, parent_digest);
|
|
209
212
|
CREATE INDEX IF NOT EXISTS idx_manifest_edges_scan_child ON manifest_edges(scan_id, child_digest);
|
|
210
213
|
CREATE INDEX IF NOT EXISTS idx_manifest_edges_scan_child_kind ON manifest_edges(scan_id, child_digest, edge_kind);
|
|
214
|
+
CREATE INDEX IF NOT EXISTS idx_manifest_edges_scan_child_nondigest_referrer
|
|
215
|
+
ON manifest_edges(scan_id, child_digest)
|
|
216
|
+
WHERE edge_kind != 'digest-tag-referrer';
|
|
211
217
|
CREATE INDEX IF NOT EXISTS idx_manifest_reachability_scan_descendant
|
|
212
218
|
ON manifest_reachability(scan_id, descendant_digest);
|
|
213
219
|
CREATE INDEX IF NOT EXISTS idx_manifest_reachability_scan_descendant_distance
|