Skip to content

Commit 12997ef

Browse files
feat(scorecard): add support for GitLab
1 parent b1c2e77 commit 12997ef

File tree

10 files changed

+70
-53
lines changed

10 files changed

+70
-53
lines changed

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ Since version 0.6.0 of Node-secure the UI include a brand new searchbar that all
167167
- author (author name/email/url).
168168
- ext (list of available file extensions in the current payload/tree).
169169
- builtin (available Node.js core module name).
170-
- size (see [here](https://github.com/NodeSecure/size-satisfies#usage-example)
170+
- size (see [here](https://github.com/NodeSecure/size-satisfies#usage-example)).
171171

172172
Exemple of query:
173173

@@ -187,7 +187,6 @@ other side will bundle and remove most of the useless files from the tarball (Li
187187
### Why some packages don't have OSSF Scorecard ?
188188
See [Scorecard Public Data](https://github.com/ossf/scorecard#public-data):
189189
> We run a weekly Scorecard scan of the 1 million most critical open source projects judged by their direct dependencies and publish the results in a BigQuery public dataset.
190-
> Currently, this list is derived from projects hosted on GitHub ONLY.
191190
192191
## Contributors guide
193192

bin/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ prog
8383
prog
8484
.command("scorecard [repository]")
8585
.describe(i18n.getTokenSync("cli.commands.scorecard.desc"))
86+
.option("--vcs", "Version control platform (GitHub, GitLab", "github")
8687
.action(commands.scorecard.main);
8788

8889
prog

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
"@nodesecure/flags": "^2.4.0",
8181
"@nodesecure/i18n": "^3.2.2",
8282
"@nodesecure/npm-registry-sdk": "^1.6.1",
83-
"@nodesecure/ossf-scorecard-sdk": "^2.0.0",
83+
"@nodesecure/ossf-scorecard-sdk": "^3.1.0",
8484
"@nodesecure/rc": "^1.5.0",
8585
"@nodesecure/scanner": "^5.0.1",
8686
"@nodesecure/utils": "^1.1.0",

public/js/components/package/pannels/scorecard.js

+25-17
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ import * as utils from "../../../utils.js";
66

77
export class Scorecard {
88
static ExternalLinks = {
9-
visualizer: "https://kooltheba.github.io/openssf-scorecard-api-visualizer/#/projects/github.com/"
9+
visualizer: (platform) => `https://kooltheba.github.io/openssf-scorecard-api-visualizer/#/projects/${platform}/`
1010
}
1111

1212
constructor(pkg) {
1313
this.package = pkg;
1414
}
1515

16-
async fetchScorecardData(repoName) {
16+
async fetchScorecardData(repoName, platform) {
1717
try {
18-
const { data } = (await getJSON(`/scorecard/${repoName}`));
18+
const { data } = (await getJSON(`/scorecard/${repoName}?platform=${platform}`));
1919
if (!data) {
2020
return null;
2121
}
@@ -36,28 +36,36 @@ export class Scorecard {
3636
}
3737
}
3838

39-
/**
40-
* @param {!HTMLTemplateElement} clone
41-
*/
42-
generate(clone) {
43-
const githubURL = this.package.links.github;
44-
if (!githubURL.href) {
45-
return this.hide();
39+
versionControlUrl(vc) {
40+
if (!vc || !vc.href) {
41+
return null;
4642
}
4743

48-
const github = new URL(githubURL.href);
49-
const repoName = github.pathname.slice(
44+
const url = new URL(vc.href);
45+
46+
return url.pathname.slice(
5047
1,
51-
github.pathname.includes(".git") ? -4 : github.pathname.length
48+
url.pathname.includes(".git") ? -4 : url.pathname.length
5249
);
50+
}
51+
52+
/**
53+
* @param {!HTMLTemplateElement} clone
54+
*/
55+
generate(clone) {
56+
const links = this.package.links;
57+
const repoName = this.versionControlUrl(links.github?.href) ?? this.versionControlUrl(links.gitlab?.href) ?? this.versionControlUrl(links.homepage) ?? this.package.name;
5358

5459
const pannel = clone.getElementById("pan-scorecard");
55-
this.fetchScorecardData(repoName).then((data) => {
60+
const isGitlab = this.package.links.gitlab || this.package.links.homepage?.href?.includes("gitlab.com");
61+
const platform = isGitlab ? "gitlab.com" : "github.com";
62+
63+
this.fetchScorecardData(repoName, platform).then((data) => {
5664
if (!data) {
5765
return this.hide();
5866
}
5967

60-
pannel.appendChild(this.renderScorecard(data, repoName));
68+
pannel.appendChild(this.renderScorecard(data, repoName, platform));
6169
document.getElementById('scorecard-menu').style.display = 'flex';
6270
});
6371
}
@@ -76,7 +84,7 @@ export class Scorecard {
7684
return "green";
7785
}
7886

79-
renderScorecard(data, repoName) {
87+
renderScorecard(data, repoName, platform) {
8088
const { score, checks } = data;
8189

8290
const container = utils.createDOMElement('div', {
@@ -94,7 +102,7 @@ export class Scorecard {
94102
document.getElementById('head-score').innerText = score;
95103
document
96104
.querySelector(".score-header .visualizer a")
97-
.setAttribute('href', Scorecard.ExternalLinks.visualizer + repoName);
105+
.setAttribute('href', Scorecard.ExternalLinks.visualizer(platform) + repoName);
98106

99107
container.childNodes.forEach((check, checkKey) => {
100108
check.addEventListener('click', () => {

src/commands/scorecard.js

+17-8
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,34 @@ function separatorLine() {
1414
return grey("-".repeat(80));
1515
}
1616

17-
export function getCurrentRepository() {
17+
export function getCurrentRepository(vcs = "github") {
1818
const config = ini.parse(fs.readFileSync(".git/config", "utf-8"));
1919

2020
const originMetadata = config["remote \"origin\""];
2121
if (!originMetadata) {
2222
return Err("Cannot find origin remote.");
2323
}
2424

25-
const [, rawPkg] = originMetadata.url.match(/github\.com(.+)\.git/) ?? [];
25+
const [, rawPkg] = originMetadata.url.match(/(?:github|gitlab)\.com(.+)\.git/) ?? [];
26+
2627
if (!rawPkg) {
27-
return Err("OSSF Scorecard supports projects hosted on Github only.");
28+
return Err("Cannot find version control host.");
2829
}
2930

30-
return Ok(rawPkg.slice(1));
31+
// vcs is github by default.
32+
return Ok([rawPkg.slice(1), originMetadata.url.includes("gitlab") ? "gitlab" : vcs]);
3133
}
3234

33-
export async function main(repo) {
34-
const result = typeof repo === "string" ? Ok(repo) : getCurrentRepository();
35+
export async function main(repo, opts) {
36+
const vcs = opts.vcs.toLowerCase();
37+
const result = typeof repo === "string" ? Ok([repo, vcs]) : getCurrentRepository(vcs);
3538

3639
let repository;
40+
let platform;
3741
try {
38-
repository = result.unwrap();
42+
const [repo, vcs] = result.unwrap();
43+
repository = repo;
44+
platform = vcs.slice(-4) === ".com" ? vsc : `${vcs}.com`;
3945
}
4046
catch (error) {
4147
console.log(white().bold(result.err));
@@ -45,7 +51,10 @@ export async function main(repo) {
4551

4652
let data;
4753
try {
48-
data = await scorecard.result(repository);
54+
data = await scorecard.result(repository, {
55+
resolveOnVersionControl: Boolean(process.env.GITHUB_TOKEN || opts.resolveOnVersionControl),
56+
platform
57+
});
4958
}
5059
catch (error) {
5160
console.log(

src/http-server/endpoints/ossf-scorecard.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@ import send from "@polka/send-type";
44

55
export async function get(req, res) {
66
const { org, pkgName } = req.params;
7+
const { platform = "github.com" } = req.query;
78

89
try {
9-
const data = await scorecard.result(`${org}/${pkgName}`);
10+
const data = await scorecard.result(`${org}/${pkgName}`, {
11+
resolveOnVersionControl: Boolean(process.env.GITHUB_TOKEN),
12+
resolveOnNpmRegistry: false,
13+
platform
14+
});
1015

1116
return send(res, 200, {
1217
data
1318
});
1419
}
15-
1620
catch (error) {
1721
return send(
1822
res,

test/commands/scorecard.test.js

+2-22
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ test("scorecard should display fastify scorecard", async() => {
7474
});
7575

7676
test("should not display scorecard for unknown repository", async() => {
77-
const packageName = "unkown/repository";
77+
const packageName = "fastify/fastify";
7878
const scorecardCliOptions = {
7979
path: kProcessPath,
8080
args: [packageName],
@@ -109,7 +109,7 @@ test("should retrieve repository whithin git config", async() => {
109109
}
110110
});
111111

112-
assert.deepEqual(testingModule.getCurrentRepository(), Ok("myawesome/repository"));
112+
assert.deepEqual(testingModule.getCurrentRepository(), Ok(["myawesome/repository", "github"]));
113113
});
114114

115115
test("should not find origin remote", async() => {
@@ -123,23 +123,3 @@ test("should not find origin remote", async() => {
123123
assert.equal(result.err, true);
124124
assert.equal(result.val, "Cannot find origin remote.");
125125
});
126-
127-
test("should support github only", async() => {
128-
const testingModule = await esmock("../../src/commands/scorecard.js", {
129-
fs: {
130-
readFileSync: () => [
131-
"[remote \"origin\"]",
132-
"\turl = [email protected]:myawesome/repository.git"
133-
].join("\n")
134-
}
135-
});
136-
// NOTE: we can then test that the only expected one console.log is correct
137-
// it's a bit simpler that running the process to parse stdout
138-
const logs = [];
139-
console.log = (str) => logs.push(str);
140-
141-
await testingModule.main();
142-
143-
assert.equal(logs.length, 1);
144-
assert.equal(stripAnsi(logs[0]), "OSSF Scorecard supports projects hosted on Github only.");
145-
});

test/httpServer.test.js

+7
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,13 @@ describe("httpServer", () => {
289289
assert.equal(result.data.data.repo.name, "github.com/NodeSecure/cli");
290290
});
291291

292+
test("'/scorecard/:org/:pkgName' should return scorecard data for GitLab repo", async() => {
293+
const result = await get(new URL("/scorecard/gitlab-org/gitlab-ui?platform=gitlab.com", HTTP_URL));
294+
295+
assert.equal(result.statusCode, 200);
296+
assert.equal(result.data.data.repo.name, "gitlab.com/gitlab-org/gitlab-ui");
297+
});
298+
292299
test("'/scorecard/:org/:pkgName' should not find repo", async() => {
293300
const wrongPackageName = "br-br-br-brah";
294301

test/process/scorecard.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
import * as scorecard from "../../src/commands/scorecard.js";
33
import { prepareProcess } from "../helpers/cliCommandRunner.js";
44

5-
prepareProcess(scorecard.main);
5+
prepareProcess(scorecard.main, ["fastify/fastify", { resolveOnVersionControl: true, vcs: "github" }]);

workspaces/vis-network/src/utils.js

+9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ export async function getJSON(path, customHeaders = Object.create(null)) {
1717
headers: Object.assign({}, headers, customHeaders)
1818
});
1919

20+
if (raw.ok === false) {
21+
const { status, statusText } = raw;
22+
23+
return {
24+
status,
25+
statusText
26+
};
27+
}
28+
2029
return raw.json();
2130
}
2231

0 commit comments

Comments
 (0)