@antseed/cli 0.1.178 → 0.1.179

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +3 -0
  2. package/dist/cli/commands/apps/index.d.ts +42 -0
  3. package/dist/cli/commands/apps/index.d.ts.map +1 -0
  4. package/dist/cli/commands/apps/index.js +224 -0
  5. package/dist/cli/commands/apps/index.js.map +1 -0
  6. package/dist/cli/commands/apps/index.test.d.ts +2 -0
  7. package/dist/cli/commands/apps/index.test.d.ts.map +1 -0
  8. package/dist/cli/commands/apps/index.test.js +206 -0
  9. package/dist/cli/commands/apps/index.test.js.map +1 -0
  10. package/dist/cli/commands/buyer/deposit.d.ts.map +1 -1
  11. package/dist/cli/commands/buyer/deposit.js +9 -1
  12. package/dist/cli/commands/buyer/deposit.js.map +1 -1
  13. package/dist/cli/index.js +2 -0
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/gateway/gateway.test.js +31 -0
  16. package/dist/gateway/gateway.test.js.map +1 -1
  17. package/dist/gateway/server.d.ts.map +1 -1
  18. package/dist/gateway/server.js +4 -1
  19. package/dist/gateway/server.js.map +1 -1
  20. package/dist/proxy/buyer-proxy.d.ts.map +1 -1
  21. package/dist/proxy/buyer-proxy.js +9 -1
  22. package/dist/proxy/buyer-proxy.js.map +1 -1
  23. package/dist/proxy/buyer-proxy.test.js +77 -0
  24. package/dist/proxy/buyer-proxy.test.js.map +1 -1
  25. package/dist/proxy/credential-headers.d.ts +17 -0
  26. package/dist/proxy/credential-headers.d.ts.map +1 -0
  27. package/dist/proxy/credential-headers.js +29 -0
  28. package/dist/proxy/credential-headers.js.map +1 -0
  29. package/dist/proxy/deposit-watcher.d.ts +19 -0
  30. package/dist/proxy/deposit-watcher.d.ts.map +1 -1
  31. package/dist/proxy/deposit-watcher.js +44 -8
  32. package/dist/proxy/deposit-watcher.js.map +1 -1
  33. package/dist/proxy/deposit-watcher.test.js +27 -4
  34. package/dist/proxy/deposit-watcher.test.js.map +1 -1
  35. package/dist/system-proxy/proxy-server.js +2 -2
  36. package/dist/system-proxy/proxy-server.js.map +1 -1
  37. package/dist/system-proxy/proxy-server.test.js +40 -0
  38. package/dist/system-proxy/proxy-server.test.js.map +1 -1
  39. package/package.json +7 -6
@@ -803,6 +803,29 @@ test('conversation routing keeps the actual peer as a soft preference and fails
803
803
  assert.equal(route.statusCode, 200);
804
804
  assert.equal(JSON.parse(route.body).conversation.lastModel, `${rankedFirst.peerId}@Kimi K3`);
805
805
  });
