Files
registry/scripts/catalog/application-release-contract.mjs

33 lines
2.4 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.
/** 作者材料的跨字段检查;身份与运行事实由客户端owner核验,不执行安装说明。 */
export function validateApplicationReleaseContract(manifest) {
if (manifest.type !== 'web-bundle' && manifest.appRelease === undefined) return []
const errors = []
if (!['web-bundle', 'native-app', 'docker-app'].includes(manifest.type)) errors.push('appRelease: unsupported delivery type')
if (!manifest.appRelease?.requiredCapabilities?.includes('app-authoring-v1')) errors.push('appRelease: app-authoring-v1 capability handshake required')
if (!manifest.appRelease?.requiredCapabilities?.includes('release') ||
(manifest.type === 'web-bundle' && !manifest.appRelease.requiredCapabilities.includes('web-bundle'))) errors.push('appRelease: delivery capability handshake required')
const images = manifest.appRelease?.imageRefs
if (manifest.type === 'docker-app' && (!Array.isArray(images) || !images.length || images.some(image =>
typeof image !== 'string' || !/^[a-z0-9][a-z0-9._:/-]*@sha256:[a-f0-9]{64}$/.test(image) ||
Number(image.split('/')[0].split(':')[1] ?? 0) > 65535))) errors.push('appRelease: Docker images must be pinned by digest')
if (manifest.type !== 'docker-app' && images !== undefined) errors.push('appRelease: imageRefs belongs only to Docker release')
const source = manifest.source
if (!source || !['git', 'release'].includes(source.kind) ||
!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(source.ref ?? '') || !/^[a-f0-9]{64}$/.test(source.sha256 ?? '')) {
errors.push('source: authored release requires immutable commit and archive sha256')
}
try {
const url = new URL(source?.url)
if (url.protocol !== 'https:' || url.username || url.password || url.hash || url.search) errors.push('source: credential-free fixed HTTPS URL required')
} catch { errors.push('source: invalid URL') }
if (source?.kind === 'git' && !isPortablePath(source.path)) errors.push('source: git archive path must be canonical and relative')
if (!isPortablePath(manifest.appRelease?.definitionPath)) errors.push('appRelease: definitionPath must be canonical and relative')
return errors
}
function isPortablePath(value) {
return typeof value === 'string' && value.length > 0 && value.length <= 512 &&
!/[\\\x00-\x1f?#:]/.test(value) && !value.startsWith('/') &&
value.split('/').every(part => part.length > 0 && part !== '.' && part !== '..')
}