Files
attest/__tests__/sbom.test.ts
T
Brian DeHamer dc4ad3cc6c Consolidate attestation actions (#346)
* consolidate attestation actions

Signed-off-by: Brian DeHamer <bdehamer@github.com>

* better errors

Signed-off-by: Brian DeHamer <bdehamer@github.com>

* Update src/sbom.ts

Co-authored-by: Austin Beattie <ajbeattie@github.com>

* clarify dedupe comment

Signed-off-by: Brian DeHamer <bdehamer@github.com>

---------

Signed-off-by: Brian DeHamer <bdehamer@github.com>
Co-authored-by: Austin Beattie <ajbeattie@github.com>
2026-02-13 11:23:24 -08:00

162 lines
4.3 KiB
TypeScript

import fs from 'fs/promises'
import os from 'os'
import path from 'path'
import { parseSBOMFromPath, generateSBOMPredicate, SBOM } from '../src/sbom'
describe('parseSBOMFromPath', () => {
let tmpDir: string
beforeEach(async () => {
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'sbom-test-'))
})
afterEach(async () => {
await fs.rm(tmpDir, { recursive: true })
})
describe('when file does not exist', () => {
it('throws an error', async () => {
await expect(parseSBOMFromPath('/nonexistent/file.json')).rejects.toThrow(
/SBOM file not found/
)
})
})
describe('when file contains valid SPDX SBOM', () => {
const spdxSBOM = {
spdxVersion: 'SPDX-2.3',
SPDXID: 'SPDXRef-DOCUMENT',
name: 'test-package',
packages: []
}
it('returns SBOM with type spdx', async () => {
const filePath = path.join(tmpDir, 'sbom.spdx.json')
await fs.writeFile(filePath, JSON.stringify(spdxSBOM))
const result = await parseSBOMFromPath(filePath)
expect(result.type).toBe('spdx')
expect(result.object).toEqual(spdxSBOM)
})
})
describe('when file contains valid CycloneDX SBOM', () => {
const cyclonedxSBOM = {
bomFormat: 'CycloneDX',
specVersion: '1.4',
serialNumber: 'urn:uuid:12345',
components: []
}
it('returns SBOM with type cyclonedx', async () => {
const filePath = path.join(tmpDir, 'sbom.cdx.json')
await fs.writeFile(filePath, JSON.stringify(cyclonedxSBOM))
const result = await parseSBOMFromPath(filePath)
expect(result.type).toBe('cyclonedx')
expect(result.object).toEqual(cyclonedxSBOM)
})
})
describe('when file contains invalid SBOM format', () => {
it('throws an error', async () => {
const filePath = path.join(tmpDir, 'invalid.json')
await fs.writeFile(filePath, JSON.stringify({ random: 'data' }))
await expect(parseSBOMFromPath(filePath)).rejects.toThrow(
/Unsupported SBOM format/
)
})
})
describe('when file contains invalid JSON', () => {
it('throws an error', async () => {
const filePath = path.join(tmpDir, 'invalid.json')
await fs.writeFile(filePath, 'not valid json')
await expect(parseSBOMFromPath(filePath)).rejects.toThrow()
})
})
describe('when file exceeds maximum size', () => {
it('throws an error', async () => {
const filePath = path.join(tmpDir, 'large.json')
// Create a file larger than 16MB
const largeContent = 'x'.repeat(17 * 1024 * 1024)
await fs.writeFile(filePath, largeContent)
await expect(parseSBOMFromPath(filePath)).rejects.toThrow(
/SBOM file exceeds maximum allowed size/
)
})
})
})
describe('generateSBOMPredicate', () => {
describe('for SPDX SBOM', () => {
const spdxSBOM: SBOM = {
type: 'spdx',
object: {
spdxVersion: 'SPDX-2.3',
SPDXID: 'SPDXRef-DOCUMENT',
name: 'test-package'
}
}
it('returns predicate with correct SPDX type', () => {
const predicate = generateSBOMPredicate(spdxSBOM)
expect(predicate.type).toBe('https://spdx.dev/Document/v2.3')
expect(predicate.params).toEqual(spdxSBOM.object)
})
})
describe('for CycloneDX SBOM', () => {
const cyclonedxSBOM: SBOM = {
type: 'cyclonedx',
object: {
bomFormat: 'CycloneDX',
specVersion: '1.4',
serialNumber: 'urn:uuid:12345'
}
}
it('returns predicate with correct CycloneDX type', () => {
const predicate = generateSBOMPredicate(cyclonedxSBOM)
expect(predicate.type).toBe('https://cyclonedx.org/bom')
expect(predicate.params).toEqual(cyclonedxSBOM.object)
})
})
describe('for SPDX without version', () => {
const invalidSBOM: SBOM = {
type: 'spdx',
object: {
SPDXID: 'SPDXRef-DOCUMENT'
}
}
it('throws an error', () => {
expect(() => generateSBOMPredicate(invalidSBOM)).toThrow(
/Cannot find spdxVersion/
)
})
})
describe('for unsupported SBOM type', () => {
const unsupportedSBOM = {
type: 'unknown' as SBOM['type'],
object: { foo: 'bar' }
}
it('throws an error', () => {
expect(() => generateSBOMPredicate(unsupportedSBOM)).toThrow(
/Unsupported SBOM format/
)
})
})
})