feat(api): complete phase 2.4 control plane

This commit is contained in:
chick
2026-07-17 00:37:11 +08:00
parent c2702b5fc6
commit 7b91dbbad1
40 changed files with 4526 additions and 74 deletions
@@ -0,0 +1,72 @@
import { describe, expect, it } from 'vitest';
import { SafeUpstreamGateway } from './safe-upstream-gateway.js';
describe('SafeUpstreamGateway', () => {
it('sends login password only as JSON through the pinned POST transport', async () => {
const calls: unknown[] = [];
const gateway = new SafeUpstreamGateway({
transport: {
get: async () => ({ status: 200, headers: {}, body: '' }),
post: async (url, headers, body) => {
calls.push({ url, headers, body });
return { status: 200, headers: { 'set-cookie': 'simadmin_session=opaque' }, body: '' };
},
},
});
await gateway.request({
url: 'https://192.168.1.20:8080/api/auth/login',
method: 'POST',
headers: { 'content-type': 'application/json' },
secret: '[REDACTED]',
body: '[REDACTED]',
});
expect(calls).toEqual([
{
url: 'https://192.168.1.20:8080/api/auth/login',
headers: { 'content-type': 'application/json' },
body: '{"password":"[REDACTED]"}',
},
]);
});
it('rejects HTTP login and logout so credentials and cookies are never sent in cleartext', async () => {
const gateway = new SafeUpstreamGateway({
transport: {
get: async () => ({ status: 200, headers: {}, body: '' }),
post: async () => ({ status: 200, headers: {}, body: '' }),
},
});
await expect(
gateway.request({
url: 'http://192.168.1.20:8080/api/auth/login',
method: 'POST',
headers: { 'content-type': 'application/json' },
secret: '[REDACTED]',
body: '[REDACTED]',
}),
).rejects.toThrow('UPSTREAM_INSECURE_AUTH');
await expect(
gateway.request({
url: 'http://192.168.1.20:8080/api/auth/logout',
method: 'POST',
headers: { cookie: 'simadmin_session=opaque' },
}),
).rejects.toThrow('UPSTREAM_INSECURE_AUTH');
});
it('does not allow a supplied redacted body marker to become a network request body', async () => {
const gateway = new SafeUpstreamGateway({
transport: {
get: async () => ({ status: 200, headers: {}, body: '' }),
post: async () => ({ status: 200, headers: {}, body: '' }),
},
});
await expect(
gateway.request({
url: 'https://192.168.1.20:8080/api/auth/login',
method: 'POST',
headers: {},
body: '[REDACTED]',
}),
).rejects.toThrow('UPSTREAM_REQUEST_INVALID');
});
});