'use strict'; const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('fs'); const path = require('path'); test('Docker runtime includes the bundled community game-hash catalog', () => { const root = path.resolve(__dirname, '..', '..'); const dockerfile = fs.readFileSync(path.join(root, 'Dockerfile'), 'utf8'); const catalog = JSON.parse(fs.readFileSync(path.join(root, 'data', 'game_hashes.json'), 'utf8')); assert.match(dockerfile, /^COPY --chown=chimera:chimera data \.\/data$/m); assert.equal(catalog.version, 1); assert.ok(Array.isArray(catalog.hashes)); }); test('git archives preserve Linux shell entrypoints with LF endings', () => { const root = path.resolve(__dirname, '..', '..'); const attributes = fs.readFileSync(path.join(root, '.gitattributes'), 'utf8'); const entrypoint = fs.readFileSync(path.join(root, 'docker', 'entrypoint.sh')); assert.match(attributes, /^\*\.sh text eol=lf$/m); assert.equal(entrypoint.includes(Buffer.from('\r\n')), false); assert.equal(entrypoint.subarray(0, 10).toString(), '#!/bin/sh\n'); }); test('git archives preserve canonical migration checksums with LF endings', () => { const root = path.resolve(__dirname, '..', '..'); const attributes = fs.readFileSync(path.join(root, '.gitattributes'), 'utf8'); const migrationsDir = path.join(root, 'src', 'database', 'migrations'); const migrations = fs.readdirSync(migrationsDir).filter((name) => name.endsWith('.js')); assert.match(attributes, /^src\/database\/migrations\/\*\.js text eol=lf$/m); assert.ok(migrations.length > 0); for (const migration of migrations) { const contents = fs.readFileSync(path.join(migrationsDir, migration)); assert.equal(contents.includes(Buffer.from('\r\n')), false, `${migration} must use LF endings`); } }); test('production deploy is runnerless and image provenance is explicit', () => { const root = path.resolve(__dirname, '..', '..'); assert.equal( fs.existsSync(path.join(root, '.gitea', 'workflows', 'unraid-deploy.yml')), false, ); const compose = fs.readFileSync(path.join(root, 'compose.yaml'), 'utf8'); const dockerfile = fs.readFileSync(path.join(root, 'Dockerfile'), 'utf8'); const dockerignore = fs.readFileSync(path.join(root, '.dockerignore'), 'utf8'); assert.match(compose, /CHIMERA_SOURCE_TREE: "\$\{CHIMERA_SOURCE_TREE:-\}"/); assert.match(compose, /CHIMERA_SOURCE_REPOSITORY: "\$\{CHIMERA_SOURCE_REPOSITORY:-development\}"/); assert.match(dockerfile, /^ARG CHIMERA_SOURCE_REPOSITORY=development$/m); assert.match(dockerfile, /org\.opencontainers\.image\.source="\$\{CHIMERA_SOURCE_REPOSITORY\}"/); assert.match(dockerignore, /^\.gitea-deploy$/m); }); test('Gitea CI publishes the SBOM with the Gitea-compatible artifact client', () => { const root = path.resolve(__dirname, '..', '..'); const workflow = fs.readFileSync(path.join(root, '.gitea', 'workflows', 'ci.yml'), 'utf8'); const containerJob = workflow.slice(workflow.indexOf('\n container:')); assert.match(containerJob, /runs-on: ubuntu-latest/); assert.match(containerJob, /gitea\.com\/actions\/checkout@v4/); assert.match(containerJob, /gitea\.com\/actions\/setup-node@v4[\s\S]*node-version: '24'[\s\S]*cache: npm/); assert.match(containerJob, /run: npm ci/); assert.match(containerJob, /docker build --pull[\s\S]*CHIMERA_SOURCE_REPOSITORY[\s\S]*CHIMERA_SOURCE_REVISION[\s\S]*CHIMERA_SOURCE_TREE[\s\S]*CHIMERA_BUILD_ID[\s\S]*CHIMERA_BUILD_DATE/); assert.match(containerJob, /npm sbom --sbom-format cyclonedx > chimera-sbom\.cdx\.json/); assert.match(containerJob, /gitea\.com\/actions\/upload-artifact@v3/); assert.doesNotMatch(containerJob, /gitea\.com\/actions\/upload-artifact@v4/); assert.match(containerJob, /if-no-files-found: error/); assert.doesNotMatch(containerJob, /unraid-deploy|Bootstrap Node|docker (?:cp|create|rm)\b/); });