fix(packages): omit source publication payloads
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
||||
import { join, relative, resolve } from 'node:path'
|
||||
import { isForbiddenPublicationFile } from './publication-payload.ts'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
// vendor/* is single-level; packages/<group>/<pkg> nests one level deeper
|
||||
@@ -30,7 +31,7 @@ const vendoredPackages = new Set([
|
||||
|
||||
const localArtifactDirs = new Set(['node_modules'])
|
||||
const appPackageFiles: Readonly<Record<string, readonly string[]>> = {
|
||||
'@deepseek-ai/dsh': ['lib/*.js', 'config', 'src'],
|
||||
'@deepseek-ai/dsh': ['lib/*.js', 'config'],
|
||||
'@deepseek-ai/dsh-frontend': ['dist'],
|
||||
}
|
||||
|
||||
@@ -140,8 +141,6 @@ function expectedDshPackageFiles(manifest: PackageManifest): readonly string[] {
|
||||
// declarations.
|
||||
...usesEmittedTreeDefaults(manifest) ? ['lib/types/**/*.js'] : [],
|
||||
'lib/types/**/*.d.ts',
|
||||
'lib/types/**/*.d.ts.map',
|
||||
'src',
|
||||
]
|
||||
}
|
||||
|
||||
@@ -171,6 +170,14 @@ function checkWorkspace({ dir, manifest }: WorkspaceManifest): string[] {
|
||||
return errors
|
||||
}
|
||||
|
||||
if (manifest.name?.startsWith('@deepseek-ai/')) {
|
||||
for (const file of manifest.files ?? []) {
|
||||
if (isForbiddenPublicationFile(file)) {
|
||||
errors.push(`${label}: package.json files must not publish ${JSON.stringify(file)}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dir.startsWith('apps/') && manifest.name?.startsWith('@deepseek-ai/')) {
|
||||
const expectedFiles = appPackageFiles[manifest.name]
|
||||
if (expectedFiles === undefined) {
|
||||
|
||||
@@ -47,7 +47,7 @@ function fixture(options: {
|
||||
default: './lib/invariant.js',
|
||||
},
|
||||
},
|
||||
files: ['lib/index.js', 'lib/invariant.js', 'src'],
|
||||
files: ['lib/index.js', 'lib/invariant.js'],
|
||||
peerDependencies: options.invariantDependency === false ? {} : {
|
||||
'@deepseek-ai/dsh-invariants': '^0.0.1',
|
||||
},
|
||||
|
||||
54
scripts/publication-payload.spec.ts
Normal file
54
scripts/publication-payload.spec.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { isForbiddenPublicationFile, validateTarballPayload } from './publication-payload.ts'
|
||||
|
||||
function validateFixtureTarball(files: readonly string[]): () => void {
|
||||
return () => {
|
||||
validateTarballPayload(files, 'fixture.tgz')
|
||||
}
|
||||
}
|
||||
|
||||
describe('publication payload policy', () => {
|
||||
it.each([
|
||||
'lib/index.js',
|
||||
'lib/types/index.d.ts',
|
||||
'lib/styles/base.css',
|
||||
])('accepts %s', (file) => {
|
||||
expect(isForbiddenPublicationFile(file)).toBe(false)
|
||||
})
|
||||
|
||||
it.each([
|
||||
'src',
|
||||
'./src',
|
||||
'src/',
|
||||
'src/index.ts',
|
||||
'./src/index.ts',
|
||||
String.raw`src\index.ts`,
|
||||
'lib/types/index.d.ts.map',
|
||||
'./lib/types/index.d.ts.map',
|
||||
])('rejects static manifest path %s', (file) => {
|
||||
expect(isForbiddenPublicationFile(file)).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects source members in packed tarballs', () => {
|
||||
expect(validateFixtureTarball([
|
||||
'package/package.json',
|
||||
'package/src/index.ts',
|
||||
])).toThrow('fixture.tgz publishes source file package/src/index.ts')
|
||||
})
|
||||
|
||||
it('rejects declaration maps in packed tarballs', () => {
|
||||
expect(validateFixtureTarball([
|
||||
'package/package.json',
|
||||
'package/lib/types/index.d.ts.map',
|
||||
])).toThrow('fixture.tgz publishes declaration map package/lib/types/index.d.ts.map')
|
||||
})
|
||||
|
||||
it('accepts a clean packed tarball', () => {
|
||||
expect(validateFixtureTarball([
|
||||
'package/package.json',
|
||||
'package/lib/index.js',
|
||||
'package/lib/types/index.d.ts',
|
||||
'package/lib/styles/base.css',
|
||||
])).not.toThrow()
|
||||
})
|
||||
})
|
||||
27
scripts/publication-payload.ts
Normal file
27
scripts/publication-payload.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/** Publication payload policy shared by static manifests and packed tarballs. */
|
||||
|
||||
/** Normalize a package manifest path or npm tarball member to its payload-relative path. */
|
||||
function payloadPath(file: string): string {
|
||||
const normalized = file.replaceAll('\\', '/').replace(/^\.\/+/, '').replace(/\/+$/, '')
|
||||
return normalized.startsWith('package/') ? normalized.slice('package/'.length) : normalized
|
||||
}
|
||||
|
||||
/** Whether a package payload path exposes source or declaration-map intermediates. */
|
||||
export function isForbiddenPublicationFile(file: string): boolean {
|
||||
const normalized = payloadPath(file)
|
||||
return normalized === 'src'
|
||||
|| normalized.startsWith('src/')
|
||||
|| normalized.endsWith('.d.ts.map')
|
||||
}
|
||||
|
||||
/** Reject source and declaration-map members in a packed npm tarball. */
|
||||
export function validateTarballPayload(files: readonly string[], context: string): void {
|
||||
for (const file of files) {
|
||||
if (!isForbiddenPublicationFile(file)) continue
|
||||
const normalized = payloadPath(file)
|
||||
if (normalized === 'src' || normalized.startsWith('src/')) {
|
||||
throw new Error(`${context} publishes source file ${file}`)
|
||||
}
|
||||
throw new Error(`${context} publishes declaration map ${file}`)
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep
|
||||
import { createInterface } from 'node:readline/promises'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { parseArgs } from 'node:util'
|
||||
import { validateTarballPayload } from './publication-payload.ts'
|
||||
|
||||
const DEFAULT_REGISTRY = 'https://registry.npm.harnessment.com'
|
||||
const DEFAULT_OUTPUT_DIRECTORY = '.artifacts/npm-baseline'
|
||||
@@ -312,6 +313,7 @@ class ReleaseBundle {
|
||||
.sort()
|
||||
.map((tarball) => {
|
||||
const artifact = inspectTarball(resolve(directory, tarball), runner)
|
||||
validateTarballPayload(artifact.files, tarball)
|
||||
if (!missingNames.delete(artifact.name)) {
|
||||
throw new Error(`unexpected or duplicate packed package: ${artifact.name}`)
|
||||
}
|
||||
@@ -388,6 +390,7 @@ class ReleaseBundle {
|
||||
throw new Error(`tarball checksum mismatch: ${pkg.tarball}`)
|
||||
}
|
||||
const artifact = inspectTarball(path, runner)
|
||||
validateTarballPayload(artifact.files, pkg.tarball)
|
||||
if (artifact.name !== pkg.name || artifact.version !== this.manifest.version) {
|
||||
throw new Error(`tarball identity mismatch: ${pkg.tarball}`)
|
||||
}
|
||||
@@ -745,6 +748,7 @@ interface InspectedTarball {
|
||||
version: string
|
||||
private: unknown
|
||||
manifest: Record<string, unknown>
|
||||
files: string[]
|
||||
}
|
||||
|
||||
function inspectTarball(path: string, runner: CommandRunner): InspectedTarball {
|
||||
@@ -757,6 +761,7 @@ function inspectTarball(path: string, runner: CommandRunner): InspectedTarball {
|
||||
version: expectString(manifest, 'version', path),
|
||||
private: manifest.private,
|
||||
manifest,
|
||||
files: runner.capture('tar', ['-tf', path], dirname(path)).split(/\r?\n/),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user