1
0
mirror of https://github.com/ko-build/ko.git synced 2025-11-23 22:35:11 +02:00

remove support for CycloneDX SBOMs

Signed-off-by: Jason Hall <jason@chainguard.dev>
This commit is contained in:
Jason Hall
2024-06-10 00:04:56 -04:00
parent 9004ba1d6e
commit 2ceaa89b7e
14 changed files with 21 additions and 274 deletions

View File

@@ -9,38 +9,6 @@ env:
SPDX_TOOLS_VERSION: 1.1.0 SPDX_TOOLS_VERSION: 1.1.0
jobs: jobs:
cyclonedx:
name: Validate CycloneDX SBOM
runs-on: ubuntu-latest
env:
KO_DOCKER_REPO: localhost:1338
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
with:
go-version-file: 'go.mod'
check-latest: true
- uses: chainguard-dev/actions/setup-registry@main
- uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
- name: Install CycloneDX
run: |
wget https://github.com/CycloneDX/cyclonedx-cli/releases/download/v0.22.0/cyclonedx-linux-x64
chmod +x cyclonedx-linux-x64
- name: Generate and Validate
run: |
cosign download sbom $(go run ./ build --sbom=cyclonedx) | tee cyclonedx.json
./cyclonedx-linux-x64 validate --input-file=cyclonedx.json --fail-on-errors
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
if: ${{ always() }}
with:
name: cyclonedx.json
path: cyclonedx.json
spdx: spdx:
name: Validate SPDX SBOM name: Validate SPDX SBOM
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -5,7 +5,7 @@ Having a list of dependencies can be helpful in determining whether any vulnerab
**From v0.9+, `ko` generates and uploads an SBOM for every image it produces by default.** **From v0.9+, `ko` generates and uploads an SBOM for every image it produces by default.**
ko will generate an SBOM in the [SPDX](https://spdx.dev/) format by default, but you can select the [CycloneDX](https://cyclonedx.org/) format instead with the `--sbom=cyclonedx` flag. To disable SBOM generation, pass `--sbom=none`. ko will generate an SBOM in the [SPDX](https://spdx.dev/) format by default. To disable SBOM generation, pass `--sbom=none`.
These SBOMs can be downloaded using the [`cosign download sbom`](https://github.com/sigstore/cosign/blob/main/doc/cosign_download_sbom.md) command. These SBOMs can be downloaded using the [`cosign download sbom`](https://github.com/sigstore/cosign/blob/main/doc/cosign_download_sbom.md) command.

View File

@@ -60,7 +60,7 @@ ko apply -f FILENAME [flags]
-P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO. -P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO.
--push Push images to KO_DOCKER_REPO (default true) --push Push images to KO_DOCKER_REPO (default true)
-R, --recursive Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory. -R, --recursive Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m). (default "spdx") --sbom string The SBOM media type to use (none will disable SBOM synthesis and upload). (default "spdx")
--sbom-dir string Path to file where the SBOM will be written. --sbom-dir string Path to file where the SBOM will be written.
-l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2) -l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
--tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated. --tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated.

View File

@@ -55,7 +55,7 @@ ko build IMPORTPATH... [flags]
--platform strings Which platform to use when pulling a multi-platform base. Format: all | <os>[/<arch>[/<variant>]][,platform]* --platform strings Which platform to use when pulling a multi-platform base. Format: all | <os>[/<arch>[/<variant>]][,platform]*
-P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO. -P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO.
--push Push images to KO_DOCKER_REPO (default true) --push Push images to KO_DOCKER_REPO (default true)
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m). (default "spdx") --sbom string The SBOM media type to use (none will disable SBOM synthesis and upload). (default "spdx")
--sbom-dir string Path to file where the SBOM will be written. --sbom-dir string Path to file where the SBOM will be written.
--tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated. --tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated.
-t, --tags strings Which tags to use for the produced image instead of the default 'latest' tag (may not work properly with --base-import-paths or --bare). (default [latest]) -t, --tags strings Which tags to use for the produced image instead of the default 'latest' tag (may not work properly with --base-import-paths or --bare). (default [latest])