806
+ test('BuyerProxy does not forward the Expect header to the seller', async () => {
807
+ const peer = makePeer('c', ['openai']);
808
+ peer.providerServiceApiProtocols = {
809
+ openai: { services: { 'kimi-k3': ['openai-chat-completions'] } },
810
+ };
811
+ const proxy = makeBuyerProxyWithPeers([peer], [peer], permissiveRouter());
812
+ let forwardedHeaders;
813
+ proxy._node.sendRequest = async (_peer, request) => {
814
+ forwardedHeaders = request.headers;
815
+ return {
816
+ requestId: request.requestId,
817
+ statusCode: 200,
818
+ headers: { 'content-type': 'application/json' },
819
+ body: Buffer.from('{}'),
820
+ };
821
+ };
822
+ await invokeProxy(proxy, makeProxyRequest({
823
+ headers: { expect: '100-continue' },
824
+ body: { model: 'kimi-k3', messages: [{ role: 'user', content: 'hello' }] },
825
+ }));
826
+ assert.ok(forwardedHeaders);
827
+ assert.equal(forwardedHeaders['expect'], undefined);
828
+ });
806
829
  test('model-only request applies a cached-input pricing reputation penalty', async () => {
807
830
  const priced = makePeer('a', ['openai']);
808
831
  priced.reputationScore = 75;
@@ -3403,6 +3426,60 @@ test('getSweepReceipt returns cached relayer receipts case-insensitively', () =>
3403
3426
  assert.equal(proxy.getSweepReceipt(nonce.toLowerCase()), receipt);
3404
3427
  assert.equal(proxy.getSweepReceipt('0x' + '00'.repeat(32)), null);
3405
3428
  });
3429
+ // Issue #1104: a client's own provider credentials must never reach a seller.
3430
+ // Sellers authenticate their upstream with their own keys; the buyer pays
3431
+ // on-chain. A malicious seller would otherwise read the raw key off the wire.
3432
+ const CLIENT_CREDENTIAL_HEADERS = {
3433
+ authorization: 'Bearer sk-real',
3434
+ 'proxy-authorization': 'Basic cHJveHk6c2VjcmV0',
3435
+ 'x-api-key': 'sk-ant-real',
3436
+ 'x-goog-api-key': 'AIza-real',
3437
+ 'api-key': 'azure-real',
3438
+ cookie: 'session=real',
3439
+ };
3440
+ test('buyer proxy does not forward client credential headers to the seller (buffered)', async () => {
3441
+ const peer = makePeer('e', ['openai']);
3442
+ const proxy = makeBuyerProxyWithPeers([peer], [peer], permissiveRouter());
3443
+ let seen = null;
3444
+ proxy._node.sendRequest = async (_peer, request) => {
3445
+ seen = request.headers;
3446
+ return { requestId: request.requestId, statusCode: 200, headers: { 'content-type': 'application/json' }, body: Buffer.from('{}') };
3447
+ };
3448
+ const res = await invokeProxy(proxy, makeProxyRequest({
3449
+ headers: {
3450
+ ...CLIENT_CREDENTIAL_HEADERS,
3451
+ 'x-antseed-pin-peer': peer.peerId,
3452
+ 'anthropic-version': '2023-06-01',
3453
+ 'x-antseed-spending-auth': 'signed-auth-payload',
3454
+ },
3455
+ }));
3456
+ assert.equal(res.statusCode, 200);
3457
+ assert.ok(seen, 'seller received a request');
3458
+ const leaked = Object.keys(CLIENT_CREDENTIAL_HEADERS).filter((name) => seen[name] !== undefined);
3459
+ assert.deepEqual(leaked, [], `credential headers reached the seller: ${leaked.join(', ')}`);
3460
+ // Non-credential client headers still pass through.
3461
+ assert.equal(seen['anthropic-version'], '2023-06-01');
3462
+ assert.equal(seen['content-type'], 'application/json');
3463
+ // AntSeed's own payment-auth header is not a client credential.
3464
+ assert.equal(seen['x-antseed-spending-auth'], 'signed-auth-payload');
3465
+ });
3466
+ test('buyer proxy does not forward client credential headers to the seller (streaming)', async () => {
3467
+ const peer = makePeer('f', ['openai']);
3468
+ const proxy = makeBuyerProxyWithPeers([peer], [peer], permissiveRouter());
3469
+ let seen = null;
3470
+ proxy._node.sendRequestStream = async (_peer, request) => {
3471
+ seen = request.headers;
3472
+ return { requestId: request.requestId, statusCode: 200, headers: { 'content-type': 'application/json' }, body: Buffer.from('{}') };
3473
+ };
3474
+ proxy._node.sendRequest = proxy._node.sendRequestStream;
3475
+ await invokeProxy(proxy, makeProxyRequest({
3476
+ headers: { ...CLIENT_CREDENTIAL_HEADERS, accept: 'text/event-stream', 'x-antseed-pin-peer': peer.peerId },
3477
+ body: { model: 'gpt-4o', stream: true, messages: [] },
3478
+ }));
3479
+ assert.ok(seen, 'seller received a request');
3480
+ const leaked = Object.keys(CLIENT_CREDENTIAL_HEADERS).filter((name) => seen[name] !== undefined);
3481
+ assert.deepEqual(leaked, [], `credential headers reached the seller: ${leaked.join(', ')}`);
3482
+ });
3406
3483
  test('switching a chat route while a request is in flight is not reverted when that request completes', async () => {
3407
3484
  const dir = await mkdtemp(join(tmpdir(), 'antseed-buyer-route-race-'));
3408
3485
  try {