Skip to content

Commit c7049c3

Browse files
authored
feat: rc.1 fixes — GLOB default alignment, commit-pinned image promotion, weekly interim image cleanup (#229)
## Summary - Aligns `RepoPermission` Java model default `matchType` to `GLOB`, matching the YAML config path default — permissions created via REST API now behave identically to those loaded from config - Pins Docker release promotion to `build-{sha7}` (commit-stable) instead of `:edge`, eliminating the race condition where edge moves forward between tag cut and workflow run - Adds `build-{sha7}` tag on every main push alongside `:edge` - Adds weekly cleanup workflow (`cleanup-interim-images.yml`) that deletes GHCR versions exclusively tagged `build-*`; protected tags (`v*`, `edge`, `latest`, untagged) are never touched; serialised with main push via concurrency group - Gradle version bumped to `1.0.0-rc.1` Closes #193 ## Test plan - [ ] CI passes - [ ] Docker Build & Publish produces both `:edge` and `build-{sha7}` tags on merge - [ ] Cleanup workflow can be triggered manually via `workflow_dispatch` to verify dry-run behaviour before first scheduled run
2 parents 618d083 + 29fc237 commit c7049c3

7 files changed

Lines changed: 112 additions & 25 deletions

File tree

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ concurrency:
1515

1616
jobs:
1717
build-and-test:
18-
name: CI / Build & Test
18+
name: Build & Test
1919
runs-on: ubuntu-latest
2020
permissions:
2121
contents: read
@@ -58,7 +58,7 @@ jobs:
5858
retention-days: 14
5959

6060
docker-smoke-test:
61-
name: CI / Docker Smoke Test (${{ matrix.db }})
61+
name: Docker Smoke Test (${{ matrix.db }})
6262
runs-on: ubuntu-latest
6363
if: >
6464
github.ref == 'refs/heads/main' ||
@@ -121,7 +121,7 @@ jobs:
121121
fi
122122
123123
dependency-submission:
124-
name: CI / Dependency Submission
124+
name: Dependency Submission
125125
runs-on: ubuntu-latest
126126
if: github.event_name == 'push'
127127
permissions:
@@ -140,7 +140,7 @@ jobs:
140140
uses: gradle/actions/dependency-submission@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # ratchet:gradle/actions/dependency-submission@v6
141141

142142
e2e-test:
143-
name: CI / E2E Test
143+
name: E2E Test
144144
runs-on: ubuntu-latest
145145
# E2E tests spin up containers; only run on push/PR to the main branches
146146
# to avoid burning minutes on every feature branch commit.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
name: Cleanup Interim Images
2+
3+
# Deletes GHCR package versions whose tags are exclusively build-* (ephemeral
4+
# per-commit images). Versions carrying any other tag (v*, edge, latest, etc.)
5+
# are never touched. Runs weekly and can be triggered manually.
6+
7+
on:
8+
schedule:
9+
- cron: '0 8 * * 1' # Monday 08:00 UTC
10+
workflow_dispatch:
11+
12+
# Serialise with docker-publish to avoid deleting a build-* image that a
13+
# concurrent release promotion is about to resolve. cancel-in-progress: false
14+
# makes cleanup wait rather than be killed.
15+
concurrency:
16+
group: docker-refs/heads/main
17+
cancel-in-progress: false
18+
19+
permissions:
20+
contents: read
21+
packages: write
22+
23+
jobs:
24+
cleanup:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- name: Delete stale build-* package versions
28+
env:
29+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30+
run: |
31+
OWNER="${{ github.repository_owner }}"
32+
PACKAGE="${{ github.event.repository.name }}"
33+
DELETED=0
34+
KEPT=0
35+
36+
echo "Fetching package versions for ${OWNER}/${PACKAGE}..."
37+
38+
# Collect all versions into a temp file (handles pagination via --paginate)
39+
gh api \
40+
-H "Accept: application/vnd.github+json" \
41+
"/users/${OWNER}/packages/container/${PACKAGE}/versions" \
42+
--paginate > /tmp/versions.json
43+
44+
TOTAL=$(jq 'length' /tmp/versions.json)
45+
echo "Found ${TOTAL} total package versions."
46+
echo ""
47+
48+
jq -c '.[]' /tmp/versions.json | while read -r version; do
49+
VERSION_ID=$(echo "$version" | jq -r '.id')
50+
TAGS=$(echo "$version" | jq -r '.metadata.container.tags // [] | .[]')
51+
52+
# Skip untagged versions — never delete them (likely referenced by a manifest list)
53+
if [ -z "$TAGS" ]; then
54+
echo "KEEP [${VERSION_ID}] (untagged)"
55+
continue
56+
fi
57+
58+
TAG_LIST=$(echo "$TAGS" | tr '\n' ' ' | sed 's/ $//')
59+
60+
# Guard: keep if ANY tag does not match build-[0-9a-f]+
61+
PROTECTED=false
62+
while IFS= read -r tag; do
63+
if [[ ! "$tag" =~ ^build-[0-9a-f]+$ ]]; then
64+
PROTECTED=true
65+
break
66+
fi
67+
done <<< "$TAGS"
68+
69+
if [ "$PROTECTED" = true ]; then
70+
echo "KEEP [${VERSION_ID}] tags: ${TAG_LIST}"
71+
else
72+
echo "DELETE [${VERSION_ID}] tags: ${TAG_LIST}"
73+
gh api \
74+
--method DELETE \
75+
-H "Accept: application/vnd.github+json" \
76+
"/users/${OWNER}/packages/container/${PACKAGE}/versions/${VERSION_ID}"
77+
fi
78+
done
79+
80+
echo ""
81+
echo "Cleanup complete."

.github/workflows/codeql.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ on:
1212

1313
jobs:
1414
analyze:
15-
name: CodeQL / ${{ matrix.language }}
15+
name: ${{ matrix.language }}
1616
runs-on: ubuntu-latest
1717
permissions:
1818
security-events: write

.github/workflows/cve.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ on:
1111

1212
jobs:
1313
grype-npm:
14-
name: CVE / npm
14+
name: npm
1515
runs-on: ubuntu-latest
1616
permissions:
1717
contents: read
@@ -56,7 +56,7 @@ jobs:
5656
retention-days: 30
5757

5858
grype-gradle:
59-
name: CVE / Gradle
59+
name: Gradle
6060
if: true
6161
runs-on: ubuntu-latest
6262
permissions:
@@ -103,7 +103,7 @@ jobs:
103103
retention-days: 30
104104

105105
depcheck:
106-
name: CVE / Dependency Check (Gradle)
106+
name: Dependency Check (Gradle)
107107
if: false # disabled — NVD API reliability issues; re-enable when stable
108108
runs-on: ubuntu-latest
109109
permissions:

.github/workflows/docker-publish.yml

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ concurrency:
2222

2323
jobs:
2424
build-and-push:
25-
# Tags are released by promoting the already-built edge image — no rebuild needed.
25+
name: Build & Push
26+
# Tags are released by promoting the already-built build image — no rebuild needed.
2627
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
2728
runs-on: ubuntu-latest
2829
outputs:
@@ -55,6 +56,7 @@ jobs:
5556
tags: |
5657
type=ref,event=pr
5758
type=raw,value=edge,enable={{is_default_branch}}
59+
type=sha,prefix=build-,format=short,enable={{is_default_branch}}
5860
type=raw,value=${{ inputs.version }},enable=${{ github.event_name == 'workflow_dispatch' }}
5961
6062
- name: Build and push
@@ -153,21 +155,25 @@ jobs:
153155
grep "grype_${GRYPE_VERSION}_linux_amd64.tar.gz" "grype_${GRYPE_VERSION}_checksums.txt" | sha256sum --check
154156
tar -xzf "grype_${GRYPE_VERSION}_linux_amd64.tar.gz" -C /usr/local/bin grype
155157
156-
# Resolve the digest of the already-built, already-scanned edge image.
157-
# The tag ruleset enforces Container Scan passed on this commit before the tag
158-
# could be pushed, so edge is guaranteed clean at this point.
159-
- name: Resolve edge digest
160-
id: edge
158+
# Resolve the digest of the build-{sha} image produced when this commit landed on main.
159+
# The tag ruleset enforces Container Scan passed on this commit before the tag could be
160+
# pushed, so the build image is guaranteed scanned. Using the commit-pinned build tag
161+
# (not :edge) ensures we promote the exact image for this release regardless of how
162+
# many commits have landed on main since.
163+
- name: Resolve build image digest
164+
id: build
161165
run: |
166+
TAG="build-${GITHUB_SHA::7}"
162167
DIGEST=$(docker buildx imagetools inspect \
163-
ghcr.io/${{ github.repository }}:edge \
168+
"ghcr.io/${{ github.repository }}:${TAG}" \
164169
--format '{{.Manifest.Digest}}')
165170
echo "digest=${DIGEST}" >> "$GITHUB_OUTPUT"
166-
echo "Promoting edge digest: ${DIGEST}"
171+
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
172+
echo "Promoting ${TAG} @ ${DIGEST}"
167173
168-
- name: Scan edge image
174+
- name: Scan build image
169175
run: |
170-
grype ghcr.io/${{ github.repository }}@${{ steps.edge.outputs.digest }} \
176+
grype "ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}" \
171177
--config .grype.yaml \
172178
-o "template=grype-report.txt" \
173179
-o "json=grype-report.json"
@@ -182,12 +188,12 @@ jobs:
182188
grype-report.json
183189
retention-days: 90
184190

185-
- name: Promote edge to release tags
191+
- name: Promote build image to release tags
186192
run: |
187193
VERSION=${GITHUB_REF_NAME}
188194
MAJOR=$(echo ${VERSION} | cut -d. -f1)
189195
MINOR=$(echo ${VERSION} | cut -d. -f1-2)
190-
SOURCE="ghcr.io/${{ github.repository }}@${{ steps.edge.outputs.digest }}"
196+
SOURCE="ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}"
191197
docker buildx imagetools create \
192198
--tag "ghcr.io/${{ github.repository }}:${VERSION}" \
193199
--tag "ghcr.io/${{ github.repository }}:${MINOR}" \

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ ext {
7979

8080
allprojects {
8181
group = 'org.finos.gitproxy'
82-
version = '1.0.0-beta.7'
82+
version = '1.0.0-rc.1'
8383

8484
repositories {
8585
mavenCentral()

git-proxy-java-core/src/main/java/org/finos/gitproxy/permission/RepoPermission.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
* {@link #value} at {@link #provider}.
1414
*
1515
* <p>{@link #target} selects which part of the repo URL is compared (default {@link MatchTarget#SLUG});
16-
* {@link #matchType} controls how {@link #value} is interpreted: {@code LITERAL} for exact equality, {@code GLOB} for
17-
* {@code *}/{@code ?} wildcards, {@code REGEX} for full Java regex.
16+
* {@link #matchType} controls how {@link #value} is interpreted: {@code GLOB} for {@code *}/{@code ?} wildcards
17+
* (default), {@code LITERAL} for exact equality, {@code REGEX} for full Java regex.
1818
*/
1919
@Data
2020
@Builder
@@ -35,9 +35,9 @@ public class RepoPermission {
3535
/** Pattern to match against the {@link #target} portion of the URL. */
3636
private String value;
3737

38-
/** How {@link #value} is interpreted when matching. Defaults to {@link MatchType#LITERAL}. */
38+
/** How {@link #value} is interpreted when matching. Defaults to {@link MatchType#GLOB}. */
3939
@Builder.Default
40-
private MatchType matchType = MatchType.LITERAL;
40+
private MatchType matchType = MatchType.GLOB;
4141

4242
@Builder.Default
4343
private Operations operations = Operations.PUSH;

0 commit comments

Comments
 (0)