chore: record pre-existing uncommitted repository state
Snapshot of the in-flight state that already existed, identically, in both this worktree and the main checkout before this session began: the initial HTTP Client platform implementation (previously untracked), the redis-lab removal, and the JPA / object-storage / notification integration work. Kept separate from this session's HTTP Client review response, which lands in the following commit, so the two bodies of work stay reviewable apart. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1a3b560678
commit
5f10b791d3
@@ -21,6 +21,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- name: Require the committed public-path security baseline
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -44,12 +47,18 @@ jobs:
|
||||
src/**/gradle.lockfile
|
||||
- name: Check quality, public paths, and dependency locks
|
||||
working-directory: src
|
||||
run: ./gradlew check verifyPublicPathSnapshot verifyDependencyLocks --no-daemon --stacktrace
|
||||
run: ./gradlew check verifyPublicPathSnapshot verifyDependencyLocks --warning-mode=fail --no-daemon --stacktrace
|
||||
- name: Qualify opt-in inbound transports without skips
|
||||
working-directory: src
|
||||
run: ./gradlew conditionalTransportQualification --no-daemon --stacktrace
|
||||
|
||||
sample-off:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
@@ -70,10 +79,13 @@ jobs:
|
||||
- name: Verify the gate matrix against the repository
|
||||
run: bash .github/scripts/verify-gate-matrix.sh
|
||||
|
||||
redis-standalone:
|
||||
redis-sdk:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
@@ -83,14 +95,15 @@ jobs:
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Verify standalone Redis policy, provider, and composition contracts
|
||||
# Milestone A of the Redis wrapper/typed API plan: policy catalog, typed API parity,
|
||||
# permit provenance, connection isolation, and the executor guard. There is no real-server
|
||||
# lane yet — Tasks 10-17 add the contract suites that need one.
|
||||
- name: Verify the Redis SDK policy, API parity, and guardrail contracts
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:application-core:redisPolicyContractTest
|
||||
:shared-contract:edgeRateLimitContractTest
|
||||
:adapter:outbound:cache-redis:check
|
||||
:app-bootstrap:redisCompositionTest
|
||||
verifyCleanArchitectureDependencies
|
||||
verifyEnvKeys
|
||||
verifyPublicPathSnapshot
|
||||
@@ -102,6 +115,9 @@ jobs:
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
@@ -132,6 +148,9 @@ jobs:
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
@@ -150,7 +169,7 @@ jobs:
|
||||
- quality-gates
|
||||
- sample-off
|
||||
- gate-matrix-lint
|
||||
- redis-standalone
|
||||
- redis-sdk
|
||||
- jpa-candidate-evidence
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
@@ -160,7 +179,7 @@ jobs:
|
||||
QUALITY_RESULT: ${{ needs.quality-gates.result }}
|
||||
SAMPLE_OFF_RESULT: ${{ needs.sample-off.result }}
|
||||
MATRIX_RESULT: ${{ needs.gate-matrix-lint.result }}
|
||||
REDIS_RESULT: ${{ needs.redis-standalone.result }}
|
||||
REDIS_RESULT: ${{ needs.redis-sdk.result }}
|
||||
JPA_CANDIDATE_RESULT: ${{ needs.jpa-candidate-evidence.result }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -35,6 +35,9 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
name: fileserver-nightly
|
||||
|
||||
# The environments that cannot run on every pull request: a real network filesystem, a foreign
|
||||
# filesystem, and the long-running fault matrices. They are nightly rather than skipped because a
|
||||
# green pull-request run is not certification of any of them.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 18 * * *'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
fileserver-nfs-ambiguity:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
FILESERVER_NFS_TESTS: "true"
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Start the NFSv4 certification environment
|
||||
run: docker compose -f infra/fileserver/nfs/compose.yml up -d --wait
|
||||
- name: Run the network-filesystem ambiguity suite
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:adapter:outbound:fileserver:test --tests '*NfsAmbiguityIntegrationTest'
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
- name: Tear down the NFS environment
|
||||
if: always()
|
||||
run: docker compose -f infra/fileserver/nfs/compose.yml down -v
|
||||
|
||||
fileserver-process-kill-matrix:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Run the crash matrix and reconciliation suites
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:adapter:outbound:fileserver:test --tests '*CrashRecoveryMatrixTest'
|
||||
:application-core:test --tests '*FileReconciliationServiceTest'
|
||||
--rerun-tasks
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
|
||||
fileserver-large-file-performance:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Run the large-file and slow-client suites under a constrained heap
|
||||
working-directory: src
|
||||
env:
|
||||
GRADLE_OPTS: -Xmx512m
|
||||
run: >-
|
||||
./gradlew
|
||||
:adapter:outbound:fileserver:test --tests '*LargeFileBoundedMemoryTest'
|
||||
:adapter:outbound:fileserver:test --tests '*LocalAppendMemoryTest'
|
||||
--rerun-tasks
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
|
||||
fileserver-multi-instance-lease:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Prove no run commits bytes from a stale lease
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:application-core:test --tests '*MultiInstanceWriterLeaseTest'
|
||||
--rerun-tasks
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
@@ -0,0 +1,164 @@
|
||||
name: fileserver-pr
|
||||
|
||||
# Every claim in docs/fileserver/support-matrix.md that says "Stable" is backed by a job here.
|
||||
# A support level with no job behind it is a marketing claim, not an engineering one, and
|
||||
# DocumentationCoverageTest fails the build when the two drift apart.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'src/application-core/src/**/fileserver/**'
|
||||
- 'src/adapter/inbound/web/src/**/fileserver/**'
|
||||
- 'src/adapter/outbound/fileserver/**'
|
||||
- 'src/adapter/outbound/persistence-jpa/src/**/fileserver/**'
|
||||
- 'src/app-bootstrap/src/**/fileserver/**'
|
||||
- 'docs/fileserver/**'
|
||||
# The capability is not only its Java files. A change to the bound settings, the shipped
|
||||
# environment, the registry that documents it, or the container that has to give it a
|
||||
# writable volume changes how it behaves at runtime just as surely — and those were the
|
||||
# exact files that could previously ship unverified.
|
||||
- 'src/app-bootstrap/src/main/resources/application.yml'
|
||||
- 'src/.env'
|
||||
- 'docs/registries/env-keys.yaml'
|
||||
- 'src/Dockerfile'
|
||||
- 'docker-compose.yml'
|
||||
- 'infra/nginx/**'
|
||||
- 'infra/k8s/**'
|
||||
- '.github/workflows/fileserver-pr.yml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
fileserver-unit-and-architecture:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Run the fileserver application and architecture suites
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:application-core:test
|
||||
:app-bootstrap:test --tests '*CleanArchitectureTest' --tests '*Fileserver*'
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
|
||||
fileserver-local-ext4-contract:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Certify the local content store against the shared contract
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:adapter:outbound:fileserver:test
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
|
||||
fileserver-http-contract:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Run the servlet and reactive transport contracts
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:adapter:inbound:web:test
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
|
||||
fileserver-security-suite:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Run the path, filename, range, and problem-detail hardening suite
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:adapter:inbound:web:test --tests '*FileserverHardeningContractTest'
|
||||
:adapter:outbound:fileserver:test --tests '*PhysicalPathResolverTest'
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
|
||||
fileserver-bounded-memory:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Prove transfer cost does not scale with file size
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:adapter:outbound:fileserver:test --tests '*LargeFileBoundedMemoryTest'
|
||||
:adapter:inbound:web:test --tests '*DataBufferReleaseTest'
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
@@ -0,0 +1,143 @@
|
||||
name: fileserver-release
|
||||
|
||||
# The gate a release must clear. Its job list is deliberately the same shape as the support matrix:
|
||||
# nothing may be advertised at a support level whose evidence job is absent here.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
fileserver-full-verification:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Run the architecture-wide dependency and module verification
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
verifyCleanArchitectureDependencies
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
- name: Run the complete fileserver suite across every leaf
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:application-core:check
|
||||
:adapter:inbound:web:check
|
||||
:adapter:outbound:fileserver:check
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
|
||||
fileserver-documentation-gate:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Prove every support claim maps to a job and every endpoint is documented
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:app-bootstrap:test --tests '*FileserverDocumentationCoverageTest'
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
|
||||
fileserver-pvc-certification:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
# Two different things, kept apart on purpose. The manifest checks below run everywhere and
|
||||
# fail on real drift; the cluster run needs a cluster and is skipped without one. The job
|
||||
# used to `test -f` the manifest and report success, which read as "ReadWriteOnce certified"
|
||||
# when nothing had been applied anywhere.
|
||||
- name: Check the certification manifest still says what the claim depends on
|
||||
run: |
|
||||
set -euo pipefail
|
||||
manifest=infra/fileserver/kubernetes/pvc-certification-job.yaml
|
||||
test -f "$manifest"
|
||||
grep -q 'kind: PersistentVolumeClaim' "$manifest"
|
||||
grep -q 'kind: Job' "$manifest"
|
||||
# ReadWriteMany is explicitly not claimed; a manifest that quietly widened the access
|
||||
# mode would certify a topology the support matrix says is uncertified.
|
||||
grep -q 'ReadWriteOnce' "$manifest"
|
||||
! grep -q 'ReadWriteMany' "$manifest"
|
||||
- name: Certify the ReadWriteOnce claim on the release cluster
|
||||
id: pvc-cluster-run
|
||||
env:
|
||||
KUBECONFIG_CONTENT: ${{ secrets.FILESERVER_PVC_KUBECONFIG }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ -z "${KUBECONFIG_CONTENT:-}" ]; then
|
||||
echo "::warning::no release cluster configured; PVC certification was NOT run."
|
||||
echo "The support matrix records this profile as Limited for exactly this reason:"
|
||||
echo "the cluster result is produced by an operator against a real cluster and read"
|
||||
echo "from docs/fileserver/storage-certification.md, not by this job."
|
||||
echo "certified=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
printf '%s' "$KUBECONFIG_CONTENT" > /tmp/kubeconfig
|
||||
export KUBECONFIG=/tmp/kubeconfig
|
||||
kubectl apply -f infra/fileserver/kubernetes/pvc-certification-job.yaml
|
||||
kubectl wait --for=condition=complete --timeout=30m job/fileserver-pvc-certification
|
||||
kubectl logs job/fileserver-pvc-certification
|
||||
echo "certified=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
fileserver-sensitive-telemetry-scan:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Prove telemetry carries no filename, path, or raw identifier
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:application-core:test --tests '*FileserverObservabilityTest'
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
@@ -0,0 +1,94 @@
|
||||
name: httpclient-nightly
|
||||
|
||||
# Lanes that need a container runtime, real time, or a QUIC-capable host (design §29). They are
|
||||
# separated from the per-PR gate rather than made optional inside it: a lane that cannot run here
|
||||
# fails, it does not skip.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 3 * * *'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
httpclient-fault-injection:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Inject TCP faults against a real upstream
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:adapter:outbound:httpclient:httpClientFailureInjectionTest
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
|
||||
httpclient-performance:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
GRADLE_OPTS: -Dorg.gradle.project.performance.assertions.enabled=true
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Certify pool, streaming, retry, and rotation bounds
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:adapter:outbound:httpclient:httpClientPerformanceTest
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
|
||||
httpclient-http3-experimental:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
# Experimental by design (D-08): the result is reported, never used to block a merge.
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Exercise the experimental HTTP/3 opt-in
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew
|
||||
:adapter:outbound:httpclient:test
|
||||
-Phttp3.tests.enabled=true
|
||||
--no-daemon
|
||||
--stacktrace
|
||||
@@ -26,6 +26,9 @@ jobs:
|
||||
JPA_EVIDENCE_TOPOLOGY: postgresql-16-testcontainers-tls-and-fault-matrix
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
|
||||
@@ -5,6 +5,8 @@ on:
|
||||
paths:
|
||||
- "README.md"
|
||||
- "src/README.md"
|
||||
- "src/**/README.md"
|
||||
- "src/**/CLAUDE.md"
|
||||
- "docs/**/*.md"
|
||||
- ".github/**/*.md"
|
||||
- ".github/workflows/link-check.yml"
|
||||
@@ -13,6 +15,8 @@ on:
|
||||
paths:
|
||||
- "README.md"
|
||||
- "src/README.md"
|
||||
- "src/**/README.md"
|
||||
- "src/**/CLAUDE.md"
|
||||
- "docs/**/*.md"
|
||||
- ".github/**/*.md"
|
||||
- ".github/workflows/link-check.yml"
|
||||
@@ -38,6 +42,8 @@ jobs:
|
||||
--root-dir .
|
||||
README.md
|
||||
src/README.md
|
||||
'src/**/README.md'
|
||||
'src/**/CLAUDE.md'
|
||||
'docs/**/*.md'
|
||||
'.github/**/*.md'
|
||||
fail: true
|
||||
|
||||
@@ -23,6 +23,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
@@ -32,7 +35,7 @@ jobs:
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Run non-skipping Poster image V7 migration qualification
|
||||
- name: Run non-skipping Poster image migration qualification
|
||||
working-directory: src
|
||||
run: ./gradlew :sample-portfolio:posterImageMigrationTest --no-daemon --stacktrace
|
||||
|
||||
@@ -40,6 +43,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
@@ -58,6 +64,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
@@ -82,6 +91,9 @@ jobs:
|
||||
OBJECT_STORAGE_AWS_EXPECTED_OWNER: ${{ secrets.OBJECT_STORAGE_AWS_EXPECTED_OWNER }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
|
||||
@@ -1,375 +0,0 @@
|
||||
name: redis-production-readiness
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "23 18 * * *"
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- "v*-rc.*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
resolve-redis-readiness:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
selected: ${{ steps.resolve.outputs.selected }}
|
||||
candidates: ${{ steps.resolve.outputs.candidates }}
|
||||
selected_count: ${{ steps.resolve.outputs.selected_count }}
|
||||
sentinel_required: ${{ steps.resolve.outputs.sentinel_required }}
|
||||
cluster_required: ${{ steps.resolve.outputs.cluster_required }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
- name: Generate the strict checked-in readiness control artifact
|
||||
working-directory: src
|
||||
run: ./gradlew writeRedisCiMatrix --no-daemon --stacktrace
|
||||
- id: resolve
|
||||
name: Transport the generated matrix to job outputs
|
||||
shell: python
|
||||
run: |
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
matrix_path = Path(
|
||||
"src/build/redis-evidence/control/redis-readiness-matrix.json"
|
||||
)
|
||||
matrix = json.loads(matrix_path.read_text(encoding="utf-8"))
|
||||
if matrix["releaseQualification"] != "NOT_CLAIMED":
|
||||
raise SystemExit("resolver control artifact must not claim release qualification")
|
||||
with Path(os.environ["GITHUB_OUTPUT"]).open("a", encoding="utf-8") as stream:
|
||||
stream.write(
|
||||
"selected="
|
||||
+ json.dumps(matrix["selected"], separators=(",", ":"))
|
||||
+ "\n"
|
||||
)
|
||||
stream.write(
|
||||
"candidates="
|
||||
+ json.dumps(
|
||||
matrix["implementedCandidates"], separators=(",", ":")
|
||||
)
|
||||
+ "\n"
|
||||
)
|
||||
stream.write(f"selected_count={matrix['selectedCount']}\n")
|
||||
stream.write(
|
||||
"sentinel_required="
|
||||
+ str(matrix["topologyJobs"]["sentinel"]).lower()
|
||||
+ "\n"
|
||||
)
|
||||
stream.write(
|
||||
"cluster_required="
|
||||
+ str(matrix["topologyJobs"]["cluster"]).lower()
|
||||
+ "\n"
|
||||
)
|
||||
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # actions/upload-artifact@v4
|
||||
with:
|
||||
name: redis-readiness-control
|
||||
path: src/build/redis-evidence/control
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
redis-security:
|
||||
needs: resolve-redis-readiness
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
- id: redis-tests
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:redisSecurityTest --no-daemon --stacktrace
|
||||
- id: redis-evidence-sanitizer
|
||||
if: always()
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:verifyRedisEvidenceArtifactsForUpload --no-daemon --stacktrace
|
||||
- if: ${{ always() && steps.redis-evidence-sanitizer.outcome == 'success' }}
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # actions/upload-artifact@v4
|
||||
with:
|
||||
name: redis-security-evidence
|
||||
path: src/adapter/outbound/cache-redis/build/redis-evidence
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
redis-sentinel:
|
||||
needs: resolve-redis-readiness
|
||||
if: ${{ needs.resolve-redis-readiness.outputs.sentinel_required == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
- id: redis-tests
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:redisSentinelTest --no-daemon --stacktrace
|
||||
- id: redis-evidence-sanitizer
|
||||
if: always()
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:verifyRedisEvidenceArtifactsForUpload --no-daemon --stacktrace
|
||||
- if: ${{ always() && steps.redis-evidence-sanitizer.outcome == 'success' }}
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # actions/upload-artifact@v4
|
||||
with:
|
||||
name: redis-sentinel-evidence
|
||||
path: src/adapter/outbound/cache-redis/build/redis-evidence
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
redis-cluster:
|
||||
needs: resolve-redis-readiness
|
||||
if: ${{ needs.resolve-redis-readiness.outputs.cluster_required == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
- id: redis-tests
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:redisClusterTest --no-daemon --stacktrace
|
||||
- id: redis-evidence-sanitizer
|
||||
if: always()
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:verifyRedisEvidenceArtifactsForUpload --no-daemon --stacktrace
|
||||
- if: ${{ always() && steps.redis-evidence-sanitizer.outcome == 'success' }}
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # actions/upload-artifact@v4
|
||||
with:
|
||||
name: redis-cluster-evidence
|
||||
path: src/adapter/outbound/cache-redis/build/redis-evidence
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
redis-fault:
|
||||
needs: resolve-redis-readiness
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
- id: redis-tests
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:redisFaultTest --no-daemon --stacktrace
|
||||
- id: redis-evidence-sanitizer
|
||||
if: always()
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:verifyRedisEvidenceArtifactsForUpload --no-daemon --stacktrace
|
||||
- if: ${{ always() && steps.redis-evidence-sanitizer.outcome == 'success' }}
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # actions/upload-artifact@v4
|
||||
with:
|
||||
name: redis-fault-evidence
|
||||
path: src/adapter/outbound/cache-redis/build/redis-evidence
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
redis-compatibility:
|
||||
needs: resolve-redis-readiness
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
- id: redis-tests
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:redisCompatibilityTest --no-daemon --stacktrace
|
||||
- id: redis-evidence-sanitizer
|
||||
if: always()
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:verifyRedisEvidenceArtifactsForUpload --no-daemon --stacktrace
|
||||
- if: ${{ always() && steps.redis-evidence-sanitizer.outcome == 'success' }}
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # actions/upload-artifact@v4
|
||||
with:
|
||||
name: redis-compatibility-evidence
|
||||
path: src/adapter/outbound/cache-redis/build/redis-evidence
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
selected-card-readiness:
|
||||
needs: resolve-redis-readiness
|
||||
if: ${{ needs.resolve-redis-readiness.outputs.selected_count != '0' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include: ${{ fromJSON(needs.resolve-redis-readiness.outputs.selected) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
- id: redis-tests
|
||||
working-directory: src
|
||||
run: ./gradlew ${{ matrix.readinessTask }} --no-daemon --stacktrace
|
||||
- id: redis-evidence-sanitizer
|
||||
if: always()
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:verifyRedisEvidenceArtifactsForUpload --no-daemon --stacktrace
|
||||
- if: ${{ always() && steps.redis-evidence-sanitizer.outcome == 'success' }}
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # actions/upload-artifact@v4
|
||||
with:
|
||||
name: redis-selected-${{ matrix.cardId }}
|
||||
path: src/adapter/outbound/cache-redis/build/redis-evidence
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
redis-all-candidates:
|
||||
needs: resolve-redis-readiness
|
||||
if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
- id: redis-tests
|
||||
working-directory: src
|
||||
run: ./gradlew redisAllImplementedCandidates --no-daemon --stacktrace
|
||||
- id: redis-evidence-sanitizer
|
||||
if: always()
|
||||
working-directory: src
|
||||
run: ./gradlew :adapter:outbound:cache-redis:verifyRedisEvidenceArtifactsForUpload --no-daemon --stacktrace
|
||||
- if: ${{ always() && steps.redis-evidence-sanitizer.outcome == 'success' }}
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # actions/upload-artifact@v4
|
||||
with:
|
||||
name: redis-all-candidates-evidence
|
||||
path: src/adapter/outbound/cache-redis/build/redis-evidence
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
redis-production-readiness:
|
||||
needs:
|
||||
- resolve-redis-readiness
|
||||
- selected-card-readiness
|
||||
if: ${{ always() && needs.resolve-redis-readiness.result == 'success' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Require the exact selected matrix result
|
||||
shell: python
|
||||
env:
|
||||
SELECTED_COUNT: ${{ needs.resolve-redis-readiness.outputs.selected_count }}
|
||||
SELECTED_JOB_RESULT: ${{ needs.selected-card-readiness.result }}
|
||||
run: |
|
||||
import os
|
||||
|
||||
selected_count_text = os.environ["SELECTED_COUNT"]
|
||||
selected_job_result = os.environ["SELECTED_JOB_RESULT"]
|
||||
if not selected_count_text.isdecimal():
|
||||
raise SystemExit("selected_count must be a non-negative integer")
|
||||
selected_count = int(selected_count_text)
|
||||
expected_result = "skipped" if selected_count == 0 else "success"
|
||||
if selected_job_result != expected_result:
|
||||
raise SystemExit(
|
||||
"selected-card-readiness result mismatch: "
|
||||
f"count={selected_count}, expected={expected_result}, "
|
||||
f"actual={selected_job_result}"
|
||||
)
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # actions/download-artifact@v4.3.0
|
||||
with:
|
||||
name: redis-readiness-control
|
||||
path: ${{ runner.temp }}/redis-readiness/control
|
||||
- if: >-
|
||||
${{
|
||||
needs.resolve-redis-readiness.outputs.selected_count != '0'
|
||||
&& needs.selected-card-readiness.result == 'success'
|
||||
}}
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # actions/download-artifact@v4.3.0
|
||||
with:
|
||||
pattern: redis-selected-*
|
||||
path: ${{ runner.temp }}/redis-readiness/selected
|
||||
- name: Record the downloaded selected artifact inventory
|
||||
shell: python
|
||||
env:
|
||||
GITHUB_RUN_ID: ${{ github.run_id }}
|
||||
SELECTED_JSON: ${{ needs.resolve-redis-readiness.outputs.selected }}
|
||||
SELECTED_COUNT: ${{ needs.resolve-redis-readiness.outputs.selected_count }}
|
||||
SELECTED_JOB_RESULT: ${{ needs.selected-card-readiness.result }}
|
||||
REDIS_SELECTED_DIRECTORY: ${{ runner.temp }}/redis-readiness/selected
|
||||
REDIS_CI_RESULT_FILE: ${{ runner.temp }}/redis-readiness/redis-ci-result.json
|
||||
run: |
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
selected = json.loads(os.environ["SELECTED_JSON"])
|
||||
if not isinstance(selected, list):
|
||||
raise SystemExit("selected matrix must be a JSON array")
|
||||
expected_names = sorted(
|
||||
"redis-selected-" + entry["cardId"] for entry in selected
|
||||
)
|
||||
if len(expected_names) != int(os.environ["SELECTED_COUNT"]):
|
||||
raise SystemExit("selected_count does not match the selected matrix")
|
||||
if len(expected_names) != len(set(expected_names)):
|
||||
raise SystemExit("selected matrix contains duplicate artifact names")
|
||||
|
||||
selected_directory = Path(os.environ["REDIS_SELECTED_DIRECTORY"])
|
||||
actual_names = (
|
||||
sorted(path.name for path in selected_directory.iterdir() if path.is_dir())
|
||||
if selected_directory.is_dir()
|
||||
else []
|
||||
)
|
||||
if actual_names != expected_names:
|
||||
raise SystemExit(
|
||||
"downloaded selected artifact inventory mismatch: "
|
||||
f"expected={expected_names}, actual={actual_names}"
|
||||
)
|
||||
|
||||
result = {
|
||||
"schemaVersion": 1,
|
||||
"runId": os.environ["GITHUB_RUN_ID"],
|
||||
"selectedCount": len(expected_names),
|
||||
"selectedJobResult": os.environ["SELECTED_JOB_RESULT"],
|
||||
"selectedArtifactNames": actual_names,
|
||||
}
|
||||
result_path = Path(os.environ["REDIS_CI_RESULT_FILE"])
|
||||
result_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
result_path.write_text(
|
||||
json.dumps(result, sort_keys=True, separators=(",", ":")) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
- if: ${{ needs.resolve-redis-readiness.outputs.selected_count == '0' }}
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew verifyRedisSelectedEvidenceArtifacts redisProductionReadiness
|
||||
-PredisControlDirectory=${{ runner.temp }}/redis-readiness/control
|
||||
-PredisCiResultFile=${{ runner.temp }}/redis-readiness/redis-ci-result.json
|
||||
--no-daemon --stacktrace
|
||||
- if: ${{ needs.resolve-redis-readiness.outputs.selected_count != '0' }}
|
||||
working-directory: src
|
||||
run: >-
|
||||
./gradlew verifyRedisSelectedEvidenceArtifacts redisProductionReadiness
|
||||
-PredisControlDirectory=${{ runner.temp }}/redis-readiness/control
|
||||
-PredisEvidenceDirectory=${{ runner.temp }}/redis-readiness/selected
|
||||
-PredisCiResultFile=${{ runner.temp }}/redis-readiness/redis-ci-result.json
|
||||
--no-daemon --stacktrace
|
||||
@@ -0,0 +1,190 @@
|
||||
# Redis SDK topology evidence.
|
||||
#
|
||||
# The lanes in infra/redis-sdk answer what the deterministic in-memory gateway cannot — Sentinel
|
||||
# promotion behaviour, Cluster redirects, ACL coverage. docs/redis/support-matrix.md records which
|
||||
# lane produced which evidence, and RedisSupportMatrixTest refuses an evidence claim that does not
|
||||
# name the test class behind it.
|
||||
#
|
||||
# Three cadences, because the cost and the question differ:
|
||||
#
|
||||
# pull_request standalone only, current supported version. The cheapest lane that can still
|
||||
# catch "this change cannot talk to a real Redis at all". A PR gate that starts
|
||||
# three topologies is a PR gate people learn to ignore.
|
||||
# schedule the full supported-version x topology matrix, nightly. This is where Sentinel
|
||||
# promotion and Cluster redirect evidence comes from.
|
||||
# workflow_dispatch one lane on demand, for reproducing a specific failure.
|
||||
#
|
||||
# A release candidate uses the nightly matrix run for its tag: `release-candidate` selects the full
|
||||
# matrix on demand so an RC does not have to wait for the next scheduled run.
|
||||
#
|
||||
# Each lane has its own endpoint. A sentinel is not a data node and a cluster node is not the whole
|
||||
# cluster, so the address, port, and (for Sentinel) the monitored primary's name are per-lane rather
|
||||
# than one hardcoded 6379 that happens to be right for standalone only.
|
||||
#
|
||||
# The Gradle task is fail-closed on its own account: an unknown mode, a missing endpoint, a lane
|
||||
# with no tagged test class, and a run that executed zero tests are all errors. This workflow does
|
||||
# not need to re-check those, but it does have to keep the evidence, which is why every run uploads
|
||||
# the JUnit XML together with the commit SHA, the server version and the resolved image digest. An
|
||||
# evidence artifact that cannot say which image produced it is not evidence.
|
||||
name: redis-sdk-topology
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "src/adapter/outbound/cache-redis/**"
|
||||
- "infra/redis-sdk/**"
|
||||
- ".github/workflows/redis-sdk-topology.yml"
|
||||
schedule:
|
||||
# 02:30 UTC daily. Nightly, not hourly: the matrix starts real servers.
|
||||
- cron: "30 2 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
topology:
|
||||
description: standalone, sentinel, cluster, tls, or release-candidate for the full matrix
|
||||
required: true
|
||||
default: standalone
|
||||
type: choice
|
||||
options: [standalone, sentinel, cluster, tls, release-candidate]
|
||||
redis_version:
|
||||
description: server version tag
|
||||
required: true
|
||||
default: "7.4"
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# The matrix is computed rather than duplicated per trigger, so adding a supported version is one
|
||||
# edit and no trigger can silently keep testing an old set.
|
||||
lanes:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.select.outputs.matrix }}
|
||||
steps:
|
||||
- id: select
|
||||
run: |
|
||||
set -euo pipefail
|
||||
case "${{ github.event_name }}" in
|
||||
pull_request)
|
||||
matrix='{"include":[{"topology":"standalone","redis_version":"7.4"}]}'
|
||||
;;
|
||||
schedule)
|
||||
matrix='{"include":[
|
||||
{"topology":"standalone","redis_version":"7.2"},
|
||||
{"topology":"standalone","redis_version":"7.4"},
|
||||
{"topology":"standalone","redis_version":"8.2"},
|
||||
{"topology":"sentinel","redis_version":"7.2"},
|
||||
{"topology":"sentinel","redis_version":"7.4"},
|
||||
{"topology":"sentinel","redis_version":"8.2"},
|
||||
{"topology":"cluster","redis_version":"7.2"},
|
||||
{"topology":"cluster","redis_version":"7.4"},
|
||||
{"topology":"cluster","redis_version":"8.2"},
|
||||
{"topology":"tls","redis_version":"7.4"},
|
||||
{"topology":"tls","redis_version":"8.2"}]}'
|
||||
;;
|
||||
*)
|
||||
if [ "${{ inputs.topology }}" = "release-candidate" ]; then
|
||||
matrix='{"include":[
|
||||
{"topology":"standalone","redis_version":"7.2"},
|
||||
{"topology":"standalone","redis_version":"7.4"},
|
||||
{"topology":"standalone","redis_version":"8.2"},
|
||||
{"topology":"sentinel","redis_version":"7.2"},
|
||||
{"topology":"sentinel","redis_version":"7.4"},
|
||||
{"topology":"sentinel","redis_version":"8.2"},
|
||||
{"topology":"cluster","redis_version":"7.2"},
|
||||
{"topology":"cluster","redis_version":"7.4"},
|
||||
{"topology":"cluster","redis_version":"8.2"},
|
||||
{"topology":"tls","redis_version":"7.4"},
|
||||
{"topology":"tls","redis_version":"8.2"}]}'
|
||||
else
|
||||
matrix='{"include":[{"topology":"${{ inputs.topology }}","redis_version":"${{ inputs.redis_version }}"}]}'
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
printf 'matrix=%s\n' "$(printf '%s' "$matrix" | tr -d '\n ')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
topology-evidence:
|
||||
needs: lanes
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.lanes.outputs.matrix) }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # actions/checkout@v4.2.2
|
||||
- name: Validate Gradle wrapper
|
||||
id: gradle-wrapper-validation
|
||||
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # gradle/actions@v6
|
||||
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # actions/setup-java@v4.7.1
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10"
|
||||
cache: gradle
|
||||
cache-dependency-path: |
|
||||
src/**/*.gradle
|
||||
src/**/gradle-wrapper.properties
|
||||
src/**/gradle.lockfile
|
||||
- name: Start the topology
|
||||
env:
|
||||
REDIS_VERSION: ${{ matrix.redis_version }}
|
||||
run: docker compose -f "infra/redis-sdk/${{ matrix.topology }}/compose.yml" up -d --wait
|
||||
- name: Record the image digest
|
||||
id: image
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# The tag says 7.4; the digest says which 7.4. Evidence that names only the tag cannot be
|
||||
# reproduced once the tag moves.
|
||||
digest="$(docker image inspect --format '{{index .RepoDigests 0}}' \
|
||||
"redis:${{ matrix.redis_version }}" 2>/dev/null || echo 'unresolved')"
|
||||
printf 'digest=%s\n' "$digest" >> "$GITHUB_OUTPUT"
|
||||
- name: Run the topology contracts
|
||||
working-directory: src
|
||||
run: |
|
||||
set -euo pipefail
|
||||
case '${{ matrix.topology }}' in
|
||||
standalone) port=6379; extra='' ;;
|
||||
sentinel) port=27010; extra='-Predis.topology.master=skeleton' ;;
|
||||
cluster) port=7100; extra='' ;;
|
||||
# The TLS lane's CA is generated at start-up, so the trust material is extracted from
|
||||
# the lane rather than checked in. A checked-in key is a secret in the repository
|
||||
# however loudly the file is named "test".
|
||||
tls)
|
||||
port=6390
|
||||
docker compose -f ../infra/redis-sdk/tls/compose.yml cp redis:/tls/ca.crt "$RUNNER_TEMP/redis-lane-ca.pem"
|
||||
extra="-Predis.topology.trust-material=$RUNNER_TEMP/redis-lane-ca.pem"
|
||||
;;
|
||||
*) echo "unknown topology"; exit 1 ;;
|
||||
esac
|
||||
./gradlew :adapter:outbound:cache-redis:redisTopologyTest --console=plain \
|
||||
-Predis.topology.host=localhost \
|
||||
-Predis.topology.port="$port" \
|
||||
-Predis.topology.mode='${{ matrix.topology }}' \
|
||||
$extra
|
||||
- name: Write the evidence manifest
|
||||
if: always()
|
||||
run: |
|
||||
set -euo pipefail
|
||||
out=src/adapter/outbound/cache-redis/build/test-results/redisTopologyTest
|
||||
mkdir -p "$out"
|
||||
cat > "$out/evidence-manifest.txt" <<MANIFEST
|
||||
commit=${{ github.sha }}
|
||||
workflow_run=${{ github.run_id }}
|
||||
trigger=${{ github.event_name }}
|
||||
topology=${{ matrix.topology }}
|
||||
redis_version=${{ matrix.redis_version }}
|
||||
image_digest=${{ steps.image.outputs.digest }}
|
||||
MANIFEST
|
||||
- name: Preserve the evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # actions/upload-artifact@v4.6.2
|
||||
with:
|
||||
name: redis-topology-${{ matrix.topology }}-${{ matrix.redis_version }}
|
||||
path: |
|
||||
src/adapter/outbound/cache-redis/build/test-results/redisTopologyTest/**
|
||||
src/adapter/outbound/cache-redis/build/reports/tests/redisTopologyTest/**
|
||||
if-no-files-found: error
|
||||
retention-days: 90
|
||||
- name: Stop the topology
|
||||
if: always()
|
||||
run: docker compose -f "infra/redis-sdk/${{ matrix.topology }}/compose.yml" down -v
|
||||
Reference in New Issue
Block a user