kotlin-security-testing
```kotlin // BAD -- hardcoded secret val jwtSecret = "super-secret-key-do-not-share"
$ npx -y skills add notque/vexjoy-agent --agent claude-codeHow it fires
How this agent gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
Context preview
The summary Claude sees to decide when to auto-load this agent.
```kotlin // BAD -- hardcoded secret val jwtSecret = "super-secret-key-do-not-share"
Agent definition
kotlin-security-testing.mdKotlin Security & Testing Reference
Security
Secrets via Environment Variables
// BAD -- hardcoded secret
val jwtSecret = "super-secret-key-do-not-share"
// GOOD -- environment variable with fail-fast on missing
val jwtSecret: String = System.getenv("JWT_SECRET")
?: throw IllegalStateException("JWT_SECRET environment variable must be set")
// GOOD -- using requireNotNull for cleaner message
val dbPassword: String = requireNotNull(System.getenv("DB_PASSWORD")) {
"DB_PASSWORD environment variable must be set before starting the application"
}Exposed DSL -- Parameterized Queries Only
// BAD -- SQL injection via string interpolation
fun findByEmail(email: String): AppUser? {
return transaction {
exec("SELECT * FROM users WHERE email = '\$email'") { rs -> parseRow(rs) } // NEVER
}
}
// GOOD -- Exposed DSL uses parameterized queries automatically
fun findByEmail(email: String): AppUser? = transaction {
Users.select { Users.email eq email }
.singleOrNull()
?.let { row -> Users.toAppUser(row) }
}
// GOOD -- if raw SQL is necessary, use explicit parameters
fun findByDomain(domain: String): List<AppUser> = transaction {
exec("SELECT * FROM users WHERE email LIKE ?", listOf(stringParam("%@\$domain"))) { rs ->
generateSequence { if (rs.next()) toAppUser(rs) else null }.toList()
}
}Ktor JWT Authentication
fun Application.configureSecurity() {
val secret = requireNotNull(System.getenv("JWT_SECRET")) { "JWT_SECRET must be set" }
val issuer = requireNotNull(System.getenv("JWT_ISSUER")) { "JWT_ISSUER must be set" }
val audience = requireNotNull(System.getenv("JWT_AUDIENCE")) { "JWT_AUDIENCE must be set" }
authentication {
jwt("auth-jwt") {
realm = "MyApp"
verifier(
JWT.require(Algorithm.HMAC256(secret))
.withIssuer(issuer)
.withAudience(audience)
.build()
)
validate { credential ->
// Validate audience, issuer, AND subject -- all three required
if (credential.payload.audience.contains(audience) &&
credential.payload.issuer == issuer &&
credential.payload.subject != null
) {
JWTPrincipal(credential.payload)
} else {
null // authentication fails
}
}
}
}
}Null Safety as a Security Property
`!!` on externally-sourced data (HTTP params, DB results, env vars) is a security vulnerability — converts compile-time safety into runtime NPE triggerable by adversarial input. Treat as critical defect.
---
Pattern Corrections
| Pattern | Why It's Wrong | Detection | Fix | |---------|---------------|-----------|-----| | `!!` operator | Bypasses null safety; runtime NPE | `grep -rn '!!' src/` | Use `?.`, `?:`, `require()`, `checkNotNull()` | | Nested scope functions | Unreadable, hard to debug; `this` ambiguity | Code review | Extract intermediate `val`s; use single scope function per expression | | `var` when `val` works | Accidental mutation, harder to reason about | detekt: `VarCouldBeVal` | Declare `val`; use `copy()` for updates | | `MutableList`/`MutableMap` in signatures | Exposes mutation capability beyond intent | Code review | Use `List`/`Map`; return immutable copy if needed | | `GlobalScope.launch` | Uncancellable; leaks coroutines at shutdown | `grep -rn 'GlobalScope' src/` | Use `viewModelScope`, `lifecycleScope`, or explicit scope | | Blocking call without `Dispatchers.IO` | Starves coroutine thread pool; hangs | Code review | Wrap in `withContext(Dispatchers.IO) { ... }` | | Platform type passthrough | Silently nullable; NPE at arbitrary call site | Code review; detekt | Annotate at Java boundary or guard with `?:` | | String interpolation in SQL | SQL injection | grep for `exec(` with string interpolation | Use Exposed DSL or explicit `?` parameters | | Hardcoded secrets | Credential leak | grep for `password =` string literals | `System.getenv()` with `requireNotNull()` | | `else` on sealed `when` | Hides missing cases for new subtypes | Code review | Remove `else`; let compiler enforce exhaustiveness | | Java-style getters/setters | Verbose; ignores Kotlin property syntax | Code review | Use Kotlin properties directly |
---
Testing
Kotest Styles
Choose per context, keep consistent within a module:
// StringSpec -- simple, flat tests
class UserValidatorTest : StringSpec({
"should reject email without @ symbol" {
val validator = UserValidator()
validator.validate("notanemail") shouldBe ValidationResult.Invalid("Invalid email format")
}
})
// FunSpec -- grouping related tests
class OrderServiceTest : FunSpec({
val mockRepo = mockk<OrderRepository>()
val service = OrderService(mockRepo)
test("create order persists to repository") {
every { mockRepo.save(any()) } returns Unit
service.createOrder(orderRequest)
verify(exactly = 1) { mockRepo.save(any()) }
}
})
// BehaviorSpec -- Given/When/Then for complex scenarios
class PaymentProcessorTest : BehaviorSpec({
Given("a valid payment request") {
val processor = PaymentProcessor(mockk())
When("the card is authorized") {
Then("the order status transitions to PAID") { }
}
}
})MockK
// Mock and stub
val repo = mockk<AccountRepository>()
every { repo.findById(1L) } returns AppUser(id = UserId(1L), name = "Alice", email = "alice@example.com")
every { repo.findById(99L) } returns null
// Capture arguments
val slot = slot<AppUser>()
every { repo.save(capture(slot)) } returns Unit
service.createUser("Bob")
assertEquals("Bob", slot.captured.name)
// Verify interactions
verify(exactly = 1) { repo.save(any()) }
confirmVerified(repo)
// Suspend functioRead more
Kotlin Security & Testing Reference
Security
Secrets via Environment Variables
// BAD -- hardcoded secret
val jwtSecret = "super-secret-key-do-not-share"
// GOOD -- environment variable with fail-fast on missing
val jwtSecret: String = System.getenv("JWT_SECRET")
?: throw IllegalStateException("JWT_SECRET environment variable must be set")
// GOOD -- using requireNotNull for cleaner message
val dbPassword: String = requireNotNull(System.getenv("DB_PASSWORD")) {
"DB_PASSWORD environment variable must be set before starting the application"
}Exposed DSL -- Parameterized Queries Only
// BAD -- SQL injection via string interpolation
fun findByEmail(email: String): AppUser? {
return transaction {
exec("SELECT * FROM users WHERE email = '\$email'") { rs -> parseRow(rs) } // NEVER
}
}
// GOOD -- Exposed DSL uses parameterized queries automatically
fun findByEmail(email: String): AppUser? = transaction {
Users.select { Users.email eq email }
.singleOrNull()
?.let { row -> Users.toAppUser(row) }
}
// GOOD -- if raw SQL is necessary, use explicit parameters
fun findByDomain(domain: String): List<AppUser> = transaction {
exec("SELECT * FROM users WHERE email LIKE ?", listOf(stringParam("%@\$domain"))) { rs ->
generateSequence { if (rs.next()) toAppUser(rs) else null }.toList()
}
}Ktor JWT Authentication
fun Application.configureSecurity() {
val secret = requireNotNull(System.getenv("JWT_SECRET")) { "JWT_SECRET must be set" }
val issuer = requireNotNull(System.getenv("JWT_ISSUER")) { "JWT_ISSUER must be set" }
val audience = requireNotNull(System.getenv("JWT_AUDIENCE")) { "JWT_AUDIENCE must be set" }
authentication {
jwt("auth-jwt") {
realm = "MyApp"
verifier(
JWT.require(Algorithm.HMAC256(secret))
.withIssuer(issuer)
.withAudience(audience)
.build()
)
validate { credential ->
// Validate audience, issuer, AND subject -- all three required
if (credential.payload.audience.contains(audience) &&
credential.payload.issuer == issuer &&
credential.payload.subject != null
) {
JWTPrincipal(credential.payload)
} else {
null // authentication fails
}
}
}
}
}Null Safety as a Security Property
`!!` on externally-sourced data (HTTP params, DB results, env vars) is a security vulnerability — converts compile-time safety into runtime NPE triggerable by adversarial input. Treat as critical defect.
---
Pattern Corrections
| Pattern | Why It's Wrong | Detection | Fix | |---------|---------------|-----------|-----| | `!!` operator | Bypasses null safety; runtime NPE | `grep -rn '!!' src/` | Use `?.`, `?:`, `require()`, `checkNotNull()` | | Nested scope functions | Unreadable, hard to debug; `this` ambiguity | Code review | Extract intermediate `val`s; use single scope function per expression | | `var` when `val` works | Accidental mutation, harder to reason about | detekt: `VarCouldBeVal` | Declare `val`; use `copy()` for updates | | `MutableList`/`MutableMap` in signatures | Exposes mutation capability beyond intent | Code review | Use `List`/`Map`; return immutable copy if needed | | `GlobalScope.launch` | Uncancellable; leaks coroutines at shutdown | `grep -rn 'GlobalScope' src/` | Use `viewModelScope`, `lifecycleScope`, or explicit scope | | Blocking call without `Dispatchers.IO` | Starves coroutine thread pool; hangs | Code review | Wrap in `withContext(Dispatchers.IO) { ... }` | | Platform type passthrough | Silently nullable; NPE at arbitrary call site | Code review; detekt | Annotate at Java boundary or guard with `?:` | | String interpolation in SQL | SQL injection | grep for `exec(` with string interpolation | Use Exposed DSL or explicit `?` parameters | | Hardcoded secrets | Credential leak | grep for `password =` string literals | `System.getenv()` with `requireNotNull()` | | `else` on sealed `when` | Hides missing cases for new subtypes | Code review | Remove `else`; let compiler enforce exhaustiveness | | Java-style getters/setters | Verbose; ignores Kotlin property syntax | Code review | Use Kotlin properties directly |
---
Testing
Kotest Styles
Choose per context, keep consistent within a module:
// StringSpec -- simple, flat tests
class UserValidatorTest : StringSpec({
"should reject email without @ symbol" {
val validator = UserValidator()
validator.validate("notanemail") shouldBe ValidationResult.Invalid("Invalid email format")
}
})
// FunSpec -- grouping related tests
class OrderServiceTest : FunSpec({
val mockRepo = mockk<OrderRepository>()
val service = OrderService(mockRepo)
test("create order persists to repository") {
every { mockRepo.save(any()) } returns Unit
service.createOrder(orderRequest)
verify(exactly = 1) { mockRepo.save(any()) }
}
})
// BehaviorSpec -- Given/When/Then for complex scenarios
class PaymentProcessorTest : BehaviorSpec({
Given("a valid payment request") {
val processor = PaymentProcessor(mockk())
When("the card is authorized") {
Then("the order status transitions to PAID") { }
}
}
})MockK
// Mock and stub
val repo = mockk<AccountRepository>()
every { repo.findById(1L) } returns AppUser(id = UserId(1L), name = "Alice", email = "alice@example.com")
every { repo.findById(99L) } returns null
// Capture arguments
val slot = slot<AppUser>()
every { repo.save(capture(slot)) } returns Unit
service.createUser("Bob")
assertEquals("Bob", slot.captured.name)
// Verify interactions
verify(exactly = 1) { repo.save(any()) }
confirmVerified(repo)
// Suspend functioEssays and writing behind this toolkit live at vexjoy.com. AI agents skip steps. "Looks correct" replaces running tests. "Trivial change" replaces verification.
Repo: notque/vexjoy-agent
Other agents on vexjoy-agent.
- ansible-automation-engineer
Ansible automation: playbooks, roles, collections, Molecule testing, Vault security.
Open agent - modules
**Scope**: Module selection patterns, builtin vs command/shell decisions, collection modules, and version-specific module changes **Version range**: ansible-core 2.14+ / Ansible Collections (community.general 7.0+) **Generated**: 2026-04-04 — verify against current Ansible
Open agent - testing
**Scope**: Molecule test scenarios, ansible-lint rules, idempotency validation, and check-mode patterns **Version range**: Molecule 6.0+ / ansible-lint 6.0+ / ansible-core 2.14+ **Generated**: 2026-04-04 — verify against current Molecule and ansible-lint documentation
Open agent - base-instructions
Universal operational rules injected by /do at agent dispatch. Domain-specific rules live in each agent's .md file.
Open agent - communication-patterns
**Scope**: Failure modes in agent output style — over-reporting, self-congratulation, verbose narration, and hedging. Covers what to detect and how to fix each. **Version range**: all versions **Generated**: 2026-05-11
Open agent - combat-effects-upgrade
Zero-dependency combat visual upgrades: CSS particle replacement, Framer Motion combat juice, CSS 3D card transforms.
Open agent

