Add Docker Hub container registry support with library prefix handling
This commit adds support for Docker Hub (registry-1.docker.io) as a container registry platform with special authentication handling for official images. Changes: - Add 'cr-docker' platform pointing to https://registry-1.docker.io in platforms.js - Implement special authentication scope handling for Docker Hub official images - Docker Hub stores official images (nginx, redis, etc.) as library/nginx, library/redis - Single-component image names are automatically prefixed with 'library/' for authentication - Multi-component names (user/image) are passed through unchanged - Add comprehensive tests for Docker Hub support This resolves the issue where pulling public images from Docker Hub would prompt for authentication incorrectly. The library prefix is now automatically added to the authentication scope for single-name images, allowing proper anonymous access to public official images. Test coverage: - Official images (single-name): /cr/docker/v2/nginx/manifests/latest - User images (namespaced): /cr/docker/v2/nginxinc/nginx-unprivileged/manifests/latest - GET and HEAD request methods verified All Docker Hub specific tests pass.
This commit is contained in:
1 parent
25338b8542
commit
331c1697bf
3 files changed
+66
-1
No files matched your search
@@ -72,6 +72,7 @@ export const PLATFORMS = {
|
||||
'ip-hyperbolic': 'https://api.hyperbolic.xyz',
|
||||
|
||||
// Container Registries
|
||||
'cr-docker': 'https://registry-1.docker.io',
|
||||
'cr-quay': 'https://quay.io',
|
||||
'cr-gcr': 'https://gcr.io',
|
||||
'cr-mcr': 'https://mcr.microsoft.com',
|
||||
|
||||
+8
-1
@@ -595,7 +595,14 @@ async function handleRequest(request, env, ctx) {
|
||||
const repoPath = pathParts.slice(4).join('/'); // Skip /v2/cr/[registry]
|
||||
const repoParts = repoPath.split('/');
|
||||
if (repoParts.length >= 1) {
|
||||
const repoName = repoParts.slice(0, -2).join('/'); // Remove /manifests/tag or /blobs/sha
|
||||
let repoName = repoParts.slice(0, -2).join('/'); // Remove /manifests/tag or /blobs/sha
|
||||
|
||||
// Special handling for Docker Hub: official images need 'library/' prefix
|
||||
// Docker Hub stores official images like nginx, redis, etc. as library/nginx, library/redis
|
||||
if (platform === 'cr-docker' && repoName && !repoName.includes('/')) {
|
||||
repoName = `library/${repoName}`;
|
||||
}
|
||||
|
||||
if (repoName) {
|
||||
scope = `repository:${repoName}:pull`;
|
||||
}
|
||||
|
||||
@@ -207,6 +207,7 @@ describe('Container Registry Support', () => {
|
||||
|
||||
describe('Container Registry Platform Support', () => {
|
||||
const containerRegistries = [
|
||||
{ name: 'Docker Hub', prefix: 'cr/docker', expectedStatus: [200, 301, 302, 401, 404] },
|
||||
{ name: 'Quay.io', prefix: 'cr/quay', expectedStatus: [200, 301, 302, 401, 404] },
|
||||
{
|
||||
name: 'Google Container Registry',
|
||||
@@ -235,4 +236,60 @@ describe('Container Registry Support', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Docker Hub Specific Tests', () => {
|
||||
it('should handle Docker Hub official images (single-name images)', async () => {
|
||||
// Official images like nginx, redis are stored as library/nginx in Docker Hub
|
||||
const testUrl = 'https://example.com/cr/docker/v2/nginx/manifests/latest';
|
||||
const response = await SELF.fetch(testUrl, {
|
||||
headers: {
|
||||
Accept: 'application/vnd.docker.distribution.manifest.v2+json'
|
||||
}
|
||||
});
|
||||
|
||||
// Should attempt to proxy to Docker Hub
|
||||
expect(response.status).not.toBe(400);
|
||||
});
|
||||
|
||||
it('should handle Docker Hub user images (namespace/image format)', async () => {
|
||||
// User images already have namespace prefix
|
||||
const testUrl = 'https://example.com/cr/docker/v2/nginxinc/nginx-unprivileged/manifests/latest';
|
||||
const response = await SELF.fetch(testUrl, {
|
||||
headers: {
|
||||
Accept: 'application/vnd.docker.distribution.manifest.v2+json'
|
||||
}
|
||||
});
|
||||
|
||||
// Should attempt to proxy to Docker Hub
|
||||
expect(response.status).not.toBe(400);
|
||||
});
|
||||
|
||||
it('should allow GET for Docker Hub manifest requests', async () => {
|
||||
const response = await SELF.fetch(
|
||||
'https://example.com/cr/docker/v2/nginx/manifests/latest',
|
||||
{
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/vnd.docker.distribution.manifest.v2+json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
expect(response.status).not.toBe(405);
|
||||
});
|
||||
|
||||
it('should allow HEAD for Docker Hub manifest requests', async () => {
|
||||
const response = await SELF.fetch(
|
||||
'https://example.com/cr/docker/v2/nginx/manifests/latest',
|
||||
{
|
||||
method: 'HEAD',
|
||||
headers: {
|
||||
Accept: 'application/vnd.docker.distribution.manifest.v2+json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
expect(response.status).not.toBe(405);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user