OCI-reference heuristic misclassifies tagless references as local files
Where: internal/source/source.go:100-103 (IsOCIReference), used by LoadArtifacts
(source.go:35). The same heuristic is copied into cmd/complypack/cli/pull.go:105
(isOCISource).
func IsOCIReference(source string) bool {
return strings.Contains(source, "/") &&
(strings.Contains(source, ":") || strings.Contains(source, "//"))
}
What's wrong: a valid but tagless registry reference such as
ghcr.io/org/catalog (which defaults to :latest) contains a / but no : and no
//, so the heuristic returns false. LoadArtifacts then routes it to the file loader
→ os.ReadFile("ghcr.io/org/catalog") → "failed to read file". The pull command has
the same gap and silently skips such a source as a "local source".
Why it matters: the classifier can't tell a registry host (host[:port]/path) from a
file path by punctuation alone; the tag is what makes it match today. Any OCI source
written without an explicit tag is mishandled — and because the same logic is duplicated
in two places, a fix has to be applied twice unless the copies are consolidated first.
Suggestion: classify by parsing rather than substring checks — e.g. attempt
registry.ParseReference and treat a successful parse with a registry host as OCI, or at
minimum require the first path segment to look like a host (contains . or :, or
equals localhost).
Drafted with LLM assistance (Claude Opus 4.6).
OCI-reference heuristic misclassifies tagless references as local files
Where:
internal/source/source.go:100-103(IsOCIReference), used byLoadArtifacts(source.go:35). The same heuristic is copied into
cmd/complypack/cli/pull.go:105(
isOCISource).What's wrong: a valid but tagless registry reference such as
ghcr.io/org/catalog(which defaults to:latest) contains a/but no:and no//, so the heuristic returnsfalse.LoadArtifactsthen routes it to the file loader→
os.ReadFile("ghcr.io/org/catalog")→ "failed to read file". Thepullcommand hasthe same gap and silently skips such a source as a "local source".
Why it matters: the classifier can't tell a registry host (
host[:port]/path) from afile path by punctuation alone; the tag is what makes it match today. Any OCI source
written without an explicit tag is mishandled — and because the same logic is duplicated
in two places, a fix has to be applied twice unless the copies are consolidated first.
Suggestion: classify by parsing rather than substring checks — e.g. attempt
registry.ParseReferenceand treat a successful parse with a registry host as OCI, or atminimum require the first path segment to look like a host (contains
.or:, orequals
localhost).Drafted with LLM assistance (Claude Opus 4.6).