Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Go example for TinyTodo based on cedar-go #182

Merged
merged 8 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
39 changes: 39 additions & 0 deletions .github/workflows/build_tiny_todo_go_reusable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Build and test TinyTodo-Go
on:
workflow_call:
inputs:
cedar_policy_ref:
required: true
type: string
cedar_examples_ref:
required: true
type: string

jobs:
build_and_test_tiny_todo_go:
name: Build and test TinyTodo-Go
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [ '1.22' ]
steps:
- name: Checkout cedar-examples
uses: actions/checkout@v4
with:
repository: cedar-policy/cedar-examples
ref: ${{ inputs.cedar_examples_ref }}
- name: Setup Go ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: go vet
working-directory: ./tinytodo-go
run: go vet ./...
- name: go test
working-directory: ./tinytodo-go
run: go test ./...
- name: python test
working-directory: ./tinytodo-go
run: |
go build ./cmd/server
python3 -m unittest
52 changes: 52 additions & 0 deletions .github/workflows/build_tiny_todo_reusable_go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Build and test TinyTodo
on:
workflow_call:
inputs:
cedar_policy_ref:
required: true
type: string
cedar_examples_ref:
required: true
type: string

jobs:
build_and_test_tiny_todo:
name: Build and test TinyTodo
runs-on: ubuntu-latest
strategy:
matrix:
toolchain:
- stable
steps:
- name: Checkout cedar-examples
uses: actions/checkout@v4
with:
repository: cedar-policy/cedar-examples
ref: ${{ inputs.cedar_examples_ref }}
- name: Use the specified branch
run: cd tinytodo && head -n -2 Cargo.toml > Temp.toml && mv Temp.toml Cargo.toml && printf 'rev = "${{ inputs.cedar_policy_ref }}"' >> Cargo.toml
- name: rustup
run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- name: cargo fmt
working-directory: ./tinytodo
run: cargo fmt --all --check
- name: cargo rustc
working-directory: ./tinytodo
run: |
RUSTFLAGS="-D warnings -F unsafe-code" cargo build --verbose
- name: cargo test
working-directory: ./tinytodo
run: cargo test --verbose
- name: cargo test templates
working-directory: ./tinytodo
run: cargo test --verbose --features=use-templates
- name: python test
working-directory: ./tinytodo
run: |
cargo build --release
python3 -m unittest
- name: python test templates
working-directory: ./tinytodo
run: |
cargo build --release --features=use-templates
python3 -m unittest
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

