Coverage for src/gitlabracadabra/containers/manifest.py: 72%

40 statements  

« prev     ^ index     » next       coverage.py v7.15.0, created at 2026-07-07 22:55 +0200

1# 

2# Copyright (C) 2019-2025 Mathieu Parent <math.parent@gmail.com> 

3# 

4# This program is free software: you can redistribute it and/or modify 

5# it under the terms of the GNU Lesser General Public License as published by 

6# the Free Software Foundation, either version 3 of the License, or 

7# (at your option) any later version. 

8# 

9# This program is distributed in the hope that it will be useful, 

10# but WITHOUT ANY WARRANTY; without even the implied warranty of 

11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

12# GNU Lesser General Public License for more details. 

13# 

14# You should have received a copy of the GNU Lesser General Public License 

15# along with this program. If not, see <http://www.gnu.org/licenses/>. 

16 

17from __future__ import annotations 

18 

19from gitlabracadabra.containers.blob import Blob 

20from gitlabracadabra.containers.const import ( 

21 DOCKER_MANIFEST_SCHEMA1, 

22 DOCKER_MANIFEST_SCHEMA1_SIGNED, 

23 DOCKER_MANIFEST_SCHEMA2, 

24 DOCKER_MANIFEST_SCHEMA2_LIST, 

25 OCI_IMAGE_INDEX, 

26 OCI_IMAGE_MANIFEST, 

27) 

28from gitlabracadabra.containers.manifest_base import ManifestBase 

29 

30 

31class Manifest(ManifestBase): 

32 """Retrieve Manifest or Manifest list.""" 

33 

34 def manifests(self) -> list[Manifest]: 

35 """Get manifests of the manifest list. 

36 

37 Returns: 

38 A list of manifests. 

39 

40 Raises: 

41 ValueError: Unsupported manifest list type. 

42 """ 

43 if self.mime_type in {DOCKER_MANIFEST_SCHEMA2_LIST, OCI_IMAGE_INDEX}: 43 ↛ 45line 43 didn't jump to line 45 because the condition on line 43 was always true

44 return self._manifests_v2() 

45 msg = f"Unsupported manifest list type {self.mime_type}" 

46 raise ValueError(msg) 

47 

48 def tag_list(self) -> list[str]: 

49 """Get tags of the manifest. 

50 

51 Returns: 

52 A list of tags (strings). 

53 

54 Raises: 

55 ValueError: Expected list got something else. 

56 """ 

57 response = self._registry.request( 

58 "get", 

59 f"/v2/{self.manifest_name}/tags/list", 

60 scopes={self.scope()}, 

61 ) 

62 tags = response.json().get("tags") 

63 if not isinstance(tags, list): 63 ↛ 64line 63 didn't jump to line 64 because the condition on line 63 was never true

64 msg = f"Expected list got {type(tags)}" 

65 raise TypeError(msg) 

66 return tags 

67 

68 def blobs(self) -> list[Blob]: 

69 """Get blobs of the manifest. 

70 

71 Returns: 

72 A list of blobs. 

73 

74 Raises: 

75 ValueError: Unsupported media type. 

76 """ 

77 if self.mime_type in {DOCKER_MANIFEST_SCHEMA2, OCI_IMAGE_MANIFEST}: 

78 return [ 

79 Blob( 

80 self.registry, 

81 self.manifest_name, 

82 layer_json["digest"], 

83 size=layer_json["size"], 

84 mime_type=layer_json["mediaType"], 

85 ) 

86 for layer_json in self.json.get("layers") 

87 ] 

88 if self.mime_type in {DOCKER_MANIFEST_SCHEMA1, DOCKER_MANIFEST_SCHEMA1_SIGNED}: 88 ↛ 98line 88 didn't jump to line 98 because the condition on line 88 was always true

89 return [ 

90 Blob( 

91 self.registry, 

92 self.manifest_name, 

93 fs_layer_json["blobSum"], 

94 mime_type="application/octet-stream", 

95 ) 

96 for fs_layer_json in self.json.get("fsLayers") 

97 ] 

98 msg = f"Unsupported media type: {self.mime_type}" 

99 raise ValueError(msg) 

100 

101 def _manifests_v2(self) -> list[Manifest]: 

102 json = dict(self.json) 

103 schema_version = json.get("schemaVersion") 

104 media_type = json.get("mediaType") 

105 if schema_version != 2: # noqa: PLR2004 105 ↛ 106line 105 didn't jump to line 106 because the condition on line 105 was never true

106 msg = f"Unexpected schema version {schema_version} in OCI Image Index" 

107 raise ValueError(msg) 

108 if media_type not in {DOCKER_MANIFEST_SCHEMA2_LIST, OCI_IMAGE_INDEX, None}: 108 ↛ 109line 108 didn't jump to line 109 because the condition on line 108 was never true

109 msg = f"Unexpected media type {media_type} in OCI Image Index" 

110 raise ValueError(msg) 

111 manifests = [] 

112 for manifest_json in json["manifests"]: 

113 manifest = Manifest( 

114 self.registry, 

115 self.manifest_name, 

116 digest=manifest_json["digest"], 

117 size=manifest_json["size"], 

118 mime_type=manifest_json["mediaType"], 

119 tag=self.tag, 

120 ) 

121 manifest.platform = manifest_json["platform"] 

122 manifests.append(manifest) 

123 return manifests