community: resolve user provided url

This commit is contained in:
Girish Ramakrishnan
2026-02-19 20:07:05 +01:00
parent 207260821b
commit 461a5a780d
5 changed files with 319 additions and 18 deletions
+144
View File
@@ -0,0 +1,144 @@
import { describe, it, before, after, afterEach } from 'mocha';
import assert from 'node:assert/strict';
import BoxError from '../boxerror.js';
import common from './common.js';
import community from '../community.js';
import nock from 'nock';
import safe from 'safetydance';
const validManifest = Object.assign({}, common.manifest, {
minBoxVersion: '9.1.0',
iconUrl: 'https://example.com/icon.png',
packagerName: 'Cloudron',
packagerUrl: 'https://cloudron.io',
tags: [ 'test' ],
changelog: '12345',
mediaLinks: [ 'https://example.com/shot.png' ]
});
const versionsFixture = {
stable: true,
versions: {
'0.1.0': {
manifest: validManifest,
publishState: 'published',
creationDate: '2026-01-01T00:00:00.000Z',
ts: Date.now()
}
}
};
describe('Community', function () {
before(function () {
if (!nock.isActive()) nock.activate();
});
after(function () {
nock.restore();
});
afterEach(function () {
nock.cleanAll();
});
describe('_toRawUrl', function () {
it('rewrites github blob root and nested paths', async function () {
assert.equal(
community._toRawUrl(new URL('https://github.com/cloudron/test-app/blob/main/CloudronVersions.json')),
'https://raw.githubusercontent.com/cloudron/test-app/main/CloudronVersions.json'
);
assert.equal(
community._toRawUrl(new URL('https://github.com/cloudron/test-app/blob/main/packaging/CloudronVersions.json')),
'https://raw.githubusercontent.com/cloudron/test-app/main/packaging/CloudronVersions.json'
);
});
it('rewrites gitlab blob root and nested paths', async function () {
assert.equal(
community._toRawUrl(new URL('https://gitlab.com/cloudron/test-app/-/blob/main/CloudronVersions.json')),
'https://gitlab.com/cloudron/test-app/-/raw/main/CloudronVersions.json'
);
assert.equal(
community._toRawUrl(new URL('https://my.gitlab.company/group/subgroup/test-app/-/blob/main/path/CloudronVersions.json')),
'https://my.gitlab.company/group/subgroup/test-app/-/raw/main/path/CloudronVersions.json'
);
});
it('rewrites gitea/forgejo/gogs src paths', async function () {
assert.equal(
community._toRawUrl(new URL('https://gitea.example.com/user/repo/src/branch/main/CloudronVersions.json')),
'https://gitea.example.com/user/repo/raw/branch/main/CloudronVersions.json'
);
assert.equal(
community._toRawUrl(new URL('https://codeberg.org/forgejo/forgejo/src/branch/forgejo/packaging/CloudronVersions.json')),
'https://codeberg.org/forgejo/forgejo/raw/branch/forgejo/packaging/CloudronVersions.json'
);
assert.equal(
community._toRawUrl(new URL('https://gogs.example.com/user/repo/src/tag/v1.0.0/CloudronVersions.json')),
'https://gogs.example.com/user/repo/raw/tag/v1.0.0/CloudronVersions.json'
);
});
it('returns null for non-rewrite URLs', async function () {
assert.equal(
community._toRawUrl(new URL('https://raw.githubusercontent.com/cloudron/test-app/main/CloudronVersions.json')),
null
);
assert.equal(
community._toRawUrl(new URL('https://github.com/cloudron/test-app')),
null
);
});
});
it('resolveVersionsUrl returns direct URL and version data', async function () {
nock('https://example.com')
.get('/CloudronVersions.json')
.reply(200, versionsFixture);
const result = await community.resolveVersionsUrl('https://example.com/CloudronVersions.json', '0.1.0');
assert.equal(result.resolvedUrl, 'https://example.com/CloudronVersions.json');
assert.equal(result.versionsUrl, 'https://example.com/CloudronVersions.json@0.1.0');
assert.deepEqual(result.manifest, validManifest);
});
it('resolveVersionsUrl handles browser blob link to CloudronVersions.json', async function () {
nock('https://github.com')
.get('/cloudron/test-app/blob/main/CloudronVersions.json')
.reply(200, '<html>not json</html>');
nock('https://raw.githubusercontent.com')
.get('/cloudron/test-app/main/CloudronVersions.json')
.reply(200, versionsFixture);
const result = await community.resolveVersionsUrl('https://github.com/cloudron/test-app/blob/main/CloudronVersions.json', 'latest');
assert.equal(result.resolvedUrl, 'https://raw.githubusercontent.com/cloudron/test-app/main/CloudronVersions.json');
assert.equal(result.versionsUrl, 'https://raw.githubusercontent.com/cloudron/test-app/main/CloudronVersions.json@latest');
});
it('resolveVersionsUrl preserves hinted path from blob URL', async function () {
nock('https://raw.githubusercontent.com')
.get('/cloudron/test-app/main/packaging/CloudronVersions.json')
.reply(200, versionsFixture);
const result = await community.resolveVersionsUrl('https://github.com/cloudron/test-app/blob/main/packaging/CloudronVersions.json', 'latest');
assert.equal(result.resolvedUrl, 'https://raw.githubusercontent.com/cloudron/test-app/main/packaging/CloudronVersions.json');
});
it('resolveVersionsUrl accepts already raw github URL', async function () {
nock('https://raw.githubusercontent.com')
.get('/cloudron/test-app/main/CloudronVersions.json')
.reply(200, versionsFixture);
const result = await community.resolveVersionsUrl('https://raw.githubusercontent.com/cloudron/test-app/main/CloudronVersions.json', 'latest');
assert.equal(result.resolvedUrl, 'https://raw.githubusercontent.com/cloudron/test-app/main/CloudronVersions.json');
});
it('resolveVersionsUrl returns not found when no candidate works', async function () {
const [error] = await safe(community.resolveVersionsUrl('https://github.com/cloudron/missing', 'latest'));
assert.equal(error.reason, BoxError.NOT_FOUND);
});
});