This repository contains examples demonstrating the use of [Cedar](https://github.com/cedar-policy/cedar), a policy language for writing and enforcing authorization policies in your applications. The following table summarizes relevant information about the applications. Please refer to the `README.md` files in the subfolders for details about how to build and run them.

| Example | Languages | Description |
| ----------- | ----------- | ---------- |
| [`tinytodo`][] | Rust, Python | A simple application for managing task lists that uses Cedar for authorization |
| [`cedar-java-hello-world`][] | Java | A simple application demonstrating the usage of the [Cedar Java APIs][] |
| [`cedar-rust-hello-world`][] | Rust | A simple application demonstrating the usage of the [Cedar Rust APIs][] |
| [`cedar-wasm-example`][] | TypeScript | A simple application demonstrating the usage of the [Cedar Wasm APIs][] |
| [`cedar-policy-language-in-action`][] | Cedar | Cedar policies and schemas for the [Cedar policy language in action](https://catalog.workshops.aws/cedar-policy-language-in-action) workshop |
| [`cedar-example-use-cases`][] | Cedar | Cedar policies and schemas for two example applications |
| [`oopsla2024-benchmarks`][] | Various | Cedar policies and schemas, along with benchmarking code and scripts, used for the performance evaluation of the [OOPSLA2024 paper on Cedar](https://dl.acm.org/doi/10.1145/3649835) |
| Example | Languages | Description |
|---------------------------------------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`tinytodo`][] | Rust, Python | A simple application for managing task lists that uses Cedar for authorization demonstrating the usage of the [Cedar Rust APIs][] |
| [`tinytodo-go`][] | Go, Python | A simple application for managing task lists that uses Cedar for authorization demonstrating the usage of the [Cedar Go APIs][] | |
| [`cedar-java-hello-world`][] | Java | A simple application demonstrating the usage of the [Cedar Java APIs][] |
| [`cedar-rust-hello-world`][] | Rust | A simple application demonstrating the usage of the [Cedar Rust APIs][] |
| [`cedar-wasm-example`][] | TypeScript | A simple application demonstrating the usage of the [Cedar Wasm APIs][] |
| [`cedar-policy-language-in-action`][] | Cedar | Cedar policies and schemas for the [Cedar policy language in action](https://catalog.workshops.aws/cedar-policy-language-in-action) workshop |
| [`cedar-example-use-cases`][] | Cedar | Cedar policies and schemas for two example applications |
| [`oopsla2024-benchmarks`][] | Various | Cedar policies and schemas, along with benchmarking code and scripts, used for the performance evaluation of the [OOPSLA2024 paper on Cedar](https://dl.acm.org/doi/10.1145/3649835) |

## Security

Expand All @@ -21,6 +22,7 @@ See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more inform
This project is licensed under the Apache-2.0 License.

[Cedar Rust APIs]: https://docs.rs/cedar-policy/latest/cedar_policy
[Cedar Go APIs]: https://github.com/cedar-policy/cedar-go
[Cedar Java APIs]: https://github.com/cedar-policy/cedar-java
[Cedar Wasm APIs]: https://github.com/cedar-policy/cedar/tree/main/cedar-wasm
[`cedar-example-use-cases`]: ./cedar-example-use-cases
Expand All @@ -30,3 +32,4 @@ This project is licensed under the Apache-2.0 License.
[`cedar-policy-language-in-action`]: ./cedar-policy-language-in-action
[`oopsla2024-benchmarks`]: ./oopsla2024-benchmarks
[`tinytodo`]: ./tinytodo
[`tinytodo-go`]: ./tinytodo-go
27 changes: 27 additions & 0 deletions tinytodo-go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# TinyTodo-Go

This is a Go implementation of [TinyTodo](../tinytodo/).

It relies on [`cedar-go`](https://github.com/cedar-policy/cedar-go).

## Usage

TinyTodo-Go's usage is similar to [TinyTodo](../tinytodo/) - you are encouraged to use an identical [Python CLI tool](./tinytodo.py) to interact with the HTTP REST APIs offered by TinyTodo-Go (which are identical to the APIs offered by TinyTodo).

To run with logging, set the environment variable `GO_LOG` to level `info`:

```SHELL
> GO_LOG=info python -i tinytodo.py
```

See [TinyTodo's README](../tinytodo/README.md) for more information.

## Build

You need Python3 and Go (1.22 or later).

See [TinyTodo's README](../tinytodo/README.md) for more information.

## Comparison with TinyTodo

TinyTodo-Go is constrained by the features of [`cedar-go`](https://github.com/cedar-policy/cedar-go). Refer to [this README](https://github.com/cedar-policy/cedar-go?tab=readme-ov-file#comparison-to-the-rust-implementation) to learn about the missing features.
38 changes: 38 additions & 0 deletions tinytodo-go/cmd/server/authorization.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package main

import (
"fmt"
"github.com/cedar-policy/cedar-examples/tinytodo-go/internal/app/server/entitystore"
"github.com/cedar-policy/cedar-go"
"os"
)

const (
DefaultCedarPolicyFileName = "policies.cedar"
DefaultEntitiesFileName = "entities.json" // this is not in the Cedar entity schema, conversion required
)

func prepareCedarPolicyEntities() (*entitystore.EntityStore, cedar.PolicySet, error) {

entitiesFile, err := os.ReadFile(DefaultEntitiesFileName)
if err != nil {
return nil, nil, fmt.Errorf("failed to read EntitiesFile: %w", err)
}

es, err := entitystore.New(entitiesFile)
if err != nil {
return nil, nil, fmt.Errorf("failed to create EntityStore: %w", err)
}

psFile, err := os.ReadFile(DefaultCedarPolicyFileName)
if err != nil {
return nil, nil, fmt.Errorf("failed to read Cedar policy file: %w", err)
}

ps, err := cedar.NewPolicySet(DefaultCedarPolicyFileName, psFile)
if err != nil {
return nil, nil, fmt.Errorf("failed to create Cedar policy set: %w", err)
}

return es, ps, nil
}
34 changes: 34 additions & 0 deletions tinytodo-go/cmd/server/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import (
"github.com/cedar-policy/cedar-examples/tinytodo-go/internal/app/server"
"log/slog"
"os"
)

func prepareLogger() server.Option {
if logLevel := os.Getenv("GO_LOG"); logLevel != "" {
var level slog.Level
switch logLevel {
case slog.LevelDebug.String():
level = slog.LevelDebug
case slog.LevelInfo.String():
level = slog.LevelInfo
case slog.LevelWarn.String():
level = slog.LevelWarn
case slog.LevelError.String():
level = slog.LevelError
}
return server.WithLogger(
slog.New(
slog.NewTextHandler(
os.Stdout,
&slog.HandlerOptions{
Level: level,
},
),
),
)
}
return server.WithLogger(DefaultLogger)
}
13 changes: 13 additions & 0 deletions tinytodo-go/cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

import (
"log/slog"
"os"
)

func main() {
if err := startServer(); err != nil {
DefaultLogger.Error("failed to start server", slog.Any("error", err))
os.Exit(-1)
}
}
42 changes: 42 additions & 0 deletions tinytodo-go/cmd/server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package main

import (
"flag"
"fmt"
"github.com/cedar-policy/cedar-examples/tinytodo-go/internal/app/server"
)

var (
DefaultLogger = server.DefaultLogger
)

// startServer starts the web server by parsing these CLI arguments:
//
// - port: Port number (default 8080)
func startServer() error {

port := flag.Int("port", 8080, "Listen port")
flag.Parse()

es, ps, err := prepareCedarPolicyEntities()
if err != nil {
return err
}

w, err := server.New(
fmt.Sprintf(":%d", *port),
es,
ps,
prepareLogger(),
)
if err != nil {
return err
}

if err := w.Serve(); err != nil {
return err
}

DefaultLogger.Info("terminating")
return nil
}
66 changes: 66 additions & 0 deletions tinytodo-go/entities.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
mqf20 marked this conversation as resolved.
Show resolved Hide resolved
"users": {
"User::\"kesha\"": {
"euid": "User::\"kesha\"",
"location": "ABC17",
"joblevel": 5,
"parents": [
"Application::\"TinyTodo\"",
"Team::\"temp\""
]
},
"User::\"aaron\"": {
"euid": "User::\"aaron\"",
"location": "ABC17",
"joblevel": 5,
"parents": [
"Team::\"interns\"",
"Application::\"TinyTodo\""
]
},
"User::\"emina\"": {
"euid": "User::\"emina\"",
"location": "DEF33",
"joblevel": 8,
"parents": [
"Application::\"TinyTodo\"",
"Team::\"admin\""
]
},
"User::\"andrew\"": {
"euid": "User::\"andrew\"",
"location": "XYZ77",
"joblevel": 5,
"parents": [
"Application::\"TinyTodo\"",
"Team::\"admin\"",
"Team::\"temp\""
]
}
},
"teams": {
"Team::\"temp\"": {
"uid": "Team::\"temp\"",
"parents": [
"Application::\"TinyTodo\""
]
},
"Team::\"admin\"": {
"uid": "Team::\"admin\"",
"parents": [
"Application::\"TinyTodo\""
]
},
"Team::\"interns\"": {
"uid": "Team::\"interns\"",
"parents": [
"Application::\"TinyTodo\"",
"Team::\"temp\""
]
}
},
"lists": {},
"app": {
"euid": "Application::\"TinyTodo\""
}
}
16 changes: 16 additions & 0 deletions tinytodo-go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module github.com/cedar-policy/cedar-examples/tinytodo-go

go 1.22

require (
github.com/cedar-policy/cedar-go v0.0.0-20240715162045-a71e93ee6ae7
github.com/go-chi/chi/v5 v5.1.0
github.com/stretchr/testify v1.9.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
16 changes: 16 additions & 0 deletions tinytodo-go/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
github.com/cedar-policy/cedar-go v0.0.0-20240715162045-a71e93ee6ae7 h1:3WPOmm5kgn8q5kbQc2kG97RK//GTQAp79AW7pV3pa8M=
github.com/cedar-policy/cedar-go v0.0.0-20240715162045-a71e93ee6ae7/go.mod h1:pEgiK479O5dJfzXnTguOMm+bCplzy5rEEFPGdZKPWz4=
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/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
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/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading
Loading