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 list audit log actions API endpoint support #386

Draft
wants to merge 2 commits into
base: hackweek-typegen
Choose a base branch
from
Draft
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
5 changes: 5 additions & 0 deletions pkg/auditlogs/auditlogs.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,8 @@ func CreateExport(ctx context.Context, e CreateExportOpts) (AuditLogExport, erro
func GetExport(ctx context.Context, e GetExportOpts) (AuditLogExport, error) {
return DefaultClient.GetExport(ctx, e)
}

// ListActions list all the audit log actions.
func ListActions(ctx context.Context, opts ListActionsOpts) (ListActionsResponse, error) {
return DefaultClient.ListActions(ctx, opts)
}
52 changes: 50 additions & 2 deletions pkg/auditlogs/auditlogs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"testing"

"github.com/stretchr/testify/require"
"github.com/workos/workos-go/v4/pkg/common"
)

func TestAuditLogsCreateEvent(t *testing.T) {
Expand All @@ -34,7 +35,6 @@ func TestAuditLogsCreateExport(t *testing.T) {
body := AuditLogExport{}
payload, _ := json.Marshal(body)
w.Write(payload)
w.WriteHeader(http.StatusOK)
}

server := httptest.NewServer(http.HandlerFunc(handlerFunc))
Expand All @@ -56,7 +56,6 @@ func TestAuditLogsGetExport(t *testing.T) {
body := AuditLogExport{}
payload, _ := json.Marshal(body)
w.Write(payload)
w.WriteHeader(http.StatusOK)
}

server := httptest.NewServer(http.HandlerFunc(handlerFunc))
Expand All @@ -72,3 +71,52 @@ func TestAuditLogsGetExport(t *testing.T) {
_, err := GetExport(context.TODO(), GetExportOpts{})
require.NoError(t, err)
}

func TestAuditLogsListActions(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(listActionsTestHandler))
defer server.Close()

DefaultClient = &Client{
HTTPClient: server.Client(),
Endpoint: server.URL,
}
SetAPIKey("test")

expectedResponse := ListActionsResponse{
Data: []AuditLogAction{
{
Name: "document.updated",
Schema: AuditLogActionSchema{
Version: 1,
Actor: AuditLogActionSchemaActor{
ID: "user_1",
Name: "Test User",
Type: "User",
},
Targets: []AuditLogActionSchemaTarget{
{
ID: "document_39127",
Name: "Test Document",
Type: "document",
},
},
Context: Context{
Location: "192.0.0.8",
UserAgent: "Firefox",
},
},
CreatedAt: "2024-01-01T00:00:00Z",
UpdatedAt: "2024-01-01T00:00:00Z",
},
},
ListMetadata: common.ListMetadata{
Before: "",
After: "",
},
}

actionsResponse, err := ListActions(context.Background(), ListActionsOpts{})

require.NoError(t, err)
require.Equal(t, expectedResponse, actionsResponse)
}
129 changes: 129 additions & 0 deletions pkg/auditlogs/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"sync"
"time"

"github.com/google/go-querystring/query"
"github.com/workos/workos-go/v4/pkg/common"
"github.com/workos/workos-go/v4/pkg/workos_errors"

"github.com/workos/workos-go/v4/internal/workos"
Expand Down Expand Up @@ -35,6 +38,9 @@ type Client struct {
// to http.Client.
HTTPClient *http.Client

// The WorkOS API URL. Defaults to https://api.workos.com.
Endpoint string

// The endpoint used to request WorkOS AuditLog events creation endpoint.
// Defaults to https://api.workos.com/audit_logs/events.
EventsEndpoint string
Expand Down Expand Up @@ -186,6 +192,10 @@ func (c *Client) init() {
c.HTTPClient = &http.Client{Timeout: 10 * time.Second}
}

if c.Endpoint == "" {
c.Endpoint = "https://api.workos.com"
}

if c.EventsEndpoint == "" {
c.EventsEndpoint = "https://api.workos.com/audit_logs/events"
}
Expand All @@ -199,6 +209,72 @@ func (c *Client) init() {
}
}

type AuditLogActionSchemaMetadataProperty struct {
Type string `json:"type"`
Nullable *bool `json:"nullable,omitempty"`
}

type AuditLogActionSchemaMetadata struct {
Type string `json:"type"`
Properties map[string]AuditLogActionSchemaMetadataProperty `json:"metadata,omitempty"`
}

type AuditLogActionSchemaActor struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Metadata AuditLogActionSchemaMetadata `json:"metadata,omitempty"`
}

type AuditLogActionSchemaTarget struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Metadata AuditLogActionSchemaMetadata `json:"metadata,omitempty"`
}

type AuditLogActionSchema struct {
Version int `json:"version"`
Actor AuditLogActionSchemaActor `json:"actor"`
Targets []AuditLogActionSchemaTarget `json:"targets"`
Context Context `json:"context"`
Metadata AuditLogActionSchemaMetadata `json:"metadata,omitempty"`
}

type AuditLogAction struct {
Name string `json:"name"`
Schema AuditLogActionSchema `json:"schema"`
// The timestamp of when the Organization was created.
CreatedAt string `json:"created_at"`
// The timestamp of when the Organization was updated.
UpdatedAt string `json:"updated_at"`
}

// ListActionsOpts contains the options to request Audit Log Actions.
type ListActionsOpts struct {
// Maximum number of records to return.
Limit int `url:"limit,omitempty"`

// The order in which to paginate records.
Order Order `url:"order,omitempty"`

// Pagination cursor to receive records before a provided Organization ID.
Before string `url:"before,omitempty"`

// Pagination cursor to receive records after a provided Organization ID.
After string `url:"after,omitempty"`
}

// ListActionsResponse describes the response structure when requesting
// Audit Log Actions.
type ListActionsResponse struct {
// List of Audit Log Actions.
Data []AuditLogAction `json:"data"`

// Cursor pagination options.
ListMetadata common.ListMetadata `json:"list_metadata"`
}

// CreateEvent creates an Audit Log event.
func (c *Client) CreateEvent(ctx context.Context, e CreateEventOpts) error {
c.once.Do(c.init)
Expand Down Expand Up @@ -295,6 +371,59 @@ func (c *Client) GetExport(ctx context.Context, e GetExportOpts) (AuditLogExport
return body, err
}

// ListActions gets a list of Audit Log Actions.
func (c *Client) ListActions(
ctx context.Context,
opts ListActionsOpts,
) (ListActionsResponse, error) {
c.once.Do(c.init)

endpoint := fmt.Sprintf("%s/audit_logs/actions", c.Endpoint)
req, err := http.NewRequest(
http.MethodGet,
endpoint,
nil,
)
if err != nil {
return ListActionsResponse{}, err
}

req = req.WithContext(ctx)
req.Header.Set("Authorization", "Bearer "+c.APIKey)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", "workos-go/"+workos.Version)

if opts.Limit == 0 {
opts.Limit = ResponseLimit
}

if opts.Order == "" {
opts.Order = Desc
}

q, err := query.Values(opts)
if err != nil {
return ListActionsResponse{}, err
}

req.URL.RawQuery = q.Encode()

res, err := c.HTTPClient.Do(req)
if err != nil {
return ListActionsResponse{}, err
}
defer res.Body.Close()

if err = workos_errors.TryGetHTTPError(res); err != nil {
return ListActionsResponse{}, err
}

var body ListActionsResponse
dec := json.NewDecoder(res.Body)
err = dec.Decode(&body)
return body, err
}

func defaultTime(t time.Time) time.Time {
if t == (time.Time{}) {
t = time.Now().UTC()
Expand Down
Loading