Validating a user provided date with sentinel

I’m trying to write a sentinel policy that will read a date provided in structured data. After reading the docs a few times I’m still unclear what the best approach is. I basically need to have the policy fail if the date is within two weeks. Using the sentinel simulator I’m failing to mock or otherwise provide a date as part of the test configuration.

The test policy I’m using is this.

import "time"

time_now = time.now
print("   Time Now :",time_now.rfc3339)

time_loaded = time.load("3030-08-28T00:00:00Z")
print("Time Loaded :",time_loaded.rfc3339)

if time_now.rfc3339 matches time_loaded.rfc3339 {
    matching_times = true
} else {
    matching_times = false
}

main = rule {
  matching_times
}

Setting the time as a global in test file like so…

{
    "global": {
        "time": {
            "now": {
                "day": 28,
                "hour": 0,
                "minute": 0,
                "month": 8,
                "month_name": "August",
                "rfc3339": "3030-08-28T00:00:00Z",
                "second": 0,
                "unix": 33471014400,
                "unix_nano": -3422473747419103232,
                "weekday": 6,
                "weekday_name": "Saturday",
                "year": 3030,
                "zone": 0,
                "zone_string": "+00:00"
            }
        },
        "test": {
            "main": true
        }
    }
}

This test fails and the date is not being passed to time.now

FAIL - time_mock.sentinel
  FAIL - test/time_mock/global_time.json
    expected "main" to be true, got: false

    logs:
         Time Now : 2019-10-29T21:13:08.563419362Z
      Time Loaded : 3030-08-28T00:00:00Z

    trace:
      FALSE - time_mock.sentinel:16:1 - Rule "main"

Here is the test config file for doing a mock date.

{
    "mock": {
        "time": {
            "now": {
                "day": 28,
                "hour": 0,
                "minute": 0,
                "month": 8,
                "month_name": "August",
                "rfc3339": "3030-08-28T00:00:00Z",
                "second": 0,
                "unix": 33471014400,
                "unix_nano": -3422473747419103232,
                "weekday": 6,
                "weekday_name": "Saturday",
                "year": 3030,
                "zone": 0,
                "zone_string": "+00:00"
            }
        }
    },
    "test": {
        "main": true
    }
}

On the test I configured to mock the date it’s failing strangely. The time is correct but the time.load() is failing for some reason.

  ERROR - test/time_mock/mock_time.json
    Error: time_mock.sentinel:7:15: key "load" doesn't support function calls

    logs:
         Time Now : 3030-08-28T00:00:00Z

    trace:

The code is stored in this repo https://github.com/trodemaster/sentinel-sandbox Looking for suggestions on how to create the policy and test it with dates included in the config file.

Thanks,
Blake

Hi Blake,

If my understanding is correct, you have a requirement for a policy to fail prior to a given date after which time all evaluations for the given policy should complete successfully? Let me know if I have missed anything

Sentinel Policy Definition

Having reviewed your requirements I believe that the following should get you the desired outcome:

import "time"

validate_after = rule {
    time.now.after(time.load("2018-11-30T00:00:00Z"))
}

main = rule {
  (validate_after)
}

Testing

Regarding the error that you are getting when providing mock data. I am getting the same behaviour on my end when I define the following:

{
    "mock": {
        "time": {
            "now": {
                "day": 30, 
                "hour": 0, 
                "minute": 0, 
                "month": 11, 
                "month_name": "November", 
                "rfc3339": "2018-11-30T00:00:00Z", 
                "second": 0, 
                "unix": 1543536000, 
                "unix_nano": 1543536000000000000, 
                "weekday": 5, 
                "weekday_name": "Friday", 
                "year": 2018, 
                "zone": 0, 
                "zone_string": "+00:00"
            }  
        }
    },
    "test": {
        "main": true,
        "validate_after": true
    }
}

Leave this with me and I will work on providing a working example.

1 Like

Hi Blake.

After a bit of trial and error and a lot of research, I now have a working example for you.

One of the interesting challenges in your use case was the mocking of the time.load() which can only be achieved by mocking the data using a mock-time.sentinel file which is documented in the following link.

My final configuration is as follows. If you have any questions, please feel free to post them here and I will respond accordingly. Hope this helps.

Folder Tree

➜  demo tree         
.
├── test
│   └── validate
│       ├── failure.json
│       └── success.json
├── testdata
│   └── mock-time.sentinel
└── validate.sentinel

3 directories, 4 files

validate.sentinel

import "time"

if trigger_failure {
  date_time = "2017-11-30T00:00:00Z"
} else {
  date_time = "2018-11-30T00:00:00Z"
}

validate_after = rule {
    time.now.after(time.load(date_time))
}

main = rule {
  (validate_after)
}

mock-time.sentinel

_validate = false

load = func(t) {
  if t is "2018-11-30T00:00:00Z" {
    _validate = true
  }
  return true
}

now = {
    "after": func(t) {
        return _validate
    },
}

success.json

{
    "global": {
        "trigger_failure": false
    },
    "mock": {
        "time": "../../testdata/mock-time.sentinel"
    },
    "test": {
        "main": true,
        "validate_after": true
    }
}

failure.json

{
    "global": {
        "trigger_failure": true
    },
    "mock": {
        "time": "../../testdata/mock-time.sentinel"
    },
    "test": {
        "main": false,
        "validate_after": false
    }
}

Ok so using sentinel code to mock the date seems reasonable. The mock-time.sentinel doesn’t appear to be providing a timespace that the main policy can act on. To clarify the end goal the main policy will receive a date from request.data.data and then load it as a timespace. Then add two weeks and compare the current time (mocked). The idea being it would fail if the provided date is within two weeks.

Hi @trodemaster. Is this an example of request.data.data that you will be evaluating?

{
    "cred_description": "Funky Service from external vendor",
    "Owner": "Blake Garner",
    "Expiration": "2020-08-16 09:52:05",
    "TeamName":   "IS",
    "Contact": "username@adobe.com",
    "AccountID": "adobeitcfunkyservice223",
    "AccountKEY": "a340b6a946bbdw4515r884dy12b8a484b518",
    "AccountKEYbase64": false
  }

Yes,
I have refined it a bit so that the “Expiration” is in the needed format. Here is what I put together for the sentinel test.

"request": {
    "data": {
        "data": {
            "token_description" : "Cool service owned by my team",
            "token_owner" : "person@company.com",
            "token_expiration" : "2019-08-28T00:00:00+00:00",
            "token_company_service_id" : "123467",
            "token_technical_contact" : "team@company.com",
            "token_id" : "funkyservice223",
            "token_secret" : "a340b6a946bbdw4515r884dy12b8a484b518",
            "token_secret_base64" : false,
            "token_mission_critical" : true
        }
    }
}

Thanks again for looking at this!

Okay, so just so I am clear, you want to do something like this?

Pseudo Code Example

current_date = time.now()
expiration_date = time.load(request.data.data.token_expiration)
future_date = expiration_date.add(1209600000000000)

if expiration_date.after(current_date) == expiration_date.before(future_date)  {
     return true
} else {
    return false
}

Note:
time.now() would be mock data returned from mock-time.sentinel.

Yes that’s the approach I’m looking at.