mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-12-15 08:05:19 -05:00
cli: state file validation (#2523)
* re-use `ReadFromFile` in `CreateOrRead` Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * [wip]: add constraints Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * [wip] error formatting Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * wip Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * formatted error messages Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * state file validation Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * linter fixes Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * allow overriding the constraints Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * dont validate on read Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add pre-create constraints Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * [wip] Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * finish pre-init validation test Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * finish post-init validation Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * use state file validation in CLI Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix apply tests Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * Update internal/validation/errors.go Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com> * use transformator for tests * tidy * use empty check directly Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * Update cli/internal/state/state.go Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com> * Update cli/internal/state/state.go Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com> * Update cli/internal/state/state.go Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com> * Update cli/internal/state/state.go Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com> * conditional validation per CSP Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * tidy Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix rebase Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add default case Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * validate state-file as last input Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> --------- Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com>
This commit is contained in:
parent
eaec73cca4
commit
744a605602
21 changed files with 1779 additions and 247 deletions
|
|
@ -13,42 +13,86 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// Error is returned when a document is not valid.
|
||||
type Error struct {
|
||||
Path string
|
||||
Err error
|
||||
// TreeError is returned when a document is not valid.
|
||||
// It contains the path to the field that failed validation, the error
|
||||
// that occurred, as well as a list of child errors, as one constraint
|
||||
// can embed multiple other constraints, e.g. in an OR.
|
||||
type TreeError struct {
|
||||
path string
|
||||
err error
|
||||
children []*TreeError
|
||||
}
|
||||
|
||||
// NewErrorTree creates a new error tree from the given error.
|
||||
func NewErrorTree(err error) *TreeError {
|
||||
return &TreeError{
|
||||
err: err,
|
||||
children: []*TreeError{},
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
newError creates a new validation Error.
|
||||
newTraceError creates a new validation error, traced to a field.
|
||||
|
||||
To find the path to the exported field that failed validation, it traverses "doc"
|
||||
recursively until it finds a field in "doc" that matches the reference to "field".
|
||||
*/
|
||||
func newError(doc, field referenceableValue, errMsg error) *Error {
|
||||
func newTraceError(doc, field referenceableValue, errMsg error) *TreeError {
|
||||
// traverse the top level struct (i.e. the "haystack") until addr (i.e. the "needle") is found
|
||||
path, err := traverse(doc, field, newPathBuilder(doc._type.Name()))
|
||||
if err != nil {
|
||||
return &Error{
|
||||
Path: "unknown",
|
||||
Err: fmt.Errorf("cannot find path to field: %w. original error: %w", err, errMsg),
|
||||
return &TreeError{
|
||||
path: "unknown",
|
||||
err: fmt.Errorf("cannot find path to field: %w. original error: %w", err, errMsg),
|
||||
}
|
||||
}
|
||||
|
||||
return &Error{
|
||||
Path: path,
|
||||
Err: errMsg,
|
||||
return &TreeError{
|
||||
path: path,
|
||||
err: errMsg,
|
||||
children: []*TreeError{},
|
||||
}
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("validating %s: %s", e.Path, e.Err)
|
||||
func (e *TreeError) Error() string {
|
||||
return e.format(0)
|
||||
}
|
||||
|
||||
// Unwrap implements the error interface.
|
||||
func (e *Error) Unwrap() error {
|
||||
return e.Err
|
||||
func (e *TreeError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
// format formats the error tree and all of its children.
|
||||
func (e *TreeError) format(indent int) string {
|
||||
var sb strings.Builder
|
||||
if e.path != "" {
|
||||
sb.WriteString(fmt.Sprintf(
|
||||
"%svalidating %s: %s",
|
||||
strings.Repeat(" ", indent),
|
||||
e.path,
|
||||
e.err,
|
||||
))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf(
|
||||
"%s%s",
|
||||
strings.Repeat(" ", indent),
|
||||
e.err,
|
||||
))
|
||||
}
|
||||
for _, child := range e.children {
|
||||
sb.WriteString(fmt.Sprintf(
|
||||
"\n%s",
|
||||
child.format(indent+1),
|
||||
))
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// appendChild adds the given child error to the tree.
|
||||
func (e *TreeError) appendChild(child *TreeError) {
|
||||
e.children = append(e.children, child)
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -238,9 +282,13 @@ func newPathBuilder(topLevelDoc string) pathBuilder {
|
|||
func (p pathBuilder) appendStructField(field reflect.StructField) pathBuilder {
|
||||
switch {
|
||||
case field.Tag.Get("json") != "":
|
||||
p.buf = append(p.buf, fmt.Sprintf(".%s", field.Tag.Get("json")))
|
||||
// cut off omitempty or other options
|
||||
jsonTagName, _, _ := strings.Cut(field.Tag.Get("json"), ",")
|
||||
p.buf = append(p.buf, fmt.Sprintf(".%s", jsonTagName))
|
||||
case field.Tag.Get("yaml") != "":
|
||||
p.buf = append(p.buf, fmt.Sprintf(".%s", field.Tag.Get("yaml")))
|
||||
// cut off omitempty or other options
|
||||
yamlTagName, _, _ := strings.Cut(field.Tag.Get("yaml"), ",")
|
||||
p.buf = append(p.buf, fmt.Sprintf(".%s", yamlTagName))
|
||||
default:
|
||||
p.buf = append(p.buf, fmt.Sprintf(".%s", field.Name))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue