Update Python version requirements and fix compatibility issues
- Bump minimum Python version from 3.11 to 3.13 across all apps - Add Python 3.11-3.13 test matrix to CLI workflow - Document Python 3.11+ requirement in .env.example - Fix Starlette Broadcast removal with in-process fallback implementation - Add _InProcessBroadcast class for tests when Starlette Broadcast is unavailable - Refactor API key validators to read live settings instead of cached values - Update database models with explicit
This commit is contained in:
77
packages/js/aitbc-sdk/src/receipts.test.ts
Normal file
77
packages/js/aitbc-sdk/src/receipts.test.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { generateKeyPairSync, sign } from "crypto";
|
||||
import { ReceiptService } from "./receipts";
|
||||
import type { ReceiptSummary } from "./types";
|
||||
|
||||
class ThrowingClient {
|
||||
async request() {
|
||||
throw new Error("offline");
|
||||
}
|
||||
}
|
||||
|
||||
describe("ReceiptService signature verification", () => {
|
||||
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
|
||||
const publicKeyPem = publicKey.export({ type: "spki", format: "pem" }).toString();
|
||||
|
||||
const baseReceipt: ReceiptSummary = {
|
||||
receiptId: "r1",
|
||||
jobId: "job-123",
|
||||
miner: "miner-1",
|
||||
coordinator: "coord-1",
|
||||
issuedAt: new Date().toISOString(),
|
||||
status: "completed",
|
||||
payload: {
|
||||
job_id: "job-123",
|
||||
provider: "miner-1",
|
||||
client: "client-1",
|
||||
},
|
||||
};
|
||||
|
||||
const signPayload = (payload: Record<string, unknown>): string => {
|
||||
const message = Buffer.from(JSON.stringify(payload));
|
||||
return sign(null, message, privateKey).toString("base64");
|
||||
};
|
||||
|
||||
it("validates with provided PEM keys", async () => {
|
||||
const sig = signPayload(baseReceipt.payload!);
|
||||
const receipt: ReceiptSummary = {
|
||||
...baseReceipt,
|
||||
payload: {
|
||||
...baseReceipt.payload,
|
||||
minerSignature: sig,
|
||||
coordinatorSignature: sig,
|
||||
},
|
||||
};
|
||||
|
||||
const svc = new ReceiptService({
|
||||
client: new ThrowingClient() as any,
|
||||
minerPublicKeyPem: publicKeyPem,
|
||||
coordinatorPublicKeyPem: publicKeyPem,
|
||||
signatureAlgorithm: "ed25519",
|
||||
});
|
||||
|
||||
const result = await svc.validateReceipt(receipt);
|
||||
expect(result.valid).toBe(true);
|
||||
});
|
||||
|
||||
it("fails with bad signature", async () => {
|
||||
const receipt: ReceiptSummary = {
|
||||
...baseReceipt,
|
||||
payload: {
|
||||
...baseReceipt.payload,
|
||||
minerSignature: "bad",
|
||||
coordinatorSignature: "bad",
|
||||
},
|
||||
};
|
||||
|
||||
const svc = new ReceiptService({
|
||||
client: new ThrowingClient() as any,
|
||||
minerPublicKeyPem: publicKeyPem,
|
||||
coordinatorPublicKeyPem: publicKeyPem,
|
||||
signatureAlgorithm: "ed25519",
|
||||
});
|
||||
|
||||
const result = await svc.validateReceipt(receipt);
|
||||
expect(result.valid).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user