Skip to content

Commit

Permalink
Merge pull request #35 from strongdm/apg/po-515-add-datetime
Browse files Browse the repository at this point in the history
Add the extension types, datetime and duration
  • Loading branch information
apg authored Sep 19, 2024
2 parents 3aaba14 + 125cddb commit d1f59f4
Show file tree
Hide file tree
Showing 23 changed files with 2,529 additions and 11 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ The Go implementation includes:

- the core authorizer
- JSON marshalling and unmarshalling
- all core and extended types
- all core and extended types (including [RFC 80](https://github.com/cedar-policy/rfcs/blob/main/text/0080-datetime-extension.md)'s datetime and duration)
- integration test suite

The Go implementation does not yet include:
Expand Down Expand Up @@ -133,6 +133,11 @@ While in development (0.x.y), each tagged release may contain breaking changes.

## Change log

### New features in 0.3.2

- An implementation of the `datetime` and `duration` extension types specified in [RFC 80](https://github.com/cedar-policy/rfcs/blob/main/text/0080-datetime-extension.md).
- Note: While these types have been accepted into the language, they have not yet been formally analyzed in the [specification](https://github.com/cedar-policy/cedar-spec/).

### New features in 0.3.1

- General performance improvements to the evaluator
Expand Down
62 changes: 62 additions & 0 deletions authorize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,68 @@ func TestIsAuthorized(t *testing.T) {
Want: false,
DiagErr: 1,
},
{
Name: "permit-when-datetime",
Policy: `permit(principal,action,resource) when {
datetime("1970-01-01T09:08:07Z") < (datetime("1970-02-01")) &&
datetime("1970-01-01T09:08:07Z") <= (datetime("1970-02-01")) &&
datetime("1970-01-01T09:08:07Z") > (datetime("1970-01-01")) &&
datetime("1970-01-01T09:08:07Z") >= (datetime("1970-01-01")) &&
datetime("1970-01-01T09:08:07Z").toDate() == datetime("1970-01-01")};`,
Entities: types.Entities{},
Principal: cuzco,
Action: dropTable,
Resource: types.NewEntityUID("table", "whatever"),
Context: types.Record{},
Want: true,
DiagErr: 0,
},
{
Name: "permit-when-datetime-fun-wrong-arity",
Policy: `permit(principal,action,resource) when { datetime("1970-01-01", "UTC") };`,
Entities: types.Entities{},
Principal: cuzco,
Action: dropTable,
Resource: types.NewEntityUID("table", "whatever"),
Context: types.Record{},
Want: false,
DiagErr: 1,
},
{
Name: "permit-when-duration",
Policy: `permit(principal,action,resource) when {
duration("9h8m") < (duration("10h")) &&
duration("9h8m") <= (duration("10h")) &&
duration("9h8m") > (duration("7h")) &&
duration("9h8m") >= (duration("7h")) &&
duration("1ms").toMilliseconds() == 1 &&
duration("1s").toSeconds() == 1 &&
duration("1m").toMinutes() == 1 &&
duration("1h").toHours() == 1 &&
duration("1d").toDays() == 1 &&
datetime("1970-01-01").toTime() == duration("0ms") &&
datetime("1970-01-01").offset(duration("1ms")).toTime() == duration("1ms") &&
datetime("1970-01-01T00:00:00.001Z").durationSince(datetime("1970-01-01")) == duration("1ms")};`,

Entities: types.Entities{},
Principal: cuzco,
Action: dropTable,
Resource: types.NewEntityUID("table", "whatever"),
Context: types.Record{},
Want: true,
DiagErr: 0,
},
{
Name: "permit-when-duration-fun-wrong-arity",
Policy: `permit(principal,action,resource) when { duration("1h", "huh?") };`,
Entities: types.Entities{},
Principal: cuzco,
Action: dropTable,
Resource: types.NewEntityUID("table", "whatever"),
Context: types.Record{},
Want: false,
DiagErr: 1,
},
{
Name: "permit-when-ip",
Policy: `permit(principal,action,resource) when {
Expand Down
7 changes: 7 additions & 0 deletions internal/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ const (
Context = "context"
)

const (
MillisPerSecond = int64(1000)
MillisPerMinute = MillisPerSecond * 60
MillisPerHour = MillisPerMinute * 60
MillisPerDay = MillisPerHour * 24
)

func init() {
_ = 42
}
17 changes: 17 additions & 0 deletions internal/eval/comparable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package eval

import "github.com/cedar-policy/cedar-go/types"

// ComparableValue provides the interface that must be implemented to
// support operator overloading of <, <=, >, and >=
type ComparableValue interface {
types.Value

// LessThan returns true if the lhs is less than the rhs, and an
// error if the rhs is not comparable to the lhs
LessThan(types.Value) (bool, error)

// LessThan returns true if the lhs is less than or equal to the
// rhs, and an error if the rhs is not comparable to the lhs
LessThanOrEqual(types.Value) (bool, error)
}
8 changes: 4 additions & 4 deletions internal/eval/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ func toEval(n ast.IsNode) Evaler {
case ast.NodeTypeNotEquals:
return newNotEqualEval(toEval(v.Left), toEval(v.Right))
case ast.NodeTypeGreaterThan:
return newLongGreaterThanEval(toEval(v.Left), toEval(v.Right))
return newComparableValueGreaterThanEval(toEval(v.Left), toEval(v.Right))
case ast.NodeTypeGreaterThanOrEqual:
return newLongGreaterThanOrEqualEval(toEval(v.Left), toEval(v.Right))
return newComparableValueGreaterThanOrEqualEval(toEval(v.Left), toEval(v.Right))
case ast.NodeTypeLessThan:
return newLongLessThanEval(toEval(v.Left), toEval(v.Right))
return newComparableValueLessThanEval(toEval(v.Left), toEval(v.Right))
case ast.NodeTypeLessThanOrEqual:
return newLongLessThanOrEqualEval(toEval(v.Left), toEval(v.Right))
return newComparableValueLessThanOrEqualEval(toEval(v.Left), toEval(v.Right))
case ast.NodeTypeSub:
return newSubtractEval(toEval(v.Left), toEval(v.Right))
case ast.NodeTypeAdd:
Expand Down
68 changes: 68 additions & 0 deletions internal/eval/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package eval
import (
"net/netip"
"testing"
"time"

"github.com/cedar-policy/cedar-go/internal/ast"
"github.com/cedar-policy/cedar-go/internal/testutil"
Expand Down Expand Up @@ -209,6 +210,73 @@ func TestToEval(t *testing.T) {
types.UnsafeDecimal(42.42),
testutil.OK,
},
{
"datetime",
ast.ExtensionCall("datetime", ast.String("1970-01-01T00:00:00.001Z")),
types.FromStdTime(time.UnixMilli(1)),
testutil.OK,
},
{
"duration",
ast.ExtensionCall("duration", ast.String("1ms")),
types.FromStdDuration(1 * time.Millisecond),
testutil.OK,
},
{
"toDate",
ast.ExtensionCall("toDate", ast.Value(types.FromStdTime(time.UnixMilli(1)))),
types.FromStdTime(time.UnixMilli(0)),
testutil.OK,
},
{
"toTime",
ast.ExtensionCall("toTime", ast.Value(types.FromStdTime(time.UnixMilli(1)))),
types.FromStdDuration(1 * time.Millisecond),
testutil.OK,
},
{
"toDays",
ast.ExtensionCall("toDays", ast.Value(types.FromStdDuration(time.Duration(0)))),
types.Long(0),
testutil.OK,
},
{
"toHours",
ast.ExtensionCall("toHours", ast.Value(types.FromStdDuration(time.Duration(0)))),
types.Long(0),
testutil.OK,
},
{
"toMinutes",
ast.ExtensionCall("toMinutes", ast.Value(types.FromStdDuration(time.Duration(0)))),
types.Long(0),
testutil.OK,
},
{
"toSeconds",
ast.ExtensionCall("toSeconds", ast.Value(types.FromStdDuration(time.Duration(0)))),
types.Long(0),
testutil.OK,
},
{
"toMilliseconds",
ast.ExtensionCall("toMilliseconds", ast.Value(types.FromStdDuration(time.Duration(0)))),
types.Long(0),
testutil.OK,
},
{
"offset",
ast.ExtensionCall("offset", ast.Value(types.FromStdTime(time.UnixMilli(0))), ast.Value(types.FromStdDuration(1*time.Millisecond))),
types.FromStdTime(time.UnixMilli(1)),
testutil.OK,
},
{
"durationSince",
ast.ExtensionCall("durationSince", ast.Value(types.FromStdTime(time.UnixMilli(1))), ast.Value(types.FromStdTime(time.UnixMilli(1)))),
types.FromStdDuration(time.Duration(0)),
testutil.OK,
},

{
"lessThan",
ast.ExtensionCall("lessThan", ast.Value(types.UnsafeDecimal(42.0)), ast.Value(types.UnsafeDecimal(43))),
Expand Down
Loading

0 comments on commit d1f59f4

Please sign in to comment.