From 869a1f8c02ec1a85f23d25abd8f18584bc2f9817 Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Sat, 25 Apr 2026 18:09:12 +1000 Subject: [PATCH] feat: enforce include_patterns on docker /v2/ proxy route MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds pattern checking to docker_v2_proxy before any upstream fetch. Patterns match against the full path and the image name (first two path segments), bypassing the index-file exemption that check_artifact_patterns applies — so restrictions apply equally to manifests, blobs, and tag lists. Returns 403 when no pattern matches, consistent with the non-docker route. --- src/artifactapi/main.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/artifactapi/main.py b/src/artifactapi/main.py index b7917dc..5c48ab2 100644 --- a/src/artifactapi/main.py +++ b/src/artifactapi/main.py @@ -452,6 +452,15 @@ async def docker_v2_proxy(request: Request, remote_name: str, path: str): if remote_config.get("type") != "docker": raise HTTPException(status_code=400, detail=f"Remote '{remote_name}' is not a docker remote") + # Check include_patterns against the image name (e.g. "library/nginx") + patterns = config.get_repository_patterns(remote_name, "") + if patterns: + path_parts = path.split("/") + image_name = "/".join(path_parts[:2]) if len(path_parts) >= 2 else path + if not any(re.search(p, path) or re.search(p, image_name) for p in patterns): + logger.info(f"PATTERN BLOCKED: {remote_name}/{path}") + raise HTTPException(status_code=403, detail="Image not allowed by configuration patterns") + remote_url = await construct_remote_url(remote_name, path) cached_key = storage.get_object_key(remote_name, path)