Test Results

118 / 118 Tests Passing

Every compliance-critical path covered. RLS isolation verified at the PostgreSQL layer — not mocked. Results updated on every pull request via GitHub Actions CI.

118 / 118
Passing
0
Failed
Skipped
~4.7s
Runtime
2026-05-20
Last Run

Test Suites

10 suites · 118 assertions
SDK
21/21
@kakunin/sdk — TypeScript SDK
sdk/kakunin-sdk/tests/sdk.test.ts

Public SDK unit tests. Mocks fetch globally. Covers client construction, model hash utility, all resource wrappers, retry logic, error mapping, and HMAC webhook verification.

Constructor throws if apiKey missing
kkn_test_ prefix detected as sandbox mode
kkn_live_ prefix is not sandbox
computeModelHash → sha256: prefixed 64-char hex
computeModelHash is deterministic for same input
computeModelHash differs for different inputs
agents.create returns agent on 201
agents.create throws KakuninError on 422
agents.certify returns certificate on 201
agents.certify throws on 409 (already certified)
agents.getRisk returns risk profile
events.ingest returns scored event result
events.ingest flags high-risk events (revocation_check_queued: true)
certificates.revoke returns revocation result
verify.cert returns verified agent info — no Authorization header sent
Error mapping: KakuninAuthError thrown on 401
Retry: 500 then 200 → succeeds on second attempt
Retry exhausted: throws KakuninError after max retries
webhooks.constructEvent verifies valid HMAC-SHA256 signature
webhooks.constructEvent throws on invalid signature
webhooks.constructEvent throws on stale timestamp (> tolerance)
SDK
16/16
@kakunin/mcp — MCP Server Tools
mcp/kakunin-mcp/tests/mcp.test.ts

MCP tool handler unit tests. Tests all three tools directly without MCP transport. KakuninMcpClient mocked to isolate handler logic.

verify_agent_scope: allows permitted action by exact scope match
verify_agent_scope: denies action not in permitted_actions
verify_agent_scope: denies when no active certificate
verify_agent_scope: denies when certificate is revoked
verify_agent_scope: denies when transaction amount exceeds financial scope
verify_agent_scope: allows when transaction amount is within limit
verify_agent_scope: denies when venue not in permitted_venues
verify_agent_scope: allows when venue is in permitted_venues
verify_agent_scope: returns permitted_actions list in result
check_risk_score: returns low risk profile with stable trend
check_risk_score: returns high risk recommendation with revocation warning
check_risk_score: returns medium increasing recommendation
check_risk_score: handles null drift (< 30 days of data)
audit_log_append: returns tx_id and risk score on success
audit_log_append: passes session_id through to ingestEvent
audit_log_append: flags revocation_check_queued on high-risk event
Unit
13/13
Risk Scoring Engine
__tests__/unit/risk-engine.test.ts

Deterministic expected score for every action type. Band boundary assertions. Auto-revocation threshold checks.

api_call → score 0.05, band low
authentication_attempt → score 0.15, band low
data_access → score 0.20, band low
authentication_failure → score 0.55, band medium
data_mutation → score 0.35, band medium
transaction_initiated → score 0.30, band medium
transaction_anomaly → score 0.85, band high
unauthorized_access_attempt → score 0.95, band high
Unknown action type → fallback 0.10, band low
Band boundary: 0.85 is high (not medium)
Band boundary: 0.30 is medium (not low)
Auto-revocation: transaction_anomaly ≥ 0.85
Auto-revocation: unauthorized_access_attempt ≥ 0.85
Integration
6/6
Certificate Issuance
__tests__/api/certify.test.ts

Full certificate issuance flow: agent lookup → KMS signing → DB write → audit log.

Issues certificate and writes audit_log on success
Returns 409 when agent already has active certificate
Returns 404 when agent not found
Returns 422 when agent is retired
Returns 503 when AWS KMS credentials not configured
Returns 500 on DB insert failure
Integration
5/5
Certificate Verification
__tests__/api/verify.test.ts

Public edge-cached verification endpoint. Cache-Control headers, expiry logic, revocation status.

Returns valid cert with agent info and Cache-Control: s-maxage=300
Returns 404 for unknown serial number
Returns 400 for serial shorter than 8 characters (no DB call)
Revoked cert returns valid: false with s-maxage=60
Active cert with past expires_at returns status: expired
Integration
10/10
Certificate Revocation
__tests__/api/revoke.test.ts

Manual revocation: cert update, agent suspension, audit trail, CRL refresh via QStash.

