opac

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2022 License: Apache-2.0 Imports: 16 Imported by: 14

README

opac: OPA/Rego inquiry library Test Vuln scan Sec Scan Go Reference

Unofficial Rego evaluation API for OPA server, local Rego file and in-memory Rego data.

Motivation

Rego is general policy language and various evaluation methods for Rego are provided by official. In programing way, there are three major to evaluate policy.

  • Inquiry to OPA server
  • Use local policy file(s)
  • Use in-memory policy data (e.g. from environment variable)

A software developer can choose a appropriate way according to own requirements. However, in many case, an end user also want to choose evaluation method by each runtime environment. Therefore, unified policy evaluation method may be useful for developer to integrate with Rego.

opac provides abstracted API to evaluate Rego with OPA server, local policy file and in-memory text data. A developer can easily implement switching evaluation method mechanism by option chosen by end user.

Example

Query to OPA server

source code

func main() {
	client, err := opac.NewRemote("https://opa-server-h6tk4k5hyq-an.a.run.app/v1/data/example")
	if err != nil {
		panic(err.Error())
	}

	input := struct {
		Color string `json:"color"`
	}{
		Color: "blue",
	}
	output := struct {
		Allow bool `json:"allow"`
	}{}

	if err := client.Query(context.Background(), input, &output); err != nil {
		panic(err.Error())
	}

	fmt.Println("result:", output)
}
Query with local policy file(s)

source code

func main() {
	client, err := opac.NewLocal(
		opac.WithFile("./examples/local/policy.rego"),
		opac.WithPackage("example"),
	)
	if err != nil {
		panic(err.Error())
	}

	input := struct {
		Color string `json:"color"`
	}{
		Color: "blue",
	}
	output := struct {
		Allow bool `json:"allow"`
	}{}

	if err := client.Query(context.Background(), input, &output); err != nil {
		panic(err.Error())
	}

	fmt.Println("result:", output)
}
Test with mock

Your package code

package mock

import (
	"context"

	"github.com/m-mizutani/opac"
)

type Foo struct {
	client opac.Client
}

type Input struct{ User string }
type Result struct{ Allow bool }

func New(url string) *Foo {
	client, err := opac.NewRemote(url)
	if err != nil {
		panic(err)
	}

	return &Foo{
		client: client,
	}
}

func (x *Foo) IsAllow(user string) bool {
	input := &Input{User: user}
	var result Result
	if err := x.client.Query(context.Background(), input, &result); err != nil {
		panic(err)
	}

	return result.Allow
}

Then, create export_test.go as following.

package mock

import "github.com/m-mizutani/opac"

func NewWithMock(f opac.MockFunc) *Foo {
	return &Foo{
		client: opac.NewMock(f),
	}
}

After that, you can write Foo's test as following.

func TestWithMock(t *testing.T) {
	foo := mock.NewWithMock(func(input interface{}) (interface{}, error) {
		in, ok := input.(*mock.Input)
		require.True(t, ok)
		return &mock.Result{Allow: in.User == "blue"}, nil
	})

	assert.True(t, foo.IsAllow("blue"))
	assert.False(t, foo.IsAllow("orange"))
}

Options

for NewRemote
  • WithHTTPClient: Replace http.DefaultClient with own HTTPClient instance.
  • WithHTTPHeader: Add HTTP header. It can be added multiply.
  • WithLoggingRemote: Enable debug logging
for NewLocal

One ore more WithFile, WithDir or WithPolicyData is required.

  • WithFile: Specify a policy file
  • WithDir: Specify a policy file directory (search recursively)
  • WithPolicyData: Specify a policy data
  • WithPackage: Specify package name like "example.my_policy"
  • WithLoggingLocal: Enable debug logging
  • WithRegoPrint: Output print() result to io.Writer

License

Apache License 2.0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNoEvalResult = goerr.New("no evaluation result")
	ErrReadRegoDir  = goerr.New("fail to read rego directory")
	ErrReadRegoFile = goerr.New("fail to read rego file")
	ErrNoPolicyData = goerr.New("no policy data, one ore more file or policy data are required")
)

Functions

This section is empty.

Types

type Client

type Client interface {
	Query(ctx context.Context, in interface{}, out interface{}) error
}

type HTTPClient

type HTTPClient interface {
	Do(req *http.Request) (*http.Response, error)
}

HTTPClient is interface of http.Client for replancement with owned HTTP client

type Local added in v0.1.0

type Local struct {
	// contains filtered or unexported fields
}

Local loads and compile local policy data and evaluate input data with them.

func NewLocal added in v0.1.0

func NewLocal(options ...LocalOption) (*Local, error)

NewLocal creates a new Local client. It requires one or more WithFile, WithDir or WithPolicyData.

func (*Local) Query added in v0.1.0

func (x *Local) Query(ctx context.Context, input interface{}, output interface{}) error

Query evaluates policy with `input` data. The result will be written to `out`. `out` must be pointer of instance.

type LocalOption added in v0.1.0

type LocalOption func(x *Local)

LocalOption is Option of functional option pattern for Local

func WithDir added in v0.1.0

func WithDir(dirPath string) LocalOption

WithDir specifies directory path of .rego policy. Import policy files recursively.

func WithFile added in v0.1.0

func WithFile(filePath string) LocalOption

WithFile specifies .rego policy file path

func WithLoggingLocal added in v0.1.0

func WithLoggingLocal() LocalOption

WithLoggingLocal enables logger for debug

func WithPackage added in v0.1.0

func WithPackage(pkg string) LocalOption

WithPackage specifies using package name. e.g. "example.my_policy"

func WithPolicyData added in v0.1.0

func WithPolicyData(name, policy string) LocalOption

WithPolicyData specifies raw policy data with name. If the `name` conflicts with file path loaded by WithFile or WithDir, the policy overwrites data loaded by WithFile or WithDir.

func WithRegoPrint added in v0.1.0

func WithRegoPrint(w io.Writer) LocalOption

WithRegoPrint enables OPA print function and output to `w`

type Mock added in v0.1.0

type Mock struct {
	// contains filtered or unexported fields
}

func NewMock added in v0.1.0

func NewMock(f MockFunc) *Mock

func (*Mock) Query added in v0.1.0

func (x *Mock) Query(ctx context.Context, in interface{}, out interface{}) error

type MockFunc added in v0.1.0

type MockFunc func(in interface{}) (interface{}, error)

type Remote added in v0.1.0

type Remote struct {
	// contains filtered or unexported fields
}

Remote sends a HTTP/HTTPS request to OPA server.

func NewRemote added in v0.1.0

func NewRemote(url string, options ...RemoteOption) (*Remote, error)

NewRemote creates a new Local client.

func (*Remote) Query added in v0.1.0

func (x *Remote) Query(ctx context.Context, in interface{}, out interface{}) error

Query evaluates policy with `input` data. The result will be written to `out`. `out` must be pointer of instance.

type RemoteOption added in v0.1.0

type RemoteOption func(x *Remote)

RemoteOption is Option of functional option pattern for Remote

func WithHTTPClient

func WithHTTPClient(client HTTPClient) RemoteOption

WithHTTPClient replaces `http.DefaultClient` with own `HTTPClient` instance.

func WithHTTPHeader added in v0.1.0

func WithHTTPHeader(name, value string) RemoteOption

WithHTTPHeader adds HTTP header. It can be added multiply.

func WithLoggingRemote added in v0.1.0

func WithLoggingRemote() RemoteOption

WithLoggingRemote enables logger for debug

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL