Validate complete import depth numbers

This commit is contained in:
2026-10-20 00:27:55 +00:00
parent 7f8ad81065
commit d3a714a1cb
3 changed files with 40 additions and 3 deletions

View File

@@ -1,6 +1,6 @@
# Import Discovery and Scheduling Review Findings # Import Discovery and Scheduling Review Findings
Status: in progress; issues 1–4 complete, two findings remain. Status: in progress; issues 1–5 complete, one finding remains.
Reviewed implementation: `aa93aed..15943e2`, ending at Reviewed implementation: `aa93aed..15943e2`, ending at
`15943e233ca3cd1286c03c0e7085871db344cd4b`, against the accepted `15943e233ca3cd1286c03c0e7085871db344cd4b`, against the accepted
@@ -150,7 +150,7 @@ loops, plus public host/native directory/glob loading coverage. Finite cases
failed before the change; all pass now alongside existing traversal-cycle and failed before the change; all pass now alongside existing traversal-cycle and
containment tests. The full everyday check passed; no new limit was added. containment tests. The full everyday check passed; no new limit was added.
## 5. [ ] P2 — Validate the complete depth token before saturating its value ## 5. [x] P2 — Validate the complete depth token before saturating its value
Owner: [parseImportDepth](../../internal/engine/import_spec.go), around lines Owner: [parseImportDepth](../../internal/engine/import_spec.go), around lines
423–430. 423–430.
@@ -171,6 +171,12 @@ large valid nonnegative integers and numeric `-0`; do not introduce a machine-si
maximum. Cover invalid suffixes after the overflow point as well as ordinary maximum. Cover invalid suffixes after the overflow point as well as ordinary
invalid depths and valid large integers. invalid depths and valid large integers.
Completed: depth parsing saturates its accumulator without stopping token
validation. Public absent-directory regressions now reject fractional/exponent
suffixes after overflow and retain valid huge integers and `-0`. The two invalid
cases failed before the fix. Existing depth/specification coverage and the full
everyday check passed; the accepted integer range was not narrowed.
## 6. [ ] P2 — Apply the active import-depth limit to actual inclusion edges ## 6. [ ] P2 — Apply the active import-depth limit to actual inclusion edges
Owner: [walkDeclarations](../../internal/engine/imports.go), around lines 403–405. Owner: [walkDeclarations](../../internal/engine/imports.go), around lines 403–405.

View File

@@ -10,6 +10,36 @@ import (
"gitea.maximumdirect.net/eric/ConfigKit/internal/engine" "gitea.maximumdirect.net/eric/ConfigKit/internal/engine"
) )
func TestImportDepthChecksSuffixAfterSaturation(t *testing.T) {
for _, test := range []struct {
depth string
valid bool
}{
{"999999999999999999999999.5", false},
{"999999999999999999999999e1", false},
{"999999999999999999999999", true},
{"-0", true},
} {
t.Run(test.depth, func(t *testing.T) {
main := writeFacadeImportFile(t, t.TempDir(), "main.yml", "value: true\nconfigkit:\n imports:\n - dir: absent\n recursive: true\n depth: "+test.depth+"\n")
result, err := Load[map[string]any](File(main), Options[map[string]any]{Imports: true})
if test.valid {
if err != nil || result.Config["value"] != true {
t.Fatalf("valid depth: %v", err)
}
return
}
var loadError *LoadError
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) != 1 {
t.Fatalf("invalid depth accepted: %v", err)
}
if diagnostic := loadError.Diagnostics()[0]; diagnostic.Code != CodeImportInvalid || diagnostic.Path.String() != "/configkit/imports/0/depth" {
t.Fatalf("invalid depth diagnostic = %#v", diagnostic)
}
})
}
}
func TestImportDefaultsApplyToTransitiveAndUnderlayImports(t *testing.T) { func TestImportDefaultsApplyToTransitiveAndUnderlayImports(t *testing.T) {
type config struct { type config struct {
Main string `yaml:"main"` Main string `yaml:"main"`

View File

@@ -427,7 +427,8 @@ func parseImportDepth(node *document.Node) (int, bool) {
} }
digit := uint64(character - '0') digit := uint64(character - '0')
if value > (maxInt-digit)/10 { if value > (maxInt-digit)/10 {
return int(maxInt), true value = maxInt
continue // Saturate the bound, but validate every remaining character.
} }
value = value*10 + digit value = value*10 + digit
} }