From 9b889592c2774254d6f733030326189627b4e772 Mon Sep 17 00:00:00 2001 From: Pat Gavlin Date: Mon, 29 Jan 2024 18:19:41 -0800 Subject: [PATCH] eval: evaluate after parse errors (#222) These changes add support for evaluating environment decls that contain parse errors. All current parse errors manifest as missing nodes. These changes add a `missingExpr` expression type to handle those cases. Missing expressions are treated as `any`-typed null literals. The primary benefit of these changes is that they enable type checking environments with parse errors (i.e. calling `CheckEnvironment`). This is important for live analysis scenarios. --- CHANGELOG_PENDING.md | 3 + ast/expr.go | 3 +- .../parse/invalid-plaintext/expected.json | 4 +- eval/eval.go | 71 +- eval/eval_test.go | 58 +- eval/expr.go | 16 + .../eval/invalid-access-load/expected.json | 1854 ++++++++++++++++- eval/testdata/eval/invalid-join/env.yaml | 4 + eval/testdata/eval/invalid-join/expected.json | 391 ++++ eval/testdata/eval/invalid-open/env.yaml | 11 + eval/testdata/eval/invalid-open/expected.json | 816 ++++++++ eval/testdata/eval/invalid-plaintext/env.yaml | 6 + .../eval/invalid-plaintext/expected.json | 584 ++++++ 13 files changed, 3767 insertions(+), 54 deletions(-) create mode 100644 eval/testdata/eval/invalid-join/env.yaml create mode 100644 eval/testdata/eval/invalid-join/expected.json create mode 100644 eval/testdata/eval/invalid-open/env.yaml create mode 100644 eval/testdata/eval/invalid-open/expected.json create mode 100644 eval/testdata/eval/invalid-plaintext/env.yaml create mode 100644 eval/testdata/eval/invalid-plaintext/expected.json diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 5ecddce9..edf30074 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -1,3 +1,6 @@ ### Improvements +- Allow evaluation of environments with parse errors. + [#222](https://github.com/pulumi/esc/pull/222) + ### Bug Fixes diff --git a/ast/expr.go b/ast/expr.go index a4c68afb..9fb00bfd 100644 --- a/ast/expr.go +++ b/ast/expr.go @@ -140,7 +140,7 @@ func StringSyntaxValue(node *syntax.StringNode, value string) *StringExpr { // String creates a new string literal expression with the given value. func String(value string) *StringExpr { - return &StringExpr{Value: value} + return &StringExpr{exprNode: expr(syntax.String(value)), Value: value} } // An InterpolateExpr represents an interpolated string. @@ -722,6 +722,7 @@ func parseSecret(node *syntax.ObjectNode, name *StringExpr, value Expr) (Expr, s var diags syntax.Diagnostics str, ok := value.(*StringExpr) if !ok { + str = String("") diags = syntax.Diagnostics{ExprError(value, "secret values must be string literals")} } return PlaintextSyntax(node, name, str), diags diff --git a/ast/testdata/parse/invalid-plaintext/expected.json b/ast/testdata/parse/invalid-plaintext/expected.json index c7011d8e..310692c7 100644 --- a/ast/testdata/parse/invalid-plaintext/expected.json +++ b/ast/testdata/parse/invalid-plaintext/expected.json @@ -9,7 +9,9 @@ "Value": "foo" }, "Value": { - "Plaintext": null, + "Plaintext": { + "Value": "" + }, "Ciphertext": null } }, diff --git a/eval/eval.go b/eval/eval.go index d147e3ed..abdf7b33 100644 --- a/eval/eval.go +++ b/eval/eval.go @@ -183,6 +183,11 @@ func (e *evalContext) errorf(expr ast.Expr, format string, a ...any) { e.error(expr, fmt.Sprintf(format, a...)) } +type exprNode interface { + ast.Expr + comparable +} + // declare creates an expr from an ast.Expr, sets its representation and initial schema, and attaches it to the given // base. declare is also responsible for recursively declaring child exprs. declare may issue errors for duplicate keys // in objects. @@ -201,8 +206,16 @@ func (e *evalContext) errorf(expr ast.Expr, format string, a ...any) { // - ToJSONExpr -> toJSONExpr // - ArrayExpr -> arrayExpr // - ObjectExpr -> objectExpr -func (e *evalContext) declare(path string, x ast.Expr, base *value) *expr { - switch x := x.(type) { +// +// This is parameterized on the Expr type to avoid unintentionally creating non-nil ast.Expr values out of nil +// pointers. Parameterization allows us to check for nil pointers explicitly. +func declare[Expr exprNode](e *evalContext, path string, x Expr, base *value) *expr { + var zero Expr + if x == zero { + return newMissingExpr(path, base) + } + + switch x := any(x).(type) { case *ast.NullExpr: return newExpr(path, &literalExpr{node: x}, schema.Null().Schema(), base) case *ast.BooleanExpr: @@ -233,48 +246,48 @@ func (e *evalContext) declare(path string, x ast.Expr, base *value) *expr { property := &propertyAccess{accessors: accessors} return newExpr(path, &symbolExpr{node: x, property: property}, schema.Always().Schema(), base) case *ast.FromBase64Expr: - repr := &fromBase64Expr{node: x, string: e.declare("", x.String, nil)} + repr := &fromBase64Expr{node: x, string: declare(e, "", x.String, nil)} return newExpr(path, repr, schema.String().Schema(), base) case *ast.FromJSONExpr: - repr := &fromJSONExpr{node: x, string: e.declare("", x.String, nil)} + repr := &fromJSONExpr{node: x, string: declare(e, "", x.String, nil)} return newExpr(path, repr, schema.Always(), base) case *ast.JoinExpr: repr := &joinExpr{ node: x, - delimiter: e.declare("", x.Delimiter, nil), - values: e.declare("", x.Values, nil), + delimiter: declare(e, "", x.Delimiter, nil), + values: declare(e, "", x.Values, nil), } return newExpr(path, repr, schema.String().Schema(), base) case *ast.OpenExpr: repr := &openExpr{ node: x, - provider: e.declare("", x.Provider, nil), - inputs: e.declare("", x.Inputs, nil), + provider: declare(e, "", x.Provider, nil), + inputs: declare(e, "", x.Inputs, nil), inputSchema: schema.Always().Schema(), } return newExpr(path, repr, schema.Always().Schema(), base) case *ast.SecretExpr: if x.Plaintext != nil { - repr := &secretExpr{node: x, plaintext: e.declare("", x.Plaintext, nil)} + repr := &secretExpr{node: x, plaintext: declare(e, "", x.Plaintext, nil)} repr.plaintext.secret = true return newExpr(path, repr, schema.String().Schema(), base) } - repr := &secretExpr{node: x, ciphertext: e.declare("", x.Ciphertext, nil)} + repr := &secretExpr{node: x, ciphertext: declare(e, "", x.Ciphertext, nil)} repr.ciphertext.secret = true return newExpr(path, repr, schema.String().Schema(), base) case *ast.ToBase64Expr: - repr := &toBase64Expr{node: x, value: e.declare("", x.Value, nil)} + repr := &toBase64Expr{node: x, value: declare(e, "", x.Value, nil)} return newExpr(path, repr, schema.String().Schema(), base) case *ast.ToJSONExpr: - repr := &toJSONExpr{node: x, value: e.declare("", x.Value, nil)} + repr := &toJSONExpr{node: x, value: declare(e, "", x.Value, nil)} return newExpr(path, repr, schema.String().Schema(), base) case *ast.ToStringExpr: - repr := &toStringExpr{node: x, value: e.declare("", x.Value, nil)} + repr := &toStringExpr{node: x, value: declare(e, "", x.Value, nil)} return newExpr(path, repr, schema.String().Schema(), base) case *ast.ArrayExpr: elements := make([]*expr, len(x.Elements)) for i, x := range x.Elements { - elements[i] = e.declare(fmt.Sprintf("%v[%d]", path, i), x, nil) + elements[i] = declare(e, fmt.Sprintf("%v[%d]", path, i), x, nil) } repr := &arrayExpr{node: x, elements: elements} return newExpr(path, repr, schema.Array().Items(schema.Always()).Schema(), base) @@ -285,7 +298,7 @@ func (e *evalContext) declare(path string, x ast.Expr, base *value) *expr { if _, ok := properties[k]; ok { e.errorf(entry.Key, "duplicate key %q", k) } else { - properties[k] = e.declare(util.JoinKey(path, k), entry.Value, base.property(entry.Key, k)) + properties[k] = declare(e, util.JoinKey(path, k), entry.Value, base.property(entry.Key, k)) } } repr := &objectExpr{node: x, properties: properties} @@ -330,7 +343,7 @@ func (e *evalContext) evaluate() (*value, syntax.Diagnostics) { } else if _, ok := properties[key]; ok { e.errorf(entry.Key, "duplicate key %q", key) } else { - properties[key] = e.declare(key, entry.Value, e.base.property(entry.Key, key)) + properties[key] = declare(e, key, entry.Value, e.base.property(entry.Key, key)) } } @@ -356,7 +369,7 @@ func (e *evalContext) evaluateImports() { } s := schema.Record(properties).Schema() - def := e.declare("", ast.Symbol(&ast.PropertyName{Name: "imports"}), nil) + def := declare(e, "", ast.Symbol(&ast.PropertyName{Name: "imports"}), nil) def.schema, def.state = s, exprDone val := &value{ @@ -400,9 +413,6 @@ func (e *evalContext) evaluateImport(myImports map[string]*value, decl *ast.Impo e.errorf(decl.Environment, "%s", err.Error()) return } - if diags.HasErrors() { - return - } imp := newEvalContext(e.ctx, e.validating, name, env, dec, e.providers, e.environments, e.imports) v, diags := imp.evaluate() @@ -443,6 +453,8 @@ func (e *evalContext) evaluateExpr(x *expr) *value { val := (*value)(nil) switch repr := x.repr.(type) { + case *missingExpr: + val = &value{def: x, schema: x.schema, unknown: true} case *literalExpr: switch syntax := x.repr.syntax().(type) { case *ast.NullExpr: @@ -578,6 +590,18 @@ func (e *evalContext) evaluatePropertyAccess(x *expr, accessors []*propertyAcces func (e *evalContext) evaluateExprAccess(x *expr, accessors []*propertyAccessor) *value { receiver := e.root + // This can happen for invalid property accesses. No need to issue an error here--the parser has already done so. + if len(accessors) == 0 { + return &value{ + def: &expr{ + repr: &literalExpr{node: x.repr.syntax()}, + state: exprDone, + }, + schema: schema.Always().Schema(), + unknown: true, + } + } + // Check for an imports access. if k, ok := e.objectKey(x.repr.syntax(), accessors[0].accessor, false); ok && k == "imports" { accessors[0].value = e.myImports @@ -818,6 +842,13 @@ func (e *evalContext) evaluateBuiltinSecret(x *expr, repr *secretExpr) *value { func (e *evalContext) evaluateBuiltinOpen(x *expr, repr *openExpr) *value { v := &value{def: x} + // Can happen if there are parse errors. + if repr.node.Provider == nil { + v.schema = schema.Always() + v.unknown = true + return v + } + provider, err := e.providers.LoadProvider(e.ctx, repr.node.Provider.GetValue()) if err != nil { e.errorf(repr.syntax(), "%v", err) diff --git a/eval/eval_test.go b/eval/eval_test.go index 1fa5d36f..152a26ba 100644 --- a/eval/eval_test.go +++ b/eval/eval_test.go @@ -207,35 +207,35 @@ func TestEval(t *testing.T) { require.NoError(t, err) sortEnvironmentDiagnostics(loadDiags) - expected := expectedData{LoadDiags: loadDiags} - if !loadDiags.HasErrors() { - check, checkDiags := CheckEnvironment(context.Background(), e.Name(), env, testProviders{}, &testEnvironments{basePath}) - sortEnvironmentDiagnostics(checkDiags) - - eval, evalDiags := EvalEnvironment(context.Background(), e.Name(), env, rot128{}, testProviders{}, &testEnvironments{basePath}) - sortEnvironmentDiagnostics(evalDiags) - - var checkJSON any - var evalJSONRedacted any - var evalJSONRevealed any - if check != nil { - check = normalize(t, check) - checkJSON = esc.NewValue(check.Properties).ToJSON(true) - } - if eval != nil { - eval = normalize(t, eval) - evalJSONRedacted = esc.NewValue(eval.Properties).ToJSON(true) - evalJSONRevealed = esc.NewValue(eval.Properties).ToJSON(false) - } - - expected.Check, expected.CheckDiags = check, checkDiags - expected.Eval, expected.EvalDiags = eval, evalDiags - expected.EvalJSONRedacted = evalJSONRedacted - expected.EvalJSONRevealed = evalJSONRevealed - expected.CheckJSON = checkJSON + check, checkDiags := CheckEnvironment(context.Background(), e.Name(), env, testProviders{}, &testEnvironments{basePath}) + sortEnvironmentDiagnostics(checkDiags) + + actual, evalDiags := EvalEnvironment(context.Background(), e.Name(), env, rot128{}, testProviders{}, &testEnvironments{basePath}) + sortEnvironmentDiagnostics(evalDiags) + + var checkJSON any + var evalJSONRedacted any + var evalJSONRevealed any + if check != nil { + check = normalize(t, check) + checkJSON = esc.NewValue(check.Properties).ToJSON(true) + } + if actual != nil { + actual = normalize(t, actual) + evalJSONRedacted = esc.NewValue(actual.Properties).ToJSON(true) + evalJSONRevealed = esc.NewValue(actual.Properties).ToJSON(false) } - bytes, err := json.MarshalIndent(expected, "", " ") + bytes, err := json.MarshalIndent(expectedData{ + LoadDiags: loadDiags, + CheckDiags: checkDiags, + EvalDiags: evalDiags, + Check: check, + Eval: actual, + EvalJSONRedacted: evalJSONRedacted, + EvalJSONRevealed: evalJSONRevealed, + CheckJSON: checkJSON, + }, "", " ") bytes = append(bytes, '\n') require.NoError(t, err) @@ -258,10 +258,6 @@ func TestEval(t *testing.T) { sortEnvironmentDiagnostics(diags) require.Equal(t, expected.LoadDiags, diags) - if diags.HasErrors() { - return - } - check, diags := CheckEnvironment(context.Background(), e.Name(), env, testProviders{}, &testEnvironments{basePath}) sortEnvironmentDiagnostics(diags) require.Equal(t, expected.CheckDiags, diags) diff --git a/eval/expr.go b/eval/expr.go index 2f1a581d..f2b2849c 100644 --- a/eval/expr.go +++ b/eval/expr.go @@ -52,6 +52,11 @@ func newExpr(path string, repr exprRepr, s *schema.Schema, base *value) *expr { return &expr{path: path, repr: repr, schema: s, base: base} } +// newMissingExpr creates a new missing expression. Used in the case of parse errors. +func newMissingExpr(path string, base *value) *expr { + return newExpr(path, &missingExpr{node: ast.Null()}, schema.Always(), base) +} + // convertRange converts an HCL2 range to an ESC range. func convertRange(r *hcl.Range, environment string) esc.Range { rng := esc.Range{Environment: environment} @@ -99,6 +104,8 @@ func (x *expr) export(environment string) esc.Expr { } switch repr := x.repr.(type) { + case *missingExpr: + // nothing to do case *literalExpr: switch syntax := x.repr.syntax().(type) { case *ast.BooleanExpr: @@ -276,6 +283,15 @@ type exprRepr interface { syntax() ast.Expr } +// missingExpr represents a missing value. +type missingExpr struct { + node ast.Expr +} + +func (x *missingExpr) syntax() ast.Expr { + return x.node +} + // literalExpr represents a literal value. type literalExpr struct { node ast.Expr diff --git a/eval/testdata/eval/invalid-access-load/expected.json b/eval/testdata/eval/invalid-access-load/expected.json index 96e8fb1a..2def896d 100644 --- a/eval/testdata/eval/invalid-access-load/expected.json +++ b/eval/testdata/eval/invalid-access-load/expected.json @@ -276,5 +276,1857 @@ "Extra": null, "Path": "values.propertyAccessTest[9]" } - ] + ], + "checkDiags": [ + { + "Severity": 1, + "Summary": "unknown property \"open\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 3, + "Column": 7, + "Byte": 36 + }, + "End": { + "Line": 3, + "Column": 20, + "Byte": 49 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[0]" + }, + { + "Severity": 1, + "Summary": "unknown property \"open\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 4, + "Column": 7, + "Byte": 56 + }, + "End": { + "Line": 4, + "Column": 20, + "Byte": 69 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[1]" + }, + { + "Severity": 1, + "Summary": "unknown property \"open\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 5, + "Column": 7, + "Byte": 76 + }, + "End": { + "Line": 5, + "Column": 20, + "Byte": 89 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[2]" + }, + { + "Severity": 1, + "Summary": "unknown property \"array\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 6, + "Column": 7, + "Byte": 96 + }, + "End": { + "Line": 6, + "Column": 17, + "Byte": 106 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[3]" + }, + { + "Severity": 1, + "Summary": "unknown property \"array\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 7, + "Column": 7, + "Byte": 113 + }, + "End": { + "Line": 7, + "Column": 27, + "Byte": 133 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[4]" + }, + { + "Severity": 1, + "Summary": "cannot access an object property using an integer index", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 9, + "Column": 7, + "Byte": 150 + }, + "End": { + "Line": 9, + "Column": 13, + "Byte": 156 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[6]" + }, + { + "Severity": 1, + "Summary": "unknown property \"2\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 10, + "Column": 7, + "Byte": 163 + }, + "End": { + "Line": 10, + "Column": 19, + "Byte": 175 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[7]" + }, + { + "Severity": 1, + "Summary": "unknown property \"34\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 11, + "Column": 7, + "Byte": 182 + }, + "End": { + "Line": 11, + "Column": 16, + "Byte": 191 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[8]" + }, + { + "Severity": 1, + "Summary": "unknown property \"bad\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 12, + "Column": 7, + "Byte": 198 + }, + "End": { + "Line": 12, + "Column": 14, + "Byte": 205 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[9]" + } + ], + "check": { + "exprs": { + "propertyAccessTest": { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 5, + "byte": 34 + }, + "end": { + "line": 12, + "column": 14, + "byte": 205 + } + }, + "schema": { + "prefixItems": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "items": false, + "type": "array" + }, + "list": [ + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 7, + "byte": 36 + }, + "end": { + "line": 3, + "column": 20, + "byte": 49 + } + }, + "schema": true, + "symbol": [ + { + "key": "open", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 7, + "byte": 36 + }, + "end": { + "line": 3, + "column": 20, + "byte": 49 + } + } + }, + { + "key": "foo", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 7, + "byte": 36 + }, + "end": { + "line": 3, + "column": 20, + "byte": 49 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 4, + "column": 7, + "byte": 56 + }, + "end": { + "line": 4, + "column": 20, + "byte": 69 + } + }, + "schema": true, + "symbol": [ + { + "key": "open", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 4, + "column": 7, + "byte": 56 + }, + "end": { + "line": 4, + "column": 20, + "byte": 69 + } + } + }, + { + "key": "foo]}", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 4, + "column": 7, + "byte": 56 + }, + "end": { + "line": 4, + "column": 20, + "byte": 69 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 5, + "column": 7, + "byte": 76 + }, + "end": { + "line": 5, + "column": 20, + "byte": 89 + } + }, + "schema": true, + "symbol": [ + { + "key": "open", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 5, + "column": 7, + "byte": 76 + }, + "end": { + "line": 5, + "column": 20, + "byte": 89 + } + } + }, + { + "key": "foo", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 5, + "column": 7, + "byte": 76 + }, + "end": { + "line": 5, + "column": 20, + "byte": 89 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 6, + "column": 7, + "byte": 96 + }, + "end": { + "line": 6, + "column": 17, + "byte": 106 + } + }, + "schema": true, + "symbol": [ + { + "key": "array", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 6, + "column": 7, + "byte": 96 + }, + "end": { + "line": 6, + "column": 17, + "byte": 106 + } + } + }, + { + "index": 1, + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 6, + "column": 7, + "byte": 96 + }, + "end": { + "line": 6, + "column": 17, + "byte": 106 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 7, + "column": 7, + "byte": 113 + }, + "end": { + "line": 7, + "column": 27, + "byte": 133 + } + }, + "schema": true, + "symbol": [ + { + "key": "array", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 7, + "column": 7, + "byte": 113 + }, + "end": { + "line": 7, + "column": 27, + "byte": 133 + } + } + }, + { + "index": 0, + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 7, + "column": 7, + "byte": 113 + }, + "end": { + "line": 7, + "column": 27, + "byte": 133 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 8, + "column": 7, + "byte": 140 + }, + "end": { + "line": 8, + "column": 10, + "byte": 143 + } + }, + "schema": true + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 9, + "column": 7, + "byte": 150 + }, + "end": { + "line": 9, + "column": 13, + "byte": 156 + } + }, + "schema": true, + "symbol": [ + { + "index": 2, + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 9, + "column": 7, + "byte": 150 + }, + "end": { + "line": 9, + "column": 13, + "byte": 156 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 10, + "column": 7, + "byte": 163 + }, + "end": { + "line": 10, + "column": 19, + "byte": 175 + } + }, + "schema": true, + "symbol": [ + { + "key": "2", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 10, + "column": 7, + "byte": 163 + }, + "end": { + "line": 10, + "column": 19, + "byte": 175 + } + } + }, + { + "key": "bad", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 10, + "column": 7, + "byte": 163 + }, + "end": { + "line": 10, + "column": 19, + "byte": 175 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 11, + "column": 7, + "byte": 182 + }, + "end": { + "line": 11, + "column": 16, + "byte": 191 + } + }, + "schema": true, + "symbol": [ + { + "key": "34", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 11, + "column": 7, + "byte": 182 + }, + "end": { + "line": 11, + "column": 16, + "byte": 191 + } + } + }, + { + "key": "bad", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 11, + "column": 7, + "byte": 182 + }, + "end": { + "line": 11, + "column": 16, + "byte": 191 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 12, + "column": 7, + "byte": 198 + }, + "end": { + "line": 12, + "column": 14, + "byte": 205 + } + }, + "schema": true, + "symbol": [ + { + "key": "bad", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 12, + "column": 7, + "byte": 198 + }, + "end": { + "line": 12, + "column": 14, + "byte": 205 + } + } + } + ] + } + ] + } + }, + "properties": { + "propertyAccessTest": { + "value": [ + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 7, + "byte": 36 + }, + "end": { + "line": 3, + "column": 20, + "byte": 49 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 4, + "column": 7, + "byte": 56 + }, + "end": { + "line": 4, + "column": 20, + "byte": 69 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 5, + "column": 7, + "byte": 76 + }, + "end": { + "line": 5, + "column": 20, + "byte": 89 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 6, + "column": 7, + "byte": 96 + }, + "end": { + "line": 6, + "column": 17, + "byte": 106 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 7, + "column": 7, + "byte": 113 + }, + "end": { + "line": 7, + "column": 27, + "byte": 133 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 8, + "column": 7, + "byte": 140 + }, + "end": { + "line": 8, + "column": 10, + "byte": 143 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 9, + "column": 7, + "byte": 150 + }, + "end": { + "line": 9, + "column": 13, + "byte": 156 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 10, + "column": 7, + "byte": 163 + }, + "end": { + "line": 10, + "column": 19, + "byte": 175 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 11, + "column": 7, + "byte": 182 + }, + "end": { + "line": 11, + "column": 16, + "byte": 191 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 12, + "column": 7, + "byte": 198 + }, + "end": { + "line": 12, + "column": 14, + "byte": 205 + } + } + } + } + ], + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 5, + "byte": 34 + }, + "end": { + "line": 12, + "column": 14, + "byte": 205 + } + } + } + } + }, + "schema": { + "properties": { + "propertyAccessTest": { + "prefixItems": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "items": false, + "type": "array" + } + }, + "type": "object", + "required": [ + "propertyAccessTest" + ] + } + }, + "checkJson": { + "propertyAccessTest": [ + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]" + ] + }, + "evalDiags": [ + { + "Severity": 1, + "Summary": "unknown property \"open\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 3, + "Column": 7, + "Byte": 36 + }, + "End": { + "Line": 3, + "Column": 20, + "Byte": 49 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[0]" + }, + { + "Severity": 1, + "Summary": "unknown property \"open\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 4, + "Column": 7, + "Byte": 56 + }, + "End": { + "Line": 4, + "Column": 20, + "Byte": 69 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[1]" + }, + { + "Severity": 1, + "Summary": "unknown property \"open\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 5, + "Column": 7, + "Byte": 76 + }, + "End": { + "Line": 5, + "Column": 20, + "Byte": 89 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[2]" + }, + { + "Severity": 1, + "Summary": "unknown property \"array\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 6, + "Column": 7, + "Byte": 96 + }, + "End": { + "Line": 6, + "Column": 17, + "Byte": 106 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[3]" + }, + { + "Severity": 1, + "Summary": "unknown property \"array\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 7, + "Column": 7, + "Byte": 113 + }, + "End": { + "Line": 7, + "Column": 27, + "Byte": 133 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[4]" + }, + { + "Severity": 1, + "Summary": "cannot access an object property using an integer index", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 9, + "Column": 7, + "Byte": 150 + }, + "End": { + "Line": 9, + "Column": 13, + "Byte": 156 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[6]" + }, + { + "Severity": 1, + "Summary": "unknown property \"2\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 10, + "Column": 7, + "Byte": 163 + }, + "End": { + "Line": 10, + "Column": 19, + "Byte": 175 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[7]" + }, + { + "Severity": 1, + "Summary": "unknown property \"34\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 11, + "Column": 7, + "Byte": 182 + }, + "End": { + "Line": 11, + "Column": 16, + "Byte": 191 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[8]" + }, + { + "Severity": 1, + "Summary": "unknown property \"bad\"", + "Detail": "", + "Subject": { + "Filename": "invalid-access-load", + "Start": { + "Line": 12, + "Column": 7, + "Byte": 198 + }, + "End": { + "Line": 12, + "Column": 14, + "Byte": 205 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.propertyAccessTest[9]" + } + ], + "eval": { + "exprs": { + "propertyAccessTest": { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 5, + "byte": 34 + }, + "end": { + "line": 12, + "column": 14, + "byte": 205 + } + }, + "schema": { + "prefixItems": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "items": false, + "type": "array" + }, + "list": [ + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 7, + "byte": 36 + }, + "end": { + "line": 3, + "column": 20, + "byte": 49 + } + }, + "schema": true, + "symbol": [ + { + "key": "open", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 7, + "byte": 36 + }, + "end": { + "line": 3, + "column": 20, + "byte": 49 + } + } + }, + { + "key": "foo", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 7, + "byte": 36 + }, + "end": { + "line": 3, + "column": 20, + "byte": 49 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 4, + "column": 7, + "byte": 56 + }, + "end": { + "line": 4, + "column": 20, + "byte": 69 + } + }, + "schema": true, + "symbol": [ + { + "key": "open", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 4, + "column": 7, + "byte": 56 + }, + "end": { + "line": 4, + "column": 20, + "byte": 69 + } + } + }, + { + "key": "foo]}", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 4, + "column": 7, + "byte": 56 + }, + "end": { + "line": 4, + "column": 20, + "byte": 69 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 5, + "column": 7, + "byte": 76 + }, + "end": { + "line": 5, + "column": 20, + "byte": 89 + } + }, + "schema": true, + "symbol": [ + { + "key": "open", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 5, + "column": 7, + "byte": 76 + }, + "end": { + "line": 5, + "column": 20, + "byte": 89 + } + } + }, + { + "key": "foo", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 5, + "column": 7, + "byte": 76 + }, + "end": { + "line": 5, + "column": 20, + "byte": 89 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 6, + "column": 7, + "byte": 96 + }, + "end": { + "line": 6, + "column": 17, + "byte": 106 + } + }, + "schema": true, + "symbol": [ + { + "key": "array", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 6, + "column": 7, + "byte": 96 + }, + "end": { + "line": 6, + "column": 17, + "byte": 106 + } + } + }, + { + "index": 1, + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 6, + "column": 7, + "byte": 96 + }, + "end": { + "line": 6, + "column": 17, + "byte": 106 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 7, + "column": 7, + "byte": 113 + }, + "end": { + "line": 7, + "column": 27, + "byte": 133 + } + }, + "schema": true, + "symbol": [ + { + "key": "array", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 7, + "column": 7, + "byte": 113 + }, + "end": { + "line": 7, + "column": 27, + "byte": 133 + } + } + }, + { + "index": 0, + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 7, + "column": 7, + "byte": 113 + }, + "end": { + "line": 7, + "column": 27, + "byte": 133 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 8, + "column": 7, + "byte": 140 + }, + "end": { + "line": 8, + "column": 10, + "byte": 143 + } + }, + "schema": true + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 9, + "column": 7, + "byte": 150 + }, + "end": { + "line": 9, + "column": 13, + "byte": 156 + } + }, + "schema": true, + "symbol": [ + { + "index": 2, + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 9, + "column": 7, + "byte": 150 + }, + "end": { + "line": 9, + "column": 13, + "byte": 156 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 10, + "column": 7, + "byte": 163 + }, + "end": { + "line": 10, + "column": 19, + "byte": 175 + } + }, + "schema": true, + "symbol": [ + { + "key": "2", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 10, + "column": 7, + "byte": 163 + }, + "end": { + "line": 10, + "column": 19, + "byte": 175 + } + } + }, + { + "key": "bad", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 10, + "column": 7, + "byte": 163 + }, + "end": { + "line": 10, + "column": 19, + "byte": 175 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 11, + "column": 7, + "byte": 182 + }, + "end": { + "line": 11, + "column": 16, + "byte": 191 + } + }, + "schema": true, + "symbol": [ + { + "key": "34", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 11, + "column": 7, + "byte": 182 + }, + "end": { + "line": 11, + "column": 16, + "byte": 191 + } + } + }, + { + "key": "bad", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 11, + "column": 7, + "byte": 182 + }, + "end": { + "line": 11, + "column": 16, + "byte": 191 + } + } + } + ] + }, + { + "range": { + "environment": "invalid-access-load", + "begin": { + "line": 12, + "column": 7, + "byte": 198 + }, + "end": { + "line": 12, + "column": 14, + "byte": 205 + } + }, + "schema": true, + "symbol": [ + { + "key": "bad", + "value": { + "environment": "invalid-access-load", + "begin": { + "line": 12, + "column": 7, + "byte": 198 + }, + "end": { + "line": 12, + "column": 14, + "byte": 205 + } + } + } + ] + } + ] + } + }, + "properties": { + "propertyAccessTest": { + "value": [ + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 7, + "byte": 36 + }, + "end": { + "line": 3, + "column": 20, + "byte": 49 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 4, + "column": 7, + "byte": 56 + }, + "end": { + "line": 4, + "column": 20, + "byte": 69 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 5, + "column": 7, + "byte": 76 + }, + "end": { + "line": 5, + "column": 20, + "byte": 89 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 6, + "column": 7, + "byte": 96 + }, + "end": { + "line": 6, + "column": 17, + "byte": 106 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 7, + "column": 7, + "byte": 113 + }, + "end": { + "line": 7, + "column": 27, + "byte": 133 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 8, + "column": 7, + "byte": 140 + }, + "end": { + "line": 8, + "column": 10, + "byte": 143 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 9, + "column": 7, + "byte": 150 + }, + "end": { + "line": 9, + "column": 13, + "byte": 156 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 10, + "column": 7, + "byte": 163 + }, + "end": { + "line": 10, + "column": 19, + "byte": 175 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 11, + "column": 7, + "byte": 182 + }, + "end": { + "line": 11, + "column": 16, + "byte": 191 + } + } + } + }, + { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 12, + "column": 7, + "byte": 198 + }, + "end": { + "line": 12, + "column": 14, + "byte": 205 + } + } + } + } + ], + "trace": { + "def": { + "environment": "invalid-access-load", + "begin": { + "line": 3, + "column": 5, + "byte": 34 + }, + "end": { + "line": 12, + "column": 14, + "byte": 205 + } + } + } + } + }, + "schema": { + "properties": { + "propertyAccessTest": { + "prefixItems": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "items": false, + "type": "array" + } + }, + "type": "object", + "required": [ + "propertyAccessTest" + ] + } + }, + "evalJsonRedacted": { + "propertyAccessTest": [ + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]" + ] + }, + "evalJSONRevealed": { + "propertyAccessTest": [ + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]", + "[unknown]" + ] + } } diff --git a/eval/testdata/eval/invalid-join/env.yaml b/eval/testdata/eval/invalid-join/env.yaml new file mode 100644 index 00000000..cf6194e5 --- /dev/null +++ b/eval/testdata/eval/invalid-join/env.yaml @@ -0,0 +1,4 @@ +values: + join: + fn::join: oops + other: value diff --git a/eval/testdata/eval/invalid-join/expected.json b/eval/testdata/eval/invalid-join/expected.json new file mode 100644 index 00000000..0f0ba034 --- /dev/null +++ b/eval/testdata/eval/invalid-join/expected.json @@ -0,0 +1,391 @@ +{ + "loadDiags": [ + { + "Severity": 1, + "Summary": "the argument to fn::join must be a two-valued list", + "Detail": "", + "Subject": { + "Filename": "invalid-join", + "Start": { + "Line": 3, + "Column": 15, + "Byte": 30 + }, + "End": { + "Line": 3, + "Column": 19, + "Byte": 34 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.join[\"fn::join\"]" + } + ], + "check": { + "exprs": { + "join": { + "range": { + "environment": "invalid-join", + "begin": { + "line": 3, + "column": 5, + "byte": 20 + }, + "end": { + "line": 3, + "column": 19, + "byte": 34 + } + }, + "schema": { + "type": "string" + }, + "builtin": { + "name": "fn::join", + "nameRange": { + "environment": "invalid-join", + "begin": { + "line": 3, + "column": 5, + "byte": 20 + }, + "end": { + "line": 3, + "column": 13, + "byte": 28 + } + }, + "argSchema": { + "prefixItems": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "items": false, + "type": "array" + }, + "arg": { + "range": { + "environment": "invalid-join", + "begin": { + "line": 3, + "column": 15, + "byte": 30 + }, + "end": { + "line": 3, + "column": 19, + "byte": 34 + } + }, + "list": [ + { + "range": { + "environment": "invalid-join", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": true + }, + { + "range": { + "environment": "invalid-join", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": true + } + ] + } + } + }, + "other": { + "range": { + "environment": "invalid-join", + "begin": { + "line": 4, + "column": 10, + "byte": 44 + }, + "end": { + "line": 4, + "column": 15, + "byte": 49 + } + }, + "schema": { + "type": "string", + "const": "value" + }, + "literal": "value" + } + }, + "properties": { + "join": { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-join", + "begin": { + "line": 3, + "column": 5, + "byte": 20 + }, + "end": { + "line": 3, + "column": 19, + "byte": 34 + } + } + } + }, + "other": { + "value": "value", + "trace": { + "def": { + "environment": "invalid-join", + "begin": { + "line": 4, + "column": 10, + "byte": 44 + }, + "end": { + "line": 4, + "column": 15, + "byte": 49 + } + } + } + } + }, + "schema": { + "properties": { + "join": { + "type": "string" + }, + "other": { + "type": "string", + "const": "value" + } + }, + "type": "object", + "required": [ + "join", + "other" + ] + } + }, + "checkJson": { + "join": "[unknown]", + "other": "value" + }, + "eval": { + "exprs": { + "join": { + "range": { + "environment": "invalid-join", + "begin": { + "line": 3, + "column": 5, + "byte": 20 + }, + "end": { + "line": 3, + "column": 19, + "byte": 34 + } + }, + "schema": { + "type": "string" + }, + "builtin": { + "name": "fn::join", + "nameRange": { + "environment": "invalid-join", + "begin": { + "line": 3, + "column": 5, + "byte": 20 + }, + "end": { + "line": 3, + "column": 13, + "byte": 28 + } + }, + "argSchema": { + "prefixItems": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "items": false, + "type": "array" + }, + "arg": { + "range": { + "environment": "invalid-join", + "begin": { + "line": 3, + "column": 15, + "byte": 30 + }, + "end": { + "line": 3, + "column": 19, + "byte": 34 + } + }, + "list": [ + { + "range": { + "environment": "invalid-join", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": true + }, + { + "range": { + "environment": "invalid-join", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": true + } + ] + } + } + }, + "other": { + "range": { + "environment": "invalid-join", + "begin": { + "line": 4, + "column": 10, + "byte": 44 + }, + "end": { + "line": 4, + "column": 15, + "byte": 49 + } + }, + "schema": { + "type": "string", + "const": "value" + }, + "literal": "value" + } + }, + "properties": { + "join": { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-join", + "begin": { + "line": 3, + "column": 5, + "byte": 20 + }, + "end": { + "line": 3, + "column": 19, + "byte": 34 + } + } + } + }, + "other": { + "value": "value", + "trace": { + "def": { + "environment": "invalid-join", + "begin": { + "line": 4, + "column": 10, + "byte": 44 + }, + "end": { + "line": 4, + "column": 15, + "byte": 49 + } + } + } + } + }, + "schema": { + "properties": { + "join": { + "type": "string" + }, + "other": { + "type": "string", + "const": "value" + } + }, + "type": "object", + "required": [ + "join", + "other" + ] + } + }, + "evalJsonRedacted": { + "join": "[unknown]", + "other": "value" + }, + "evalJSONRevealed": { + "join": "[unknown]", + "other": "value" + } +} diff --git a/eval/testdata/eval/invalid-open/env.yaml b/eval/testdata/eval/invalid-open/env.yaml new file mode 100644 index 00000000..b215191b --- /dev/null +++ b/eval/testdata/eval/invalid-open/env.yaml @@ -0,0 +1,11 @@ +values: + missing-provider: + fn::open: + inputs: inputs + missing-inputs: + fn::open: + provider: test + invalid-provider: + fn::open: + provider: [ oops ] + inputs: inputs diff --git a/eval/testdata/eval/invalid-open/expected.json b/eval/testdata/eval/invalid-open/expected.json new file mode 100644 index 00000000..9c8a11a1 --- /dev/null +++ b/eval/testdata/eval/invalid-open/expected.json @@ -0,0 +1,816 @@ +{ + "loadDiags": [ + { + "Severity": 1, + "Summary": "missing provider name ('provider')", + "Detail": "", + "Subject": { + "Filename": "invalid-open", + "Start": { + "Line": 4, + "Column": 7, + "Byte": 48 + }, + "End": { + "Line": 4, + "Column": 21, + "Byte": 62 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values[\"missing-provider\"][\"fn::open\"]" + }, + { + "Severity": 1, + "Summary": "missing provider inputs ('inputs')", + "Detail": "", + "Subject": { + "Filename": "invalid-open", + "Start": { + "Line": 7, + "Column": 7, + "Byte": 101 + }, + "End": { + "Line": 7, + "Column": 21, + "Byte": 115 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values[\"missing-inputs\"][\"fn::open\"]" + }, + { + "Severity": 1, + "Summary": "provider name must be a string literal", + "Detail": "", + "Subject": { + "Filename": "invalid-open", + "Start": { + "Line": 10, + "Column": 17, + "Byte": 166 + }, + "End": { + "Line": 10, + "Column": 23, + "Byte": 172 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values[\"invalid-provider\"][\"fn::open\"].provider" + } + ], + "check": { + "exprs": { + "invalid-provider": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 9, + "column": 5, + "byte": 140 + }, + "end": { + "line": 11, + "column": 21, + "byte": 195 + } + }, + "schema": true, + "builtin": { + "name": "fn::open", + "nameRange": { + "environment": "invalid-open", + "begin": { + "line": 9, + "column": 5, + "byte": 140 + }, + "end": { + "line": 9, + "column": 13, + "byte": 148 + } + }, + "argSchema": { + "properties": { + "inputs": true, + "provider": { + "type": "string" + } + }, + "type": "object", + "required": [ + "inputs", + "provider" + ] + }, + "arg": { + "range": { + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "object": { + "inputs": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 11, + "column": 15, + "byte": 189 + }, + "end": { + "line": 11, + "column": 21, + "byte": 195 + } + }, + "schema": { + "type": "string", + "const": "inputs" + }, + "literal": "inputs" + }, + "provider": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": true + } + } + } + } + }, + "missing-inputs": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 6, + "column": 5, + "byte": 85 + }, + "end": { + "line": 7, + "column": 21, + "byte": 115 + } + }, + "schema": true, + "builtin": { + "name": "fn::open", + "nameRange": { + "environment": "invalid-open", + "begin": { + "line": 6, + "column": 5, + "byte": 85 + }, + "end": { + "line": 6, + "column": 13, + "byte": 93 + } + }, + "argSchema": { + "properties": { + "inputs": true, + "provider": { + "type": "string" + } + }, + "type": "object", + "required": [ + "inputs", + "provider" + ] + }, + "arg": { + "range": { + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "object": { + "inputs": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": true + }, + "provider": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 7, + "column": 17, + "byte": 111 + }, + "end": { + "line": 7, + "column": 21, + "byte": 115 + } + }, + "schema": { + "type": "string", + "const": "test" + }, + "literal": "test" + } + } + } + } + }, + "missing-provider": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 3, + "column": 5, + "byte": 32 + }, + "end": { + "line": 4, + "column": 21, + "byte": 62 + } + }, + "schema": true, + "builtin": { + "name": "fn::open", + "nameRange": { + "environment": "invalid-open", + "begin": { + "line": 3, + "column": 5, + "byte": 32 + }, + "end": { + "line": 3, + "column": 13, + "byte": 40 + } + }, + "argSchema": { + "properties": { + "inputs": true, + "provider": { + "type": "string" + } + }, + "type": "object", + "required": [ + "inputs", + "provider" + ] + }, + "arg": { + "range": { + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "object": { + "inputs": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 4, + "column": 15, + "byte": 56 + }, + "end": { + "line": 4, + "column": 21, + "byte": 62 + } + }, + "schema": { + "type": "string", + "const": "inputs" + }, + "literal": "inputs" + }, + "provider": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": true + } + } + } + } + } + }, + "properties": { + "invalid-provider": { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-open", + "begin": { + "line": 9, + "column": 5, + "byte": 140 + }, + "end": { + "line": 11, + "column": 21, + "byte": 195 + } + } + } + }, + "missing-inputs": { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-open", + "begin": { + "line": 6, + "column": 5, + "byte": 85 + }, + "end": { + "line": 7, + "column": 21, + "byte": 115 + } + } + } + }, + "missing-provider": { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-open", + "begin": { + "line": 3, + "column": 5, + "byte": 32 + }, + "end": { + "line": 4, + "column": 21, + "byte": 62 + } + } + } + } + }, + "schema": { + "properties": { + "invalid-provider": true, + "missing-inputs": true, + "missing-provider": true + }, + "type": "object", + "required": [ + "invalid-provider", + "missing-inputs", + "missing-provider" + ] + } + }, + "checkJson": { + "invalid-provider": "[unknown]", + "missing-inputs": "[unknown]", + "missing-provider": "[unknown]" + }, + "eval": { + "exprs": { + "invalid-provider": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 9, + "column": 5, + "byte": 140 + }, + "end": { + "line": 11, + "column": 21, + "byte": 195 + } + }, + "schema": true, + "builtin": { + "name": "fn::open", + "nameRange": { + "environment": "invalid-open", + "begin": { + "line": 9, + "column": 5, + "byte": 140 + }, + "end": { + "line": 9, + "column": 13, + "byte": 148 + } + }, + "argSchema": { + "properties": { + "inputs": true, + "provider": { + "type": "string" + } + }, + "type": "object", + "required": [ + "inputs", + "provider" + ] + }, + "arg": { + "range": { + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "object": { + "inputs": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 11, + "column": 15, + "byte": 189 + }, + "end": { + "line": 11, + "column": 21, + "byte": 195 + } + }, + "schema": { + "type": "string", + "const": "inputs" + }, + "literal": "inputs" + }, + "provider": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": true + } + } + } + } + }, + "missing-inputs": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 6, + "column": 5, + "byte": 85 + }, + "end": { + "line": 7, + "column": 21, + "byte": 115 + } + }, + "schema": true, + "builtin": { + "name": "fn::open", + "nameRange": { + "environment": "invalid-open", + "begin": { + "line": 6, + "column": 5, + "byte": 85 + }, + "end": { + "line": 6, + "column": 13, + "byte": 93 + } + }, + "argSchema": { + "properties": { + "inputs": true, + "provider": { + "type": "string" + } + }, + "type": "object", + "required": [ + "inputs", + "provider" + ] + }, + "arg": { + "range": { + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "object": { + "inputs": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": true + }, + "provider": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 7, + "column": 17, + "byte": 111 + }, + "end": { + "line": 7, + "column": 21, + "byte": 115 + } + }, + "schema": { + "type": "string", + "const": "test" + }, + "literal": "test" + } + } + } + } + }, + "missing-provider": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 3, + "column": 5, + "byte": 32 + }, + "end": { + "line": 4, + "column": 21, + "byte": 62 + } + }, + "schema": true, + "builtin": { + "name": "fn::open", + "nameRange": { + "environment": "invalid-open", + "begin": { + "line": 3, + "column": 5, + "byte": 32 + }, + "end": { + "line": 3, + "column": 13, + "byte": 40 + } + }, + "argSchema": { + "properties": { + "inputs": true, + "provider": { + "type": "string" + } + }, + "type": "object", + "required": [ + "inputs", + "provider" + ] + }, + "arg": { + "range": { + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "object": { + "inputs": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 4, + "column": 15, + "byte": 56 + }, + "end": { + "line": 4, + "column": 21, + "byte": 62 + } + }, + "schema": { + "type": "string", + "const": "inputs" + }, + "literal": "inputs" + }, + "provider": { + "range": { + "environment": "invalid-open", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": true + } + } + } + } + } + }, + "properties": { + "invalid-provider": { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-open", + "begin": { + "line": 9, + "column": 5, + "byte": 140 + }, + "end": { + "line": 11, + "column": 21, + "byte": 195 + } + } + } + }, + "missing-inputs": { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-open", + "begin": { + "line": 6, + "column": 5, + "byte": 85 + }, + "end": { + "line": 7, + "column": 21, + "byte": 115 + } + } + } + }, + "missing-provider": { + "unknown": true, + "trace": { + "def": { + "environment": "invalid-open", + "begin": { + "line": 3, + "column": 5, + "byte": 32 + }, + "end": { + "line": 4, + "column": 21, + "byte": 62 + } + } + } + } + }, + "schema": { + "properties": { + "invalid-provider": true, + "missing-inputs": true, + "missing-provider": true + }, + "type": "object", + "required": [ + "invalid-provider", + "missing-inputs", + "missing-provider" + ] + } + }, + "evalJsonRedacted": { + "invalid-provider": "[unknown]", + "missing-inputs": "[unknown]", + "missing-provider": "[unknown]" + }, + "evalJSONRevealed": { + "invalid-provider": "[unknown]", + "missing-inputs": "[unknown]", + "missing-provider": "[unknown]" + } +} diff --git a/eval/testdata/eval/invalid-plaintext/env.yaml b/eval/testdata/eval/invalid-plaintext/env.yaml new file mode 100644 index 00000000..e354a49e --- /dev/null +++ b/eval/testdata/eval/invalid-plaintext/env.yaml @@ -0,0 +1,6 @@ +values: + foo: + fn::secret: [ some, list ] + bar: + a: valid + object: here diff --git a/eval/testdata/eval/invalid-plaintext/expected.json b/eval/testdata/eval/invalid-plaintext/expected.json new file mode 100644 index 00000000..c7b008bf --- /dev/null +++ b/eval/testdata/eval/invalid-plaintext/expected.json @@ -0,0 +1,584 @@ +{ + "loadDiags": [ + { + "Severity": 1, + "Summary": "secret values must be string literals", + "Detail": "", + "Subject": { + "Filename": "invalid-plaintext", + "Start": { + "Line": 3, + "Column": 17, + "Byte": 31 + }, + "End": { + "Line": 3, + "Column": 29, + "Byte": 43 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "values.foo[\"fn::secret\"]" + } + ], + "check": { + "exprs": { + "bar": { + "range": { + "environment": "invalid-plaintext", + "begin": { + "line": 5, + "column": 5, + "byte": 57 + }, + "end": { + "line": 6, + "column": 17, + "byte": 82 + } + }, + "schema": { + "properties": { + "a": { + "type": "string", + "const": "valid" + }, + "object": { + "type": "string", + "const": "here" + } + }, + "type": "object", + "required": [ + "a", + "object" + ] + }, + "keyRanges": { + "a": { + "environment": "invalid-plaintext", + "begin": { + "line": 5, + "column": 5, + "byte": 57 + }, + "end": { + "line": 5, + "column": 6, + "byte": 58 + } + }, + "object": { + "environment": "invalid-plaintext", + "begin": { + "line": 6, + "column": 5, + "byte": 70 + }, + "end": { + "line": 6, + "column": 11, + "byte": 76 + } + } + }, + "object": { + "a": { + "range": { + "environment": "invalid-plaintext", + "begin": { + "line": 5, + "column": 8, + "byte": 60 + }, + "end": { + "line": 5, + "column": 13, + "byte": 65 + } + }, + "schema": { + "type": "string", + "const": "valid" + }, + "literal": "valid" + }, + "object": { + "range": { + "environment": "invalid-plaintext", + "begin": { + "line": 6, + "column": 13, + "byte": 78 + }, + "end": { + "line": 6, + "column": 17, + "byte": 82 + } + }, + "schema": { + "type": "string", + "const": "here" + }, + "literal": "here" + } + } + }, + "foo": { + "range": { + "environment": "invalid-plaintext", + "begin": { + "line": 3, + "column": 5, + "byte": 19 + }, + "end": { + "line": 3, + "column": 29, + "byte": 43 + } + }, + "schema": { + "type": "string", + "const": "" + }, + "builtin": { + "name": "fn::secret", + "nameRange": { + "environment": "invalid-plaintext", + "begin": { + "line": 3, + "column": 5, + "byte": 19 + }, + "end": { + "line": 3, + "column": 15, + "byte": 29 + } + }, + "argSchema": true, + "arg": { + "range": { + "environment": "invalid-plaintext", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": { + "type": "string", + "const": "" + }, + "literal": "" + } + } + } + }, + "properties": { + "bar": { + "value": { + "a": { + "value": "valid", + "trace": { + "def": { + "environment": "invalid-plaintext", + "begin": { + "line": 5, + "column": 8, + "byte": 60 + }, + "end": { + "line": 5, + "column": 13, + "byte": 65 + } + } + } + }, + "object": { + "value": "here", + "trace": { + "def": { + "environment": "invalid-plaintext", + "begin": { + "line": 6, + "column": 13, + "byte": 78 + }, + "end": { + "line": 6, + "column": 17, + "byte": 82 + } + } + } + } + }, + "trace": { + "def": { + "environment": "invalid-plaintext", + "begin": { + "line": 5, + "column": 5, + "byte": 57 + }, + "end": { + "line": 6, + "column": 17, + "byte": 82 + } + } + } + }, + "foo": { + "value": "", + "secret": true, + "trace": { + "def": { + "environment": "invalid-plaintext", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "schema": { + "properties": { + "bar": { + "properties": { + "a": { + "type": "string", + "const": "valid" + }, + "object": { + "type": "string", + "const": "here" + } + }, + "type": "object", + "required": [ + "a", + "object" + ] + }, + "foo": { + "type": "string", + "const": "" + } + }, + "type": "object", + "required": [ + "bar", + "foo" + ] + } + }, + "checkJson": { + "bar": { + "a": "valid", + "object": "here" + }, + "foo": "[secret]" + }, + "eval": { + "exprs": { + "bar": { + "range": { + "environment": "invalid-plaintext", + "begin": { + "line": 5, + "column": 5, + "byte": 57 + }, + "end": { + "line": 6, + "column": 17, + "byte": 82 + } + }, + "schema": { + "properties": { + "a": { + "type": "string", + "const": "valid" + }, + "object": { + "type": "string", + "const": "here" + } + }, + "type": "object", + "required": [ + "a", + "object" + ] + }, + "keyRanges": { + "a": { + "environment": "invalid-plaintext", + "begin": { + "line": 5, + "column": 5, + "byte": 57 + }, + "end": { + "line": 5, + "column": 6, + "byte": 58 + } + }, + "object": { + "environment": "invalid-plaintext", + "begin": { + "line": 6, + "column": 5, + "byte": 70 + }, + "end": { + "line": 6, + "column": 11, + "byte": 76 + } + } + }, + "object": { + "a": { + "range": { + "environment": "invalid-plaintext", + "begin": { + "line": 5, + "column": 8, + "byte": 60 + }, + "end": { + "line": 5, + "column": 13, + "byte": 65 + } + }, + "schema": { + "type": "string", + "const": "valid" + }, + "literal": "valid" + }, + "object": { + "range": { + "environment": "invalid-plaintext", + "begin": { + "line": 6, + "column": 13, + "byte": 78 + }, + "end": { + "line": 6, + "column": 17, + "byte": 82 + } + }, + "schema": { + "type": "string", + "const": "here" + }, + "literal": "here" + } + } + }, + "foo": { + "range": { + "environment": "invalid-plaintext", + "begin": { + "line": 3, + "column": 5, + "byte": 19 + }, + "end": { + "line": 3, + "column": 29, + "byte": 43 + } + }, + "schema": { + "type": "string", + "const": "" + }, + "builtin": { + "name": "fn::secret", + "nameRange": { + "environment": "invalid-plaintext", + "begin": { + "line": 3, + "column": 5, + "byte": 19 + }, + "end": { + "line": 3, + "column": 15, + "byte": 29 + } + }, + "argSchema": true, + "arg": { + "range": { + "environment": "invalid-plaintext", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + }, + "schema": { + "type": "string", + "const": "" + }, + "literal": "" + } + } + } + }, + "properties": { + "bar": { + "value": { + "a": { + "value": "valid", + "trace": { + "def": { + "environment": "invalid-plaintext", + "begin": { + "line": 5, + "column": 8, + "byte": 60 + }, + "end": { + "line": 5, + "column": 13, + "byte": 65 + } + } + } + }, + "object": { + "value": "here", + "trace": { + "def": { + "environment": "invalid-plaintext", + "begin": { + "line": 6, + "column": 13, + "byte": 78 + }, + "end": { + "line": 6, + "column": 17, + "byte": 82 + } + } + } + } + }, + "trace": { + "def": { + "environment": "invalid-plaintext", + "begin": { + "line": 5, + "column": 5, + "byte": 57 + }, + "end": { + "line": 6, + "column": 17, + "byte": 82 + } + } + } + }, + "foo": { + "value": "", + "secret": true, + "trace": { + "def": { + "environment": "invalid-plaintext", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "schema": { + "properties": { + "bar": { + "properties": { + "a": { + "type": "string", + "const": "valid" + }, + "object": { + "type": "string", + "const": "here" + } + }, + "type": "object", + "required": [ + "a", + "object" + ] + }, + "foo": { + "type": "string", + "const": "" + } + }, + "type": "object", + "required": [ + "bar", + "foo" + ] + } + }, + "evalJsonRedacted": { + "bar": { + "a": "valid", + "object": "here" + }, + "foo": "[secret]" + }, + "evalJSONRevealed": { + "bar": { + "a": "valid", + "object": "here" + }, + "foo": "" + } +}