From 946468dc9925a958e80f0523ce65abb137ae13df Mon Sep 17 00:00:00 2001 From: James Shubin Date: Wed, 20 Mar 2024 18:06:29 -0400 Subject: [PATCH] lang: ast: Ensure a list doesn't sneak through type interpolation If we had a single list wrapped in an interpolated string, it could sneak through type unification, which is not correct. Wrapping a variable by interpolation in a string, must force it to be a string. --- lang/ast/structs.go | 4 ++++ lang/interpolate/interpolate_test.go | 7 +++++++ .../unify-interpolate-edge1-fail.txtar | 10 ++++++++++ .../unify-interpolate-edge1-pass.txtar | 16 ++++++++++++++++ .../unify-interpolate-edge2-fail.txtar | 10 ++++++++++ .../unify-interpolate-edge2-pass.txtar | 16 ++++++++++++++++ .../unify-interpolate-res-fail.txtar | 8 ++++++++ .../unify-interpolate-res-pass.txtar | 10 ++++++++++ 8 files changed, 81 insertions(+) create mode 100644 lang/interpret_test/TestAstFunc2/unify-interpolate-edge1-fail.txtar create mode 100644 lang/interpret_test/TestAstFunc2/unify-interpolate-edge1-pass.txtar create mode 100644 lang/interpret_test/TestAstFunc2/unify-interpolate-edge2-fail.txtar create mode 100644 lang/interpret_test/TestAstFunc2/unify-interpolate-edge2-pass.txtar create mode 100644 lang/interpret_test/TestAstFunc2/unify-interpolate-res-fail.txtar create mode 100644 lang/interpret_test/TestAstFunc2/unify-interpolate-res-pass.txtar diff --git a/lang/ast/structs.go b/lang/ast/structs.go index 8ae2e1f5..1667ed0c 100644 --- a/lang/ast/structs.go +++ b/lang/ast/structs.go @@ -5408,6 +5408,10 @@ func (obj *ExprStr) Interpolate() (interfaces.Expr, error) { }, nil } // we got something, overwrite the existing static str + // ensure str, to avoid a pass-through list in a simple interpolation + if err := result.SetType(types.TypeStr); err != nil { + return nil, errwrap.Wrapf(err, "interpolated string expected a different type") + } return result, nil // replacement } diff --git a/lang/interpolate/interpolate_test.go b/lang/interpolate/interpolate_test.go index eab03e4d..49e2068f 100644 --- a/lang/interpolate/interpolate_test.go +++ b/lang/interpolate/interpolate_test.go @@ -41,6 +41,7 @@ import ( "github.com/purpleidea/mgmt/lang/funcs" "github.com/purpleidea/mgmt/lang/interfaces" "github.com/purpleidea/mgmt/lang/parser" + "github.com/purpleidea/mgmt/lang/types" "github.com/purpleidea/mgmt/util" "github.com/davecgh/go-spew/spew" @@ -384,6 +385,9 @@ func TestInterpolateBasicStmt(t *testing.T) { }, }, } + if err := resName.SetType(types.TypeStr); err != nil { + panic("could not set type") + } exp := &ast.StmtProg{ Body: []interfaces.Stmt{ &ast.StmtRes{ @@ -574,6 +578,9 @@ func TestInterpolateBasicExpr(t *testing.T) { }, }, } + if err := exp.SetType(types.TypeStr); err != nil { + panic("could not set type") + } testCases = append(testCases, test{ name: "basic expansion", ast: xast, diff --git a/lang/interpret_test/TestAstFunc2/unify-interpolate-edge1-fail.txtar b/lang/interpret_test/TestAstFunc2/unify-interpolate-edge1-fail.txtar new file mode 100644 index 00000000..757cca2a --- /dev/null +++ b/lang/interpret_test/TestAstFunc2/unify-interpolate-edge1-fail.txtar @@ -0,0 +1,10 @@ +-- main.mcl -- +$name = ["a", "bb", "ccc",] +test $name {} +test "test" {} + +#Test[$name] -> Test["test"] # must pass +Test["${name}"] -> Test["test"] # must fail + +-- OUTPUT -- +# err: errUnify: can't unify, invariant illogicality with equality: base kind does not match (Str != List) diff --git a/lang/interpret_test/TestAstFunc2/unify-interpolate-edge1-pass.txtar b/lang/interpret_test/TestAstFunc2/unify-interpolate-edge1-pass.txtar new file mode 100644 index 00000000..f82b4d8e --- /dev/null +++ b/lang/interpret_test/TestAstFunc2/unify-interpolate-edge1-pass.txtar @@ -0,0 +1,16 @@ +-- main.mcl -- +$name = ["a", "bb", "ccc",] +test $name {} +test "test" {} + +Test[$name] -> Test["test"] # must pass +#Test["${name}"] -> Test["test"] # must fail + +-- OUTPUT -- +Edge: test[a] -> test[test] # test[a] -> test[test] +Edge: test[bb] -> test[test] # test[bb] -> test[test] +Edge: test[ccc] -> test[test] # test[ccc] -> test[test] +Vertex: test[a] +Vertex: test[bb] +Vertex: test[ccc] +Vertex: test[test] diff --git a/lang/interpret_test/TestAstFunc2/unify-interpolate-edge2-fail.txtar b/lang/interpret_test/TestAstFunc2/unify-interpolate-edge2-fail.txtar new file mode 100644 index 00000000..521662c8 --- /dev/null +++ b/lang/interpret_test/TestAstFunc2/unify-interpolate-edge2-fail.txtar @@ -0,0 +1,10 @@ +-- main.mcl -- +$name = ["a", "bb", "ccc",] +test $name {} +test "test" {} + +#Test["test"] -> Test[$name] # must pass +Test["test"] -> Test["${name}"] # must fail + +-- OUTPUT -- +# err: errUnify: can't unify, invariant illogicality with equality: base kind does not match (Str != List) diff --git a/lang/interpret_test/TestAstFunc2/unify-interpolate-edge2-pass.txtar b/lang/interpret_test/TestAstFunc2/unify-interpolate-edge2-pass.txtar new file mode 100644 index 00000000..e5bec9d2 --- /dev/null +++ b/lang/interpret_test/TestAstFunc2/unify-interpolate-edge2-pass.txtar @@ -0,0 +1,16 @@ +-- main.mcl -- +$name = ["a", "bb", "ccc",] +test $name {} +test "test" {} + +Test["test"] -> Test[$name] # must pass +#Test["test"] -> Test["${name}"] # must fail + +-- OUTPUT -- +Edge: test[test] -> test[a] # test[test] -> test[a] +Edge: test[test] -> test[bb] # test[test] -> test[bb] +Edge: test[test] -> test[ccc] # test[test] -> test[ccc] +Vertex: test[a] +Vertex: test[bb] +Vertex: test[ccc] +Vertex: test[test] diff --git a/lang/interpret_test/TestAstFunc2/unify-interpolate-res-fail.txtar b/lang/interpret_test/TestAstFunc2/unify-interpolate-res-fail.txtar new file mode 100644 index 00000000..8f0a7e90 --- /dev/null +++ b/lang/interpret_test/TestAstFunc2/unify-interpolate-res-fail.txtar @@ -0,0 +1,8 @@ +-- main.mcl -- +$name = ["a", "bb", "ccc",] + +#test $name {} # must pass +test "${name}" {} # must fail + +-- OUTPUT -- +# err: errUnify: can't unify, invariant illogicality with equality: base kind does not match (Str != List) diff --git a/lang/interpret_test/TestAstFunc2/unify-interpolate-res-pass.txtar b/lang/interpret_test/TestAstFunc2/unify-interpolate-res-pass.txtar new file mode 100644 index 00000000..c31eb28a --- /dev/null +++ b/lang/interpret_test/TestAstFunc2/unify-interpolate-res-pass.txtar @@ -0,0 +1,10 @@ +-- main.mcl -- +$name = ["a", "bb", "ccc",] + +test $name {} # must pass +#test "${name}" {} # must fail + +-- OUTPUT -- +Vertex: test[a] +Vertex: test[bb] +Vertex: test[ccc]