diff --git a/services/reproducible-central/reproducible-central.service.js b/services/reproducible-central/reproducible-central.service.js new file mode 100644 index 0000000000..93f87920e8 --- /dev/null +++ b/services/reproducible-central/reproducible-central.service.js @@ -0,0 +1,94 @@ +import Joi from 'joi' +import { BaseJsonService, pathParams } from '../index.js' + +const schema = Joi.object() + .pattern(Joi.string(), Joi.string().regex(/^\d+\/\d+$|^[X?]$/)) + .required() + +const description = ` +[Reproducible Central](https://github.com/jvm-repo-rebuild/reproducible-central) +provides [Reproducible Builds](https://reproducible-builds.org/) check status +for projects published to [Maven Central](https://central.sonatype.com/). +` + +export default class ReproducibleCentral extends BaseJsonService { + static category = 'dependencies' + + static route = { + base: 'reproducible-central/artifact', + pattern: ':groupId/:artifactId/:version', + } + + static openApi = { + '/reproducible-central/artifact/{groupId}/{artifactId}/{version}': { + get: { + summary: 'Reproducible Central Artifact', + description, + parameters: pathParams( + { + name: 'groupId', + example: 'org.apache.maven', + }, + { + name: 'artifactId', + example: 'maven-core', + }, + { + name: 'version', + example: '3.9.9', + }, + ), + }, + }, + } + + static defaultBadgeData = { + label: 'reproducible builds', + } + + static render(rebuildResult) { + if (rebuildResult === undefined) { + return { color: 'red', message: 'version not available in Maven Central' } + } else if (rebuildResult === 'X') { + return { color: 'red', message: 'unable to rebuild' } + } else if (rebuildResult === '?') { + return { color: 'grey', message: 'version not evaluated' } + } + + const [ok, count] = rebuildResult.split('/') + let color + if (ok === count) { + color = 'brightgreen' + } else if (ok > count - ok) { + color = 'yellow' + } else { + color = 'red' + } + return { color, message: rebuildResult } + } + + async fetch({ groupId, artifactId }) { + return this._requestJson({ + schema, + url: `https://jvm-repo-rebuild.github.io/reproducible-central/badge/artifact/${groupId.replace(/\./g, '/')}/${artifactId}.json`, + httpErrors: { + 404: 'groupId:artifactId unknown', + }, + }) + } + + async handle({ groupId, artifactId, version }) { + if (version.endsWith('-SNAPSHOT')) { + return { + message: 'SNAPSHOT, not evaluated', + color: 'grey', + } + } + + const versions = await this.fetch({ + groupId, + artifactId, + }) + return this.constructor.render(versions[version]) + } +} diff --git a/services/reproducible-central/reproducible-central.tester.js b/services/reproducible-central/reproducible-central.tester.js new file mode 100644 index 0000000000..9a9857885b --- /dev/null +++ b/services/reproducible-central/reproducible-central.tester.js @@ -0,0 +1,62 @@ +import { createServiceTester } from '../tester.js' +export const t = await createServiceTester() + +t.create('reproducible gav') + .get('/org.apache.maven/maven-core/3.9.9.json') + .expectBadge({ + label: 'reproducible builds', + message: '75/75', + color: 'brightgreen', + }) + +t.create('mostly reproducible gav') + .get('/org.apache.maven/maven-core/3.8.5.json') + .expectBadge({ + label: 'reproducible builds', + message: '43/47', + color: 'yellow', + }) + +t.create('mostly non-reproducible gav') + .get('/org.apache.maven/maven-core/3.6.3.json') + .expectBadge({ + label: 'reproducible builds', + message: '2/32', + color: 'red', + }) + +t.create('non-rebuildable gav') + .get('/org.apache.maven/maven-core/4.0.0-alpha-2.json') + .expectBadge({ + label: 'reproducible builds', + message: 'unable to rebuild', + color: 'red', + }) + +t.create('unknown v for known ga') + .get('/org.apache.maven/maven-core/3.9.9.1.json') + .expectBadge({ + label: 'reproducible builds', + message: 'version not available in Maven Central', + color: 'red', + }) + +t.create('untested v for known ga') + .get('/org.apache.maven/maven-core/2.2.1.json') + .expectBadge({ + label: 'reproducible builds', + message: 'version not evaluated', + color: 'grey', + }) + +t.create('unknown ga').get('/org.apache.maven/any/3.9.9.json').expectBadge({ + label: 'reproducible builds', + message: 'groupId:artifactId unknown', + color: 'red', +}) + +t.create('SNAPSHOT').get('/any/any/anything-SNAPSHOT.json').expectBadge({ + label: 'reproducible builds', + message: 'SNAPSHOT, not evaluated', + color: 'grey', +})