import * as crypto from 'crypto'; import * as smartarchive from '@push.rocks/smartarchive'; /** * Helper to calculate SHA-256 digest in OCI format */ export function calculateDigest(data: Buffer): string { const hash = crypto.createHash('sha256').update(data).digest('hex'); return `sha256:${hash}`; } /** * Helper to create a minimal valid OCI manifest */ export function createTestManifest(configDigest: string, layerDigest: string) { return { schemaVersion: 2, mediaType: 'application/vnd.oci.image.manifest.v1+json', config: { mediaType: 'application/vnd.oci.image.config.v1+json', size: 123, digest: configDigest, }, layers: [ { mediaType: 'application/vnd.oci.image.layer.v1.tar+gzip', size: 456, digest: layerDigest, }, ], }; } /** * Helper to create a minimal valid NPM packument */ export function createTestPackument(packageName: string, version: string, tarballData: Buffer) { const shasum = crypto.createHash('sha1').update(tarballData).digest('hex'); const integrity = `sha512-${crypto.createHash('sha512').update(tarballData).digest('base64')}`; return { name: packageName, versions: { [version]: { name: packageName, version: version, description: 'Test package', main: 'index.js', scripts: {}, dist: { shasum: shasum, integrity: integrity, tarball: `http://localhost:5000/npm/${packageName}/-/${packageName}-${version}.tgz`, }, }, }, 'dist-tags': { latest: version, }, _attachments: { [`${packageName}-${version}.tgz`]: { content_type: 'application/octet-stream', data: tarballData.toString('base64'), length: tarballData.length, }, }, }; } /** * Helper to create a minimal valid Maven POM file */ export function createTestPom( groupId: string, artifactId: string, version: string, packaging: string = 'jar' ): string { return ` 4.0.0 ${groupId} ${artifactId} ${version} ${packaging} ${artifactId} Test Maven artifact `; } /** * Helper to create a test JAR file (minimal ZIP with manifest) */ export function createTestJar(): Buffer { const manifestContent = `Manifest-Version: 1.0 Created-By: SmartRegistry Test `; return Buffer.from(manifestContent, 'utf-8'); } /** * Helper to calculate Maven checksums */ export function calculateMavenChecksums(data: Buffer) { return { md5: crypto.createHash('md5').update(data).digest('hex'), sha1: crypto.createHash('sha1').update(data).digest('hex'), sha256: crypto.createHash('sha256').update(data).digest('hex'), sha512: crypto.createHash('sha512').update(data).digest('hex'), }; } /** * Helper to create a Composer package ZIP using smartarchive */ export async function createComposerZip( vendorPackage: string, version: string, options?: { description?: string; license?: string[]; authors?: Array<{ name: string; email?: string }>; } ): Promise { const zipTools = new smartarchive.ZipTools(); const composerJson = { name: vendorPackage, version: version, type: 'library', description: options?.description || 'Test Composer package', license: options?.license || ['MIT'], authors: options?.authors || [{ name: 'Test Author', email: 'test@example.com' }], require: { php: '>=7.4', }, autoload: { 'psr-4': { 'Vendor\\TestPackage\\': 'src/', }, }, }; const [vendor, pkg] = vendorPackage.split('/'); const namespace = `${vendor.charAt(0).toUpperCase() + vendor.slice(1)}\\${pkg.charAt(0).toUpperCase() + pkg.slice(1).replace(/-/g, '')}`; const testPhpContent = ` { const zipTools = new smartarchive.ZipTools(); const normalizedName = packageName.replace(/-/g, '_'); const distInfoDir = `${normalizedName}-${version}.dist-info`; const metadata = `Metadata-Version: 2.1 Name: ${packageName} Version: ${version} Summary: Test Python package Home-page: https://example.com Author: Test Author Author-email: test@example.com License: MIT Platform: UNKNOWN Classifier: Programming Language :: Python :: 3 Requires-Python: >=3.7 Description-Content-Type: text/markdown # ${packageName} Test package for SmartRegistry `; const wheelContent = `Wheel-Version: 1.0 Generator: test 1.0.0 Root-Is-Purelib: true Tag: ${pyVersion}-none-any `; const moduleContent = `"""${packageName} module""" __version__ = "${version}" def hello(): return "Hello from ${packageName}!" `; const entries: smartarchive.IArchiveEntry[] = [ { archivePath: `${distInfoDir}/METADATA`, content: Buffer.from(metadata, 'utf-8'), }, { archivePath: `${distInfoDir}/WHEEL`, content: Buffer.from(wheelContent, 'utf-8'), }, { archivePath: `${distInfoDir}/RECORD`, content: Buffer.from('', 'utf-8'), }, { archivePath: `${distInfoDir}/top_level.txt`, content: Buffer.from(normalizedName, 'utf-8'), }, { archivePath: `${normalizedName}/__init__.py`, content: Buffer.from(moduleContent, 'utf-8'), }, ]; return Buffer.from(await zipTools.createZip(entries)); } /** * Helper to create a test Python source distribution (sdist) using smartarchive */ export async function createPythonSdist( packageName: string, version: string ): Promise { const tarTools = new smartarchive.TarTools(); const normalizedName = packageName.replace(/-/g, '_'); const dirPrefix = `${packageName}-${version}`; const pkgInfo = `Metadata-Version: 2.1 Name: ${packageName} Version: ${version} Summary: Test Python package Home-page: https://example.com Author: Test Author Author-email: test@example.com License: MIT `; const setupPy = `from setuptools import setup, find_packages setup( name="${packageName}", version="${version}", packages=find_packages(), python_requires=">=3.7", ) `; const moduleContent = `"""${packageName} module""" __version__ = "${version}" def hello(): return "Hello from ${packageName}!" `; const entries: smartarchive.IArchiveEntry[] = [ { archivePath: `${dirPrefix}/PKG-INFO`, content: Buffer.from(pkgInfo, 'utf-8'), }, { archivePath: `${dirPrefix}/setup.py`, content: Buffer.from(setupPy, 'utf-8'), }, { archivePath: `${dirPrefix}/${normalizedName}/__init__.py`, content: Buffer.from(moduleContent, 'utf-8'), }, ]; return Buffer.from(await tarTools.packFilesToTarGz(entries)); } /** * Helper to calculate PyPI file hashes */ export function calculatePypiHashes(data: Buffer) { return { md5: crypto.createHash('md5').update(data).digest('hex'), sha256: crypto.createHash('sha256').update(data).digest('hex'), blake2b: crypto.createHash('blake2b512').update(data).digest('hex'), }; } /** * Helper to create a test RubyGem file (minimal tar.gz structure) using smartarchive */ export async function createRubyGem( gemName: string, version: string, platform: string = 'ruby' ): Promise { const tarTools = new smartarchive.TarTools(); const gzipTools = new smartarchive.GzipTools(); const metadataYaml = `--- !ruby/object:Gem::Specification name: ${gemName} version: !ruby/object:Gem::Version version: ${version} platform: ${platform} authors: - Test Author autorequire: bindir: bin cert_chain: [] date: ${new Date().toISOString().split('T')[0]} dependencies: [] description: Test RubyGem email: test@example.com executables: [] extensions: [] extra_rdoc_files: [] files: - lib/${gemName}.rb homepage: https://example.com licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '2.7' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubygems_version: 3.0.0 signing_key: specification_version: 4 summary: Test gem for SmartRegistry test_files: [] `; const metadataGz = Buffer.from(await gzipTools.compress(Buffer.from(metadataYaml, 'utf-8'))); const libContent = `# ${gemName} module ${gemName.charAt(0).toUpperCase() + gemName.slice(1).replace(/-/g, '')} VERSION = "${version}" def self.hello "Hello from #{gemName}!" end end `; const dataEntries: smartarchive.IArchiveEntry[] = [ { archivePath: `lib/${gemName}.rb`, content: Buffer.from(libContent, 'utf-8'), }, ]; const dataTarGz = Buffer.from(await tarTools.packFilesToTarGz(dataEntries)); const gemEntries: smartarchive.IArchiveEntry[] = [ { archivePath: 'metadata.gz', content: metadataGz, }, { archivePath: 'data.tar.gz', content: dataTarGz, }, ]; return Buffer.from(await tarTools.packFiles(gemEntries)); } /** * Helper to calculate RubyGems checksums */ export function calculateRubyGemsChecksums(data: Buffer) { return { md5: crypto.createHash('md5').update(data).digest('hex'), sha256: crypto.createHash('sha256').update(data).digest('hex'), }; }