From 78feb4b49533215c405dea48306878794fa6192e Mon Sep 17 00:00:00 2001 From: Andrei Aaron Date: Thu, 2 Feb 2023 22:46:35 +0200 Subject: [PATCH] docs(graphql): rewrote search.md (#1130) * docs(graphql): rewrote search.md docs(graphql): added pagination and filter docs for gql Squash of both commits: (cherry picked from commit 2268fa0510b32b27f2c1f71e9889ec769877553b) (cherry picked from commit c96adc88b2fb9edff90e7e4b01a8885511ceb0df) Signed-off-by: Catalin Hofnar Some additional updates by Andrei Aaron to keep up with the changes on main. Also add more comments to schema.graphql Signed-off-by: Andrei Aaron * style: run a graphql schemma linter as a github workflow Signed-off-by: Andrei Aaron --------- Signed-off-by: Andrei Aaron Co-authored-by: Catalin Hofnar --- .github/workflows/gqlgen.yaml | 15 +- .../search/gql_generated/generated.go | 467 ++++++++++- .../search/gql_generated/models_gen.go | 272 ++++-- pkg/extensions/search/schema.graphql | 465 +++++++++- pkg/extensions/search/search.md | 791 ++++++++++++++---- 5 files changed, 1695 insertions(+), 315 deletions(-) diff --git a/.github/workflows/gqlgen.yaml b/.github/workflows/gqlgen.yaml index 450a4053..e06489b6 100644 --- a/.github/workflows/gqlgen.yaml +++ b/.github/workflows/gqlgen.yaml @@ -1,7 +1,8 @@ -name: "GQL generation" +name: "GQL generation and linting" # Validate gqlgen works # Validate there are no uncommitted changes after running gqlgen +# Lint the graphql schemma on: push: @@ -34,3 +35,15 @@ jobs: - name: Verify uncommitted files run: | make verify-gql-committed + gqllint: + name: Check GQL schemma follows best practices + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install dependencies + run: | + cd $GITHUB_WORKSPACE + npm install graphql-schema-linter graphql + - name: Lint the graphql schemma + run: | + $(npm bin)/graphql-schema-linter pkg/extensions/search/*.graphql \ No newline at end of file diff --git a/pkg/extensions/search/gql_generated/generated.go b/pkg/extensions/search/gql_generated/generated.go index 510a407b..482ef239 100644 --- a/pkg/extensions/search/gql_generated/generated.go +++ b/pkg/extensions/search/gql_generated/generated.go @@ -947,25 +947,60 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er } var sources = []*ast.Source{ - {Name: "../schema.graphql", Input: `scalar Time + {Name: "../schema.graphql", Input: `# Exclude these linters because current implementation of the clients would need an update +# lint-disable fields-are-camel-cased, input-object-values-are-camel-cased +# Exclude this linter as we have a different implementation for pagination +# lint-disable relay-page-info-spec +# Exclude this linters and fix the issues later +# lint-disable type-fields-sorted-alphabetically, input-object-fields-sorted-alphabetically, enum-values-sorted-alphabetically + +""" +A timestamp +""" +scalar Time """ Contains the tag of the image and a list of CVEs """ type CVEResultForImage { + """ + Tag affected by the CVEs + """ Tag: String + """ + List of CVE objects which afect this specific image:tag + """ CVEList: [CVE] + """ + The CVE pagination information, see PageInfo object for more details + """ Page: PageInfo } """ -Contains various details about the CVE and a list of PackageInfo about the affected packages +Contains various details about the CVE (Common Vulnerabilities and Exposures) +and a list of PackageInfo about the affected packages """ type CVE { + """ + CVE ID + """ Id: String + """ + A short title describing the CVE + """ Title: String + """ + A detailed description of the CVE + """ Description: String + """ + The impact the CVE has, one of "UNKNOWN", "LOW", "MEDIUM", "HIGH", "CRITICAL" + """ Severity: String + """ + Information on the packages in which the CVE was found + """ PackageList: [PackageInfo] } @@ -973,95 +1008,239 @@ type CVE { Contains the name of the package, the current installed version and the version where the CVE was fixed """ type PackageInfo { + """ + Name of the package affected by a CVE + """ Name: String + """ + Current version of the package, typically affected by the CVE + """ InstalledVersion: String + """ + Minimum version of the package in which the CVE is fixed + """ FixedVersion: String } """ -Contains details about the repo: a list of image summaries and a summary of the repo +Contains details about the repo: both general information on the repo, and the list of images """ type RepoInfo { + """ + List of images in the repo + """ Images: [ImageSummary] + """ + Details about the repository itself + """ Summary: RepoSummary } -# Search results in all repos/images/layers -# There will be other more structures for more detailed information """ -Search everything. Can search Images, Repos and Layers +Search results, can contain images, repositories and layers """ type GlobalSearchResult { + """ + Pagination information + """ Page: PageInfo + """ + List of images matching the search criteria + """ Images: [ImageSummary] + """ + List of repositories matching the search criteria + """ Repos: [RepoSummary] + """ + List of layers matching the search criteria + NOTE: the actual search logic for layers is not implemented at the moment + """ Layers: [LayerSummary] } -# Brief on a specific image to be used in queries returning a list of images -# We define an image as a pairing or a repo and a tag belonging to that repo """ -Contains details about the image +Details about a specific image, it is used by queries returning a list of images +We define an image as a pairing or a repository and a tag belonging to that repository """ type ImageSummary { + """ + Name of the repository where the image is found + """ RepoName: String + """ + Tag identifying the image within the repository + """ Tag: String + """ + Digest of the manifest file associated with this image + """ Digest: String + """ + Digest of the config file associated with this image + """ ConfigDigest: String + """ + Timestamp of the last modification done to the image (from config or the last updated layer) + """ LastUpdated: Time + """ + True if the image has a signature associated with it, false otherwise + """ IsSigned: Boolean + """ + Total size of the files associated with this image (manigest, config, layers) + """ Size: String + """ + OS and architecture supported by this image + """ Platform: OsArch + """ + Vendor associated with this image, the distributing entity, organization or individual + """ Vendor: String + """ + Integer used to rank search results by relevance + """ Score: Int + """ + Number of downloads of the manifest of this image + """ DownloadCount: Int + """ + Information on the layers of this image + """ Layers: [LayerSummary] + """ + Human-readable description of the software packaged in the image + """ Description: String - Licenses: String # The value of the annotation if present, 'unknown' otherwise). + """ + License(s) under which contained software is distributed as an SPDX License Expression + """ + Licenses: String + """ + Labels associated with this image + NOTE: currently this field is unused + """ Labels: String + """ + Human-readable title of the image + """ Title: String + """ + URL to get source code for building the image + """ Source: String + """ + URL to get documentation on the image + """ Documentation: String + """ + Information about the history of the specific image, see LayerHistory + """ History: [LayerHistory] + """ + Short summary of the identified CVEs + """ Vulnerabilities: ImageVulnerabilitySummary + """ + Contact details of the people or organization responsible for the image + """ Authors: String } +""" +Contains summary of vulnerabilities found in a specific image +""" type ImageVulnerabilitySummary { + """ + Maximum severity of all CVEs found in this image + """ MaxSeverity: String + """ + Count of all CVEs found in this image + """ Count: Int } -# Brief on a specific repo to be used in queries returning a list of repos """ -Contains details about the repo +Details of a specific repo, it is used by queries returning a list of repos """ type RepoSummary { + """ + Name of the repository + """ Name: String + """ + Timestamp of the last update to an image inside this repository + """ LastUpdated: Time + """ + Total size of the files within this repository + """ Size: String + """ + List of platforms supported by this repository + """ Platforms: [OsArch] + """ + Vendors associated with this image, the distributing entities, organizations or individuals + """ Vendors: [String] + """ + Integer used to rank search results by relevance + """ Score: Int - NewestImage: ImageSummary # Newest based on created timestamp + """ + Details of the newest image inside the repository + NOTE: not the image with the ` + "`" + `latest` + "`" + ` tag, the one with the most recent created timestamp + """ + NewestImage: ImageSummary + """ + Total numer of image manifest downloads from this repository + """ DownloadCount: Int + """ + Number of stars attributed to this repository by users + """ StarCount: Int + """ + True if the repository is bookmarked by the current user, false otherwise + """ IsBookmarked: Boolean + """ + True if the repository is stared by the current user, fale otherwise + """ IsStarred: Boolean } -# Currently the same as LayerInfo, we can refactor later -# For detailed information on the layer a ImageListForDigest call can be made """ -Contains details about the layer +Contains details about a specific layer which is part of an image """ type LayerSummary { + """ + The size of the layer in bytes + """ Size: String # Int64 is not supported. + """ + Digest of the layer content + """ Digest: String + """ + Integer used to rank search results by relevance + """ Score: Int } +""" +Information on how a layer was created +""" type HistoryDescription { + """ + Created is the time when the layer was created. + """ Created: Time """ CreatedBy is the command which created the layer. @@ -1081,135 +1260,335 @@ type HistoryDescription { EmptyLayer: Boolean } +""" +Information about how/when a layer was built +""" type LayerHistory { + """ + Information specific to the layer such as size and digest. + """ Layer: LayerSummary + """ + Additional information about how the layer was created. + """ HistoryDescription: HistoryDescription } +""" +Annotation is Key:Value pair representing custom data which is otherwise +not available in other fields. +""" type Annotation { + """ + Custom key + """ Key: String + """ + Value associated with the custom key + """ Value: String } +""" +A referrer is an object which has a reference to a another object +""" type Referrer { - MediaType: String - ArtifactType: String - Size: Int - Digest: String - Annotations: [Annotation]! + """ + Referrer MediaType + See https://github.com/opencontainers/artifacts for more details + """ + MediaType: String + """ + Referrer ArtifactType + See https://github.com/opencontainers/artifacts for more details + """ + ArtifactType: String + """ + Total size of the referrer files in bytes + """ + Size: Int + """ + Digest of the manifest file of the referrer + """ + Digest: String + """ + A list of annotations associated with this referrer + """ + Annotations: [Annotation]! } """ -Contains details about the supported OS and architecture of the image +Contains details about the OS and architecture of the image """ type OsArch { + """ + The name of the operating system which the image is built to run on, + Should be values listed in the Go Language document https://go.dev/doc/install/source#environment + """ Os: String + """ + The name of the compilation architecture which the image is built to run on, + Should be values listed in the Go Language document https://go.dev/doc/install/source#environment + """ Arch: String } +""" +All sort criteria usable with pagination, some of these criteria applies only +to certain queries. For example sort by severity is available for CVEs but not +for repositories +""" enum SortCriteria { + """ + How relevant the result is based on the user input used while searching + Applies to: images and repositories + """ RELEVANCE + """ + Sort by the most recently created timestamp of the images + Applies to: images and repositories + """ UPDATE_TIME + """ + Sort alphabetically ascending + Applies to: images, repositories and CVEs + """ ALPHABETIC_ASC + """ + Sort alphabetically descending + Applies to: images, repositories and CVEs + """ ALPHABETIC_DSC + """ + Sort from the most severe to the least severe + Applies to: CVEs + """ SEVERITY + """ + Sort by the total number of stars given by users + Applies to: repositories + """ STARS + """ + Sort by the total download count + Applies to: repositories and images + """ DOWNLOADS } +""" +Information on current page returned by the API +""" type PageInfo { + """ + The total number of objects on all pages + """ TotalCount: Int! + """ + The number of objects in this page + """ ItemCount: Int! } -# Pagination parameters +""" +Pagination parameters +If PageInput is empty, the request should return all objects. +""" input PageInput { + """ + The maximum amount of results to return for this page + Negative values are not allowed + """ limit: Int + """ + The results page number you want to receive + Negative values are not allowed + """ offset: Int + """ + The criteria used to sort the results on the page + """ sortBy: SortCriteria } -# Paginated list of RepoSummary objects -# If limit is -1, pagination is disabled +""" +Paginated list of RepoSummary objects +""" type PaginatedReposResult { + """ + Information on the returned page + """ Page: PageInfo + """ + List of repositories + """ Results: [RepoSummary!]! } -# Paginated list of ImageSummary objects -# If limit is -1, pagination is disabled +""" +Paginated list of ImageSummary objects +""" type PaginatedImagesResult { + """ + Information on the returned page + """ Page: PageInfo + """ + List of images + """ Results: [ImageSummary!]! } +""" +Apply various types of filters to the queries made for repositories and images +For example we only want to display repositories which contain images with +a certain OS ar Architecture. +""" input Filter { + """ + Only return images or repositories supporting the operating systems in the list + Should be values listed in the Go Language document https://go.dev/doc/install/source#environment + """ Os: [String] + """ + Only return images or repositories supporting the build architectures in the list + Should be values listed in the Go Language document https://go.dev/doc/install/source#environment + """ Arch: [String] + """ + Only return images or repositories with at least one signature + """ HasToBeSigned: Boolean } +""" +Queries supported by the zot server +""" type Query { """ - Returns a CVE list for the image specified in the argument. Format image:tag + Returns a CVE list for the image specified in the argument """ - CVEListForImage(image: String!, requestedPage: PageInput): CVEResultForImage! + CVEListForImage( + "Image name in format ` + "`" + `repository:tag` + "`" + `" + image: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): CVEResultForImage! """ Returns a list of images vulnerable to the CVE of the specified ID """ - ImageListForCVE(id: String!, requestedPage: PageInput): [ImageSummary!] + ImageListForCVE( + "CVE ID" + id: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): [ImageSummary!] """ - Returns a list of images that are no longer vulnerable to the CVE of the specified ID, from the specified image (repo) + Returns a list of images that are no longer vulnerable to the CVE of the specified ID, + from the specified repository """ - ImageListWithCVEFixed(id: String!, image: String!, requestedPage: PageInput): [ImageSummary!] + ImageListWithCVEFixed( + "CVE ID" + id: String!, + "Repository name" + image: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): [ImageSummary!] """ Returns a list of images which contain the specified digest """ - ImageListForDigest(id: String!, requestedPage: PageInput): [ImageSummary!] + ImageListForDigest( + "Digest to be used in searching for images" + id: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): [ImageSummary!] """ - Returns a list of repos with the newest tag within + Returns a list of repositories with the newest tag (most recently created timestamp) """ - RepoListWithNewestImage(requestedPage: PageInput): PaginatedReposResult! # Newest based on created timestamp + RepoListWithNewestImage( + "Sets the parameters of the requested page" + requestedPage: PageInput + ): PaginatedReposResult! """ - Returns all the images from the specified repo | from all repos if specified repo is "" + Returns all the images from the specified repository | from all repositories if specified repository is "" """ - ImageList(repo: String!, requestedPage: PageInput): [ImageSummary!] + ImageList( + "Repository name" + repo: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): [ImageSummary!] """ - Returns information about the specified repo + Obtain detailed information about a repository and container images within """ - ExpandedRepoInfo(repo: String!): RepoInfo! + ExpandedRepoInfo( + "Repository name" + repo: String! + ): RepoInfo! """ Searches within repos, images, and layers """ - GlobalSearch(query: String!, filter: Filter, requestedPage: PageInput): GlobalSearchResult! + GlobalSearch( + """ + Query string, searches for repository names by default, + when containing ` + "`" + `:` + "`" + ` it searches for tags inside a repository + """ + query: String!, + "Filter to apply on the matches" + filter: Filter, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): GlobalSearchResult! """ List of images which use the argument image """ - DerivedImageList(image: String!, requestedPage: PageInput): PaginatedImagesResult! + DerivedImageList( + "Image name in the format ` + "`" + `repository:tag` + "`" + `" + image: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): PaginatedImagesResult! """ List of images on which the argument image depends on """ - BaseImageList(image: String!, requestedPage: PageInput): PaginatedImagesResult! + BaseImageList( + "Image name in the format ` + "`" + `repository:tag` + "`" + `" + image: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): PaginatedImagesResult! """ Search for a specific image using its name """ - Image(image: String!): ImageSummary + Image( + "Image name in the format ` + "`" + `repository:tag` + "`" + `" + image: String! + ): ImageSummary """ Returns a list of descriptors of an image or artifact manifest that are found in a and have a subject field of Can be filtered based on a specific artifact type """ - Referrers(repo: String!, digest: String!, type: [String!]): [Referrer]! + Referrers( + "Repository name" + repo: String!, + "Digest the referrers are referring to" + digest: String!, + "Types of artifacts to return in the referrer list" + type: [String!] + ): [Referrer]! } `, BuiltIn: false}, } diff --git a/pkg/extensions/search/gql_generated/models_gen.go b/pkg/extensions/search/gql_generated/models_gen.go index ec703dca..c7179c56 100644 --- a/pkg/extensions/search/gql_generated/models_gen.go +++ b/pkg/extensions/search/gql_generated/models_gen.go @@ -9,42 +9,70 @@ import ( "time" ) +// Annotation is Key:Value pair representing custom data which is otherwise +// not available in other fields. type Annotation struct { - Key *string `json:"Key"` + // Custom key + Key *string `json:"Key"` + // Value associated with the custom key Value *string `json:"Value"` } -// Contains various details about the CVE and a list of PackageInfo about the affected packages +// Contains various details about the CVE (Common Vulnerabilities and Exposures) +// and a list of PackageInfo about the affected packages type Cve struct { - ID *string `json:"Id"` - Title *string `json:"Title"` - Description *string `json:"Description"` - Severity *string `json:"Severity"` + // CVE ID + ID *string `json:"Id"` + // A short title describing the CVE + Title *string `json:"Title"` + // A detailed description of the CVE + Description *string `json:"Description"` + // The impact the CVE has, one of "UNKNOWN", "LOW", "MEDIUM", "HIGH", "CRITICAL" + Severity *string `json:"Severity"` + // Information on the packages in which the CVE was found PackageList []*PackageInfo `json:"PackageList"` } // Contains the tag of the image and a list of CVEs type CVEResultForImage struct { - Tag *string `json:"Tag"` - CVEList []*Cve `json:"CVEList"` - Page *PageInfo `json:"Page"` + // Tag affected by the CVEs + Tag *string `json:"Tag"` + // List of CVE objects which afect this specific image:tag + CVEList []*Cve `json:"CVEList"` + // The CVE pagination information, see PageInfo object for more details + Page *PageInfo `json:"Page"` } +// Apply various types of filters to the queries made for repositories and images +// For example we only want to display repositories which contain images with +// a certain OS ar Architecture. type Filter struct { - Os []*string `json:"Os"` - Arch []*string `json:"Arch"` - HasToBeSigned *bool `json:"HasToBeSigned"` + // Only return images or repositories supporting the operating systems in the list + // Should be values listed in the Go Language document https://go.dev/doc/install/source#environment + Os []*string `json:"Os"` + // Only return images or repositories supporting the build architectures in the list + // Should be values listed in the Go Language document https://go.dev/doc/install/source#environment + Arch []*string `json:"Arch"` + // Only return images or repositories with at least one signature + HasToBeSigned *bool `json:"HasToBeSigned"` } -// Search everything. Can search Images, Repos and Layers +// Search results, can contain images, repositories and layers type GlobalSearchResult struct { - Page *PageInfo `json:"Page"` + // Pagination information + Page *PageInfo `json:"Page"` + // List of images matching the search criteria Images []*ImageSummary `json:"Images"` - Repos []*RepoSummary `json:"Repos"` + // List of repositories matching the search criteria + Repos []*RepoSummary `json:"Repos"` + // List of layers matching the search criteria + // NOTE: the actual search logic for layers is not implemented at the moment Layers []*LayerSummary `json:"Layers"` } +// Information on how a layer was created type HistoryDescription struct { + // Created is the time when the layer was created. Created *time.Time `json:"Created"` // CreatedBy is the command which created the layer. CreatedBy *string `json:"CreatedBy"` @@ -56,121 +84,215 @@ type HistoryDescription struct { EmptyLayer *bool `json:"EmptyLayer"` } -// Contains details about the image +// Details about a specific image, it is used by queries returning a list of images +// We define an image as a pairing or a repository and a tag belonging to that repository type ImageSummary struct { - RepoName *string `json:"RepoName"` - Tag *string `json:"Tag"` - Digest *string `json:"Digest"` - ConfigDigest *string `json:"ConfigDigest"` - LastUpdated *time.Time `json:"LastUpdated"` - IsSigned *bool `json:"IsSigned"` - Size *string `json:"Size"` - Platform *OsArch `json:"Platform"` - Vendor *string `json:"Vendor"` - Score *int `json:"Score"` - DownloadCount *int `json:"DownloadCount"` - Layers []*LayerSummary `json:"Layers"` - Description *string `json:"Description"` - Licenses *string `json:"Licenses"` - Labels *string `json:"Labels"` - Title *string `json:"Title"` - Source *string `json:"Source"` - Documentation *string `json:"Documentation"` - History []*LayerHistory `json:"History"` + // Name of the repository where the image is found + RepoName *string `json:"RepoName"` + // Tag identifying the image within the repository + Tag *string `json:"Tag"` + // Digest of the manifest file associated with this image + Digest *string `json:"Digest"` + // Digest of the config file associated with this image + ConfigDigest *string `json:"ConfigDigest"` + // Timestamp of the last modification done to the image (from config or the last updated layer) + LastUpdated *time.Time `json:"LastUpdated"` + // True if the image has a signature associated with it, false otherwise + IsSigned *bool `json:"IsSigned"` + // Total size of the files associated with this image (manigest, config, layers) + Size *string `json:"Size"` + // OS and architecture supported by this image + Platform *OsArch `json:"Platform"` + // Vendor associated with this image, the distributing entity, organization or individual + Vendor *string `json:"Vendor"` + // Integer used to rank search results by relevance + Score *int `json:"Score"` + // Number of downloads of the manifest of this image + DownloadCount *int `json:"DownloadCount"` + // Information on the layers of this image + Layers []*LayerSummary `json:"Layers"` + // Human-readable description of the software packaged in the image + Description *string `json:"Description"` + // License(s) under which contained software is distributed as an SPDX License Expression + Licenses *string `json:"Licenses"` + // Labels associated with this image + // NOTE: currently this field is unused + Labels *string `json:"Labels"` + // Human-readable title of the image + Title *string `json:"Title"` + // URL to get source code for building the image + Source *string `json:"Source"` + // URL to get documentation on the image + Documentation *string `json:"Documentation"` + // Information about the history of the specific image, see LayerHistory + History []*LayerHistory `json:"History"` + // Short summary of the identified CVEs Vulnerabilities *ImageVulnerabilitySummary `json:"Vulnerabilities"` - Authors *string `json:"Authors"` + // Contact details of the people or organization responsible for the image + Authors *string `json:"Authors"` } +// Contains summary of vulnerabilities found in a specific image type ImageVulnerabilitySummary struct { + // Maximum severity of all CVEs found in this image MaxSeverity *string `json:"MaxSeverity"` - Count *int `json:"Count"` + // Count of all CVEs found in this image + Count *int `json:"Count"` } +// Information about how/when a layer was built type LayerHistory struct { - Layer *LayerSummary `json:"Layer"` + // Information specific to the layer such as size and digest. + Layer *LayerSummary `json:"Layer"` + // Additional information about how the layer was created. HistoryDescription *HistoryDescription `json:"HistoryDescription"` } -// Contains details about the layer +// Contains details about a specific layer which is part of an image type LayerSummary struct { - Size *string `json:"Size"` + // The size of the layer in bytes + Size *string `json:"Size"` + // Digest of the layer content Digest *string `json:"Digest"` - Score *int `json:"Score"` + // Integer used to rank search results by relevance + Score *int `json:"Score"` } -// Contains details about the supported OS and architecture of the image +// Contains details about the OS and architecture of the image type OsArch struct { - Os *string `json:"Os"` + // The name of the operating system which the image is built to run on, + // Should be values listed in the Go Language document https://go.dev/doc/install/source#environment + Os *string `json:"Os"` + // The name of the compilation architecture which the image is built to run on, + // Should be values listed in the Go Language document https://go.dev/doc/install/source#environment Arch *string `json:"Arch"` } // Contains the name of the package, the current installed version and the version where the CVE was fixed type PackageInfo struct { - Name *string `json:"Name"` + // Name of the package affected by a CVE + Name *string `json:"Name"` + // Current version of the package, typically affected by the CVE InstalledVersion *string `json:"InstalledVersion"` - FixedVersion *string `json:"FixedVersion"` + // Minimum version of the package in which the CVE is fixed + FixedVersion *string `json:"FixedVersion"` } +// Information on current page returned by the API type PageInfo struct { + // The total number of objects on all pages TotalCount int `json:"TotalCount"` - ItemCount int `json:"ItemCount"` + // The number of objects in this page + ItemCount int `json:"ItemCount"` } +// Pagination parameters +// If PageInput is empty, the request should return all objects. type PageInput struct { - Limit *int `json:"limit"` - Offset *int `json:"offset"` + // The maximum amount of results to return for this page + // Negative values are not allowed + Limit *int `json:"limit"` + // The results page number you want to receive + // Negative values are not allowed + Offset *int `json:"offset"` + // The criteria used to sort the results on the page SortBy *SortCriteria `json:"sortBy"` } +// Paginated list of ImageSummary objects type PaginatedImagesResult struct { - Page *PageInfo `json:"Page"` + // Information on the returned page + Page *PageInfo `json:"Page"` + // List of images Results []*ImageSummary `json:"Results"` } +// Paginated list of RepoSummary objects type PaginatedReposResult struct { - Page *PageInfo `json:"Page"` + // Information on the returned page + Page *PageInfo `json:"Page"` + // List of repositories Results []*RepoSummary `json:"Results"` } +// A referrer is an object which has a reference to a another object type Referrer struct { - MediaType *string `json:"MediaType"` - ArtifactType *string `json:"ArtifactType"` - Size *int `json:"Size"` - Digest *string `json:"Digest"` - Annotations []*Annotation `json:"Annotations"` + // Referrer MediaType + // See https://github.com/opencontainers/artifacts for more details + MediaType *string `json:"MediaType"` + // Referrer ArtifactType + // See https://github.com/opencontainers/artifacts for more details + ArtifactType *string `json:"ArtifactType"` + // Total size of the referrer files in bytes + Size *int `json:"Size"` + // Digest of the manifest file of the referrer + Digest *string `json:"Digest"` + // A list of annotations associated with this referrer + Annotations []*Annotation `json:"Annotations"` } -// Contains details about the repo: a list of image summaries and a summary of the repo +// Contains details about the repo: both general information on the repo, and the list of images type RepoInfo struct { - Images []*ImageSummary `json:"Images"` - Summary *RepoSummary `json:"Summary"` + // List of images in the repo + Images []*ImageSummary `json:"Images"` + // Details about the repository itself + Summary *RepoSummary `json:"Summary"` } -// Contains details about the repo +// Details of a specific repo, it is used by queries returning a list of repos type RepoSummary struct { - Name *string `json:"Name"` - LastUpdated *time.Time `json:"LastUpdated"` - Size *string `json:"Size"` - Platforms []*OsArch `json:"Platforms"` - Vendors []*string `json:"Vendors"` - Score *int `json:"Score"` - NewestImage *ImageSummary `json:"NewestImage"` - DownloadCount *int `json:"DownloadCount"` - StarCount *int `json:"StarCount"` - IsBookmarked *bool `json:"IsBookmarked"` - IsStarred *bool `json:"IsStarred"` + // Name of the repository + Name *string `json:"Name"` + // Timestamp of the last update to an image inside this repository + LastUpdated *time.Time `json:"LastUpdated"` + // Total size of the files within this repository + Size *string `json:"Size"` + // List of platforms supported by this repository + Platforms []*OsArch `json:"Platforms"` + // Vendors associated with this image, the distributing entities, organizations or individuals + Vendors []*string `json:"Vendors"` + // Integer used to rank search results by relevance + Score *int `json:"Score"` + // Details of the newest image inside the repository + // NOTE: not the image with the `latest` tag, the one with the most recent created timestamp + NewestImage *ImageSummary `json:"NewestImage"` + // Total numer of image manifest downloads from this repository + DownloadCount *int `json:"DownloadCount"` + // Number of stars attributed to this repository by users + StarCount *int `json:"StarCount"` + // True if the repository is bookmarked by the current user, false otherwise + IsBookmarked *bool `json:"IsBookmarked"` + // True if the repository is stared by the current user, fale otherwise + IsStarred *bool `json:"IsStarred"` } +// All sort criteria usable with pagination, some of these criteria applies only +// to certain queries. For example sort by severity is available for CVEs but not +// for repositories type SortCriteria string const ( - SortCriteriaRelevance SortCriteria = "RELEVANCE" - SortCriteriaUpdateTime SortCriteria = "UPDATE_TIME" + // How relevant the result is based on the user input used while searching + // Applies to: images and repositories + SortCriteriaRelevance SortCriteria = "RELEVANCE" + // Sort by the most recently created timestamp of the images + // Applies to: images and repositories + SortCriteriaUpdateTime SortCriteria = "UPDATE_TIME" + // Sort alphabetically ascending + // Applies to: images, repositories and CVEs SortCriteriaAlphabeticAsc SortCriteria = "ALPHABETIC_ASC" + // Sort alphabetically descending + // Applies to: images, repositories and CVEs SortCriteriaAlphabeticDsc SortCriteria = "ALPHABETIC_DSC" - SortCriteriaSeverity SortCriteria = "SEVERITY" - SortCriteriaStars SortCriteria = "STARS" - SortCriteriaDownloads SortCriteria = "DOWNLOADS" + // Sort from the most severe to the least severe + // Applies to: CVEs + SortCriteriaSeverity SortCriteria = "SEVERITY" + // Sort by the total number of stars given by users + // Applies to: repositories + SortCriteriaStars SortCriteria = "STARS" + // Sort by the total download count + // Applies to: repositories and images + SortCriteriaDownloads SortCriteria = "DOWNLOADS" ) var AllSortCriteria = []SortCriteria{ diff --git a/pkg/extensions/search/schema.graphql b/pkg/extensions/search/schema.graphql index 3a9062ae..efd67301 100644 --- a/pkg/extensions/search/schema.graphql +++ b/pkg/extensions/search/schema.graphql @@ -1,22 +1,57 @@ +# Exclude these linters because current implementation of the clients would need an update +# lint-disable fields-are-camel-cased, input-object-values-are-camel-cased +# Exclude this linter as we have a different implementation for pagination +# lint-disable relay-page-info-spec +# Exclude this linters and fix the issues later +# lint-disable type-fields-sorted-alphabetically, input-object-fields-sorted-alphabetically, enum-values-sorted-alphabetically + +""" +A timestamp +""" scalar Time """ Contains the tag of the image and a list of CVEs """ type CVEResultForImage { + """ + Tag affected by the CVEs + """ Tag: String + """ + List of CVE objects which afect this specific image:tag + """ CVEList: [CVE] + """ + The CVE pagination information, see PageInfo object for more details + """ Page: PageInfo } """ -Contains various details about the CVE and a list of PackageInfo about the affected packages +Contains various details about the CVE (Common Vulnerabilities and Exposures) +and a list of PackageInfo about the affected packages """ type CVE { + """ + CVE ID + """ Id: String + """ + A short title describing the CVE + """ Title: String + """ + A detailed description of the CVE + """ Description: String + """ + The impact the CVE has, one of "UNKNOWN", "LOW", "MEDIUM", "HIGH", "CRITICAL" + """ Severity: String + """ + Information on the packages in which the CVE was found + """ PackageList: [PackageInfo] } @@ -24,95 +59,239 @@ type CVE { Contains the name of the package, the current installed version and the version where the CVE was fixed """ type PackageInfo { + """ + Name of the package affected by a CVE + """ Name: String + """ + Current version of the package, typically affected by the CVE + """ InstalledVersion: String + """ + Minimum version of the package in which the CVE is fixed + """ FixedVersion: String } """ -Contains details about the repo: a list of image summaries and a summary of the repo +Contains details about the repo: both general information on the repo, and the list of images """ type RepoInfo { + """ + List of images in the repo + """ Images: [ImageSummary] + """ + Details about the repository itself + """ Summary: RepoSummary } -# Search results in all repos/images/layers -# There will be other more structures for more detailed information """ -Search everything. Can search Images, Repos and Layers +Search results, can contain images, repositories and layers """ type GlobalSearchResult { + """ + Pagination information + """ Page: PageInfo + """ + List of images matching the search criteria + """ Images: [ImageSummary] + """ + List of repositories matching the search criteria + """ Repos: [RepoSummary] + """ + List of layers matching the search criteria + NOTE: the actual search logic for layers is not implemented at the moment + """ Layers: [LayerSummary] } -# Brief on a specific image to be used in queries returning a list of images -# We define an image as a pairing or a repo and a tag belonging to that repo """ -Contains details about the image +Details about a specific image, it is used by queries returning a list of images +We define an image as a pairing or a repository and a tag belonging to that repository """ type ImageSummary { + """ + Name of the repository where the image is found + """ RepoName: String + """ + Tag identifying the image within the repository + """ Tag: String + """ + Digest of the manifest file associated with this image + """ Digest: String + """ + Digest of the config file associated with this image + """ ConfigDigest: String + """ + Timestamp of the last modification done to the image (from config or the last updated layer) + """ LastUpdated: Time + """ + True if the image has a signature associated with it, false otherwise + """ IsSigned: Boolean + """ + Total size of the files associated with this image (manigest, config, layers) + """ Size: String + """ + OS and architecture supported by this image + """ Platform: OsArch + """ + Vendor associated with this image, the distributing entity, organization or individual + """ Vendor: String + """ + Integer used to rank search results by relevance + """ Score: Int + """ + Number of downloads of the manifest of this image + """ DownloadCount: Int + """ + Information on the layers of this image + """ Layers: [LayerSummary] + """ + Human-readable description of the software packaged in the image + """ Description: String - Licenses: String # The value of the annotation if present, 'unknown' otherwise). + """ + License(s) under which contained software is distributed as an SPDX License Expression + """ + Licenses: String + """ + Labels associated with this image + NOTE: currently this field is unused + """ Labels: String + """ + Human-readable title of the image + """ Title: String + """ + URL to get source code for building the image + """ Source: String + """ + URL to get documentation on the image + """ Documentation: String + """ + Information about the history of the specific image, see LayerHistory + """ History: [LayerHistory] + """ + Short summary of the identified CVEs + """ Vulnerabilities: ImageVulnerabilitySummary + """ + Contact details of the people or organization responsible for the image + """ Authors: String } +""" +Contains summary of vulnerabilities found in a specific image +""" type ImageVulnerabilitySummary { + """ + Maximum severity of all CVEs found in this image + """ MaxSeverity: String + """ + Count of all CVEs found in this image + """ Count: Int } -# Brief on a specific repo to be used in queries returning a list of repos """ -Contains details about the repo +Details of a specific repo, it is used by queries returning a list of repos """ type RepoSummary { + """ + Name of the repository + """ Name: String + """ + Timestamp of the last update to an image inside this repository + """ LastUpdated: Time + """ + Total size of the files within this repository + """ Size: String + """ + List of platforms supported by this repository + """ Platforms: [OsArch] + """ + Vendors associated with this image, the distributing entities, organizations or individuals + """ Vendors: [String] + """ + Integer used to rank search results by relevance + """ Score: Int - NewestImage: ImageSummary # Newest based on created timestamp + """ + Details of the newest image inside the repository + NOTE: not the image with the `latest` tag, the one with the most recent created timestamp + """ + NewestImage: ImageSummary + """ + Total numer of image manifest downloads from this repository + """ DownloadCount: Int + """ + Number of stars attributed to this repository by users + """ StarCount: Int + """ + True if the repository is bookmarked by the current user, false otherwise + """ IsBookmarked: Boolean + """ + True if the repository is stared by the current user, fale otherwise + """ IsStarred: Boolean } -# Currently the same as LayerInfo, we can refactor later -# For detailed information on the layer a ImageListForDigest call can be made """ -Contains details about the layer +Contains details about a specific layer which is part of an image """ type LayerSummary { + """ + The size of the layer in bytes + """ Size: String # Int64 is not supported. + """ + Digest of the layer content + """ Digest: String + """ + Integer used to rank search results by relevance + """ Score: Int } +""" +Information on how a layer was created +""" type HistoryDescription { + """ + Created is the time when the layer was created. + """ Created: Time """ CreatedBy is the command which created the layer. @@ -132,133 +311,333 @@ type HistoryDescription { EmptyLayer: Boolean } +""" +Information about how/when a layer was built +""" type LayerHistory { + """ + Information specific to the layer such as size and digest. + """ Layer: LayerSummary + """ + Additional information about how the layer was created. + """ HistoryDescription: HistoryDescription } +""" +Annotation is Key:Value pair representing custom data which is otherwise +not available in other fields. +""" type Annotation { + """ + Custom key + """ Key: String + """ + Value associated with the custom key + """ Value: String } +""" +A referrer is an object which has a reference to a another object +""" type Referrer { - MediaType: String - ArtifactType: String - Size: Int - Digest: String - Annotations: [Annotation]! + """ + Referrer MediaType + See https://github.com/opencontainers/artifacts for more details + """ + MediaType: String + """ + Referrer ArtifactType + See https://github.com/opencontainers/artifacts for more details + """ + ArtifactType: String + """ + Total size of the referrer files in bytes + """ + Size: Int + """ + Digest of the manifest file of the referrer + """ + Digest: String + """ + A list of annotations associated with this referrer + """ + Annotations: [Annotation]! } """ -Contains details about the supported OS and architecture of the image +Contains details about the OS and architecture of the image """ type OsArch { + """ + The name of the operating system which the image is built to run on, + Should be values listed in the Go Language document https://go.dev/doc/install/source#environment + """ Os: String + """ + The name of the compilation architecture which the image is built to run on, + Should be values listed in the Go Language document https://go.dev/doc/install/source#environment + """ Arch: String } +""" +All sort criteria usable with pagination, some of these criteria applies only +to certain queries. For example sort by severity is available for CVEs but not +for repositories +""" enum SortCriteria { + """ + How relevant the result is based on the user input used while searching + Applies to: images and repositories + """ RELEVANCE + """ + Sort by the most recently created timestamp of the images + Applies to: images and repositories + """ UPDATE_TIME + """ + Sort alphabetically ascending + Applies to: images, repositories and CVEs + """ ALPHABETIC_ASC + """ + Sort alphabetically descending + Applies to: images, repositories and CVEs + """ ALPHABETIC_DSC + """ + Sort from the most severe to the least severe + Applies to: CVEs + """ SEVERITY + """ + Sort by the total number of stars given by users + Applies to: repositories + """ STARS + """ + Sort by the total download count + Applies to: repositories and images + """ DOWNLOADS } +""" +Information on current page returned by the API +""" type PageInfo { + """ + The total number of objects on all pages + """ TotalCount: Int! + """ + The number of objects in this page + """ ItemCount: Int! } -# Pagination parameters +""" +Pagination parameters +If PageInput is empty, the request should return all objects. +""" input PageInput { + """ + The maximum amount of results to return for this page + Negative values are not allowed + """ limit: Int + """ + The results page number you want to receive + Negative values are not allowed + """ offset: Int + """ + The criteria used to sort the results on the page + """ sortBy: SortCriteria } -# Paginated list of RepoSummary objects -# If limit is -1, pagination is disabled +""" +Paginated list of RepoSummary objects +""" type PaginatedReposResult { + """ + Information on the returned page + """ Page: PageInfo + """ + List of repositories + """ Results: [RepoSummary!]! } -# Paginated list of ImageSummary objects -# If limit is -1, pagination is disabled +""" +Paginated list of ImageSummary objects +""" type PaginatedImagesResult { + """ + Information on the returned page + """ Page: PageInfo + """ + List of images + """ Results: [ImageSummary!]! } +""" +Apply various types of filters to the queries made for repositories and images +For example we only want to display repositories which contain images with +a certain OS ar Architecture. +""" input Filter { + """ + Only return images or repositories supporting the operating systems in the list + Should be values listed in the Go Language document https://go.dev/doc/install/source#environment + """ Os: [String] + """ + Only return images or repositories supporting the build architectures in the list + Should be values listed in the Go Language document https://go.dev/doc/install/source#environment + """ Arch: [String] + """ + Only return images or repositories with at least one signature + """ HasToBeSigned: Boolean } +""" +Queries supported by the zot server +""" type Query { """ - Returns a CVE list for the image specified in the argument. Format image:tag + Returns a CVE list for the image specified in the argument """ - CVEListForImage(image: String!, requestedPage: PageInput): CVEResultForImage! + CVEListForImage( + "Image name in format `repository:tag`" + image: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): CVEResultForImage! """ Returns a list of images vulnerable to the CVE of the specified ID """ - ImageListForCVE(id: String!, requestedPage: PageInput): [ImageSummary!] + ImageListForCVE( + "CVE ID" + id: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): [ImageSummary!] """ - Returns a list of images that are no longer vulnerable to the CVE of the specified ID, from the specified image (repo) + Returns a list of images that are no longer vulnerable to the CVE of the specified ID, + from the specified repository """ - ImageListWithCVEFixed(id: String!, image: String!, requestedPage: PageInput): [ImageSummary!] + ImageListWithCVEFixed( + "CVE ID" + id: String!, + "Repository name" + image: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): [ImageSummary!] """ Returns a list of images which contain the specified digest """ - ImageListForDigest(id: String!, requestedPage: PageInput): [ImageSummary!] + ImageListForDigest( + "Digest to be used in searching for images" + id: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): [ImageSummary!] """ - Returns a list of repos with the newest tag within + Returns a list of repositories with the newest tag (most recently created timestamp) """ - RepoListWithNewestImage(requestedPage: PageInput): PaginatedReposResult! # Newest based on created timestamp + RepoListWithNewestImage( + "Sets the parameters of the requested page" + requestedPage: PageInput + ): PaginatedReposResult! """ - Returns all the images from the specified repo | from all repos if specified repo is "" + Returns all the images from the specified repository | from all repositories if specified repository is "" """ - ImageList(repo: String!, requestedPage: PageInput): [ImageSummary!] + ImageList( + "Repository name" + repo: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): [ImageSummary!] """ - Returns information about the specified repo + Obtain detailed information about a repository and container images within """ - ExpandedRepoInfo(repo: String!): RepoInfo! + ExpandedRepoInfo( + "Repository name" + repo: String! + ): RepoInfo! """ Searches within repos, images, and layers """ - GlobalSearch(query: String!, filter: Filter, requestedPage: PageInput): GlobalSearchResult! + GlobalSearch( + """ + Query string, searches for repository names by default, + when containing `:` it searches for tags inside a repository + """ + query: String!, + "Filter to apply on the matches" + filter: Filter, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): GlobalSearchResult! """ List of images which use the argument image """ - DerivedImageList(image: String!, requestedPage: PageInput): PaginatedImagesResult! + DerivedImageList( + "Image name in the format `repository:tag`" + image: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): PaginatedImagesResult! """ List of images on which the argument image depends on """ - BaseImageList(image: String!, requestedPage: PageInput): PaginatedImagesResult! + BaseImageList( + "Image name in the format `repository:tag`" + image: String!, + "Sets the parameters of the requested page" + requestedPage: PageInput + ): PaginatedImagesResult! """ Search for a specific image using its name """ - Image(image: String!): ImageSummary + Image( + "Image name in the format `repository:tag`" + image: String! + ): ImageSummary """ Returns a list of descriptors of an image or artifact manifest that are found in a and have a subject field of Can be filtered based on a specific artifact type """ - Referrers(repo: String!, digest: String!, type: [String!]): [Referrer]! + Referrers( + "Repository name" + repo: String!, + "Digest the referrers are referring to" + digest: String!, + "Types of artifacts to return in the referrer list" + type: [String!] + ): [Referrer]! } diff --git a/pkg/extensions/search/search.md b/pkg/extensions/search/search.md index 4f346756..c76814bc 100644 --- a/pkg/extensions/search/search.md +++ b/pkg/extensions/search/search.md @@ -1,186 +1,673 @@ -# `search` +# `search` `search` component provides efficient and enhanced registry search capabilities using graphQL backend. - + | Supported queries | Input | Ouput | Description | graphQL query | | --- | --- | --- | --- | --- | | [Search images by digest](#search-images-by-digest) | digest | image list | Search all repositories in the registry and return list of images that matches given digest (manifest, config or layers) | ImageListForDigest | | [Search images affected by a given CVE id](#search-images-affected-by-a-given-cve-id) | CVE id | image list | Search the entire registry and return list of images affected by given CVE | ImagesListForCVE | | [List CVEs for a given image](#list-cves-of-given-image) | image | CVE list | Scan given image and return list of CVEs affecting the image | CVEListForImage | | [List images not affected by a given CVE id](#list-images-not-affected-by-a-given-cve-id) | repository, CVE id | image list | Scan all images in a given repository and return list of latest (by date) images not affected by the given CVE |ImagesListWithCVEFixed| -| [List the latest image across every repository](#list-the-latest-image-across-every-repository) | \ | image list | Search entire registry and return a list containing the latest (by date) image in each repository | ImageListWithLatestTag | -| [List all images with expanded information for a given repository](#list-all-images-with-expanded-information-for-a-given-repository) | repository | image list | List expanded image information for all images (including manifest, all layers, etc) in a given repository | ExpandedRepoInfo | +| [Latest image from all repos](#list-the-latest-image-across-every-repository) | none | repo summary list | Return the latest image from all the repos in the registry | RepoListWithNewestImage | +| [List all images with expanded information for a given repository](#list-all-images-with-expanded-information-for-a-given-repository) | repository | repo info | List expanded repo information for all images in repo, alongisde a repo summary | ExpandedRepoInfo | +| [All images in repo](#all-images-in-repo) | repository | image list | Returns all images in the specified repo | ImageList | +| [Global search](#global-search) | query | image summary / repo summary / layer summary | Will return what's requested in the query argument | GlobalSearch | +| [Derived image list](#search-derived-images) | image | image list | Returns a list of images that depend on the image specified in the arg | DerivedImageList | +| [Base image list](#search-base-images) | image | image list | Returns a list of images that the specified image depends on | BaseImageList | +| [Get details of a specific image](#get-details-of-a-specific-image) | image | image summary | Returns details about a specific image | Image | +| [Get referrers of a specific image](#get-referrers-of-a-specific-image) | repo, digest, type | artifact manifests | Returns a list of artifacts of given type referring to a specific repo and digests | Referrers | -# Search images by digest +The examples below only include the GraphQL query without any additional details on how to send them to a server. They were made with the GraphQL playground from the debug binary. You can also use curl to make these queries, here's an example: -**Sample request** - -``` -curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageListForDigest (id:\"63a795ca90aa6e7cca60941e826810a4cd0a2e73ea02bf458241df2a5c973e29\") { Name Tags } }" }' http://localhost:8080/v2/_zot/ext/search -``` - -**Sample response** - -``` - { - "data": { - "ImageListForDigest": [{ - "Name": "centos", - "Tags": ["8"] - }, { - "Name": "v2/centos", - "Tags": ["8"] - }] - } - } -``` - -# Search images affected by a given CVE id - -**Sample request** - -``` +```bash curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageListForCVE (id:\"CVE-2002-1119\") { Name Tags } }" }' http://localhost:8080/v2/_zot/ext/search ``` -**Sample response** +## List CVEs of given image -``` +**Sample request** + +```graphql { - "data": { - "ImageListForCVE": [{ - "Name": "centos", - "Tags": ["8"] - }, { - "Name": "v2/centos", - "Tags": ["7", "8"] - }] - } + CVEListForImage(image: "centos:8", requestedPage: {limit: 1, offset:1, sortBy: SEVERITY}) { + Tag + Page { + TotalCount + ItemCount + } + CVEList { + Id + Title + Description + Severity + PackageList { + Name + InstalledVersion + FixedVersion + } + } + } } ``` -# List CVEs of given image -**Sample reques**t - - -``` -curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ CVEListForImage (image:\"centos\" ) { Tag CVEList { Id Title Description Severity PackageList {Name InstalledVersion FixedVersion } } } }" }' http://localhost:8080/v2/_zot/ext/search -``` - **Sample response** -``` +```json { - "data": { - "CVEListForImage": { - "Tag": "", - "CVEList": [{ - "Id": "CVE-2021-3712", - "Title": "openssl: Read buffer overruns processing ASN.1 strings", - "Description": "ASN.1 strings are represented internally within OpenSSL as an ASN1_STRING structure which contains a buffer. Fixed in OpenSSL 1.1.1l (Affected 1.1.1-1.1.1k). Fixed in OpenSSL 1.0.2za (Affected 1.0.2-1.0.2y).", - "Severity": "MEDIUM", - "PackageList": [{ - "Name": "openssl-libs", - "InstalledVersion": "1:1.1.1g-11.el8", - "FixedVersion": "1:1.1.1k-5.el8_5" - }] - }] - } - } - } -``` -# List images not affected by a given CVE id - -**Sample request** - -``` -curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageListWithCVEFixed (id:\"CVE-2021-3713\",image:\"centos\") { Tags {Name Digest Timestamp} } }" }' http://localhost:8080/v2/_zot/ext/search -``` - -**Sample response** - -``` -{ - "data": { - "ImageListWithCVEFixed": { - "Tags": [{ - "Name": "8", - "Digest": "sha256:63a795ca90aa6e7cca60941e826810a4cd0a2e73ea02bf458241df2a5c973e29", - "Timestamp": "2020-12-08T00:22:52.526672082Z" - }] - } - } + "data": { + "CVEListForImage": { + "Tag": "8", + "Page": { + "TotalCount": 292, + "ItemCount": 1 + }, + "CVEList": [ + { + "Id": "CVE-2022-24407", + "Title": "cyrus-sasl: failure to properly escape SQL input allows an attacker to execute arbitrary SQL commands", + "Description": "In Cyrus SASL 2.1.17 through 2.1.27 before 2.1.28, plugins/sql.c does not escape the password for a SQL INSERT or UPDATE statement.", + "Severity": "HIGH", + "PackageList": [ + { + "Name": "cyrus-sasl-lib", + "InstalledVersion": "2.1.27-5.el8", + "FixedVersion": "2.1.27-6.el8_5" + } + ] + } + ] + } + } } ``` -# List the latest image across every repository +## Search images affected by a given CVE id -**Sample request** +**Sample request** -``` -curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageListWithLatestTag () { Name Latest LastUpdated Description Licenses Vendor Size Labels} }" }' http://localhost:8080/v2/_zot/ext/search -``` - -**Sample response** - -``` +```graphql { - "data": { - "ImageListWithLatestTag": [{ - "Name": "centos", - "Latest": "8", - "LastUpdated": "2020-12-08T00:22:52.526672082Z", - "Description": "", - "Licenses": "GPLv2", - "Vendor": "CentOS", - "Size": "1074", - "Labels": "" - }, { - "Name": "v2/centos", - "Latest": "8", - "LastUpdated": "2020-12-08T00:22:52.526672082Z", - "Description": "", - "Licenses": "GPLv2", - "Vendor": "CentOS", - "Size": "1074", - "Labels": "" - }] - } + ImageListForCVE(id: "CVE-2018-20651") { + RepoName + Tag + Digest + ConfigDigest + LastUpdated + IsSigned + Size + Platform { + Os + Arch + } + Vendor + Score + DownloadCount + Licenses + Title + } } ``` -# List all images with expanded information for a given repository +**Sample response** -Sample request - -``` -curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ExpandedRepoInfo (repo:\"v2/centos\") { Manifests {Digest Tag IsSigned Layers {Size Digest}}} }" }' http://localhost:8080/v2/_zot/ext/search -``` - -**Sample response** - -``` +```json { - "data": { - "ExpandedRepoInfo": { - "Manifests": [{ - "Digest": "2bacca16b9df395fc855c14ccf50b12b58d35d468b8e7f25758aff90f89bf396", - "Tag": "7", - "IsSigned": false, - "Layers": [{ - "Size": "76097157", - "Digest": "2d473b07cdd5f0912cd6f1a703352c82b512407db6b05b43f2553732b55df3bc" - }] - }, { - "Digest": "63a795ca90aa6e7cca60941e826810a4cd0a2e73ea02bf458241df2a5c973e29", - "Tag": "8", - "IsSigned": false, - "Layers": [{ - "Size": "75181999", - "Digest": "7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621" - }] - }] - } - } + "data": { + "ImageListForCVE": [ + { + "RepoName": "centos", + "Tag": "centos8", + "Digest": "sha256:ac0dc62b48b7f683b49365fecef3b1f4d99fbd249b762e99f13f74938d85a6c8", + "ConfigDigest": "sha256:98a5843635a2ccc7d72b269923a65721480de929f882143c6c0a0eb43f9a2869", + "LastUpdated": "2022-10-17T16:36:09.1751694+03:00", + "IsSigned": true, + "Size": "83545800", + "Platform": { + "Os": "linux", + "Arch": "amd64" + }, + "Vendor": "[The CentOS Project](https://github.com/CentOS/sig-cloud-instance-images)\n", + "Score": null, + "DownloadCount": 0, + "Licenses": "View [license information](https://www.centos.org/legal/) for the software contained in this image.", + "Title": "centos" + }, + ] + } +} +``` + +## List images not affected by a given CVE id + +**Sample request** + +```graphql +{ + ImageListWithCVEFixed(id: "CVE-2018-20651", image: "ubuntu") { + RepoName + Tag + Digest + ConfigDigest + LastUpdated + } +} +``` + +**Sample response** + +```json +{ + "data": { + "ImageListWithCVEFixed": [ + { + "RepoName": "ubuntu", + "Tag": "latest", + "Digest": "sha256:650d596072ad45c6b74f4923e2cfea8158da2fb3a7b8dbb0b9ae4da3088d0591", + "ConfigDigest": "sha256:88eef892e29d5b11be933f13424ef885644a6a6978924fedfb51ba555278fe74", + "LastUpdated": "2022-10-25T01:53:41.769246372Z" + } + ] + } +} +``` + +## Search images by digest + +**Sample request** + +```graphql +{ + ImageListForDigest( + id: "5f34d0bb0261d32d0b0bc91024b7d4e98d94b08a49615e08c8a5a65bc3a7e09f" + ) { + RepoName + Tag + Title + } +} +``` + +**Sample response** + +```json +{ + "data": { + "ImageListForDigest": [ + { + "RepoName": "centos", + "Tag": "8", + "Title": "CentOS Base Image" + } + ] + } +} +``` + +## List the latest image across every repository + +**Sample request** + +```graphql +{ + RepoListWithNewestImage(requestedPage: {limit: 2, offset:0, sortBy: ALPHABETIC_ASC}) { + Page { + TotalCount + ItemCount + } + Results { + Name + LastUpdated + Size + Platforms { + Os + Arch + } + NewestImage { + Digest + Tag + } + } + } +} +``` + +**Sample response** + +```json +{ + "data": { + "RepoListWithNewestImage": { + "Page": { + "TotalCount": 30, + "ItemCount": 2 + }, + "Results": [ + { + "Name": "mariadb", + "LastUpdated": "2022-10-18T14:56:33.1993083+03:00", + "Size": "124116964", + "Platforms": [ + { + "Os": "linux", + "Arch": "amd64" + } + ], + "NewestImage": { + "Digest": "sha256:49a299f5c4b1af5bc2aa6cf8e50ab5bad85db4d0095745369acfc1934ece99d0", + "Tag": "latest" + } + }, + { + "Name": "tomcat", + "LastUpdated": "2022-10-18T14:55:13.8303866+03:00", + "Size": "311658063", + "Platforms": [ + { + "Os": "linux", + "Arch": "amd64" + } + ], + "NewestImage": { + "Digest": "sha256:bbc5a3912b568fbfb5912beaf25054f1f407c32a53acae29f19ad97485731a78", + "Tag": "jre17" + } + } + ] + } + } +} +``` + +## All images in repo + +**Sample request** + +```graphql +{ + ImageList (repo: "ubuntu") { + Tag + Digest + LastUpdated + Size + } +} +``` + +**Sample response** + +```json +{ + "data": { + "ImageList": [ + { + "Tag": "latest", + "Digest": "sha256:650d596072ad45c6b74f4923e2cfea8158da2fb3a7b8dbb0b9ae4da3088d0591", + "LastUpdated": "2022-10-25T01:53:41.769246372Z", + "Size": "30426374" + }, + { + "Tag": "xenial", + "Digest": "sha256:34de800b5da88feb7723a87ecbbf238afb63dbfe0c828838e26ac7458bef0ac5", + "LastUpdated": "2021-08-31T01:21:30.672229355Z", + "Size": "46499103" + } + ] + } +} +``` + +## List all images with expanded information for a given repository + +**Sample request** + +```graphql +{ + ExpandedRepoInfo(repo: "ubuntu") { + Images { + Tag + Digest + } + Summary { + LastUpdated + Size + NewestImage { + Tag + LastUpdated + Digest + } + } + } +} +``` + +**Sample response** + +```json +{ + "data": { + "ExpandedRepoInfo": { + "Images": [ + { + "Tag": "xenial", + "Digest": "sha256:34de800b5da88feb7723a87ecbbf238afb63dbfe0c828838e26ac7458bef0ac5" + }, + { + "Tag": "latest", + "Digest": "sha256:650d596072ad45c6b74f4923e2cfea8158da2fb3a7b8dbb0b9ae4da3088d0591" + } + ], + "Summary": { + "LastUpdated": "2022-10-25T01:53:41.769246372Z", + "Size": "76929691", + "NewestImage": { + "Tag": "latest", + "LastUpdated": "2022-10-25T01:53:41.769246372Z", + "Digest": "sha256:650d596072ad45c6b74f4923e2cfea8158da2fb3a7b8dbb0b9ae4da3088d0591" + } + } + } + } +} +``` + +## Global search + +**Sample request** + +```graphql +{ + GlobalSearch(query: "ubuntu:latest") { + Page { + ItemCount + TotalCount + } + Images { + RepoName + Tag + LastUpdated + Layers { + Size + Digest + } + } + } +} +``` + +**Sample response** + +```json +{ + "data": { + "GlobalSearch": { + "Page": { + "ItemCount": 1, + "TotalCount": 1 + }, + "Images": [ + { + "RepoName": "ubuntu", + "Tag": "latest", + "LastUpdated": "2022-10-14T18:26:59.6707939+03:00", + "Layers": [ + { + "Size": "30428928", + "Digest": "sha256:cf92e523b49ea3d1fae59f5f082437a5f96c244fda6697995920142ff31d59cf" + } + ] + } + ] + } + } +} +``` + +**Sample request** + +```graphql +{ + GlobalSearch(query: "") { + Repos { + Name + } + } +} +``` + +**Sample response** + +```json +{ + "data": { + "GlobalSearch": { + "Repos": [ + { + "Name": "centos" + }, + { + "Name": "ubuntu" + } + ] + } + } +} +``` + +## Search derived images + +**Sample query** + +```graphql +{ + DerivedImageList(image: "ubuntu:latest", requestedPage: {offset: 0, limit: 10}) { + Page { + TotalCount + ItemCount + } + Results { + RepoName + Tag + LastUpdated + } + } +} +``` + +**Sample response** + +```json +{ + "data": { + "DerivedImageList": { + "Page": { + "TotalCount": 9, + "ItemCount": 9 + }, + "Results": [ + { + "RepoName": "mariadb", + "Tag": "latest", + "LastUpdated": "2022-10-18T14:56:33.1993083+03:00" + }, + { + "RepoName": "maven", + "Tag": "latest", + "LastUpdated": "2022-10-14T18:30:12.0929807+03:00" + }, + { + "RepoName": "tomcat", + "Tag": "latest", + "LastUpdated": "2022-10-18T14:50:09.7229959+03:00" + }, + { + "RepoName": "tomcat", + "Tag": "jre17", + "LastUpdated": "2022-10-18T14:55:13.8303866+03:00" + }, + { + "RepoName": "tomcat", + "Tag": "jre17-temurin", + "LastUpdated": "2022-10-18T14:54:46.4133521+03:00" + }, + { + "RepoName": "tomcat", + "Tag": "jre17-temurin-jammy", + "LastUpdated": "2022-10-18T14:51:12.235475+03:00" + } + ] + } + } +} +``` + +## Search base images + +**Sample query** + +```graphql +{ + BaseImageList(image: "mariadb:latest", requestedPage: {offset: 0, limit: 10}) { + Page { + TotalCount + ItemCount + } + Results { + RepoName + Tag + LastUpdated + } + } +} +``` + +**Sample response** + +```json +{ + "data": { + "BaseImageList": { + "Page": { + "TotalCount": 4, + "ItemCount": 4 + }, + "Results": [ + { + "RepoName": "ubuntu", + "Tag": "jammy", + "LastUpdated": "2022-10-14T18:29:18.0325322+03:00" + }, + { + "RepoName": "ubuntu", + "Tag": "jammy-20221003", + "LastUpdated": "2022-10-14T18:29:07.0004587+03:00" + }, + { + "RepoName": "ubuntu", + "Tag": "latest", + "LastUpdated": "2022-10-14T18:26:59.6707939+03:00" + }, + { + "RepoName": "ubuntu", + "Tag": "rolling", + "LastUpdated": "2022-10-14T18:27:21.2441356+03:00" + } + ] + } + } +} +``` + +## Get details of a specific image + +**Sample query** + +```graphql +{ + Image(image: "mariadb:latest") { + RepoName + Tag + LastUpdated + Digest + Description + } +} +``` + +**Sample response** + +```json +{ + "data": { + "Image": { + "RepoName": "mariadb", + "Tag": "latest", + "LastUpdated": "2022-10-18T14:56:33.1993083+03:00", + "Digest": "sha256:49a299f5c4b1af5bc2aa6cf8e50ab5bad85db4d0095745369acfc1934ece99d0", + "Description": "MariaDB Server is a high performing open source relational database, forked from MySQL." + } + } +} +``` + +## Get referrers of a specific image + +**Sample query** + +```graphql +{ + Referrers( + repo: "golang" + digest: "sha256:fed08b0eaea00aab17f82ecbb78675919d216c72eea985581758191f694aeaf7" + type: "application/vnd.example.icecream.v1" + ) { + MediaType + ArtifactType + Digest + Annotations { + Key + Value + } + } +} +``` + +**Sample response** + +```json +{ + "data": { + "Referrers": [ + { + "MediaType": "application/vnd.oci.artifact.manifest.v1+json", + "ArtifactType": "application/vnd.example.icecream.v1", + "Digest": "sha256:be7a3d01c35a2cf53c502e9dc50cdf36b15d9361c81c63bf319f1d5cbe44ab7c", + "Annotations": [ + { + "Key": "format", + "Value": "oci" + }, + { + "Key": "demo", + "Value": "true" + } + ] + }, + { + "MediaType": "application/vnd.oci.artifact.manifest.v1+json", + "ArtifactType": "application/vnd.example.icecream.v1", + "Digest": "sha256:d9ad22f41d9cb9797c134401416eee2a70446cee1a8eb76fc6b191f4320dade2", + "Annotations": [ + { + "Key": "demo", + "Value": "true" + }, + { + "Key": "format", + "Value": "oci" + } + ] + } + ] + } } ```