Skip to content

Commit 545b16f

Browse files
authored
Update headers in do_request method, provider.py (#129)
* Update headers in do_request method, provider.py During the push operation POST and PUT methods loose provided auth headers. It is crucial for remote registry, since further re-auth logic tries to reach registry locally. do_request method is updated to include always 'Authorization' header if it is provided. Added refresh_headers flag to allow user to keep basic auth in headers during the push flow Signed-off-by: my5cents <julie.zag@gmail.com>
1 parent 592cf4c commit 545b16f

File tree

4 files changed

+58
-9
lines changed

4 files changed

+58
-9
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ oras.egg-info/
55
.env
66
env
77
__pycache__
8+
.python-version

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ 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 option to not refresh headers during the pushing flow, useful for push with basic auth (0.1.29)
1718
- enable additionalProperties in schema validation (0.1.28)
1819
- Introduce the option to not refresh headers when fetching manifests when pulling artifacts (0.1.27)
1920
- To make it available for more OCI registries, the value of config used when `manifest_config` is not specified in `client.push()` has been changed from a pure empty string to `{}` (0.1.26)

oras/provider.py

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ def upload_blob(
226226
container: container_type,
227227
layer: dict,
228228
do_chunked: bool = False,
229+
refresh_headers: bool = True,
229230
) -> requests.Response:
230231
"""
231232
Prepare and upload a blob.
@@ -239,6 +240,8 @@ def upload_blob(
239240
:type container: oras.container.Container or str
240241
:param layer: dict from oras.oci.NewLayer
241242
:type layer: dict
243+
:param refresh_headers: if true, headers are refreshed
244+
:type refresh_headers: bool
242245
"""
243246
blob = os.path.abspath(blob)
244247
container = self.get_container(container)
@@ -250,9 +253,13 @@ def upload_blob(
250253
# This is currently disabled unless the user asks for it, as
251254
# it doesn't seem to work for all registries
252255
if not do_chunked:
253-
response = self.put_upload(blob, container, layer)
256+
response = self.put_upload(
257+
blob, container, layer, refresh_headers=refresh_headers
258+
)
254259
else:
255-
response = self.chunked_upload(blob, container, layer)
260+
response = self.chunked_upload(
261+
blob, container, layer, refresh_headers=refresh_headers
262+
)
256263

257264
# If we have an empty layer digest and the registry didn't accept, just return dummy successful response
258265
if (
@@ -474,7 +481,11 @@ def download_blob(
474481
return outfile
475482

476483
def put_upload(
477-
self, blob: str, container: oras.container.Container, layer: dict
484+
self,
485+
blob: str,
486+
container: oras.container.Container,
487+
layer: dict,
488+
refresh_headers: bool = True,
478489
) -> requests.Response:
479490
"""
480491
Upload to a registry via put.
@@ -485,9 +496,15 @@ def put_upload(
485496
:type container: oras.container.Container or str
486497
:param layer: dict from oras.oci.NewLayer
487498
:type layer: dict
499+
:param refresh_headers: if true, headers are refreshed
500+
:type refresh_headers: bool
488501
"""
489502
# Start an upload session
490503
headers = {"Content-Type": "application/octet-stream"}
504+
505+
if not refresh_headers:
506+
headers.update(self.headers)
507+
491508
upload_url = f"{self.prefix}://{container.upload_blob_url()}"
492509
r = self.do_request(upload_url, "POST", headers=headers)
493510

@@ -541,7 +558,11 @@ def _get_location(
541558
return session_url
542559

543560
def chunked_upload(
544-
self, blob: str, container: oras.container.Container, layer: dict
561+
self,
562+
blob: str,
563+
container: oras.container.Container,
564+
layer: dict,
565+
refresh_headers: bool = True,
545566
) -> requests.Response:
546567
"""
547568
Upload via a chunked upload.
@@ -552,9 +573,14 @@ def chunked_upload(
552573
:type container: oras.container.Container or str
553574
:param layer: dict from oras.oci.NewLayer
554575
:type layer: dict
576+
:param refresh_headers: if true, headers are refreshed
577+
:type refresh_headers: bool
555578
"""
556579
# Start an upload session
557580
headers = {"Content-Type": "application/octet-stream", "Content-Length": "0"}
581+
if not refresh_headers:
582+
headers.update(self.headers)
583+
558584
upload_url = f"{self.prefix}://{container.upload_blob_url()}"
559585
r = self.do_request(upload_url, "POST", headers=headers)
560586

@@ -618,7 +644,10 @@ def _parse_response_errors(self, response: requests.Response):
618644
pass
619645

620646
def upload_manifest(
621-
self, manifest: dict, container: oras.container.Container
647+
self,
648+
manifest: dict,
649+
container: oras.container.Container,
650+
refresh_headers: bool = True,
622651
) -> requests.Response:
623652
"""
624653
Read a manifest file and upload it.
@@ -627,13 +656,19 @@ def upload_manifest(
627656
:type manifest: dict
628657
:param container: parsed container URI
629658
:type container: oras.container.Container or str
659+
:param refresh_headers: if true, headers are refreshed
660+
:type refresh_headers: bool
630661
"""
631662
self.reset_basic_auth()
632663
jsonschema.validate(manifest, schema=oras.schemas.manifest)
633664
headers = {
634665
"Content-Type": oras.defaults.default_manifest_media_type,
635666
"Content-Length": str(len(manifest)),
636667
}
668+
669+
if not refresh_headers:
670+
headers.update(self.headers)
671+
637672
return self.do_request(
638673
f"{self.prefix}://{container.manifest_url()}", # noqa
639674
"PUT",
@@ -659,6 +694,8 @@ def push(self, *args, **kwargs) -> requests.Response:
659694
:type manifest_annotations: dict
660695
:param target: target location to push to
661696
:type target: str
697+
:param refresh_headers: if true or None, headers are refreshed
698+
:type refresh_headers: bool
662699
:param subject: optional subject reference
663700
:type subject: Subject
664701
"""
@@ -675,6 +712,10 @@ def push(self, *args, **kwargs) -> requests.Response:
675712
annotset = oras.oci.Annotations(kwargs.get("annotation_file"))
676713
media_type = None
677714

715+
refresh_headers = kwargs.get("refresh_headers")
716+
if refresh_headers is None:
717+
refresh_headers = True
718+
678719
# Upload files as blobs
679720
for blob in kwargs.get("files", []):
680721
# You can provide a blob + content type
@@ -720,7 +761,9 @@ def push(self, *args, **kwargs) -> requests.Response:
720761
logger.debug(f"Preparing layer {layer}")
721762

722763
# Upload the blob layer
723-
response = self.upload_blob(blob, container, layer)
764+
response = self.upload_blob(
765+
blob, container, layer, refresh_headers=refresh_headers
766+
)
724767
self._check_200_response(response)
725768

726769
# Do we need to cleanup a temporary targz?
@@ -762,13 +805,17 @@ def push(self, *args, **kwargs) -> requests.Response:
762805
if config_file is None
763806
else nullcontext(config_file)
764807
) as config_file:
765-
response = self.upload_blob(config_file, container, conf)
808+
response = self.upload_blob(
809+
config_file, container, conf, refresh_headers=refresh_headers
810+
)
766811

767812
self._check_200_response(response)
768813

769814
# Final upload of the manifest
770815
manifest["config"] = conf
771-
self._check_200_response(self.upload_manifest(manifest, container))
816+
self._check_200_response(
817+
self.upload_manifest(manifest, container, refresh_headers=refresh_headers)
818+
)
772819
print(f"Successfully pushed {container}")
773820
return response
774821

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.1.28"
5+
__version__ = "0.1.29"
66
AUTHOR = "Vanessa Sochat"
77
EMAIL = "vsoch@users.noreply.github.com"
88
NAME = "oras"

0 commit comments

Comments
 (0)