From a272ef19426753378c430bbca9f89b1bf68bdc00 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 23 Jun 2023 12:36:37 +0200 Subject: [PATCH] use containerd's epoch package for handling SOURCE_DATE_EPOCH This allows us to validate the value before we're using it, and makes sure we handle things in the same way. Signed-off-by: Sebastiaan van Stijn --- commands/bake.go | 12 ++-- commands/build.go | 12 ++-- .../containerd/pkg/epoch/context.go | 41 +++++++++++ .../containerd/containerd/pkg/epoch/epoch.go | 69 +++++++++++++++++++ vendor/modules.txt | 1 + 5 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 vendor/github.com/containerd/containerd/pkg/epoch/context.go create mode 100644 vendor/github.com/containerd/containerd/pkg/epoch/epoch.go diff --git a/commands/bake.go b/commands/bake.go index 574a6874..0a9fe3d5 100644 --- a/commands/bake.go +++ b/commands/bake.go @@ -5,8 +5,10 @@ import ( "encoding/json" "fmt" "os" + "strconv" "github.com/containerd/console" + "github.com/containerd/containerd/pkg/epoch" "github.com/containerd/containerd/platforms" "github.com/docker/buildx/bake" "github.com/docker/buildx/build" @@ -162,16 +164,18 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions, cFlags com return err } - if v := os.Getenv("SOURCE_DATE_EPOCH"); v != "" { - // TODO: extract env var parsing to a method easily usable by library consumers + if v, err := epoch.SourceDateEpoch(); err != nil { + return err + } else if v != nil { + esd := strconv.FormatInt(v.Unix(), 10) for _, t := range tgts { - if _, ok := t.Args["SOURCE_DATE_EPOCH"]; ok { + if _, ok := t.Args[epoch.SourceDateEpochEnv]; ok { continue } if t.Args == nil { t.Args = map[string]*string{} } - t.Args["SOURCE_DATE_EPOCH"] = &v + t.Args[epoch.SourceDateEpochEnv] = &esd } } diff --git a/commands/build.go b/commands/build.go index 7feee06e..5b1439b8 100644 --- a/commands/build.go +++ b/commands/build.go @@ -15,6 +15,7 @@ import ( "strings" "github.com/containerd/console" + "github.com/containerd/containerd/pkg/epoch" "github.com/docker/buildx/build" "github.com/docker/buildx/builder" "github.com/docker/buildx/controller" @@ -120,10 +121,13 @@ func (o *buildOptions) toControllerOptions() (*controllerapi.BuildOptions, error ExportLoad: o.exportLoad, } - // TODO: extract env var parsing to a method easily usable by library consumers - if v := os.Getenv("SOURCE_DATE_EPOCH"); v != "" { - if _, ok := opts.BuildArgs["SOURCE_DATE_EPOCH"]; !ok { - opts.BuildArgs["SOURCE_DATE_EPOCH"] = v + if _, ok := opts.BuildArgs[epoch.SourceDateEpochEnv]; !ok { + v, err := epoch.SourceDateEpoch() + if err != nil { + return nil, err + } + if v != nil { + opts.BuildArgs[epoch.SourceDateEpochEnv] = strconv.FormatInt(v.Unix(), 10) } } diff --git a/vendor/github.com/containerd/containerd/pkg/epoch/context.go b/vendor/github.com/containerd/containerd/pkg/epoch/context.go new file mode 100644 index 00000000..fd16f951 --- /dev/null +++ b/vendor/github.com/containerd/containerd/pkg/epoch/context.go @@ -0,0 +1,41 @@ +/* + Copyright The containerd Authors. + + 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 epoch + +import ( + "context" + "time" +) + +type ( + epochKey struct{} +) + +// WithSourceDateEpoch associates the context with the epoch. +func WithSourceDateEpoch(ctx context.Context, tm *time.Time) context.Context { + return context.WithValue(ctx, epochKey{}, tm) +} + +// FromContext returns the epoch associated with the context. +// FromContext does not fall back to read the SOURCE_DATE_EPOCH env var. +func FromContext(ctx context.Context) *time.Time { + v := ctx.Value(epochKey{}) + if v == nil { + return nil + } + return v.(*time.Time) +} diff --git a/vendor/github.com/containerd/containerd/pkg/epoch/epoch.go b/vendor/github.com/containerd/containerd/pkg/epoch/epoch.go new file mode 100644 index 00000000..124e8edb --- /dev/null +++ b/vendor/github.com/containerd/containerd/pkg/epoch/epoch.go @@ -0,0 +1,69 @@ +/* + Copyright The containerd Authors. + + 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 epoch provides SOURCE_DATE_EPOCH utilities. +package epoch + +import ( + "fmt" + "os" + "strconv" + "time" + + "github.com/sirupsen/logrus" +) + +// SourceDateEpochEnv is the SOURCE_DATE_EPOCH env var. +// See https://reproducible-builds.org/docs/source-date-epoch/ +const SourceDateEpochEnv = "SOURCE_DATE_EPOCH" + +// SourceDateEpoch returns the SOURCE_DATE_EPOCH env var as *time.Time. +// If the env var is not set, SourceDateEpoch returns nil without an error. +func SourceDateEpoch() (*time.Time, error) { + v, ok := os.LookupEnv(SourceDateEpochEnv) + if !ok || v == "" { + return nil, nil // not an error + } + i64, err := strconv.ParseInt(v, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid %s value %q: %w", SourceDateEpochEnv, v, err) + } + unix := time.Unix(i64, 0).UTC() + return &unix, nil +} + +// SourceDateEpochOrNow returns the SOURCE_DATE_EPOCH time if available, +// otherwise returns the current time. +func SourceDateEpochOrNow() time.Time { + epoch, err := SourceDateEpoch() + if err != nil { + logrus.WithError(err).Warnf("Invalid %s", SourceDateEpochEnv) + } + if epoch != nil { + return *epoch + } + return time.Now().UTC() +} + +// SetSourceDateEpoch sets the SOURCE_DATE_EPOCH env var. +func SetSourceDateEpoch(tm time.Time) { + os.Setenv(SourceDateEpochEnv, fmt.Sprintf("%d", tm.Unix())) +} + +// UnsetSourceDateEpoch unsets the SOURCE_DATE_EPOCH env var. +func UnsetSourceDateEpoch() { + os.Unsetenv(SourceDateEpochEnv) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 453d24b1..afa21ae3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -165,6 +165,7 @@ github.com/containerd/containerd/leases github.com/containerd/containerd/log github.com/containerd/containerd/namespaces github.com/containerd/containerd/pkg/dialer +github.com/containerd/containerd/pkg/epoch github.com/containerd/containerd/pkg/randutil github.com/containerd/containerd/pkg/seed github.com/containerd/containerd/pkg/userns