Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 53 additions & 18 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ func addBuildFlags(cmd *cobra.Command) {
cmd.Flags().String("coverage-output-path", "", "Output path where test coverage file will be copied after running tests")
cmd.Flags().Bool("disable-coverage", false, "Disable test coverage collection (defaults to false)")
cmd.Flags().StringToString("docker-build-options", nil, "Options passed to all 'docker build' commands")
cmd.Flags().Bool("slsa-cache-verification", false, "Enable SLSA verification for cached artifacts")
cmd.Flags().String("slsa-source-uri", "", "Expected source URI for SLSA verification (required when verification enabled)")
cmd.Flags().String("report", "", "Generate a HTML report after the build has finished. (e.g. --report myreport.html)")
cmd.Flags().String("report-segment", os.Getenv("LEEWAY_SEGMENT_KEY"), "Report build events to segment using the segment key (defaults to $LEEWAY_SEGMENT_KEY)")
cmd.Flags().Bool("report-github", os.Getenv("GITHUB_OUTPUT") != "", "Report package build success/failure to GitHub Actions using the GITHUB_OUTPUT environment variable")
Expand All @@ -194,7 +196,7 @@ func getBuildOpts(cmd *cobra.Command) ([]leeway.BuildOption, cache.LocalCache) {
log.WithField("cacheMode", cm).Debug("configuring caches")
cacheLevel := leeway.CacheLevel(cm)

remoteCache := getRemoteCache()
remoteCache := getRemoteCache(cmd)
switch cacheLevel {
case leeway.CacheNone, leeway.CacheLocal:
remoteCache = remote.NewNoRemoteCache()
Expand Down Expand Up @@ -365,34 +367,67 @@ func (c *pullOnlyRemoteCache) Upload(ctx context.Context, src cache.LocalCache,
return nil
}

func getRemoteCache() cache.RemoteCache {
func getRemoteCacheFromEnv() cache.RemoteCache {
return getRemoteCache(nil)
}

func getRemoteCache(cmd *cobra.Command) cache.RemoteCache {
remoteCacheBucket := os.Getenv(EnvvarRemoteCacheBucket)
remoteStorage := os.Getenv(EnvvarRemoteCacheStorage)

// Get SLSA verification settings from environment variables (defaults)
slsaVerificationEnabled := os.Getenv(EnvvarSLSACacheVerification) == "true"
slsaSourceURI := os.Getenv(EnvvarSLSASourceURI)

// CLI flags override environment variables (if cmd is provided)
if cmd != nil {
if cmd.Flags().Changed("slsa-cache-verification") {
if flagValue, err := cmd.Flags().GetBool("slsa-cache-verification"); err == nil {
slsaVerificationEnabled = flagValue
}
}
if cmd.Flags().Changed("slsa-source-uri") {
if flagValue, err := cmd.Flags().GetString("slsa-source-uri"); err == nil && flagValue != "" {
slsaSourceURI = flagValue
}
}
}

// CONDITIONAL VALIDATION - Follow existing Leeway pattern
if slsaVerificationEnabled && slsaSourceURI == "" {
log.Fatal("--slsa-source-uri is required when using --slsa-cache-verification")
}

if remoteCacheBucket != "" {
config := &cache.RemoteConfig{
BucketName: remoteCacheBucket,
SLSAVerification: slsaVerificationEnabled,
SourceURI: slsaSourceURI,
TrustedRoots: []string{
"https://fulcio.sigstore.dev",
},
}

switch remoteStorage {
case "GCP":
return remote.NewGSUtilCache(
&cache.RemoteConfig{
BucketName: remoteCacheBucket,
},
)
if slsaVerificationEnabled {
log.Warn("SLSA verification not yet supported with GCP storage, verification disabled")
config.SLSAVerification = false
}
return remote.NewGSUtilCache(config)
case "AWS":
rc, err := remote.NewS3Cache(
&cache.RemoteConfig{
BucketName: remoteCacheBucket,
},
)
// AWS supports SLSA verification
rc, err := remote.NewS3Cache(config)
if err != nil {
log.Fatalf("cannot access remote S3 cache: %v", err)
}

return rc
default:
return remote.NewGSUtilCache(
&cache.RemoteConfig{
BucketName: remoteCacheBucket,
},
)
if slsaVerificationEnabled {
log.Warn("SLSA verification not yet supported with GCP storage, verification disabled")
config.SLSAVerification = false
}
return remote.NewGSUtilCache(config)
}
}

Expand Down
34 changes: 21 additions & 13 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ const (

// EnvvarRemoteCacheStorage configures a Remote Storage Provider. Default is GCP
EnvvarRemoteCacheStorage = "LEEWAY_REMOTE_CACHE_STORAGE"

// EnvvarSLSACacheVerification enables SLSA verification for cached artifacts
EnvvarSLSACacheVerification = "LEEWAY_SLSA_CACHE_VERIFICATION"

// EnvvarSLSASourceURI configures the expected source URI for SLSA verification
EnvvarSLSASourceURI = "LEEWAY_SLSA_SOURCE_URI"
)

const (
Expand Down Expand Up @@ -79,19 +85,21 @@ var rootCmd = &cobra.Command{
<white>Configuration</>
Leeway is configured exclusively through the WORKSPACE/BUILD files and environment variables. The following environment
variables have an effect on leeway:
<light_blue>LEEWAY_WORKSPACE_ROOT</> Contains the path where to look for a WORKSPACE file. Can also be set using --workspace.
<light_blue>LEEWAY_REMOTE_CACHE_STORAGE</> Defines the remote caching storage provider. Valid values are "GCP" and "AWS". Defaults to "GCP".
<light_blue>LEEWAY_REMOTE_CACHE_BUCKET</> Enables remote caching using GCP or S3 buckets. Required credentials depend on the storage provider:
- GCP: leeway expects "gsutil" in the path configured and authenticated so that it can work with the bucket.
- AWS: leeway expects that AWS credentials have been provided and with read/write access to the S3 bucket.
For details on configuring AWS credentials see https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html
<light_blue>LEEWAY_CACHE_DIR</> Location of the local build cache. The directory does not have to exist yet.
<light_blue>LEEWAY_BUILD_DIR</> Working location of leeway (i.e. where the actual builds happen). This location will see heavy I/O
which makes it advisable to place this on a fast SSD or in RAM.
<light_blue>LEEWAY_YARN_MUTEX</> Configures the mutex flag leeway will pass to yarn. Defaults to "network".
See https://yarnpkg.com/lang/en/docs/cli/#toc-concurrency-and-mutex for possible values.
<light_blue>LEEWAY_DEFAULT_CACHE_LEVEL</> Sets the default cache level for builds. Defaults to "remote".
<light_blue>LEEWAY_EXPERIMENTAL</> Enables experimental leeway features and commands.
<light_blue>LEEWAY_WORKSPACE_ROOT</> Contains the path where to look for a WORKSPACE file. Can also be set using --workspace.
<light_blue>LEEWAY_REMOTE_CACHE_STORAGE</> Defines the remote caching storage provider. Valid values are "GCP" and "AWS". Defaults to "GCP".
<light_blue>LEEWAY_REMOTE_CACHE_BUCKET</> Enables remote caching using GCP or S3 buckets. Required credentials depend on the storage provider:
- GCP: leeway expects "gsutil" in the path configured and authenticated so that it can work with the bucket.
- AWS: leeway expects that AWS credentials have been provided and with read/write access to the S3 bucket.
For details on configuring AWS credentials see https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html
<light_blue>LEEWAY_CACHE_DIR</> Location of the local build cache. The directory does not have to exist yet.
<light_blue>LEEWAY_BUILD_DIR</> Working location of leeway (i.e. where the actual builds happen). This location will see heavy I/O
which makes it advisable to place this on a fast SSD or in RAM.
<light_blue>LEEWAY_YARN_MUTEX</> Configures the mutex flag leeway will pass to yarn. Defaults to "network".
See https://yarnpkg.com/lang/en/docs/cli/#toc-concurrency-and-mutex for possible values.
<light_blue>LEEWAY_DEFAULT_CACHE_LEVEL</> Sets the default cache level for builds. Defaults to "remote".
<light_blue>LEEWAY_SLSA_CACHE_VERIFICATION</> Enables SLSA verification for cached artifacts (true/false).
<light_blue>LEEWAY_SLSA_SOURCE_URI</> Expected source URI for SLSA verification (github.com/owner/repo).
<light_blue>LEEWAY_EXPERIMENTAL</> Enables experimental leeway features and commands.
`),
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if verbose {
Expand Down
2 changes: 1 addition & 1 deletion cmd/sbom-export.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func GetPackagePath(pkg *leeway.Package, localCache cache.LocalCache) (packagePa
// Package not found in local cache, check if it's in the remote cache
log.Debugf("Package %s not found in local cache, checking remote cache", pkg.FullName())

remoteCache := getRemoteCache()
remoteCache := getRemoteCacheFromEnv()
remoteCache = &pullOnlyRemoteCache{C: remoteCache}

// Convert to cache.Package interface
Expand Down
Loading
Loading