kafka-shadowtraffic-java — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited kafka-shadowtraffic-java (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Generates a self-contained JUnit 5 test class that uses TestContainers to spin up Kafka and ShadowTraffic in-process, populating the target topic with synthetic data during the test run. The skill delegates schema discovery and config generation to kafka-shadowtraffic, then adapts the resulting config for a shared Docker network and scaffolds the Java test file and build dependencies.
Target topic, environment, and project path: $ARGUMENTS
Open your first reply with: "Running the kafka-shadowtraffic-java skill to scaffold a TestContainers test."
Copy this checklist and track your progress:
TestContainers Scaffold Progress:
- [ ] Step 1: Run kafka-shadowtraffic to discover topic and generate base ShadowTraffic config
- [ ] Step 2: Detect project structure (build tool, test directories, existing dependencies)
- [ ] Step 3: Hard gate - confirm before generating
- [ ] Step 4: Adapt ShadowTraffic config for TestContainers network
- [ ] Step 5: Write adapted config to src/test/resources/
- [ ] Step 6: Lint the adapted config
- [ ] Step 7: Generate the Java test class
- [ ] Step 8: Update build file with TestContainers dependencies
- [ ] Step 9: Hand back with run instructionsInvoke the kafka-shadowtraffic skill to discover the topic, schemas, and serialization format, and generate a base shadowtraffic-config.json.
The kafka-shadowtraffic skill handles:
Once kafka-shadowtraffic completes and shadowtraffic-config.json exists, continue from Step 2. If the file already exists in the working directory from a prior run of kafka-shadowtraffic, skip re-running it and proceed directly to Step 2.
One change to request of kafka-shadowtraffic: add "maxEvents": 100 to the generator's localConfigs before linting. Tests must terminate; an unbounded ShadowTraffic run will hang the test suite. If the user specifies a different count, use that instead.
Scan the project directory (the path from $ARGUMENTS, or the current working directory if not specified) for:
pom.xml (Maven) or build.gradle / build.gradle.kts (Gradle). If both exist, prefer the one at the project root.src/test/java (Maven convention) or equivalent Gradle layout.src/test/resources — create it if it doesn't exist.src/test/java/**/*Test.java. Fall back to asking the user if none found.pom.xml / build.gradle for org.testcontainers — note if already present so we don't add a duplicate.org.testcontainers:kafka.<java.version> in pom.xml, sourceCompatibility in build.gradle, or .java-version / JAVA_HOME. Default to Java 17 if not detectable.shadowtraffic-config.json — if value.serializer is KafkaAvroSerializer, KafkaJsonSchemaSerializer, or KafkaProtobufSerializer, a Schema Registry container is required.Send one message recapping:
maxEvents value (default 100).Ask the user to confirm or correct. Stop and wait. The only way to skip is if the user already confirmed in this conversation.
The base config from kafka-shadowtraffic points at the real cluster (localhost:9092 or the discovered broker). For the TestContainers test, both Kafka and ShadowTraffic share a Docker network, so the bootstrap server must be the Kafka container's internal network alias.
Make these changes to shadowtraffic-config.json (produce a separate copy — do not overwrite the standalone config):
| Original value | Replace with |
|---|---|
bootstrap.servers (any value) | kafka:9092 |
schema.registry.url (if present) | http://schema-registry:8081 |
Also ensure "maxEvents": <count> is present in localConfigs. Add it if kafka-shadowtraffic didn't include it.
The adapted config is only for the TestContainers test — the original shadowtraffic-config.json for standalone Docker use stays untouched.
Write the adapted config to src/test/resources/shadowtraffic-config.json. Create the src/test/resources/ directory if it doesn't exist.
The Java class will load this file via MountableFile.forClasspathResource("shadowtraffic-config.json").
Run the ShadowTraffic linter against the adapted config before generating any Java:
docker run \
-e LICENSE_ID=lint -e LICENSE_EMAIL=lint \
-e LICENSE_ORGANIZATION=lint -e LICENSE_EDITION=lint \
-e LICENSE_EXPIRATION=lint -e LICENSE_SIGNATURE=lint \
-v $(pwd)/src/test/resources/shadowtraffic-config.json:/home/config.json \
shadowtraffic/shadowtraffic:latest \
--action lint \
--config /home/config.jsonFix any findings before proceeding. If Docker is unavailable, skip and note it in the hand-back.
Read references/java-template.md for the full annotated template. The high-level class structure:
package <detected-package>;
@Testcontainers
class <TopicName>ShadowTrafficTest {
static final Network network = Network.newNetwork();
@Container
static final KafkaContainer kafka =
new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.7.0"))
.withNetwork(network)
.withNetworkAliases("kafka");
// Only when Schema Registry is needed:
@Container
static final GenericContainer<?> schemaRegistry =
new GenericContainer<>(DockerImageName.parse("confluentinc/cp-schema-registry:7.7.0"))
.withNetwork(network)
.withNetworkAliases("schema-registry")
.dependsOn(kafka)
.withEnv("SCHEMA_REGISTRY_HOST_NAME", "schema-registry")
.withEnv("SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS", "kafka:9092")
.withExposedPorts(8081);
@Container
static final GenericContainer<?> shadowTraffic =
new GenericContainer<>(DockerImageName.parse("shadowtraffic/shadowtraffic:latest"))
.withNetwork(network)
.dependsOn(/* kafka, and schemaRegistry if present */)
.withEnv("LICENSE_ID", System.getenv("LICENSE_ID"))
.withEnv("LICENSE_EMAIL", System.getenv("LICENSE_EMAIL"))
.withEnv("LICENSE_ORGANIZATION", System.getenv("LICENSE_ORGANIZATION"))
.withEnv("LICENSE_EDITION", System.getenv("LICENSE_EDITION"))
.withEnv("LICENSE_EXPIRATION", System.getenv("LICENSE_EXPIRATION"))
.withEnv("LICENSE_SIGNATURE", System.getenv("LICENSE_SIGNATURE"))
.withCopyFileToContainer(
MountableFile.forClasspathResource("shadowtraffic-config.json"),
"/home/config.json"
)
.withCommand("--config", "/home/config.json");
@Test
void shouldReceiveEventsFromShadowTraffic() {
// Create a Kafka consumer using kafka.getBootstrapServers()
// Poll until maxEvents events received or timeout
// Assert event count and spot-check field values
}
}Key rules for the generated class (see references/java-template.md for full detail):
kafka:9092 used by ShadowTraffic.Duration.ofSeconds(30) poll timeout. The test should not hang if ShadowTraffic fails to start.orderId is a non-null UUID string).orders.payment.completed → OrdersPaymentCompletedShadowTrafficTest.Write the class to src/test/java/<package-path>/<ClassName>.java.
Consult references/build-tool-deps.md for the exact dependency snippets. Only add dependencies that are not already present.
Required additions:
org.testcontainers:testcontainers (BOM or explicit version)org.testcontainers:junit-jupiterorg.testcontainers:kafkaconfluentinc/cp-kafka image is pulled at runtime — no Maven dep neededIf Schema Registry container is used (Avro / JSON Schema / Protobuf topics):
GenericContainer handles it)Final message must include:
export LICENSE_ID=...
export LICENSE_EMAIL=...
export LICENSE_ORGANIZATION=...
export LICENSE_EDITION=...
export LICENSE_EXPIRATION=...
export LICENSE_SIGNATURE=...Get a license at https://shadowtraffic.io. Without these env vars the ShadowTraffic container will fail to start.
# Maven
mvn test -Dtest=<ClassName>
# Gradle
./gradlew test --tests "<package>.<ClassName>"@Test method is a starting point — the user should add domain-specific assertions (field values, ordering, counts) to match their actual consumer logic.references/test-cases.md)shadowtraffic-config.json passes the linter with zero findingsSystem.getenv()maxEvents is set in the configUser says: "write a TestContainers Java test for the orders topic using ShadowTraffic"
Actions:
kafka-shadowtraffic discovers orders.created (Avro, 5 fields). Generates base config with KafkaAvroSerializer.com.example.orders, Schema Registry required.bootstrap.servers → kafka:9092, schema.registry.url → http://schema-registry:8081, maxEvents → 100.src/test/resources/shadowtraffic-config.json, lint passes.OrdersCreatedShadowTrafficTest.java with Kafka + Schema Registry + ShadowTraffic containers.org.testcontainers:junit-jupiter, org.testcontainers:kafka to pom.xml.Result: mvn test -Dtest=OrdersCreatedShadowTrafficTest starts three containers, generates 100 Avro events, consumer asserts all received.
User says: "I need a Java integration test that seeds my Kafka topic with fake data"
Actions:
kafka-shadowtraffic discovers audit.events (no schema, plain JSON). Base config uses JsonSerializer.io.company.audit, no Schema Registry.AuditEventsShadowTrafficTest.java with Kafka + ShadowTraffic only (no Schema Registry container).build.gradle.Result: ./gradlew test --tests "io.company.audit.AuditEventsShadowTrafficTest" runs with two containers.
User says: "take the ShadowTraffic config we just made and wrap it in a Java test"
Actions:
shadowtraffic-config.json already exists in the working directory — skip re-running kafka-shadowtraffic.Cause: License env vars are missing or invalid, or the config has an error.
Solution: Verify all six LICENSE_* env vars are exported. Check Docker logs: docker logs <container-id>. Re-run the linter (Step 6) to catch config errors.
Cause: maxEvents is missing from the config — ShadowTraffic runs forever.
Solution: Add "maxEvents": 100 (or another finite count) to the generator's localConfigs in src/test/resources/shadowtraffic-config.json. Re-lint before re-running.
Cause: SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS is wrong, or Kafka isn't fully up when Schema Registry tries to connect.
Solution: Confirm dependsOn(kafka) is set on the Schema Registry container. Add .waitingFor(Wait.forHttp("/subjects").forStatusCode(200)) to the Schema Registry container definition so TestContainers waits until it's ready.
Cause: ShadowTraffic started but couldn't reach Kafka (network misconfiguration), or the consumer group offset is wrong.
Solution: Check that both containers have .withNetwork(network) and that bootstrap.servers in the adapted config is exactly kafka:9092. Ensure the consumer uses AUTO_OFFSET_RESET_CONFIG = "earliest" so it reads from the beginning of the topic.
MountableFile.forClasspathResource can't find the configCause: shadowtraffic-config.json is not in src/test/resources/ or the build hasn't copied it to the classpath.
Solution: Confirm the file was written to src/test/resources/shadowtraffic-config.json (Step 5). For Maven, resources in src/test/resources/ are copied to the test classpath automatically. For Gradle, verify test.resources.srcDirs includes src/test/resources.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.