Skip to content

Commit

Permalink
init release
Browse files Browse the repository at this point in the history
  • Loading branch information
ahsayde authored and ahsayde committed Sep 6, 2022
0 parents commit 7050528
Show file tree
Hide file tree
Showing 25 changed files with 2,946 additions and 0 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: main

on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
build:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: 1.18
- name: Run Tests
run: make test
- uses: codecov/codecov-action@v2
with:
token: ${{ secrets.CODECOV_TOKEN }}
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
*.exe
*.exe~
*.dll
*.so
*.dylib
policies-service
__debug_bin
*.test
*.out
bin/
coverage.txt
coverage.html
input.yaml
rule.yaml
rule.json
.vscode
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
build:
go build

test:
go test -v -race -cover -covermode=atomic -coverprofile=coverage.txt -coverpkg=github.com/ahsayde/yapl/yapl,github.com/ahsayde/yapl/internal/operator,github.com/ahsayde/yapl/internal/parser,github.com/ahsayde/yapl/internal/renderer ./...
go tool cover -html=coverage.txt -o coverage.html
260 changes: 260 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@

# YAPL
*YAML as Policy Language*

[![codecov](https://codecov.io/gh/ahsayde/yapl/branch/master/graph/badge.svg?token=N5CJSZBHNF)](https://codecov.io/gh/ahsayde/yapl)
![example workflow](https://github.com/ahsayde/yapl/actions/workflows/main.yml/badge.svg)


- [Syntax](#syntax)
- [Usage](#usage)
- [Contexts](#contexts)
- [Operators](#operators)


## Syntax


### Selecting Resources

The `match` and `exclude` are optional declarations used to filter resources which will be validated by the rules.

They have the same syntax, and can be used together to include and exclude resources.

#### Examples

For example this code will only validate resources when `request.method` is equal `GET`

```yaml
match:
field: request.method
operator: equal
value: GET
```
this code will validate all resources except when the `request.method` is equal `GET`

```yaml
exclude:
field: request.method
operator: equal
value: GET
```

this code will validate all resources when `request.method` equals `GET` and `request.endpoint` not equals `/api`

```yaml
match:
field: request.method
operator: equal
value: GET
exclude:
field: request.endpoint
operator: equal
value: /api
```

the previous example can be done using only `match` statement as follow:

```yaml
match:
and:
- field: request.method
operator: equal
value: GET
- not:
field: request.endpoint
operator: equal
value: /api
```

### Validating Resources

Policies can have multiple rules. Each rule has its own condition and result object.

rule's condition doesn't support nested conditions like `match` and `exclude`, It's only one level

```yaml
rules:
- condition:
field: metadata.name
equal: hasPrefix
value: app
result: container name must starts with app
```

the `result` field could be an object, see this example

```yaml
rules:
- condition:
field: metadata.name
equal: hasPrefix
value: app
result:
msg: container name must starts with app
```

#### Conditional Rule

You can add conditional rule by adding field `when` which implements the `condition` object

In this example, instead for writing two policies for each container type. Ypu can add two conditional rules

```yaml
rules:
- when:
field: image
equal: equal
value: my-app-image
condition:
field: metadata.name
equal: hasPrefix
value: app
result: app container's name must starts with app
- when:
field: image
equal: equal
value: my-db-image
condition:
field: metadata.name
equal: hasPrefix
value: db
result: db container's name must starts with db
```

### Context

Contexts are a way to access information about current rule

### Available Contexts

| Name | Type | Description | Availability |
|--------------|-----------------|--------------------------------------------------|---------------------------------|
| [`Input`](#input-context) | `object` | The input to be checked | all fields |
| [`Params`](#params-context) | `object` | Parameters passed during evaulation | all fields |
| [`Env`](#env-context) | `object` | exported environment variable | all fields |
| [`Cond`](#condition-context) | `object` | Current condition information, | only on `rules.result` field |


#### `Input` Context

Input contex allow you to access the resource object

```yaml
rules:
- condition:
field: user.role
operator: equal
value: admin
result: user ${ .Input.user.name } doesn't has access
```

#### `Params` Context

You can access parameters passed during the evaluation of input using `${ .Params.<variable name> }` expression. For example

```yaml
rules:
- condition:
field: request.body
operator: maxLength
value: ${ .Params.max_body_size }
result: request body must not exceed ${ .Params.max_body_size }
```

#### `Env` context

You can access any environment variable value by using expression `${ .Env.<variable name> }`

```yaml
rules:
- condition:
field: request.body
operator: maxLength
value: ${ .Env.MAX_BODY_SIZE }
result: request body must not exceed ${ .Env.MAX_BODY_SIZE }
```

#### `Cond` context

`Cond` context allow you to access all the information of the current field.

This context is only availabe on field `rules.result`.


| Key | Type | Description |
|----------------------------------|-------------------|-------------------------------------------------------|
| `Cond.Field.Value` | `any` | The value of the field |
| `Cond.Field.Index` | `integer` | The index of the field if field's parent is an array |
| `Cond.Field.Parent` | `[field object]` | The parent of the field |
| `Cond.Operator` | `string` | Condition's operator |
| `Cond.Value` | `string` | Condition's value |

Example

```yaml
rules:
- condition:
field: metadata.labels.app
operator: hasPrefix
value: app
result:
msg: resource app label must starts with ${ .Cond.Value } but found ${ .Cond.Field.Value }
key: ${ .Field.Path }
```



## Usage

```go
input := map[string]interface{}{
"users": []interface{}{
map[string]interface{}{
"name": "bob",
"role": "member",
},
},
}
params := map[string]interface{}{
"role": "admin",
}
raw, err := ioutil.ReadFile("policy.yaml")
if err != nil {
panic(err)
}
policy, err := yapl.Parse(raw)
if err != nil {
panic(err)
}
result, err := policy.Eval(input, params)
if err != nil {
panic(err)
}
```


## Operators

| Operator | Alias | Description | Field Value | Operator Value |
|-------------|----------|---------------------------------------------------------------------------|-------------|----------------|
| `exists` | | checks whether field is exist or not | `any` | |
| `equal` | `eq` | asserts field's value equal provided value | `any` | `any` |
| `hasPrefix` | | checks whether field's value begins with prefix | `string` | `string` |
| `hasSuffix` | | checks whether field's value ends with suffix | `string` | `string` |
| `regex` | | checks whether field's value matches the provided regex | `string` | `string` |
| `minValue` | `min` | checks whether field's value is greater than or equals provided value | `number` | `number` |
| `maxValue` | `max` | checks whether field's value is less than or equals the provided value | `number` | `number` |
| `in` | | checks whether field's value in the provided value | `any` | `array` |
| `contains` | | checks whether field's value contains the provided value | `array` | `any` |
| `length` | `len` | checks whether field's value length equals the provided value | `array` | `integer` |
| `minLength` | `minlen` | checks whether field's value has minimum length equals the provided value | `array` | `integer` |
| `maxLength` | `maxlen` | checks whether field's value has maximum length equals the provided value | `array` | `integer` |
13 changes: 13 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module github.com/ahsayde/yapl

go 1.18

require (
github.com/stretchr/testify v1.8.0
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
)
15 changes: 15 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading

0 comments on commit 7050528

Please sign in to comment.