Skip to content

Commit a9f04ab

Browse files
committed
fix(provider): load auth configs before making requests to container registry
- Add authentication config loading before making requests to container registry by using decorators. Now all user callable public methods have the ability to load authentication configs if it's needed. Signed-off-by: diverger <diverger@live.cn>
1 parent b63ede0 commit a9f04ab

File tree

5 files changed

+77
-11
lines changed

5 files changed

+77
-11
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ and **Merged pull requests**. Critical items to know are:
1414
The versions coincide with releases on pip. Only major versions will be released as tags on Github.
1515

1616
## [0.0.x](https://github.com/oras-project/oras-py/tree/main) (0.0.x)
17+
- Add authentication config loading before making requests to container registry (0.2.34)
18+
- Affected methods: 'delete_tag()', 'get_tags()', 'get_blob()', 'put_upload()', 'blob_exists()', 'chunked_upload()' and 'upload_manifest()'
1719
- fix 'get_manifest()' method with adding 'load_configs()' calling (0.2.33)
1820
- fix 'Provider' method signature to allow custom CA-Bundles (0.2.32)
1921
- initialize headers variable in do_request (0.2.31)

oras/auth/base.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import oras.auth.utils as auth_utils
1111
import oras.container
1212
import oras.decorator as decorator
13+
import oras.utils
1314
from oras.logger import logger
1415
from oras.types import container_type
1516

