AFI parity: close all 35 gaps — every adapter wires every AFI-common capability
The conformance board (tests/afi/test_capability_parity.py) is now fully green: 90 capability cells + 4 meta-locks + 3 codegen byte-parity = 97 passed. The gaps the prose table used to launder as "Django-only" / "out of scope" are wired, against the pinned-spec model (single-authored spec, byte-identical conformance across languages) — never per-language reimplementation. FastAPI — edge_manifest + PSR (logic single-sourced in mizan_core.manifest), WebSocket RPC (/ws/ through the shared dispatch), SSR (the framework-agnostic SSRBridge relocated to mizan_core.ssr; Django rides it from there), Shapes (SQLAlchemy projection, same declaration surface as django-readers), Forms (Pydantic schema/validate/submit). Rust (Axum + Tauri + cores/mizan-rust) — X-Mizan-Invalidate header, auth= enforcement, origin HMAC cache, edge manifest + PSR, WebSocket handler / IPC subscription channel, multipart upload, SSR bridge, Shapes, Forms; JWT/MWT mint+verify and cache-key derivation byte-pinned to the Python reference (cache_keys_pin, token_pin, invalidate_header_pin). TypeScript — a KDL IR emitter byte-identical to the Python build_ir (so a TS backend can feed the codegen — the largest gap), multipart upload, session-init, WebSocket transport, SSR bridge, JWT/MWT mint (pinned to Python), Shapes, Forms. Verified in the merged tree: core 25, fastapi 74, django 353/21-skip, mizan-rust (incl. cross-language pins) green, axum 10, tauri 8, mizan-ts 103/2-skip. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,23 @@
|
||||
/**
|
||||
* MWT decode tests — round-trip + cross-language pin against Python create_mwt.
|
||||
* MWT / JWT token tests — decode round-trip + cross-language byte-parity pins
|
||||
* against the live Python mint (`cores/mizan-python`).
|
||||
*/
|
||||
|
||||
import { describe, test, expect } from 'bun:test'
|
||||
import { createHmac } from 'crypto'
|
||||
import { decodeMwt, decodeJwtBearer, identityFromMwt } from '../src'
|
||||
import { createHmac, createHash } from 'crypto'
|
||||
import { execFileSync } from 'child_process'
|
||||
import { existsSync } from 'fs'
|
||||
import { resolve } from 'path'
|
||||
import {
|
||||
decodeMwt,
|
||||
decodeJwtBearer,
|
||||
identityFromMwt,
|
||||
signMwt,
|
||||
computePermissionKey,
|
||||
createAccessToken,
|
||||
createRefreshToken,
|
||||
type MintUser,
|
||||
} from '../src'
|
||||
|
||||
function b64url(buf: Buffer | string): string {
|
||||
return Buffer.from(buf).toString('base64url')
|
||||
@@ -124,3 +137,117 @@ describe('MWT cross-language pin (Python create_mwt)', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// ─── Mint: round-trip + cross-language byte-parity ────────────────────────────
|
||||
|
||||
const REPO_ROOT = resolve(import.meta.dir, '../../..')
|
||||
const MIZAN_PYTHON = resolve(REPO_ROOT, 'cores/mizan-python')
|
||||
|
||||
const UV_AVAILABLE = (() => {
|
||||
try {
|
||||
execFileSync('uv', ['--version'], { stdio: 'ignore' })
|
||||
return existsSync(resolve(MIZAN_PYTHON, 'pyproject.toml'))
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
})()
|
||||
|
||||
/**
|
||||
* Run a Python snippet against cores/mizan-python and return stdout (trimmed).
|
||||
* `time.time` is pinned so the production mint functions are deterministic.
|
||||
*/
|
||||
function py(snippet: string): string {
|
||||
return execFileSync('uv', ['run', '--project', MIZAN_PYTHON, 'python', '-c', snippet], {
|
||||
encoding: 'utf-8',
|
||||
}).trim()
|
||||
}
|
||||
|
||||
describe('MWT mint — round-trip', () => {
|
||||
const SECRET = 'mint-roundtrip-secret'
|
||||
|
||||
test('signMwt produces a token decodeMwt accepts', () => {
|
||||
const user: MintUser = { pk: 7, isStaff: true, isSuperuser: false, permissions: ['a.view', 'a.edit'] }
|
||||
const token = signMwt(user, SECRET, { now: Math.floor(Date.now() / 1000) })
|
||||
const p = decodeMwt(token, SECRET)
|
||||
expect(p).not.toBeNull()
|
||||
expect(p!.sub).toBe('7')
|
||||
expect(p!.staff).toBe(true)
|
||||
expect(p!.super).toBe(false)
|
||||
expect(p!.kid).toBe('v1')
|
||||
expect(p!.aud).toBe('mizan')
|
||||
// pkey is the permission hash, surviving the round-trip.
|
||||
expect(p!.pkey).toBe(computePermissionKey(user))
|
||||
})
|
||||
|
||||
test('computePermissionKey matches the documented blob hash', () => {
|
||||
const user: MintUser = { pk: 1, isStaff: true, isSuperuser: false, permissions: ['z', 'a'] }
|
||||
// "1:0:a,z" — staff:super:sorted-perms.
|
||||
const expected = createHash('sha256').update('1:0:a,z', 'utf-8').digest('hex')
|
||||
expect(computePermissionKey(user)).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('MWT mint — cross-language pin (Python create_mwt)', () => {
|
||||
const SECRET = 'pin-mint-secret-mwt'
|
||||
const NOW = 1700000000
|
||||
|
||||
test.skipIf(!UV_AVAILABLE)('TS signMwt byte-identical to Python create_mwt', () => {
|
||||
const user: MintUser = {
|
||||
pk: 42,
|
||||
isStaff: true,
|
||||
isSuperuser: false,
|
||||
permissions: ['app.view_thing', 'app.change_thing'],
|
||||
}
|
||||
const tsToken = signMwt(user, SECRET, { ttl: 300, now: NOW })
|
||||
|
||||
// Drive the REAL create_mwt with time.time pinned to NOW and a
|
||||
// user stub whose get_all_permissions returns the same perms.
|
||||
const pyToken = py(String.raw`
|
||||
import time, sys
|
||||
time.time = lambda: ${NOW}
|
||||
from mizan_core.mwt import create_mwt
|
||||
|
||||
class U:
|
||||
pk = 42
|
||||
is_staff = True
|
||||
is_superuser = False
|
||||
def get_all_permissions(self):
|
||||
return {"app.view_thing", "app.change_thing"}
|
||||
|
||||
sys.stdout.write(create_mwt(U(), ${JSON.stringify(SECRET)}, ttl=300))
|
||||
`)
|
||||
expect(tsToken).toBe(pyToken)
|
||||
})
|
||||
})
|
||||
|
||||
describe('JWT mint — cross-language pin (Python create_access/refresh_token)', () => {
|
||||
const SECRET = 'pin-mint-secret-jwt'
|
||||
const NOW = 1700000000
|
||||
|
||||
const config = { privateKey: SECRET, accessTokenExpiresIn: 300, refreshTokenExpiresIn: 604800 }
|
||||
const claims = { userId: 42, sessionKey: 'sess-abc', isStaff: true, isSuperuser: false }
|
||||
|
||||
test.skipIf(!UV_AVAILABLE)('TS createAccessToken byte-identical to Python', () => {
|
||||
const tsToken = createAccessToken(claims, config, NOW)
|
||||
const pyToken = py(String.raw`
|
||||
import time, sys
|
||||
time.time = lambda: ${NOW}
|
||||
from mizan_core.auth.jwt import JWTConfig, create_access_token
|
||||
cfg = JWTConfig(private_key=${JSON.stringify(SECRET)}, public_key=${JSON.stringify(SECRET)})
|
||||
sys.stdout.write(create_access_token(42, "sess-abc", cfg, is_staff=True, is_superuser=False))
|
||||
`)
|
||||
expect(tsToken).toBe(pyToken)
|
||||
})
|
||||
|
||||
test.skipIf(!UV_AVAILABLE)('TS createRefreshToken byte-identical to Python', () => {
|
||||
const tsToken = createRefreshToken(claims, config, NOW)
|
||||
const pyToken = py(String.raw`
|
||||
import time, sys
|
||||
time.time = lambda: ${NOW}
|
||||
from mizan_core.auth.jwt import JWTConfig, create_refresh_token
|
||||
cfg = JWTConfig(private_key=${JSON.stringify(SECRET)}, public_key=${JSON.stringify(SECRET)})
|
||||
sys.stdout.write(create_refresh_token(42, "sess-abc", cfg, is_staff=True, is_superuser=False))
|
||||
`)
|
||||
expect(tsToken).toBe(pyToken)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user