Esempio n. 1
0
func validateGetAttAttributeID(builtin parse.IntrinsicFunction, resourceID, attributeID interface{}, ctx PropertyContext) reporting.Reports {
	resource := ctx.Template().Resources[resourceID.(string)]
	definition := ctx.Definitions().Lookup(resource.Type)

	switch t := attributeID.(type) {
	case string:
		if attribute, ok := definition.Attributes[t]; ok {
			targetType := attribute.Type
			switch targetType.CoercibleTo(ctx.Property().Type) {
			case CoercionNever:
				return reporting.Reports{reporting.NewFailure(ctx, "GetAtt value of %s.%s is %s but is being assigned to a %s property", resourceID, t, targetType.Describe(), ctx.Property().Type.Describe())}
			case CoercionBegrudgingly:
				return reporting.Reports{reporting.NewWarning(ctx, "GetAtt value of %s.%s is %s but is being dangerously coerced to a %s property", resourceID, t, targetType.Describe(), ctx.Property().Type.Describe())}
			}

			return nil
		}
	case parse.IntrinsicFunction:
		getAttAttributeNameType := Schema{Type: ValueString}
		_, errs := ValidateIntrinsicFunctions(t, NewPropertyContext(ctx, getAttAttributeNameType), SupportedFunctions{
			parse.FnRef: true,
		})
		return errs
	}

	return reporting.Reports{reporting.NewFailure(ctx, "%s is not an attribute of %s", attributeID, resource.Type)}
}
Esempio n. 2
0
func coerce(from, to PropertyType, ctx PropertyContext) reporting.Reports {
	switch from.CoercibleTo(to) {
	case CoercionNever:
		return reporting.Reports{
			reporting.NewFailure(ctx, "Value of %s used in %s property", from.Describe(), to.Describe()),
		}
	case CoercionBegrudgingly:
		return reporting.Reports{
			reporting.NewWarning(ctx, "%s is dangerously coerced to a %s property", from.Describe(), to.Describe()),
		}
	case CoercionAlways:
		return nil
	}

	return nil
}
Esempio n. 3
0
func (p Properties) Validate(ctx ResourceContext) reporting.Reports {
	failures := make(reporting.Reports, 0, len(p)*2)
	visited := make(map[string]bool)

	self := ctx.CurrentResource()

	for key, schema := range p {
		visited[key] = true
		value, _ := self.PropertyValue(key)
		keyCtx := ResourceContextAdd(ctx, key)

		// Validate conflicting properties
		if value != nil && schema.Conflicts != nil && schema.Conflicts.Pass(self) {
			failures = append(failures, reporting.NewFailure(keyCtx, "Conflict: %s", schema.Conflicts.Describe(self)))
		}

		// Validate Required
		if value == nil && schema.Required != nil && schema.Required.Pass(self) {
			failures = append(failures, reporting.NewFailure(keyCtx, "%s is required because %s", key, schema.Required.Describe(self)))
		}

		// Validate Deprecated
		if value != nil && schema.Deprecated != nil {
			failures = append(failures, reporting.NewWarning(keyCtx, schema.Deprecated.Describe()))
			continue
		}

		// assuming the above either failed and logged some failures, or passed and
		// we can safely skip over a nil property
		if value == nil {
			continue
		}

		if _, errs := schema.Validate(value, keyCtx); errs != nil {
			failures = append(failures, errs...)
		}
	}

	// Reject any properties we weren't expecting
	for _, key := range self.Properties() {
		if !visited[key] {
			failures = append(failures, reporting.NewFailure(ResourceContextAdd(ctx, key), "%s is not a property of %s", key, self.AwsType()))
		}
	}

	return reporting.Safe(failures)
}
Esempio n. 4
0
// validateMapWhereArrayShouldBe runs validations against a map which was found
// where an Array was expected; this is possibly valid, and could either be a
// function reference or some attempt at coercion.
func validateMapWhereArrayShouldBe(arrayType ArrayPropertyType, itemSchema Schema, value map[string]interface{}, ctx PropertyContext) (reporting.ValidateResult, reporting.Reports) {
	if ctx.Options()[OptionExperimentDisableObjectArrayCoercion] {
		return reporting.ValidateOK, reporting.Reports{reporting.NewFailure(ctx, "%s used instead of %s", arrayType.Unwrap().Describe(), arrayType.Describe())}
	}

	// CloudFormation appears to allow you to flatten a single item array
	// for array properties, e.g. X: [Y] can be specified as X: Y
	//
	// So in this case if we get a map here just validate it against the
	// schema for the item of the array and provide a warning.
	results := make(reporting.Reports, 0, 25)

	if _, errs := itemSchema.Validate(value, ctx); errs != nil {
		results = append(results, errs...)
	}

	results = append(results, reporting.NewWarning(ctx, "%s used instead of %s", arrayType.Unwrap().Describe(), arrayType.Describe()))

	return reporting.ValidateOK, reporting.Safe(results)
}
Esempio n. 5
0
func validateSelectIndex(builtin parse.IntrinsicFunction, index interface{}, array interface{}, ctx PropertyContext) reporting.Reports {
	if index == nil {
		return reporting.Reports{reporting.NewFailure(ctx, "Index cannot be null")}
	}

	switch t := index.(type) {
	case string:
		return reporting.Reports{reporting.NewWarning(ctx, "Wrong type for index %T (can't ensure validity of index)", index)}
	case float64:
		return validateIndexNumericalValue(t, array, ctx)
	case parse.IntrinsicFunction:
		indexType := Schema{Type: ValueNumber}
		_, errs := ValidateIntrinsicFunctions(t, NewPropertyContext(ctx, indexType), SupportedFunctions{
			parse.FnRef:       true,
			parse.FnFindInMap: true,
		})
		return errs
	}

	return reporting.Reports{reporting.NewFailure(ctx, "Invalid value for index %#v", index)}
}
Esempio n. 6
0
func validateRef(builtin parse.IntrinsicFunction, ctx PropertyContext) reporting.Reports {
	if errs := validateIntrinsicFunctionBasicCriteria(parse.FnRef, builtin, ctx); errs != nil {
		return errs
	}

	refValue := builtin.UnderlyingMap[string(parse.FnRef)]
	refString, ok := refValue.(string)
	if !ok || refString == "" {
		return reporting.Reports{reporting.NewFailure(ctx, "Invalid type for \"Ref\" key: %T", refValue)}
	}

	target := resolveTarget(refString, ctx.Definitions(), ctx.Template())
	if target == nil {
		return reporting.Reports{reporting.NewFailure(ctx, "Ref '%s' is not a resource, parameter, or pseudo-parameter", refString)}
	}

	targetType := target.TargetType()
	if targetType == nil {
		return reporting.Reports{reporting.NewFailure(ctx, "%s cannot be used in a Ref", refString)}
	}

	if refString == "AWS::NoValue" {
		// AWS::NoValue is a magic absent-value value so we don't do any type
		// assertions on it
		return nil
	}

	switch targetType.CoercibleTo(ctx.Property().Type) {
	case CoercionNever:
		return reporting.Reports{reporting.NewFailure(ctx, "Ref value of '%s' is %s but is being assigned to a %s property", refString, targetType.Describe(), ctx.Property().Type.Describe())}
	case CoercionBegrudgingly:
		return reporting.Reports{reporting.NewWarning(ctx, "Ref value of '%s' is %s but is being dangerously coerced to a %s property", refString, targetType.Describe(), ctx.Property().Type.Describe())}
	}

	return nil
}
Esempio n. 7
0
func (UnsupportedProperties) Validate(ctx ResourceContext) reporting.Reports {
	return reporting.Reports{
		reporting.NewWarning(ctx, "<unsupported> cfval does support validating %s resources yet", ctx.CurrentResource().AwsType()),
	}
}