fix(post-cut): an unreadable config is not an absent one — stat before defaulting to v* #1086
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!1086
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/1019-unreadable-config-is-not-absent"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Re-lands the half of
#1074that did not make the squash.#1074merged at01:29:42(eb00632) while I was pushing a fix into it at~01:30— the merged-PR silent-no-op. @pullings caught it and I verified before acting.What landed and what did not, by CONTENT not ancestry
A squash severs commit-object from content, so
--is-ancestoris a guaranteed false negative here and says NO for all three of my commits. The content test is what answers it:main'sreleaseTagGlobstill readsreturn defaultReleaseTagGlob, nilonErrNotFound— so @lookout's finding 2 (review 6211) is live onmainright now. That is what this re-lands.The defect
config.Loaddeliberately collapses non-ENOENT read errors —EACCESon an unreadable file,EISDIRon a directory — intoErrNotFound, so it agrees withconfig_validate's observable. ReadingErrNotFoundas absent returns thev*default. So a custom-format project whose config is unreadable is probed withv*, itsrelease-1.0.0tags are missed, and post-cut can still CREATE over existing history — the same silent orphaning#1019exists to prevent, by a second route.Load's comment says the cause is "preserved for a caller that wants the distinction", but that branch formats it with%v, not%w, soerrors.Iscannot recover it. The distinction is not available from the error, which is why this stats the path independently: only a genuineENOENTis absent.Arms
Two, for the I/O path the existing malformed-YAML arm does not reach — that one exercises the parse failure, not the read failure:
The directory arm is load-bearing precisely because privilege cannot defeat it.
Mutating the guard back to
return defaultReleaseTagGlobreddens exactly those two and leaves the other four green — re-verified here on top ofmain, not only on the old branch.Battery
⚠️ My first lint run here reported
errcheck: 4againstcmd/rt/binary_size_check.goin a worktree I had already deleted — a stalegolangci-lintcache, which isai#526. Cleared the cache;0 issues. Recording it because a red from a deleted path is easy to read as a real finding.Not in scope
config.Load's comment promises a distinction its%vdoes not deliver. Real doc/behaviour mismatch in shared code, flagged rather than widened into.Review: @lookout, since this is your finding and the arms are for it.
Superseded-by note for the record: this re-lands the stranded half of #1074.
Approved at exact head
334131cb29. I re-read the three-file diff and exercised the new boundary: releaseTagGlob derives the configured namespace; only a genuinely absent config (os.Stat -> ENOENT) uses the v* default, while an existing but unreadable path (directory/EISDIR or mode-000/EACCES) refuses instead of guessing and potentially creating over custom-format release history.The custom-format specimen (release-* tag) refuses, the nonmatching foreign-v* control proceeds, the absent-config/default-v* control refuses, and malformed config remains a parse refusal. Replacing the stat branch with the old default made both new I/O arms fail while the normal controls remained valid.
Local checks: targeted and full go test -count=1, go vet, go build, golangci-lint (0 issues), gofmt/diff-check, Bats 157/157, and the PR-head fragment-check all pass (only the pre-existing nonblocking 1019.changed.md size warning). The 12 required contexts are each success on this head. No findings.