127
127
from .retry import retry
128
128
from .utils import get_artifact_path
129
129
from .utils import get_basicauth
130
+ from .utils import get_mime_type_header
130
131
from .utils import get_params
131
132
from .utils import get_project_headers
132
133
from .utils import get_repo_path
@@ -2336,6 +2337,100 @@ async def get_project_summary(
2336
2337
)
2337
2338
return self .construct_model (ProjectSummary , summary )
2338
2339
2340
+ # GET /projects/{project_name_or_id}/artifacts
2341
+ async def get_project_artifacts (
2342
+ self ,
2343
+ project_name_or_id : Union [str , int ],
2344
+ query : Optional [str ] = None ,
2345
+ sort : Optional [str ] = None ,
2346
+ page : int = 1 ,
2347
+ page_size : int = 10 ,
2348
+ limit : Optional [int ] = None ,
2349
+ latest : bool = False ,
2350
+ with_tag : bool = False ,
2351
+ with_label : bool = False ,
2352
+ with_scan_overview : bool = False ,
2353
+ with_sbom_overview : bool = False ,
2354
+ with_immutable_status : bool = False ,
2355
+ with_accessory : bool = False ,
2356
+ mime_type : Union [str , Sequence [str ]] = DEFAULT_MIME_TYPES ,
2357
+ ) -> List [Artifact ]:
2358
+ """Get artifatcs for a project.
2359
+
2360
+ Parameters
2361
+ ----------
2362
+ project_name_or_id : Union[str, int]
2363
+ The name or ID of the project
2364
+ String arguments are treated as project names.
2365
+ Integer arguments are treated as project IDs.
2366
+ query : Optional[str]
2367
+ Query string to filter the artifacts.
2368
+
2369
+ Supported query patterns are:
2370
+
2371
+ * exact match(`"k=v"`)
2372
+ * fuzzy match(`"k=~v"`)
2373
+ * range(`"k=[min~max]"`)
2374
+ * list with union releationship(`"k={v1 v2 v3}"`)
2375
+ * list with intersection relationship(`"k=(v1 v2 v3)`).
2376
+
2377
+ The value of range and list can be:
2378
+
2379
+ * string(enclosed by `"` or `'`)
2380
+ * integer
2381
+ * time(in format `"2020-04-09 02:36:00"`)
2382
+
2383
+ All of these query patterns should be put in the query string
2384
+ and separated by `","`. e.g. `"k1=v1,k2=~v2,k3=[min~max]"`
2385
+ sort : Optional[str]
2386
+ The sort order of the artifacts.
2387
+ page : int
2388
+ The page of results to return
2389
+ page_size : int
2390
+ The number of results to return per page
2391
+ limit : Optional[int]
2392
+ The maximum number of results to return
2393
+ latest : bool
2394
+ Whether to return only the latest version of each artifact
2395
+ with_tag : bool
2396
+ Whether to include the tags of the artifacts
2397
+ with_label : bool
2398
+ Whether to include the labels of the artifacts
2399
+ with_scan_overview : bool
2400
+ Whether to include the scan overview of the artifacts
2401
+ with_sbom_overview : bool
2402
+ Whether to include the SBOM overview of the artifacts
2403
+ with_immutable_status : bool
2404
+ Whether to include the immutable status of the artifacts
2405
+ with_accessory : bool
2406
+ Whether to include the accessory of the artifacts
2407
+ mime_type : Union[str, Sequence[str]]
2408
+ MIME types for the scan report or scan summary. The first mime type will be used when a report is found for it.
2409
+ Can be a list of MIME types or a single MIME type.
2410
+ """
2411
+ params = get_params (
2412
+ q = query ,
2413
+ sort = sort ,
2414
+ page = page ,
2415
+ page_size = page_size ,
2416
+ latest = latest ,
2417
+ with_tag = with_tag ,
2418
+ with_label = with_label ,
2419
+ with_scan_overview = with_scan_overview ,
2420
+ with_sbom_overview = with_sbom_overview ,
2421
+ with_immutable_status = with_immutable_status ,
2422
+ with_accessory = with_accessory ,
2423
+ )
2424
+ headers = get_project_headers (project_name_or_id )
2425
+ headers .update (get_mime_type_header (mime_type ))
2426
+ resp = await self .get (
2427
+ f"/projects/{ project_name_or_id } /artifacts" ,
2428
+ params = params ,
2429
+ headers = headers ,
2430
+ limit = limit ,
2431
+ )
2432
+ return self .construct_model (Artifact , resp , is_list = True )
2433
+
2339
2434
# GET /projects/{project_name_or_id}/_deletable
2340
2435
async def get_project_deletable (
2341
2436
self , project_name_or_id : Union [str , int ]
@@ -3512,7 +3607,7 @@ async def copy_artifact(
3512
3607
)
3513
3608
return urldecode_header (resp , "Location" )
3514
3609
3515
- # GET /projects/{project_name }/repositories/{repository_name}/artifacts
3610
+ # GET /projects/{project_name_or_id }/repositories/{repository_name}/artifacts
3516
3611
async def get_artifacts (
3517
3612
self ,
3518
3613
project_name : str ,
@@ -3525,10 +3620,11 @@ async def get_artifacts(
3525
3620
with_tag : bool = True ,
3526
3621
with_label : bool = False ,
3527
3622
with_scan_overview : bool = False ,
3623
+ with_sbom_overview : bool = False ,
3528
3624
with_signature : bool = False ,
3529
3625
with_immutable_status : bool = False ,
3530
3626
with_accessory : bool = False ,
3531
- mime_type : str = "application/vnd.security.vulnerability.report; version=1.1" ,
3627
+ mime_type : Union [ str , Sequence [ str ]] = DEFAULT_MIME_TYPES ,
3532
3628
** kwargs : Any ,
3533
3629
) -> List [Artifact ]:
3534
3630
"""Get the artifacts in a repository.
@@ -3572,21 +3668,18 @@ async def get_artifacts(
3572
3668
Whether to include the labels of the artifact in the response
3573
3669
with_scan_overview : bool
3574
3670
Whether to include the scan overview of the artifact in the response
3671
+ with_sbom_overview : bool
3672
+ Whether to include the SBOM overview of the artifacts
3575
3673
with_signature : bool
3576
3674
Whether the signature is included inside the tags of the returning artifacts.
3577
3675
Only works when setting `with_tag==True`.
3578
3676
with_immutable_status : bool
3579
3677
Whether the immutable status is included inside the tags of the returning artifacts.
3580
3678
with_accessory : bool
3581
3679
Whether the accessories are included of the returning artifacts.
3582
- mime_type : str
3583
- A comma-separated lists of MIME types for the scan report or scan summary.
3584
- The first mime type will be used when the report found for it.
3585
- Currently the mime type supports:
3586
-
3587
- * application/vnd.scanner.adapter.vuln.report.harbor+json; version=1.0
3588
- * application/vnd.security.vulnerability.report; version=1.1
3589
-
3680
+ mime_type : Union[str, Sequence[str]]
3681
+ MIME types for the scan report or scan summary. The first mime type will be used when a report is found for it.
3682
+ Can be a list of MIME types or a single MIME type.
3590
3683
Returns
3591
3684
-------
3592
3685
List[Artifact]
@@ -3601,14 +3694,15 @@ async def get_artifacts(
3601
3694
with_tag = with_tag ,
3602
3695
with_label = with_label ,
3603
3696
with_scan_overview = with_scan_overview ,
3697
+ with_sbom_overview = with_scan_overview ,
3604
3698
with_signature = with_signature ,
3605
3699
with_immutable_status = with_immutable_status ,
3606
3700
with_accessory = with_accessory ,
3607
3701
)
3608
3702
resp = await self .get (
3609
3703
path ,
3610
3704
params = params ,
3611
- headers = { "X-Accept-Vulnerabilities" : mime_type } ,
3705
+ headers = get_mime_type_header ( mime_type ) ,
3612
3706
limit = limit ,
3613
3707
)
3614
3708
return self .construct_model (Artifact , resp , is_list = True )
@@ -3655,7 +3749,8 @@ async def get_artifact(
3655
3749
with_signature : bool = False ,
3656
3750
with_immutable_status : bool = False ,
3657
3751
with_accessory : bool = False ,
3658
- mime_type : str = "application/vnd.security.vulnerability.report; version=1.1" ,
3752
+ with_sbom_overview : bool = False ,
3753
+ mime_type : Union [str , Sequence [str ]] = DEFAULT_MIME_TYPES ,
3659
3754
) -> Artifact :
3660
3755
"""Get an artifact.
3661
3756
@@ -3684,6 +3779,8 @@ async def get_artifact(
3684
3779
Whether the immutable status is included inside the tags of the returning artifact.
3685
3780
with_accessory : bool
3686
3781
Whether the accessories are included of the returning artifact.
3782
+ with_sbom_overview : bool
3783
+ Whether the sbom overview is included of the returning artifact.
3687
3784
mime_type : str
3688
3785
A comma-separated lists of MIME types for the scan report or scan summary.
3689
3786
The first mime type will be used when the report found for it.
@@ -3709,8 +3806,9 @@ async def get_artifact(
3709
3806
"with_signature" : with_signature ,
3710
3807
"with_immutable_status" : with_immutable_status ,
3711
3808
"with_accessory" : with_accessory ,
3809
+ "with_sbom_overview" : with_sbom_overview ,
3712
3810
},
3713
- headers = { "X-Accept-Vulnerabilities" : mime_type } ,
3811
+ headers = get_mime_type_header ( mime_type ) ,
3714
3812
)
3715
3813
return self .construct_model (Artifact , resp )
3716
3814
@@ -3841,15 +3939,7 @@ async def get_artifact_vulnerability_reports(
3841
3939
"""
3842
3940
path = get_artifact_path (project_name , repository_name , reference )
3843
3941
url = f"{ path } /additions/vulnerabilities"
3844
- # NOTE: in the offical API spec, a comma AND space is used to separate:
3845
- # https://github.com/goharbor/harbor/blob/df4ab856c7597e6fe28b466ba8419257de8a1af7/api/v2.0/swagger.yaml#L6256
3846
- if not isinstance (mime_type , str ):
3847
- mime_type_param = ", " .join (mime_type )
3848
- else :
3849
- mime_type_param = mime_type
3850
- resp = await self .get (
3851
- url , headers = {"X-Accept-Vulnerabilities" : mime_type_param }
3852
- )
3942
+ resp = await self .get (url , headers = get_mime_type_header (mime_type ))
3853
3943
if not isinstance (resp , dict ):
3854
3944
raise UnprocessableEntity (f"Unable to process response from { url } : { resp } " )
3855
3945
reports : FirstDict [str , HarborVulnerabilityReport ] = FirstDict ()
0 commit comments