Skip to content

Commit 9841a29

Browse files
committed
Accept optional strings
1 parent 8aaa6df commit 9841a29

File tree

4 files changed

+74
-1
lines changed

4 files changed

+74
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ Main (unreleased)
1818

1919
- Add `hash_string_id` argument to `foreach` block to hash the string representation of the pipeline id instead of using the string itself. (@wildum)
2020

21+
### Bugfixes
22+
23+
- Fixed a bug which prevented non-secret optional secrets to be passed in as `number` arguments. (@ptodev)
24+
2125
v1.9.0
2226
-----------------
2327

syntax/internal/value/value.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,22 @@ func convertValue(val Value, toType Type) (Value, error) {
541541
return Uint(parsed), nil
542542
}
543543
}
544+
545+
case TypeCapsule:
546+
// Some capsules, such as optional secrects, may be convertible to a string.
547+
// Try to convert them to a string and then rerun convertValue.
548+
cc, ok := val.Interface().(ConvertibleIntoCapsule)
549+
if ok {
550+
into := reflect.New(reflect.TypeOf(string(""))).Elem()
551+
552+
err := cc.ConvertInto(into.Addr().Interface())
553+
if err == nil {
554+
val, err := convertValue(Value{into, TypeString}, toType)
555+
if err == nil {
556+
return val, nil
557+
}
558+
}
559+
}
544560
}
545561

546562
return Null, TypeError{Value: val, Expected: toType}

syntax/vm/vm_stdlib_test.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ func TestVM_Stdlib_Errors(t *testing.T) {
203203
func TestStdlibCoalesce(t *testing.T) {
204204
t.Setenv("TEST_VAR2", "Hello!")
205205

206+
scope := vm.NewScope(map[string]any{
207+
"optionalSecretStr": alloytypes.OptionalSecret{Value: "bar"},
208+
"optionalSecretInt": alloytypes.OptionalSecret{Value: "123", IsSecret: false},
209+
})
210+
206211
tt := []struct {
207212
name string
208213
input string
@@ -221,6 +226,10 @@ func TestStdlibCoalesce(t *testing.T) {
221226
{"coalesce(object, true) and return true", `coalesce(encoding.from_json("{}"), true)`, true},
222227
{"coalesce(object, false) and return false", `coalesce(encoding.from_json("{}"), false)`, false},
223228
{"coalesce(list, nil)", `coalesce([],null)`, value.Null},
229+
{"optional secret str first in coalesce", `coalesce(optionalSecretStr, 1)`, string("bar")},
230+
{"optional secret str second in coalesce", `coalesce("foo", optionalSecretStr)`, string("foo")},
231+
{"optional secret int first in coalesce", `coalesce(optionalSecretInt, 1)`, int(123)},
232+
{"optional secret int second in coalesce", `coalesce(1, optionalSecretInt)`, int(1)},
224233
}
225234

226235
for _, tc := range tt {
@@ -231,7 +240,7 @@ func TestStdlibCoalesce(t *testing.T) {
231240
eval := vm.New(expr)
232241

233242
rv := reflect.New(reflect.TypeOf(tc.expect))
234-
require.NoError(t, eval.Evaluate(nil, rv.Interface()))
243+
require.NoError(t, eval.Evaluate(scope, rv.Interface()))
235244
require.Equal(t, tc.expect, rv.Elem().Interface())
236245
})
237246
}

syntax/vm/vm_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"testing"
77
"unicode"
88

9+
"github.com/grafana/alloy/syntax/alloytypes"
910
"github.com/grafana/alloy/syntax/parser"
1011
"github.com/grafana/alloy/syntax/scanner"
1112
"github.com/grafana/alloy/syntax/token"
@@ -61,6 +62,49 @@ func TestVM_Evaluate_Literals(t *testing.T) {
6162
}
6263
}
6364

65+
func TestVM_Evaluate_Secrets(t *testing.T) {
66+
scope := vm.NewScope(map[string]any{
67+
"secretSecret": alloytypes.Secret("foo"),
68+
"optionalSecretStr": alloytypes.OptionalSecret{Value: "bar"},
69+
"optionalSecretInt": alloytypes.OptionalSecret{Value: "123", IsSecret: false},
70+
"optionalSecretNegative": alloytypes.OptionalSecret{Value: "-123", IsSecret: false},
71+
"optionalSecretFloat": alloytypes.OptionalSecret{Value: "23.5", IsSecret: false},
72+
})
73+
74+
tt := map[string]struct {
75+
input string
76+
expect interface{}
77+
errMsg string
78+
}{
79+
"secret": {`secretSecret`, string("bar"), "secrets may not be converted into strings"},
80+
"optional secret str": {`optionalSecretStr`, string("bar"), ""},
81+
"optional secret int": {`optionalSecretInt`, int(123), ""},
82+
"optional secret negative int": {`optionalSecretNegative`, int(-123), ""},
83+
"optional secret float": {`optionalSecretFloat`, float64(23.5), ""},
84+
}
85+
86+
for name, tc := range tt {
87+
t.Run(name, func(t *testing.T) {
88+
expr, err := parser.ParseExpression(tc.input)
89+
require.NoError(t, err)
90+
91+
eval := vm.New(expr)
92+
93+
vPtr := reflect.New(reflect.TypeOf(tc.expect)).Interface()
94+
95+
err = eval.Evaluate(scope, vPtr)
96+
if tc.errMsg == "" {
97+
require.NoError(t, err)
98+
99+
actual := reflect.ValueOf(vPtr).Elem().Interface()
100+
require.Equal(t, tc.expect, actual)
101+
} else {
102+
require.ErrorContains(t, err, tc.errMsg)
103+
}
104+
})
105+
}
106+
}
107+
64108
func TestVM_Evaluate(t *testing.T) {
65109
// Shared scope across all tests below
66110
scope := vm.NewScope(map[string]interface{}{

0 commit comments

Comments
 (0)