mirror of
https://github.com/helm/helm.git
synced 2026-04-24 07:37:48 -04:00
fix(epoch): override all timestamps unconditionally and route warnings through m.Out
ApplySourceDateEpoch previously only stamped entries with a zero ModTime, but charts loaded from disk (via loader.LoadDir) already have non-zero ModTimes populated from the filesystem. This made the function a no-op in the common helm-package path, defeating reproducible builds. The function now unconditionally overrides every ModTime to the SOURCE_DATE_EPOCH value, which is the correct behaviour for producing bit-for-bit identical archives regardless of filesystem metadata. Additionally, tarFromLocalDir in pkg/downloader/manager.go was writing its SOURCE_DATE_EPOCH warning directly to os.Stderr, which is inconsistent with the rest of Manager that routes user-facing output through m.Out. The function now accepts an io.Writer parameter and the call site passes m.Out. Tests updated to verify that existing (non-zero) timestamps are overridden rather than preserved. Signed-off-by: Maxime Kawawa-Beaudan <maxkawab@gmail.com> Signed-off-by: Maxime Grenu <maxime.grenu@gmail.com>
This commit is contained in:
parent
f2d339dfa4
commit
81c8a2d844
5 changed files with 65 additions and 47 deletions
|
|
@ -47,36 +47,29 @@ func ParseSourceDateEpoch() (time.Time, error) {
|
|||
return time.Unix(epoch, 0), nil
|
||||
}
|
||||
|
||||
// ApplySourceDateEpoch sets the ModTime on the chart and all of its entries
|
||||
// that currently have a zero ModTime to t. It recurses into dependencies.
|
||||
// ApplySourceDateEpoch overrides the ModTime on the chart and all of its
|
||||
// entries to t, ensuring reproducible archives regardless of the original
|
||||
// timestamps. It recurses into dependencies.
|
||||
// When t is the zero time this is a no-op.
|
||||
func ApplySourceDateEpoch(c *chart.Chart, t time.Time) {
|
||||
if t.IsZero() {
|
||||
return
|
||||
}
|
||||
if c.ModTime.IsZero() {
|
||||
c.ModTime = t
|
||||
}
|
||||
if c.Lock != nil && c.Lock.Generated.IsZero() {
|
||||
c.ModTime = t
|
||||
if c.Lock != nil {
|
||||
c.Lock.Generated = t
|
||||
}
|
||||
if c.Schema != nil && c.SchemaModTime.IsZero() {
|
||||
if c.Schema != nil {
|
||||
c.SchemaModTime = t
|
||||
}
|
||||
for _, f := range c.Raw {
|
||||
if f.ModTime.IsZero() {
|
||||
f.ModTime = t
|
||||
}
|
||||
f.ModTime = t
|
||||
}
|
||||
for _, f := range c.Templates {
|
||||
if f.ModTime.IsZero() {
|
||||
f.ModTime = t
|
||||
}
|
||||
f.ModTime = t
|
||||
}
|
||||
for _, f := range c.Files {
|
||||
if f.ModTime.IsZero() {
|
||||
f.ModTime = t
|
||||
}
|
||||
f.ModTime = t
|
||||
}
|
||||
for _, dep := range c.Dependencies() {
|
||||
ApplySourceDateEpoch(dep, t)
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ func TestApplySourceDateEpoch(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestApplySourceDateEpochPreservesExisting(t *testing.T) {
|
||||
func TestApplySourceDateEpochOverridesExisting(t *testing.T) {
|
||||
epoch := time.Unix(1700000000, 0)
|
||||
existing := time.Unix(1600000000, 0)
|
||||
|
||||
|
|
@ -133,12 +133,28 @@ func TestApplySourceDateEpochPreservesExisting(t *testing.T) {
|
|||
Version: "0.1.0",
|
||||
},
|
||||
ModTime: existing,
|
||||
Templates: []*common.File{
|
||||
{Name: "templates/test.yaml", ModTime: existing},
|
||||
},
|
||||
Files: []*common.File{
|
||||
{Name: "README.md", ModTime: existing},
|
||||
},
|
||||
}
|
||||
|
||||
ApplySourceDateEpoch(c, epoch)
|
||||
|
||||
if !c.ModTime.Equal(existing) {
|
||||
t.Errorf("Chart.ModTime = %v, want existing %v", c.ModTime, existing)
|
||||
if !c.ModTime.Equal(epoch) {
|
||||
t.Errorf("Chart.ModTime = %v, want epoch %v", c.ModTime, epoch)
|
||||
}
|
||||
for _, f := range c.Templates {
|
||||
if !f.ModTime.Equal(epoch) {
|
||||
t.Errorf("Template %s ModTime = %v, want epoch %v", f.Name, f.ModTime, epoch)
|
||||
}
|
||||
}
|
||||
for _, f := range c.Files {
|
||||
if !f.ModTime.Equal(epoch) {
|
||||
t.Errorf("File %s ModTime = %v, want epoch %v", f.Name, f.ModTime, epoch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -185,9 +201,9 @@ func TestApplySourceDateEpochDependencies(t *testing.T) {
|
|||
|
||||
ApplySourceDateEpoch(c, epoch)
|
||||
|
||||
// Parent chart already had a ModTime, so it should be preserved.
|
||||
if !c.ModTime.Equal(existing) {
|
||||
t.Errorf("parent Chart.ModTime = %v, want existing %v", c.ModTime, existing)
|
||||
// Parent chart had an existing ModTime, but it should be overridden.
|
||||
if !c.ModTime.Equal(epoch) {
|
||||
t.Errorf("parent Chart.ModTime = %v, want epoch %v", c.ModTime, epoch)
|
||||
}
|
||||
// Dependency had a zero ModTime, so it should be stamped.
|
||||
if !dep.ModTime.Equal(epoch) {
|
||||
|
|
|
|||
|
|
@ -47,36 +47,29 @@ func ParseSourceDateEpoch() (time.Time, error) {
|
|||
return time.Unix(epoch, 0), nil
|
||||
}
|
||||
|
||||
// ApplySourceDateEpoch sets the ModTime on the chart and all of its entries
|
||||
// that currently have a zero ModTime to t. It recurses into dependencies.
|
||||
// ApplySourceDateEpoch overrides the ModTime on the chart and all of its
|
||||
// entries to t, ensuring reproducible archives regardless of the original
|
||||
// timestamps. It recurses into dependencies.
|
||||
// When t is the zero time this is a no-op.
|
||||
func ApplySourceDateEpoch(c *chart.Chart, t time.Time) {
|
||||
if t.IsZero() {
|
||||
return
|
||||
}
|
||||
if c.ModTime.IsZero() {
|
||||
c.ModTime = t
|
||||
}
|
||||
if c.Lock != nil && c.Lock.Generated.IsZero() {
|
||||
c.ModTime = t
|
||||
if c.Lock != nil {
|
||||
c.Lock.Generated = t
|
||||
}
|
||||
if c.Schema != nil && c.SchemaModTime.IsZero() {
|
||||
if c.Schema != nil {
|
||||
c.SchemaModTime = t
|
||||
}
|
||||
for _, f := range c.Raw {
|
||||
if f.ModTime.IsZero() {
|
||||
f.ModTime = t
|
||||
}
|
||||
f.ModTime = t
|
||||
}
|
||||
for _, f := range c.Templates {
|
||||
if f.ModTime.IsZero() {
|
||||
f.ModTime = t
|
||||
}
|
||||
f.ModTime = t
|
||||
}
|
||||
for _, f := range c.Files {
|
||||
if f.ModTime.IsZero() {
|
||||
f.ModTime = t
|
||||
}
|
||||
f.ModTime = t
|
||||
}
|
||||
for _, dep := range c.Dependencies() {
|
||||
ApplySourceDateEpoch(dep, t)
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ func TestApplySourceDateEpoch(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestApplySourceDateEpochPreservesExisting(t *testing.T) {
|
||||
func TestApplySourceDateEpochOverridesExisting(t *testing.T) {
|
||||
epoch := time.Unix(1700000000, 0)
|
||||
existing := time.Unix(1600000000, 0)
|
||||
|
||||
|
|
@ -133,12 +133,28 @@ func TestApplySourceDateEpochPreservesExisting(t *testing.T) {
|
|||
Version: "0.1.0",
|
||||
},
|
||||
ModTime: existing,
|
||||
Templates: []*common.File{
|
||||
{Name: "templates/test.yaml", ModTime: existing},
|
||||
},
|
||||
Files: []*common.File{
|
||||
{Name: "README.md", ModTime: existing},
|
||||
},
|
||||
}
|
||||
|
||||
ApplySourceDateEpoch(c, epoch)
|
||||
|
||||
if !c.ModTime.Equal(existing) {
|
||||
t.Errorf("Chart.ModTime = %v, want existing %v", c.ModTime, existing)
|
||||
if !c.ModTime.Equal(epoch) {
|
||||
t.Errorf("Chart.ModTime = %v, want epoch %v", c.ModTime, epoch)
|
||||
}
|
||||
for _, f := range c.Templates {
|
||||
if !f.ModTime.Equal(epoch) {
|
||||
t.Errorf("Template %s ModTime = %v, want epoch %v", f.Name, f.ModTime, epoch)
|
||||
}
|
||||
}
|
||||
for _, f := range c.Files {
|
||||
if !f.ModTime.Equal(epoch) {
|
||||
t.Errorf("File %s ModTime = %v, want epoch %v", f.Name, f.ModTime, epoch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -187,9 +203,9 @@ func TestApplySourceDateEpochDependencies(t *testing.T) {
|
|||
|
||||
ApplySourceDateEpoch(c, epoch)
|
||||
|
||||
// Parent chart already had a ModTime, so it should be preserved.
|
||||
if !c.ModTime.Equal(existing) {
|
||||
t.Errorf("parent Chart.ModTime = %v, want existing %v", c.ModTime, existing)
|
||||
// Parent chart had an existing ModTime, but it should be overridden.
|
||||
if !c.ModTime.Equal(epoch) {
|
||||
t.Errorf("parent Chart.ModTime = %v, want epoch %v", c.ModTime, epoch)
|
||||
}
|
||||
// Dependency had a zero ModTime, so it should be stamped.
|
||||
if !dep.ModTime.Equal(epoch) {
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
|
|||
if m.Debug {
|
||||
fmt.Fprintf(m.Out, "Archiving %s from repo %s\n", dep.Name, dep.Repository)
|
||||
}
|
||||
ver, err := tarFromLocalDir(m.ChartPath, dep.Name, dep.Repository, dep.Version, tmpPath)
|
||||
ver, err := tarFromLocalDir(m.ChartPath, dep.Name, dep.Repository, dep.Version, tmpPath, m.Out)
|
||||
if err != nil {
|
||||
saveError = err
|
||||
break
|
||||
|
|
@ -873,7 +873,7 @@ func writeLock(chartpath string, lock *chart.Lock, legacyLockfile bool) error {
|
|||
}
|
||||
|
||||
// archive a dep chart from local directory and save it into destPath
|
||||
func tarFromLocalDir(chartpath, name, repo, version, destPath string) (string, error) {
|
||||
func tarFromLocalDir(chartpath, name, repo, version, destPath string, out io.Writer) (string, error) {
|
||||
if !strings.HasPrefix(repo, "file://") {
|
||||
return "", fmt.Errorf("wrong format: chart %s repository %s", name, repo)
|
||||
}
|
||||
|
|
@ -902,7 +902,7 @@ func tarFromLocalDir(chartpath, name, repo, version, destPath string) (string, e
|
|||
// Apply SOURCE_DATE_EPOCH for reproducible builds if set.
|
||||
epoch, epochErr := chartutil.ParseSourceDateEpoch()
|
||||
if epochErr != nil {
|
||||
fmt.Fprintf(os.Stderr, "WARNING: %v\n", epochErr)
|
||||
fmt.Fprintf(out, "WARNING: %v\n", epochErr)
|
||||
}
|
||||
chartutil.ApplySourceDateEpoch(ch, epoch)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue