Merge pull request #3027 from LaurentGoderre/fix-attest-extra-args

Fix attest extra arguments
This commit is contained in:
CrazyMax 2025-03-03 16:28:02 +01:00 committed by GitHub
commit 128acdb471
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 56 additions and 9 deletions

View File

@ -608,7 +608,7 @@ func TestHCLAttrsCapsuleType(t *testing.T) {
target "app" { target "app" {
attest = [ attest = [
{ type = "provenance", mode = "max" }, { type = "provenance", mode = "max" },
"type=sbom,disabled=true", "type=sbom,disabled=true,generator=foo,\"ENV1=bar,baz\",ENV2=hello",
] ]
cache-from = [ cache-from = [
@ -641,7 +641,7 @@ func TestHCLAttrsCapsuleType(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(c.Targets)) require.Equal(t, 1, len(c.Targets))
require.Equal(t, []string{"type=provenance,mode=max", "type=sbom,disabled=true"}, stringify(c.Targets[0].Attest)) require.Equal(t, []string{"type=provenance,mode=max", "type=sbom,disabled=true,\"ENV1=bar,baz\",ENV2=hello,generator=foo"}, stringify(c.Targets[0].Attest))
require.Equal(t, []string{"type=local,dest=../out", "type=oci,dest=../out.tar"}, stringify(c.Targets[0].Outputs)) require.Equal(t, []string{"type=local,dest=../out", "type=oci,dest=../out.tar"}, stringify(c.Targets[0].Outputs))
require.Equal(t, []string{"type=local,src=path/to/cache", "user/app:cache"}, stringify(c.Targets[0].CacheFrom)) require.Equal(t, []string{"type=local,src=path/to/cache", "user/app:cache"}, stringify(c.Targets[0].CacheFrom))
require.Equal(t, []string{"type=local,dest=path/to/cache"}, stringify(c.Targets[0].CacheTo)) require.Equal(t, []string{"type=local,dest=path/to/cache"}, stringify(c.Targets[0].CacheTo))

View File

@ -148,9 +148,8 @@ func (a *Attest) UnmarshalText(text []byte) error {
if !ok { if !ok {
return errors.Errorf("invalid value %s", field) return errors.Errorf("invalid value %s", field)
} }
key = strings.TrimSpace(strings.ToLower(key))
switch key { switch strings.TrimSpace(strings.ToLower(key)) {
case "type": case "type":
a.Type = value a.Type = value
case "disabled": case "disabled":

View File

@ -13,16 +13,21 @@ func TestAttests(t *testing.T) {
attests := Attests{ attests := Attests{
{Type: "provenance", Attrs: map[string]string{"mode": "max"}}, {Type: "provenance", Attrs: map[string]string{"mode": "max"}},
{Type: "sbom", Disabled: true}, {Type: "sbom", Disabled: true},
{Type: "sbom", Attrs: map[string]string{
"generator": "scanner",
"ENV1": `"foo,bar"`,
"Env2": "hello",
}},
} }
expected := `[{"type":"provenance","mode":"max"},{"type":"sbom","disabled":true}]` expected := `[{"type":"provenance","mode":"max"},{"type":"sbom","disabled":true},{"ENV1":"\"foo,bar\"","Env2":"hello","generator":"scanner","type":"sbom"}]`
actual, err := json.Marshal(attests) actual, err := json.Marshal(attests)
require.NoError(t, err) require.NoError(t, err)
require.JSONEq(t, expected, string(actual)) require.JSONEq(t, expected, string(actual))
}) })
t.Run("UnmarshalJSON", func(t *testing.T) { t.Run("UnmarshalJSON", func(t *testing.T) {
in := `[{"type":"provenance","mode":"max"},{"type":"sbom","disabled":true}]` in := `[{"type":"provenance","mode":"max"},{"type":"sbom","disabled":true},{"ENV1":"\"foo,bar\"","Env2":"hello","generator":"scanner","type":"sbom"}]`
var actual Attests var actual Attests
err := json.Unmarshal([]byte(in), &actual) err := json.Unmarshal([]byte(in), &actual)
@ -31,6 +36,11 @@ func TestAttests(t *testing.T) {
expected := Attests{ expected := Attests{
{Type: "provenance", Attrs: map[string]string{"mode": "max"}}, {Type: "provenance", Attrs: map[string]string{"mode": "max"}},
{Type: "sbom", Disabled: true, Attrs: map[string]string{}}, {Type: "sbom", Disabled: true, Attrs: map[string]string{}},
{Type: "sbom", Disabled: false, Attrs: map[string]string{
"generator": "scanner",
"ENV1": `"foo,bar"`,
"Env2": "hello",
}},
} }
require.Equal(t, expected, actual) require.Equal(t, expected, actual)
}) })
@ -41,7 +51,14 @@ func TestAttests(t *testing.T) {
"type": cty.StringVal("provenance"), "type": cty.StringVal("provenance"),
"mode": cty.StringVal("max"), "mode": cty.StringVal("max"),
}), }),
cty.ObjectVal(map[string]cty.Value{
"type": cty.StringVal("sbom"),
"generator": cty.StringVal("scan"),
"ENV1": cty.StringVal(`foo,bar`),
"Env2": cty.StringVal(`hello`),
}),
cty.StringVal("type=sbom,disabled=true"), cty.StringVal("type=sbom,disabled=true"),
cty.StringVal(`type=sbom,generator=scan,"FOO=bar,baz",Hello=World`),
}) })
var actual Attests var actual Attests
@ -50,7 +67,17 @@ func TestAttests(t *testing.T) {
expected := Attests{ expected := Attests{
{Type: "provenance", Attrs: map[string]string{"mode": "max"}}, {Type: "provenance", Attrs: map[string]string{"mode": "max"}},
{Type: "sbom", Attrs: map[string]string{
"generator": "scan",
"ENV1": "foo,bar",
"Env2": "hello",
}},
{Type: "sbom", Disabled: true, Attrs: map[string]string{}}, {Type: "sbom", Disabled: true, Attrs: map[string]string{}},
{Type: "sbom", Attrs: map[string]string{
"generator": "scan",
"FOO": "bar,baz",
"Hello": "World",
}},
} }
require.Equal(t, expected, actual) require.Equal(t, expected, actual)
}) })
@ -59,6 +86,11 @@ func TestAttests(t *testing.T) {
attests := Attests{ attests := Attests{
{Type: "provenance", Attrs: map[string]string{"mode": "max"}}, {Type: "provenance", Attrs: map[string]string{"mode": "max"}},
{Type: "sbom", Disabled: true}, {Type: "sbom", Disabled: true},
{Type: "sbom", Attrs: map[string]string{
"generator": "scan",
"ENV1": `"foo,bar"`,
"Env2": "hello",
}},
} }
actual := attests.ToCtyValue() actual := attests.ToCtyValue()
@ -71,6 +103,12 @@ func TestAttests(t *testing.T) {
"type": cty.StringVal("sbom"), "type": cty.StringVal("sbom"),
"disabled": cty.StringVal("true"), "disabled": cty.StringVal("true"),
}), }),
cty.MapVal(map[string]cty.Value{
"type": cty.StringVal("sbom"),
"generator": cty.StringVal("scan"),
"ENV1": cty.StringVal(`"foo,bar"`),
"Env2": cty.StringVal("hello"),
}),
}) })
result := actual.Equals(expected) result := actual.Equals(expected)

View File

@ -1,6 +1,7 @@
package buildflags package buildflags
import ( import (
"encoding/csv"
"encoding/json" "encoding/json"
"maps" "maps"
"regexp" "regexp"
@ -259,9 +260,18 @@ func (w *csvBuilder) Write(key, value string) {
if w.sb.Len() > 0 { if w.sb.Len() > 0 {
w.sb.WriteByte(',') w.sb.WriteByte(',')
} }
w.sb.WriteString(key)
w.sb.WriteByte('=') pair := key + "=" + value
w.sb.WriteString(value) if strings.ContainsRune(pair, ',') || strings.ContainsRune(pair, '"') {
var attr strings.Builder
writer := csv.NewWriter(&attr)
writer.Write([]string{pair})
writer.Flush()
// Strips the extra newline added by the csv writer
pair = strings.TrimSpace(attr.String())
}
w.sb.WriteString(pair)
} }
func (w *csvBuilder) WriteAttributes(attrs map[string]string) { func (w *csvBuilder) WriteAttributes(attrs map[string]string) {