cloudposse / cloudposse/atmos

archive step: mtime git/epoch silently stamp 1980-01-01 in linked git worktrees

Open
#2,823 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
1.4k
Forks
175
Avg merge
2d 3h
Merged PRs (30d)
134

Description

The archive step's promise is that identical committed sources yield byte-identical archives on any machine. In a linked worktree (`git worktree add`) the promise quietly inverts: the same commit produces different bytes than a plain checkout, with no warning that anything degraded.

## Describe the Bug

With `mtime: git` (or `epoch`), building from a plain checkout stamps entries with real commit timestamps. Building the same commit from a linked worktree stamps every entry with the 1980-01-01 fallback, so the two archives differ byte-for-byte and any hash-based consumer (S3 etags, SSM package manifests, lockfiles) sees a phantom change.

### Expected Behavior

The docs scope the fallback to operating "outside a Git repository" or untracked paths. A linked worktree is inside a git repository (`git log` works normally there), so I expected commit timestamps, matching the plain checkout.

### Actual Behavior

Every entry gets the fallback. `unzip -l` on two builds of the same commit:

```
=== control: plain checkout ===
6 07-28-2026 17:48 a.sh
=== trial: linked worktree of the same commit ===
6 12-31-1979 18:00 a.sh
```

(The trial row is 1980-01-01 00:00 UTC rendered in local time.)

### Steps to Reproduce

Self-contained script and one fresh run (Atmos 1.224.1, darwin/arm64)

```bash
#!/usr/bin/env bash
# Repro: archive step mtime git/epoch silently fall back to 1980-01-01
# inside a linked git worktree, while a plain checkout of the same commit
# resolves real commit timestamps.
set -euo pipefail

ATMOS="${ATMOS:-atmos}"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
cd "$tmp"

"$ATMOS" version

git init -q repo
cd repo
mkdir src
printf 'hello\n' > src/a.sh
git add src/a.sh
git -c user.name=repro -c user.email=repro@example.invalid -c commit.gpgsign=false \
commit -qm 'add a.sh'
git log -1 --format='committed: %cI'

cat > atmos.yaml <<'YAML'
base_path: ""
components: { terraform: { base_path: "components" } }
stacks: { base_path: "stacks", included_paths: ["**/*"], name_pattern: "{stage}" }
workflows: { base_path: "workflows" }
YAML
mkdir -p workflows stacks
cat > workflows/repro.yaml <<'YAML'
workflows:
build:
steps:
- name: pkg
type: archive
source: src
destination: out.zip
format: zip
action: replace
mtime: git
YAML

echo "=== control: plain checkout ==="
"$ATMOS" workflow build -f repro
unzip -l out.zip | grep 'a.sh'

echo "=== trial: linked worktree of the same commit ==="
git worktree add -q ../wt HEAD
cp atmos.yaml ../wt/
cp -R workflows ../wt/
mkdir -p ../wt/stacks
cd ../wt
"$ATMOS" workflow build -f repro
unzip -l out.zip | grep 'a.sh'
```

Transcript:

```
👽 Atmos 1.224.1 on darwin/arm64

committed: 2026-07-28T17:48:06-05:00
=== control: plain checkout ===
6 07-28-2026 17:48 a.sh
=== trial: linked worktree of the same commit ===
6 12-31-1979 18:00 a.sh
```

### Mechanism

`newMtimeConfig` is deliberately fail-open: any error locating the repository or its history falls back to `mtimeFallbackEpoch`, which is the right call for temp build dirs and untracked files but also swallows this case. In a linked worktree `.git` is a gitdir pointer file rather than a directory; go-git's linked-worktree support looks partial (go-git/go-git#1812 reviewed the API for opening them), and somewhere along `PlainOpenWithOptions(DetectDotGit)` / `Worktree()` / `Head()` the resolution fails, so the fallback engages with no signal. This may be the archive-step sibling of the worktree gaps #1509 addresses for `describe affected`.

Relevant paths: `pkg/archive/mtime.go` (`newMtimeConfig`, `modTimeFor`, `mtimeFallbackEpoch`).

### Ask

Could `newMtimeConfig` resolve the gitdir pointer for linked worktrees, or at least log a warning when a `.git` entry exists but git resolution falls back to the epoch? The silent divergence is the painful part; a build that warns is easy to live with. Happy to follow up with a PR.

Environment: Atmos 1.224.1 (`pkg/archive/mtime.go` is unchanged on `main`), darwin/arm64, git version 2.55.0.

Contributor guide

Open the contributing guide

Research direction

Read pkg/archive/mtime.go, especially newMtimeConfig, modTimeFor, and mtimeFallbackEpoch, then run the self-contained linked-worktree reproduction in the issue. Done means the same commit gets matching archive timestamps in a plain checkout and linked worktree, or the fallback produces a warning when Git resolution fails.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, go
Domain
build-system, cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
70/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.