SPB Git

spb/zyquo-router Public MIT

One local endpoint, every AI provider — a private OpenAI-compatible LLM gateway for your Mac (170 models, 12 providers).

Swift 95.7% Python 2.3% Shell 1.2% Makefile 0.9%
2.4 KB · 66 lines swift
Raw Blame History
1//2//  AuthMiddlewareTests.swift3//  Zyquo Router4//5//  Author: Simon-Pierre Boucher6//  Mail: contact@spboucher.ai7//8//  Local API key gate: open with no keys, valid / invalid / revoked tokens,9//  malformed Authorization headers.10//1112import NIOHTTP113import XCTest14@testable import ZyquoRouter1516final class AuthMiddlewareTests: XCTestCase {17    private func request(authorization: String?) -> RouteRequest {18        var headers = HTTPHeaders()19        if let authorization {20            headers.add(name: "Authorization", value: authorization)21        }22        return RouteRequest(method: .POST, uri: "/v1/chat/completions", headers: headers, body: Data())23    }2425    func testOpenWhenNoKeysConfigured() {26        let auth = AuthMiddleware(keys: [])27        guard case .allowed(nil) = auth.authorize(request(authorization: nil)) else {28            return XCTFail("no keys ⇒ open on localhost")29        }30    }3132    func testTokenLifecycle() {33        var (record, token) = APIKeyRecord.generate(name: "test")34        let auth = AuthMiddleware(keys: [record])3536        guard case .allowed(let matched) = auth.authorize(request(authorization: "Bearer \(token)")),37              matched?.name == "test" else {38            return XCTFail("valid token must pass and carry its record")39        }40        guard case .unauthorized = auth.authorize(request(authorization: "Bearer zyquo-sk-wrong")) else {41            return XCTFail("unknown token must 401")42        }43        guard case .unauthorized = auth.authorize(request(authorization: nil)) else {44            return XCTFail("missing header must 401 when keys exist")45        }46        guard case .unauthorized = auth.authorize(request(authorization: "Basic abc")) else {47            return XCTFail("non-bearer scheme must 401")48        }4950        // Revocation (disabled key keeps its hash but must be rejected).51        record.enabled = false52        let revoked = AuthMiddleware(keys: [record])53        guard case .unauthorized(let message) = revoked.authorize(request(authorization: "Bearer \(token)")),54              message.contains("revoked") else {55            return XCTFail("revoked token must 401 with a revocation message")56        }57    }5859    func testTokenHashIsStoredNotPlaintext() {60        let (record, token) = APIKeyRecord.generate(name: "x")61        XCTAssertFalse(record.tokenHash.contains(token))62        XCTAssertEqual(record.tokenHash, APIKeyRecord.hash(token))63        XCTAssertEqual(record.tokenPrefix.count, 12)64    }65}66