cache.Key() (pkg/core/cache/source.go:69) hashes resource.ReportConfig(). The cache is created unconditionally in pkg/core/engine/run.go:32 with no opt-out, so any spec field a plugin leaves out of ReportConfig is invisible to the cache key. Two distinct sources then share a key and the second silently receives the first one's value.
ReportConfig predates the cache (#4898, report export), where omitting a field was harmless.
#9821 is one instance of this (temurin omitted specificversion). Auditing all 43 implementations found 11 more.
Method: AST diff of each Spec against the fields assigned in its ReportConfig, then manual verification that the field reaches the Source() path.
| Plugin |
Missing |
Collision |
shell |
Shell, WorkDir, Environments |
Same command in two workdirs: second source gets the first's stdout |
updateclihttp |
Request (Verb, Body, Headers, NoFollowRedirects) |
Same url, different POST body or verb (main.go:62-80) |
yaml |
DocumentIndex |
Same file and key, different document (source.go:91) |
csv |
Comma, Comment, VersionFilter |
Different separator or version filter |
maven |
VersionFilter |
Same artifact, different filter |
cargopackage |
VersionFilter |
Same |
json |
Engine |
dasel v1/v2/v3 differ in query semantics (source.go:37+) |
awsami |
SortBy |
Newest vs oldest AMI from identical filters (helpers.go:37) |
go/gomod |
Indirect, Replace, ReplaceVersion |
Different module version from the same go.mod (version.go:48-134) |
gittag |
LsRemote, Depth |
lsremote bypasses the clone; depth truncates the tag list |
gitbranch |
Depth |
Clone depth changes the branch list |
Verified as not bugs: credentials (intentional, documented at pkg/core/cache/source.go:46); target/condition-only fields (file.ForceCreate, yaml.Comment, gittag.Message, release Title/Commitish/Description/Draft/Prerelease, updateclihttp.ResponseAsserts); json.Multiple and csv.Multiple (deprecated, normalized into the reported Query at New()).
Decision needed
Nine are a one-line addition each. Two are not: shell.Environments and updateclihttp.Request.Headers routinely carry secrets, and ReportConfig now serves two conflicting contracts, redaction for display and completeness for keying. Redacting two distinct values to the same string reintroduces the collision.
- Add the 9 safe fields, leave
shell and updateclihttp.
- Split the concerns: a separate cache-key method on the resource interface,
ReportConfig untouched for display. Touches every plugin, removes the bug class.
- One method, but hash secret-bearing fields instead of redacting them, so distinct values stay distinct without appearing in the report.
Option 2 makes the contract explicit, which matters because the failure mode is silent: no error, no warning, just a wrong value written to the target.
@olblak preference?
cache.Key()(pkg/core/cache/source.go:69) hashesresource.ReportConfig(). The cache is created unconditionally inpkg/core/engine/run.go:32with no opt-out, so any spec field a plugin leaves out ofReportConfigis invisible to the cache key. Two distinct sources then share a key and the second silently receives the first one's value.ReportConfigpredates the cache (#4898, report export), where omitting a field was harmless.#9821 is one instance of this (
temurinomittedspecificversion). Auditing all 43 implementations found 11 more.Method: AST diff of each
Specagainst the fields assigned in itsReportConfig, then manual verification that the field reaches theSource()path.shellShell,WorkDir,Environmentscommandin twoworkdirs: second source gets the first's stdoutupdateclihttpRequest(Verb,Body,Headers,NoFollowRedirects)url, different POST body or verb (main.go:62-80)yamlDocumentIndexsource.go:91)csvComma,Comment,VersionFiltermavenVersionFiltercargopackageVersionFilterjsonEnginesource.go:37+)awsamiSortByhelpers.go:37)go/gomodIndirect,Replace,ReplaceVersiongo.mod(version.go:48-134)gittagLsRemote,Depthlsremotebypasses the clone;depthtruncates the tag listgitbranchDepthVerified as not bugs: credentials (intentional, documented at
pkg/core/cache/source.go:46); target/condition-only fields (file.ForceCreate,yaml.Comment,gittag.Message, releaseTitle/Commitish/Description/Draft/Prerelease,updateclihttp.ResponseAsserts);json.Multipleandcsv.Multiple(deprecated, normalized into the reportedQueryatNew()).Decision needed
Nine are a one-line addition each. Two are not:
shell.Environmentsandupdateclihttp.Request.Headersroutinely carry secrets, andReportConfignow serves two conflicting contracts, redaction for display and completeness for keying. Redacting two distinct values to the same string reintroduces the collision.shellandupdateclihttp.ReportConfiguntouched for display. Touches every plugin, removes the bug class.Option 2 makes the contract explicit, which matters because the failure mode is silent: no error, no warning, just a wrong value written to the target.
@olblak preference?