feat: add built-in OCI registry

This commit is contained in:
2026-04-28 15:23:51 +00:00
parent 333cbeb221
commit 94f1199858
9 changed files with 1456 additions and 1883 deletions
+73
View File
@@ -84,6 +84,79 @@ tap.test('should get an identity', async () => {
}
});
tap.test('should expose the OCI registry endpoint', async () => {
const response = await fetch(
`http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}/v2/`,
);
expect(response.status).toEqual(200);
expect(response.headers.get('docker-distribution-api-version')).toEqual('registry/2.0');
});
tap.test('should require authentication for OCI registry tokens', async () => {
const response = await fetch(
`http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}/v2/token?service=cloudly&scope=repository:test/app:pull`,
);
expect(response.status).toEqual(401);
});
tap.test('should issue OCI registry tokens for the initial admin', async () => {
const credentials = Buffer.from(
`${helpers.testCloudlyAdminAccount.username}:${helpers.testCloudlyAdminAccount.password}`,
).toString('base64');
const response = await fetch(
`http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}/v2/token?service=cloudly&scope=repository:test/app:pull,push`,
{
headers: {
Authorization: `Basic ${credentials}`,
},
},
);
const body = await response.json();
expect(response.status).toEqual(200);
expect(body.token).toBeTruthy();
expect(body.access_token).toEqual(body.token);
});
tap.test('should deny OCI registry push tokens for non-admin users', async () => {
const readonlyUsername = 'registry-readonly';
const readonlyToken = 'registry-readonly-token';
const readonlyUser = new testCloudly.authManager.CUser();
readonlyUser.id = await testCloudly.authManager.CUser.getNewId();
readonlyUser.data = {
type: 'machine',
username: readonlyUsername,
password: readonlyToken,
tokens: [{
token: readonlyToken,
expiresAt: Date.now() + 3600 * 1000,
assignedRoles: [],
}],
role: 'user',
};
await readonlyUser.save();
const credentials = Buffer.from(`${readonlyUsername}:${readonlyToken}`).toString('base64');
const pullResponse = await fetch(
`http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}/v2/token?service=cloudly&scope=repository:test/readonly:pull`,
{
headers: {
Authorization: `Basic ${credentials}`,
},
},
);
expect(pullResponse.status).toEqual(200);
const pushResponse = await fetch(
`http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}/v2/token?service=cloudly&scope=repository:test/readonly:pull,push`,
{
headers: {
Authorization: `Basic ${credentials}`,
},
},
);
expect(pushResponse.status).toEqual(403);
});
tap.test('should expose platform desired state', async () => {
const capabilitiesResponse = await testClient.platform.getPlatformCapabilities();
expect(capabilitiesResponse.capabilities.find((capability) => capability.id === 'database')).toBeTruthy();