Skip to content

Commit c4148a3

Browse files
authored
Merge branch 'main' into fix/js-shells
2 parents 2ba0c80 + 0d8c7d4 commit c4148a3

15 files changed

+167445
-26
lines changed

.eslintrc.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
],
1919
"rules": {
2020
"curly": "warn",
21-
"eqeqeq": "warn",
21+
"eqeqeq": ["warn", "always", {"null": "never"}],
2222
"no-throw-literal": "warn",
2323
"sort-imports": "warn"
2424
},
2525
"ignorePatterns": [
2626
"integration"
2727
]
28-
}
28+
}

.github/workflows/pr.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ jobs:
7070
- name: Setup Gradle
7171
uses: gradle/actions/setup-gradle@v4
7272

73+
- name: Setup syft
74+
uses: jaxxstorm/[email protected]
75+
with:
76+
repo: anchore/syft
77+
platform: linux
78+
arch: amd64
79+
# tag: the latest one, so we can catch changes
80+
81+
- name: Setup skopeo
82+
run: sudo apt update && sudo apt-get -y install skopeo
83+
7384
- name: Install project modules
7485
run: npm ci
7586

.github/workflows/stage.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ jobs:
6060
- name: Prepare PNPM
6161
run: corepack prepare pnpm@latest --activate
6262

63-
6463
- name: Setup Java 17
6564
uses: actions/setup-java@v4
6665
with:
@@ -76,6 +75,17 @@ jobs:
7675
- name: Setup Gradle
7776
uses: gradle/gradle-build-action@v3
7877

78+
- name: Setup syft
79+
uses: jaxxstorm/[email protected]
80+
with:
81+
repo: anchore/syft
82+
platform: linux
83+
arch: amd64
84+
# tag: the latest one, so we can catch changes
85+
86+
- name: Setup skopeo
87+
run: sudo apt update && sudo apt-get -y install skopeo
88+
7989
- name: Configure git
8090
run: |
8191
git config user.name "${{ github.actor }}"

package-lock.json

Lines changed: 27 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@trustification/exhort-javascript-api",
3-
"version": "0.1.1-ea.71",
3+
"version": "0.1.1-ea.73",
44
"description": "Code-Ready Dependency Analytics JavaScript API.",
55
"license": "Apache-2.0",
66
"homepage": "https://github.com/trustification/exhort-javascript-api#README.md",
@@ -49,6 +49,7 @@
4949
"fast-toml": "^0.5.4",
5050
"fast-xml-parser": "^4.2.4",
5151
"help": "^3.0.2",
52+
"https-proxy-agent": "^7.0.6",
5253
"node-fetch": "^2.6.7",
5354
"packageurl-js": "^1.0.2",
5455
"yargs": "^17.7.2"

src/analysis.js

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import fs from "node:fs";
22
import path from "node:path";
3-
import {EOL} from "os";
4-
import {RegexNotToBeLogged, getCustom} from "./tools.js";
5-
import http from 'node:http';
6-
import https from 'node:https';
3+
import { EOL } from "os";
4+
import { RegexNotToBeLogged, getCustom } from "./tools.js";
5+
import { HttpsProxyAgent } from "https-proxy-agent";
6+
import { generateImageSBOM, parseImageRef } from "./oci_image/utils.js";
77

8-
export default { requestComponent, requestStack, validateToken }
8+
export default { requestComponent, requestStack, requestImages, validateToken }
99

1010
const rhdaTokenHeader = "rhda-token";
1111
const rhdaSourceHeader = "rhda-source"
@@ -20,10 +20,7 @@ const rhdaOperationTypeHeader = "rhda-operation-type"
2020
function addProxyAgent(options, opts) {
2121
const proxyUrl = getCustom('EXHORT_PROXY_URL', null, opts);
2222
if (proxyUrl) {
23-
const proxyUrlObj = new URL(proxyUrl);
24-
options.agent = proxyUrlObj.protocol === 'https:'
25-
? new https.Agent({ proxy: proxyUrl })
26-
: new http.Agent({ proxy: proxyUrl });
23+
options.agent = new HttpsProxyAgent(proxyUrl);
2724
}
2825
return options;
2926
}
@@ -137,6 +134,52 @@ async function requestComponent(provider, manifest, url, opts = {}) {
137134
return Promise.resolve(result)
138135
}
139136

