diff --git a/internal/cloudapi/v2/handler.go b/internal/cloudapi/v2/handler.go index 3a15caaa1..34ecd8821 100644 --- a/internal/cloudapi/v2/handler.go +++ b/internal/cloudapi/v2/handler.go @@ -6,6 +6,8 @@ import ( "fmt" "net/http" "os" + "slices" + "sort" "strconv" "strings" @@ -16,6 +18,7 @@ import ( "github.com/osbuild/images/pkg/manifest" "github.com/osbuild/images/pkg/osbuild" "github.com/osbuild/images/pkg/rpmmd" + "github.com/osbuild/images/pkg/sbom" "github.com/osbuild/osbuild-composer/internal/blueprint" "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/target" @@ -888,6 +891,169 @@ func (h *apiHandlers) getComposeManifestsImpl(ctx echo.Context, id string) error return ctx.JSON(http.StatusOK, resp) } +// sbomsFromOSBuildJob extracts SBOM documents from dependencies of an OSBuild job. +func sbomsFromOSBuildJob(w *worker.Server, osbuildJobUUID uuid.UUID) ([]ImageSBOM, error) { + var osbuildJobResult worker.OSBuildJobResult + osbuildJobInfo, err := w.OSBuildJobInfo(osbuildJobUUID, &osbuildJobResult) + if err != nil { + return nil, fmt.Errorf("Failed to get results for OSBuild job %q: %v", osbuildJobUUID, err) + } + + pipelineNameToPurpose := func(pipelineName string) (ImageSBOMPipelinePurpose, error) { + if slices.Contains(osbuildJobResult.PipelineNames.Payload, pipelineName) { + return ImageSBOMPipelinePurposeImage, nil + } + if slices.Contains(osbuildJobResult.PipelineNames.Build, pipelineName) { + return ImageSBOMPipelinePurposeBuildroot, nil + } + return "", fmt.Errorf("Pipeline %q is not listed as either a payload or build pipeline", pipelineName) + } + + // SBOMs are attached to the depsolve job results. + // Depsolve jobs are dependencies of Manifest job. + // Manifest job is a dependency of OSBuild job. + manifesJobInfo, _, err := manifestJobResultsFromJobDeps(w, osbuildJobInfo.Deps) + if err != nil { + return nil, fmt.Errorf("Failed to get manifest job info for OSBuild job %q: %v", osbuildJobUUID, err) + } + + var imageSBOMs []ImageSBOM + for _, manifestDepUUID := range manifesJobInfo.Deps { + depJobType, err := w.JobType(manifestDepUUID) + if err != nil { + return nil, fmt.Errorf("Failed to get job type for dependency %q: %v", manifestDepUUID, err) + } + + if depJobType != worker.JobTypeDepsolve { + continue + } + + var depsolveJobResult worker.DepsolveJobResult + _, err = w.DepsolveJobInfo(manifestDepUUID, &depsolveJobResult) + if err != nil { + return nil, fmt.Errorf("Failed to get results for depsolve job %q: %v", manifestDepUUID, err) + } + + if depsolveJobResult.SbomDocs == nil { + return nil, fmt.Errorf("depsolve job %q: missing SBOMs", manifestDepUUID) + } + + for pipelineName, sbomDoc := range depsolveJobResult.SbomDocs { + purpose, err := pipelineNameToPurpose(pipelineName) + if err != nil { + return nil, fmt.Errorf("Failed to determine purpose for pipeline %q: %v", pipelineName, err) + } + + var sbomType ImageSBOMSbomType + switch sbomDoc.DocType { + case sbom.StandardTypeSpdx: + sbomType = ImageSBOMSbomTypeSpdx + default: + return nil, fmt.Errorf("Unknown SBOM type %q attached to depsolve job %q", sbomDoc.DocType, manifestDepUUID) + } + + imageSBOMs = append(imageSBOMs, ImageSBOM{ + PipelineName: pipelineName, + PipelinePurpose: purpose, + Sbom: sbomDoc.Document, + SbomType: sbomType, + }) + } + + // There should be only one depsolve job per OSBuild job + break + } + + if len(imageSBOMs) == 0 { + return nil, fmt.Errorf("OSBuild job %q: manifest job dependency is missing depsolve job dependency", osbuildJobUUID) + } + + // Sort the SBOMs by pipeline name to ensure consistent ordering. + // The SBOM documents are attached to the depsolve job results, in a map where the key is the pipeline name. + // The order of the keys in the map is not guaranteed to be consistent across different runs. + sort.Slice(imageSBOMs, func(i, j int) bool { + return imageSBOMs[i].PipelineName < imageSBOMs[j].PipelineName + }) + + return imageSBOMs, nil +} + +// GetComposeSBOMs returns the SBOM documents for a given Compose (multiple SBOMs for each image). +func (h *apiHandlers) GetComposeSBOMs(ctx echo.Context, id string) error { + return h.server.EnsureJobChannel(h.getComposeSBOMsImpl)(ctx, id) +} + +func (h *apiHandlers) getComposeSBOMsImpl(ctx echo.Context, id string) error { + jobId, err := uuid.Parse(id) + if err != nil { + return HTTPError(ErrorInvalidComposeId) + } + + jobType, err := h.server.workers.JobType(jobId) + if err != nil { + return HTTPError(ErrorComposeNotFound) + } + + var items [][]ImageSBOM + + switch jobType { + // Koji compose + case worker.JobTypeKojiFinalize: + var finalizeResult worker.KojiFinalizeJobResult + finalizeInfo, err := h.server.workers.KojiFinalizeJobInfo(jobId, &finalizeResult) + if err != nil { + return HTTPErrorWithInternal(ErrorComposeNotFound, err) + } + + for _, kojiFinalizeDepUUID := range finalizeInfo.Deps { + buildJobType, err := h.server.workers.JobType(kojiFinalizeDepUUID) + if err != nil { + return HTTPErrorWithInternal(ErrorComposeNotFound, err) + } + + switch buildJobType { + case worker.JobTypeKojiInit: + continue + + case worker.JobTypeOSBuild: + imageSBOMs, err := sbomsFromOSBuildJob(h.server.workers, kojiFinalizeDepUUID) + if err != nil { + return HTTPErrorWithInternal(ErrorComposeNotFound, + fmt.Errorf("Failed to get SBOMs for OSBuild job %q: %v", kojiFinalizeDepUUID, err)) + } + items = append(items, imageSBOMs) + + default: + return HTTPErrorWithInternal(ErrorInvalidJobType, + fmt.Errorf("unexpected job type in koji compose dependencies: %q", buildJobType)) + } + } + + // non-Koji compose + case worker.JobTypeOSBuild: + imageSBOMs, err := sbomsFromOSBuildJob(h.server.workers, jobId) + if err != nil { + return HTTPErrorWithInternal(ErrorComposeNotFound, + fmt.Errorf("Failed to get SBOMs for OSBuild job %q: %v", jobId, err)) + } + items = append(items, imageSBOMs) + + default: + return HTTPError(ErrorInvalidJobType) + } + + resp := &ComposeSBOMs{ + ObjectReference: ObjectReference{ + Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/sboms", jobId), + Id: jobId.String(), + Kind: "ComposeSBOMs", + }, + Items: items, + } + + return ctx.JSON(http.StatusOK, resp) +} + // Converts repositories in the request to the internal rpmmd.RepoConfig representation func convertRepos(irRepos, payloadRepositories []Repository, payloadPackageSets []string) ([]rpmmd.RepoConfig, error) { repos := make([]rpmmd.RepoConfig, 0, len(irRepos)+len(payloadRepositories)) diff --git a/internal/cloudapi/v2/openapi.v2.gen.go b/internal/cloudapi/v2/openapi.v2.gen.go index 9dab74042..c76902471 100644 --- a/internal/cloudapi/v2/openapi.v2.gen.go +++ b/internal/cloudapi/v2/openapi.v2.gen.go @@ -49,6 +49,18 @@ const ( CustomizationsPartitioningModeRaw CustomizationsPartitioningMode = "raw" ) +// Defines values for ImageSBOMPipelinePurpose. +const ( + ImageSBOMPipelinePurposeBuildroot ImageSBOMPipelinePurpose = "buildroot" + + ImageSBOMPipelinePurposeImage ImageSBOMPipelinePurpose = "image" +) + +// Defines values for ImageSBOMSbomType. +const ( + ImageSBOMSbomTypeSpdx ImageSBOMSbomType = "spdx" +) + // Defines values for ImageStatusValue. const ( ImageStatusValueBuilding ImageStatusValue = "building" @@ -470,6 +482,15 @@ type ComposeRequest struct { Koji *Koji `json:"koji,omitempty"` } +// ComposeSBOMs defines model for ComposeSBOMs. +type ComposeSBOMs struct { + // Embedded struct due to allOf(#/components/schemas/ObjectReference) + ObjectReference `yaml:",inline"` + // Embedded fields due to inline allOf schema + // The SBOM documents for each image built in the compose. + Items [][]ImageSBOM `json:"items"` +} + // ComposeStatus defines model for ComposeStatus. type ComposeStatus struct { // Embedded struct due to allOf(#/components/schemas/ObjectReference) @@ -811,6 +832,36 @@ type ImageRequest struct { UploadTargets *[]UploadTarget `json:"upload_targets,omitempty"` } +// ImageSBOM defines model for ImageSBOM. +type ImageSBOM struct { + // The name of the osbuild pipeline which has the packages described + // in the SBOM installed. + PipelineName string `json:"pipeline_name"` + + // The purpose of the pipeline. The `buildroot` pipeline was used for + // the build environment dueing the image build. The `image` pipeline + // represents the actual content of the image. Due to the nature of + // some image types, there may be multiple pipelines of the same + // purpose. + PipelinePurpose ImageSBOMPipelinePurpose `json:"pipeline_purpose"` + + // The SBOM document in the 'sbom_type' format. + Sbom interface{} `json:"sbom"` + + // The type of the SBOM document. Currently only SPDX is supported. + SbomType ImageSBOMSbomType `json:"sbom_type"` +} + +// The purpose of the pipeline. The `buildroot` pipeline was used for +// the build environment dueing the image build. The `image` pipeline +// represents the actual content of the image. Due to the nature of +// some image types, there may be multiple pipelines of the same +// purpose. +type ImageSBOMPipelinePurpose string + +// The type of the SBOM document. Currently only SPDX is supported. +type ImageSBOMSbomType string + // ImageStatus defines model for ImageStatus. type ImageStatus struct { Error *ComposeStatusError `json:"error,omitempty"` @@ -1194,6 +1245,9 @@ type ServerInterface interface { // Get the metadata for a compose. // (GET /composes/{id}/metadata) GetComposeMetadata(ctx echo.Context, id string) error + // Get the SBOMs for a compose. + // (GET /composes/{id}/sboms) + GetComposeSBOMs(ctx echo.Context, id string) error // Get a list of all possible errors // (GET /errors) GetErrorList(ctx echo.Context, params GetErrorListParams) error @@ -1323,6 +1377,22 @@ func (w *ServerInterfaceWrapper) GetComposeMetadata(ctx echo.Context) error { return err } +// GetComposeSBOMs converts echo context to params. +func (w *ServerInterfaceWrapper) GetComposeSBOMs(ctx echo.Context) error { + var err error + // ------------- Path parameter "id" ------------- + var id string + + err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) + } + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.GetComposeSBOMs(ctx, id) + return err +} + // GetErrorList converts echo context to params. func (w *ServerInterfaceWrapper) GetErrorList(ctx echo.Context) error { var err error @@ -1414,6 +1484,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.GET(baseURL+"/composes/:id/logs", wrapper.GetComposeLogs) router.GET(baseURL+"/composes/:id/manifests", wrapper.GetComposeManifests) router.GET(baseURL+"/composes/:id/metadata", wrapper.GetComposeMetadata) + router.GET(baseURL+"/composes/:id/sboms", wrapper.GetComposeSBOMs) router.GET(baseURL+"/errors", wrapper.GetErrorList) router.GET(baseURL+"/errors/:id", wrapper.GetError) router.GET(baseURL+"/openapi", wrapper.GetOpenapi) @@ -1423,183 +1494,189 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "IoqHWQfn89f/HwAA//80eIXXl8EAAA==", + "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", + "qo1G0xneTHt/vnxsFHb2H33HnbQbT48ng5fJ2aBLCp/72+/X/ftR76RcPHytDFs7V0f7l0Vy/uXz/l3J", + "C0btz6+doF15OGf7Fa9yHLjCP7s9PD07F17t8KBLSuz4/UuDdkoTf/exVT9vHNgXzebV5KXxwunDXX3n", + "8S5ofi70yAvroNvy+e1Vsz+5bu5sP+zWa/jqvku8Wvtzj98cjHea5XPm2o2L6sVBQCdPpTYWx/CpenZz", + "fi8+dw5hqYr5Y/u4+fJOd64f6/eV06thrdglzuuDUy9fFnpe+fC9vdOpVx4OD3old/RSbbmjN6f1eoac", + "Uun9y+Obxx7bT6enzf7ovf/ZvWxvB2/OSZe8vBVOixP3qXyOe8ds+7jRmFzt3j2wxlN73L4oHlovnfr4", + "sEnehu2DYPLqPYzvR5f7X4LD1n39ClUeu+QC35X6p5d1bu8c+PzorXbx+YtNLshN+/MJe+lcnx1UvAfm", + "Nmxy2BnYj/f1l6eh/zA4mPBKYXcXXXXJYFhk52RSfLkcD2HQL+C7+pW1/WV0MXw5v704dWp3u/dnk9Pg", + "4UG8j7+Ql4vL2sPt0f7rWZU/Ue/iokv6otc5KX2uTXq3D4VGZbTfg2+3D2Wxc/d++WK9o2H76RDD88vd", + "88KJddps3ZZujurb9fKB3XAPj3btLhmWnRv82L5pQHhaPD1tvJ+Mboe3p+fnzln58eYRn1zeT8qicjo5", + "6nMGvdq43Xy46g+uUWtyvt95Ou2SEfMv3ese6vPObm2n0y/vX7YC5/2JNWv3bwfts+GTczso3R+P2q0b", + "0py8D28m24d35ddrHz/UdqWMGly3vjyxM2qdVc7O27sF/H5607l1xctF47cu+e2639npEnW6HF4eLDt6", + "FpS7ogw9c+6mH9I/qx6ufvRnqTv4ox4Bilf/SfW6yPFCx4YuEaSc6jGtCHKp0HCgTK5YRomqPNQlv4aR", + "TJ9SqxDN5RSEZWbphpW2PtaPnnSVgwWe8jVLE5hHQzezq1NVyYZtRxd1oc/VPO8DAzGgDL8jW9kz8/nt", + "a73W02g/YDG8Oqne1XeqhzbfvyMT0av0xqNbxzlxb9ze4xd3h5SKo90FdW5T0+Tv9BtHkfmj86TM46uS", + "pJKOIdvDZHXEN1dBBRJPadbx2pnLH5CBDHqT2Fs6KdVxw2KIdrokIi3dpfQhqckroSF9FbTFNwbGg3y4", + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/cloudapi/v2/openapi.v2.yml b/internal/cloudapi/v2/openapi.v2.yml index 993384e80..95c61bfc8 100644 --- a/internal/cloudapi/v2/openapi.v2.yml +++ b/internal/cloudapi/v2/openapi.v2.yml @@ -215,6 +215,42 @@ paths: schema: type: string + '/composes/{id}/sboms': + get: + operationId: getComposeSBOMs + summary: Get the SBOMs for a compose. + parameters: + - in: path + name: id + schema: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426655440000 + required: true + description: ID of compose for which to get SBOMs + description: |- + Returns a set of SBOM documents for each image in the request. + SBOM documents are in the SPDX format. + responses: + '200': + description: The SBOMs for the given compose. + content: + application/json: + schema: + $ref: '#/components/schemas/ComposeSBOMs' + '400': + description: Invalid compose id + content: + text/plain: + schema: + type: string + '404': + description: Unknown compose id + content: + text/plain: + schema: + type: string + /composes/{id}/clone: post: operationId: postCloneCompose @@ -571,6 +607,56 @@ components: items: type: object x-go-type: interface{} + ImageSBOM: + required: + - sbom + - sbom_type + - pipeline_name + - pipeline_purpose + properties: + sbom: + type: object + x-go-type: interface{} + description: |- + The SBOM document in the 'sbom_type' format. + sbom_type: + type: string + enum: ["spdx"] + description: |- + The type of the SBOM document. Currently only SPDX is supported. + pipeline_name: + type: string + description: |- + The name of the osbuild pipeline which has the packages described + in the SBOM installed. + pipeline_purpose: + type: string + enum: ["buildroot", "image"] + description: |- + The purpose of the pipeline. The `buildroot` pipeline was used for + the build environment dueing the image build. The `image` pipeline + represents the actual content of the image. Due to the nature of + some image types, there may be multiple pipelines of the same + purpose. + ComposeSBOMs: + allOf: + - $ref: '#/components/schemas/ObjectReference' + - type: object + required: + - items + properties: + items: + type: array + description: |- + The SBOM documents for each image built in the compose. + items: + type: array + description: |- + The SBOM documents for the given image. Each image usually has + at least two SBOMs, one for the build environment and one for the + actual content of the image. + items: + $ref: '#/components/schemas/ImageSBOM' ImageStatus: required: - status