Skip to content

ADR-001 Policy tests

ADR-001: Typed TypeScript policy API for kyku test

Section titled “ADR-001: Typed TypeScript policy API for kyku test”

Status: Accepted
Date: 2026-08-15
Tickets: PAS-155

kyku test must assert against the generated plan with no cloud calls. Two assertion surfaces were on the table:

  1. Reuse the repo Gherkin suite (features/*.feature + vitest-cucumber). Users would write .feature files and step definitions.
  2. A typed TypeScript policy API that receives the desired BaseResource[] and the offline Plan.

Use a typed TypeScript policy API (definePolicy in @kykucloud/core). Do not reuse Gherkin as the user-facing assertion surface.

  • The in-repo Gherkin suite tests the engine (plan/apply/destroy/crypto). Its step definitions bind to Vitest world objects, not to a user’s infrastructure.ts.
  • Shipping that harness as a product API would mean documenting Cucumber, a World object, and a second file format. Users already write TypeScript configs.
  • Plan and BaseResource are already typed. A check(ctx) function is a few lines; a .feature file still needs custom steps to reach security-group ingress.
  • Scope cut: no OPA/Rego, no watch mode, no coverage. Adding a Gherkin parser would be extra surface for no extra power.

Gherkin stays as the project’s own BDD suite. It is not the policy language.

import { definePolicy, findOpenIngress } from '@kykucloud/core'
export default [
definePolicy('ssh-not-world-open', ({ resources, plan, fail }) => {
for (const resource of resources) {
for (const hit of findOpenIngress(resource, { port: 22 })) {
fail(`${resource.id}: SSH open to ${hit.source}`, resource.id)
}
}
void plan
}),
]

kyku test loads the config, builds an offline plan from local state (never provider.readState), runs each policy, exits 1 on any fail(), 0 when all pass.

  • Default policy file is ./infrastructure.test.ts.
  • Policies can inspect desired resources and the generated plan (creates/updates/destroys) without credentials.
  • Sample in examples/policy/: an open SSH rule fails; a narrowed source passes.