mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 01:32:44 +08:00
104 lines
3.4 KiB
JavaScript
104 lines
3.4 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const test = require('node:test');
|
|
|
|
const {
|
|
MODEL_PROVIDER_CREDENTIAL_TRANSITION_COMMAND_SCHEMA,
|
|
InvalidModelProviderCredentialTransitionError,
|
|
ModelProviderCredentialTransitionConflictError,
|
|
createModelProviderCredentialTransition,
|
|
createModelProviderCredentialTransitionCommand,
|
|
modelProviderCredentialBindingForTransition,
|
|
normalizeModelProviderCredentialTransition,
|
|
} = require('../dist/model-provider-credential/modelProviderCredentialCatalog.js');
|
|
const {
|
|
MODEL_PROVIDER_CREDENTIAL_BINDING_SCHEMA,
|
|
} = require('../dist/model-provider-credential/providerCredential.js');
|
|
const { createSecretRef } = require('@qinglong/runtime-core/secret-reference');
|
|
|
|
function binding(overrides = {}) {
|
|
return {
|
|
schema: MODEL_PROVIDER_CREDENTIAL_BINDING_SCHEMA,
|
|
projectId: 'project-a',
|
|
provider: 'openai-compatible',
|
|
revision: 'credential-v1',
|
|
secretRef: createSecretRef({
|
|
projectId: 'project-a',
|
|
name: 'openai-token',
|
|
}),
|
|
scheme: 'bearer',
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function command(overrides = {}) {
|
|
return createModelProviderCredentialTransitionCommand({
|
|
schema: MODEL_PROVIDER_CREDENTIAL_TRANSITION_COMMAND_SCHEMA,
|
|
mutationId: 'credential-bind-1',
|
|
projectId: 'project-a',
|
|
provider: 'openai-compatible',
|
|
expectedGeneration: 0,
|
|
action: 'bind',
|
|
binding: binding(),
|
|
changedBy: { type: 'user', id: 'owner-a' },
|
|
...overrides,
|
|
});
|
|
}
|
|
|
|
test('credential catalog creates an immutable bind/revoke hash chain', () => {
|
|
const bind = command();
|
|
const first = createModelProviderCredentialTransition(bind, null, 10);
|
|
assert.equal(first.generation, 1);
|
|
assert.equal(first.action, 'bind');
|
|
assert.equal(first.previousTransitionDigest, null);
|
|
assert.deepEqual(
|
|
modelProviderCredentialBindingForTransition(first, bind.binding),
|
|
bind.binding,
|
|
);
|
|
assert.deepEqual(normalizeModelProviderCredentialTransition(first), first);
|
|
|
|
const revoke = command({
|
|
mutationId: 'credential-revoke-2',
|
|
expectedGeneration: 1,
|
|
action: 'revoke',
|
|
binding: null,
|
|
});
|
|
const second = createModelProviderCredentialTransition(revoke, first, 20);
|
|
assert.equal(second.generation, 2);
|
|
assert.equal(second.action, 'revoke');
|
|
assert.equal(second.previousTransitionDigest, first.transitionDigest);
|
|
assert.equal(modelProviderCredentialBindingForTransition(second, null), null);
|
|
});
|
|
|
|
test('credential catalog rejects cross-Project binding and stale CAS', () => {
|
|
assert.throws(
|
|
() => command({ binding: binding({ projectId: 'project-b' }) }),
|
|
InvalidModelProviderCredentialTransitionError,
|
|
);
|
|
const firstCommand = command();
|
|
const first = createModelProviderCredentialTransition(firstCommand, null, 1);
|
|
assert.throws(
|
|
() => createModelProviderCredentialTransition(command(), first, 2),
|
|
ModelProviderCredentialTransitionConflictError,
|
|
);
|
|
});
|
|
|
|
test('credential transition tampering is detected before storage use', () => {
|
|
const first = createModelProviderCredentialTransition(command(), null, 1);
|
|
assert.throws(
|
|
() =>
|
|
normalizeModelProviderCredentialTransition({
|
|
...first,
|
|
activeBindingRevision: 'credential-v2',
|
|
}),
|
|
InvalidModelProviderCredentialTransitionError,
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
modelProviderCredentialBindingForTransition(
|
|
first,
|
|
binding({ revision: 'credential-v2' }),
|
|
),
|
|
/unavailable/,
|
|
);
|
|
});
|