Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e55b086
Fix foreground reads joining skipped refreshes
cramen Sep 21, 2026
a2dc8ad
Preserve tagged write outcomes and atomically replace tag metadata
cramen Sep 21, 2026
817f739
Isolate Redis namespaces with v2 keys and align tagged expiry
cramen Sep 21, 2026
969162a
Move invalidation recovery outside state monitors
cramen Sep 22, 2026
db55676
Recover pending Streams invalidations before acknowledging gaps
cramen Sep 22, 2026
f33cca7
Close owned cache resources safely across lifecycle races
cramen Sep 22, 2026
719b1b0
Bind L1 freshness to entry lifetime and atomically refresh access expiry
cramen Sep 22, 2026
077fc12
Complete Spring async cache retrieval through managed factory views
cramen Sep 22, 2026
9db41b3
Validate invalidation journal capacity against cursor cadence
cramen Sep 22, 2026
5c05eb1
Observe invalidation publication outcomes with bounded diagnostics
cramen Sep 22, 2026
b9bbe5f
Preserve JMX registration ownership and locale-independent metric tags
cramen Sep 22, 2026
32facac
Repair soak memory measurements and worker completion checks
cramen Sep 22, 2026
22aa973
Add server, Spring consumer and Sentinel compatibility matrix
cramen Sep 22, 2026
fd310ac
Verify resolved release dependencies and exact artifact evidence
cramen Sep 22, 2026
ad364b4
Update vulnerable Micrometer and align Netty dependencies
cramen Sep 22, 2026
3601d83
Align cache documentation with verified runtime and release contracts
cramen Sep 23, 2026
e79630a
docs: remove claims that JetCache is unmaintained
cramen Sep 23, 2026
9e6d863
Prepare 2.0.0 release with Redis keyspace v2 migration
cramen Sep 23, 2026
a04b944
Fix release checks for shaded caches and Linux Sentinel fixtures
cramen Sep 23, 2026
ad0cbfa
Keep Sentinel fixture addresses stable across container failures
cramen Sep 23, 2026
29a1e9a
Handle networks without IPAM subnets in Sentinel fixture
cramen Sep 23, 2026
b01f370
Wait for closed breakers before Sentinel recovery assertions
cramen Sep 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,44 @@ jobs:
run: |
./gradlew build --offline -x :tiercache-tck:test -x :tiercache-transport-redis:test -x :examples:demo-spring:test
./gradlew :tiercache-core:shadowJar --offline

server-contracts:
runs-on: ubuntu-latest
timeout-minutes: 25
strategy:
fail-fast: false
matrix:
profile: [redis62, redis74, redis8, valkey]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '17'
- uses: gradle/actions/setup-gradle@v6.3.0
- run: python3 compatibility/run-server-matrix.py ${{ matrix.profile }}
- uses: actions/upload-artifact@v7
if: always()
with:
name: server-${{ matrix.profile }}
path: build/compatibility-evidence/
if-no-files-found: error

spring-consumers:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '17'
- uses: gradle/actions/setup-gradle@v6.3.0
- run: ./gradlew stageCompatibilityArtifacts
- run: python3 compatibility/run-consumers.py
- uses: actions/upload-artifact@v7
if: always()
with:
name: spring-consumers
path: build/compatibility-evidence/
if-no-files-found: error
61 changes: 47 additions & 14 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,27 +105,40 @@ jobs:
fi
echo "reproducible build OK: $HASH_A"

