Files
attest-sbom/src/sbom.ts
T
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Brian DeHamer
0486c4aa49 Bump jest and @types/jest (#182)
* Bump jest and @types/jest

Bumps [jest](https://github.com/jestjs/jest/tree/HEAD/packages/jest) and [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest). These dependencies needed to be updated together.

Updates `jest` from 29.7.0 to 30.0.0
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.0.0/packages/jest)

Updates `@types/jest` from 29.5.14 to 30.0.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-version: 30.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
- dependency-name: "@types/jest"
  dependency-version: 30.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>

* ts isolated modules

Signed-off-by: Brian DeHamer <[email protected]>

* test coverage

Signed-off-by: Brian DeHamer <[email protected]>

* rebuild dist

Signed-off-by: Brian DeHamer <[email protected]>

---------

Signed-off-by: dependabot[bot] <[email protected]>
Signed-off-by: Brian DeHamer <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Brian DeHamer <[email protected]>
2025-06-17 09:51:48 -07:00

101 lines
2.4 KiB
TypeScript

import fs from 'fs'
import * as path from 'path'
import type { Predicate } from '@actions/attest'
export type SBOM = {
type: 'spdx' | 'cyclonedx'
object: object
}
export async function parseSBOMFromPath(filePath: string): Promise<SBOM> {
// Read the file content
const fileContent = await fs.promises.readFile(filePath, 'utf8')
const sbom = JSON.parse(fileContent) as object
if (checkIsSPDX(sbom)) {
return { type: 'spdx', object: sbom }
} else if (checkIsCycloneDX(sbom)) {
return { type: 'cyclonedx', object: sbom }
}
throw new Error('Unsupported SBOM format')
}
function checkIsSPDX(sbomObject: {
spdxVersion?: string
SPDXID?: string
}): boolean {
if (sbomObject?.spdxVersion && sbomObject?.SPDXID) {
return true
} else {
return false
}
}
function checkIsCycloneDX(sbomObject: {
bomFormat?: string
serialNumber?: string
specVersion?: string
}): boolean {
if (
sbomObject?.bomFormat &&
sbomObject?.serialNumber &&
sbomObject?.specVersion
) {
return true
} else {
return false
}
}
export const storePredicate = (predicate: Predicate): string => {
// random tempfile
const basePath = process.env['RUNNER_TEMP']
if (!basePath) {
throw new Error('Missing RUNNER_TEMP environment variable')
}
const tmpDir = fs.mkdtempSync(path.join(basePath, path.sep))
const tempFile = path.join(tmpDir, 'predicate.json')
// write predicate to file
fs.writeFileSync(tempFile, JSON.stringify(predicate.params))
return tempFile
}
export const generateSBOMPredicate = (sbom: SBOM): Predicate => {
switch (sbom.type) {
case 'spdx':
return generateSPDXIntoto(sbom.object)
case 'cyclonedx':
return generateCycloneDXIntoto(sbom.object)
default:
throw new Error('Unsupported SBOM format')
}
}
// ref: https://github.com/in-toto/attestation/blob/main/spec/predicates/spdx.md
const generateSPDXIntoto = (sbom: object): Predicate => {
const spdxVersion = (sbom as { spdxVersion?: string })?.['spdxVersion']
if (!spdxVersion) {
throw new Error('Cannot find spdxVersion in the SBOM')
}
const version = spdxVersion.split('-')[1]
return {
type: `https://spdx.dev/Document/v${version}`,
params: sbom
}
}
// ref: https://github.com/in-toto/attestation/blob/main/spec/predicates/cyclonedx.md
const generateCycloneDXIntoto = (sbom: object): Predicate => {
return {
type: 'https://cyclonedx.org/bom',
params: sbom
}
}