feat(appstore): resolve repo manifests and docker digest-tracked images
This commit is contained in:
@@ -81,6 +81,96 @@ Deno.test('appstore rejects invalid template ports and volumes', () => {
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test('appstore resolves repo manifests and docker digest-tracked latest images', async () => {
|
||||
const catalogBaseUrl = 'https://catalog.example.test';
|
||||
const manifestUrl = 'https://code.example.test/cloudly/servezone.catalog.json';
|
||||
const digest = 'sha256:1234567890abcdef';
|
||||
|
||||
const fakeFetch: typeof fetch = async (input, init) => {
|
||||
const url = input instanceof Request ? input.url : input.toString();
|
||||
const method = init?.method || 'GET';
|
||||
|
||||
if (url === `${catalogBaseUrl}/catalog.resolved.json`) {
|
||||
return new Response('not found', { status: 404 });
|
||||
}
|
||||
|
||||
if (url === `${catalogBaseUrl}/catalog.json`) {
|
||||
return Response.json({
|
||||
schemaVersion: 1,
|
||||
updatedAt: '2026-05-24T00:00:00Z',
|
||||
apps: [
|
||||
{
|
||||
id: 'cloudly',
|
||||
name: 'Cloudly',
|
||||
description: 'Central metadata can stay curated.',
|
||||
category: 'Dev Tools',
|
||||
latestVersion: '1.0.0',
|
||||
source: {
|
||||
type: 'repoManifest',
|
||||
url: manifestUrl,
|
||||
ref: 'main',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
if (url === manifestUrl) {
|
||||
return Response.json({
|
||||
schemaVersion: 1,
|
||||
app: {
|
||||
id: 'cloudly',
|
||||
name: 'Cloudly',
|
||||
description: 'Manifest-owned app metadata.',
|
||||
category: 'Dev Tools',
|
||||
maintainer: 'serve.zone',
|
||||
},
|
||||
latestVersion: 'latest',
|
||||
source: {
|
||||
type: 'dockerImage',
|
||||
image: 'registry.example.test/serve.zone/cloudly:latest',
|
||||
tracking: 'digest',
|
||||
},
|
||||
runtime: {
|
||||
image: 'registry.example.test/serve.zone/cloudly:latest',
|
||||
port: 80,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
url === 'https://registry.example.test/v2/serve.zone/cloudly/manifests/latest' &&
|
||||
method === 'HEAD'
|
||||
) {
|
||||
return new Response(null, {
|
||||
status: 200,
|
||||
headers: { 'docker-content-digest': digest },
|
||||
});
|
||||
}
|
||||
|
||||
return new Response(`unexpected ${method} ${url}`, { status: 500 });
|
||||
};
|
||||
|
||||
const appStore = new AppStoreManager({} as any, {
|
||||
repoBaseUrl: catalogBaseUrl,
|
||||
fetch: fakeFetch,
|
||||
});
|
||||
|
||||
const catalog = await appStore.getCatalog();
|
||||
assertEquals(catalog.apps[0].latestVersion, `latest@${digest}`);
|
||||
assertEquals(catalog.apps[0].resolvedSource?.manifestHash?.length, 64);
|
||||
assertEquals(catalog.apps[0].upgradeStrategy, 'dockerDigest');
|
||||
|
||||
const appMeta = await appStore.getAppMeta('cloudly');
|
||||
assertEquals(appMeta.latestVersion, `latest@${digest}`);
|
||||
assertEquals(appMeta.versions, [`latest@${digest}`]);
|
||||
|
||||
const config = await appStore.getAppVersionConfig('cloudly', appMeta.latestVersion);
|
||||
assertEquals(config.image, 'registry.example.test/serve.zone/cloudly:latest');
|
||||
assertEquals(config.catalogVersion, `latest@${digest}`);
|
||||
assertEquals(config.resolvedImageDigest, digest);
|
||||
});
|
||||
|
||||
Deno.test('docker service spec validation rejects unsafe volume and port declarations', () => {
|
||||
const dockerManager = new OneboxDockerManager();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user