@@ -106,6 +107,23 @@ def load_configs(self, container: container_type, configs: Optional[list] = None
106107
if self._load_auth(registry):
107108
return
108109

110+
def ensure_auth_for_container(self, container: container_type):
111+
"""
112+
Ensure authentication is loaded for a specific container's registry.
113+
This assumes auths have already been loaded via load_configs or __init__.
114+
115+
:param container: the parsed container URI with components
116+
:type container: oras.container.Container
117+
"""
118+
# Convert to container if needed
119+
if not isinstance(container, oras.container.Container):
120+
container = self.get_container(container)
121+
122+
# Try to load auth for this container's registry
123+
for registry in oras.utils.iter_localhosts(container.registry): # type: ignore
124+
if self._load_auth(registry):
125+
return
126+
109127
def set_token_auth(self, token: str):
110128
"""
111129
Set token authentication.

oras/decorator.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,30 @@ def wrapper(cls, *args, **kwargs):
2828
return wrapper
2929

3030

31+
def ensure_auth(func):
32+
"""
33+
Ensure authentication is loaded for the container's registry.
34+
This decorator should be applied after @ensure_container.
35+
"""
36+
37+
@wraps(func)
38+
def wrapper(cls, *args, **kwargs):
39+
# Get the container from the first argument (after ensure_container processing)
40+
container = None
41+
if "container" in kwargs:
42+
container = kwargs["container"]
43+
elif args:
44+
container = args[0]
45+
46+
if container and hasattr(cls, "auth"):
47+
# Load auth for this specific container's registry without reloading configs
48+
cls.auth.ensure_auth_for_container(container)
49+
50+
return func(cls, *args, **kwargs)
51+
52+
return wrapper
53+
54+
3155
def retry(attempts=5, timeout=2):
3256
"""
3357
A simple retry decorator

oras/provider.py

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import requests
1717

1818
import oras.auth
19+
import oras.auth.utils
1920
import oras.container
2021
import oras.decorator as decorator
2122
import oras.defaults
@@ -84,6 +85,10 @@ def __init__(
8485
auth_backend, self.session, insecure, tls_verify=tls_verify
8586
)
8687

88+
# Load all authentication configs once during initialization
89+
# This avoids re-reading the docker config file for each operation
90+
self.auth._auths = oras.auth.utils.load_configs()
91+
8792
def __repr__(self) -> str:
8893
return str(self)
8994

@@ -307,6 +312,7 @@ def upload_blob(
307312
return response
308313

309314
@decorator.ensure_container
315+
@decorator.ensure_auth
310316
def delete_tag(self, container: container_type, tag: str) -> bool:
311317
"""
312318
Delete a tag for a container.
@@ -341,6 +347,7 @@ def delete_tag(self, container: container_type, tag: str) -> bool:
341347
return True
342348

343349
@decorator.ensure_container
350+
@decorator.ensure_auth
344351
def get_tags(self, container: container_type, N=None) -> List[str]:
345352
"""
346353
Retrieve tags for a package.
@@ -405,6 +412,7 @@ def _do_paginated_request(
405412
url = urllib.parse.urljoin(base_url, link)
406413

407414
@decorator.ensure_container
415+
@decorator.ensure_auth
408416
def get_blob(
409417
self,
410418
container: container_type,
@@ -516,6 +524,8 @@ def download_blob(
516524
raise e
517525
return outfile
518526

527+
@decorator.ensure_container
528+
@decorator.ensure_auth
519529
def put_upload(
520530
self,
521531
blob: str,
@@ -561,6 +571,8 @@ def put_upload(
561571
)
562572
return response
563573

574+
@decorator.ensure_container
575+
@decorator.ensure_auth
564576
def blob_exists(self, layer: dict, container: oras.container.Container) -> bool:
565577
"""
566578
Check if a layer already exists in the registry.
@@ -600,6 +612,8 @@ def _get_location(
600612
session_url = f"{prefix}{session_url}"
601613
return session_url
602614

615+
@decorator.ensure_container
616+
@decorator.ensure_auth
603617
def chunked_upload(
604618
self,
605619
blob: str,
@@ -688,6 +702,8 @@ def _parse_response_errors(self, response: requests.Response):
688702
except Exception:
689703
pass
690704

705+
@decorator.ensure_container
706+
@decorator.ensure_auth
691707
def upload_manifest(
692708
self,
693709
manifest: dict,
@@ -751,9 +767,13 @@ def push(
751767
"""
752768
container = self.get_container(target)
753769
files = files or []
754-
self.auth.load_configs(
755-
container, configs=[config_path] if config_path else None
756-
)
770+
771+
# If a custom config path is provided, load those configs
772+
if config_path:
773+
self.auth.load_configs(container, configs=[config_path])
774+
else:
775+
# Use the already loaded auths with ensure_auth pattern
776+
self.auth.ensure_auth_for_container(container)
757777

758778
# Prepare a new manifest
759779
manifest = oras.oci.NewManifest()
@@ -866,6 +886,7 @@ def push(
866886
print(f"Successfully pushed {container}")
867887
return response
868888

889+
@decorator.ensure_auth
869890
def pull(
870891
self,
871892
target: str,
@@ -891,9 +912,13 @@ def pull(
891912
:type target: str
892913
"""
893914
container = self.get_container(target)
894-
self.auth.load_configs(
895-
container, configs=[config_path] if config_path else None
896-
)
915+
916+
# If a custom config path is provided, load those configs
917+
if config_path:
918+
self.auth.load_configs(container, configs=[config_path])
919+
else:
920+
# Use the already loaded auths with ensure_auth pattern
921+
self.auth.ensure_auth_for_container(container)
897922
manifest = self.get_manifest(container, allowed_media_type)
898923
outdir = outdir or oras.utils.get_tmpdir()
899924
overwrite = overwrite
@@ -933,6 +958,7 @@ def pull(
933958
return files
934959

935960
@decorator.ensure_container
961+
@decorator.ensure_auth
936962
def get_manifest(
937963
self,
938964
container: container_type,
@@ -946,10 +972,6 @@ def get_manifest(
946972
:param allowed_media_type: one or more allowed media types
947973
:type allowed_media_type: str
948974
"""
949-
# Load authentication configs for the container's registry
950-
# This ensures credentials are available for authenticated registries
951-
self.auth.load_configs(container)
952-
953975
if not allowed_media_type:
954976
allowed_media_type = [oras.defaults.default_manifest_media_type]
955977
headers = {"Accept": ";".join(allowed_media_type)}

oras/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
__copyright__ = "Copyright The ORAS Authors."
33
__license__ = "Apache-2.0"
44

5-
__version__ = "0.2.33"
5+
__version__ = "0.2.34"
66
AUTHOR = "Vanessa Sochat"
77
EMAIL = "vsoch@users.noreply.github.com"
88
NAME = "oras"

0 commit comments

Comments
 (0)