View File

@@ -60,7 +60,7 @@ ko create -f FILENAME [flags]
-P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO. -P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO.
--push Push images to KO_DOCKER_REPO (default true) --push Push images to KO_DOCKER_REPO (default true)
-R, --recursive Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory. -R, --recursive Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m). (default "spdx") --sbom string The SBOM media type to use (none will disable SBOM synthesis and upload). (default "spdx")
--sbom-dir string Path to file where the SBOM will be written. --sbom-dir string Path to file where the SBOM will be written.
-l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2) -l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
--tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated. --tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated.

View File

@@ -53,7 +53,7 @@ ko resolve -f FILENAME [flags]
-P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO. -P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO.
--push Push images to KO_DOCKER_REPO (default true) --push Push images to KO_DOCKER_REPO (default true)
-R, --recursive Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory. -R, --recursive Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m). (default "spdx") --sbom string The SBOM media type to use (none will disable SBOM synthesis and upload). (default "spdx")
--sbom-dir string Path to file where the SBOM will be written. --sbom-dir string Path to file where the SBOM will be written.
-l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2) -l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
--tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated. --tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated.

View File

@@ -43,7 +43,7 @@ ko run IMPORTPATH [flags]
--platform strings Which platform to use when pulling a multi-platform base. Format: all | <os>[/<arch>[/<variant>]][,platform]* --platform strings Which platform to use when pulling a multi-platform base. Format: all | <os>[/<arch>[/<variant>]][,platform]*
-P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO. -P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO.
--push Push images to KO_DOCKER_REPO (default true) --push Push images to KO_DOCKER_REPO (default true)
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m). (default "spdx") --sbom string The SBOM media type to use (none will disable SBOM synthesis and upload). (default "spdx")
--sbom-dir string Path to file where the SBOM will be written. --sbom-dir string Path to file where the SBOM will be written.
--tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated. --tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated.
-t, --tags strings Which tags to use for the produced image instead of the default 'latest' tag (may not work properly with --base-import-paths or --bare). (default [latest]) -t, --tags strings Which tags to use for the produced image instead of the default 'latest' tag (may not work properly with --base-import-paths or --bare). (default [latest])

View File

