Files
registry/scripts/native-app.test.mjs
Yige 3828aa6800 feat(registry): 插件与应用关系契约4.2 / plugin and application contract (#10)
* feat(registry): 增加插件贡献与应用依赖的4.2契约

* fix(registry): preserve legacy App manifests for published clients

---------

Co-authored-by: yi-ge <6657330+yi-ge@users.noreply.github.com>
2026-10-07 19:08:18 -07:00

64 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from 'node:assert/strict'
import { test, afterEach } from 'node:test'
import { cpSync, readFileSync, writeFileSync, mkdtempSync, rmSync } from 'node:fs'
import { join, dirname } from 'node:path'
import { tmpdir } from 'node:os'
import { fileURLToPath } from 'node:url'
import { validateRegistry } from './catalog/validator.mjs'
const source = join(dirname(fileURLToPath(import.meta.url)), '..')
const temporary = []
afterEach(() => { for (const root of temporary.splice(0)) rmSync(root, { recursive: true, force: true }) })
function fixture() {
const root = mkdtempSync(join(tmpdir(), 'registry-native-'))
temporary.push(root)
cpSync(join(source, 'schemas'), join(root, 'schemas'), { recursive: true })
cpSync(join(source, 'entries/desirecore-control'), join(root, 'entries/desirecore-control'), { recursive: true })
const manifest = JSON.parse(readFileSync(join(source, 'manifest.json'), 'utf8'))
manifest.stats = { totalEntries: 1, dockerApps: 0, nativeApps: 1, mcpServices: 0, httpApis: 0, externalIntegrations: 0 }
writeFileSync(join(root, 'manifest.json'), JSON.stringify(manifest))
writeFileSync(join(root, 'SCHEMA_VERSION'), manifest.version + '\n')
return root
}
function mutate(root, file, change) {
const path = join(root, file)
const data = JSON.parse(readFileSync(path, 'utf8'))
change(data)
writeFileSync(path, JSON.stringify(data))
}
const entry = 'entries/desirecore-control/'
test('真实原生应用条目是 App,固定 1.4.0 制品,不包含内部 MCP 配置', () => {
const root = fixture()
const report = validateRegistry(root)
assert.equal(report.ok, true, JSON.stringify(report.errors))
assert.equal(report.counts.nativeApps, 1)
assert.equal(report.counts.mcpServices, 0)
const manifest = JSON.parse(readFileSync(join(root, entry, 'manifest.json'), 'utf8'))
assert.equal(manifest.type, 'native-app')
assert.equal(manifest.install.method, 'native-node')
assert.equal(manifest.install.requirements.docker, false)
assert.equal(manifest.version, '1.4.0')
assert.equal(manifest.connection, undefined)
assert.equal(manifest.exposes, undefined)
})
for (const field of ['connection', 'exposes', 'toolCount', 'capabilities']) test('拒绝原生应用内部服务字段 ' + field, () => {
const root = fixture()
mutate(root, entry + 'manifest.json', data => { data[field] = field === 'toolCount' ? 5 : field === 'connection' ? { transport: 'stdio', command: 'node' } : [] })
assert.equal(validateRegistry(root).ok, false)
})
test('摘要、最低客户端版本和统计必须与目录事实一致', () => {
for (const change of [data => { data.provenance.content.sha256 = '0'.repeat(64) }, data => { data.compatibility.requiredClientVersion = '0.0.0' }]) {
const root = fixture()
mutate(root, entry + 'catalog-metadata.v1.json', change)
assert.equal(validateRegistry(root).ok, false)
}
const root = fixture()
mutate(root, 'manifest.json', data => { data.stats.nativeApps = 0 })
assert.equal(validateRegistry(root).ok, false)
})
test('字段顺序不是治理身份,值相同时允许序列化重排', () => {
const root = fixture()
mutate(root, entry + 'manifest.json', data => { data.source = Object.fromEntries(Object.entries(data.source).reverse()) })
assert.equal(validateRegistry(root).ok, true)
})