Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,7 @@ Thumbs.db
# Ignore built ts files
__tests__/runner/*
__test__/*.js
lib/**/*
lib/**/*

# Ignore compiled js files
src/*.js
42 changes: 30 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,39 @@

# Generate SBOM Action

This action uses the REST API call to generate the SBOM for the repo (on the default branch). You can then use the `fileName` output to upload the file as an artifact.
This action uses the REST API call to generate the SBOM for the repo (on the default branch). You can then use the `fileName` output to upload the file(s) as an artifact.

## Usage

You can use the workflow as follows:
You can use the workflow as follows to retrieve the SBOM for the current repo:

```yaml
gen-sbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: advanced-security/generate-sbom-action@v1
id: gensbom
- uses: actions/upload-artifact@v3
with:
name: sbom
path: ${{ steps.gensbom.outputs.fileName }}
gen-sbom-for-repo:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: advanced-security/generate-sbom-action@v1
id: gensbom
- uses: actions/upload-artifact@v3
with:
name: sbom
path: ${{ steps.gensbom.outputs.fileName }}
```

Or, the action can generate all SBOMs for a given organization (PAT required):

```yaml
gen-sbom-for-repo:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: advanced-security/generate-sbom-action@v1
id: gensbom
with:
token: ${{ secrets.PAT }}
resource: ${{ github.repository_owner }}
- uses: actions/upload-artifact@v3
with:
name: sbom-org
path: ${{ steps.gensbom.outputs.fileName }}
```
50 changes: 42 additions & 8 deletions __tests__/generate-sbom.test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import {Octokit} from '@octokit/core'
import {Octokit} from 'octokit'
import {describe, expect} from '@jest/globals'
import {generateSBOM} from '../src/generate-sbom'
import {createRepoList, generateSBOM} from '../src/generate-sbom'
import fs from 'fs'

const mockSBOM = fs.readFileSync('./__tests__/mock-sbom.json', 'utf-8')
const mockRepos = fs.readFileSync('./__tests__/mock-repos.json', 'utf-8')

jest.spyOn(fs, 'writeFile').mockImplementation((f, d, callback) => {
console.log('[mock] writing file')
callback(null)
})

describe('generateSBOM', () => {
describe('generateSBOMForRepo', () => {
it('should retrieve the SBOM for a repository', async () => {
const token = 'test-token'
const owner = 'octocat'
const repo = 'hello-world'
const sha = 'fe43fdf'
const resource = 'octocat/hello-world'
const [owner, repo] = resource.split('/')

const octokit = new Octokit()
;(<any>octokit).request = jest.fn().mockResolvedValue({
Expand All @@ -24,7 +24,7 @@ describe('generateSBOM', () => {
}
})

await generateSBOM(token, owner, repo, sha, <any>octokit)
await generateSBOM(owner, repo, <any>octokit, 'repo')

expect(octokit.request).toHaveBeenCalledWith(
'GET /repos/{owner}/{repo}/dependency-graph/sbom',
Expand All @@ -38,7 +38,41 @@ describe('generateSBOM', () => {
)

expect(fs.writeFile).toHaveBeenCalledWith(
`sbom-${owner}-${repo}-${sha}.json`,
`sbom-${owner}-${repo}.json`,
JSON.stringify(mockSBOM),
expect.any(Function)
)
})
})

describe('generateSBOMForOrg', () => {
it('should retrieve the SBOMs for an organization', async () => {
const token = 'test-token'
const resource = 'actions'
const [owner, repo] = resource.split('/')

const octokit = new Octokit()
;(<any>octokit).paginate = jest.fn().mockResolvedValue({
data: {
repos: mockRepos
}
})

console.log(`this is org: ${owner}`)

// repo is supposed to be undefined
await createRepoList(token, owner, repo, <any>octokit)

expect(octokit.paginate).toHaveBeenCalledWith('GET /orgs/{owner}/repos', {
owner,
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
})

// TODO: this fails b/c no repos are returned in the above mock
expect(fs.writeFile).toHaveBeenCalledWith(
`sbom-${owner}-*.json`,
JSON.stringify(mockSBOM),
expect.any(Function)
)
Expand Down
Loading