mirror of
https://github.com/graalvm/setup-graalvm.git
synced 2025-03-13 14:30:15 +08:00
Integrate Native Image SBOM with GitHub's Dependency Submission API (#119)
Co-authored-by: Fabio Niephaus <fabio.niephaus@oracle.com>
This commit is contained in:
parent
c09e29bb11
commit
7b74bd8bd8
37
.github/workflows/test.yml
vendored
37
.github/workflows/test.yml
vendored
@ -420,3 +420,40 @@ jobs:
|
|||||||
# popd > /dev/null
|
# popd > /dev/null
|
||||||
- name: Remove components
|
- name: Remove components
|
||||||
run: gu remove espresso llvm-toolchain nodejs python ruby wasm
|
run: gu remove espresso llvm-toolchain nodejs python ruby wasm
|
||||||
|
test-sbom:
|
||||||
|
name: test 'native-image-enable-sbom' option
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
java-version: ['24-ea', 'latest-ea']
|
||||||
|
distribution: ['graalvm']
|
||||||
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
|
set-gds-token: [false]
|
||||||
|
components: ['']
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Run setup-graalvm action
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
java-version: ${{ matrix.java-version }}
|
||||||
|
distribution: ${{ matrix.distribution }}
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
components: ${{ matrix.components }}
|
||||||
|
gds-token: ${{ matrix.set-gds-token && secrets.GDS_TOKEN || '' }}
|
||||||
|
native-image-enable-sbom: 'true'
|
||||||
|
- name: Build Maven project and verify that SBOM was generated and its contents
|
||||||
|
run: |
|
||||||
|
cd __tests__/sbom/main-test-app
|
||||||
|
mvn --no-transfer-progress -Pnative package
|
||||||
|
bash verify-sbom.sh
|
||||||
|
shell: bash
|
||||||
|
if: runner.os != 'Windows'
|
||||||
|
- name: Build Maven project and verify that SBOM was generated and its contents (Windows)
|
||||||
|
run: |
|
||||||
|
cd __tests__\sbom\main-test-app
|
||||||
|
mvn --no-transfer-progress -Pnative package
|
||||||
|
cmd /c verify-sbom.cmd
|
||||||
|
shell: cmd
|
||||||
|
if: runner.os == 'Windows'
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -96,4 +96,7 @@ Thumbs.db
|
|||||||
|
|
||||||
# Ignore built ts files
|
# Ignore built ts files
|
||||||
__tests__/runner/*
|
__tests__/runner/*
|
||||||
lib/**/*
|
lib/**/*
|
||||||
|
|
||||||
|
# Ignore target directory in __tests__
|
||||||
|
__tests__/**/target
|
||||||
|
@ -205,6 +205,7 @@ This actions can be configured with the following options:
|
|||||||
| `native-image-job-reports` *) | `'false'` | If set to `'true'`, post a job summary containing a Native Image build report. |
|
| `native-image-job-reports` *) | `'false'` | If set to `'true'`, post a job summary containing a Native Image build report. |
|
||||||
| `native-image-pr-reports` *) | `'false'` | If set to `'true'`, post a comment containing a Native Image build report on pull requests. Requires `write` permissions for the [`pull-requests` scope][gha-permissions]. |
|
| `native-image-pr-reports` *) | `'false'` | If set to `'true'`, post a comment containing a Native Image build report on pull requests. Requires `write` permissions for the [`pull-requests` scope][gha-permissions]. |
|
||||||
| `native-image-pr-reports-update-existing` *) | `'false'` | Instead of posting another comment, update an existing PR comment with the latest Native Image build report. Requires `native-image-pr-reports` to be `true`. |
|
| `native-image-pr-reports-update-existing` *) | `'false'` | Instead of posting another comment, update an existing PR comment with the latest Native Image build report. Requires `native-image-pr-reports` to be `true`. |
|
||||||
|
| `native-image-enable-sbom` | `'false'` | If set to `'true'`, generate a minimal SBOM based on the Native Image static analysis and submit it to GitHub's dependency submission API. This enables the [dependency graph feature](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-the-dependency-graph) for dependency tracking and vulnerability analysis. Requires `write` permissions for the [`contents` scope][gha-permissions] and the dependency graph to be actived (on by default for public repositories - see [how to activate](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/configuring-the-dependency-graph#enabling-and-disabling-the-dependency-graph-for-a-private-repository)). Only available in Oracle GraalVM for JDK 24 or later. |
|
||||||
| `components` | `''` | Comma-separated list of GraalVM components (e.g., `native-image` or `ruby,nodejs`) that will be installed by the [GraalVM Updater][gu]. |
|
| `components` | `''` | Comma-separated list of GraalVM components (e.g., `native-image` or `ruby,nodejs`) that will be installed by the [GraalVM Updater][gu]. |
|
||||||
| `version` | `''` | `X.Y.Z` (e.g., `22.3.0`) for a specific [GraalVM release][releases] up to `22.3.2`<br>`mandrel-X.Y.Z.W` or `X.Y.Z.W-Final` (e.g., `mandrel-21.3.0.0-Final` or `21.3.0.0-Final`) for a specific [Mandrel release][mandrel-releases],<br>`mandrel-latest` or `latest` for the latest Mandrel stable release. |
|
| `version` | `''` | `X.Y.Z` (e.g., `22.3.0`) for a specific [GraalVM release][releases] up to `22.3.2`<br>`mandrel-X.Y.Z.W` or `X.Y.Z.W-Final` (e.g., `mandrel-21.3.0.0-Final` or `21.3.0.0-Final`) for a specific [Mandrel release][mandrel-releases],<br>`mandrel-latest` or `latest` for the latest Mandrel stable release. |
|
||||||
| `gds-token` | `''` Download token for the GraalVM Download Service. If a non-empty token is provided, the action will set up Oracle GraalVM (see [Oracle GraalVM via GDS template](#template-for-oracle-graalvm-via-graalvm-download-service)) or GraalVM Enterprise Edition (see [GraalVM EE template](#template-for-graalvm-enterprise-edition)) via GDS. |
|
| `gds-token` | `''` Download token for the GraalVM Download Service. If a non-empty token is provided, the action will set up Oracle GraalVM (see [Oracle GraalVM via GDS template](#template-for-oracle-graalvm-via-graalvm-download-service)) or GraalVM Enterprise Edition (see [GraalVM EE template](#template-for-graalvm-enterprise-edition)) via GDS. |
|
||||||
|
@ -49,7 +49,7 @@ describe('cleanup', () => {
|
|||||||
resetState()
|
resetState()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does not fail nor warn even when the save provess throws a ReserveCacheError', async () => {
|
it('does not fail nor warn even when the save process throws a ReserveCacheError', async () => {
|
||||||
spyCacheSave.mockImplementation((paths: string[], key: string) =>
|
spyCacheSave.mockImplementation((paths: string[], key: string) =>
|
||||||
Promise.reject(
|
Promise.reject(
|
||||||
new cache.ReserveCacheError(
|
new cache.ReserveCacheError(
|
||||||
|
306
__tests__/sbom.test.ts
Normal file
306
__tests__/sbom.test.ts
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
import * as c from '../src/constants'
|
||||||
|
import {setUpSBOMSupport, processSBOM} from '../src/features/sbom'
|
||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as github from '@actions/github'
|
||||||
|
import * as glob from '@actions/glob'
|
||||||
|
import {join} from 'path'
|
||||||
|
import {tmpdir} from 'os'
|
||||||
|
import {mkdtempSync, writeFileSync, rmSync} from 'fs'
|
||||||
|
|
||||||
|
jest.mock('@actions/glob')
|
||||||
|
jest.mock('@actions/github', () => ({
|
||||||
|
getOctokit: jest.fn(() => ({
|
||||||
|
request: jest.fn().mockResolvedValue(undefined)
|
||||||
|
})),
|
||||||
|
context: {
|
||||||
|
repo: {
|
||||||
|
owner: 'test-owner',
|
||||||
|
repo: 'test-repo'
|
||||||
|
},
|
||||||
|
sha: 'test-sha',
|
||||||
|
ref: 'test-ref',
|
||||||
|
workflow: 'test-workflow',
|
||||||
|
job: 'test-job',
|
||||||
|
runId: '12345'
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
function mockFindSBOM(files: string[]) {
|
||||||
|
const mockCreate = jest.fn().mockResolvedValue({
|
||||||
|
glob: jest.fn().mockResolvedValue(files)
|
||||||
|
})
|
||||||
|
;(glob.create as jest.Mock).mockImplementation(mockCreate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mocks the GitHub dependency submission API return value
|
||||||
|
// 'undefined' is treated as a successful request
|
||||||
|
function mockGithubAPIReturnValue(returnValue: Error | undefined = undefined) {
|
||||||
|
const mockOctokit = {
|
||||||
|
request:
|
||||||
|
returnValue === undefined
|
||||||
|
? jest.fn().mockResolvedValue(returnValue)
|
||||||
|
: jest.fn().mockRejectedValue(returnValue)
|
||||||
|
}
|
||||||
|
;(github.getOctokit as jest.Mock).mockReturnValue(mockOctokit)
|
||||||
|
return mockOctokit
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('sbom feature', () => {
|
||||||
|
let spyInfo: jest.SpyInstance<void, Parameters<typeof core.info>>
|
||||||
|
let spyWarning: jest.SpyInstance<void, Parameters<typeof core.warning>>
|
||||||
|
let spyExportVariable: jest.SpyInstance<
|
||||||
|
void,
|
||||||
|
Parameters<typeof core.exportVariable>
|
||||||
|
>
|
||||||
|
let workspace: string
|
||||||
|
let originalEnv: NodeJS.ProcessEnv
|
||||||
|
const javaVersion = '24.0.0'
|
||||||
|
const distribution = c.DISTRIBUTION_GRAALVM
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
originalEnv = process.env
|
||||||
|
|
||||||
|
process.env = {
|
||||||
|
...process.env,
|
||||||
|
GITHUB_REPOSITORY: 'test-owner/test-repo',
|
||||||
|
GITHUB_TOKEN: 'fake-token'
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace = mkdtempSync(join(tmpdir(), 'setup-graalvm-sbom-'))
|
||||||
|
mockGithubAPIReturnValue()
|
||||||
|
|
||||||
|
spyInfo = jest.spyOn(core, 'info').mockImplementation(() => null)
|
||||||
|
spyWarning = jest.spyOn(core, 'warning').mockImplementation(() => null)
|
||||||
|
spyExportVariable = jest
|
||||||
|
.spyOn(core, 'exportVariable')
|
||||||
|
.mockImplementation(() => null)
|
||||||
|
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||||
|
if (name === 'native-image-enable-sbom') {
|
||||||
|
return 'true'
|
||||||
|
}
|
||||||
|
if (name === 'github-token') {
|
||||||
|
return 'fake-token'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
process.env = originalEnv
|
||||||
|
jest.clearAllMocks()
|
||||||
|
spyInfo.mockRestore()
|
||||||
|
spyWarning.mockRestore()
|
||||||
|
spyExportVariable.mockRestore()
|
||||||
|
rmSync(workspace, {recursive: true, force: true})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('setup', () => {
|
||||||
|
it('should throw an error when the distribution is not Oracle GraalVM', () => {
|
||||||
|
const not_supported_distributions = [
|
||||||
|
c.DISTRIBUTION_GRAALVM_COMMUNITY,
|
||||||
|
c.DISTRIBUTION_MANDREL,
|
||||||
|
c.DISTRIBUTION_LIBERICA,
|
||||||
|
''
|
||||||
|
]
|
||||||
|
for (const distribution of not_supported_distributions) {
|
||||||
|
expect(() => setUpSBOMSupport(javaVersion, distribution)).toThrow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error when the java-version is not supported', () => {
|
||||||
|
const not_supported_versions = ['23', '23-ea', '21.0.3', 'dev', '17', '']
|
||||||
|
for (const version of not_supported_versions) {
|
||||||
|
expect(() => setUpSBOMSupport(version, distribution)).toThrow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not throw an error when the java-version is supported', () => {
|
||||||
|
const supported_versions = ['24', '24-ea', '24.0.2', 'latest-ea']
|
||||||
|
for (const version of supported_versions) {
|
||||||
|
expect(() => setUpSBOMSupport(version, distribution)).not.toThrow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should set the SBOM option when activated', () => {
|
||||||
|
setUpSBOMSupport(javaVersion, distribution)
|
||||||
|
|
||||||
|
expect(spyExportVariable).toHaveBeenCalledWith(
|
||||||
|
c.NATIVE_IMAGE_OPTIONS_ENV,
|
||||||
|
expect.stringContaining('--enable-sbom=export')
|
||||||
|
)
|
||||||
|
expect(spyInfo).toHaveBeenCalledWith(
|
||||||
|
'Enabled SBOM generation for Native Image build'
|
||||||
|
)
|
||||||
|
expect(spyWarning).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not set the SBOM option when not activated', () => {
|
||||||
|
jest.spyOn(core, 'getInput').mockReturnValue('false')
|
||||||
|
setUpSBOMSupport(javaVersion, distribution)
|
||||||
|
|
||||||
|
expect(spyExportVariable).not.toHaveBeenCalled()
|
||||||
|
expect(spyInfo).not.toHaveBeenCalled()
|
||||||
|
expect(spyWarning).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('process', () => {
|
||||||
|
async function setUpAndProcessSBOM(sbom: object): Promise<void> {
|
||||||
|
setUpSBOMSupport(javaVersion, distribution)
|
||||||
|
spyInfo.mockClear()
|
||||||
|
|
||||||
|
// Mock 'native-image' invocation by creating the SBOM file
|
||||||
|
const sbomPath = join(workspace, 'test.sbom.json')
|
||||||
|
writeFileSync(sbomPath, JSON.stringify(sbom, null, 2))
|
||||||
|
|
||||||
|
mockFindSBOM([sbomPath])
|
||||||
|
|
||||||
|
await processSBOM()
|
||||||
|
}
|
||||||
|
|
||||||
|
const sampleSBOM = {
|
||||||
|
bomFormat: 'CycloneDX',
|
||||||
|
specVersion: '1.5',
|
||||||
|
version: 1,
|
||||||
|
serialNumber: 'urn:uuid:52c977f8-6d04-3c07-8826-597a036d61a6',
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 'library',
|
||||||
|
group: 'org.json',
|
||||||
|
name: 'json',
|
||||||
|
version: '20241224',
|
||||||
|
purl: 'pkg:maven/org.json/json@20241224',
|
||||||
|
'bom-ref': 'pkg:maven/org.json/json@20241224',
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
name: 'syft:cpe23',
|
||||||
|
value: 'cpe:2.3:a:json:json:20241224:*:*:*:*:*:*:*'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'library',
|
||||||
|
group: 'com.oracle',
|
||||||
|
name: 'main-test-app',
|
||||||
|
version: '1.0-SNAPSHOT',
|
||||||
|
purl: 'pkg:maven/com.oracle/main-test-app@1.0-SNAPSHOT',
|
||||||
|
'bom-ref': 'pkg:maven/com.oracle/main-test-app@1.0-SNAPSHOT'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
{
|
||||||
|
ref: 'pkg:maven/com.oracle/main-test-app@1.0-SNAPSHOT',
|
||||||
|
dependsOn: ['pkg:maven/org.json/json@20241224']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ref: 'pkg:maven/org.json/json@20241224',
|
||||||
|
dependsOn: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should process SBOM and display components', async () => {
|
||||||
|
await setUpAndProcessSBOM(sampleSBOM)
|
||||||
|
|
||||||
|
expect(spyInfo).toHaveBeenCalledWith(
|
||||||
|
'Found SBOM: ' + join(workspace, 'test.sbom.json')
|
||||||
|
)
|
||||||
|
expect(spyInfo).toHaveBeenCalledWith('=== SBOM Content ===')
|
||||||
|
expect(spyInfo).toHaveBeenCalledWith('- pkg:maven/org.json/json@20241224')
|
||||||
|
expect(spyInfo).toHaveBeenCalledWith(
|
||||||
|
'- pkg:maven/com.oracle/main-test-app@1.0-SNAPSHOT'
|
||||||
|
)
|
||||||
|
expect(spyInfo).toHaveBeenCalledWith(
|
||||||
|
' depends on: pkg:maven/org.json/json@20241224'
|
||||||
|
)
|
||||||
|
expect(spyWarning).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle components without purl', async () => {
|
||||||
|
const sbomWithoutPurl = {
|
||||||
|
...sampleSBOM,
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
type: 'library',
|
||||||
|
name: 'no-purl-package',
|
||||||
|
version: '1.0.0',
|
||||||
|
'bom-ref': 'no-purl-package@1.0.0'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
await setUpAndProcessSBOM(sbomWithoutPurl)
|
||||||
|
|
||||||
|
expect(spyInfo).toHaveBeenCalledWith('=== SBOM Content ===')
|
||||||
|
expect(spyInfo).toHaveBeenCalledWith('- no-purl-package@1.0.0')
|
||||||
|
expect(spyWarning).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle missing SBOM file', async () => {
|
||||||
|
setUpSBOMSupport(javaVersion, distribution)
|
||||||
|
spyInfo.mockClear()
|
||||||
|
|
||||||
|
mockFindSBOM([])
|
||||||
|
|
||||||
|
await expect(processSBOM()).rejects.toBeInstanceOf(Error)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw when JSON contains an invalid SBOM', async () => {
|
||||||
|
const invalidSBOM = {
|
||||||
|
'out-of-spec-field': {}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await setUpAndProcessSBOM(invalidSBOM)
|
||||||
|
fail('Expected an error since invalid JSON was passed')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should submit dependencies when processing valid SBOM', async () => {
|
||||||
|
const mockOctokit = mockGithubAPIReturnValue(undefined)
|
||||||
|
await setUpAndProcessSBOM(sampleSBOM)
|
||||||
|
|
||||||
|
expect(mockOctokit.request).toHaveBeenCalledWith(
|
||||||
|
'POST /repos/{owner}/{repo}/dependency-graph/snapshots',
|
||||||
|
expect.objectContaining({
|
||||||
|
owner: 'test-owner',
|
||||||
|
repo: 'test-repo',
|
||||||
|
version: expect.any(Number),
|
||||||
|
sha: 'test-sha',
|
||||||
|
ref: 'test-ref',
|
||||||
|
job: expect.objectContaining({
|
||||||
|
correlator: 'test-workflow_test-job',
|
||||||
|
id: '12345'
|
||||||
|
}),
|
||||||
|
manifests: expect.objectContaining({
|
||||||
|
'test.sbom.json': expect.objectContaining({
|
||||||
|
name: 'test.sbom.json',
|
||||||
|
resolved: expect.objectContaining({
|
||||||
|
json: expect.objectContaining({
|
||||||
|
package_url: 'pkg:maven/org.json/json@20241224',
|
||||||
|
dependencies: []
|
||||||
|
}),
|
||||||
|
'main-test-app': expect.objectContaining({
|
||||||
|
package_url:
|
||||||
|
'pkg:maven/com.oracle/main-test-app@1.0-SNAPSHOT',
|
||||||
|
dependencies: ['pkg:maven/org.json/json@20241224']
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
expect(spyInfo).toHaveBeenCalledWith(
|
||||||
|
'Dependency snapshot submitted successfully.'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle GitHub API submission errors gracefully', async () => {
|
||||||
|
mockGithubAPIReturnValue(new Error('API submission failed'))
|
||||||
|
|
||||||
|
await expect(setUpAndProcessSBOM(sampleSBOM)).rejects.toBeInstanceOf(
|
||||||
|
Error
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
54
__tests__/sbom/main-test-app/pom.xml
Normal file
54
__tests__/sbom/main-test-app/pom.xml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.oracle</groupId>
|
||||||
|
<artifactId>main-test-app</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.json</groupId>
|
||||||
|
<artifactId>json</artifactId>
|
||||||
|
<version>20241224</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>native</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.graalvm.buildtools</groupId>
|
||||||
|
<artifactId>native-maven-plugin</artifactId>
|
||||||
|
<version>0.10.3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>compile-no-fork</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>package</phase>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>com.oracle.sbom.SBOMTestApplication</mainClass>
|
||||||
|
<buildArgs>
|
||||||
|
<buildArg>-Ob</buildArg>
|
||||||
|
<buildArg>--no-fallback</buildArg>
|
||||||
|
<buildArg>-H:+ReportExceptionStackTraces</buildArg>
|
||||||
|
</buildArgs>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</project>
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.oracle.sbom;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
public class SBOMTestApplication {
|
||||||
|
public static void main(String argv[]) {
|
||||||
|
JSONObject jo = new JSONObject();
|
||||||
|
jo.put("lorem", "ipsum");
|
||||||
|
jo.put("dolor", "sit amet");
|
||||||
|
System.out.println(jo);
|
||||||
|
}
|
||||||
|
}
|
14
__tests__/sbom/main-test-app/verify-sbom.cmd
Normal file
14
__tests__/sbom/main-test-app/verify-sbom.cmd
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
@echo off
|
||||||
|
set "SCRIPT_DIR=%~dp0"
|
||||||
|
|
||||||
|
for %%p in (
|
||||||
|
"\"pkg:maven/org.json/json@20241224\""
|
||||||
|
"\"main-test-app\""
|
||||||
|
"\"svm\""
|
||||||
|
"\"nativeimage\""
|
||||||
|
) do (
|
||||||
|
echo Checking for %%p
|
||||||
|
findstr /c:%%p "%SCRIPT_DIR%target\main-test-app.sbom.json" || exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo SBOM was successfully generated and contained the expected components
|
19
__tests__/sbom/main-test-app/verify-sbom.sh
Normal file
19
__tests__/sbom/main-test-app/verify-sbom.sh
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
required_patterns=(
|
||||||
|
'"pkg:maven/org.json/json@20241224"'
|
||||||
|
'"main-test-app"'
|
||||||
|
'"svm"'
|
||||||
|
'"nativeimage"'
|
||||||
|
)
|
||||||
|
|
||||||
|
for pattern in "${required_patterns[@]}"; do
|
||||||
|
echo "Checking for $pattern"
|
||||||
|
if ! grep -q "$pattern" "$script_dir/target/main-test-app.sbom.json"; then
|
||||||
|
echo "Pattern not found: $pattern"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "SBOM was successfully generated and contained the expected components"
|
@ -51,6 +51,10 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
description: 'Instead of posting another comment, update an existing PR comment with the latest Native Image build report.'
|
description: 'Instead of posting another comment, update an existing PR comment with the latest Native Image build report.'
|
||||||
default: 'false'
|
default: 'false'
|
||||||
|
native-image-enable-sbom:
|
||||||
|
required: false
|
||||||
|
description: 'Automatically generate an SBOM and submit it to the GitHub dependency submission API for vulnerability and dependency tracking.'
|
||||||
|
default: 'false'
|
||||||
version:
|
version:
|
||||||
required: false
|
required: false
|
||||||
description: 'GraalVM version (release, latest, dev).'
|
description: 'GraalVM version (release, latest, dev).'
|
||||||
|
322
dist/cleanup/index.js
generated
vendored
322
dist/cleanup/index.js
generated
vendored
@ -98011,6 +98011,7 @@ const core = __importStar(__nccwpck_require__(2186));
|
|||||||
const constants = __importStar(__nccwpck_require__(9042));
|
const constants = __importStar(__nccwpck_require__(9042));
|
||||||
const cache_1 = __nccwpck_require__(9179);
|
const cache_1 = __nccwpck_require__(9179);
|
||||||
const reports_1 = __nccwpck_require__(2046);
|
const reports_1 = __nccwpck_require__(2046);
|
||||||
|
const sbom_1 = __nccwpck_require__(9181);
|
||||||
/**
|
/**
|
||||||
* Check given input and run a save process for the specified package manager
|
* Check given input and run a save process for the specified package manager
|
||||||
* @returns Promise that will be resolved when the save process finishes
|
* @returns Promise that will be resolved when the save process finishes
|
||||||
@ -98043,6 +98044,7 @@ function ignoreErrors(promise) {
|
|||||||
function run() {
|
function run() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
yield ignoreErrors((0, reports_1.generateReports)());
|
yield ignoreErrors((0, reports_1.generateReports)());
|
||||||
|
yield ignoreErrors((0, sbom_1.processSBOM)());
|
||||||
yield ignoreErrors(saveCache());
|
yield ignoreErrors(saveCache());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -98064,7 +98066,7 @@ else {
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.ERROR_HINT = exports.ERROR_REQUEST = exports.EVENT_NAME_PULL_REQUEST = exports.ENV_GITHUB_EVENT_NAME = exports.GDS_GRAALVM_PRODUCT_ID = exports.GDS_BASE = exports.MANDREL_NAMESPACE = exports.GRAALVM_RELEASES_REPO = exports.GRAALVM_PLATFORM = exports.GRAALVM_GH_USER = exports.GRAALVM_FILE_EXTENSION = exports.GRAALVM_ARCH = exports.JDK_HOME_SUFFIX = exports.JDK_PLATFORM = exports.JDK_ARCH = exports.VERSION_LATEST = exports.VERSION_DEV = exports.DISTRIBUTION_LIBERICA = exports.DISTRIBUTION_MANDREL = exports.DISTRIBUTION_GRAALVM_COMMUNITY = exports.DISTRIBUTION_GRAALVM = exports.EXECUTABLE_SUFFIX = exports.IS_WINDOWS = exports.IS_MACOS = exports.IS_LINUX = exports.INPUT_NI_MUSL = exports.INPUT_CHECK_FOR_UPDATES = exports.INPUT_CACHE = exports.INPUT_SET_JAVA_HOME = exports.INPUT_GITHUB_TOKEN = exports.INPUT_COMPONENTS = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_JAVA_VERSION = exports.INPUT_GDS_TOKEN = exports.INPUT_VERSION = exports.ACTION_VERSION = void 0;
|
exports.ERROR_HINT = exports.ERROR_REQUEST = exports.EVENT_NAME_PULL_REQUEST = exports.ENV_GITHUB_EVENT_NAME = exports.GDS_GRAALVM_PRODUCT_ID = exports.GDS_BASE = exports.MANDREL_NAMESPACE = exports.GRAALVM_RELEASES_REPO = exports.GRAALVM_PLATFORM = exports.GRAALVM_GH_USER = exports.GRAALVM_FILE_EXTENSION = exports.GRAALVM_ARCH = exports.JDK_HOME_SUFFIX = exports.JDK_PLATFORM = exports.JDK_ARCH = exports.VERSION_LATEST = exports.VERSION_DEV = exports.DISTRIBUTION_LIBERICA = exports.DISTRIBUTION_MANDREL = exports.DISTRIBUTION_GRAALVM_COMMUNITY = exports.DISTRIBUTION_GRAALVM = exports.EXECUTABLE_SUFFIX = exports.IS_WINDOWS = exports.IS_MACOS = exports.IS_LINUX = exports.NATIVE_IMAGE_OPTIONS_ENV = exports.INPUT_NI_MUSL = exports.INPUT_CHECK_FOR_UPDATES = exports.INPUT_CACHE = exports.INPUT_SET_JAVA_HOME = exports.INPUT_GITHUB_TOKEN = exports.INPUT_COMPONENTS = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_JAVA_VERSION = exports.INPUT_GDS_TOKEN = exports.INPUT_VERSION = exports.ACTION_VERSION = void 0;
|
||||||
exports.ACTION_VERSION = '1.2.7';
|
exports.ACTION_VERSION = '1.2.7';
|
||||||
exports.INPUT_VERSION = 'version';
|
exports.INPUT_VERSION = 'version';
|
||||||
exports.INPUT_GDS_TOKEN = 'gds-token';
|
exports.INPUT_GDS_TOKEN = 'gds-token';
|
||||||
@ -98077,6 +98079,7 @@ exports.INPUT_SET_JAVA_HOME = 'set-java-home';
|
|||||||
exports.INPUT_CACHE = 'cache';
|
exports.INPUT_CACHE = 'cache';
|
||||||
exports.INPUT_CHECK_FOR_UPDATES = 'check-for-updates';
|
exports.INPUT_CHECK_FOR_UPDATES = 'check-for-updates';
|
||||||
exports.INPUT_NI_MUSL = 'native-image-musl';
|
exports.INPUT_NI_MUSL = 'native-image-musl';
|
||||||
|
exports.NATIVE_IMAGE_OPTIONS_ENV = 'NATIVE_IMAGE_OPTIONS';
|
||||||
exports.IS_LINUX = process.platform === 'linux';
|
exports.IS_LINUX = process.platform === 'linux';
|
||||||
exports.IS_MACOS = process.platform === 'darwin';
|
exports.IS_MACOS = process.platform === 'darwin';
|
||||||
exports.IS_WINDOWS = process.platform === 'win32';
|
exports.IS_WINDOWS = process.platform === 'win32';
|
||||||
@ -98420,10 +98423,8 @@ const core = __importStar(__nccwpck_require__(2186));
|
|||||||
const fs = __importStar(__nccwpck_require__(7147));
|
const fs = __importStar(__nccwpck_require__(7147));
|
||||||
const github = __importStar(__nccwpck_require__(5438));
|
const github = __importStar(__nccwpck_require__(5438));
|
||||||
const semver = __importStar(__nccwpck_require__(1383));
|
const semver = __importStar(__nccwpck_require__(1383));
|
||||||
const path_1 = __nccwpck_require__(1017);
|
|
||||||
const os_1 = __nccwpck_require__(2037);
|
|
||||||
const utils_1 = __nccwpck_require__(1314);
|
const utils_1 = __nccwpck_require__(1314);
|
||||||
const BUILD_OUTPUT_JSON_PATH = (0, path_1.join)((0, os_1.tmpdir)(), 'native-image-build-output.json');
|
const BUILD_OUTPUT_JSON_PATH = (0, utils_1.tmpfile)('native-image-build-output.json');
|
||||||
const BYTES_TO_KiB = 1024;
|
const BYTES_TO_KiB = 1024;
|
||||||
const BYTES_TO_MiB = 1024 * 1024;
|
const BYTES_TO_MiB = 1024 * 1024;
|
||||||
const BYTES_TO_GiB = 1024 * 1024 * 1024;
|
const BYTES_TO_GiB = 1024 * 1024 * 1024;
|
||||||
@ -98431,9 +98432,6 @@ const DOCS_BASE = 'https://github.com/oracle/graal/blob/master/docs/reference-ma
|
|||||||
const INPUT_NI_JOB_REPORTS = 'native-image-job-reports';
|
const INPUT_NI_JOB_REPORTS = 'native-image-job-reports';
|
||||||
const INPUT_NI_PR_REPORTS = 'native-image-pr-reports';
|
const INPUT_NI_PR_REPORTS = 'native-image-pr-reports';
|
||||||
const INPUT_NI_PR_REPORTS_UPDATE = 'native-image-pr-reports-update-existing';
|
const INPUT_NI_PR_REPORTS_UPDATE = 'native-image-pr-reports-update-existing';
|
||||||
const NATIVE_IMAGE_CONFIG_FILE = (0, path_1.join)((0, os_1.tmpdir)(), 'native-image-options.properties');
|
|
||||||
const NATIVE_IMAGE_OPTIONS_ENV = 'NATIVE_IMAGE_OPTIONS';
|
|
||||||
const NATIVE_IMAGE_CONFIG_FILE_ENV = 'NATIVE_IMAGE_CONFIG_FILE';
|
|
||||||
const PR_COMMENT_TITLE = '## GraalVM Native Image Build Report';
|
const PR_COMMENT_TITLE = '## GraalVM Native Image Build Report';
|
||||||
function setUpNativeImageBuildReports(isGraalVMforJDK17OrLater, javaVersionOrDev, graalVMVersion) {
|
function setUpNativeImageBuildReports(isGraalVMforJDK17OrLater, javaVersionOrDev, graalVMVersion) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@ -98450,7 +98448,7 @@ function setUpNativeImageBuildReports(isGraalVMforJDK17OrLater, javaVersionOrDev
|
|||||||
core.warning(`Build reports for PRs and job summaries are only available in GraalVM 22.2.0 or later. This build job uses GraalVM ${graalVMVersion}.`);
|
core.warning(`Build reports for PRs and job summaries are only available in GraalVM 22.2.0 or later. This build job uses GraalVM ${graalVMVersion}.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setNativeImageOption(javaVersionOrDev, `-H:BuildOutputJSONFile=${BUILD_OUTPUT_JSON_PATH.replace(/\\/g, '\\\\')}`); // Escape backslashes for Windows
|
(0, utils_1.setNativeImageOption)(javaVersionOrDev, `-H:BuildOutputJSONFile=${BUILD_OUTPUT_JSON_PATH.replace(/\\/g, '\\\\')}`); // Escape backslashes for Windows
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.setUpNativeImageBuildReports = setUpNativeImageBuildReports;
|
exports.setUpNativeImageBuildReports = setUpNativeImageBuildReports;
|
||||||
@ -98492,38 +98490,6 @@ function arePRReportsEnabled() {
|
|||||||
function arePRReportsUpdateEnabled() {
|
function arePRReportsUpdateEnabled() {
|
||||||
return (0, utils_1.isPREvent)() && core.getInput(INPUT_NI_PR_REPORTS_UPDATE) === 'true';
|
return (0, utils_1.isPREvent)() && core.getInput(INPUT_NI_PR_REPORTS_UPDATE) === 'true';
|
||||||
}
|
}
|
||||||
function setNativeImageOption(javaVersionOrDev, optionValue) {
|
|
||||||
const coercedJavaVersionOrDev = semver.coerce(javaVersionOrDev);
|
|
||||||
if ((coercedJavaVersionOrDev &&
|
|
||||||
semver.gte(coercedJavaVersionOrDev, '22.0.0')) ||
|
|
||||||
javaVersionOrDev === c.VERSION_DEV ||
|
|
||||||
javaVersionOrDev.endsWith('-ea')) {
|
|
||||||
/* NATIVE_IMAGE_OPTIONS was introduced in GraalVM for JDK 22 (so were EA builds). */
|
|
||||||
let newOptionValue = optionValue;
|
|
||||||
const existingOptions = process.env[NATIVE_IMAGE_OPTIONS_ENV];
|
|
||||||
if (existingOptions) {
|
|
||||||
newOptionValue = `${existingOptions} ${newOptionValue}`;
|
|
||||||
}
|
|
||||||
core.exportVariable(NATIVE_IMAGE_OPTIONS_ENV, newOptionValue);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const optionsFile = getNativeImageOptionsFile();
|
|
||||||
if (fs.existsSync(optionsFile)) {
|
|
||||||
fs.appendFileSync(optionsFile, ` ${optionValue}`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fs.writeFileSync(optionsFile, `NativeImageArgs = ${optionValue}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function getNativeImageOptionsFile() {
|
|
||||||
let optionsFile = process.env[NATIVE_IMAGE_CONFIG_FILE_ENV];
|
|
||||||
if (optionsFile === undefined) {
|
|
||||||
optionsFile = NATIVE_IMAGE_CONFIG_FILE;
|
|
||||||
core.exportVariable(NATIVE_IMAGE_CONFIG_FILE_ENV, optionsFile);
|
|
||||||
}
|
|
||||||
return optionsFile;
|
|
||||||
}
|
|
||||||
function createReport(data) {
|
function createReport(data) {
|
||||||
const context = github.context;
|
const context = github.context;
|
||||||
const info = data.general_info;
|
const info = data.general_info;
|
||||||
@ -98751,6 +98717,239 @@ function secondsToHuman(seconds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 9181:
|
||||||
|
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
|
exports.processSBOM = exports.setUpSBOMSupport = void 0;
|
||||||
|
const c = __importStar(__nccwpck_require__(9042));
|
||||||
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
|
const fs = __importStar(__nccwpck_require__(7147));
|
||||||
|
const github = __importStar(__nccwpck_require__(5438));
|
||||||
|
const glob = __importStar(__nccwpck_require__(8090));
|
||||||
|
const path_1 = __nccwpck_require__(1017);
|
||||||
|
const semver = __importStar(__nccwpck_require__(1383));
|
||||||
|
const utils_1 = __nccwpck_require__(1314);
|
||||||
|
const INPUT_NI_SBOM = 'native-image-enable-sbom';
|
||||||
|
const SBOM_FILE_SUFFIX = '.sbom.json';
|
||||||
|
const MIN_JAVA_VERSION = '24.0.0';
|
||||||
|
let javaVersionOrLatestEA = null;
|
||||||
|
function setUpSBOMSupport(javaVersionOrDev, distribution) {
|
||||||
|
if (!isFeatureEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
validateJavaVersionAndDistribution(javaVersionOrDev, distribution);
|
||||||
|
javaVersionOrLatestEA = javaVersionOrDev;
|
||||||
|
(0, utils_1.setNativeImageOption)(javaVersionOrLatestEA, '--enable-sbom=export');
|
||||||
|
core.info('Enabled SBOM generation for Native Image build');
|
||||||
|
}
|
||||||
|
exports.setUpSBOMSupport = setUpSBOMSupport;
|
||||||
|
function validateJavaVersionAndDistribution(javaVersionOrDev, distribution) {
|
||||||
|
if (distribution !== c.DISTRIBUTION_GRAALVM) {
|
||||||
|
throw new Error(`The '${INPUT_NI_SBOM}' option is only supported for Oracle GraalVM (distribution '${c.DISTRIBUTION_GRAALVM}'), but found distribution '${distribution}'.`);
|
||||||
|
}
|
||||||
|
if (javaVersionOrDev === 'dev') {
|
||||||
|
throw new Error(`The '${INPUT_NI_SBOM}' option is not supported for java-version 'dev'.`);
|
||||||
|
}
|
||||||
|
if (javaVersionOrDev === 'latest-ea') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const coercedJavaVersion = semver.coerce(javaVersionOrDev);
|
||||||
|
if (!coercedJavaVersion || semver.gt(MIN_JAVA_VERSION, coercedJavaVersion)) {
|
||||||
|
throw new Error(`The '${INPUT_NI_SBOM}' option is only supported for GraalVM for JDK ${MIN_JAVA_VERSION} or later, but found java-version '${javaVersionOrDev}'.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function processSBOM() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (!isFeatureEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (javaVersionOrLatestEA === null) {
|
||||||
|
throw new Error('setUpSBOMSupport must be called before processSBOM');
|
||||||
|
}
|
||||||
|
const sbomPath = yield findSBOMFilePath();
|
||||||
|
try {
|
||||||
|
const sbomContent = fs.readFileSync(sbomPath, 'utf8');
|
||||||
|
const sbomData = parseSBOM(sbomContent);
|
||||||
|
const components = mapToComponentsWithDependencies(sbomData);
|
||||||
|
printSBOMContent(components);
|
||||||
|
const snapshot = convertSBOMToSnapshot(sbomPath, components);
|
||||||
|
yield submitDependencySnapshot(snapshot);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
throw new Error(`Failed to process and submit SBOM to the GitHub dependency submission API: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.processSBOM = processSBOM;
|
||||||
|
function isFeatureEnabled() {
|
||||||
|
return core.getInput(INPUT_NI_SBOM) === 'true';
|
||||||
|
}
|
||||||
|
function findSBOMFilePath() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const globber = yield glob.create(`**/*${SBOM_FILE_SUFFIX}`);
|
||||||
|
const sbomFiles = yield globber.glob();
|
||||||
|
if (sbomFiles.length === 0) {
|
||||||
|
throw new Error('No SBOM found. Make sure native-image build completed successfully.');
|
||||||
|
}
|
||||||
|
if (sbomFiles.length > 1) {
|
||||||
|
throw new Error(`Expected one SBOM but found multiple: ${sbomFiles.join(', ')}.`);
|
||||||
|
}
|
||||||
|
core.info(`Found SBOM: ${sbomFiles[0]}`);
|
||||||
|
return sbomFiles[0];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function parseSBOM(jsonString) {
|
||||||
|
try {
|
||||||
|
const sbomData = JSON.parse(jsonString);
|
||||||
|
return sbomData;
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
throw new Error(`Failed to parse SBOM JSON: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Maps the SBOM to a list of components with their dependencies
|
||||||
|
function mapToComponentsWithDependencies(sbom) {
|
||||||
|
if (!sbom || sbom.components.length === 0) {
|
||||||
|
throw new Error('Invalid SBOM data or no components found.');
|
||||||
|
}
|
||||||
|
return sbom.components.map((component) => {
|
||||||
|
var _a, _b;
|
||||||
|
const dependencies = ((_b = (_a = sbom.dependencies) === null || _a === void 0 ? void 0 : _a.find((dep) => dep.ref === component['bom-ref'])) === null || _b === void 0 ? void 0 : _b.dependsOn) || [];
|
||||||
|
return {
|
||||||
|
name: component.name,
|
||||||
|
version: component.version,
|
||||||
|
purl: component.purl,
|
||||||
|
dependencies,
|
||||||
|
'bom-ref': component['bom-ref']
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function printSBOMContent(components) {
|
||||||
|
core.info('=== SBOM Content ===');
|
||||||
|
for (const component of components) {
|
||||||
|
core.info(`- ${component['bom-ref']}`);
|
||||||
|
if (component.dependencies && component.dependencies.length > 0) {
|
||||||
|
core.info(` depends on: ${component.dependencies.join(', ')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core.info('==================');
|
||||||
|
}
|
||||||
|
function convertSBOMToSnapshot(sbomPath, components) {
|
||||||
|
const context = github.context;
|
||||||
|
const sbomFileName = (0, path_1.basename)(sbomPath);
|
||||||
|
if (!sbomFileName.endsWith(SBOM_FILE_SUFFIX)) {
|
||||||
|
throw new Error(`Invalid SBOM file name: ${sbomFileName}. Expected a file ending with ${SBOM_FILE_SUFFIX}.`);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
version: 0,
|
||||||
|
sha: context.sha,
|
||||||
|
ref: context.ref,
|
||||||
|
job: {
|
||||||
|
correlator: `${context.workflow}_${context.job}`,
|
||||||
|
id: context.runId.toString(),
|
||||||
|
html_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`
|
||||||
|
},
|
||||||
|
detector: {
|
||||||
|
name: 'Oracle GraalVM',
|
||||||
|
version: javaVersionOrLatestEA !== null && javaVersionOrLatestEA !== void 0 ? javaVersionOrLatestEA : '',
|
||||||
|
url: 'https://www.graalvm.org/'
|
||||||
|
},
|
||||||
|
scanned: new Date().toISOString(),
|
||||||
|
manifests: {
|
||||||
|
[sbomFileName]: {
|
||||||
|
name: sbomFileName,
|
||||||
|
resolved: mapComponentsToGithubAPIFormat(components),
|
||||||
|
metadata: {
|
||||||
|
generated_by: 'SBOM generated by GraalVM Native Image',
|
||||||
|
action_version: c.ACTION_VERSION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function mapComponentsToGithubAPIFormat(components) {
|
||||||
|
return Object.fromEntries(components
|
||||||
|
.filter(component => {
|
||||||
|
if (!component.purl) {
|
||||||
|
core.info(`Component ${component.name} does not have a valid package URL (purl). Skipping.`);
|
||||||
|
}
|
||||||
|
return component.purl;
|
||||||
|
})
|
||||||
|
.map(component => [
|
||||||
|
component.name,
|
||||||
|
{
|
||||||
|
package_url: component.purl,
|
||||||
|
dependencies: component.dependencies || []
|
||||||
|
}
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
function submitDependencySnapshot(snapshotData) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const token = core.getInput(c.INPUT_GITHUB_TOKEN, { required: true });
|
||||||
|
const octokit = github.getOctokit(token);
|
||||||
|
const context = github.context;
|
||||||
|
try {
|
||||||
|
yield octokit.request('POST /repos/{owner}/{repo}/dependency-graph/snapshots', {
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
version: snapshotData.version,
|
||||||
|
sha: snapshotData.sha,
|
||||||
|
ref: snapshotData.ref,
|
||||||
|
job: snapshotData.job,
|
||||||
|
detector: snapshotData.detector,
|
||||||
|
metadata: {},
|
||||||
|
scanned: snapshotData.scanned,
|
||||||
|
manifests: snapshotData.manifests,
|
||||||
|
headers: {
|
||||||
|
'X-GitHub-Api-Version': '2022-11-28'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
core.info('Dependency snapshot submitted successfully.');
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
throw new Error(`Failed to submit dependency snapshot for SBOM: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 1314:
|
/***/ 1314:
|
||||||
@ -98791,18 +98990,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.createPRComment = exports.updatePRComment = exports.findExistingPRCommentId = exports.isPREvent = exports.toSemVer = exports.calculateSHA256 = exports.downloadExtractAndCacheJDK = exports.downloadAndExtractJDK = exports.getMatchingTags = exports.getTaggedRelease = exports.getContents = exports.getLatestRelease = exports.exec = void 0;
|
exports.setNativeImageOption = exports.tmpfile = exports.createPRComment = exports.updatePRComment = exports.findExistingPRCommentId = exports.isPREvent = exports.toSemVer = exports.calculateSHA256 = exports.downloadExtractAndCacheJDK = exports.downloadAndExtractJDK = exports.getMatchingTags = exports.getTaggedRelease = exports.getContents = exports.getLatestRelease = exports.exec = void 0;
|
||||||
const c = __importStar(__nccwpck_require__(9042));
|
const c = __importStar(__nccwpck_require__(9042));
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const github = __importStar(__nccwpck_require__(5438));
|
const github = __importStar(__nccwpck_require__(5438));
|
||||||
const httpClient = __importStar(__nccwpck_require__(6255));
|
const httpClient = __importStar(__nccwpck_require__(6255));
|
||||||
const semver = __importStar(__nccwpck_require__(1383));
|
const semver = __importStar(__nccwpck_require__(1383));
|
||||||
const tc = __importStar(__nccwpck_require__(7784));
|
const tc = __importStar(__nccwpck_require__(7784));
|
||||||
|
const fs = __importStar(__nccwpck_require__(7147));
|
||||||
const exec_1 = __nccwpck_require__(1514);
|
const exec_1 = __nccwpck_require__(1514);
|
||||||
const fs_1 = __nccwpck_require__(7147);
|
const fs_1 = __nccwpck_require__(7147);
|
||||||
const core_1 = __nccwpck_require__(6762);
|
const core_1 = __nccwpck_require__(6762);
|
||||||
const crypto_1 = __nccwpck_require__(6113);
|
const crypto_1 = __nccwpck_require__(6113);
|
||||||
const path_1 = __nccwpck_require__(1017);
|
const path_1 = __nccwpck_require__(1017);
|
||||||
|
const os_1 = __nccwpck_require__(2037);
|
||||||
// Set up Octokit for github.com only and in the same way as @actions/github (see https://git.io/Jy9YP)
|
// Set up Octokit for github.com only and in the same way as @actions/github (see https://git.io/Jy9YP)
|
||||||
const baseUrl = 'https://api.github.com';
|
const baseUrl = 'https://api.github.com';
|
||||||
const GitHubDotCom = core_1.Octokit.defaults({
|
const GitHubDotCom = core_1.Octokit.defaults({
|
||||||
@ -98999,6 +99200,45 @@ function createPRComment(content) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.createPRComment = createPRComment;
|
exports.createPRComment = createPRComment;
|
||||||
|
function tmpfile(fileName) {
|
||||||
|
return (0, path_1.join)((0, os_1.tmpdir)(), fileName);
|
||||||
|
}
|
||||||
|
exports.tmpfile = tmpfile;
|
||||||
|
function setNativeImageOption(javaVersionOrDev, optionValue) {
|
||||||
|
const coercedJavaVersionOrDev = semver.coerce(javaVersionOrDev);
|
||||||
|
if ((coercedJavaVersionOrDev &&
|
||||||
|
semver.gte(coercedJavaVersionOrDev, '22.0.0')) ||
|
||||||
|
javaVersionOrDev === c.VERSION_DEV ||
|
||||||
|
javaVersionOrDev.endsWith('-ea')) {
|
||||||
|
/* NATIVE_IMAGE_OPTIONS was introduced in GraalVM for JDK 22 (so were EA builds). */
|
||||||
|
let newOptionValue = optionValue;
|
||||||
|
const existingOptions = process.env[c.NATIVE_IMAGE_OPTIONS_ENV];
|
||||||
|
if (existingOptions) {
|
||||||
|
newOptionValue = `${existingOptions} ${newOptionValue}`;
|
||||||
|
}
|
||||||
|
core.exportVariable(c.NATIVE_IMAGE_OPTIONS_ENV, newOptionValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const optionsFile = getNativeImageOptionsFile();
|
||||||
|
if (fs.existsSync(optionsFile)) {
|
||||||
|
fs.appendFileSync(optionsFile, ` ${optionValue}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fs.writeFileSync(optionsFile, `NativeImageArgs = ${optionValue}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.setNativeImageOption = setNativeImageOption;
|
||||||
|
const NATIVE_IMAGE_CONFIG_FILE = tmpfile('native-image-options.properties');
|
||||||
|
const NATIVE_IMAGE_CONFIG_FILE_ENV = 'NATIVE_IMAGE_CONFIG_FILE';
|
||||||
|
function getNativeImageOptionsFile() {
|
||||||
|
let optionsFile = process.env[NATIVE_IMAGE_CONFIG_FILE_ENV];
|
||||||
|
if (optionsFile === undefined) {
|
||||||
|
optionsFile = NATIVE_IMAGE_CONFIG_FILE;
|
||||||
|
core.exportVariable(NATIVE_IMAGE_CONFIG_FILE_ENV, optionsFile);
|
||||||
|
}
|
||||||
|
return optionsFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
322
dist/main/index.js
generated
vendored
322
dist/main/index.js
generated
vendored
@ -97949,7 +97949,7 @@ function wrappy (fn, cb) {
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.ERROR_HINT = exports.ERROR_REQUEST = exports.EVENT_NAME_PULL_REQUEST = exports.ENV_GITHUB_EVENT_NAME = exports.GDS_GRAALVM_PRODUCT_ID = exports.GDS_BASE = exports.MANDREL_NAMESPACE = exports.GRAALVM_RELEASES_REPO = exports.GRAALVM_PLATFORM = exports.GRAALVM_GH_USER = exports.GRAALVM_FILE_EXTENSION = exports.GRAALVM_ARCH = exports.JDK_HOME_SUFFIX = exports.JDK_PLATFORM = exports.JDK_ARCH = exports.VERSION_LATEST = exports.VERSION_DEV = exports.DISTRIBUTION_LIBERICA = exports.DISTRIBUTION_MANDREL = exports.DISTRIBUTION_GRAALVM_COMMUNITY = exports.DISTRIBUTION_GRAALVM = exports.EXECUTABLE_SUFFIX = exports.IS_WINDOWS = exports.IS_MACOS = exports.IS_LINUX = exports.INPUT_NI_MUSL = exports.INPUT_CHECK_FOR_UPDATES = exports.INPUT_CACHE = exports.INPUT_SET_JAVA_HOME = exports.INPUT_GITHUB_TOKEN = exports.INPUT_COMPONENTS = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_JAVA_VERSION = exports.INPUT_GDS_TOKEN = exports.INPUT_VERSION = exports.ACTION_VERSION = void 0;
|
exports.ERROR_HINT = exports.ERROR_REQUEST = exports.EVENT_NAME_PULL_REQUEST = exports.ENV_GITHUB_EVENT_NAME = exports.GDS_GRAALVM_PRODUCT_ID = exports.GDS_BASE = exports.MANDREL_NAMESPACE = exports.GRAALVM_RELEASES_REPO = exports.GRAALVM_PLATFORM = exports.GRAALVM_GH_USER = exports.GRAALVM_FILE_EXTENSION = exports.GRAALVM_ARCH = exports.JDK_HOME_SUFFIX = exports.JDK_PLATFORM = exports.JDK_ARCH = exports.VERSION_LATEST = exports.VERSION_DEV = exports.DISTRIBUTION_LIBERICA = exports.DISTRIBUTION_MANDREL = exports.DISTRIBUTION_GRAALVM_COMMUNITY = exports.DISTRIBUTION_GRAALVM = exports.EXECUTABLE_SUFFIX = exports.IS_WINDOWS = exports.IS_MACOS = exports.IS_LINUX = exports.NATIVE_IMAGE_OPTIONS_ENV = exports.INPUT_NI_MUSL = exports.INPUT_CHECK_FOR_UPDATES = exports.INPUT_CACHE = exports.INPUT_SET_JAVA_HOME = exports.INPUT_GITHUB_TOKEN = exports.INPUT_COMPONENTS = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_JAVA_VERSION = exports.INPUT_GDS_TOKEN = exports.INPUT_VERSION = exports.ACTION_VERSION = void 0;
|
||||||
exports.ACTION_VERSION = '1.2.7';
|
exports.ACTION_VERSION = '1.2.7';
|
||||||
exports.INPUT_VERSION = 'version';
|
exports.INPUT_VERSION = 'version';
|
||||||
exports.INPUT_GDS_TOKEN = 'gds-token';
|
exports.INPUT_GDS_TOKEN = 'gds-token';
|
||||||
@ -97962,6 +97962,7 @@ exports.INPUT_SET_JAVA_HOME = 'set-java-home';
|
|||||||
exports.INPUT_CACHE = 'cache';
|
exports.INPUT_CACHE = 'cache';
|
||||||
exports.INPUT_CHECK_FOR_UPDATES = 'check-for-updates';
|
exports.INPUT_CHECK_FOR_UPDATES = 'check-for-updates';
|
||||||
exports.INPUT_NI_MUSL = 'native-image-musl';
|
exports.INPUT_NI_MUSL = 'native-image-musl';
|
||||||
|
exports.NATIVE_IMAGE_OPTIONS_ENV = 'NATIVE_IMAGE_OPTIONS';
|
||||||
exports.IS_LINUX = process.platform === 'linux';
|
exports.IS_LINUX = process.platform === 'linux';
|
||||||
exports.IS_MACOS = process.platform === 'darwin';
|
exports.IS_MACOS = process.platform === 'darwin';
|
||||||
exports.IS_WINDOWS = process.platform === 'win32';
|
exports.IS_WINDOWS = process.platform === 'win32';
|
||||||
@ -98519,10 +98520,8 @@ const core = __importStar(__nccwpck_require__(42186));
|
|||||||
const fs = __importStar(__nccwpck_require__(57147));
|
const fs = __importStar(__nccwpck_require__(57147));
|
||||||
const github = __importStar(__nccwpck_require__(95438));
|
const github = __importStar(__nccwpck_require__(95438));
|
||||||
const semver = __importStar(__nccwpck_require__(11383));
|
const semver = __importStar(__nccwpck_require__(11383));
|
||||||
const path_1 = __nccwpck_require__(71017);
|
|
||||||
const os_1 = __nccwpck_require__(22037);
|
|
||||||
const utils_1 = __nccwpck_require__(71314);
|
const utils_1 = __nccwpck_require__(71314);
|
||||||
const BUILD_OUTPUT_JSON_PATH = (0, path_1.join)((0, os_1.tmpdir)(), 'native-image-build-output.json');
|
const BUILD_OUTPUT_JSON_PATH = (0, utils_1.tmpfile)('native-image-build-output.json');
|
||||||
const BYTES_TO_KiB = 1024;
|
const BYTES_TO_KiB = 1024;
|
||||||
const BYTES_TO_MiB = 1024 * 1024;
|
const BYTES_TO_MiB = 1024 * 1024;
|
||||||
const BYTES_TO_GiB = 1024 * 1024 * 1024;
|
const BYTES_TO_GiB = 1024 * 1024 * 1024;
|
||||||
@ -98530,9 +98529,6 @@ const DOCS_BASE = 'https://github.com/oracle/graal/blob/master/docs/reference-ma
|
|||||||
const INPUT_NI_JOB_REPORTS = 'native-image-job-reports';
|
const INPUT_NI_JOB_REPORTS = 'native-image-job-reports';
|
||||||
const INPUT_NI_PR_REPORTS = 'native-image-pr-reports';
|
const INPUT_NI_PR_REPORTS = 'native-image-pr-reports';
|
||||||
const INPUT_NI_PR_REPORTS_UPDATE = 'native-image-pr-reports-update-existing';
|
const INPUT_NI_PR_REPORTS_UPDATE = 'native-image-pr-reports-update-existing';
|
||||||
const NATIVE_IMAGE_CONFIG_FILE = (0, path_1.join)((0, os_1.tmpdir)(), 'native-image-options.properties');
|
|
||||||
const NATIVE_IMAGE_OPTIONS_ENV = 'NATIVE_IMAGE_OPTIONS';
|
|
||||||
const NATIVE_IMAGE_CONFIG_FILE_ENV = 'NATIVE_IMAGE_CONFIG_FILE';
|
|
||||||
const PR_COMMENT_TITLE = '## GraalVM Native Image Build Report';
|
const PR_COMMENT_TITLE = '## GraalVM Native Image Build Report';
|
||||||
function setUpNativeImageBuildReports(isGraalVMforJDK17OrLater, javaVersionOrDev, graalVMVersion) {
|
function setUpNativeImageBuildReports(isGraalVMforJDK17OrLater, javaVersionOrDev, graalVMVersion) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@ -98549,7 +98545,7 @@ function setUpNativeImageBuildReports(isGraalVMforJDK17OrLater, javaVersionOrDev
|
|||||||
core.warning(`Build reports for PRs and job summaries are only available in GraalVM 22.2.0 or later. This build job uses GraalVM ${graalVMVersion}.`);
|
core.warning(`Build reports for PRs and job summaries are only available in GraalVM 22.2.0 or later. This build job uses GraalVM ${graalVMVersion}.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setNativeImageOption(javaVersionOrDev, `-H:BuildOutputJSONFile=${BUILD_OUTPUT_JSON_PATH.replace(/\\/g, '\\\\')}`); // Escape backslashes for Windows
|
(0, utils_1.setNativeImageOption)(javaVersionOrDev, `-H:BuildOutputJSONFile=${BUILD_OUTPUT_JSON_PATH.replace(/\\/g, '\\\\')}`); // Escape backslashes for Windows
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.setUpNativeImageBuildReports = setUpNativeImageBuildReports;
|
exports.setUpNativeImageBuildReports = setUpNativeImageBuildReports;
|
||||||
@ -98591,38 +98587,6 @@ function arePRReportsEnabled() {
|
|||||||
function arePRReportsUpdateEnabled() {
|
function arePRReportsUpdateEnabled() {
|
||||||
return (0, utils_1.isPREvent)() && core.getInput(INPUT_NI_PR_REPORTS_UPDATE) === 'true';
|
return (0, utils_1.isPREvent)() && core.getInput(INPUT_NI_PR_REPORTS_UPDATE) === 'true';
|
||||||
}
|
}
|
||||||
function setNativeImageOption(javaVersionOrDev, optionValue) {
|
|
||||||
const coercedJavaVersionOrDev = semver.coerce(javaVersionOrDev);
|
|
||||||
if ((coercedJavaVersionOrDev &&
|
|
||||||
semver.gte(coercedJavaVersionOrDev, '22.0.0')) ||
|
|
||||||
javaVersionOrDev === c.VERSION_DEV ||
|
|
||||||
javaVersionOrDev.endsWith('-ea')) {
|
|
||||||
/* NATIVE_IMAGE_OPTIONS was introduced in GraalVM for JDK 22 (so were EA builds). */
|
|
||||||
let newOptionValue = optionValue;
|
|
||||||
const existingOptions = process.env[NATIVE_IMAGE_OPTIONS_ENV];
|
|
||||||
if (existingOptions) {
|
|
||||||
newOptionValue = `${existingOptions} ${newOptionValue}`;
|
|
||||||
}
|
|
||||||
core.exportVariable(NATIVE_IMAGE_OPTIONS_ENV, newOptionValue);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const optionsFile = getNativeImageOptionsFile();
|
|
||||||
if (fs.existsSync(optionsFile)) {
|
|
||||||
fs.appendFileSync(optionsFile, ` ${optionValue}`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fs.writeFileSync(optionsFile, `NativeImageArgs = ${optionValue}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function getNativeImageOptionsFile() {
|
|
||||||
let optionsFile = process.env[NATIVE_IMAGE_CONFIG_FILE_ENV];
|
|
||||||
if (optionsFile === undefined) {
|
|
||||||
optionsFile = NATIVE_IMAGE_CONFIG_FILE;
|
|
||||||
core.exportVariable(NATIVE_IMAGE_CONFIG_FILE_ENV, optionsFile);
|
|
||||||
}
|
|
||||||
return optionsFile;
|
|
||||||
}
|
|
||||||
function createReport(data) {
|
function createReport(data) {
|
||||||
const context = github.context;
|
const context = github.context;
|
||||||
const info = data.general_info;
|
const info = data.general_info;
|
||||||
@ -98850,6 +98814,239 @@ function secondsToHuman(seconds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 69181:
|
||||||
|
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
|
exports.processSBOM = exports.setUpSBOMSupport = void 0;
|
||||||
|
const c = __importStar(__nccwpck_require__(69042));
|
||||||
|
const core = __importStar(__nccwpck_require__(42186));
|
||||||
|
const fs = __importStar(__nccwpck_require__(57147));
|
||||||
|
const github = __importStar(__nccwpck_require__(95438));
|
||||||
|
const glob = __importStar(__nccwpck_require__(28090));
|
||||||
|
const path_1 = __nccwpck_require__(71017);
|
||||||
|
const semver = __importStar(__nccwpck_require__(11383));
|
||||||
|
const utils_1 = __nccwpck_require__(71314);
|
||||||
|
const INPUT_NI_SBOM = 'native-image-enable-sbom';
|
||||||
|
const SBOM_FILE_SUFFIX = '.sbom.json';
|
||||||
|
const MIN_JAVA_VERSION = '24.0.0';
|
||||||
|
let javaVersionOrLatestEA = null;
|
||||||
|
function setUpSBOMSupport(javaVersionOrDev, distribution) {
|
||||||
|
if (!isFeatureEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
validateJavaVersionAndDistribution(javaVersionOrDev, distribution);
|
||||||
|
javaVersionOrLatestEA = javaVersionOrDev;
|
||||||
|
(0, utils_1.setNativeImageOption)(javaVersionOrLatestEA, '--enable-sbom=export');
|
||||||
|
core.info('Enabled SBOM generation for Native Image build');
|
||||||
|
}
|
||||||
|
exports.setUpSBOMSupport = setUpSBOMSupport;
|
||||||
|
function validateJavaVersionAndDistribution(javaVersionOrDev, distribution) {
|
||||||
|
if (distribution !== c.DISTRIBUTION_GRAALVM) {
|
||||||
|
throw new Error(`The '${INPUT_NI_SBOM}' option is only supported for Oracle GraalVM (distribution '${c.DISTRIBUTION_GRAALVM}'), but found distribution '${distribution}'.`);
|
||||||
|
}
|
||||||
|
if (javaVersionOrDev === 'dev') {
|
||||||
|
throw new Error(`The '${INPUT_NI_SBOM}' option is not supported for java-version 'dev'.`);
|
||||||
|
}
|
||||||
|
if (javaVersionOrDev === 'latest-ea') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const coercedJavaVersion = semver.coerce(javaVersionOrDev);
|
||||||
|
if (!coercedJavaVersion || semver.gt(MIN_JAVA_VERSION, coercedJavaVersion)) {
|
||||||
|
throw new Error(`The '${INPUT_NI_SBOM}' option is only supported for GraalVM for JDK ${MIN_JAVA_VERSION} or later, but found java-version '${javaVersionOrDev}'.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function processSBOM() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (!isFeatureEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (javaVersionOrLatestEA === null) {
|
||||||
|
throw new Error('setUpSBOMSupport must be called before processSBOM');
|
||||||
|
}
|
||||||
|
const sbomPath = yield findSBOMFilePath();
|
||||||
|
try {
|
||||||
|
const sbomContent = fs.readFileSync(sbomPath, 'utf8');
|
||||||
|
const sbomData = parseSBOM(sbomContent);
|
||||||
|
const components = mapToComponentsWithDependencies(sbomData);
|
||||||
|
printSBOMContent(components);
|
||||||
|
const snapshot = convertSBOMToSnapshot(sbomPath, components);
|
||||||
|
yield submitDependencySnapshot(snapshot);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
throw new Error(`Failed to process and submit SBOM to the GitHub dependency submission API: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.processSBOM = processSBOM;
|
||||||
|
function isFeatureEnabled() {
|
||||||
|
return core.getInput(INPUT_NI_SBOM) === 'true';
|
||||||
|
}
|
||||||
|
function findSBOMFilePath() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const globber = yield glob.create(`**/*${SBOM_FILE_SUFFIX}`);
|
||||||
|
const sbomFiles = yield globber.glob();
|
||||||
|
if (sbomFiles.length === 0) {
|
||||||
|
throw new Error('No SBOM found. Make sure native-image build completed successfully.');
|
||||||
|
}
|
||||||
|
if (sbomFiles.length > 1) {
|
||||||
|
throw new Error(`Expected one SBOM but found multiple: ${sbomFiles.join(', ')}.`);
|
||||||
|
}
|
||||||
|
core.info(`Found SBOM: ${sbomFiles[0]}`);
|
||||||
|
return sbomFiles[0];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function parseSBOM(jsonString) {
|
||||||
|
try {
|
||||||
|
const sbomData = JSON.parse(jsonString);
|
||||||
|
return sbomData;
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
throw new Error(`Failed to parse SBOM JSON: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Maps the SBOM to a list of components with their dependencies
|
||||||
|
function mapToComponentsWithDependencies(sbom) {
|
||||||
|
if (!sbom || sbom.components.length === 0) {
|
||||||
|
throw new Error('Invalid SBOM data or no components found.');
|
||||||
|
}
|
||||||
|
return sbom.components.map((component) => {
|
||||||
|
var _a, _b;
|
||||||
|
const dependencies = ((_b = (_a = sbom.dependencies) === null || _a === void 0 ? void 0 : _a.find((dep) => dep.ref === component['bom-ref'])) === null || _b === void 0 ? void 0 : _b.dependsOn) || [];
|
||||||
|
return {
|
||||||
|
name: component.name,
|
||||||
|
version: component.version,
|
||||||
|
purl: component.purl,
|
||||||
|
dependencies,
|
||||||
|
'bom-ref': component['bom-ref']
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function printSBOMContent(components) {
|
||||||
|
core.info('=== SBOM Content ===');
|
||||||
|
for (const component of components) {
|
||||||
|
core.info(`- ${component['bom-ref']}`);
|
||||||
|
if (component.dependencies && component.dependencies.length > 0) {
|
||||||
|
core.info(` depends on: ${component.dependencies.join(', ')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core.info('==================');
|
||||||
|
}
|
||||||
|
function convertSBOMToSnapshot(sbomPath, components) {
|
||||||
|
const context = github.context;
|
||||||
|
const sbomFileName = (0, path_1.basename)(sbomPath);
|
||||||
|
if (!sbomFileName.endsWith(SBOM_FILE_SUFFIX)) {
|
||||||
|
throw new Error(`Invalid SBOM file name: ${sbomFileName}. Expected a file ending with ${SBOM_FILE_SUFFIX}.`);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
version: 0,
|
||||||
|
sha: context.sha,
|
||||||
|
ref: context.ref,
|
||||||
|
job: {
|
||||||
|
correlator: `${context.workflow}_${context.job}`,
|
||||||
|
id: context.runId.toString(),
|
||||||
|
html_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`
|
||||||
|
},
|
||||||
|
detector: {
|
||||||
|
name: 'Oracle GraalVM',
|
||||||
|
version: javaVersionOrLatestEA !== null && javaVersionOrLatestEA !== void 0 ? javaVersionOrLatestEA : '',
|
||||||
|
url: 'https://www.graalvm.org/'
|
||||||
|
},
|
||||||
|
scanned: new Date().toISOString(),
|
||||||
|
manifests: {
|
||||||
|
[sbomFileName]: {
|
||||||
|
name: sbomFileName,
|
||||||
|
resolved: mapComponentsToGithubAPIFormat(components),
|
||||||
|
metadata: {
|
||||||
|
generated_by: 'SBOM generated by GraalVM Native Image',
|
||||||
|
action_version: c.ACTION_VERSION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function mapComponentsToGithubAPIFormat(components) {
|
||||||
|
return Object.fromEntries(components
|
||||||
|
.filter(component => {
|
||||||
|
if (!component.purl) {
|
||||||
|
core.info(`Component ${component.name} does not have a valid package URL (purl). Skipping.`);
|
||||||
|
}
|
||||||
|
return component.purl;
|
||||||
|
})
|
||||||
|
.map(component => [
|
||||||
|
component.name,
|
||||||
|
{
|
||||||
|
package_url: component.purl,
|
||||||
|
dependencies: component.dependencies || []
|
||||||
|
}
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
function submitDependencySnapshot(snapshotData) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const token = core.getInput(c.INPUT_GITHUB_TOKEN, { required: true });
|
||||||
|
const octokit = github.getOctokit(token);
|
||||||
|
const context = github.context;
|
||||||
|
try {
|
||||||
|
yield octokit.request('POST /repos/{owner}/{repo}/dependency-graph/snapshots', {
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
version: snapshotData.version,
|
||||||
|
sha: snapshotData.sha,
|
||||||
|
ref: snapshotData.ref,
|
||||||
|
job: snapshotData.job,
|
||||||
|
detector: snapshotData.detector,
|
||||||
|
metadata: {},
|
||||||
|
scanned: snapshotData.scanned,
|
||||||
|
manifests: snapshotData.manifests,
|
||||||
|
headers: {
|
||||||
|
'X-GitHub-Api-Version': '2022-11-28'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
core.info('Dependency snapshot submitted successfully.');
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
throw new Error(`Failed to submit dependency snapshot for SBOM: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 19543:
|
/***/ 19543:
|
||||||
@ -99684,6 +99881,7 @@ const musl_1 = __nccwpck_require__(10316);
|
|||||||
const msvc_1 = __nccwpck_require__(31165);
|
const msvc_1 = __nccwpck_require__(31165);
|
||||||
const reports_1 = __nccwpck_require__(92046);
|
const reports_1 = __nccwpck_require__(92046);
|
||||||
const exec_1 = __nccwpck_require__(71514);
|
const exec_1 = __nccwpck_require__(71514);
|
||||||
|
const sbom_1 = __nccwpck_require__(69181);
|
||||||
function run() {
|
function run() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
@ -99795,6 +99993,7 @@ function run() {
|
|||||||
yield (0, cache_2.restore)(cache);
|
yield (0, cache_2.restore)(cache);
|
||||||
}
|
}
|
||||||
(0, reports_1.setUpNativeImageBuildReports)(isGraalVMforJDK17OrLater, javaVersion, graalVMVersion);
|
(0, reports_1.setUpNativeImageBuildReports)(isGraalVMforJDK17OrLater, javaVersion, graalVMVersion);
|
||||||
|
(0, sbom_1.setUpSBOMSupport)(javaVersion, distribution);
|
||||||
core.startGroup(`Successfully set up '${(0, path_1.basename)(graalVMHome)}'`);
|
core.startGroup(`Successfully set up '${(0, path_1.basename)(graalVMHome)}'`);
|
||||||
yield (0, exec_1.exec)((0, path_1.join)(graalVMHome, 'bin', `java${c.EXECUTABLE_SUFFIX}`), [
|
yield (0, exec_1.exec)((0, path_1.join)(graalVMHome, 'bin', `java${c.EXECUTABLE_SUFFIX}`), [
|
||||||
javaVersion.startsWith('8') ? '-version' : '--version'
|
javaVersion.startsWith('8') ? '-version' : '--version'
|
||||||
@ -100117,18 +100316,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.createPRComment = exports.updatePRComment = exports.findExistingPRCommentId = exports.isPREvent = exports.toSemVer = exports.calculateSHA256 = exports.downloadExtractAndCacheJDK = exports.downloadAndExtractJDK = exports.getMatchingTags = exports.getTaggedRelease = exports.getContents = exports.getLatestRelease = exports.exec = void 0;
|
exports.setNativeImageOption = exports.tmpfile = exports.createPRComment = exports.updatePRComment = exports.findExistingPRCommentId = exports.isPREvent = exports.toSemVer = exports.calculateSHA256 = exports.downloadExtractAndCacheJDK = exports.downloadAndExtractJDK = exports.getMatchingTags = exports.getTaggedRelease = exports.getContents = exports.getLatestRelease = exports.exec = void 0;
|
||||||
const c = __importStar(__nccwpck_require__(69042));
|
const c = __importStar(__nccwpck_require__(69042));
|
||||||
const core = __importStar(__nccwpck_require__(42186));
|
const core = __importStar(__nccwpck_require__(42186));
|
||||||
const github = __importStar(__nccwpck_require__(95438));
|
const github = __importStar(__nccwpck_require__(95438));
|
||||||
const httpClient = __importStar(__nccwpck_require__(96255));
|
const httpClient = __importStar(__nccwpck_require__(96255));
|
||||||
const semver = __importStar(__nccwpck_require__(11383));
|
const semver = __importStar(__nccwpck_require__(11383));
|
||||||
const tc = __importStar(__nccwpck_require__(27784));
|
const tc = __importStar(__nccwpck_require__(27784));
|
||||||
|
const fs = __importStar(__nccwpck_require__(57147));
|
||||||
const exec_1 = __nccwpck_require__(71514);
|
const exec_1 = __nccwpck_require__(71514);
|
||||||
const fs_1 = __nccwpck_require__(57147);
|
const fs_1 = __nccwpck_require__(57147);
|
||||||
const core_1 = __nccwpck_require__(76762);
|
const core_1 = __nccwpck_require__(76762);
|
||||||
const crypto_1 = __nccwpck_require__(6113);
|
const crypto_1 = __nccwpck_require__(6113);
|
||||||
const path_1 = __nccwpck_require__(71017);
|
const path_1 = __nccwpck_require__(71017);
|
||||||
|
const os_1 = __nccwpck_require__(22037);
|
||||||
// Set up Octokit for github.com only and in the same way as @actions/github (see https://git.io/Jy9YP)
|
// Set up Octokit for github.com only and in the same way as @actions/github (see https://git.io/Jy9YP)
|
||||||
const baseUrl = 'https://api.github.com';
|
const baseUrl = 'https://api.github.com';
|
||||||
const GitHubDotCom = core_1.Octokit.defaults({
|
const GitHubDotCom = core_1.Octokit.defaults({
|
||||||
@ -100325,6 +100526,45 @@ function createPRComment(content) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.createPRComment = createPRComment;
|
exports.createPRComment = createPRComment;
|
||||||
|
function tmpfile(fileName) {
|
||||||
|
return (0, path_1.join)((0, os_1.tmpdir)(), fileName);
|
||||||
|
}
|
||||||
|
exports.tmpfile = tmpfile;
|
||||||
|
function setNativeImageOption(javaVersionOrDev, optionValue) {
|
||||||
|
const coercedJavaVersionOrDev = semver.coerce(javaVersionOrDev);
|
||||||
|
if ((coercedJavaVersionOrDev &&
|
||||||
|
semver.gte(coercedJavaVersionOrDev, '22.0.0')) ||
|
||||||
|
javaVersionOrDev === c.VERSION_DEV ||
|
||||||
|
javaVersionOrDev.endsWith('-ea')) {
|
||||||
|
/* NATIVE_IMAGE_OPTIONS was introduced in GraalVM for JDK 22 (so were EA builds). */
|
||||||
|
let newOptionValue = optionValue;
|
||||||
|
const existingOptions = process.env[c.NATIVE_IMAGE_OPTIONS_ENV];
|
||||||
|
if (existingOptions) {
|
||||||
|
newOptionValue = `${existingOptions} ${newOptionValue}`;
|
||||||
|
}
|
||||||
|
core.exportVariable(c.NATIVE_IMAGE_OPTIONS_ENV, newOptionValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const optionsFile = getNativeImageOptionsFile();
|
||||||
|
if (fs.existsSync(optionsFile)) {
|
||||||
|
fs.appendFileSync(optionsFile, ` ${optionValue}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fs.writeFileSync(optionsFile, `NativeImageArgs = ${optionValue}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.setNativeImageOption = setNativeImageOption;
|
||||||
|
const NATIVE_IMAGE_CONFIG_FILE = tmpfile('native-image-options.properties');
|
||||||
|
const NATIVE_IMAGE_CONFIG_FILE_ENV = 'NATIVE_IMAGE_CONFIG_FILE';
|
||||||
|
function getNativeImageOptionsFile() {
|
||||||
|
let optionsFile = process.env[NATIVE_IMAGE_CONFIG_FILE_ENV];
|
||||||
|
if (optionsFile === undefined) {
|
||||||
|
optionsFile = NATIVE_IMAGE_CONFIG_FILE;
|
||||||
|
core.exportVariable(NATIVE_IMAGE_CONFIG_FILE_ENV, optionsFile);
|
||||||
|
}
|
||||||
|
return optionsFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
36
package-lock.json
generated
36
package-lock.json
generated
@ -19,6 +19,7 @@
|
|||||||
"@actions/tool-cache": "^2.0.2",
|
"@actions/tool-cache": "^2.0.2",
|
||||||
"@octokit/core": "^5.2.0",
|
"@octokit/core": "^5.2.0",
|
||||||
"@octokit/types": "^12.6.0",
|
"@octokit/types": "^12.6.0",
|
||||||
|
"@github/dependency-submission-toolkit": "^2.0.4",
|
||||||
"semver": "^7.6.3",
|
"semver": "^7.6.3",
|
||||||
"uuid": "^11.0.5"
|
"uuid": "^11.0.5"
|
||||||
},
|
},
|
||||||
@ -1111,6 +1112,22 @@
|
|||||||
"integrity": "sha512-gIhjdJp/c2beaIWWIlsXdqXVRUz3r2BxBCpfz/F3JXHvSAQ1paMYjLH+maEATtENg+k5eLV7gA+9yPp762ieuw==",
|
"integrity": "sha512-gIhjdJp/c2beaIWWIlsXdqXVRUz3r2BxBCpfz/F3JXHvSAQ1paMYjLH+maEATtENg+k5eLV7gA+9yPp762ieuw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@github/dependency-submission-toolkit": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@github/dependency-submission-toolkit/-/dependency-submission-toolkit-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-uQia1YSLTrVmy+f6XpAzy/MEFDvjMg/VOm9pdROxVKQA5SvLXDvXeGgxLwy9fH+sXHqtDWRnVOI1+UAcQ4pi/w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"workspaces": [
|
||||||
|
"example"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": "^1.10.1",
|
||||||
|
"@actions/github": "^6.0.0",
|
||||||
|
"@octokit/request-error": "^5.0.1",
|
||||||
|
"@octokit/webhooks-types": "^7.3.1",
|
||||||
|
"packageurl-js": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.11.14",
|
"version": "0.11.14",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||||
@ -1796,6 +1813,12 @@
|
|||||||
"@octokit/openapi-types": "^20.0.0"
|
"@octokit/openapi-types": "^20.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@octokit/webhooks-types": {
|
||||||
|
"version": "7.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-7.6.1.tgz",
|
||||||
|
"integrity": "sha512-S8u2cJzklBC0FgTwWVLaM8tMrDuDMVE4xiTK4EYXM9GntyvrdbSoxqDQa+Fh57CCNApyIpyeqPhhFEmHPfrXgw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@opentelemetry/api": {
|
"node_modules/@opentelemetry/api": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz",
|
||||||
@ -6648,6 +6671,12 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/packageurl-js": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/packageurl-js/-/packageurl-js-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-cZ6/MzuXaoFd16/k0WnwtI298UCaDHe/XlSh85SeOKbGZ1hq0xvNbx3ILyCMyk7uFQxl6scF3Aucj6/EO9NwcA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
@ -7998,10 +8027,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.4.2",
|
"version": "5.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
|
||||||
"integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==",
|
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
"@actions/tool-cache": "^2.0.2",
|
"@actions/tool-cache": "^2.0.2",
|
||||||
"@octokit/core": "^5.2.0",
|
"@octokit/core": "^5.2.0",
|
||||||
"@octokit/types": "^12.6.0",
|
"@octokit/types": "^12.6.0",
|
||||||
|
"@github/dependency-submission-toolkit": "^2.0.4",
|
||||||
"semver": "^7.6.3",
|
"semver": "^7.6.3",
|
||||||
"uuid": "^11.0.5"
|
"uuid": "^11.0.5"
|
||||||
},
|
},
|
||||||
|
@ -28,6 +28,7 @@ import * as core from '@actions/core'
|
|||||||
import * as constants from './constants'
|
import * as constants from './constants'
|
||||||
import {save} from './features/cache'
|
import {save} from './features/cache'
|
||||||
import {generateReports} from './features/reports'
|
import {generateReports} from './features/reports'
|
||||||
|
import {processSBOM} from './features/sbom'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check given input and run a save process for the specified package manager
|
* Check given input and run a save process for the specified package manager
|
||||||
@ -58,6 +59,7 @@ async function ignoreErrors(promise: Promise<void>): Promise<unknown> {
|
|||||||
|
|
||||||
export async function run(): Promise<void> {
|
export async function run(): Promise<void> {
|
||||||
await ignoreErrors(generateReports())
|
await ignoreErrors(generateReports())
|
||||||
|
await ignoreErrors(processSBOM())
|
||||||
await ignoreErrors(saveCache())
|
await ignoreErrors(saveCache())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ export const INPUT_CACHE = 'cache'
|
|||||||
export const INPUT_CHECK_FOR_UPDATES = 'check-for-updates'
|
export const INPUT_CHECK_FOR_UPDATES = 'check-for-updates'
|
||||||
export const INPUT_NI_MUSL = 'native-image-musl'
|
export const INPUT_NI_MUSL = 'native-image-musl'
|
||||||
|
|
||||||
|
export const NATIVE_IMAGE_OPTIONS_ENV = 'NATIVE_IMAGE_OPTIONS'
|
||||||
|
|
||||||
export const IS_LINUX = process.platform === 'linux'
|
export const IS_LINUX = process.platform === 'linux'
|
||||||
export const IS_MACOS = process.platform === 'darwin'
|
export const IS_MACOS = process.platform === 'darwin'
|
||||||
export const IS_WINDOWS = process.platform === 'win32'
|
export const IS_WINDOWS = process.platform === 'win32'
|
||||||
|
@ -3,17 +3,17 @@ import * as core from '@actions/core'
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as github from '@actions/github'
|
import * as github from '@actions/github'
|
||||||
import * as semver from 'semver'
|
import * as semver from 'semver'
|
||||||
import {join} from 'path'
|
|
||||||
import {tmpdir} from 'os'
|
|
||||||
import {
|
import {
|
||||||
createPRComment,
|
createPRComment,
|
||||||
findExistingPRCommentId,
|
findExistingPRCommentId,
|
||||||
isPREvent,
|
isPREvent,
|
||||||
toSemVer,
|
toSemVer,
|
||||||
updatePRComment
|
updatePRComment,
|
||||||
|
tmpfile,
|
||||||
|
setNativeImageOption
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
|
|
||||||
const BUILD_OUTPUT_JSON_PATH = join(tmpdir(), 'native-image-build-output.json')
|
const BUILD_OUTPUT_JSON_PATH = tmpfile('native-image-build-output.json')
|
||||||
const BYTES_TO_KiB = 1024
|
const BYTES_TO_KiB = 1024
|
||||||
const BYTES_TO_MiB = 1024 * 1024
|
const BYTES_TO_MiB = 1024 * 1024
|
||||||
const BYTES_TO_GiB = 1024 * 1024 * 1024
|
const BYTES_TO_GiB = 1024 * 1024 * 1024
|
||||||
@ -22,12 +22,6 @@ const DOCS_BASE =
|
|||||||
const INPUT_NI_JOB_REPORTS = 'native-image-job-reports'
|
const INPUT_NI_JOB_REPORTS = 'native-image-job-reports'
|
||||||
const INPUT_NI_PR_REPORTS = 'native-image-pr-reports'
|
const INPUT_NI_PR_REPORTS = 'native-image-pr-reports'
|
||||||
const INPUT_NI_PR_REPORTS_UPDATE = 'native-image-pr-reports-update-existing'
|
const INPUT_NI_PR_REPORTS_UPDATE = 'native-image-pr-reports-update-existing'
|
||||||
const NATIVE_IMAGE_CONFIG_FILE = join(
|
|
||||||
tmpdir(),
|
|
||||||
'native-image-options.properties'
|
|
||||||
)
|
|
||||||
const NATIVE_IMAGE_OPTIONS_ENV = 'NATIVE_IMAGE_OPTIONS'
|
|
||||||
const NATIVE_IMAGE_CONFIG_FILE_ENV = 'NATIVE_IMAGE_CONFIG_FILE'
|
|
||||||
const PR_COMMENT_TITLE = '## GraalVM Native Image Build Report'
|
const PR_COMMENT_TITLE = '## GraalVM Native Image Build Report'
|
||||||
|
|
||||||
interface AnalysisResult {
|
interface AnalysisResult {
|
||||||
@ -169,43 +163,6 @@ function arePRReportsUpdateEnabled(): boolean {
|
|||||||
return isPREvent() && core.getInput(INPUT_NI_PR_REPORTS_UPDATE) === 'true'
|
return isPREvent() && core.getInput(INPUT_NI_PR_REPORTS_UPDATE) === 'true'
|
||||||
}
|
}
|
||||||
|
|
||||||
function setNativeImageOption(
|
|
||||||
javaVersionOrDev: string,
|
|
||||||
optionValue: string
|
|
||||||
): void {
|
|
||||||
const coercedJavaVersionOrDev = semver.coerce(javaVersionOrDev)
|
|
||||||
if (
|
|
||||||
(coercedJavaVersionOrDev &&
|
|
||||||
semver.gte(coercedJavaVersionOrDev, '22.0.0')) ||
|
|
||||||
javaVersionOrDev === c.VERSION_DEV ||
|
|
||||||
javaVersionOrDev.endsWith('-ea')
|
|
||||||
) {
|
|
||||||
/* NATIVE_IMAGE_OPTIONS was introduced in GraalVM for JDK 22 (so were EA builds). */
|
|
||||||
let newOptionValue = optionValue
|
|
||||||
const existingOptions = process.env[NATIVE_IMAGE_OPTIONS_ENV]
|
|
||||||
if (existingOptions) {
|
|
||||||
newOptionValue = `${existingOptions} ${newOptionValue}`
|
|
||||||
}
|
|
||||||
core.exportVariable(NATIVE_IMAGE_OPTIONS_ENV, newOptionValue)
|
|
||||||
} else {
|
|
||||||
const optionsFile = getNativeImageOptionsFile()
|
|
||||||
if (fs.existsSync(optionsFile)) {
|
|
||||||
fs.appendFileSync(optionsFile, ` ${optionValue}`)
|
|
||||||
} else {
|
|
||||||
fs.writeFileSync(optionsFile, `NativeImageArgs = ${optionValue}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNativeImageOptionsFile(): string {
|
|
||||||
let optionsFile = process.env[NATIVE_IMAGE_CONFIG_FILE_ENV]
|
|
||||||
if (optionsFile === undefined) {
|
|
||||||
optionsFile = NATIVE_IMAGE_CONFIG_FILE
|
|
||||||
core.exportVariable(NATIVE_IMAGE_CONFIG_FILE_ENV, optionsFile)
|
|
||||||
}
|
|
||||||
return optionsFile
|
|
||||||
}
|
|
||||||
|
|
||||||
function createReport(data: BuildOutput): string {
|
function createReport(data: BuildOutput): string {
|
||||||
const context = github.context
|
const context = github.context
|
||||||
const info = data.general_info
|
const info = data.general_info
|
||||||
|
300
src/features/sbom.ts
Normal file
300
src/features/sbom.ts
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
import * as c from '../constants'
|
||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as fs from 'fs'
|
||||||
|
import * as github from '@actions/github'
|
||||||
|
import * as glob from '@actions/glob'
|
||||||
|
import {basename} from 'path'
|
||||||
|
import * as semver from 'semver'
|
||||||
|
import {setNativeImageOption} from '../utils'
|
||||||
|
|
||||||
|
const INPUT_NI_SBOM = 'native-image-enable-sbom'
|
||||||
|
const SBOM_FILE_SUFFIX = '.sbom.json'
|
||||||
|
const MIN_JAVA_VERSION = '24.0.0'
|
||||||
|
|
||||||
|
let javaVersionOrLatestEA: string | null = null
|
||||||
|
|
||||||
|
interface SBOM {
|
||||||
|
components: Component[]
|
||||||
|
dependencies: Dependency[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Component {
|
||||||
|
name: string
|
||||||
|
version?: string
|
||||||
|
purl?: string
|
||||||
|
dependencies?: string[]
|
||||||
|
'bom-ref': string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dependency {
|
||||||
|
ref: string
|
||||||
|
dependsOn: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DependencySnapshot {
|
||||||
|
version: number
|
||||||
|
sha: string
|
||||||
|
ref: string
|
||||||
|
job: {
|
||||||
|
correlator: string
|
||||||
|
id: string
|
||||||
|
html_url?: string
|
||||||
|
}
|
||||||
|
detector: {
|
||||||
|
name: string
|
||||||
|
version: string
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
scanned: string
|
||||||
|
manifests: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
name: string
|
||||||
|
metadata?: Record<string, string>
|
||||||
|
// Not including the 'file' property because we cannot specify any reasonable value for 'source_location'
|
||||||
|
// since the SBOM will not necessarily be saved in the repository of the user.
|
||||||
|
// GitHub docs: https://docs.github.com/en/rest/dependency-graph/dependency-submission?apiVersion=2022-11-28#create-a-snapshot-of-dependencies-for-a-repository
|
||||||
|
resolved: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
package_url: string
|
||||||
|
relationship?: 'direct'
|
||||||
|
scope?: 'runtime'
|
||||||
|
dependencies?: string[]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setUpSBOMSupport(
|
||||||
|
javaVersionOrDev: string,
|
||||||
|
distribution: string
|
||||||
|
): void {
|
||||||
|
if (!isFeatureEnabled()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
validateJavaVersionAndDistribution(javaVersionOrDev, distribution)
|
||||||
|
javaVersionOrLatestEA = javaVersionOrDev
|
||||||
|
setNativeImageOption(javaVersionOrLatestEA, '--enable-sbom=export')
|
||||||
|
core.info('Enabled SBOM generation for Native Image build')
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateJavaVersionAndDistribution(
|
||||||
|
javaVersionOrDev: string,
|
||||||
|
distribution: string
|
||||||
|
): void {
|
||||||
|
if (distribution !== c.DISTRIBUTION_GRAALVM) {
|
||||||
|
throw new Error(
|
||||||
|
`The '${INPUT_NI_SBOM}' option is only supported for Oracle GraalVM (distribution '${c.DISTRIBUTION_GRAALVM}'), but found distribution '${distribution}'.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (javaVersionOrDev === 'dev') {
|
||||||
|
throw new Error(
|
||||||
|
`The '${INPUT_NI_SBOM}' option is not supported for java-version 'dev'.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (javaVersionOrDev === 'latest-ea') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const coercedJavaVersion = semver.coerce(javaVersionOrDev)
|
||||||
|
if (!coercedJavaVersion || semver.gt(MIN_JAVA_VERSION, coercedJavaVersion)) {
|
||||||
|
throw new Error(
|
||||||
|
`The '${INPUT_NI_SBOM}' option is only supported for GraalVM for JDK ${MIN_JAVA_VERSION} or later, but found java-version '${javaVersionOrDev}'.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function processSBOM(): Promise<void> {
|
||||||
|
if (!isFeatureEnabled()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (javaVersionOrLatestEA === null) {
|
||||||
|
throw new Error('setUpSBOMSupport must be called before processSBOM')
|
||||||
|
}
|
||||||
|
|
||||||
|
const sbomPath = await findSBOMFilePath()
|
||||||
|
try {
|
||||||
|
const sbomContent = fs.readFileSync(sbomPath, 'utf8')
|
||||||
|
const sbomData = parseSBOM(sbomContent)
|
||||||
|
const components = mapToComponentsWithDependencies(sbomData)
|
||||||
|
printSBOMContent(components)
|
||||||
|
const snapshot = convertSBOMToSnapshot(sbomPath, components)
|
||||||
|
await submitDependencySnapshot(snapshot)
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to process and submit SBOM to the GitHub dependency submission API: ${error instanceof Error ? error.message : String(error)}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFeatureEnabled(): boolean {
|
||||||
|
return core.getInput(INPUT_NI_SBOM) === 'true'
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findSBOMFilePath(): Promise<string> {
|
||||||
|
const globber = await glob.create(`**/*${SBOM_FILE_SUFFIX}`)
|
||||||
|
const sbomFiles = await globber.glob()
|
||||||
|
|
||||||
|
if (sbomFiles.length === 0) {
|
||||||
|
throw new Error(
|
||||||
|
'No SBOM found. Make sure native-image build completed successfully.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sbomFiles.length > 1) {
|
||||||
|
throw new Error(
|
||||||
|
`Expected one SBOM but found multiple: ${sbomFiles.join(', ')}.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info(`Found SBOM: ${sbomFiles[0]}`)
|
||||||
|
return sbomFiles[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseSBOM(jsonString: string): SBOM {
|
||||||
|
try {
|
||||||
|
const sbomData: SBOM = JSON.parse(jsonString)
|
||||||
|
return sbomData
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to parse SBOM JSON: ${error instanceof Error ? error.message : String(error)}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maps the SBOM to a list of components with their dependencies
|
||||||
|
function mapToComponentsWithDependencies(sbom: SBOM): Component[] {
|
||||||
|
if (!sbom || sbom.components.length === 0) {
|
||||||
|
throw new Error('Invalid SBOM data or no components found.')
|
||||||
|
}
|
||||||
|
|
||||||
|
return sbom.components.map((component: Component) => {
|
||||||
|
const dependencies =
|
||||||
|
sbom.dependencies?.find(
|
||||||
|
(dep: Dependency) => dep.ref === component['bom-ref']
|
||||||
|
)?.dependsOn || []
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: component.name,
|
||||||
|
version: component.version,
|
||||||
|
purl: component.purl,
|
||||||
|
dependencies,
|
||||||
|
'bom-ref': component['bom-ref']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function printSBOMContent(components: Component[]): void {
|
||||||
|
core.info('=== SBOM Content ===')
|
||||||
|
for (const component of components) {
|
||||||
|
core.info(`- ${component['bom-ref']}`)
|
||||||
|
if (component.dependencies && component.dependencies.length > 0) {
|
||||||
|
core.info(` depends on: ${component.dependencies.join(', ')}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core.info('==================')
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertSBOMToSnapshot(
|
||||||
|
sbomPath: string,
|
||||||
|
components: Component[]
|
||||||
|
): DependencySnapshot {
|
||||||
|
const context = github.context
|
||||||
|
const sbomFileName = basename(sbomPath)
|
||||||
|
|
||||||
|
if (!sbomFileName.endsWith(SBOM_FILE_SUFFIX)) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid SBOM file name: ${sbomFileName}. Expected a file ending with ${SBOM_FILE_SUFFIX}.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: 0,
|
||||||
|
sha: context.sha,
|
||||||
|
ref: context.ref,
|
||||||
|
job: {
|
||||||
|
correlator: `${context.workflow}_${context.job}`,
|
||||||
|
id: context.runId.toString(),
|
||||||
|
html_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`
|
||||||
|
},
|
||||||
|
detector: {
|
||||||
|
name: 'Oracle GraalVM',
|
||||||
|
version: javaVersionOrLatestEA ?? '',
|
||||||
|
url: 'https://www.graalvm.org/'
|
||||||
|
},
|
||||||
|
scanned: new Date().toISOString(),
|
||||||
|
manifests: {
|
||||||
|
[sbomFileName]: {
|
||||||
|
name: sbomFileName,
|
||||||
|
resolved: mapComponentsToGithubAPIFormat(components),
|
||||||
|
metadata: {
|
||||||
|
generated_by: 'SBOM generated by GraalVM Native Image',
|
||||||
|
action_version: c.ACTION_VERSION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapComponentsToGithubAPIFormat(
|
||||||
|
components: Component[]
|
||||||
|
): Record<string, {package_url: string; dependencies?: string[]}> {
|
||||||
|
return Object.fromEntries(
|
||||||
|
components
|
||||||
|
.filter(component => {
|
||||||
|
if (!component.purl) {
|
||||||
|
core.info(
|
||||||
|
`Component ${component.name} does not have a valid package URL (purl). Skipping.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return component.purl
|
||||||
|
})
|
||||||
|
.map(component => [
|
||||||
|
component.name,
|
||||||
|
{
|
||||||
|
package_url: component.purl as string,
|
||||||
|
dependencies: component.dependencies || []
|
||||||
|
}
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submitDependencySnapshot(
|
||||||
|
snapshotData: DependencySnapshot
|
||||||
|
): Promise<void> {
|
||||||
|
const token = core.getInput(c.INPUT_GITHUB_TOKEN, {required: true})
|
||||||
|
const octokit = github.getOctokit(token)
|
||||||
|
const context = github.context
|
||||||
|
|
||||||
|
try {
|
||||||
|
await octokit.request(
|
||||||
|
'POST /repos/{owner}/{repo}/dependency-graph/snapshots',
|
||||||
|
{
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
version: snapshotData.version,
|
||||||
|
sha: snapshotData.sha,
|
||||||
|
ref: snapshotData.ref,
|
||||||
|
job: snapshotData.job,
|
||||||
|
detector: snapshotData.detector,
|
||||||
|
metadata: {},
|
||||||
|
scanned: snapshotData.scanned,
|
||||||
|
manifests: snapshotData.manifests,
|
||||||
|
headers: {
|
||||||
|
'X-GitHub-Api-Version': '2022-11-28'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
core.info('Dependency snapshot submitted successfully.')
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to submit dependency snapshot for SBOM: ${error instanceof Error ? error.message : String(error)}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ import {setUpNativeImageMusl} from './features/musl'
|
|||||||
import {setUpWindowsEnvironment} from './msvc'
|
import {setUpWindowsEnvironment} from './msvc'
|
||||||
import {setUpNativeImageBuildReports} from './features/reports'
|
import {setUpNativeImageBuildReports} from './features/reports'
|
||||||
import {exec} from '@actions/exec'
|
import {exec} from '@actions/exec'
|
||||||
|
import {setUpSBOMSupport} from './features/sbom'
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
@ -148,7 +149,6 @@ async function run(): Promise<void> {
|
|||||||
if (setJavaHome) {
|
if (setJavaHome) {
|
||||||
core.exportVariable('JAVA_HOME', graalVMHome)
|
core.exportVariable('JAVA_HOME', graalVMHome)
|
||||||
}
|
}
|
||||||
|
|
||||||
await setUpGUComponents(
|
await setUpGUComponents(
|
||||||
javaVersion,
|
javaVersion,
|
||||||
graalVMVersion,
|
graalVMVersion,
|
||||||
@ -165,6 +165,7 @@ async function run(): Promise<void> {
|
|||||||
javaVersion,
|
javaVersion,
|
||||||
graalVMVersion
|
graalVMVersion
|
||||||
)
|
)
|
||||||
|
setUpSBOMSupport(javaVersion, distribution)
|
||||||
|
|
||||||
core.startGroup(`Successfully set up '${basename(graalVMHome)}'`)
|
core.startGroup(`Successfully set up '${basename(graalVMHome)}'`)
|
||||||
await exec(join(graalVMHome, 'bin', `java${c.EXECUTABLE_SUFFIX}`), [
|
await exec(join(graalVMHome, 'bin', `java${c.EXECUTABLE_SUFFIX}`), [
|
||||||
|
46
src/utils.ts
46
src/utils.ts
@ -4,11 +4,13 @@ import * as github from '@actions/github'
|
|||||||
import * as httpClient from '@actions/http-client'
|
import * as httpClient from '@actions/http-client'
|
||||||
import * as semver from 'semver'
|
import * as semver from 'semver'
|
||||||
import * as tc from '@actions/tool-cache'
|
import * as tc from '@actions/tool-cache'
|
||||||
|
import * as fs from 'fs'
|
||||||
import {ExecOptions, exec as e} from '@actions/exec'
|
import {ExecOptions, exec as e} from '@actions/exec'
|
||||||
import {readFileSync, readdirSync} from 'fs'
|
import {readFileSync, readdirSync} from 'fs'
|
||||||
import {Octokit} from '@octokit/core'
|
import {Octokit} from '@octokit/core'
|
||||||
import {createHash} from 'crypto'
|
import {createHash} from 'crypto'
|
||||||
import {join} from 'path'
|
import {join} from 'path'
|
||||||
|
import {tmpdir} from 'os'
|
||||||
|
|
||||||
// Set up Octokit for github.com only and in the same way as @actions/github (see https://git.io/Jy9YP)
|
// Set up Octokit for github.com only and in the same way as @actions/github (see https://git.io/Jy9YP)
|
||||||
const baseUrl = 'https://api.github.com'
|
const baseUrl = 'https://api.github.com'
|
||||||
@ -247,3 +249,47 @@ export async function createPRComment(content: string): Promise<void> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function tmpfile(fileName: string) {
|
||||||
|
return join(tmpdir(), fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setNativeImageOption(
|
||||||
|
javaVersionOrDev: string,
|
||||||
|
optionValue: string
|
||||||
|
): void {
|
||||||
|
const coercedJavaVersionOrDev = semver.coerce(javaVersionOrDev)
|
||||||
|
if (
|
||||||
|
(coercedJavaVersionOrDev &&
|
||||||
|
semver.gte(coercedJavaVersionOrDev, '22.0.0')) ||
|
||||||
|
javaVersionOrDev === c.VERSION_DEV ||
|
||||||
|
javaVersionOrDev.endsWith('-ea')
|
||||||
|
) {
|
||||||
|
/* NATIVE_IMAGE_OPTIONS was introduced in GraalVM for JDK 22 (so were EA builds). */
|
||||||
|
let newOptionValue = optionValue
|
||||||
|
const existingOptions = process.env[c.NATIVE_IMAGE_OPTIONS_ENV]
|
||||||
|
if (existingOptions) {
|
||||||
|
newOptionValue = `${existingOptions} ${newOptionValue}`
|
||||||
|
}
|
||||||
|
core.exportVariable(c.NATIVE_IMAGE_OPTIONS_ENV, newOptionValue)
|
||||||
|
} else {
|
||||||
|
const optionsFile = getNativeImageOptionsFile()
|
||||||
|
if (fs.existsSync(optionsFile)) {
|
||||||
|
fs.appendFileSync(optionsFile, ` ${optionValue}`)
|
||||||
|
} else {
|
||||||
|
fs.writeFileSync(optionsFile, `NativeImageArgs = ${optionValue}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NATIVE_IMAGE_CONFIG_FILE = tmpfile('native-image-options.properties')
|
||||||
|
const NATIVE_IMAGE_CONFIG_FILE_ENV = 'NATIVE_IMAGE_CONFIG_FILE'
|
||||||
|
|
||||||
|
function getNativeImageOptionsFile(): string {
|
||||||
|
let optionsFile = process.env[NATIVE_IMAGE_CONFIG_FILE_ENV]
|
||||||
|
if (optionsFile === undefined) {
|
||||||
|
optionsFile = NATIVE_IMAGE_CONFIG_FILE
|
||||||
|
core.exportVariable(NATIVE_IMAGE_CONFIG_FILE_ENV, optionsFile)
|
||||||
|
}
|
||||||
|
return optionsFile
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user