137+
/**
138+
*
139+
* @param {Array<string>} imageRefs
140+
* @param {string} url
141+
* @param {{}} [opts={}] - optional various options to pass along the application
142+
* @returns {Promise<string|import('@trustification/exhort-api-spec/model/v4/AnalysisReport').AnalysisReport>}
143+
*/
144+
async function requestImages(imageRefs, url, html = false, opts = {}) {
145+
const imageSboms = {}
146+
for (const image of imageRefs) {
147+
const parsedImageRef = parseImageRef(image)
148+
imageSboms[parsedImageRef.getPackageURL().toString()] = generateImageSBOM(parsedImageRef)
149+
}
150+
151+
const resp = await fetch(`${url}/api/v4/batch-analysis`, {
152+
method: 'POST',
153+
headers: {
154+
'Accept': html ? 'text/html' : 'application/json',
155+
'Content-Type': 'application/vnd.cyclonedx+json',
156+
...getTokenHeaders(opts)
157+
},
158+
body: JSON.stringify(imageSboms),
159+
})
160+
161+
if(resp.status === 200) {
162+
let result;
163+
if (!html) {
164+
result = await resp.json()
165+
} else {
166+
result = await resp.text()
167+
}
168+
if (process.env["EXHORT_DEBUG"] === "true") {
169+
let exRequestId = resp.headers.get("ex-request-id");
170+
if (exRequestId) {
171+
console.log("Unique Identifier associated with this request - ex-request-id=" + exRequestId)
172+
}
173+
console.log("Response body received from exhort server : " + EOL + EOL)
174+
console.log(JSON.stringify(result, null, 4))
175+
console.log("Ending time of sending component analysis request to exhort server= " + new Date())
176+
}
177+
return result
178+
} else {
179+
throw new Error(`Got error response from exhort backend - http return code : ${resp.status}, ex-request-id: ${resp.headers.get("ex-request-id")} error message => ${await resp.text()}`)
180+
}
181+
}
182+
140183
/**
141184
*
142185
* @param url the backend url to send the request to

src/index.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { getCustom } from "./tools.js";
77
import.meta.dirname
88
import * as url from 'url';
99

10-
export default { componentAnalysis, stackAnalysis, validateToken }
10+
export default { componentAnalysis, stackAnalysis, imageAnalysis, validateToken }
1111

1212
export const exhortDevDefaultUrl = 'https://exhort.stage.devshift.net';
1313

@@ -148,6 +148,39 @@ async function componentAnalysis(manifest, opts = {}) {
148148
return await analysis.requestComponent(provider, manifest, theUrl, opts) // throws error request sending failed
149149
}
150150

151+
/**
152+
* @overload
153+
* @param {Array<string>} imageRefs
154+
* @param {true} html
155+
* @param {object} [opts={}]
156+
* @returns {Promise<string>}
157+
* @throws {Error}
158+
*/
159+
160+
/**
161+
* @overload
162+
* @param {Array<string>} imageRefs
163+
* @param {false} html
164+
* @param {object} [opts={}]
165+
* @returns {Promise<import('@trustification/exhort-api-spec/model/v4/AnalysisReport').AnalysisReport}
166+
* @throws {Error}
167+
*/
168+
169+
/**
170+
* Get image analysis report for a set of OCI image references.
171+
* @overload
172+
* @param {Array<string>} imageRefs - OCI image references
173+
* @param {boolean} [html=false] - true will return a html string, false will return AnalysisReport
174+
* @param {{}} [opts={}] - optional various options to pass along the application
175+
* @returns {Promise<string|import('@trustification/exhort-api-spec/model/v4/AnalysisReport').AnalysisReport}
176+
* @throws {Error} if manifest inaccessible, no matching provider, failed to get create content,
177+
* or backend request failed
178+
*/
179+
async function imageAnalysis(imageRefs, html = false, opts = {}) {
180+
theUrl = selectExhortBackend(opts)
181+
return await analysis.requestImages(imageRefs, theUrl, opts)
182+
}
183+
151184
/**
152185
* Validates the Exhort token.
153186
* @param {object} [opts={}] - Optional parameters, potentially including token override.

0 commit comments

Comments
 (0)