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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Add API methods required for type generation.
mattgd committed Dec 19, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 7fba0cdf89ccdb0b7a3cc6f211f0b79a815ffbc9
5 changes: 5 additions & 0 deletions pkg/auditlogs/auditlogs.go
Original file line number Diff line number Diff line change
@@ -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
@@ -8,6 +8,7 @@ import (
"testing"

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

func TestAuditLogsCreateEvent(t *testing.T) {
@@ -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))
@@ -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))
@@ -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: Actor{
ID: "user_1",
Name: "Test User",
Type: "User",
},
Targets: []Target{
{
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)
}
105 changes: 105 additions & 0 deletions pkg/auditlogs/client.go
Original file line number Diff line number Diff line change
@@ -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"
@@ -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
@@ -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"
}
@@ -199,6 +209,48 @@ func (c *Client) init() {
}
}

type AuditLogActionSchema struct {
Version int `json:"version"`
Actor Actor `json:"actor"`
Targets []Target `json:"targets"`
Context Context `json:"context"`
Metadata map[string]interface{} `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)
@@ -295,6 +347,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()
Loading