springboot-verification
affaan-m/ecc
Build, test, analyze, and security-scan Spring Boot projects before PR or deploy.
What is springboot-verification?
Verification loop for Spring Boot projects that orchestrates build, static analysis, unit/integration/API tests with coverage reporting, dependency and secrets scanning, and diff review. Run before pull requests, after major changes, or pre-deployment to catch issues early.
- Parallel Maven/Gradle build with test skipping for fast compilation
- Static analysis via SpotBugs, PMD, and Checkstyle
- Unit tests with mocks, integration tests with Testcontainers, and API tests with MockMvc
- Code coverage reporting (JaCoCo) with threshold validation
- OWASP dependency CVE scanning and secrets detection in source and git history
- Diff review checklist for logging, error handling, transactions, and config changes
How to install springboot-verification
npx skills add null --skill springboot-verification- Maven 3.6+ or Gradle 7.0+
- Java 11+
- Git (for diff and secrets scanning)
- Optional: Testcontainers Docker setup for integration tests
- Optional: SpotBugs, PMD, Checkstyle, JaCoCo, OWASP Dependency-Check plugins configured in pom.xml or build.gradle
How to use springboot-verification
- 1.Run Phase 1 (Build): `mvn clean verify -DskipTests` or `./gradlew clean assemble -x test`
- 2.Run Phase 2 (Static Analysis): `mvn spotbugs:check pmd:check checkstyle:check` or Gradle equivalents
- 3.Run Phase 3 (Tests + Coverage): `mvn test && mvn jacoco:report` and verify coverage meets threshold
- 4.Run Phase 4 (Security Scan): `mvn org.owasp:dependency-check-maven:check` and grep for hardcoded secrets
- 5.Run Phase 5 (Lint): `mvn spotless:apply` if configured
- 6.Run Phase 6 (Diff Review): `git diff --stat && git diff` and check against provided checklist
- 7.Generate output report summarizing pass/fail for each phase and overall readiness
Use cases
- Pre-pull-request verification for Spring Boot microservices
- Post-refactoring or dependency-upgrade validation
- Pre-staging and pre-production deployment checks
- Continuous verification loop during active development sessions
- Coverage threshold enforcement (80%+) before merge
- Spring Boot backend developers
- DevOps engineers managing CI/CD pipelines
- Teams enforcing code quality gates
- Security-conscious projects requiring CVE and secrets scanning
springboot-verification FAQ
Stop immediately and fix compilation errors before proceeding to later phases. A broken build blocks all downstream verification.
Add the Testcontainers dependency to your pom.xml or build.gradle, annotate test classes with @Testcontainers, declare @Container static fields (e.g., PostgreSQLContainer), and use @DynamicPropertySource to inject connection details into Spring properties.
The skill recommends 80%+ line and branch coverage. Adjust based on your team's standards, but treat it as a gate before merge.
Use grep patterns for common secrets (password=, sk-, api_key, secret), configure git-secrets for pre-commit hooks, and scan git history with `git secrets --scan`.
Yes. Execute the phases sequentially in your pipeline (GitHub Actions, GitLab CI, Jenkins, etc.) and fail the build if any phase returns non-zero exit code.
Full instructions (SKILL.md)
Source of truth, from affaan-m/ecc.
name: springboot-verification description: "Verification loop for Spring Boot projects: build, static analysis, tests with coverage, security scans, and diff review before release or PR." metadata: origin: ECC
Spring Boot Verification Loop
Run before PRs, after major changes, and pre-deploy.
When to Activate
- Before opening a pull request for a Spring Boot service
- After major refactoring or dependency upgrades
- Pre-deployment verification for staging or production
- Running full build → lint → test → security scan pipeline
- Validating test coverage meets thresholds
Phase 1: Build
mvn -T 4 clean verify -DskipTests
# or
./gradlew clean assemble -x test
If build fails, stop and fix.
Phase 2: Static Analysis
Maven (common plugins):
mvn -T 4 spotbugs:check pmd:check checkstyle:check
Gradle (if configured):
./gradlew checkstyleMain pmdMain spotbugsMain
Phase 3: Tests + Coverage
mvn -T 4 test
mvn jacoco:report # verify 80%+ coverage
# or
./gradlew test jacocoTestReport
Report:
- Total tests, passed/failed
- Coverage % (lines/branches)
Unit Tests
Test service logic in isolation with mocked dependencies:
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock private UserRepository userRepository;
@InjectMocks private UserService userService;
@Test
void createUser_validInput_returnsUser() {
var dto = new CreateUserDto("Alice", "alice@example.com");
var expected = new User(1L, "Alice", "alice@example.com");
when(userRepository.save(any(User.class))).thenReturn(expected);
var result = userService.create(dto);
assertThat(result.name()).isEqualTo("Alice");
verify(userRepository).save(any(User.class));
}
@Test
void createUser_duplicateEmail_throwsException() {
var dto = new CreateUserDto("Alice", "existing@example.com");
when(userRepository.existsByEmail(dto.email())).thenReturn(true);
assertThatThrownBy(() -> userService.create(dto))
.isInstanceOf(DuplicateEmailException.class);
}
}
Integration Tests with Testcontainers
Test against a real database instead of H2:
@SpringBootTest
@Testcontainers
class UserRepositoryIntegrationTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")
.withDatabaseName("testdb");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Autowired private UserRepository userRepository;
@Test
void findByEmail_existingUser_returnsUser() {
userRepository.save(new User("Alice", "alice@example.com"));
var found = userRepository.findByEmail("alice@example.com");
assertThat(found).isPresent();
assertThat(found.get().getName()).isEqualTo("Alice");
}
}
API Tests with MockMvc
Test controller layer with full Spring context:
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired private MockMvc mockMvc;
@MockBean private UserService userService;
@Test
void createUser_validInput_returns201() throws Exception {
var user = new UserDto(1L, "Alice", "alice@example.com");
when(userService.create(any())).thenReturn(user);
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"name": "Alice", "email": "alice@example.com"}
"""))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.name").value("Alice"));
}
@Test
void createUser_invalidEmail_returns400() throws Exception {
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"name": "Alice", "email": "not-an-email"}
"""))
.andExpect(status().isBadRequest());
}
}
Phase 4: Security Scan
# Dependency CVEs
mvn org.owasp:dependency-check-maven:check
# or
./gradlew dependencyCheckAnalyze
# Secrets in source
grep -rn "password\s*=\s*\"" src/ --include="*.java" --include="*.yml" --include="*.properties"
grep -rn "sk-\|api_key\|secret" src/ --include="*.java" --include="*.yml"
# Secrets (git history)
git secrets --scan # if configured
Common Security Findings
# Check for System.out.println (use logger instead)
grep -rn "System\.out\.print" src/main/ --include="*.java"
# Check for raw exception messages in responses
grep -rn "e\.getMessage()" src/main/ --include="*.java"
# Check for wildcard CORS
grep -rn "allowedOrigins.*\*" src/main/ --include="*.java"
Phase 5: Lint/Format (optional gate)
mvn spotless:apply # if using Spotless plugin
./gradlew spotlessApply
Phase 6: Diff Review
git diff --stat
git diff
Checklist:
- No debugging logs left (
System.out,log.debugwithout guards) - Meaningful errors and HTTP statuses
- Transactions and validation present where needed
- Config changes documented
Output Template
VERIFICATION REPORT
===================
Build: [PASS/FAIL]
Static: [PASS/FAIL] (spotbugs/pmd/checkstyle)
Tests: [PASS/FAIL] (X/Y passed, Z% coverage)
Security: [PASS/FAIL] (CVE findings: N)
Diff: [X files changed]
Overall: [READY / NOT READY]
Issues to Fix:
1. ...
2. ...
Continuous Mode
- Re-run phases on significant changes or every 30–60 minutes in long sessions
- Keep a short loop:
mvn -T 4 test+ spotbugs for quick feedback
Remember: Fast feedback beats late surprises. Keep the gate strict—treat warnings as defects in production systems.
Related skills
More from affaan-m/ecc and the wider catalog.
strategic-compact
Suggests manual context compaction at strategic task boundaries to preserve context through multi-phase workflows.
swift-actor-persistence
Thread-safe data persistence in Swift using actors with in-memory cache and file-backed storage.
swift-concurrency-6-2
Swift 6.2 concurrency patterns: single-threaded by default, explicit background offloading with @concurrent, safe MainActor conformances.
swift-protocol-di-testing
Protocol-based dependency injection for testable Swift code with mocks and Swift Testing.
swiftui-patterns
Modern SwiftUI patterns: @Observable state, type-safe navigation, view composition, and performance optimization.
taste
Agent skill from affaan-m/ecc.