Check native overlay link targets

This commit is contained in:
2026-11-09 21:16:30 +00:00
parent 9a08438769
commit 81c27bb9cd
3 changed files with 87 additions and 7 deletions

View File

@@ -76,12 +76,21 @@ func loadSelectedOverlay(request selectedOverlayRequest, access *filesystemAcces
lookupDirectory = access.rootPath
}
overlayPath := access.join(lookupDirectory, "overlays/"+request.name+".yml")
canonical, err := access.canonical(overlayPath)
links, _ := access.native.(fs.ReadLinkFS)
var canonical string
var err error
if links != nil {
canonical, err = resolveNativeImportPath(access, links, overlayPath)
} else {
canonical, err = access.canonical(overlayPath)
}
if err != nil {
code := CodeOverlayInvalid
message := "selected overlay could not be resolved"
if errors.Is(err, fs.ErrNotExist) {
code, message = CodeOverlayMissing, "selected overlay does not exist"
} else if errors.Is(err, errImportPathOutsideRoot) {
code, message = CodeOverlayOutsideRoot, "selected overlay resolves outside the configuration root"
} else if errors.Is(err, fs.ErrPermission) {
code, message = CodeImportPermission, "selected overlay cannot be accessed"
}
@@ -90,12 +99,8 @@ func loadSelectedOverlay(request selectedOverlayRequest, access *filesystemAcces
if !access.contains(canonical) {
return cloneSourceInfos(sources), []Diagnostic{importDiagnostic(CodeOverlayOutsideRoot, "selected overlay resolves outside the configuration root", nil)}
}
for _, existing := range sources {
if existing.Path != "" && existing.Path == canonical &&
((access.native == nil && existing.Kind == SourceKindFile) ||
(access.native != nil && existing.Kind == SourceKindFilesystem && existing.namespace == access.token)) {
return cloneSourceInfos(sources), []Diagnostic{importDiagnostic(CodeOverlayRepeated, "selected overlay is already present in the base source graph", nil)}
}
if overlayRepeatsSource(access, links, canonical, sources) {
return cloneSourceInfos(sources), []Diagnostic{importDiagnostic(CodeOverlayRepeated, "selected overlay is already present in the base source graph", nil)}
}
if len(sources)+1 > limits.sources {
return cloneSourceInfos(sources), []Diagnostic{importDiagnostic(CodeOverlayLimitExceeded, "selected overlay exceeds the source-count limit", nil)}
@@ -174,6 +179,37 @@ func loadSelectedOverlay(request selectedOverlayRequest, access *filesystemAcces
return sources, nil
}
func overlayRepeatsSource(access *filesystemAccess, links fs.ReadLinkFS, canonical string, sources []SourceInfo) bool {
// Other inputs can have a wider root. Compare their identities in the
// shared native namespace while keeping overlay lookup rooted separately.
namespaceAccess := *access
namespaceAccess.rootPath = "."
for _, source := range sources {
if source.Path == "" {
continue
}
if access.native == nil {
if source.Kind == SourceKindFile && source.Path == canonical {
return true
}
continue
}
if source.Kind != SourceKindFilesystem || source.namespace != access.token {
continue
}
if source.Path == canonical {
return true
}
if links != nil {
target, err := resolveNativeImportPath(&namespaceAccess, links, source.Path)
if err == nil && target == canonical {
return true
}
}
}
return false
}
func readOverlayFile(access *filesystemAccess, name, sourceID string, remaining int64) ([]byte, *Diagnostic) {
limit := min(int64(maxSourceBytes), remaining)
if limit < 0 {