diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index ce7802cd..c14ae72a 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -1,5 +1,8 @@ ### Improvements +- Add support for environment-level schema validation with top-level `schema` key. + [#625](https://github.com/pulumi/esc/pull/625) + - Surface warnings when editing environments with the CLI [#631](https://github.com/pulumi/esc/pull/631) diff --git a/ast/environment.go b/ast/environment.go index fe086fbf..993e7f67 100644 --- a/ast/environment.go +++ b/ast/environment.go @@ -197,6 +197,7 @@ type EnvironmentDecl struct { Description *StringExpr Imports ImportListDecl Values PropertyMapDecl + Schema Expr } func (d *EnvironmentDecl) Syntax() syntax.Node { diff --git a/ast/testdata/parse/duplicate-top-level-keys/expected.json b/ast/testdata/parse/duplicate-top-level-keys/expected.json index 6e5fa8f1..24f28330 100644 --- a/ast/testdata/parse/duplicate-top-level-keys/expected.json +++ b/ast/testdata/parse/duplicate-top-level-keys/expected.json @@ -13,7 +13,8 @@ } } ] - } + }, + "Schema": null }, "diags": [ { diff --git a/ast/testdata/parse/invalid-interpolations/expected.json b/ast/testdata/parse/invalid-interpolations/expected.json index bfea9c04..8fca7f8d 100644 --- a/ast/testdata/parse/invalid-interpolations/expected.json +++ b/ast/testdata/parse/invalid-interpolations/expected.json @@ -303,7 +303,8 @@ } } ] - } + }, + "Schema": null }, "diags": [ { diff --git a/ast/testdata/parse/invalid-invocation/expected.json b/ast/testdata/parse/invalid-invocation/expected.json index a46a3f07..b89b0421 100644 --- a/ast/testdata/parse/invalid-invocation/expected.json +++ b/ast/testdata/parse/invalid-invocation/expected.json @@ -48,7 +48,8 @@ } } ] - } + }, + "Schema": null }, "diags": [ { diff --git a/ast/testdata/parse/invalid-invocation2/expected.json b/ast/testdata/parse/invalid-invocation2/expected.json index fe24a84c..1b68d3aa 100644 --- a/ast/testdata/parse/invalid-invocation2/expected.json +++ b/ast/testdata/parse/invalid-invocation2/expected.json @@ -13,7 +13,8 @@ } } ] - } + }, + "Schema": null }, "diags": [ { diff --git a/ast/testdata/parse/invalid-join/expected.json b/ast/testdata/parse/invalid-join/expected.json index 0ca69370..72f4af31 100644 --- a/ast/testdata/parse/invalid-join/expected.json +++ b/ast/testdata/parse/invalid-join/expected.json @@ -22,7 +22,8 @@ } } ] - } + }, + "Schema": null }, "diags": [ { diff --git a/ast/testdata/parse/invalid-open/expected.json b/ast/testdata/parse/invalid-open/expected.json index 19eaa4b8..81246399 100644 --- a/ast/testdata/parse/invalid-open/expected.json +++ b/ast/testdata/parse/invalid-open/expected.json @@ -38,7 +38,8 @@ } } ] - } + }, + "Schema": null }, "diags": [ { diff --git a/ast/testdata/parse/invalid-plaintext/expected.json b/ast/testdata/parse/invalid-plaintext/expected.json index 310692c7..c56636e9 100644 --- a/ast/testdata/parse/invalid-plaintext/expected.json +++ b/ast/testdata/parse/invalid-plaintext/expected.json @@ -41,7 +41,8 @@ } } ] - } + }, + "Schema": null }, "diags": [ { diff --git a/eval/eval.go b/eval/eval.go index 7328cecc..1dc59da3 100644 --- a/eval/eval.go +++ b/eval/eval.go @@ -426,7 +426,7 @@ func declare[Expr exprNode](e *evalContext, path string, x Expr, base *value) *e func (e *evalContext) isReserveTopLevelKey(k string) bool { switch k { - case "imports", "context", "environments": + case "imports", "context", "environments", "schema": return true default: return false @@ -471,6 +471,30 @@ func (e *evalContext) evaluate() (*value, syntax.Diagnostics) { // Evaluate the root value and return. v := e.evaluateExpr(e.root, schema.Always()) + + // If a top-level schema is defined, validate the root value against it. + if e.env.Schema != nil { + schemaDef := declare(e, "*schema*", e.env.Schema, nil) + schemaVal := e.evaluateExpr(schemaDef, schema.JSONSchemaSchema()) + if schemaVal.containsUnknowns() { + e.errorf(e.env.Schema, "schema must not contain unknowns") + } else { + vv := validator{} + schemaOk := vv.validateValue(schemaVal, schema.JSONSchemaSchema(), validationLoc{x: schemaDef}) + e.diags.Extend(vv.diags...) + if schemaOk { + validationSchema, err := e.valueToSchema(schemaVal) + if err != nil { + e.errorf(e.env.Schema, "invalid schema: %v", err) + } else if err := validationSchema.Compile(); err != nil { + e.errorf(e.env.Schema, "invalid schema: %v", err) + } else { + v, _ = e.evaluateTypedExpr(e.root, validationSchema) + } + } + } + } + return v, e.diags } diff --git a/eval/testdata/eval/schema-top-level-error/env.yaml b/eval/testdata/eval/schema-top-level-error/env.yaml new file mode 100644 index 00000000..4921c61a --- /dev/null +++ b/eval/testdata/eval/schema-top-level-error/env.yaml @@ -0,0 +1,9 @@ +schema: + type: object + properties: + foo: + type: string + required: + - foo +values: + bar: baz diff --git a/eval/testdata/eval/schema-top-level-error/expected.json b/eval/testdata/eval/schema-top-level-error/expected.json new file mode 100644 index 00000000..f455b7f3 --- /dev/null +++ b/eval/testdata/eval/schema-top-level-error/expected.json @@ -0,0 +1,525 @@ +{ + "checkDiags": [ + { + "Severity": 1, + "Summary": "missing required properties: foo", + "Detail": "", + "Subject": null, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "" + } + ], + "check": { + "exprs": { + "bar": { + "range": { + "environment": "schema-top-level-error", + "begin": { + "line": 9, + "column": 8, + "byte": 102 + }, + "end": { + "line": 9, + "column": 11, + "byte": 105 + } + }, + "schema": { + "type": "string", + "const": "baz" + }, + "literal": "baz" + } + }, + "properties": { + "bar": { + "value": "baz", + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 9, + "column": 8, + "byte": 102 + }, + "end": { + "line": 9, + "column": 11, + "byte": 105 + } + } + } + } + }, + "schema": { + "properties": { + "bar": { + "type": "string", + "const": "baz" + } + }, + "type": "object", + "required": [ + "bar" + ] + }, + "executionContext": { + "properties": { + "currentEnvironment": { + "value": { + "name": { + "value": "schema-top-level-error", + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "pulumi": { + "value": { + "user": { + "value": { + "id": { + "value": "USER_123", + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "rootEnvironment": { + "value": { + "name": { + "value": "schema-top-level-error", + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "schema": { + "properties": { + "currentEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-error" + } + }, + "type": "object", + "required": [ + "name" + ] + }, + "pulumi": { + "properties": { + "user": { + "properties": { + "id": { + "type": "string", + "const": "USER_123" + } + }, + "type": "object", + "required": [ + "id" + ] + } + }, + "type": "object", + "required": [ + "user" + ] + }, + "rootEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-error" + } + }, + "type": "object", + "required": [ + "name" + ] + } + }, + "type": "object", + "required": [ + "currentEnvironment", + "pulumi", + "rootEnvironment" + ] + } + } + }, + "checkJson": { + "bar": "baz" + }, + "evalDiags": [ + { + "Severity": 1, + "Summary": "missing required properties: foo", + "Detail": "", + "Subject": null, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "" + } + ], + "eval": { + "exprs": { + "bar": { + "range": { + "environment": "schema-top-level-error", + "begin": { + "line": 9, + "column": 8, + "byte": 102 + }, + "end": { + "line": 9, + "column": 11, + "byte": 105 + } + }, + "schema": { + "type": "string", + "const": "baz" + }, + "literal": "baz" + } + }, + "properties": { + "bar": { + "value": "baz", + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 9, + "column": 8, + "byte": 102 + }, + "end": { + "line": 9, + "column": 11, + "byte": 105 + } + } + } + } + }, + "schema": { + "properties": { + "bar": { + "type": "string", + "const": "baz" + } + }, + "type": "object", + "required": [ + "bar" + ] + }, + "executionContext": { + "properties": { + "currentEnvironment": { + "value": { + "name": { + "value": "schema-top-level-error", + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "pulumi": { + "value": { + "user": { + "value": { + "id": { + "value": "USER_123", + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "rootEnvironment": { + "value": { + "name": { + "value": "schema-top-level-error", + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-error", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "schema": { + "properties": { + "currentEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-error" + } + }, + "type": "object", + "required": [ + "name" + ] + }, + "pulumi": { + "properties": { + "user": { + "properties": { + "id": { + "type": "string", + "const": "USER_123" + } + }, + "type": "object", + "required": [ + "id" + ] + } + }, + "type": "object", + "required": [ + "user" + ] + }, + "rootEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-error" + } + }, + "type": "object", + "required": [ + "name" + ] + } + }, + "type": "object", + "required": [ + "currentEnvironment", + "pulumi", + "rootEnvironment" + ] + } + } + }, + "evalJsonRedacted": { + "bar": "baz" + }, + "evalJSONRevealed": { + "bar": "baz" + } +} diff --git a/eval/testdata/eval/schema-top-level-invalid/env.yaml b/eval/testdata/eval/schema-top-level-invalid/env.yaml new file mode 100644 index 00000000..285e2480 --- /dev/null +++ b/eval/testdata/eval/schema-top-level-invalid/env.yaml @@ -0,0 +1,4 @@ +schema: + type: not-a-real-type +values: + foo: bar diff --git a/eval/testdata/eval/schema-top-level-invalid/expected.json b/eval/testdata/eval/schema-top-level-invalid/expected.json new file mode 100644 index 00000000..69f68699 --- /dev/null +++ b/eval/testdata/eval/schema-top-level-invalid/expected.json @@ -0,0 +1,641 @@ +{ + "checkDiags": [ + { + "Severity": 1, + "Summary": "expected boolean, got object", + "Detail": "", + "Subject": { + "Filename": "schema-top-level-invalid", + "Start": { + "Line": 2, + "Column": 3, + "Byte": 10 + }, + "End": { + "Line": 2, + "Column": 24, + "Byte": 31 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "schema" + }, + { + "Severity": 1, + "Summary": "at least one subschema must match", + "Detail": "", + "Subject": { + "Filename": "schema-top-level-invalid", + "Start": { + "Line": 2, + "Column": 3, + "Byte": 10 + }, + "End": { + "Line": 2, + "Column": 24, + "Byte": 31 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "schema" + }, + { + "Severity": 1, + "Summary": "expected one of [\"string\",\"number\",\"boolean\",\"array\",\"object\",\"null\"]", + "Detail": "", + "Subject": { + "Filename": "schema-top-level-invalid", + "Start": { + "Line": 2, + "Column": 9, + "Byte": 16 + }, + "End": { + "Line": 2, + "Column": 24, + "Byte": 31 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "schema.type" + } + ], + "check": { + "exprs": { + "foo": { + "range": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 4, + "column": 8, + "byte": 47 + }, + "end": { + "line": 4, + "column": 11, + "byte": 50 + } + }, + "schema": { + "type": "string", + "const": "bar" + }, + "literal": "bar" + } + }, + "properties": { + "foo": { + "value": "bar", + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 4, + "column": 8, + "byte": 47 + }, + "end": { + "line": 4, + "column": 11, + "byte": 50 + } + } + } + } + }, + "schema": { + "properties": { + "foo": { + "type": "string", + "const": "bar" + } + }, + "type": "object", + "required": [ + "foo" + ] + }, + "executionContext": { + "properties": { + "currentEnvironment": { + "value": { + "name": { + "value": "schema-top-level-invalid", + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "pulumi": { + "value": { + "user": { + "value": { + "id": { + "value": "USER_123", + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "rootEnvironment": { + "value": { + "name": { + "value": "schema-top-level-invalid", + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "schema": { + "properties": { + "currentEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-invalid" + } + }, + "type": "object", + "required": [ + "name" + ] + }, + "pulumi": { + "properties": { + "user": { + "properties": { + "id": { + "type": "string", + "const": "USER_123" + } + }, + "type": "object", + "required": [ + "id" + ] + } + }, + "type": "object", + "required": [ + "user" + ] + }, + "rootEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-invalid" + } + }, + "type": "object", + "required": [ + "name" + ] + } + }, + "type": "object", + "required": [ + "currentEnvironment", + "pulumi", + "rootEnvironment" + ] + } + } + }, + "checkJson": { + "foo": "bar" + }, + "evalDiags": [ + { + "Severity": 1, + "Summary": "expected boolean, got object", + "Detail": "", + "Subject": { + "Filename": "schema-top-level-invalid", + "Start": { + "Line": 2, + "Column": 3, + "Byte": 10 + }, + "End": { + "Line": 2, + "Column": 24, + "Byte": 31 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "schema" + }, + { + "Severity": 1, + "Summary": "at least one subschema must match", + "Detail": "", + "Subject": { + "Filename": "schema-top-level-invalid", + "Start": { + "Line": 2, + "Column": 3, + "Byte": 10 + }, + "End": { + "Line": 2, + "Column": 24, + "Byte": 31 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "schema" + }, + { + "Severity": 1, + "Summary": "expected one of [\"string\",\"number\",\"boolean\",\"array\",\"object\",\"null\"]", + "Detail": "", + "Subject": { + "Filename": "schema-top-level-invalid", + "Start": { + "Line": 2, + "Column": 9, + "Byte": 16 + }, + "End": { + "Line": 2, + "Column": 24, + "Byte": 31 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "schema.type" + } + ], + "eval": { + "exprs": { + "foo": { + "range": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 4, + "column": 8, + "byte": 47 + }, + "end": { + "line": 4, + "column": 11, + "byte": 50 + } + }, + "schema": { + "type": "string", + "const": "bar" + }, + "literal": "bar" + } + }, + "properties": { + "foo": { + "value": "bar", + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 4, + "column": 8, + "byte": 47 + }, + "end": { + "line": 4, + "column": 11, + "byte": 50 + } + } + } + } + }, + "schema": { + "properties": { + "foo": { + "type": "string", + "const": "bar" + } + }, + "type": "object", + "required": [ + "foo" + ] + }, + "executionContext": { + "properties": { + "currentEnvironment": { + "value": { + "name": { + "value": "schema-top-level-invalid", + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "pulumi": { + "value": { + "user": { + "value": { + "id": { + "value": "USER_123", + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "rootEnvironment": { + "value": { + "name": { + "value": "schema-top-level-invalid", + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-invalid", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "schema": { + "properties": { + "currentEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-invalid" + } + }, + "type": "object", + "required": [ + "name" + ] + }, + "pulumi": { + "properties": { + "user": { + "properties": { + "id": { + "type": "string", + "const": "USER_123" + } + }, + "type": "object", + "required": [ + "id" + ] + } + }, + "type": "object", + "required": [ + "user" + ] + }, + "rootEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-invalid" + } + }, + "type": "object", + "required": [ + "name" + ] + } + }, + "type": "object", + "required": [ + "currentEnvironment", + "pulumi", + "rootEnvironment" + ] + } + } + }, + "evalJsonRedacted": { + "foo": "bar" + }, + "evalJSONRevealed": { + "foo": "bar" + } +} diff --git a/eval/testdata/eval/schema-top-level-with-unknowns/env.yaml b/eval/testdata/eval/schema-top-level-with-unknowns/env.yaml new file mode 100644 index 00000000..1fc9ceb4 --- /dev/null +++ b/eval/testdata/eval/schema-top-level-with-unknowns/env.yaml @@ -0,0 +1,10 @@ +schema: + fn::open::test: + type: object + properties: + foo: + type: string + required: + - foo +values: + foo: bar diff --git a/eval/testdata/eval/schema-top-level-with-unknowns/expected.json b/eval/testdata/eval/schema-top-level-with-unknowns/expected.json new file mode 100644 index 00000000..3f3dd3c3 --- /dev/null +++ b/eval/testdata/eval/schema-top-level-with-unknowns/expected.json @@ -0,0 +1,524 @@ +{ + "checkDiags": [ + { + "Severity": 1, + "Summary": "schema must not contain unknowns", + "Detail": "", + "Subject": { + "Filename": "schema-top-level-with-unknowns", + "Start": { + "Line": 2, + "Column": 3, + "Byte": 10 + }, + "End": { + "Line": 8, + "Column": 12, + "Byte": 116 + } + }, + "Context": null, + "Expression": null, + "EvalContext": null, + "Extra": null, + "Path": "schema" + } + ], + "check": { + "exprs": { + "foo": { + "range": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 10, + "column": 8, + "byte": 132 + }, + "end": { + "line": 10, + "column": 11, + "byte": 135 + } + }, + "schema": { + "type": "string", + "const": "bar" + }, + "literal": "bar" + } + }, + "properties": { + "foo": { + "value": "bar", + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 10, + "column": 8, + "byte": 132 + }, + "end": { + "line": 10, + "column": 11, + "byte": 135 + } + } + } + } + }, + "schema": { + "properties": { + "foo": { + "type": "string", + "const": "bar" + } + }, + "type": "object", + "required": [ + "foo" + ] + }, + "executionContext": { + "properties": { + "currentEnvironment": { + "value": { + "name": { + "value": "schema-top-level-with-unknowns", + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "pulumi": { + "value": { + "user": { + "value": { + "id": { + "value": "USER_123", + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "rootEnvironment": { + "value": { + "name": { + "value": "schema-top-level-with-unknowns", + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "schema": { + "properties": { + "currentEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-with-unknowns" + } + }, + "type": "object", + "required": [ + "name" + ] + }, + "pulumi": { + "properties": { + "user": { + "properties": { + "id": { + "type": "string", + "const": "USER_123" + } + }, + "type": "object", + "required": [ + "id" + ] + } + }, + "type": "object", + "required": [ + "user" + ] + }, + "rootEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-with-unknowns" + } + }, + "type": "object", + "required": [ + "name" + ] + } + }, + "type": "object", + "required": [ + "currentEnvironment", + "pulumi", + "rootEnvironment" + ] + } + } + }, + "checkJson": { + "foo": "bar" + }, + "eval": { + "exprs": { + "foo": { + "range": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 10, + "column": 8, + "byte": 132 + }, + "end": { + "line": 10, + "column": 11, + "byte": 135 + } + }, + "schema": { + "type": "string", + "const": "bar" + }, + "literal": "bar" + } + }, + "properties": { + "foo": { + "value": "bar", + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 10, + "column": 8, + "byte": 132 + }, + "end": { + "line": 10, + "column": 11, + "byte": 135 + } + } + } + } + }, + "schema": { + "properties": { + "foo": { + "type": "string", + "const": "bar" + } + }, + "type": "object", + "required": [ + "foo" + ] + }, + "executionContext": { + "properties": { + "currentEnvironment": { + "value": { + "name": { + "value": "schema-top-level-with-unknowns", + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "pulumi": { + "value": { + "user": { + "value": { + "id": { + "value": "USER_123", + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "rootEnvironment": { + "value": { + "name": { + "value": "schema-top-level-with-unknowns", + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level-with-unknowns", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "schema": { + "properties": { + "currentEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-with-unknowns" + } + }, + "type": "object", + "required": [ + "name" + ] + }, + "pulumi": { + "properties": { + "user": { + "properties": { + "id": { + "type": "string", + "const": "USER_123" + } + }, + "type": "object", + "required": [ + "id" + ] + } + }, + "type": "object", + "required": [ + "user" + ] + }, + "rootEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level-with-unknowns" + } + }, + "type": "object", + "required": [ + "name" + ] + } + }, + "type": "object", + "required": [ + "currentEnvironment", + "pulumi", + "rootEnvironment" + ] + } + } + }, + "evalJsonRedacted": { + "foo": "bar" + }, + "evalJSONRevealed": { + "foo": "bar" + } +} diff --git a/eval/testdata/eval/schema-top-level/env.yaml b/eval/testdata/eval/schema-top-level/env.yaml new file mode 100644 index 00000000..8d2dff3d --- /dev/null +++ b/eval/testdata/eval/schema-top-level/env.yaml @@ -0,0 +1,9 @@ +schema: + type: object + properties: + foo: + type: string + required: + - foo +values: + foo: bar diff --git a/eval/testdata/eval/schema-top-level/expected.json b/eval/testdata/eval/schema-top-level/expected.json new file mode 100644 index 00000000..f4ed1d7a --- /dev/null +++ b/eval/testdata/eval/schema-top-level/expected.json @@ -0,0 +1,499 @@ +{ + "check": { + "exprs": { + "foo": { + "range": { + "environment": "schema-top-level", + "begin": { + "line": 9, + "column": 8, + "byte": 102 + }, + "end": { + "line": 9, + "column": 11, + "byte": 105 + } + }, + "schema": { + "type": "string", + "const": "bar" + }, + "literal": "bar" + } + }, + "properties": { + "foo": { + "value": "bar", + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 9, + "column": 8, + "byte": 102 + }, + "end": { + "line": 9, + "column": 11, + "byte": 105 + } + } + } + } + }, + "schema": { + "properties": { + "foo": { + "type": "string", + "const": "bar" + } + }, + "type": "object", + "required": [ + "foo" + ] + }, + "executionContext": { + "properties": { + "currentEnvironment": { + "value": { + "name": { + "value": "schema-top-level", + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "pulumi": { + "value": { + "user": { + "value": { + "id": { + "value": "USER_123", + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "rootEnvironment": { + "value": { + "name": { + "value": "schema-top-level", + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "schema": { + "properties": { + "currentEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level" + } + }, + "type": "object", + "required": [ + "name" + ] + }, + "pulumi": { + "properties": { + "user": { + "properties": { + "id": { + "type": "string", + "const": "USER_123" + } + }, + "type": "object", + "required": [ + "id" + ] + } + }, + "type": "object", + "required": [ + "user" + ] + }, + "rootEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level" + } + }, + "type": "object", + "required": [ + "name" + ] + } + }, + "type": "object", + "required": [ + "currentEnvironment", + "pulumi", + "rootEnvironment" + ] + } + } + }, + "checkJson": { + "foo": "bar" + }, + "eval": { + "exprs": { + "foo": { + "range": { + "environment": "schema-top-level", + "begin": { + "line": 9, + "column": 8, + "byte": 102 + }, + "end": { + "line": 9, + "column": 11, + "byte": 105 + } + }, + "schema": { + "type": "string", + "const": "bar" + }, + "literal": "bar" + } + }, + "properties": { + "foo": { + "value": "bar", + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 9, + "column": 8, + "byte": 102 + }, + "end": { + "line": 9, + "column": 11, + "byte": 105 + } + } + } + } + }, + "schema": { + "properties": { + "foo": { + "type": "string", + "const": "bar" + } + }, + "type": "object", + "required": [ + "foo" + ] + }, + "executionContext": { + "properties": { + "currentEnvironment": { + "value": { + "name": { + "value": "schema-top-level", + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "pulumi": { + "value": { + "user": { + "value": { + "id": { + "value": "USER_123", + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + }, + "rootEnvironment": { + "value": { + "name": { + "value": "schema-top-level", + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "trace": { + "def": { + "environment": "schema-top-level", + "begin": { + "line": 0, + "column": 0, + "byte": 0 + }, + "end": { + "line": 0, + "column": 0, + "byte": 0 + } + } + } + } + }, + "schema": { + "properties": { + "currentEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level" + } + }, + "type": "object", + "required": [ + "name" + ] + }, + "pulumi": { + "properties": { + "user": { + "properties": { + "id": { + "type": "string", + "const": "USER_123" + } + }, + "type": "object", + "required": [ + "id" + ] + } + }, + "type": "object", + "required": [ + "user" + ] + }, + "rootEnvironment": { + "properties": { + "name": { + "type": "string", + "const": "schema-top-level" + } + }, + "type": "object", + "required": [ + "name" + ] + } + }, + "type": "object", + "required": [ + "currentEnvironment", + "pulumi", + "rootEnvironment" + ] + } + } + }, + "evalJsonRedacted": { + "foo": "bar" + }, + "evalJSONRevealed": { + "foo": "bar" + } +}