-
-
Notifications
You must be signed in to change notification settings - Fork 511
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: bootstrap openfga module * chore: add wait strategy * feat: add container endpoints methods * chore: add example using client sdk * feat: enable playground * chore: add example for writing a model * docs: include example in docs * chore: simplify API using built-in blocks * chore: remove from dependabot
- Loading branch information
1 parent
c6f1f53
commit a935f77
Showing
12 changed files
with
708 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# OpenFGA | ||
|
||
Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a> | ||
|
||
## Introduction | ||
|
||
The Testcontainers module for OpenFGA. | ||
|
||
## Adding this module to your project dependencies | ||
|
||
Please run the following command to add the OpenFGA module to your Go dependencies: | ||
|
||
``` | ||
go get github.com/testcontainers/testcontainers-go/modules/openfga | ||
``` | ||
|
||
## Usage example | ||
|
||
<!--codeinclude--> | ||
[Creating a OpenFGA container](../../modules/openfga/examples_test.go) inside_block:runOpenFGAContainer | ||
<!--/codeinclude--> | ||
|
||
## Module reference | ||
|
||
The OpenFGA module exposes one entrypoint function to create the OpenFGA container, and this function receives two parameters: | ||
|
||
```golang | ||
func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*OpenFGAContainer, error) | ||
``` | ||
|
||
- `context.Context`, the Go context. | ||
- `testcontainers.ContainerCustomizer`, a variadic argument for passing options. | ||
|
||
### Container Options | ||
|
||
When starting the OpenFGA container, you can pass options in a variadic way to configure it. | ||
|
||
#### Image | ||
|
||
If you need to set a different OpenFGA Docker image, you can use `testcontainers.WithImage` with a valid Docker image | ||
for OpenFGA. E.g. `testcontainers.WithImage("openfga/openfga:v1.5.0")`. | ||
|
||
{% include "../features/common_functional_options.md" %} | ||
|
||
### Container Methods | ||
|
||
The OpenFGA container exposes the following methods: | ||
|
||
#### HttpEndpoint | ||
|
||
This method returns the HTTP endpoint to connect to the OpenFGA container, using the `8080` port. | ||
|
||
<!--codeinclude--> | ||
[Get HTTP endpoint](../../modules/openfga/examples_test.go) inside_block:httpEndpoint | ||
<!--/codeinclude--> | ||
|
||
#### GrpcEndpoint | ||
|
||
This method returns the gRPC endpoint to connect to the OpenFGA container, using the `8081` port. | ||
|
||
#### Playground URL | ||
|
||
In case you want to interact with the openfga playground, please use the `PlaygroundEndpoint` method, using the `3000` port. | ||
|
||
<!--codeinclude--> | ||
[Get Playground endpoint](../../modules/openfga/examples_test.go) inside_block:playgroundEndpoint | ||
<!--/codeinclude--> | ||
|
||
## Examples | ||
|
||
### Writing an OpenFGA model | ||
|
||
The following example shows how to write an OpenFGA model using the OpenFGA container. | ||
|
||
<!--codeinclude--> | ||
[Get Playground endpoint](../../modules/openfga/examples_test.go) inside_block:openFGAwriteModel | ||
<!--/codeinclude--> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
include ../../commons-test.mk | ||
|
||
.PHONY: test | ||
test: | ||
$(MAKE) test-openfga |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
package openfga_test | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"log" | ||
"net/http" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/openfga/go-sdk/client" | ||
"github.com/openfga/go-sdk/credentials" | ||
|
||
"github.com/testcontainers/testcontainers-go" | ||
"github.com/testcontainers/testcontainers-go/modules/openfga" | ||
) | ||
|
||
func ExampleRunContainer() { | ||
// runOpenFGAContainer { | ||
ctx := context.Background() | ||
|
||
openfgaContainer, err := openfga.RunContainer(ctx, testcontainers.WithImage("openfga/openfga:v1.5.0")) | ||
if err != nil { | ||
log.Fatalf("failed to start container: %s", err) | ||
} | ||
|
||
// Clean up the container | ||
defer func() { | ||
if err := openfgaContainer.Terminate(ctx); err != nil { | ||
log.Fatalf("failed to terminate container: %s", err) // nolint:gocritic | ||
} | ||
}() | ||
// } | ||
|
||
state, err := openfgaContainer.State(ctx) | ||
if err != nil { | ||
log.Fatalf("failed to get container state: %s", err) // nolint:gocritic | ||
} | ||
|
||
fmt.Println(state.Running) | ||
|
||
// Output: | ||
// true | ||
} | ||
|
||
func ExampleRunContainer_connectToPlayground() { | ||
openfgaContainer, err := openfga.RunContainer(context.Background(), testcontainers.WithImage("openfga/openfga:v1.5.0")) | ||
if err != nil { | ||
log.Fatalf("failed to start container: %s", err) | ||
} | ||
|
||
// Clean up the container | ||
defer func() { | ||
if err := openfgaContainer.Terminate(context.Background()); err != nil { | ||
log.Fatalf("failed to terminate container: %s", err) // nolint:gocritic | ||
} | ||
}() | ||
|
||
// playgroundEndpoint { | ||
playgroundEndpoint, err := openfgaContainer.PlaygroundEndpoint(context.Background()) | ||
if err != nil { | ||
log.Fatalf("failed to get playground endpoint: %s", err) // nolint:gocritic | ||
} | ||
// } | ||
|
||
httpClient := http.Client{} | ||
|
||
resp, err := httpClient.Get(playgroundEndpoint) | ||
if err != nil { | ||
log.Fatalf("failed to get playground endpoint: %s", err) // nolint:gocritic | ||
} | ||
|
||
fmt.Println(resp.StatusCode) | ||
|
||
// Output: | ||
// 200 | ||
} | ||
|
||
func ExampleRunContainer_connectWithSDKClient() { | ||
openfgaContainer, err := openfga.RunContainer(context.Background(), testcontainers.WithImage("openfga/openfga:v1.5.0")) | ||
if err != nil { | ||
log.Fatalf("failed to start container: %s", err) | ||
} | ||
|
||
// Clean up the container | ||
defer func() { | ||
if err := openfgaContainer.Terminate(context.Background()); err != nil { | ||
log.Fatalf("failed to terminate container: %s", err) // nolint:gocritic | ||
} | ||
}() | ||
|
||
// httpEndpoint { | ||
httpEndpoint, err := openfgaContainer.HttpEndpoint(context.Background()) | ||
if err != nil { | ||
log.Fatalf("failed to get HTTP endpoint: %s", err) // nolint:gocritic | ||
} | ||
// } | ||
|
||
// StoreId is not required for listing and creating stores | ||
fgaClient, err := client.NewSdkClient(&client.ClientConfiguration{ | ||
ApiUrl: httpEndpoint, // required | ||
}) | ||
if err != nil { | ||
log.Fatalf("failed to create SDK client: %s", err) // nolint:gocritic | ||
} | ||
|
||
list, err := fgaClient.ListStores(context.Background()).Execute() | ||
if err != nil { | ||
log.Fatalf("failed to list stores: %s", err) // nolint:gocritic | ||
} | ||
|
||
fmt.Println(len(list.Stores)) | ||
|
||
store, err := fgaClient.CreateStore(context.Background()).Body(client.ClientCreateStoreRequest{Name: "test"}).Execute() | ||
if err != nil { | ||
log.Fatalf("failed to create store: %s", err) // nolint:gocritic | ||
} | ||
|
||
fmt.Println(store.Name) | ||
|
||
list, err = fgaClient.ListStores(context.Background()).Execute() | ||
if err != nil { | ||
log.Fatalf("failed to list stores: %s", err) // nolint:gocritic | ||
} | ||
|
||
fmt.Println(len(list.Stores)) | ||
|
||
// Output: | ||
// 0 | ||
// test | ||
// 1 | ||
} | ||
|
||
func ExampleRunContainer_writeModel() { | ||
// openFGAwriteModel { | ||
secret := "openfga-secret" | ||
openfgaContainer, err := openfga.RunContainer( | ||
context.Background(), | ||
testcontainers.WithImage("openfga/openfga:v1.5.0"), | ||
testcontainers.WithEnv(map[string]string{ | ||
"OPENFGA_LOG_LEVEL": "warn", | ||
"OPENFGA_AUTHN_METHOD": "preshared", | ||
"OPENFGA_AUTHN_PRESHARED_KEYS": secret, | ||
}), | ||
) | ||
if err != nil { | ||
log.Fatalf("failed to start container: %s", err) | ||
} | ||
|
||
// Clean up the container | ||
defer func() { | ||
if err := openfgaContainer.Terminate(context.Background()); err != nil { | ||
log.Fatalf("failed to terminate container: %s", err) // nolint:gocritic | ||
} | ||
}() | ||
|
||
httpEndpoint, err := openfgaContainer.HttpEndpoint(context.Background()) | ||
if err != nil { | ||
log.Fatalf("failed to get HTTP endpoint: %s", err) // nolint:gocritic | ||
} | ||
|
||
fgaClient, err := client.NewSdkClient(&client.ClientConfiguration{ | ||
ApiUrl: httpEndpoint, | ||
Credentials: &credentials.Credentials{ | ||
Method: credentials.CredentialsMethodApiToken, | ||
Config: &credentials.Config{ | ||
ApiToken: secret, | ||
}, | ||
}, | ||
// because we are going to write an authorization model, | ||
// we need to specify an store id. Else, it will fail with | ||
// "Configuration.StoreId is required and must be specified to call this method" | ||
// In this example, it's an arbitrary store id, that will be created | ||
// on the fly. | ||
StoreId: "11111111111111111111111111", | ||
}) | ||
if err != nil { | ||
log.Fatalf("failed to create openfga client: %v", err) | ||
} | ||
|
||
f, err := os.Open(filepath.Join("testdata", "authorization_model.json")) | ||
if err != nil { | ||
log.Fatalf("failed to open file: %v", err) | ||
} | ||
defer f.Close() | ||
|
||
bs, err := io.ReadAll(f) | ||
if err != nil { | ||
log.Fatalf("failed to read file: %v", err) | ||
} | ||
|
||
var body client.ClientWriteAuthorizationModelRequest | ||
if err := json.Unmarshal(bs, &body); err != nil { | ||
log.Fatalf("failed to unmarshal json: %v", err) | ||
} | ||
|
||
resp, err := fgaClient.WriteAuthorizationModel(context.Background()).Body(body).Execute() | ||
if err != nil { | ||
log.Fatalf("failed to write authorization model: %v", err) | ||
} | ||
|
||
// } | ||
|
||
value, ok := resp.GetAuthorizationModelIdOk() | ||
fmt.Println(ok) | ||
fmt.Println(*value != "") | ||
|
||
// Output: | ||
// true | ||
// true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
module github.com/testcontainers/testcontainers-go/modules/openfga | ||
|
||
go 1.21 | ||
|
||
require ( | ||
github.com/openfga/go-sdk v0.3.5 | ||
github.com/testcontainers/testcontainers-go v0.29.1 | ||
) | ||
|
||
require ( | ||
dario.cat/mergo v1.0.0 // indirect | ||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect | ||
github.com/Microsoft/go-winio v0.6.1 // indirect | ||
github.com/Microsoft/hcsshim v0.11.4 // indirect | ||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect | ||
github.com/containerd/containerd v1.7.12 // indirect | ||
github.com/containerd/log v0.1.0 // indirect | ||
github.com/cpuguy83/dockercfg v0.3.1 // indirect | ||
github.com/distribution/reference v0.5.0 // indirect | ||
github.com/docker/docker v25.0.3+incompatible // indirect | ||
github.com/docker/go-connections v0.5.0 // indirect | ||
github.com/docker/go-units v0.5.0 // indirect | ||
github.com/felixge/httpsnoop v1.0.3 // indirect | ||
github.com/go-logr/logr v1.2.4 // indirect | ||
github.com/go-logr/stdr v1.2.2 // indirect | ||
github.com/go-ole/go-ole v1.2.6 // indirect | ||
github.com/gogo/protobuf v1.3.2 // indirect | ||
github.com/golang/protobuf v1.5.3 // indirect | ||
github.com/google/uuid v1.6.0 // indirect | ||
github.com/klauspost/compress v1.16.0 // indirect | ||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect | ||
github.com/magiconair/properties v1.8.7 // indirect | ||
github.com/moby/patternmatcher v0.6.0 // indirect | ||
github.com/moby/sys/sequential v0.5.0 // indirect | ||
github.com/moby/sys/user v0.1.0 // indirect | ||
github.com/moby/term v0.5.0 // indirect | ||
github.com/morikuni/aec v1.0.0 // indirect | ||
github.com/opencontainers/go-digest v1.0.0 // indirect | ||
github.com/opencontainers/image-spec v1.1.0 // indirect | ||
github.com/pkg/errors v0.9.1 // indirect | ||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect | ||
github.com/shirou/gopsutil/v3 v3.23.12 // indirect | ||
github.com/shoenig/go-m1cpu v0.1.6 // indirect | ||
github.com/sirupsen/logrus v1.9.3 // indirect | ||
github.com/tklauser/go-sysconf v0.3.12 // indirect | ||
github.com/tklauser/numcpus v0.6.1 // indirect | ||
github.com/yusufpapurcu/wmi v1.2.3 // indirect | ||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect | ||
go.opentelemetry.io/otel v1.19.0 // indirect | ||
go.opentelemetry.io/otel/metric v1.19.0 // indirect | ||
go.opentelemetry.io/otel/trace v1.19.0 // indirect | ||
golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect | ||
golang.org/x/mod v0.16.0 // indirect | ||
golang.org/x/sync v0.6.0 // indirect | ||
golang.org/x/sys v0.16.0 // indirect | ||
golang.org/x/tools v0.13.0 // indirect | ||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect | ||
google.golang.org/grpc v1.58.3 // indirect | ||
google.golang.org/protobuf v1.31.0 // indirect | ||
) | ||
|
||
replace github.com/testcontainers/testcontainers-go => ../.. |
Oops, something went wrong.