Skip to content

Commit 4d3ad7e

Browse files
committed
Embed binary files as base64 encoded strings
They need to be broken into smaller lines; yqlib doesn't do this, and yamlfmt fails with a buffer overflow when it tries to keep existing line breaks. Signed-off-by: Jan Dubois <[email protected]>
1 parent bf3d444 commit 4d3ad7e

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

pkg/limatmpl/embed.go

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ package limatmpl
66
import (
77
"bytes"
88
"context"
9+
"encoding/base64"
910
"fmt"
1011
"os"
1112
"path/filepath"
1213
"slices"
14+
"strings"
1315
"sync"
16+
"unicode"
1417

1518
"github.com/coreos/go-semver/semver"
1619
"github.com/lima-vm/lima/pkg/limayaml"
@@ -254,7 +257,7 @@ const mergeDocuments = `
254257
| $a | (select(.mountTypesUnsupported) | .mountTypesUnsupported) |= unique
255258
256259
# Remove the custom tags again so they do not clutter up the YAML output.
257-
| $a | .. tag = ""
260+
| $a | .. | select(tag == "!!tag") tag = ""
258261
`
259262

260263
// listFields returns dst and src fields like "list[idx].field".
@@ -552,11 +555,49 @@ func (tmpl *Template) combineNetworks() {
552555
}
553556
}
554557

558+
// Break base64 strings into shorter chunks; otherwise the yamlfmt code will fail
559+
// with a buffer overflow while trying to retain line breaks.
560+
const lineLength = 76
561+
562+
// binaryString returns a base64 encoded version of the binary string, broken into chunks
563+
// of at most lineLength characters per line.
564+
func binaryString(s string) string {
565+
encoded := base64.StdEncoding.EncodeToString([]byte(s))
566+
if len(encoded) <= lineLength {
567+
return encoded
568+
}
569+
570+
// Estimate capacity: encoded length + number of newlines
571+
lineCount := (len(encoded) + lineLength - 1) / lineLength
572+
builder := strings.Builder{}
573+
builder.Grow(len(encoded) + lineCount)
574+
575+
for i := 0; i < len(encoded); i += lineLength {
576+
end := i + lineLength
577+
if end > len(encoded) {
578+
end = len(encoded)
579+
}
580+
builder.WriteString(encoded[i:end])
581+
builder.WriteByte('\n')
582+
}
583+
584+
return builder.String()
585+
}
586+
555587
// updateScript replaces a "file" property with the actual script and then renames the field to newName ("script" or "content").
556588
func (tmpl *Template) updateScript(field string, idx int, newName, script string) {
589+
tag := ""
590+
for _, r := range script {
591+
if !(unicode.IsPrint(r) || r == '\n' || r == '\r' || r == '\t') {
592+
script = binaryString(script)
593+
tag = "!!binary"
594+
break
595+
}
596+
}
557597
entry := fmt.Sprintf("$a.%s[%d].file", field, idx)
558598
// Assign script to the "file" field and then rename it to "script".
559-
tmpl.expr.WriteString(fmt.Sprintf("| (%s) = %q | (%s | key) = %q\n", entry, script, entry, newName))
599+
tmpl.expr.WriteString(fmt.Sprintf("| (%s) = %q | (%s) tag = %q | (%s | key) = %q\n",
600+
entry, script, entry, tag, entry, newName))
560601
}
561602

562603
// embedAllScripts replaces all "provision" and "probes" file references with the actual script.

pkg/limatmpl/embed_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,27 @@ provision:
392392
"base: https://example.com/lima-linux-riscv64.img",
393393
"{arch: riscv64, images: [{location: https://example.com/lima-linux-riscv64.img, arch: riscv64}]}",
394394
},
395+
{
396+
"Binary files are base64 encoded",
397+
`#
398+
provision:
399+
- mode: data
400+
file: base1.sh # This comment will move to the "content" key
401+
path: /tmp/data
402+
`,
403+
// base1.sh is binary because it contains an audible bell character '\a'
404+
"# base0.yaml is ignored\n---\n#!\a123456789012345678901234567890123456789012345678901234567890",
405+
`
406+
provision:
407+
- mode: data
408+
content: !!binary | # This comment will move to the "content" key
409+
IyEHMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0
410+
NTY3ODkw
411+
path: /tmp/data
412+
413+
# base0.yaml is ignored
414+
`,
415+
},
395416
}
396417

397418
func TestEmbed(t *testing.T) {

0 commit comments

Comments
 (0)