@@ -1,175 +0,0 @@
// Copyright 2022 ko Build Authors All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sbom
import (
"bytes"
"encoding/base64"
"encoding/hex"
"encoding/json"
"runtime/debug"
"strings"
"github.com/sigstore/cosign/v2/pkg/oci"
)
func h1ToSHA256(s string) string {
if !strings.HasPrefix(s, "h1:") {
return ""
}
b, err := base64.StdEncoding.DecodeString(s[3:])
if err != nil {
return ""
}
return hex.EncodeToString(b)
}
func GenerateImageCycloneDX(mod []byte) ([]byte, error) {
var err error
mod, err = massageGoVersionM(mod)
if err != nil {
return nil, err
}
bi, err := debug.ParseBuildInfo(string(mod))
if err != nil {
return nil, err
}
doc := document{
BOMFormat: "CycloneDX",
SpecVersion: "1.4",
Version: 1,
Metadata: metadata{
Component: component{
BOMRef: bomRef(&bi.Main),
Type: "application",
Name: bi.Main.Path,
Version: bi.Main.Version,
Purl: bomRef(&bi.Main),
ExternalReferences: []externalReference{{
URL: "https://" + bi.Main.Path,
Type: "vcs",
}},
},
Properties: []property{{
Name: "cdx:gomod:binary:name",
Value: "out",
}},
// TODO: include all hashes
// TODO: include go version
// TODO: include bi.Settings?
},
Dependencies: []dependency{{
Ref: bomRef(&bi.Main),
}},
Compositions: []composition{{
Aggregate: "complete",
Dependencies: []string{
bomRef(&bi.Main),
},
}, {
Aggregate: "unknown",
Dependencies: []string{},
}},
}
for _, dep := range bi.Deps {
// Don't include replaced deps
if dep.Replace != nil {
continue
}
comp := component{
BOMRef: bomRef(dep),
Type: "library",
Name: dep.Path,
Version: dep.Version,
Scope: "required",
Purl: bomRef(dep),
ExternalReferences: []externalReference{{
URL: "https://" + dep.Path,
Type: "vcs",
}},
}
if dep.Sum != "" {
comp.Hashes = []hash{{
Alg: "SHA-256",
Content: h1ToSHA256(dep.Sum),
}}
}
doc.Components = append(doc.Components, comp)
doc.Dependencies[0].DependsOn = append(doc.Dependencies[0].DependsOn, bomRef(dep))
doc.Dependencies = append(doc.Dependencies, dependency{
Ref: bomRef(dep),
})
doc.Compositions[1].Dependencies = append(doc.Compositions[1].Dependencies, bomRef(dep))
}
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetIndent("", " ")
if err := enc.Encode(doc); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func GenerateIndexCycloneDX(oci.SignedImageIndex) ([]byte, error) {
return nil, nil
}
type document struct {
BOMFormat string `json:"bomFormat"`
SpecVersion string `json:"specVersion"`
Version int `json:"version"`
Metadata metadata `json:"metadata"`
Components []component `json:"components,omitempty"`
Dependencies []dependency `json:"dependencies,omitempty"`
Compositions []composition `json:"compositions,omitempty"`
}
type metadata struct {
Component component `json:"component"`
Properties []property `json:"properties,omitempty"`
}
type component struct {
BOMRef string `json:"bom-ref"`
Type string `json:"type"`
Name string `json:"name"`
Version string `json:"version"`
Scope string `json:"scope,omitempty"`
Hashes []hash `json:"hashes,omitempty"`
Purl string `json:"purl"`
ExternalReferences []externalReference `json:"externalReferences"`
}
type hash struct {
Alg string `json:"alg"`
Content string `json:"content"`
}
type externalReference struct {
URL string `json:"url"`
Type string `json:"type"`
}
type property struct {
Name string `json:"name"`
Value string `json:"value"`
}
type dependency struct {
Ref string `json:"ref"`
DependsOn []string `json:"dependsOn,omitempty"`
}
type composition struct {
Aggregate string `json:"aggregate"`
Dependencies []string `json:"dependencies,omitempty"`
}

View File

@@ -16,6 +16,8 @@ package sbom
import ( import (
"bytes" "bytes"
"encoding/base64"
"encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@@ -51,6 +53,17 @@ func ociRef(path string, imgDigest v1.Hash, qual ...qualifier) string {
return purl return purl
} }
func h1ToSHA256(s string) string {
if !strings.HasPrefix(s, "h1:") {
return ""
}
b, err := base64.StdEncoding.DecodeString(s[3:])
if err != nil {
return ""
}
return hex.EncodeToString(b)
}
const dateFormat = "2006-01-02T15:04:05Z" const dateFormat = "2006-01-02T15:04:05Z"
func GenerateImageSPDX(koVersion string, mod []byte, img oci.SignedImage) ([]byte, error) { func GenerateImageSPDX(koVersion string, mod []byte, img oci.SignedImage) ([]byte, error) {

View File

@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:generate go run ./cmd/help/main.go -d docs/reference/
package main package main
import ( import (

View File

@@ -454,44 +454,6 @@ func writeSBOM(sbom []byte, appFileName, dir, ext string) error {
return nil return nil
} }
func cycloneDX() sbomber {
return func(ctx context.Context, file string, appPath string, appFileName string, se oci.SignedEntity, dir string) ([]byte, types.MediaType, error) {
switch obj := se.(type) {
case oci.SignedImage:
b, _, err := goversionm(ctx, file, appPath, appFileName, obj, "")
if err != nil {
return nil, "", err
}
b, err = sbom.GenerateImageCycloneDX(b)
if err != nil {
return nil, "", err
}
if err := writeSBOM(b, appFileName, dir, "cyclonedx.json"); err != nil {
return nil, "", err
}
return b, ctypes.CycloneDXJSONMediaType, nil
case oci.SignedImageIndex:
b, err := sbom.GenerateIndexCycloneDX(obj)
if err != nil {
return nil, "", err
}
if err := writeSBOM(b, appFileName, dir, "cyclonedx.json"); err != nil {
return nil, "", err
}
return b, ctypes.SPDXJSONMediaType, err
default:
return nil, "", fmt.Errorf("unrecognized type: %T", se)
}
}
}
// buildEnv creates the environment variables used by the `go build` command. // buildEnv creates the environment variables used by the `go build` command.
// From `os/exec.Cmd`: If there are duplicate environment keys, only the last // From `os/exec.Cmd`: If there are duplicate environment keys, only the last
// value in the slice for each duplicate key is used. // value in the slice for each duplicate key is used.

View File

@@ -151,15 +151,6 @@ func withBuilder(b builder) Option {
} }
} }
// WithGoVersionSBOM is a functional option to direct ko to use
// go version -m for SBOM format.
func WithGoVersionSBOM() Option {
return func(gbo *gobuildOpener) error {
gbo.sbom = goversionm
return nil
}
}
// WithSPDX is a functional option to direct ko to use // WithSPDX is a functional option to direct ko to use
// SPDX for SBOM format. // SPDX for SBOM format.
func WithSPDX(version string) Option { func WithSPDX(version string) Option {
@@ -169,15 +160,6 @@ func WithSPDX(version string) Option {
} }
} }
// WithCycloneDX is a functional option to direct ko to use CycloneDX for SBOM
// format.
func WithCycloneDX() Option {
return func(gbo *gobuildOpener) error {
gbo.sbom = cycloneDX()
return nil
}
}
// withSBOMber is a functional option for overriding the way SBOMs // withSBOMber is a functional option for overriding the way SBOMs
// are generated. // are generated.
func withSBOMber(sbom sbomber) Option { func withSBOMber(sbom sbomber) Option {

View File

@@ -87,7 +87,7 @@ func AddBuildOptions(cmd *cobra.Command, bo *BuildOptions) {
cmd.Flags().BoolVar(&bo.DisableOptimizations, "disable-optimizations", bo.DisableOptimizations, cmd.Flags().BoolVar(&bo.DisableOptimizations, "disable-optimizations", bo.DisableOptimizations,
"Disable optimizations when building Go code. Useful when you want to interactively debug the created container.") "Disable optimizations when building Go code. Useful when you want to interactively debug the created container.")
cmd.Flags().StringVar(&bo.SBOM, "sbom", "spdx", cmd.Flags().StringVar(&bo.SBOM, "sbom", "spdx",
"The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m).") "The SBOM media type to use (none will disable SBOM synthesis and upload).")
cmd.Flags().StringVar(&bo.SBOMDir, "sbom-dir", "", cmd.Flags().StringVar(&bo.SBOMDir, "sbom-dir", "",
"Path to file where the SBOM will be written.") "Path to file where the SBOM will be written.")
cmd.Flags().StringSliceVar(&bo.Platforms, "platform", []string{}, cmd.Flags().StringSliceVar(&bo.Platforms, "platform", []string{},

View File

@@ -104,10 +104,6 @@ func gobuildOptions(bo *options.BuildOptions) ([]build.Option, error) {
switch bo.SBOM { switch bo.SBOM {
case "none": case "none":
opts = append(opts, build.WithDisabledSBOM()) opts = append(opts, build.WithDisabledSBOM())
case "go.version-m":
opts = append(opts, build.WithGoVersionSBOM())
case "cyclonedx":
opts = append(opts, build.WithCycloneDX())
default: // "spdx" default: // "spdx"
opts = append(opts, build.WithSPDX(version())) opts = append(opts, build.WithSPDX(version()))
} }