mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 01:00:24 +08:00
111 lines
3.6 KiB
JavaScript
111 lines
3.6 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const { createHash, generateKeyPairSync, sign } = require('node:crypto');
|
|
const { test } = require('node:test');
|
|
|
|
const {
|
|
PLUGIN_PACKAGE_PROMPT_OUTPUT_EXTERNAL_CUSTODY_BUNDLE_SCHEMA,
|
|
createPluginPackagePromptOutputExternalCustodyBundle,
|
|
openPluginPackagePromptOutputExternalCustodyBundle,
|
|
} = require('../dist/prompt-output/custody/pluginPackagePromptOutputExternalCustodyBundle.js');
|
|
const {
|
|
InvalidPluginPackagePromptOutputExternalCustodyError,
|
|
PluginPackagePromptOutputExternalCustodyUntrustedError,
|
|
createPluginPackagePromptOutputExternalCustodyReceipt,
|
|
} = require('../dist/prompt-output/custody/pluginPackagePromptOutputExternalCustody.js');
|
|
|
|
function fixture(byte = 0x51) {
|
|
const keys = generateKeyPairSync('ed25519');
|
|
const wrappedMaterial = Buffer.from(`external-provider-wrapped-${byte}`);
|
|
const receipt = createPluginPackagePromptOutputExternalCustodyReceipt(
|
|
{
|
|
custodyId: 'provider-neutral-custody-001',
|
|
keyId: 'prompt-output-key-001',
|
|
materialProof: '1'.repeat(64),
|
|
sourceGeneration: 3,
|
|
sourceCatalogDigest: '2'.repeat(64),
|
|
wrappingProvider: 'external-kms',
|
|
wrappingKeyRefDigest: '3'.repeat(64),
|
|
wrappedMaterialDigest: createHash('sha256')
|
|
.update(wrappedMaterial)
|
|
.digest('hex'),
|
|
wrappedMaterialBytes: wrappedMaterial.byteLength,
|
|
createdAtMs: 1_700_000_000_000,
|
|
},
|
|
{
|
|
publicKey: keys.publicKey,
|
|
sign: (message) => sign(null, message, keys.privateKey),
|
|
},
|
|
);
|
|
const bundle = createPluginPackagePromptOutputExternalCustodyBundle(
|
|
receipt,
|
|
keys.publicKey,
|
|
wrappedMaterial,
|
|
);
|
|
return { keys, wrappedMaterial, receipt, bundle };
|
|
}
|
|
|
|
test('creates and opens one provider-neutral atomic custody bundle', () => {
|
|
const value = fixture();
|
|
const opened = openPluginPackagePromptOutputExternalCustodyBundle(
|
|
value.bundle,
|
|
value.keys.publicKey,
|
|
);
|
|
try {
|
|
assert.equal(
|
|
value.bundle.schema,
|
|
PLUGIN_PACKAGE_PROMPT_OUTPUT_EXTERNAL_CUSTODY_BUNDLE_SCHEMA,
|
|
);
|
|
assert.equal(opened.bundleDigest, value.bundle.bundleDigest);
|
|
assert.equal(opened.receipt.receiptDigest, value.receipt.receiptDigest);
|
|
assert.deepEqual(opened.wrappedMaterial, value.wrappedMaterial);
|
|
} finally {
|
|
opened.wrappedMaterial.fill(0);
|
|
}
|
|
});
|
|
|
|
test('rejects split-file substitution even when the receipt remains valid', () => {
|
|
const left = fixture(0x51);
|
|
const right = fixture(0x52);
|
|
assert.throws(
|
|
() =>
|
|
openPluginPackagePromptOutputExternalCustodyBundle(
|
|
{ ...left.bundle, wrappedMaterial: right.bundle.wrappedMaterial },
|
|
left.keys.publicKey,
|
|
),
|
|
PluginPackagePromptOutputExternalCustodyUntrustedError,
|
|
);
|
|
});
|
|
|
|
test('rejects bundle digest drift and extra fields', () => {
|
|
const value = fixture();
|
|
assert.throws(
|
|
() =>
|
|
openPluginPackagePromptOutputExternalCustodyBundle(
|
|
{ ...value.bundle, bundleDigest: '4'.repeat(64) },
|
|
value.keys.publicKey,
|
|
),
|
|
PluginPackagePromptOutputExternalCustodyUntrustedError,
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
openPluginPackagePromptOutputExternalCustodyBundle(
|
|
{ ...value.bundle, providerConfig: 'must-not-be-embedded' },
|
|
value.keys.publicKey,
|
|
),
|
|
InvalidPluginPackagePromptOutputExternalCustodyError,
|
|
);
|
|
});
|
|
|
|
test('rejects a valid bundle under a different custody signing authority', () => {
|
|
const value = fixture();
|
|
const other = generateKeyPairSync('ed25519');
|
|
assert.throws(
|
|
() =>
|
|
openPluginPackagePromptOutputExternalCustodyBundle(
|
|
value.bundle,
|
|
other.publicKey,
|
|
),
|
|
PluginPackagePromptOutputExternalCustodyUntrustedError,
|
|
);
|
|
});
|