Skip to content

Commit e465eb3

Browse files
committed
Throw validation error when a template digest is specified
because digest validation is not yet implemented. Also adds missing unmarshalling for `base: {file: URL}` and related tests. Signed-off-by: Jan Dubois <[email protected]>
1 parent fe87298 commit e465eb3

File tree

7 files changed

+95
-18
lines changed

7 files changed

+95
-18
lines changed

pkg/limatmpl/abs.go

+17-9
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,39 @@ func (tmpl *Template) useAbsLocators() error {
2626
return err
2727
}
2828
for i, baseLocator := range tmpl.Config.Base {
29-
locator, err := absPath(baseLocator.URL, basePath)
29+
absLocator, err := absPath(baseLocator.URL, basePath)
3030
if err != nil {
3131
return err
3232
}
3333
if i == 0 {
34-
// base can either be a single string, or a list of strings
35-
tmpl.expr.WriteString(fmt.Sprintf("| ($a.base | select(type == \"!!str\")) |= %q\n", locator))
36-
tmpl.expr.WriteString(fmt.Sprintf("| ($a.base | select(type == \"!!seq\") | .[0]) |= %q\n", locator))
34+
// base can be either a single string (URL), or a single locator object, or a list whose first element can be either a string or an object
35+
tmpl.expr.WriteString(fmt.Sprintf("| ($a.base | select(type == \"!!str\")) |= %q\n", absLocator))
36+
tmpl.expr.WriteString(fmt.Sprintf("| ($a.base | select(type == \"!!map\") | .url) |= %q\n", absLocator))
37+
tmpl.expr.WriteString(fmt.Sprintf("| ($a.base | select(type == \"!!seq\" and (.[0] | type) == \"!!str\") | .[0]) |= %q\n", absLocator))
38+
tmpl.expr.WriteString(fmt.Sprintf("| ($a.base | select(type == \"!!seq\" and (.[0] | type) == \"!!map\") | .[0].url) |= %q\n", absLocator))
3739
} else {
38-
tmpl.expr.WriteString(fmt.Sprintf("| $a.base[%d] = %q\n", i, locator))
40+
tmpl.expr.WriteString(fmt.Sprintf("| ($a.base[%d] | select(type == \"!!str\")) |= %q\n", i, absLocator))
41+
tmpl.expr.WriteString(fmt.Sprintf("| ($a.base[%d] | select(type == \"!!map\") | .url) |= %q\n", i, absLocator))
3942
}
4043
}
4144
for i, p := range tmpl.Config.Probes {
4245
if p.File != nil {
43-
locator, err := absPath(p.File.URL, basePath)
46+
absLocator, err := absPath(p.File.URL, basePath)
4447
if err != nil {
4548
return err
4649
}
47-
tmpl.expr.WriteString(fmt.Sprintf("| $a.probes[%d].file = %q\n", i, locator))
50+
tmpl.expr.WriteString(fmt.Sprintf("| ($a.probes[%d].file | select(type == \"!!str\")) = %q\n", i, absLocator))
51+
tmpl.expr.WriteString(fmt.Sprintf("| ($a.probes[%d].file | select(type == \"!!map\") | .url) = %q\n", i, absLocator))
4852
}
4953
}
5054
for i, p := range tmpl.Config.Provision {
5155
if p.File != nil {
52-
locator, err := absPath(p.File.URL, basePath)
56+
absLocator, err := absPath(p.File.URL, basePath)
5357
if err != nil {
5458
return err
5559
}
56-
tmpl.expr.WriteString(fmt.Sprintf("| $a.provision[%d].file = %q\n", i, locator))
60+
tmpl.expr.WriteString(fmt.Sprintf("| ($a.provision[%d].file | select(type == \"!!str\")) = %q\n", i, absLocator))
61+
tmpl.expr.WriteString(fmt.Sprintf("| ($a.provision[%d].file | select(type == \"!!map\") | .url) = %q\n", i, absLocator))
5762
}
5863
}
5964
return tmpl.evalExpr()
@@ -90,6 +95,9 @@ func basePath(locator string) (string, error) {
9095

9196
// absPath either returns the locator directly, or combines it with the basePath if the locator is a relative path.
9297
func absPath(locator, basePath string) (string, error) {
98+
if locator == "" {
99+
return "", errors.New("locator is empty")
100+
}
93101
u, err := url.Parse(locator)
94102
if err == nil && len(u.Scheme) > 1 {
95103
return locator, nil

pkg/limatmpl/abs_test.go

+37-5
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,21 @@ var useAbsLocatorsTestCases = []useAbsLocatorsTestCase{
3232
{
3333
"Flow style array of one base template",
3434
"template://foo",
35-
`base: [bar.yaml]`,
36-
`base: ['template://bar.yaml']`,
35+
`base: {url: bar.yaml, digest: deadbeef}`,
36+
// not sure why the quotes around the URL were added; maybe because we don't copy the style from the source
37+
`base: {url: 'template://bar.yaml', digest: deadbeef}`,
38+
},
39+
{
40+
"Flow style array of sequence of two base URLs",
41+
"template://foo",
42+
`base: [bar.yaml, baz.yaml]`,
43+
`base: ['template://bar.yaml', 'template://baz.yaml']`,
44+
},
45+
{
46+
"Flow style array of sequence of two base locator objects",
47+
"template://foo",
48+
`base: [{url: bar.yaml, digest: deadbeef}, {url: baz.yaml, digest: decafbad}]`,
49+
`base: [{url: 'template://bar.yaml', digest: deadbeef}, {url: 'template://baz.yaml', digest: decafbad}]`,
3750
},
3851
{
3952
"Block style array of one base template",
@@ -70,16 +83,30 @@ base:
7083
`
7184
provision:
7285
- mode: user
73-
file: script.sh
86+
file: userscript.sh
87+
- mode: system
88+
file:
89+
url: systemscript.sh
90+
digest: abc123
7491
probes:
7592
- file: probe.sh
93+
- file:
94+
url: probe.sh
95+
digest: digest
7696
`,
7797
`
7898
provision:
7999
- mode: user
80-
file: template://experimental/script.sh
100+
file: template://experimental/userscript.sh
101+
- mode: system
102+
file:
103+
url: template://experimental/systemscript.sh
104+
digest: abc123
81105
probes:
82106
- file: template://experimental/probe.sh
107+
- file:
108+
url: template://experimental/probe.sh
109+
digest: digest
83110
`,
84111
},
85112
}
@@ -203,9 +230,14 @@ func TestAbsPath(t *testing.T) {
203230
assert.ErrorContains(t, err, "'../'")
204231
})
205232

233+
t.Run("locator must not be empty", func(t *testing.T) {
234+
_, err = absPath("", "foo")
235+
assert.ErrorContains(t, err, "locator is empty")
236+
})
237+
206238
t.Run("basePath must not be empty", func(t *testing.T) {
207239
_, err = absPath("foo", "")
208-
assert.ErrorContains(t, err, "empty")
240+
assert.ErrorContains(t, err, "basePath is empty")
209241
})
210242

211243
t.Run("", func(t *testing.T) {

pkg/limatmpl/embed.go

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ func (tmpl *Template) embedAllBases(ctx context.Context, embedAll, defaultBase b
7272
break
7373
}
7474
baseLocator := tmpl.Config.Base[0]
75+
if baseLocator.Digest != nil {
76+
return fmt.Errorf("base %q in %q has specified a digest; digest support is not yet implemented", baseLocator.URL, tmpl.Locator)
77+
}
7578
isTemplate, _ := SeemsTemplateURL(baseLocator.URL)
7679
if isTemplate && !embedAll {
7780
// Once we skip a template:// URL we can no longer embed any other base template

pkg/limatmpl/embed_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,18 @@ provision:
359359
"#! my script",
360360
`provision: [{script: "#! my script"}]`,
361361
},
362+
{
363+
"ERROR base digest is not yet implemented (1)",
364+
"",
365+
"base: {url: base.yaml, digest: deafbad}",
366+
"not yet implemented",
367+
},
368+
{
369+
"ERROR base digest is not yet implemented (2)",
370+
"",
371+
"base: [{url: base.yaml, digest: deafbad}]",
372+
"not yet implemented",
373+
},
362374
}
363375

364376
func TestEmbed(t *testing.T) {

pkg/limayaml/marshal.go

+5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ func unmarshalBaseTemplates(dst *BaseTemplates, b []byte) error {
4242
*dst = BaseTemplates{LocatorWithDigest{URL: s}}
4343
return nil
4444
}
45+
var locator LocatorWithDigest
46+
if err := yaml.Unmarshal(b, &locator); err == nil {
47+
*dst = BaseTemplates{locator}
48+
return nil
49+
}
4550
return yaml.UnmarshalWithOptions(b, dst, yaml.CustomUnmarshaler[LocatorWithDigest](unmarshalLocatorWithDigest))
4651
}
4752

pkg/limayaml/validate.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,13 @@ func Validate(y *LimaYAML, warn bool) error {
206206
// y.Firmware.LegacyBIOS is ignored for aarch64, but not a fatal error.
207207

208208
for i, p := range y.Provision {
209-
if p.File != nil && p.File.URL != "" {
210-
return fmt.Errorf("field `provision[%d].file.url` must be empty during validation (script should already be embedded)", i)
209+
if p.File != nil {
210+
if p.File.URL != "" {
211+
return fmt.Errorf("field `provision[%d].file.url` must be empty during validation (script should already be embedded)", i)
212+
}
213+
if p.File.Digest != nil {
214+
return fmt.Errorf("field `provision[%d].file.digest` support is not yet implemented", i)
215+
}
211216
}
212217
switch p.Mode {
213218
case ProvisionModeSystem, ProvisionModeUser, ProvisionModeBoot:
@@ -249,8 +254,13 @@ func Validate(y *LimaYAML, warn bool) error {
249254
}
250255
}
251256
for i, p := range y.Probes {
252-
if p.File != nil && p.File.URL != "" {
253-
return fmt.Errorf("field `probes[%d].file.url` must be empty during validation (script should already be embedded)", i)
257+
if p.File != nil {
258+
if p.File.URL != "" {
259+
return fmt.Errorf("field `probe[%d].file.url` must be empty during validation (script should already be embedded)", i)
260+
}
261+
if p.File.Digest != nil {
262+
return fmt.Errorf("field `probe[%d].file.digest` support is not yet implemented", i)
263+
}
254264
}
255265
if !strings.HasPrefix(p.Script, "#!") {
256266
return fmt.Errorf("field `probe[%d].script` must start with a '#!' line", i)

pkg/limayaml/validate_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ func TestValidateProbes(t *testing.T) {
4646

4747
err = Validate(y, false)
4848
assert.Error(t, err, "field `probe[0].script` must start with a '#!' line")
49+
50+
invalidProbe = `probes: [{file: {digest: decafbad}}]`
51+
y, err = Load([]byte(invalidProbe+"\n"+images), "lima.yaml")
52+
assert.NilError(t, err)
53+
54+
err = Validate(y, false)
55+
assert.Error(t, err, "field `probe[0].file.digest` support is not yet implemented")
4956
}
5057

5158
func TestValidateAdditionalDisks(t *testing.T) {

0 commit comments

Comments
 (0)