Revokes cert and returns status: revoked with timestamp
Writes certificate.revoked entry to audit_log
Dispatches certificate.revoked webhook event
Enqueues CRL regeneration via QStash after revocation
Returns 409 when certificate already revoked
Returns 422 when certificate is expired
Returns 404 when certificate not found or wrong tenant
Returns 400 when revocation reason is empty
Returns 400 when request body missing reason field
Returns 500 on database update failure
Integration
17/17
Behavior Event Ingestion
__tests__/api/events.test.ts

Core event pipeline: Zod validation → quota check → risk scoring → DB write → async side effects.

Ingests low-risk event — returns risk_score, risk_band, event_id
Writes behavior.{action_type} to audit_log on success
High-risk event queues revocation check via QStash
High-risk event dispatches risk.alert webhook
Financial: amount > max_single_trade_usd auto-elevates to unauthorized_access_attempt
Financial: disallowed venue auto-elevates to unauthorized_access_attempt
Returns 429 when monthly event quota exceeded (with Retry-After header)
Returns 404 on cross-tenant agent injection attempt
Returns 422 when agent is retired
Returns 400 on invalid action_type (Zod enum)
Returns 400 on non-UUID agentId
Returns 500 on database insert failure
QStash failure is non-blocking — response still 200
GET: returns events with pagination metadata
GET: returns 400 for invalid band parameter
GET: returns 400 for invalid action_type parameter
GET: clamps limit to maximum 100
Integration
14/14
Agent Registration
__tests__/api/agents.test.ts

Agent creation and listing. Plan quota enforcement, financial scope metadata, Stripe sync.

Creates agent and returns 201 with agent data
Writes agent.created to audit_log on success
Fires Stripe subscription quantity sync (fire-and-forget)
Stores financial_scope in agent metadata when provided
Returns 422 when agent quota exceeded for current plan
Returns 400 when name is missing
Returns 400 when model_hash is missing
Returns 400 when financial_scope is missing required fields
Returns 500 on database insert failure
GET: returns agents list with total count
GET: clamps limit to maximum 100
GET: applies status filter when provided
GET: ignores invalid status parameter
GET: returns 500 on database error
Integration
9/9
Kill Switch (Halt)
__tests__/api/halt.test.ts

Cryptographic kill switch: signed halt receipt, cert revocation, agent suspension. KMS failure is non-fatal.

Halts agent and returns signed halt receipt
Writes agent.halted to audit_log
Dispatches agent.halted webhook
KMS signing failure is non-fatal — signed_by_ca: false
Proceeds without active certificate (agent suspended only)
Returns 404 when agent not found
Returns 409 when agent is already retired
Returns 400 for invalid reason enum value
Returns 400 when request body has invalid reason
SecurityLive DB
7/7
Cross-Tenant RLS Isolation
__tests__/security/rls-isolation.test.ts

Live Supabase test DB. Tenant A cannot read Tenant B data at the PostgreSQL layer — no application-level filter can fake this.

agents table: Tenant A cannot read Tenant B agents
certificates table: Tenant A cannot read Tenant B certificates
behavior_events table: Tenant A cannot read Tenant B events
compliance_reports table: Tenant A cannot read Tenant B reports
audit_log table: Tenant A cannot read Tenant B audit entries
api_keys table: Tenant A cannot read Tenant B API key hashes
audit_log immutability: UPDATE blocked by DB rule (append-only)

What Is Tested vs. Mocked

ComponentApproachReason
Risk scoring logicReal code, no mockPure function — tests the actual algorithm
Certificate issuanceReal code, KMS mockedKMS calls require live AWS credentials
Supabase DB operationsMockedAvoids test DB dependency; tests business logic in isolation
QStash job queueMockedFire-and-forget — tested for invocation, not delivery
Webhook dispatchMockedExternal HTTP — tested for invocation and correct payload
AWS KMS signingMockedRequires live AWS credentials with KMS permissions
Stripe billing syncMockedExternal API — tested for invocation
RLS policiesLive test DBMust run against real Postgres RLS engine — cannot mock
@kakunin/sdk HTTP clientMocked fetchTests retry logic, error mapping, and HMAC signing without a live API
@kakunin/mcp tool handlersReal code, client mockedTool handlers tested directly; KakuninMcpClient mocked to isolate logic

Run the Tests

Commands

All tests (no live DB required)npm run test
Full suite including RLS isolationnode --env-file=.env.rls.test node_modules/.bin/vitest run
RLS isolation onlynode --env-file=.env.rls.test node_modules/.bin/vitest run __tests__/security/rls-isolation.test.ts
Seed RLS test DB (dedicated test project only)npx tsx scripts/setup-rls-test-db.ts
@kakunin/sdk — 21 unit testscd sdk/kakunin-sdk && npm test
@kakunin/mcp — 16 unit testscd mcp/kakunin-mcp && npm test
Vitest 4.1
TypeScript strict
Node.js environment
GitHub Actions CI
RLS on live Supabase test project