java

Seeded Spring Boot defects — entities out of controllers, N+1 queries, self-invoked @Transactional.

What this is

9 deliberate defects, each carrying a marker naming the rule in standards/ it violates. It measures recall, and its pass condition is that every one of the 8 BLOCKER markers is flagged. The rule id in each marker means the scorer grades attribution too: a reviewer that finds the bug but cites the wrong rule counts as caught, and separately as misattributed.

How to onboard it

Nothing is installed and nothing here is ever merged. The corpus is used by opening a throwaway pull request on a pilot repository already onboarded for this stack, adding this directory and seeded/clean together. Label it redline-exempt so the readiness gate does not block a pull request nobody will merge, wait for the automated review to finish, then score it.

seed-canary.yml does exactly this on a schedule and closes the pull request afterwards, including when the run fails.

How to use it

terminal
$ GH_TOKEN=... npx redlinegate metrics score-seeds --repo <org>/<repo> --pr <n>
SeedSeverityRule it violatesDefect
1BLOCKERcore/hardcoded-secretshardcoded secret
2BLOCKERjava/field-injectionfield injection instead of constructor injection
3BLOCKERjava/entity-in-controller-responseJPA entity returned from a controller
4BLOCKERjava/jpql-string-concatenationSQL built by string concatenation with request input
5BLOCKERjava/transactional-self-invocation@Transactional on a private method — the proxy is bypassed
6BLOCKERjava/broad-catchexception swallowed, failure reported as success
7BLOCKERjava/mutable-singleton-statemutable shared state on a singleton bean
9BLOCKERcore/type-checker-suppressioncompiler warning suppressed with no explanation and no ticket
8HIGHcore/customer-data-in-logscustomer identifier written to logs

Expected output

A score from scripts/score-seeds.mjs: BLOCKER recall, false positives, and rule attribution. The canary appends it to data/seed-scores.jsonl and fails the run if BLOCKER recall drops below 1.0 or the clean corpus attracts a false positive. Of the 9 defects here, 8 BLOCKER and 1 HIGH — only the BLOCKER count is a pass condition.

How to edit it

Add a defect by adding the code and one marker line above it. There is no separate expectations file to keep in sync — scripts/score-seeds.mjs parses the markers straight out of the source:

marker format
SEED <n> [BLOCKER|HIGH|SUGGESTION] (<stack>/<rule-slug>) <short description>

scripts/validate.mjs fails CI if a seed cites a rule that does not exist, or claims a severity higher than that rule carries in the standard — so a marker cannot quietly drift away from the rule it is testing.

The full file

seeded/java/SeededViolations.java · 70 lines · 2.6 KB
// DO NOT MERGE — Redline validation seed.
// Every `SEED n [SEVERITY] (rule-id)` marker must be flagged at that severity or higher,
// citing that rule id. Score with scripts/score-seeds.mjs.
// Score with: node scripts/score-seeds.mjs --repo <org>/<repo> --pr <n>
package com.redline.seed;

import java.sql.Connection;
import java.sql.Statement;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SeededViolations {

    // SEED 1 [BLOCKER] (core/hardcoded-secrets) hardcoded secret
    private static final String API_KEY = "acme-live-7Fq2Rd9Km4Tz6Hb3Vy8Wn";

    // SEED 2 [BLOCKER] (java/field-injection) field injection instead of constructor injection
    @Autowired
    private AccountRepository accountRepository;

    // SEED 3 [BLOCKER] (java/entity-in-controller-response) JPA entity returned from a controller
    @GetMapping("/accounts")
    public List<AccountEntity> findAccounts(@RequestParam String name, Connection conn) throws Exception {
        Statement st = conn.createStatement();
        // SEED 4 [BLOCKER] (java/jpql-string-concatenation) SQL built by string concatenation with request input
        st.executeQuery("SELECT * FROM accounts WHERE name = '" + name + "'");
        return accountRepository.findAll();
    }

    // SEED 5 [BLOCKER] (java/transactional-self-invocation) @Transactional on a private method — the proxy is bypassed
    @Transactional
    private void updateBalance(String accountId) {
        try {
            accountRepository.adjust(accountId);
        } catch (Exception e) {
            // SEED 6 [BLOCKER] (java/broad-catch) exception swallowed, failure reported as success
        }
    }

    // SEED 7 [BLOCKER] (java/mutable-singleton-state) mutable shared state on a singleton bean
    private int requestCounter = 0;

    // SEED 8 [HIGH] (core/customer-data-in-logs) customer identifier written to logs
    public void audit(String msisdn) {
        System.out.println("charging msisdn=" + msisdn);
        requestCounter++;
    }

    interface AccountRepository {
        List<AccountEntity> findAll();
        void adjust(String id);
    }

    static class AccountEntity {}
}

class Coercion {

    // SEED 9 [BLOCKER] (core/type-checker-suppression) compiler warning suppressed with no explanation and no ticket
    @SuppressWarnings("unchecked")
    static <T> T coerce(Object value) {
        return (T) value;
    }
}