Files
coder/codersdk/audit.go
Kyle Carberry 7ad87505c8 chore: move agent functions from codersdk into agentsdk (#5903)
* chore: rename `AgentConn` to `WorkspaceAgentConn`

The codersdk was becoming bloated with consts for the workspace
agent that made no sense to a reader. `Tailnet*` is an example
of these consts.

* chore: remove `Get` prefix from *Client functions

* chore: remove `BypassRatelimits` option in `codersdk.Client`

It feels wrong to have this as a direct option because it's so infrequently
needed by API callers. It's better to directly modify headers in the two
places that we actually use it.

* Merge `appearance.go` and `buildinfo.go` into `deployment.go`

* Merge `experiments.go` and `features.go` into `deployment.go`

* Fix `make gen` referencing old type names

* Merge `error.go` into `client.go`

`codersdk.Response` lived in `error.go`, which is wrong.

* chore: refactor workspace agent functions into agentsdk

It was odd conflating the codersdk that clients should use
with functions that only the agent should use. This separates
them into two SDKs that are closely coupled, but separate.

* Merge `insights.go` into `deployment.go`

* Merge `organizationmember.go` into `organizations.go`

* Merge `quota.go` into `workspaces.go`

* Rename `sse.go` to `serversentevents.go`

* Rename `codersdk.WorkspaceAppHostResponse` to `codersdk.AppHostResponse`

* Format `.vscode/settings.json`

* Fix outdated naming in `api.ts`

* Fix app host response

* Fix unsupported type

* Fix imported type
2023-01-29 15:47:24 -06:00

172 lines
4.8 KiB
Go

package codersdk
import (
"context"
"encoding/json"
"net/http"
"net/netip"
"strings"
"time"
"github.com/google/uuid"
)
type ResourceType string
const (
ResourceTypeTemplate ResourceType = "template"
ResourceTypeTemplateVersion ResourceType = "template_version"
ResourceTypeUser ResourceType = "user"
ResourceTypeWorkspace ResourceType = "workspace"
ResourceTypeWorkspaceBuild ResourceType = "workspace_build"
ResourceTypeGitSSHKey ResourceType = "git_ssh_key"
ResourceTypeAPIKey ResourceType = "api_key"
ResourceTypeGroup ResourceType = "group"
)
func (r ResourceType) FriendlyString() string {
switch r {
case ResourceTypeTemplate:
return "template"
case ResourceTypeTemplateVersion:
return "template version"
case ResourceTypeUser:
return "user"
case ResourceTypeWorkspace:
return "workspace"
case ResourceTypeWorkspaceBuild:
// workspace builds have a unique friendly string
// see coderd/audit.go:298 for explanation
return "workspace"
case ResourceTypeGitSSHKey:
return "git ssh key"
case ResourceTypeAPIKey:
return "api key"
case ResourceTypeGroup:
return "group"
default:
return "unknown"
}
}
type AuditAction string
const (
AuditActionCreate AuditAction = "create"
AuditActionWrite AuditAction = "write"
AuditActionDelete AuditAction = "delete"
AuditActionStart AuditAction = "start"
AuditActionStop AuditAction = "stop"
)
func (a AuditAction) Friendly() string {
switch a {
case AuditActionCreate:
return "created"
case AuditActionWrite:
return "updated"
case AuditActionDelete:
return "deleted"
case AuditActionStart:
return "started"
case AuditActionStop:
return "stopped"
default:
return "unknown"
}
}
type AuditDiff map[string]AuditDiffField
type AuditDiffField struct {
Old any `json:"old,omitempty"`
New any `json:"new,omitempty"`
Secret bool `json:"secret"`
}
type AuditLog struct {
ID uuid.UUID `json:"id" format:"uuid"`
RequestID uuid.UUID `json:"request_id" format:"uuid"`
Time time.Time `json:"time" format:"date-time"`
OrganizationID uuid.UUID `json:"organization_id" format:"uuid"`
IP netip.Addr `json:"ip"`
UserAgent string `json:"user_agent"`
ResourceType ResourceType `json:"resource_type"`
ResourceID uuid.UUID `json:"resource_id" format:"uuid"`
// ResourceTarget is the name of the resource.
ResourceTarget string `json:"resource_target"`
ResourceIcon string `json:"resource_icon"`
Action AuditAction `json:"action"`
Diff AuditDiff `json:"diff"`
StatusCode int32 `json:"status_code"`
AdditionalFields json.RawMessage `json:"additional_fields"`
Description string `json:"description"`
ResourceLink string `json:"resource_link"`
IsDeleted bool `json:"is_deleted"`
User *User `json:"user"`
}
type AuditLogsRequest struct {
SearchQuery string `json:"q,omitempty"`
Pagination
}
type AuditLogResponse struct {
AuditLogs []AuditLog `json:"audit_logs"`
Count int64 `json:"count"`
}
type CreateTestAuditLogRequest struct {
Action AuditAction `json:"action,omitempty" enums:"create,write,delete,start,stop"`
ResourceType ResourceType `json:"resource_type,omitempty" enums:"template,template_version,user,workspace,workspace_build,git_ssh_key,auditable_group"`
ResourceID uuid.UUID `json:"resource_id,omitempty" format:"uuid"`
Time time.Time `json:"time,omitempty" format:"date-time"`
BuildReason BuildReason `json:"build_reason,omitempty" enums:"autostart,autostop,initiator"`
}
// AuditLogs retrieves audit logs from the given page.
func (c *Client) AuditLogs(ctx context.Context, req AuditLogsRequest) (AuditLogResponse, error) {
res, err := c.Request(ctx, http.MethodGet, "/api/v2/audit", nil, req.Pagination.asRequestOption(), func(r *http.Request) {
q := r.URL.Query()
var params []string
if req.SearchQuery != "" {
params = append(params, req.SearchQuery)
}
q.Set("q", strings.Join(params, " "))
r.URL.RawQuery = q.Encode()
})
if err != nil {
return AuditLogResponse{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return AuditLogResponse{}, ReadBodyAsError(res)
}
var logRes AuditLogResponse
err = json.NewDecoder(res.Body).Decode(&logRes)
if err != nil {
return AuditLogResponse{}, err
}
return logRes, nil
}
// CreateTestAuditLog creates a fake audit log. Only owners of the organization
// can perform this action. It's used for testing purposes.
func (c *Client) CreateTestAuditLog(ctx context.Context, req CreateTestAuditLogRequest) error {
res, err := c.Request(ctx, http.MethodPost, "/api/v2/audit/testgenerate", req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusNoContent {
return err
}
return nil
}