# CVE scan (supply-chain design D4): daily Trivy filesystem scan.
# Non-blocking by design (exit-code 0) - release gating comes later.
# Resolve the published runtime/classifier graphs; source-only scanning is insufficient.
cve-scan:
runs-on: ubuntu-latest
timeout-minutes: 40
permissions:
contents: read
steps:
- uses: actions/checkout@v7
- name: Trivy filesystem scan (HIGH,CRITICAL)
uses: aquasecurity/trivy-action@v0.36.0
with:
scan-type: fs
scan-ref: .
severity: HIGH,CRITICAL
format: table
output: trivy-report.txt
exit-code: '0'
with:
persist-credentials: false
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '17'
- uses: gradle/actions/setup-gradle@v6.3.0
- run: python3 -m unittest discover -s scripts/release -p 'test_*.py' -v
- run: ./gradlew releaseEvidenceInputs --max-workers=2
- run: python3 scripts/release/install_trivy.py "$RUNNER_TEMP/trivy"
- run: python3 scripts/release/evidence.py scan --trivy "$RUNNER_TEMP/trivy/trivy" --output build/release-scan --exceptions scripts/release/exceptions.json
- name: Append report to job summary
run: cat trivy-report.txt >> "$GITHUB_STEP_SUMMARY"
if: always()
run: |
if [ -f build/release-scan/summary.txt ]; then cat build/release-scan/summary.txt >> "$GITHUB_STEP_SUMMARY"; fi
- uses: actions/upload-artifact@v7
if: always()
with:
name: trivy-report
path: trivy-report.txt
name: dependency-scan
path: |
build/release-inputs/
build/release-scan/*.json
build/release-scan/*.log
build/release-scan/*.txt
**/build/reports/cyclonedx/*-sbom.json
if-no-files-found: error
retention-days: 90

native-smoke:
Expand Down Expand Up @@ -179,3 +192,23 @@ jobs:
name: native-smoke-log
path: native-smoke.log
retention-days: 30

sentinel-regression:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '17'
- uses: gradle/actions/setup-gradle@v6.3.0
- run: ./gradlew :tiercache-spring-boot-starter:sentinelRuntime
- run: docker pull eclipse-temurin:17-jre
- run: python3 compatibility/run-sentinel.py
- uses: actions/upload-artifact@v7
if: always()
with:
name: sentinel-regression
path: build/compatibility-evidence/
if-no-files-found: error
182 changes: 120 additions & 62 deletions .github/workflows/release-candidate.yml
Original file line number Diff line number Diff line change
@@ -1,87 +1,145 @@
name: release-candidate

# Manual trigger only: builds the publishable module jars, signs them with
# Sigstore keyless (GitHub Actions OIDC identity, no stored keys), and creates
# GitHub Artifact Attestations (SLSA-style build provenance).
on:
workflow_dispatch:
inputs:
source_ref:
description: 'Source commit/ref; final mode requires refs/tags/v<version>'
required: true
type: string
version:
description: 'Must equal the checked-out gradle.properties version'
required: true
type: string
mode:
description: 'Trial accepts development snapshots; final attaches evidence to an existing release'
required: true
default: trial
type: choice
options: [trial, final]

permissions:
contents: read
id-token: write
attestations: write
permissions: {}

jobs:
build-sign-attest:
build-scan:
outputs:
source_commit: ${{ steps.source.outputs.commit }}
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
contents: read
steps:
- uses: actions/checkout@v7
with:
ref: ${{ inputs.source_ref }}
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '17'
- uses: gradle/actions/setup-gradle@v6.3.0

# Tests are covered by ci.yml; this workflow only assembles the
# publishable artifact set. shadowJar is listed explicitly because the
# shaded jar is the main core artifact (the plain jar keeps the
# `unshaded` classifier).
- name: Build module jars
run: ./gradlew build -x test :tiercache-core:shadowJar

# Publishable set: the seven library module jars (core shaded + unshaded)
# plus the TCK compliance-suite jar (`tests` classifier), excluding
# jmh/test-fixtures jars, the plain TCK jar, and the demo app.
- name: Stage artifacts
- name: Check source and version identity
id: source
env:
SOURCE_REF: ${{ inputs.source_ref }}
INTENDED_VERSION: ${{ inputs.version }}
EVIDENCE_MODE: ${{ inputs.mode }}
run: |
set -euo pipefail
mkdir -p dist
cp tiercache-core/build/libs/tiercache-core-*.jar dist/
rm -f dist/*-jmh.jar dist/*-test-fixtures.jar
for module in tiercache-invalidation tiercache-transport-redis tiercache-spring-boot-starter tiercache-micrometer tiercache-kotlin tiercache-reactor tiercache-micronaut; do
cp "$module/build/libs/$module"-*.jar dist/
done
cp tiercache-tck/build/libs/tiercache-tck-*-tests.jar dist/
ls -l dist/

# SLSA-style build provenance as GitHub Artifact Attestations.
- uses: actions/attest-build-provenance@v4
python3 scripts/release/evidence.py identity --ref "$SOURCE_REF" --version "$INTENDED_VERSION" --mode "$EVIDENCE_MODE"
echo "commit=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Evidence regression tests
run: python3 -m unittest discover -s scripts/release -p 'test_*.py' -v
- name: Build fresh publication inputs and resolved SBOMs
run: ./gradlew clean releaseEvidenceInputs --no-build-cache --max-workers=2
- name: Install checksum-pinned scanner
run: python3 scripts/release/install_trivy.py "$RUNNER_TEMP/trivy"
- name: Scan and enforce acceptance
run: python3 scripts/release/evidence.py scan --trivy "$RUNNER_TEMP/trivy/trivy" --output build/release-scan --exceptions scripts/release/exceptions.json
- name: Stage exact current-run evidence
env:
SOURCE_REF: ${{ inputs.source_ref }}
INTENDED_VERSION: ${{ inputs.version }}
EVIDENCE_MODE: ${{ inputs.mode }}
run: python3 scripts/release/evidence.py stage --scan build/release-scan --output dist --ref "$SOURCE_REF" --version "$INTENDED_VERSION" --mode "$EVIDENCE_MODE"
- uses: actions/upload-artifact@v7
with:
subject-path: 'dist/*.jar'

- uses: sigstore/cosign-installer@v4.1.2

# Keyless signing via the runner's OIDC identity. Cosign v3 requires
# --bundle: each jar gets a <jar>.sigstore.json bundle holding the
# signature, certificate, and transparency-log proof.
- name: Sign jars (cosign keyless)
name: candidate-inputs
path: dist/
if-no-files-found: error
retention-days: 7
- name: Keep scan diagnostics even on rejection
uses: actions/upload-artifact@v7
if: always()
with:
name: dependency-scan
path: |
build/release-inputs/
build/release-scan/*.json
build/release-scan/*.log
build/release-scan/*.txt
**/build/reports/cyclonedx/*-sbom.json
if-no-files-found: error
retention-days: 90
- name: Scan summary
if: always()
run: |
set -euo pipefail
cd dist
for jar in *.jar; do
cosign sign-blob --yes --bundle "$jar.sigstore.json" "$jar"
done
if [ -f build/release-scan/summary.txt ]; then cat build/release-scan/summary.txt >> "$GITHUB_STEP_SUMMARY"; fi

sign-attest:
needs: build-scan
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
id-token: write
attestations: write
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.build-scan.outputs.source_commit }}
persist-credentials: false
- uses: actions/download-artifact@v8
with:
name: candidate-inputs
path: dist
- run: python3 scripts/release/evidence.py verify dist
- name: Package the complete manifest-covered bundle
run: |
mkdir signed
tar -czf signed/tiercache-evidence.tar.gz -C dist .
- uses: sigstore/cosign-installer@v4.1.2
- name: Sign all evidence bytes as one bundle
run: timeout 300 cosign sign-blob --yes --bundle signed/tiercache-evidence.sigstore.json signed/tiercache-evidence.tar.gz
- uses: actions/attest-build-provenance@v4
with:
subject-path: signed/tiercache-evidence.tar.gz
- uses: actions/upload-artifact@v7
with:
name: release-candidate
path: dist/
path: signed/
if-no-files-found: error
retention-days: 90

- name: Print verification commands
retain-with-release:
if: inputs.mode == 'final'
needs: sign-attest
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
steps:
- uses: actions/download-artifact@v8
with:
name: release-candidate
path: signed
# Requires an existing release (draft is allowed); creates no release,
# changes no published artifact, and does not upload to Maven Central.
- name: Attach immutable evidence to the existing release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
INTENDED_VERSION: ${{ inputs.version }}
run: |
cat <<EOF
Artifacts: download the 'release-candidate' artifact from this run (jars + .sigstore.json bundles).

Verify a jar's signature (keyless, bound to this workflow's OIDC identity):

cosign verify-blob \\
--bundle <jar>.sigstore.json \\
--certificate-identity-regexp '^https://github.com/${{ github.repository }}/\\.github/workflows/release-candidate\\.yml@.*' \\
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \\
<jar>

Verify a jar's build provenance (GitHub Artifact Attestations):

gh attestation verify <jar> --repo ${{ github.repository }}
EOF
gh release view "v$INTENDED_VERSION"
gh release upload "v$INTENDED_VERSION" signed/tiercache-evidence.tar.gz signed/tiercache-evidence.sigstore.json
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ out/
.classpath
.project
.settings/
.agents

# OS
.DS_Store
Expand Down
Loading
Loading