Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export PATH := $(BIN):$(PATH)
export GOBIN := $(abspath $(BIN))
# Set to use a different Python interpreter. For example, `PYTHON=python make test`.
PYTHON ?= python3
CONFORMANCE_ARGS ?= --strict --expected_failures=tests/conformance/nonconforming.yaml --timeout 10s
CONFORMANCE_ARGS ?= --strict --strict_message --expected_failures=tests/conformance/nonconforming.yaml --timeout 10s
ADD_LICENSE_HEADER := $(BIN)/license-header \
--license-type apache \
--copyright-holder "Buf Technologies, Inc." \
Expand Down
16 changes: 15 additions & 1 deletion protovalidate/internal/string_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,16 +146,30 @@ def format_string(self, arg: celtypes.Value) -> celpy.Result:
if isinstance(arg, celtypes.StringType):
return arg
if isinstance(arg, celtypes.BytesType):
return celtypes.StringType(arg.hex())
return celtypes.StringType(arg)
if isinstance(arg, celtypes.ListType):
return self.format_list(arg)
if isinstance(arg, celtypes.BoolType):
# True -> true
return celtypes.StringType(str(arg).lower())
if isinstance(arg, celtypes.DoubleType):
return celtypes.StringType(f"{arg:.0f}")
if isinstance(arg, celtypes.TimestampType):
base = arg.isoformat()
if arg.getMilliseconds() != 0:
base = arg.isoformat(timespec="milliseconds")
return celtypes.StringType(base.removesuffix("+00:00") + "Z")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just for context, most protovalidate rules are defined in CEL using the %s verb (in fact, I don't think I've seen another verb used). format_string handles that verb, so we need to add some additional handling here.

return celtypes.StringType(arg)

def format_value(self, arg: celtypes.Value) -> celpy.Result:
if isinstance(arg, (celtypes.StringType, str)):
return celtypes.StringType(quote(arg))
if isinstance(arg, celtypes.UintType):
return celtypes.StringType(arg)
if isinstance(arg, celtypes.DurationType):
return celtypes.StringType(f'duration("{arg.seconds + (arg.microseconds // 1e6):.0f}s")')
if isinstance(arg, celtypes.DoubleType):
return celtypes.StringType(f"{arg:f}")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format_value handles lists, where we add more context to what type of value is in the list (think repr instead of str in Python). hence the additional context.

return self.format_string(arg)

def format_list(self, arg: celtypes.ListType) -> celpy.Result:
Expand Down
8 changes: 7 additions & 1 deletion tests/conformance/nonconforming.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# celpy doesn't support nano seconds
# ref: https://github.com/cloud-custodian/cel-python/issues/43
standard_constraints/well_known_types/duration:
- gte_lte/invalid/above
- lte/invalid
- not in/valid
- gte/invalid
- gt/invalid
- in/invalid
- "not in/valid"
standard_constraints/well_known_types/timestamp:
- gte_lte/invalid/above
- lte/invalid
standard_constraints/repeated:
- duration/gte/invalid
Loading