diff --git a/.stats.yml b/.stats.yml index 71c320f..50996d4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 127 +configured_endpoints: 134 diff --git a/api.md b/api.md index bbd5b3c..9b2b461 100644 --- a/api.md +++ b/api.md @@ -273,6 +273,16 @@ Methods: # Auth +## Context + +Response Types: + +- kernel.AuthContext + +Methods: + +- client.Auth.Context.Get(ctx context.Context) (\*kernel.AuthContext, error) + ## Connections Params Types: @@ -438,6 +448,27 @@ Methods: - client.AuditLogs.List(ctx context.Context, query kernel.AuditLogListParams) (\*pagination.PageTokenPagination[kernel.AuditLogEntry], error) - client.AuditLogs.ExportChunk(ctx context.Context, query kernel.AuditLogExportChunkParams) (\*http.Response, error) +## ExportDestinations + +Params Types: + +- kernel.CreateAuditLogExportDestinationRequestParam +- kernel.UpdateAuditLogExportDestinationRequestParam + +Response Types: + +- kernel.AuditLogExportDestination +- kernel.AuditLogExportDestinationTestResult + +Methods: + +- client.AuditLogs.ExportDestinations.New(ctx context.Context, body kernel.AuditLogExportDestinationNewParams) (\*kernel.AuditLogExportDestination, error) +- client.AuditLogs.ExportDestinations.Get(ctx context.Context, id string) (\*kernel.AuditLogExportDestination, error) +- client.AuditLogs.ExportDestinations.Update(ctx context.Context, id string, body kernel.AuditLogExportDestinationUpdateParams) (\*kernel.AuditLogExportDestination, error) +- client.AuditLogs.ExportDestinations.List(ctx context.Context, query kernel.AuditLogExportDestinationListParams) (\*pagination.OffsetPagination[kernel.AuditLogExportDestination], error) +- client.AuditLogs.ExportDestinations.Delete(ctx context.Context, id string) error +- client.AuditLogs.ExportDestinations.Test(ctx context.Context, id string) (\*kernel.AuditLogExportDestinationTestResult, error) + # APIKeys Response Types: diff --git a/auditlog.go b/auditlog.go index 9096e7c..665df86 100644 --- a/auditlog.go +++ b/auditlog.go @@ -28,6 +28,8 @@ import ( // the [NewAuditLogService] method instead. type AuditLogService struct { Options []option.RequestOption + // Read audit log records for the authenticated organization. + ExportDestinations AuditLogExportDestinationService } // NewAuditLogService generates a new service that applies the given options to @@ -36,6 +38,7 @@ type AuditLogService struct { func NewAuditLogService(opts ...option.RequestOption) (r AuditLogService) { r = AuditLogService{} r.Options = opts + r.ExportDestinations = NewAuditLogExportDestinationService(opts...) return } diff --git a/auditlogexportdestination.go b/auditlogexportdestination.go new file mode 100644 index 0000000..db967d3 --- /dev/null +++ b/auditlogexportdestination.go @@ -0,0 +1,391 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package kernel + +import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + "slices" + "time" + + "github.com/kernel/kernel-go-sdk/internal/apijson" + "github.com/kernel/kernel-go-sdk/internal/apiquery" + shimjson "github.com/kernel/kernel-go-sdk/internal/encoding/json" + "github.com/kernel/kernel-go-sdk/internal/requestconfig" + "github.com/kernel/kernel-go-sdk/option" + "github.com/kernel/kernel-go-sdk/packages/pagination" + "github.com/kernel/kernel-go-sdk/packages/param" + "github.com/kernel/kernel-go-sdk/packages/respjson" +) + +// Read audit log records for the authenticated organization. +// +// AuditLogExportDestinationService contains methods and other services that help +// with interacting with the kernel API. +// +// Note, unlike clients, this service does not read variables from the environment +// automatically. You should not instantiate this service directly, and instead use +// the [NewAuditLogExportDestinationService] method instead. +type AuditLogExportDestinationService struct { + Options []option.RequestOption +} + +// NewAuditLogExportDestinationService generates a new service that applies the +// given options to each request. These options are applied after the parent +// client's options (if there is one), and before any request-specific options. +func NewAuditLogExportDestinationService(opts ...option.RequestOption) (r AuditLogExportDestinationService) { + r = AuditLogExportDestinationService{} + r.Options = opts + return +} + +// Create a paused destination. Activate it with a status update once the +// destination test passes. Requires an active Enterprise plan. +func (r *AuditLogExportDestinationService) New(ctx context.Context, body AuditLogExportDestinationNewParams, opts ...option.RequestOption) (res *AuditLogExportDestination, err error) { + opts = slices.Concat(r.Options, opts) + path := "audit-logs/export/destinations" + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) + return res, err +} + +// Retrieve details for a single audit log export destination by its ID. +func (r *AuditLogExportDestinationService) Get(ctx context.Context, id string, opts ...option.RequestOption) (res *AuditLogExportDestination, err error) { + opts = slices.Concat(r.Options, opts) + if id == "" { + err = errors.New("missing required id parameter") + return nil, err + } + path := fmt.Sprintf("audit-logs/export/destinations/%s", id) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) + return res, err +} + +// Apply a partial update to a destination. Requires an active Enterprise plan. +// Returns 409 when the destination was changed concurrently, because the merged +// configuration this request validated is no longer the one that would be stored; +// retry against fresh state. Pausing prevents new delivery attempts, but an S3 +// upload already in progress may complete after the response. +func (r *AuditLogExportDestinationService) Update(ctx context.Context, id string, body AuditLogExportDestinationUpdateParams, opts ...option.RequestOption) (res *AuditLogExportDestination, err error) { + opts = slices.Concat(r.Options, opts) + if id == "" { + err = errors.New("missing required id parameter") + return nil, err + } + path := fmt.Sprintf("audit-logs/export/destinations/%s", id) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, body, &res, opts...) + return res, err +} + +// List audit log export destinations for the organization with pagination support. +func (r *AuditLogExportDestinationService) List(ctx context.Context, query AuditLogExportDestinationListParams, opts ...option.RequestOption) (res *pagination.OffsetPagination[AuditLogExportDestination], err error) { + var raw *http.Response + opts = slices.Concat(r.Options, opts) + opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) + path := "audit-logs/export/destinations" + cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, query, &res, opts...) + if err != nil { + return nil, err + } + err = cfg.Execute() + if err != nil { + return nil, err + } + res.SetPageConfig(cfg, raw) + return res, nil +} + +// List audit log export destinations for the organization with pagination support. +func (r *AuditLogExportDestinationService) ListAutoPaging(ctx context.Context, query AuditLogExportDestinationListParams, opts ...option.RequestOption) *pagination.OffsetPaginationAutoPager[AuditLogExportDestination] { + return pagination.NewOffsetPaginationAutoPager(r.List(ctx, query, opts...)) +} + +// Soft delete the destination and prevent new delivery attempts. An S3 upload +// already in progress may complete after the response. +func (r *AuditLogExportDestinationService) Delete(ctx context.Context, id string, opts ...option.RequestOption) (err error) { + opts = slices.Concat(r.Options, opts) + opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) + if id == "" { + err = errors.New("missing required id parameter") + return err + } + path := fmt.Sprintf("audit-logs/export/destinations/%s", id) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, nil, opts...) + return err +} + +// Verify the destination is writable by assuming the configured role and uploading +// a temporary probe object with the same request metadata as a real delivery. +// Requires an active Enterprise plan. +func (r *AuditLogExportDestinationService) Test(ctx context.Context, id string, opts ...option.RequestOption) (res *AuditLogExportDestinationTestResult, err error) { + opts = slices.Concat(r.Options, opts) + if id == "" { + err = errors.New("missing required id parameter") + return nil, err + } + path := fmt.Sprintf("audit-logs/export/destinations/%s/test", id) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...) + return res, err +} + +// An organization-scoped audit log export destination. +// +// Delivery is at-least-once for rows visible when their window is committed: a +// delivery that is retried rewrites the same object, and the same `event_id` can +// appear in more than one object, so consumers must deduplicate on `event_id`. +// Each event-time window is held for ten minutes before it commits; a row that +// becomes visible after its window is committed may not be delivered. +// +// Objects are written as +// `/destination_id=/org_id=/date=/hour=/-.jsonl.gz`, +// where `date` and `hour` are the UTC calendar hour that fully contains every row +// in the object, so the layout is safe to register as a Hive-partitioned table. +// The object name is derived from the rows it holds, so a retried delivery +// rewrites its own object. +type AuditLogExportDestination struct { + ID string `json:"id" api:"required"` + Bucket string `json:"bucket" api:"required"` + ConsecutiveFailures int64 `json:"consecutive_failures" api:"required"` + CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"` + ExternalID string `json:"external_id" api:"required"` + // Any of "jsonl.gz". + Format AuditLogExportDestinationFormat `json:"format" api:"required"` + // The Kernel role that assumes `role_arn` in your account to deliver logs. Allow + // this role as the principal in your role's trust policy, and require + // `external_id` as the `sts:ExternalId` condition. + // + // Recreating a destination issues a new `external_id`, which the trust policy has + // to be updated to match. + KernelRoleArn string `json:"kernel_role_arn" api:"required"` + Prefix string `json:"prefix" api:"required"` + Region string `json:"region" api:"required"` + RoleArn string `json:"role_arn" api:"required"` + // Pausing prevents new delivery attempts. An S3 upload already in progress may + // complete after the pause response; its rows can appear again after the + // destination is resumed. + // + // Any of "active", "paused". + Status AuditLogExportDestinationStatus `json:"status" api:"required"` + // Any of "s3". + Type AuditLogExportDestinationType `json:"type" api:"required"` + UpdatedAt time.Time `json:"updated_at" api:"required" format:"date-time"` + KmsKeyID string `json:"kms_key_id"` + // Sanitized description of the most recent delivery failure. + LastError string `json:"last_error"` + LastErrorAt time.Time `json:"last_error_at" format:"date-time"` + // Opaque, versioned checkpoint for forward-only continuous export. This value is + // not compatible with audit-log list page tokens. + // + // Delivery starts at the moment the destination is activated, so events recorded + // before that are not delivered. Pausing stops delivery and resuming starts again + // from the time of the resume: events recorded while a destination was paused are + // never exported, and pausing is not a way to defer delivery. + LastExportedCursor string `json:"last_exported_cursor"` + LastSuccessAt time.Time `json:"last_success_at" format:"date-time"` + NextAttemptAt time.Time `json:"next_attempt_at" format:"date-time"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + ID respjson.Field + Bucket respjson.Field + ConsecutiveFailures respjson.Field + CreatedAt respjson.Field + ExternalID respjson.Field + Format respjson.Field + KernelRoleArn respjson.Field + Prefix respjson.Field + Region respjson.Field + RoleArn respjson.Field + Status respjson.Field + Type respjson.Field + UpdatedAt respjson.Field + KmsKeyID respjson.Field + LastError respjson.Field + LastErrorAt respjson.Field + LastExportedCursor respjson.Field + LastSuccessAt respjson.Field + NextAttemptAt respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AuditLogExportDestination) RawJSON() string { return r.JSON.raw } +func (r *AuditLogExportDestination) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type AuditLogExportDestinationFormat string + +const ( + AuditLogExportDestinationFormatJSONLGz AuditLogExportDestinationFormat = "jsonl.gz" +) + +// Pausing prevents new delivery attempts. An S3 upload already in progress may +// complete after the pause response; its rows can appear again after the +// destination is resumed. +type AuditLogExportDestinationStatus string + +const ( + AuditLogExportDestinationStatusActive AuditLogExportDestinationStatus = "active" + AuditLogExportDestinationStatusPaused AuditLogExportDestinationStatus = "paused" +) + +type AuditLogExportDestinationType string + +const ( + AuditLogExportDestinationTypeS3 AuditLogExportDestinationType = "s3" +) + +type AuditLogExportDestinationTestResult struct { + // Any of "assume_role", "put_object", "complete". + Stage AuditLogExportDestinationTestResultStage `json:"stage" api:"required"` + Success bool `json:"success" api:"required"` + Error AuditLogExportDestinationTestResultError `json:"error"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + Stage respjson.Field + Success respjson.Field + Error respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AuditLogExportDestinationTestResult) RawJSON() string { return r.JSON.raw } +func (r *AuditLogExportDestinationTestResult) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type AuditLogExportDestinationTestResultStage string + +const ( + AuditLogExportDestinationTestResultStageAssumeRole AuditLogExportDestinationTestResultStage = "assume_role" + AuditLogExportDestinationTestResultStagePutObject AuditLogExportDestinationTestResultStage = "put_object" + AuditLogExportDestinationTestResultStageComplete AuditLogExportDestinationTestResultStage = "complete" +) + +type AuditLogExportDestinationTestResultError struct { + // Any of "assume_role_failed", "put_object_failed". + Code string `json:"code" api:"required"` + Message string `json:"message" api:"required"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + Code respjson.Field + Message respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AuditLogExportDestinationTestResultError) RawJSON() string { return r.JSON.raw } +func (r *AuditLogExportDestinationTestResultError) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +// The properties Bucket, Format, Prefix, Region, RoleArn, Type are required. +type CreateAuditLogExportDestinationRequestParam struct { + Bucket string `json:"bucket" api:"required"` + // Any of "jsonl.gz". + Format CreateAuditLogExportDestinationRequestFormat `json:"format,omitzero" api:"required"` + Prefix string `json:"prefix" api:"required"` + Region string `json:"region" api:"required"` + RoleArn string `json:"role_arn" api:"required"` + // Any of "s3". + Type CreateAuditLogExportDestinationRequestType `json:"type,omitzero" api:"required"` + KmsKeyID param.Opt[string] `json:"kms_key_id,omitzero"` + paramObj +} + +func (r CreateAuditLogExportDestinationRequestParam) MarshalJSON() (data []byte, err error) { + type shadow CreateAuditLogExportDestinationRequestParam + return param.MarshalObject(r, (*shadow)(&r)) +} +func (r *CreateAuditLogExportDestinationRequestParam) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type CreateAuditLogExportDestinationRequestFormat string + +const ( + CreateAuditLogExportDestinationRequestFormatJSONLGz CreateAuditLogExportDestinationRequestFormat = "jsonl.gz" +) + +type CreateAuditLogExportDestinationRequestType string + +const ( + CreateAuditLogExportDestinationRequestTypeS3 CreateAuditLogExportDestinationRequestType = "s3" +) + +type UpdateAuditLogExportDestinationRequestParam struct { + Bucket param.Opt[string] `json:"bucket,omitzero"` + // KMS key ID, alias, or ARN. Set to an empty string to remove the configured KMS + // key; omit or send null to leave unchanged. + KmsKeyID param.Opt[string] `json:"kms_key_id,omitzero"` + Prefix param.Opt[string] `json:"prefix,omitzero"` + Region param.Opt[string] `json:"region,omitzero"` + RoleArn param.Opt[string] `json:"role_arn,omitzero"` + // Any of "active", "paused". + Status UpdateAuditLogExportDestinationRequestStatus `json:"status,omitzero"` + paramObj +} + +func (r UpdateAuditLogExportDestinationRequestParam) MarshalJSON() (data []byte, err error) { + type shadow UpdateAuditLogExportDestinationRequestParam + return param.MarshalObject(r, (*shadow)(&r)) +} +func (r *UpdateAuditLogExportDestinationRequestParam) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type UpdateAuditLogExportDestinationRequestStatus string + +const ( + UpdateAuditLogExportDestinationRequestStatusActive UpdateAuditLogExportDestinationRequestStatus = "active" + UpdateAuditLogExportDestinationRequestStatusPaused UpdateAuditLogExportDestinationRequestStatus = "paused" +) + +type AuditLogExportDestinationNewParams struct { + CreateAuditLogExportDestinationRequest CreateAuditLogExportDestinationRequestParam + paramObj +} + +func (r AuditLogExportDestinationNewParams) MarshalJSON() (data []byte, err error) { + return shimjson.Marshal(r.CreateAuditLogExportDestinationRequest) +} +func (r *AuditLogExportDestinationNewParams) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type AuditLogExportDestinationUpdateParams struct { + UpdateAuditLogExportDestinationRequest UpdateAuditLogExportDestinationRequestParam + paramObj +} + +func (r AuditLogExportDestinationUpdateParams) MarshalJSON() (data []byte, err error) { + return shimjson.Marshal(r.UpdateAuditLogExportDestinationRequest) +} +func (r *AuditLogExportDestinationUpdateParams) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type AuditLogExportDestinationListParams struct { + // Limit the number of destinations to return. + Limit param.Opt[int64] `query:"limit,omitzero" json:"-"` + // Offset the number of destinations to return. + Offset param.Opt[int64] `query:"offset,omitzero" json:"-"` + paramObj +} + +// URLQuery serializes [AuditLogExportDestinationListParams]'s query parameters as +// `url.Values`. +func (r AuditLogExportDestinationListParams) URLQuery() (v url.Values, err error) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatComma, + NestedFormat: apiquery.NestedQueryFormatBrackets, + }) +} diff --git a/auditlogexportdestination_test.go b/auditlogexportdestination_test.go new file mode 100644 index 0000000..b9ceb30 --- /dev/null +++ b/auditlogexportdestination_test.go @@ -0,0 +1,178 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package kernel_test + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/kernel/kernel-go-sdk" + "github.com/kernel/kernel-go-sdk/internal/testutil" + "github.com/kernel/kernel-go-sdk/option" +) + +func TestAuditLogExportDestinationNewWithOptionalParams(t *testing.T) { + t.Skip("Mock server tests are disabled") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := kernel.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("My API Key"), + ) + _, err := client.AuditLogs.ExportDestinations.New(context.TODO(), kernel.AuditLogExportDestinationNewParams{ + CreateAuditLogExportDestinationRequest: kernel.CreateAuditLogExportDestinationRequestParam{ + Bucket: "xxx", + Format: kernel.CreateAuditLogExportDestinationRequestFormatJSONLGz, + Prefix: "prefix", + Region: "x", + RoleArn: "x", + Type: kernel.CreateAuditLogExportDestinationRequestTypeS3, + KmsKeyID: kernel.String("kms_key_id"), + }, + }) + if err != nil { + var apierr *kernel.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestAuditLogExportDestinationGet(t *testing.T) { + t.Skip("Mock server tests are disabled") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := kernel.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("My API Key"), + ) + _, err := client.AuditLogs.ExportDestinations.Get(context.TODO(), "id") + if err != nil { + var apierr *kernel.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestAuditLogExportDestinationUpdateWithOptionalParams(t *testing.T) { + t.Skip("Mock server tests are disabled") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := kernel.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("My API Key"), + ) + _, err := client.AuditLogs.ExportDestinations.Update( + context.TODO(), + "id", + kernel.AuditLogExportDestinationUpdateParams{ + UpdateAuditLogExportDestinationRequest: kernel.UpdateAuditLogExportDestinationRequestParam{ + Bucket: kernel.String("xxx"), + KmsKeyID: kernel.String("kms_key_id"), + Prefix: kernel.String("prefix"), + Region: kernel.String("x"), + RoleArn: kernel.String("x"), + Status: kernel.UpdateAuditLogExportDestinationRequestStatusActive, + }, + }, + ) + if err != nil { + var apierr *kernel.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestAuditLogExportDestinationListWithOptionalParams(t *testing.T) { + t.Skip("Mock server tests are disabled") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := kernel.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("My API Key"), + ) + _, err := client.AuditLogs.ExportDestinations.List(context.TODO(), kernel.AuditLogExportDestinationListParams{ + Limit: kernel.Int(1), + Offset: kernel.Int(0), + }) + if err != nil { + var apierr *kernel.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestAuditLogExportDestinationDelete(t *testing.T) { + t.Skip("Mock server tests are disabled") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := kernel.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("My API Key"), + ) + err := client.AuditLogs.ExportDestinations.Delete(context.TODO(), "id") + if err != nil { + var apierr *kernel.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestAuditLogExportDestinationTest(t *testing.T) { + t.Skip("Mock server tests are disabled") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := kernel.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("My API Key"), + ) + _, err := client.AuditLogs.ExportDestinations.Test(context.TODO(), "id") + if err != nil { + var apierr *kernel.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} diff --git a/auth.go b/auth.go index 6475100..843f122 100644 --- a/auth.go +++ b/auth.go @@ -14,6 +14,8 @@ import ( // the [NewAuthService] method instead. type AuthService struct { Options []option.RequestOption + // Inspect the identity and authorization context for the current request. + Context AuthContextService // Create and manage auth connections for automated credential capture and login. Connections AuthConnectionService } @@ -24,6 +26,7 @@ type AuthService struct { func NewAuthService(opts ...option.RequestOption) (r AuthService) { r = AuthService{} r.Options = opts + r.Context = NewAuthContextService(opts...) r.Connections = NewAuthConnectionService(opts...) return } diff --git a/authcontext.go b/authcontext.go new file mode 100644 index 0000000..dbb922d --- /dev/null +++ b/authcontext.go @@ -0,0 +1,198 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package kernel + +import ( + "context" + "net/http" + "slices" + + "github.com/kernel/kernel-go-sdk/internal/apijson" + "github.com/kernel/kernel-go-sdk/internal/requestconfig" + "github.com/kernel/kernel-go-sdk/option" + "github.com/kernel/kernel-go-sdk/packages/respjson" +) + +// Inspect the identity and authorization context for the current request. +// +// AuthContextService contains methods and other services that help with +// interacting with the kernel API. +// +// Note, unlike clients, this service does not read variables from the environment +// automatically. You should not instantiate this service directly, and instead use +// the [NewAuthContextService] method instead. +type AuthContextService struct { + Options []option.RequestOption +} + +// NewAuthContextService generates a new service that applies the given options to +// each request. These options are applied after the parent client's options (if +// there is one), and before any request-specific options. +func NewAuthContextService(opts ...option.RequestOption) (r AuthContextService) { + r = AuthContextService{} + r.Options = opts + return +} + +// Returns the authenticated principal, organization, credential scope, and +// effective request scope. The response is derived from the verified request +// context and does not expose credential secrets. +func (r *AuthContextService) Get(ctx context.Context, opts ...option.RequestOption) (res *AuthContext, err error) { + opts = slices.Concat(r.Options, opts) + path := "auth/context" + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) + return res, err +} + +// The identity and authorization context resolved for the current request. +type AuthContext struct { + Authentication AuthContextAuthentication `json:"authentication" api:"required"` + // The credential's maximum scope and the effective scope selected for this + // request. Future permission data can be added without changing scope semantics. + Authorization AuthContextAuthorization `json:"authorization" api:"required"` + Organization AuthContextOrganization `json:"organization" api:"required"` + Principal AuthContextPrincipal `json:"principal" api:"required"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + Authentication respjson.Field + Authorization respjson.Field + Organization respjson.Field + Principal respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AuthContext) RawJSON() string { return r.JSON.raw } +func (r *AuthContext) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type AuthContextAuthentication struct { + // The API key ID when authenticated with an API key; null for session credentials. + CredentialID string `json:"credential_id" api:"required"` + // The credential format used to authenticate the request. + // + // Any of "api_key", "jwt". + Method string `json:"method" api:"required"` + // The source classification resolved by authentication middleware. + // + // Any of "api_key", "oauth", "dashboard". + Source string `json:"source" api:"required"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + CredentialID respjson.Field + Method respjson.Field + Source respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AuthContextAuthentication) RawJSON() string { return r.JSON.raw } +func (r *AuthContextAuthentication) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +// The credential's maximum scope and the effective scope selected for this +// request. Future permission data can be added without changing scope semantics. +type AuthContextAuthorization struct { + // A scope within the authenticated organization. A null project_id represents + // organization-wide scope. + CredentialScope AuthContextAuthorizationCredentialScope `json:"credential_scope" api:"required"` + // A scope within the authenticated organization. A null project_id represents + // organization-wide scope. + EffectiveScope AuthContextAuthorizationEffectiveScope `json:"effective_scope" api:"required"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + CredentialScope respjson.Field + EffectiveScope respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AuthContextAuthorization) RawJSON() string { return r.JSON.raw } +func (r *AuthContextAuthorization) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +// A scope within the authenticated organization. A null project_id represents +// organization-wide scope. +type AuthContextAuthorizationCredentialScope struct { + // The Kernel project ID, or null when the scope is organization-wide. + ProjectID string `json:"project_id" api:"required"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + ProjectID respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AuthContextAuthorizationCredentialScope) RawJSON() string { return r.JSON.raw } +func (r *AuthContextAuthorizationCredentialScope) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +// A scope within the authenticated organization. A null project_id represents +// organization-wide scope. +type AuthContextAuthorizationEffectiveScope struct { + // The Kernel project ID, or null when the scope is organization-wide. + ProjectID string `json:"project_id" api:"required"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + ProjectID respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AuthContextAuthorizationEffectiveScope) RawJSON() string { return r.JSON.raw } +func (r *AuthContextAuthorizationEffectiveScope) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type AuthContextOrganization struct { + // The authenticated Kernel organization ID. + ID string `json:"id" api:"required"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + ID respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AuthContextOrganization) RawJSON() string { return r.JSON.raw } +func (r *AuthContextOrganization) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + +type AuthContextPrincipal struct { + // The API key ID for API-key principals or user ID for user principals. + ID string `json:"id" api:"required"` + // The kind of principal authenticated for the request. + // + // Any of "api_key", "user". + Type string `json:"type" api:"required"` + // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. + JSON struct { + ID respjson.Field + Type respjson.Field + ExtraFields map[string]respjson.Field + raw string + } `json:"-"` +} + +// Returns the unmodified JSON received from the API +func (r AuthContextPrincipal) RawJSON() string { return r.JSON.raw } +func (r *AuthContextPrincipal) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} diff --git a/authcontext_test.go b/authcontext_test.go new file mode 100644 index 0000000..2d8dcb2 --- /dev/null +++ b/authcontext_test.go @@ -0,0 +1,37 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package kernel_test + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/kernel/kernel-go-sdk" + "github.com/kernel/kernel-go-sdk/internal/testutil" + "github.com/kernel/kernel-go-sdk/option" +) + +func TestAuthContextGet(t *testing.T) { + t.Skip("Mock server tests are disabled") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := kernel.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("My API Key"), + ) + _, err := client.Auth.Context.Get(context.TODO()) + if err != nil { + var apierr *kernel.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} diff --git a/browser.go b/browser.go index 30e19b1..1fb4801 100644 --- a/browser.go +++ b/browser.go @@ -273,6 +273,9 @@ type BrowserNewResponse struct { Pool BrowserPoolRef `json:"pool"` // Browser profile metadata. Profile Profile `json:"profile"` + // Whether changes made during this browser session are saved back to its profile + // when the session ends. Omitted when no profile is attached. + ProfileSaveChanges bool `json:"profile_save_changes"` // ID of the proxy associated with this browser session, if any. ProxyID string `json:"proxy_id"` // URL the session was asked to navigate to on creation, if any. Recorded for @@ -319,6 +322,7 @@ type BrowserNewResponse struct { Name respjson.Field Pool respjson.Field Profile respjson.Field + ProfileSaveChanges respjson.Field ProxyID respjson.Field StartURL respjson.Field Tags respjson.Field @@ -373,6 +377,9 @@ type BrowserGetResponse struct { Pool BrowserPoolRef `json:"pool"` // Browser profile metadata. Profile Profile `json:"profile"` + // Whether changes made during this browser session are saved back to its profile + // when the session ends. Omitted when no profile is attached. + ProfileSaveChanges bool `json:"profile_save_changes"` // ID of the proxy associated with this browser session, if any. ProxyID string `json:"proxy_id"` // URL the session was asked to navigate to on creation, if any. Recorded for @@ -419,6 +426,7 @@ type BrowserGetResponse struct { Name respjson.Field Pool respjson.Field Profile respjson.Field + ProfileSaveChanges respjson.Field ProxyID respjson.Field StartURL respjson.Field Tags respjson.Field @@ -473,6 +481,9 @@ type BrowserUpdateResponse struct { Pool BrowserPoolRef `json:"pool"` // Browser profile metadata. Profile Profile `json:"profile"` + // Whether changes made during this browser session are saved back to its profile + // when the session ends. Omitted when no profile is attached. + ProfileSaveChanges bool `json:"profile_save_changes"` // ID of the proxy associated with this browser session, if any. ProxyID string `json:"proxy_id"` // URL the session was asked to navigate to on creation, if any. Recorded for @@ -519,6 +530,7 @@ type BrowserUpdateResponse struct { Name respjson.Field Pool respjson.Field Profile respjson.Field + ProfileSaveChanges respjson.Field ProxyID respjson.Field StartURL respjson.Field Tags respjson.Field @@ -573,6 +585,9 @@ type BrowserListResponse struct { Pool BrowserPoolRef `json:"pool"` // Browser profile metadata. Profile Profile `json:"profile"` + // Whether changes made during this browser session are saved back to its profile + // when the session ends. Omitted when no profile is attached. + ProfileSaveChanges bool `json:"profile_save_changes"` // ID of the proxy associated with this browser session, if any. ProxyID string `json:"proxy_id"` // URL the session was asked to navigate to on creation, if any. Recorded for @@ -619,6 +634,7 @@ type BrowserListResponse struct { Name respjson.Field Pool respjson.Field Profile respjson.Field + ProfileSaveChanges respjson.Field ProxyID respjson.Field StartURL respjson.Field Tags respjson.Field diff --git a/browserpool.go b/browserpool.go index c479e8b..641cc2d 100644 --- a/browserpool.go +++ b/browserpool.go @@ -360,6 +360,9 @@ type BrowserPoolAcquireResponse struct { Pool BrowserPoolRef `json:"pool"` // Browser profile metadata. Profile Profile `json:"profile"` + // Whether changes made during this browser session are saved back to its profile + // when the session ends. Omitted when no profile is attached. + ProfileSaveChanges bool `json:"profile_save_changes"` // ID of the proxy associated with this browser session, if any. ProxyID string `json:"proxy_id"` // URL the session was asked to navigate to on creation, if any. Recorded for @@ -406,6 +409,7 @@ type BrowserPoolAcquireResponse struct { Name respjson.Field Pool respjson.Field Profile respjson.Field + ProfileSaveChanges respjson.Field ProxyID respjson.Field StartURL respjson.Field Tags respjson.Field diff --git a/invocation.go b/invocation.go index 9855eeb..a2bb44a 100644 --- a/invocation.go +++ b/invocation.go @@ -574,6 +574,9 @@ type InvocationListBrowsersResponseBrowser struct { Pool BrowserPoolRef `json:"pool"` // Browser profile metadata. Profile Profile `json:"profile"` + // Whether changes made during this browser session are saved back to its profile + // when the session ends. Omitted when no profile is attached. + ProfileSaveChanges bool `json:"profile_save_changes"` // ID of the proxy associated with this browser session, if any. ProxyID string `json:"proxy_id"` // URL the session was asked to navigate to on creation, if any. Recorded for @@ -620,6 +623,7 @@ type InvocationListBrowsersResponseBrowser struct { Name respjson.Field Pool respjson.Field Profile respjson.Field + ProfileSaveChanges respjson.Field ProxyID respjson.Field StartURL respjson.Field Tags respjson.Field