Files
js/vitest.config.ts
zeekay c86c75efb0 feat(cap): real capability lifecycle — issue/attenuate/verify/verifyChain/revoke
Port the ZAP capability layer to TypeScript at src/cap.ts, the byte-for-byte
peer of github.com/zap-proto/go/cap (SPEC.md §2.3/§3/§4 + capabilities_kinds.md).
Exported at @zap-proto/zap/cap; the universal root stays browser-safe.

- Cap view/builder over the zero-copy runtime for capabilities.zap (v1.1, 3408B
  Sig footer); Capability/Caveat/Revocation codec vendored in, as Go vendors
  capabilities_zap.go into package cap.
- canonicalBytes: Capability[0..164) || canonical(Caveats) — byte-identical to
  Go's signed scope; heap-indirection excluded so it is identical across runtimes.
- issue + attenuate: mint-time delegation gate (parent PermAttenuate or
  Kind==Delegate), monotonic perm narrowing, holder→issuer linkage, expiry
  shrink-only. Signs canonicalBytes.
- verify + verifyChain: all SPEC §2.3 invariants (monotonic perms, holder
  linkage, target invariance, root zero-Parent, delegation gate) + FAIL-CLOSED
  scheme dispatch (reject 0x00/unknown; never downgrade; never return ok on an
  unverified sig).
- capId = SHA-256(canonicalBytes || Sig) (spec-corrected from BLAKE3).
- Schemes: Ed25519 MANDATORY via node:crypto (synchronous, RFC 8032, raw seed
  framed into PKCS8/SPKI). ML-DSA-65 / hybrid / secp256k1 fail-closed unless a
  schemeVerify hook is wired — the JS runtime fabricates no PQ verify.
- Zero npm runtime deps preserved (node:crypto is stdlib); synchronous API
  matching Go exactly, no async contagion through the auth primitive.

Cross-language KAT (interop proof): test/cap_go_kat.hex is a Go-signed cap over
a fixed Ed25519 seed (32x0x42); test/cap_kat.test.ts decodes it, asserts JS
canonicalBytes + capId match Go's, verifies the Go Ed25519 sig in JS -> true,
and a tampered variant -> false. Re-issuing the same inputs+seed in JS
reproduces Go's exact CapID (1b809edc...), signature, and full wire bytes.

Tests: 110 pass (66 pre-existing + 44 new mirroring Go's 34 cap tests:
happy/attenuate-refuses/chain-rejects/fail-closed/revocation + KAT + custom
Signer). Bump @zap-proto/zap 1.4.2 -> 1.5.0.
2026-06-21 01:15:57 -07:00

27 lines
905 B
TypeScript

import { fileURLToPath } from "node:url";
import { defineConfig } from "vitest/config";
// Self-host alias: the generated bindings import the public "@zap-proto/zap"
// specifier; under test we resolve it to the package's own source so the
// runtime under test is exactly what ships. (Mirrors zap-es self-hosting
// its own package specifier → ./src.)
export default defineConfig({
resolve: {
alias: {
// Order matters: the sub-path aliases must precede the bare specifier so
// they are not shadowed.
"@zap-proto/zap/node": fileURLToPath(
new URL("./src/node.ts", import.meta.url),
),
"@zap-proto/zap/cap": fileURLToPath(
new URL("./src/cap.ts", import.meta.url),
),
"@zap-proto/zap": fileURLToPath(new URL("./src/index.ts", import.meta.url)),
},
},
test: {
include: ["test/**/*.test.ts"],
environment: "node",
},
});