prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  OCI Registry Blueprint port ignored
  **Describe the bug**
  When I try to load blueprints from a registry running on a custom port (e.g. port 5050) the connection fails.
  
  **To Reproduce**
  Steps to reproduce the behavior:
  
  1. Go to `Costomization > Blueprints`
  2. Create a new `OCI Registry` Blueprint with a non default Port
  3. Example `oci://larsl.dev:5050/larsl-net/authentik-config/blueprints/larsl-stages-base:latest`
  4. A connection error occurs
  
  **Expected behavior**
  authentik connects on the port specified in the URL (5050). What happens according to the error message is that authentik uses port 443.
  
  **Logs**
  ```
  HTTPSConnectionPool(host='larsl.dev', port=443): Max retries exceeded with url: /v2/larsl-net/authentik-config/blueprints/larsl-stages-base/manifests/latest (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f2e26efa690>: Failed to establish a new connection: [Errno 111] Connection refused'))
  ```
  
  **Version and Deployment (please complete the following information):**
  
  -   authentik version: 2023.5.1
  -   Deployment: docker-compose
  
  
  </issue>
  <code>
  [start of authentik/blueprints/v1/oci.py]
  1 """OCI Client"""
  2 from typing import Any
  3 from urllib.parse import ParseResult, urlparse
  4 
  5 from opencontainers.distribution.reggie import (
  6     NewClient,
  7     WithDebug,
  8     WithDefaultName,
  9     WithDigest,
  10     WithReference,
  11     WithUserAgent,
  12     WithUsernamePassword,
  13 )
  14 from requests.exceptions import RequestException
  15 from structlog import get_logger
  16 from structlog.stdlib import BoundLogger
  17 
  18 from authentik.lib.sentry import SentryIgnoredException
  19 from authentik.lib.utils.http import authentik_user_agent
  20 
  21 OCI_MEDIA_TYPE = "application/vnd.goauthentik.blueprint.v1+yaml"
  22 
  23 
  24 class OCIException(SentryIgnoredException):
  25     """OCI-related errors"""
  26 
  27 
  28 class BlueprintOCIClient:
  29     """Blueprint OCI Client"""
  30 
  31     url: ParseResult
  32     sanitized_url: str
  33     logger: BoundLogger
  34     ref: str
  35     client: NewClient
  36 
  37     def __init__(self, url: str) -> None:
  38         self._parse_url(url)
  39         self.logger = get_logger().bind(url=self.sanitized_url)
  40 
  41         self.ref = "latest"
  42         path = self.url.path[1:]
  43         if ":" in self.url.path:
  44             path, _, self.ref = path.partition(":")
  45         self.client = NewClient(
  46             f"https://{self.url.hostname}",
  47             WithUserAgent(authentik_user_agent()),
  48             WithUsernamePassword(self.url.username, self.url.password),
  49             WithDefaultName(path),
  50             WithDebug(True),
  51         )
  52 
  53     def _parse_url(self, url: str):
  54         self.url = urlparse(url)
  55         netloc = self.url.netloc
  56         if "@" in netloc:
  57             netloc = netloc[netloc.index("@") + 1 :]
  58         self.sanitized_url = self.url._replace(netloc=netloc).geturl()
  59 
  60     def fetch_manifests(self) -> dict[str, Any]:
  61         """Fetch manifests for ref"""
  62         self.logger.info("Fetching OCI manifests for blueprint")
  63         manifest_request = self.client.NewRequest(
  64             "GET",
  65             "/v2/<name>/manifests/<reference>",
  66             WithReference(self.ref),
  67         ).SetHeader("Accept", "application/vnd.oci.image.manifest.v1+json")
  68         try:
  69             manifest_response = self.client.Do(manifest_request)
  70             manifest_response.raise_for_status()
  71         except RequestException as exc:
  72             raise OCIException(exc) from exc
  73         manifest = manifest_response.json()
  74         if "errors" in manifest:
  75             raise OCIException(manifest["errors"])
  76         return manifest
  77 
  78     def fetch_blobs(self, manifest: dict[str, Any]):
  79         """Fetch blob based on manifest info"""
  80         blob = None
  81         for layer in manifest.get("layers", []):
  82             if layer.get("mediaType", "") == OCI_MEDIA_TYPE:
  83                 blob = layer.get("digest")
  84                 self.logger.debug("Found layer with matching media type", blob=blob)
  85         if not blob:
  86             raise OCIException("Blob not found")
  87 
  88         blob_request = self.client.NewRequest(
  89             "GET",
  90             "/v2/<name>/blobs/<digest>",
  91             WithDigest(blob),
  92         )
  93         try:
  94             blob_response = self.client.Do(blob_request)
  95             blob_response.raise_for_status()
  96             return blob_response.text
  97         except RequestException as exc:
  98             raise OCIException(exc) from exc
  99
  [end of authentik/blueprints/v1/oci.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/authentik/blueprints/v1/oci.py b/authentik/blueprints/v1/oci.py
  --- a/authentik/blueprints/v1/oci.py
  +++ b/authentik/blueprints/v1/oci.py
  @@ -39,11 +39,16 @@
           self.logger = get_logger().bind(url=self.sanitized_url)
   
           self.ref = "latest"
  +        # Remove the leading slash of the path to convert it to an image name
           path = self.url.path[1:]
  -        if ":" in self.url.path:
  +        if ":" in path:
  +            # if there's a colon in the path, use everything after it as a ref
               path, _, self.ref = path.partition(":")
  +        base_url = f"https://{self.url.hostname}"
  +        if self.url.port:
  +            base_url += f":{self.url.port}"
           self.client = NewClient(
  -            f"https://{self.url.hostname}",
  +            base_url,
               WithUserAgent(authentik_user_agent()),
               WithUsernamePassword(self.url.username, self.url.password),
               WithDefaultName(path),
  
verification_info: {"golden_diff": "diff --git a/authentik/blueprints/v1/oci.py b/authentik/blueprints/v1/oci.py\n--- a/authentik/blueprints/v1/oci.py\n+++ b/authentik/blueprints/v1/oci.py\n@@ -39,11 +39,16 @@\n         self.logger = get_logger().bind(url=self.sanitized_url)\n \n         self.ref = \"latest\"\n+        # Remove the leading slash of the path to convert it to an image name\n         path = self.url.path[1:]\n-        if \":\" in self.url.path:\n+        if \":\" in path:\n+            # if there's a colon in the path, use everything after it as a ref\n             path, _, self.ref = path.partition(\":\")\n+        base_url = f\"https://{self.url.hostname}\"\n+        if self.url.port:\n+            base_url += f\":{self.url.port}\"\n         self.client = NewClient(\n-            f\"https://{self.url.hostname}\",\n+            base_url,\n             WithUserAgent(authentik_user_agent()),\n             WithUsernamePassword(self.url.username, self.url.password),\n             WithDefaultName(path),\n", "issue": "OCI Registry Blueprint port ignored\n**Describe the bug**\r\nWhen I try to load blueprints from a registry running on a custom port (e.g. port 5050) the connection fails.\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n\r\n1. Go to `Costomization > Blueprints`\r\n2. Create a new `OCI Registry` Blueprint with a non default Port\r\n3. Example `oci://larsl.dev:5050/larsl-net/authentik-config/blueprints/larsl-stages-base:latest`\r\n4. A connection error occurs\r\n\r\n**Expected behavior**\r\nauthentik connects on the port specified in the URL (5050). What happens according to the error message is that authentik uses port 443.\r\n\r\n**Logs**\r\n```\r\nHTTPSConnectionPool(host='larsl.dev', port=443): Max retries exceeded with url: /v2/larsl-net/authentik-config/blueprints/larsl-stages-base/manifests/latest (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f2e26efa690>: Failed to establish a new connection: [Errno 111] Connection refused'))\r\n```\r\n\r\n**Version and Deployment (please complete the following information):**\r\n\r\n-   authentik version: 2023.5.1\r\n-   Deployment: docker-compose\r\n\n", "before_files": [{"content": "\"\"\"OCI Client\"\"\"\nfrom typing import Any\nfrom urllib.parse import ParseResult, urlparse\n\nfrom opencontainers.distribution.reggie import (\n    NewClient,\n    WithDebug,\n    WithDefaultName,\n    WithDigest,\n    WithReference,\n    WithUserAgent,\n    WithUsernamePassword,\n)\nfrom requests.exceptions import RequestException\nfrom structlog import get_logger\nfrom structlog.stdlib import BoundLogger\n\nfrom authentik.lib.sentry import SentryIgnoredException\nfrom authentik.lib.utils.http import authentik_user_agent\n\nOCI_MEDIA_TYPE = \"application/vnd.goauthentik.blueprint.v1+yaml\"\n\n\nclass OCIException(SentryIgnoredException):\n    \"\"\"OCI-related errors\"\"\"\n\n\nclass BlueprintOCIClient:\n    \"\"\"Blueprint OCI Client\"\"\"\n\n    url: ParseResult\n    sanitized_url: str\n    logger: BoundLogger\n    ref: str\n    client: NewClient\n\n    def __init__(self, url: str) -> None:\n        self._parse_url(url)\n        self.logger = get_logger().bind(url=self.sanitized_url)\n\n        self.ref = \"latest\"\n        path = self.url.path[1:]\n        if \":\" in self.url.path:\n            path, _, self.ref = path.partition(\":\")\n        self.client = NewClient(\n            f\"https://{self.url.hostname}\",\n            WithUserAgent(authentik_user_agent()),\n            WithUsernamePassword(self.url.username, self.url.password),\n            WithDefaultName(path),\n            WithDebug(True),\n        )\n\n    def _parse_url(self, url: str):\n        self.url = urlparse(url)\n        netloc = self.url.netloc\n        if \"@\" in netloc:\n            netloc = netloc[netloc.index(\"@\") + 1 :]\n        self.sanitized_url = self.url._replace(netloc=netloc).geturl()\n\n    def fetch_manifests(self) -> dict[str, Any]:\n        \"\"\"Fetch manifests for ref\"\"\"\n        self.logger.info(\"Fetching OCI manifests for blueprint\")\n        manifest_request = self.client.NewRequest(\n            \"GET\",\n            \"/v2/<name>/manifests/<reference>\",\n            WithReference(self.ref),\n        ).SetHeader(\"Accept\", \"application/vnd.oci.image.manifest.v1+json\")\n        try:\n            manifest_response = self.client.Do(manifest_request)\n            manifest_response.raise_for_status()\n        except RequestException as exc:\n            raise OCIException(exc) from exc\n        manifest = manifest_response.json()\n        if \"errors\" in manifest:\n            raise OCIException(manifest[\"errors\"])\n        return manifest\n\n    def fetch_blobs(self, manifest: dict[str, Any]):\n        \"\"\"Fetch blob based on manifest info\"\"\"\n        blob = None\n        for layer in manifest.get(\"layers\", []):\n            if layer.get(\"mediaType\", \"\") == OCI_MEDIA_TYPE:\n                blob = layer.get(\"digest\")\n                self.logger.debug(\"Found layer with matching media type\", blob=blob)\n        if not blob:\n            raise OCIException(\"Blob not found\")\n\n        blob_request = self.client.NewRequest(\n            \"GET\",\n            \"/v2/<name>/blobs/<digest>\",\n            WithDigest(blob),\n        )\n        try:\n            blob_response = self.client.Do(blob_request)\n            blob_response.raise_for_status()\n            return blob_response.text\n        except RequestException as exc:\n            raise OCIException(exc) from exc\n", "path": "authentik/blueprints/v1/oci.py"}]}