@@ -2,7 +2,7 @@ module.exports = {
|
|||||||
context: {
|
context: {
|
||||||
repo: { owner: 'test-owner', repo: 'test-repo' },
|
repo: { owner: 'test-owner', repo: 'test-repo' },
|
||||||
runId: 12345,
|
runId: 12345,
|
||||||
workflow: 'ci.yml'
|
serverUrl: 'https://github.com'
|
||||||
},
|
},
|
||||||
getOctokit: jest.fn()
|
getOctokit: jest.fn()
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-2
@@ -77,7 +77,12 @@ describe('SBOM Action', () => {
|
|||||||
}
|
}
|
||||||
getInputMock.mockImplementation(mockInput(inputs))
|
getInputMock.mockImplementation(mockInput(inputs))
|
||||||
const originalEnv = process.env
|
const originalEnv = process.env
|
||||||
process.env = { ...originalEnv, RUNNER_TEMP: '/tmp' }
|
process.env = {
|
||||||
|
...originalEnv,
|
||||||
|
RUNNER_TEMP: '/tmp',
|
||||||
|
GITHUB_WORKFLOW_REF:
|
||||||
|
'test-owner/test-repo/.github/workflows/ci.yml@refs/heads/main'
|
||||||
|
}
|
||||||
|
|
||||||
// Run the main function
|
// Run the main function
|
||||||
await main.run()
|
await main.run()
|
||||||
@@ -145,7 +150,12 @@ describe('SBOM Action', () => {
|
|||||||
}
|
}
|
||||||
getInputMock.mockImplementation(mockInput(inputs))
|
getInputMock.mockImplementation(mockInput(inputs))
|
||||||
const originalEnv = process.env
|
const originalEnv = process.env
|
||||||
process.env = { ...originalEnv, RUNNER_TEMP: '/tmp' }
|
process.env = {
|
||||||
|
...originalEnv,
|
||||||
|
RUNNER_TEMP: '/tmp',
|
||||||
|
GITHUB_WORKFLOW_REF:
|
||||||
|
'test-owner/test-repo/.github/workflows/ci.yml@refs/heads/main'
|
||||||
|
}
|
||||||
|
|
||||||
// Mock release not found
|
// Mock release not found
|
||||||
mockGetReleaseByTag.mockRejectedValue({ status: 404 })
|
mockGetReleaseByTag.mockRejectedValue({ status: 404 })
|
||||||
|
|||||||
@@ -13,17 +13,33 @@ describe('generateAssetName', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('buildAttesterId', () => {
|
describe('buildAttesterId', () => {
|
||||||
it('builds correct attester ID URL', () => {
|
it('builds correct attester ID URL from workflow ref', () => {
|
||||||
const result = buildAttesterId('octocat', 'hello-world', 'ci.yml')
|
const result = buildAttesterId(
|
||||||
|
'https://github.com',
|
||||||
|
'octocat/hello-world/.github/workflows/ci.yml@refs/heads/main'
|
||||||
|
)
|
||||||
expect(result).toBe(
|
expect(result).toBe(
|
||||||
'https://github.com/octocat/hello-world/.github/workflows/ci.yml'
|
'https://github.com/octocat/hello-world/.github/workflows/ci.yml'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles workflow names with spaces', () => {
|
it('handles workflow refs with tags', () => {
|
||||||
const result = buildAttesterId('owner', 'repo', 'Build and Test.yml')
|
const result = buildAttesterId(
|
||||||
|
'https://github.com',
|
||||||
|
'owner/repo/.github/workflows/release.yml@refs/tags/v1.0.0'
|
||||||
|
)
|
||||||
expect(result).toBe(
|
expect(result).toBe(
|
||||||
'https://github.com/owner/repo/.github/workflows/Build and Test.yml'
|
'https://github.com/owner/repo/.github/workflows/release.yml'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles enterprise server URLs', () => {
|
||||||
|
const result = buildAttesterId(
|
||||||
|
'https://github.example.com',
|
||||||
|
'owner/repo/.github/workflows/build.yml@refs/heads/main'
|
||||||
|
)
|
||||||
|
expect(result).toBe(
|
||||||
|
'https://github.example.com/owner/repo/.github/workflows/build.yml'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+11
-4
@@ -58393,13 +58393,17 @@ async function run() {
|
|||||||
// Get context for release upload
|
// Get context for release upload
|
||||||
const { owner, repo } = github.context.repo;
|
const { owner, repo } = github.context.repo;
|
||||||
const runId = github.context.runId;
|
const runId = github.context.runId;
|
||||||
const workflow = github.context.workflow;
|
const serverUrl = github.context.serverUrl;
|
||||||
|
const workflowRef = process.env.GITHUB_WORKFLOW_REF;
|
||||||
|
if (!workflowRef) {
|
||||||
|
throw new Error('Missing GITHUB_WORKFLOW_REF environment variable');
|
||||||
|
}
|
||||||
// Upload SBOM to release
|
// Upload SBOM to release
|
||||||
core.debug('Uploading SBOM to release');
|
core.debug('Uploading SBOM to release');
|
||||||
const octokit = github.getOctokit(token);
|
const octokit = github.getOctokit(token);
|
||||||
const { downloadUrl } = await (0, release_1.uploadSBOMToRelease)(octokit, owner, repo, runId, sbomPath);
|
const { downloadUrl } = await (0, release_1.uploadSBOMToRelease)(octokit, owner, repo, runId, sbomPath);
|
||||||
// Generate reference predicate
|
// Generate reference predicate
|
||||||
const attesterId = (0, release_1.buildAttesterId)(owner, repo, workflow);
|
const attesterId = (0, release_1.buildAttesterId)(serverUrl, workflowRef);
|
||||||
const mediaType = (0, reference_1.getMediaType)(sbom.type);
|
const mediaType = (0, reference_1.getMediaType)(sbom.type);
|
||||||
const predicate = (0, reference_1.generateReferencePredicate)({
|
const predicate = (0, reference_1.generateReferencePredicate)({
|
||||||
attesterId,
|
attesterId,
|
||||||
@@ -58542,8 +58546,11 @@ function generateAssetName(runId, sbomPath) {
|
|||||||
const originalName = path_1.default.basename(sbomPath);
|
const originalName = path_1.default.basename(sbomPath);
|
||||||
return `${runId}-${originalName}`;
|
return `${runId}-${originalName}`;
|
||||||
}
|
}
|
||||||
function buildAttesterId(owner, repo, workflow) {
|
function buildAttesterId(serverUrl, workflowRef) {
|
||||||
return `https://github.com/${owner}/${repo}/.github/workflows/${workflow}`;
|
// workflowRef is in the format: owner/repo/.github/workflows/file.yml@refs/heads/branch
|
||||||
|
// Extract just the owner/repo/.github/workflows/file.yml part
|
||||||
|
const workflowPath = workflowRef.split('@')[0];
|
||||||
|
return `${serverUrl}/${workflowPath}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -27,7 +27,12 @@ export async function run(): Promise<void> {
|
|||||||
// Get context for release upload
|
// Get context for release upload
|
||||||
const { owner, repo } = github.context.repo
|
const { owner, repo } = github.context.repo
|
||||||
const runId = github.context.runId
|
const runId = github.context.runId
|
||||||
const workflow = github.context.workflow
|
const serverUrl = github.context.serverUrl
|
||||||
|
const workflowRef = process.env.GITHUB_WORKFLOW_REF
|
||||||
|
|
||||||
|
if (!workflowRef) {
|
||||||
|
throw new Error('Missing GITHUB_WORKFLOW_REF environment variable')
|
||||||
|
}
|
||||||
|
|
||||||
// Upload SBOM to release
|
// Upload SBOM to release
|
||||||
core.debug('Uploading SBOM to release')
|
core.debug('Uploading SBOM to release')
|
||||||
@@ -41,7 +46,7 @@ export async function run(): Promise<void> {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Generate reference predicate
|
// Generate reference predicate
|
||||||
const attesterId = buildAttesterId(owner, repo, workflow)
|
const attesterId = buildAttesterId(serverUrl, workflowRef)
|
||||||
const mediaType = getMediaType(sbom.type)
|
const mediaType = getMediaType(sbom.type)
|
||||||
const predicate = generateReferencePredicate({
|
const predicate = generateReferencePredicate({
|
||||||
attesterId,
|
attesterId,
|
||||||
|
|||||||
+6
-4
@@ -81,9 +81,11 @@ export function generateAssetName(runId: number, sbomPath: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function buildAttesterId(
|
export function buildAttesterId(
|
||||||
owner: string,
|
serverUrl: string,
|
||||||
repo: string,
|
workflowRef: string
|
||||||
workflow: string
|
|
||||||
): string {
|
): string {
|
||||||
return `https://github.com/${owner}/${repo}/.github/workflows/${workflow}`
|
// workflowRef is in the format: owner/repo/.github/workflows/file.yml@refs/heads/branch
|
||||||
|
// Extract just the owner/repo/.github/workflows/file.yml part
|
||||||
|
const workflowPath = workflowRef.split('@')[0]
|
||||||
|
return `${serverUrl}/${workflowPath}`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user