# evidence 250 — messaging-certification-gate-chain # revision: a24ece9cf797f7ea647e33bf846b115208ed1ba5 # cwd: /shared/codebase/clean-architecture-backend-template/src/messaging # command: sed -n "36,130p" messaging-kafka/build.gradle; echo; echo ---CI JOB---; sed -n "44,52p" ../../.github/workflows/messaging-certification.yml # ---- raw output ---- // `CertifiedEvidence` used to be a hand-written list of three scenarios, and every consumer of it — // the compatibility matrix, the cross-broker release suite, the support matrix document — believed // it without a container ever starting. The lane below produces that list, and // `verifyMessagingCertificationEvidence` refuses to pass when the committed manifest claims a // scenario this run did not prove. Editing the manifest by hand therefore fails the build; running // the lane rewrites it. strictTestLanes { lane('messagingCertificationTest') { tag = 'messaging-certification' description = 'Runs the broker fault scenarios against a real Kafka and writes the ' + 'certification evidence the compatibility matrix reads.' customize = { test -> // Pinned images. A certification claim names the build it was made against, so a // floating tag would make a red run unattributable and a green one unrepeatable. // `-PmessagingKafkaImage=` overrides for a one-off run against another version. test.systemProperty 'messaging.kafka.image', (project.findProperty('messagingKafkaImage') ?: 'apache/kafka:4.1.0').toString() test.systemProperty 'messaging.toxiproxy.image', (project.findProperty('messagingToxiproxyImage') ?: 'ghcr.io/shopify/toxiproxy:2.12.0').toString() test.systemProperty 'messaging.certification.manifest', project.layout.buildDirectory .file('messaging-certification/broker-certification-evidence.jsonl') .get().asFile.absolutePath // The commit is part of the evidence: "certified" is a claim about one source tree. // Read from the environment rather than a `-P` flag so the CI job's command line stays // the literal grammar the gate matrix lint accepts. test.systemProperty 'messaging.certification.commit', (project.findProperty('certificationCommit') ?: providers.environmentVariable('GITHUB_SHA').getOrElse('local')) .toString() } } } // The certification tag is excluded from `test` because the lane deliberately carries no Docker // guard. Every other container suite here skips with a stated reason when Docker is absent; a lane // that skipped would report success for a broker nobody started, which is the whole failure the // evidence exists to rule out. Keeping it out of `test` is what lets it fail closed without // breaking a laptop build. tasks.named('test', Test) { useJUnitPlatform { excludeTags 'quarantine', 'messaging-certification' } } tasks.register('verifyMessagingCertificationEvidence') { group = 'verification' description = 'Fails when the committed broker certification manifest claims a scenario the ' + 'certification lane did not produce.' dependsOn 'messagingCertificationTest' def produced = layout.buildDirectory .file('messaging-certification/broker-certification-evidence.jsonl') def committed = rootProject.file( 'messaging/messaging-testkit/src/main/resources/messaging/' + 'broker-certification-evidence.jsonl') inputs.file(produced) inputs.file(committed) outputs.file(layout.buildDirectory.file('reports/messaging-certification-evidence.txt')) // A gate whose result can be served from an earlier run is evidence about that run. outputs.upToDateWhen { false } doLast { // The commit and the observation instant differ on every run by design, so they are not // part of the comparison — what has to match is which adapter proved which scenario against // which image, and which test produced it. Closure> claims = { File file -> file.readLines('UTF-8') .findAll { !it.trim().isEmpty() } .collect { line -> line.replaceAll(/,"gitCommit":"[^"]*"/, '') .replaceAll(/,"observedAt":"[^"]*"/, '') } .toSet() } Set ran = claims(produced.get().asFile) Set shipped = claims(committed) if (ran != shipped) { def unproven = shipped - ran def unrecorded = ran - shipped throw new GradleException( "the committed certification manifest does not match this run.\n" + " claimed but not produced: ${unproven.isEmpty() ? 'none' : unproven}\n" + " produced but not claimed: ${unrecorded.isEmpty() ? 'none' : unrecorded}\n" + "Copy ${produced.get().asFile} over ${committed} — the manifest is a " + "record of a run, not a statement about one.") } def report = outputs.files.singleFile report.parentFile.mkdirs() report.text = "scenarios=${ran.size()} manifest=${committed}\n" } } ---CI JOB--- cache-dependency-path: | src/**/*.gradle src/**/gradle-wrapper.properties src/**/gradle.lockfile - name: Certify the Kafka adapter against a real broker working-directory: src # GITHUB_SHA is read by the lane and written into every evidence line, because "certified" # is a claim about one source tree. run: ./gradlew :messaging:messaging-kafka:verifyMessagingCertificationEvidence --no-daemon --stacktrace