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
Context
Section titled “Context”kyku test must assert against the generated plan with no cloud calls. Two assertion surfaces were on the table:
- Reuse the repo Gherkin suite (
features/*.feature+ vitest-cucumber). Users would write.featurefiles and step definitions. - A typed TypeScript policy API that receives the desired
BaseResource[]and the offlinePlan.
Decision
Section titled “Decision”Use a typed TypeScript policy API (definePolicy in @kykucloud/core). Do not reuse Gherkin as the user-facing assertion surface.
Why Gherkin is not cheaper here
Section titled “Why Gherkin is not cheaper here”- 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.
PlanandBaseResourceare already typed. Acheck(ctx)function is a few lines; a.featurefile 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.
Assertion surface
Section titled “Assertion surface”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.
Consequences
Section titled “Consequences”- 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.