feat: 添加 Kimi WebBridge 受控目录条目 (#2)

This commit is contained in:
2026-08-30 13:49:44 -04:00
committed by GitHub
parent e06a0b74d0
commit 877a3b2424
11 changed files with 1565 additions and 23 deletions

View File

@@ -0,0 +1,381 @@
import { lstat, readFile, readdir } from 'node:fs/promises'
import { dirname, join, relative, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import Ajv from 'ajv'
const scriptDirectory = dirname(fileURLToPath(import.meta.url))
const rootArgumentIndex = process.argv.indexOf('--root')
if (rootArgumentIndex >= 0 && !process.argv[rootArgumentIndex + 1]) {
throw new Error('--root requires a directory path')
}
const repositoryRoot = rootArgumentIndex >= 0
? resolve(process.argv[rootArgumentIndex + 1])
: resolve(scriptDirectory, '..')
const entriesRoot = join(repositoryRoot, 'entries')
const errors = []
const addError = (message) => errors.push(message)
const readText = async (path) => {
try {
return await readFile(path, 'utf8')
} catch (error) {
addError(`${relative(repositoryRoot, path)}: unable to read (${error.message})`)
return null
}
}
const readJson = async (path) => {
const text = await readText(path)
if (text === null) return null
try {
return JSON.parse(text)
} catch (error) {
addError(`${relative(repositoryRoot, path)}: invalid JSON (${error.message})`)
return null
}
}
const formatAjvErrors = (validationErrors = []) =>
validationErrors
.map((error) => `${error.instancePath || '/'} ${error.message}`)
.join('; ')
const sorted = (values) => [...values].sort()
const sameSet = (actual, expected) =>
JSON.stringify(sorted(actual)) === JSON.stringify(sorted(expected))
const containsKey = (value, prohibitedKey) => {
if (Array.isArray(value)) return value.some((item) => containsKey(item, prohibitedKey))
if (!value || typeof value !== 'object') return false
if (Object.hasOwn(value, prohibitedKey)) return true
return Object.values(value).some((item) => containsKey(item, prohibitedKey))
}
const assertHttpsUrl = (rawUrl, context) => {
try {
const url = new URL(rawUrl)
if (url.protocol !== 'https:') addError(`${context}: URL must use HTTPS`)
if (url.username || url.password) addError(`${context}: URL must not contain credentials`)
return url
} catch {
addError(`${context}: invalid URL`)
return null
}
}
const requiredOfficialLinkKinds = [
'product',
'documentation',
'chrome-web-store',
'edge-add-ons',
'privacy',
'terms',
]
const admittedExternalIntegrationIds = new Set(['kimi-webbridge'])
const kimiOfficialLinkPolicy = {
product: {
url: 'https://www.kimi.ai/products/kimi-webbridge',
},
documentation: {
url: 'https://www.kimi.ai/help/kimi-webbridge/kimi-webbridge-introduction',
},
'chrome-web-store': {
url: 'https://chromewebstore.google.com/detail/kimi-webbridge/fldmhceldgbpfpkbgopacenieobmligc',
extensionId: 'fldmhceldgbpfpkbgopacenieobmligc',
},
'edge-add-ons': {
url: 'https://microsoftedge.microsoft.com/addons/detail/kimi-webbridge/bnlffdbcfnanfbknnlaflhlhkocccckg',
extensionId: 'bnlffdbcfnanfbknnlaflhlhkocccckg',
},
privacy: {
url: 'https://www.kimi.ai/user/agreement/userPrivacy?version=v2',
},
terms: {
url: 'https://www.kimi.ai/user/agreement/modelUse?version=v2',
},
}
const requiredKimiPermissions = [
'tabs',
'activeTab',
'debugger',
'storage',
'alarms',
'tabGroups',
'windows',
]
const requiredAdmissionPrerequisites = [
'stable-auditable-protocol',
'integration-authorization',
'deterministic-command-receipts',
'user-interaction-pause-signal',
]
const isValidCalendarDate = (value) => {
if (typeof value !== 'string') return false
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value)
if (!match) return false
const year = Number(match[1])
const month = Number(match[2])
const day = Number(match[3])
const date = new Date(Date.UTC(year, month - 1, day))
return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day
}
const describeFilesystemEntry = (entry) => {
if (entry.isSymbolicLink()) return 'symbolic link'
if (entry.isDirectory()) return 'directory'
if (entry.isFile()) return 'file'
if (entry.isBlockDevice()) return 'block device'
if (entry.isCharacterDevice()) return 'character device'
if (entry.isFIFO()) return 'FIFO'
if (entry.isSocket()) return 'socket'
return 'unsupported filesystem entry'
}
const validateExternalDirectoryLayout = async (entryDirectory, manifestId) => {
const prefix = `entries/${manifestId}`
const directoryEntries = await readdir(entryDirectory, { withFileTypes: true })
for (const entry of directoryEntries) {
if (entry.name !== 'manifest.json') {
addError(`${prefix}: external-integration allows only manifest.json; found ${describeFilesystemEntry(entry)} ${entry.name}`)
continue
}
if (!entry.isFile() || entry.isSymbolicLink()) {
addError(`${prefix}/manifest.json: must be a regular file, not a ${describeFilesystemEntry(entry)}`)
}
}
if (directoryEntries.length !== 1 || directoryEntries[0]?.name !== 'manifest.json') {
addError(`${prefix}: external-integration directory must contain exactly one manifest.json regular file`)
}
}
const validateExternalIntegration = async (entryDirectory, manifest) => {
const prefix = `entries/${manifest.id}`
await validateExternalDirectoryLayout(entryDirectory, manifest.id)
if (!admittedExternalIntegrationIds.has(manifest.id)) {
addError(`${prefix}/manifest.json: unknown external-integration id ${manifest.id}`)
}
const forbiddenFields = [
'install',
'entrypoints',
'exposes',
'endpoint',
'connection',
'auth',
'operations',
'source',
]
for (const field of forbiddenFields) {
if (Object.hasOwn(manifest, field)) addError(`${prefix}/manifest.json: forbidden field "${field}"`)
}
const linkKinds = manifest.officialLinks?.map((link) => link.kind) ?? []
if (!sameSet(linkKinds, requiredOfficialLinkKinds)) {
addError(`${prefix}/manifest.json: officialLinks must contain each required kind exactly once`)
}
for (const link of manifest.officialLinks ?? []) {
const url = assertHttpsUrl(link.url, `${prefix}/manifest.json officialLinks.${link.kind}`)
const policy = kimiOfficialLinkPolicy[link.kind]
if (!policy || link.url !== policy.url) {
addError(`${prefix}/manifest.json officialLinks.${link.kind}: URL must exactly equal ${policy?.url ?? 'an admitted URL'}`)
}
if (policy?.extensionId) {
if (link.extensionId !== policy.extensionId) {
addError(`${prefix}/manifest.json officialLinks.${link.kind}: extensionId must equal ${policy.extensionId}`)
}
if (url && url.pathname.split('/').filter(Boolean).at(-1) !== link.extensionId) {
addError(`${prefix}/manifest.json officialLinks.${link.kind}: URL path must end with extensionId`)
}
} else if (Object.hasOwn(link, 'extensionId')) {
addError(`${prefix}/manifest.json officialLinks.${link.kind}: extensionId is allowed only for browser stores`)
}
}
if (manifest.id === 'kimi-webbridge') {
for (const [field, expectedHost] of [
['listingMaintainer', 'github.com'],
['upstreamMaintainer', 'www.kimi.ai'],
]) {
const url = assertHttpsUrl(manifest[field]?.url, `${prefix}/manifest.json ${field}.url`)
if (url && url.hostname !== expectedHost) {
addError(`${prefix}/manifest.json ${field}.url: hostname must be ${expectedHost}`)
}
}
}
if (manifest.listingMaintainer?.url !== 'https://github.com/desirecore/registry' || manifest.listingMaintainer?.verified !== true) {
addError(`${prefix}/manifest.json: listingMaintainer must be the verified DesireCore Registry URL`)
}
if (manifest.upstreamMaintainer?.url !== 'https://www.kimi.ai/' || manifest.upstreamMaintainer?.verified !== true) {
addError(`${prefix}/manifest.json: upstreamMaintainer must be the verified Kimi URL`)
}
const componentKinds = manifest.components?.map((component) => component.kind) ?? []
if (!sameSet(componentKinds, ['browser-extension', 'local-daemon'])) {
addError(`${prefix}/manifest.json: components must contain browser-extension and local-daemon exactly once`)
}
for (const component of manifest.components ?? []) {
if (component.kind === 'browser-extension') {
if (!sameSet(component.browsers ?? [], ['chrome', 'edge']) || Object.hasOwn(component, 'platforms')) {
addError(`${prefix}/manifest.json: browser-extension must declare only Chrome and Edge browsers`)
}
}
if (component.kind === 'local-daemon') {
if (!Array.isArray(component.platforms) ||
!component.platforms.includes('windows') ||
!component.platforms.includes('macos') ||
Object.hasOwn(component, 'browsers')) {
addError(`${prefix}/manifest.json: local-daemon must declare at least Windows and macOS and no browsers`)
}
}
}
const apiPermissions = manifest.permissions?.browserExtension?.apiPermissions ?? []
if (!sameSet(apiPermissions, requiredKimiPermissions)) {
addError(`${prefix}/manifest.json: browser extension API permissions must match the audited Kimi permission set`)
}
const hostPermissions = manifest.permissions?.browserExtension?.hostPermissions ?? []
if (!sameSet(hostPermissions, ['<all_urls>'])) {
addError(`${prefix}/manifest.json: browser extension must disclose <all_urls>`)
}
if (!sameSet(manifest.admission?.missingPrerequisites ?? [], requiredAdmissionPrerequisites)) {
addError(`${prefix}/manifest.json: blocked admission prerequisites are incomplete`)
}
const artifactIdentities = new Set()
if (!isValidCalendarDate(manifest.compliance?.reviewedAt)) {
addError(`${prefix}/manifest.json compliance.reviewedAt: expected a real YYYY-MM-DD calendar date`)
}
for (const artifact of manifest.compliance?.artifactReviews ?? []) {
const artifactContext = `${prefix}/manifest.json artifact ${artifact.platform}/${artifact.architecture}`
const url = assertHttpsUrl(artifact.url, artifactContext)
if (url && url.hostname !== 'cdn.kimi.com') {
addError(`${artifactContext}: hostname must be cdn.kimi.com`)
}
if (url && !url.pathname.includes(`/v${artifact.version}/releases/`)) {
addError(`${artifactContext}: URL must pin the reviewed version in its release path`)
}
if (url && (url.search || url.hash)) {
addError(`${artifactContext}: URL must not contain query or fragment components`)
}
if (!isValidCalendarDate(artifact.reviewedAt)) {
addError(`${artifactContext} reviewedAt: expected a real YYYY-MM-DD calendar date`)
}
const identity = `${artifact.platform}/${artifact.architecture}`
if (artifactIdentities.has(identity)) addError(`${artifactContext}: duplicate platform/architecture review`)
artifactIdentities.add(identity)
}
}
const schemaVersion = (await readText(join(repositoryRoot, 'SCHEMA_VERSION')))?.trim()
const rootManifest = await readJson(join(repositoryRoot, 'manifest.json'))
const entrySchema = await readJson(join(repositoryRoot, 'schemas', 'registry-entry.schema.json'))
if (!schemaVersion || !/^\d+\.\d+\.\d+$/.test(schemaVersion)) {
addError('SCHEMA_VERSION: expected a semantic version')
}
if (rootManifest) {
if (rootManifest.version !== schemaVersion) addError('manifest.json#version must equal SCHEMA_VERSION')
if (rootManifest.dataVersion !== schemaVersion) addError('manifest.json#dataVersion must equal SCHEMA_VERSION')
}
let validateEntry = null
if (entrySchema) {
try {
const ajv = new Ajv({ allErrors: true, strict: true, validateFormats: false })
validateEntry = ajv.compile(entrySchema)
} catch (error) {
addError(`schemas/registry-entry.schema.json: unable to compile (${error.message})`)
}
}
const manifests = []
const seenIds = new Set()
for (const directoryEntry of await readdir(entriesRoot, { withFileTypes: true })) {
if (!directoryEntry.isDirectory()) {
addError(`entries/${directoryEntry.name}: entries root may contain directories only`)
continue
}
const entryDirectory = join(entriesRoot, directoryEntry.name)
const manifestPath = join(entryDirectory, 'manifest.json')
let manifestStat
try {
manifestStat = await lstat(manifestPath)
} catch (error) {
if (error.code === 'ENOENT') {
addError(`entries/${directoryEntry.name}: missing manifest.json`)
continue
}
throw error
}
if (!manifestStat.isFile() || manifestStat.isSymbolicLink()) {
addError(`entries/${directoryEntry.name}/manifest.json: must be a regular file and not a symbolic link`)
continue
}
const manifest = await readJson(manifestPath)
if (!manifest) continue
manifests.push(manifest)
if (manifest.id !== directoryEntry.name) {
addError(`entries/${directoryEntry.name}/manifest.json: id must equal directory name`)
}
if (seenIds.has(manifest.id)) addError(`entries/${directoryEntry.name}/manifest.json: duplicate id ${manifest.id}`)
seenIds.add(manifest.id)
for (const injectedField of ['sourceId', 'hasInstall']) {
if (containsKey(manifest, injectedField)) {
addError(`entries/${directoryEntry.name}/manifest.json: ${injectedField} is client-injected and must not be authored`)
}
}
if (validateEntry && !validateEntry(manifest)) {
addError(`entries/${directoryEntry.name}/manifest.json: ${formatAjvErrors(validateEntry.errors)}`)
}
if (manifest.type === 'external-integration') {
await validateExternalIntegration(entryDirectory, manifest)
}
}
if (rootManifest) {
const expectedStats = {
totalEntries: manifests.length,
dockerApps: manifests.filter((entry) => entry.type === 'docker-app').length,
mcpServices: manifests.filter((entry) => entry.type === 'mcp').length,
httpApis: manifests.filter((entry) => entry.type === 'http-api').length,
externalIntegrations: manifests.filter((entry) => entry.type === 'external-integration').length,
}
for (const [field, expected] of Object.entries(expectedStats)) {
if (rootManifest.stats?.[field] !== expected) {
addError(`manifest.json#stats.${field}: expected ${expected}, received ${rootManifest.stats?.[field]}`)
}
}
const extraStats = Object.keys(rootManifest.stats ?? {}).filter((field) => !Object.hasOwn(expectedStats, field))
if (extraStats.length > 0) addError(`manifest.json#stats: unknown fields ${extraStats.join(', ')}`)
}
for (const manifest of manifests) {
if (manifest.sourceAppId && !seenIds.has(manifest.sourceAppId)) {
addError(`entries/${manifest.id}/manifest.json: sourceAppId ${manifest.sourceAppId} does not exist`)
}
}
if (errors.length > 0) {
console.error(`Registry validation failed with ${errors.length} error(s):`)
for (const error of errors) console.error(`- ${error}`)
process.exitCode = 1
} else {
const counts = rootManifest.stats
console.log(
`Registry validation passed: ${counts.totalEntries} entries ` +
`(${counts.dockerApps} Docker, ${counts.mcpServices} MCP, ` +
`${counts.httpApis} HTTP API, ${counts.externalIntegrations} external integration).`,
)
}

View File

@@ -0,0 +1,259 @@
import assert from 'node:assert/strict'
import { cp, mkdir, mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { dirname, join, resolve } from 'node:path'
import { spawnSync } from 'node:child_process'
import { fileURLToPath } from 'node:url'
import test from 'node:test'
const scriptDirectory = dirname(fileURLToPath(import.meta.url))
const repositoryRoot = resolve(scriptDirectory, '..')
const validatorPath = join(scriptDirectory, 'validate-registry.mjs')
const createFixture = async () => {
const root = await mkdtemp(join(tmpdir(), 'desirecore-registry-test-'))
await Promise.all([
cp(join(repositoryRoot, 'entries'), join(root, 'entries'), { recursive: true }),
cp(join(repositoryRoot, 'schemas'), join(root, 'schemas'), { recursive: true }),
cp(join(repositoryRoot, 'SCHEMA_VERSION'), join(root, 'SCHEMA_VERSION')),
cp(join(repositoryRoot, 'manifest.json'), join(root, 'manifest.json')),
])
return root
}
const readJson = async (path) => JSON.parse(await readFile(path, 'utf8'))
const writeJson = async (path, value) => writeFile(path, `${JSON.stringify(value, null, 2)}\n`, 'utf8')
const runValidator = (root) => spawnSync(
process.execPath,
[validatorPath, '--root', root],
{ cwd: repositoryRoot, encoding: 'utf8' },
)
const expectRejected = async (mutate, expectedMessage) => {
const root = await createFixture()
try {
await mutate(root)
const result = runValidator(root)
assert.equal(result.status, 1, `validator unexpectedly passed:\n${result.stdout}`)
assert.match(`${result.stdout}\n${result.stderr}`, expectedMessage)
} finally {
await rm(root, { recursive: true, force: true })
}
}
test('accepts the checked-in Registry fixture', async () => {
const root = await createFixture()
try {
const result = runValidator(root)
assert.equal(result.status, 0, result.stderr)
assert.match(result.stdout, /Registry validation passed: 22 entries/)
} finally {
await rm(root, { recursive: true, force: true })
}
})
test('rejects an entry whose directory and id differ', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.id = 'different-id'
await writeJson(path, manifest)
}, /id must equal directory name/)
})
test('rejects client-injected sourceId in an upstream manifest', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.sourceId = 'untrusted-source'
await writeJson(path, manifest)
}, /sourceId is client-injected/)
})
test('rejects stale root statistics', async () => {
await expectRejected(async (root) => {
const path = join(root, 'manifest.json')
const manifest = await readJson(path)
manifest.stats.externalIntegrations = 0
await writeJson(path, manifest)
}, /stats\.externalIntegrations: expected 1, received 0/)
})
test('rejects an unknown external-integration id', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.id = 'unreviewed-bridge'
await writeJson(path, manifest)
}, /unknown external-integration id unreviewed-bridge/)
})
for (const kind of ['product', 'documentation', 'chrome-web-store', 'edge-add-ons', 'privacy', 'terms']) {
test(`rejects a modified ${kind} official URL`, async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
const link = manifest.officialLinks.find((item) => item.kind === kind)
link.url = `${link.url}/tampered`
await writeJson(path, manifest)
}, /URL must exactly equal/)
})
}
test('rejects a browser-store extension id that does not match its URL path', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
const link = manifest.officialLinks.find((item) => item.kind === 'chrome-web-store')
link.url = 'https://chromewebstore.google.com/detail/kimi-webbridge/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
await writeJson(path, manifest)
}, /URL path must end with extensionId/)
})
test('rejects an incorrect structured extension id', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
const link = manifest.officialLinks.find((item) => item.kind === 'edge-addons')
?? manifest.officialLinks.find((item) => item.kind === 'edge-add-ons')
link.extensionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
await writeJson(path, manifest)
}, /extensionId must equal bnlffdbcfnanfbknnlaflhlhkocccckg/)
})
test('rejects installation fields for listing-only integrations', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.install = { method: 'unsupported' }
await writeJson(path, manifest)
}, /forbidden field "install"/)
})
test('rejects an unverified or unexpected listing maintainer', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.listingMaintainer.url = 'https://github.com/example/registry'
manifest.listingMaintainer.verified = false
await writeJson(path, manifest)
}, /listingMaintainer must be the verified DesireCore Registry URL/)
})
test('rejects a non-tools external category', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.category = 'browser'
await writeJson(path, manifest)
}, /must be equal to constant/)
})
test('rejects an unapproved external icon', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.icon = 'kimi-logo'
await writeJson(path, manifest)
}, /must be equal to one of the allowed values/)
})
test('rejects extra text files in an external-integration directory', async () => {
await expectRejected(async (root) => {
await writeFile(join(root, 'entries', 'kimi-webbridge', 'usage.md'), '# not allowed\n', 'utf8')
}, /allows only manifest\.json; found file usage\.md/)
})
test('rejects extra directories in an external-integration directory', async () => {
await expectRejected(async (root) => {
await mkdir(join(root, 'entries', 'kimi-webbridge', 'assets'))
}, /allows only manifest\.json; found directory assets/)
})
test('rejects symbolic links in an external-integration directory', { skip: process.platform === 'win32' }, async () => {
await expectRejected(async (root) => {
await symlink('manifest.json', join(root, 'entries', 'kimi-webbridge', 'alias.json'))
}, /allows only manifest\.json; found symbolic link alias\.json/)
})
test('rejects a symbolic-link manifest', { skip: process.platform === 'win32' }, async () => {
await expectRejected(async (root) => {
const directory = join(root, 'entries', 'kimi-webbridge')
const manifestPath = join(directory, 'manifest.json')
const backupPath = join(directory, 'reviewed.json')
await cp(manifestPath, backupPath)
await rm(manifestPath)
await symlink('reviewed.json', manifestPath)
}, /manifest\.json: must be a regular file and not a symbolic link/)
})
test('rejects binary files in an external-integration directory', async () => {
await expectRejected(async (root) => {
await writeFile(join(root, 'entries', 'kimi-webbridge', 'payload.bin'), Buffer.from([0, 255, 1, 254]))
}, /allows only manifest\.json; found file payload\.bin/)
})
test('rejects special filesystem entries in an external-integration directory', { skip: process.platform === 'win32' }, async () => {
await expectRejected(async (root) => {
const fifoPath = join(root, 'entries', 'kimi-webbridge', 'control.fifo')
const result = spawnSync('mkfifo', [fifoPath], { encoding: 'utf8' })
assert.equal(result.status, 0, result.stderr)
}, /allows only manifest\.json; found FIFO control\.fifo/)
})
test('rejects an impossible compliance review date', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.compliance.reviewedAt = '2026-02-30'
await writeJson(path, manifest)
}, /compliance\.reviewedAt: expected a real YYYY-MM-DD calendar date/)
})
test('rejects an impossible artifact review date', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.compliance.artifactReviews[0].reviewedAt = '2026-13-01'
await writeJson(path, manifest)
}, /artifact macos\/arm64 reviewedAt: expected a real YYYY-MM-DD calendar date/)
})
test('rejects an artifact URL that is not pinned to its reviewed version', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.compliance.artifactReviews[0].url =
'https://cdn.kimi.com/webbridge/unpinned/releases/kimi-webbridge-darwin-arm64'
await writeJson(path, manifest)
}, /URL must pin the reviewed version in its release path/)
})
test('rejects query parameters on an immutable artifact URL', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.compliance.artifactReviews[0].url += '?redirect=1'
await writeJson(path, manifest)
}, /URL must not contain query or fragment components/)
})
test('rejects unsupported universal artifact architecture', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.compliance.artifactReviews[0].architecture = 'universal'
await writeJson(path, manifest)
}, /must be equal to one of the allowed values/)
})
test('rejects a local daemon that omits Windows', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
const daemon = manifest.components.find((item) => item.kind === 'local-daemon')
daemon.platforms = ['macos', 'linux']
await writeJson(path, manifest)
}, /local-daemon must declare at least Windows and macOS/)
})