openlane

package module
v0.3.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 31, 2025 License: Apache-2.0 Imports: 18 Imported by: 0

README

go-client

A Go client library for interacting with the Openlane API.

Installation

go get github.com/theopenlane/go-client

Features

  • Full GraphQL and REST API support
  • Built-in pagination support
  • Type-safe queries and mutations
  • Authentication handling
  • Comprehensive query operations (CRUD)

Usage

Basic Setup
    import (
        openlane "github.com/theopenlane/go-client"
    )

    // get the api token
    apiToken := os.Getenv("OPENLANE_API_TOKEN")

	// Initialize the client
	client, err := openlane.New(
		openlane.WithAPIToken(apiToken),
	)
Basic Queries
Get a Resource by ID
ctx := context.Background()

// Get a control by ID
control, err := client.GetControlByID(ctx, "control-id")
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Control: %s\n", control.Control.RefCode)
Get All Resources
// Get all controls you have access to view
controls, err := client.GetAllControls(ctx, first, last, after, before, orderBy)
if err != nil {
    log.Fatal(err)
}

for _, ctrl := range controls.Edges {
    fmt.Printf("Control: %s - %s\n", ctrl.Node.RefCode, ctrl.Node.Title)
}
Pagination

The client supports cursor-based pagination using first, last, after, and before parameters.

Forward Pagination
// Get first 10 controls
pageSize := int64(10)
after := (*string)(nil)

for {
		response, err := client.GetControls(ctx, &pageSize, nil, after, nil, nil, nil)
		if err != nil {
			return nil, fmt.Errorf("failed to fetch controls: %w", err)
		}

		// Collect results from current page
		for _, edge := range response.Controls.Edges {
			allControls = append(allControls, edge.Node)
		}

		// Check if there are more pages
		if !response.Controls.PageInfo.HasNextPage {
			break
		}

		// Update cursor for next page
		after = response.Controls.PageInfo.EndCursor
	}
Backward Pagination
// Get last 10 controls
pageSize := int64(10)
before := (*string)(nil)

for {
		response, err := client.GetControls(ctx, &pageSize, nil, nil, before, nil, nil)
		if err != nil {
			return nil, fmt.Errorf("failed to fetch controls: %w", err)
		}

		// Collect results from current page
		for _, edge := range response.Controls.Edges {
			allControls = append(allControls, edge.Node)
		}

		// Check if there are more pages
		if !response.Controls.PageInfo.HasPreviousPage {
			break
		}

		// Update cursor for next page
		after = response.Controls.PageInfo.StartCursor
	}

For a full example of pagination through all results, refer to the example:

go run example/main.go
Fetched page with 10 controls (total so far: 10 of 61)
Fetched page with 10 controls (total so far: 20 of 61)
Fetched page with 10 controls (total so far: 30 of 61)
Fetched page with 10 controls (total so far: 40 of 61)
Fetched page with 10 controls (total so far: 50 of 61)
Fetched page with 10 controls (total so far: 60 of 61)
Fetched page with 1 controls (total so far: 61 of 61)
Total controls fetched: 61

1. [A1.1]
   Category: Availability
...
Filtering and Ordering
Using Where Clauses

All Get and GetAll functions support pagination and ordering, the Get functions support where filters as well.

// Get controls with specific filters
	pageSize := int64(10)

    // where filter
	where := &graphclient.ControlWhereInput{
		ReferenceFramework: lo.ToPtr("SOC 2"),
		SystemOwned:        lo.ToPtr(true),
	}

    // order fields
	orderBy := &graphclient.ControlOrder{
		Field:     graphclient.ControlOrderFieldRefCode,
		Direction: graphclient.OrderDirectionAsc,
	}
	after := (*string)(nil)

    client.GetControls(ctx, &pageSize, nil, after, nil, where, []*graphclient.ControlOrder{orderBy})
    if err != nil {
        log.Fatal(err)
    }
Mutations
Create a Resource
	input := graphclient.CreateControlInput{
		RefCode: "AC-001",
	}

	resp, err := client.CreateControl(ctx, input)
	if err != nil {
		return nil, fmt.Errorf("failed to create control: %w", err)
	}

	fmt.Printf("Created control with ID: %s, RefCode: %s\n", resp.CreateControl.Control.ID, resp.CreateControl.Control.RefCode)
Update a Resource
	input := graphclient.UpdateControlInput{
		Description: lo.ToPtr("description of the control"),
	}

	resp, err := client.UpdateControl(ctx, "control-id", input)
	if err != nil {
		return nil, fmt.Errorf("failed to create control: %w", err)
	}

	fmt.Printf("Updated control: %s\n", resp.UpdateControl.Control.ID)
Delete a Resource
	resp, err := client.DeleteControl(ctx, "control-id")
	if err != nil {
		return nil, fmt.Errorf("failed to delete control: %w", err)
	}
	fmt.Printf("Deleted Control: %s\n", resp.DeleteControl.DeletedID)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

Apache License Version 2.0,

Support

For questions and support, please open an issue on GitHub.

Documentation

Overview

Package openlane contains the go client to interact with the openlane api

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrFailedToGetOauthToken is returned when the client fails to get an OAuth2 token
	ErrFailedToGetOauthToken = errors.New("failed to get oauth2 token")
	// ErrNoCookieJarSet is returned when the client does not have a cookie jar, cannot set cookies
	ErrNoCookieJarSet = errors.New("client does not have a cookie jar, cannot set cookies")
	// ErrEmptyCSRFToken is returned when an empty CSRF token is received from the server
	ErrEmptyCSRFToken = errors.New("empty csrf token received from server, cannot continue")
	// ErrCSRFCookieNotFound is returned when the CSRF cookie is not found in the cookie jar
	ErrCSRFCookieNotFound = errors.New("csrf cookie not found in cookie jar, cannot continue")
)

Functions

func GetErrorCode

func GetErrorCode(err error) string

GetErrorCode returns the error code from the GraphQL error extensions

func GetErrorMessage

func GetErrorMessage(err error) string

GetErrorMessage returns the error message from the GraphQL error extensions

func GraphRequestPath

func GraphRequestPath(config *Config) string

GraphRequestPath returns the full URL path for the GraphQL endpoint

func WithCSRFTokenInterceptor

func WithCSRFTokenInterceptor(token string) clientv2.RequestInterceptor

WithCSRFTokenInterceptor adds a CSRF token interceptor to the client request in the header

func WithEmptyInterceptor

func WithEmptyInterceptor() clientv2.RequestInterceptor

WithEmptyInterceptor adds an empty interceptor

func WithImpersonationInterceptor

func WithImpersonationInterceptor(userID string, orgID string) clientv2.RequestInterceptor

WithImpersonationInterceptor adds impersonation headers to the request

func WithLoggingInterceptor

func WithLoggingInterceptor() clientv2.RequestInterceptor

WithLoggingInterceptor adds a http debug logging interceptor

func WithOrganizationHeader

func WithOrganizationHeader(orgID string) clientv2.RequestInterceptor

WithOrganizationHeader adds the organization id header to the request this is required when using personal access tokens that are authorized for more than one organization

Types

type APIv1

type APIv1 struct {
	// Config is the configuration for the APIv1 client
	Config *Config
	// Requester is the HTTP client for the APIv1 client
	Requester *httpsling.Requester
}

APIv1 implements the Client interface and provides methods to interact with the API

func (*APIv1) AcceptInvite

func (s *APIv1) AcceptInvite(ctx context.Context, in *api.InviteRequest) (out *api.InviteReply, err error)

AcceptInvite accepts an invite to join an organization

func (*APIv1) AccountAccess

func (s *APIv1) AccountAccess(ctx context.Context, in *api.AccountAccessRequest) (out *api.AccountAccessReply, err error)

AccountAccess checks if a subject has access to an object.

func (*APIv1) AccountFeatures

func (s *APIv1) AccountFeatures(ctx context.Context, in *api.AccountFeaturesRequest) (out *api.AccountFeaturesReply, err error)

AccountFeatures lists features a user has for an organization.

func (*APIv1) AccountRoles

func (s *APIv1) AccountRoles(ctx context.Context, in *api.AccountRolesRequest) (out *api.AccountRolesReply, err error)

AccountRoles lists the relations a subject has in relation to an object.

func (*APIv1) AccountRolesOrganization

func (s *APIv1) AccountRolesOrganization(ctx context.Context, in *api.AccountRolesOrganizationRequest) (out *api.AccountRolesOrganizationReply, err error)

AccountRolesOrganization lists roles a user has for an organization.

func (*APIv1) ForgotPassword

func (s *APIv1) ForgotPassword(ctx context.Context, in *api.ForgotPasswordRequest) (out *api.ForgotPasswordReply, err error)

ForgotPassword sends a password reset email to the user

func (*APIv1) Login

func (s *APIv1) Login(ctx context.Context, in *api.LoginRequest) (out *api.LoginReply, err error)

Login to the API

func (*APIv1) OAuthRegister

func (s *APIv1) OAuthRegister(ctx context.Context, in *api.OauthTokenRequest) (out *api.LoginReply, err error)

OAuthRegister registers or logs in a user using an OAuth provider.

func (*APIv1) Refresh

func (s *APIv1) Refresh(ctx context.Context, in *api.RefreshRequest) (out *api.RefreshReply, err error)

Refresh a user's access token

func (*APIv1) Register

func (s *APIv1) Register(ctx context.Context, in *api.RegisterRequest) (out *api.RegisterReply, err error)

Register a new user with the API

func (*APIv1) RegisterRunner

func (s *APIv1) RegisterRunner(ctx context.Context, in *api.JobRunnerRegistrationRequest) (out *api.JobRunnerRegistrationReply, err error)

RegisterRunner registers a new job runner node with the server.

func (*APIv1) ResendEmail

func (s *APIv1) ResendEmail(ctx context.Context, in *api.ResendRequest) (out *api.ResendReply, err error)

ResendEmail resends the verification email to the user

func (*APIv1) ResetPassword

func (s *APIv1) ResetPassword(ctx context.Context, in *api.ResetPasswordRequest) (out *api.ResetPasswordReply, err error)

ResetPassword resets the user's password

func (*APIv1) Switch

Switch the current organization context

func (*APIv1) ValidateTOTP

func (s *APIv1) ValidateTOTP(ctx context.Context, in *api.TFARequest) (out *api.TFAReply, err error)

ValidateTOTP validates a user's TOTP or recovery code.

func (*APIv1) VerifyEmail

func (s *APIv1) VerifyEmail(ctx context.Context, in *api.VerifyRequest) (out *api.VerifyReply, err error)

VerifyEmail verifies the email address of a user

func (*APIv1) VerifySubscriberEmail

func (s *APIv1) VerifySubscriberEmail(ctx context.Context, in *api.VerifySubscribeRequest) (out *api.VerifySubscribeReply, err error)

VerifySubscriberEmail verifies the email address of a subscriber

func (*APIv1) Webfinger

func (s *APIv1) Webfinger(ctx context.Context, resource string) (out *api.SSOStatusReply, err error)

Webfinger retrieves SSO status information via the webfinger endpoint.

type AuthenticationError

type AuthenticationError struct {
	// StatusCode is the http response code that was returned
	StatusCode int
	// Body of the response
	Body string
}

AuthenticationError is returned when a user cannot be authenticated

func (*AuthenticationError) Error

func (e *AuthenticationError) Error() string

Error returns the AuthenticationError in string format

type Authorization

type Authorization struct {
	// BearerToken is the bearer token to be used in the authorization header
	// this can be the access token, api token, or personal access token
	BearerToken string
	// Session is the session cookie to be used in the request
	// this is required for requests using the access token
	Session string
}

Authorization contains the bearer token and optional session cookie

func NewAuthorization

func NewAuthorization(creds Credentials) (Authorization, error)

NewAuthorization creates a new Authorization from the given Credentials

func (Authorization) AccessToken

func (a Authorization) AccessToken() (string, error)

AccessToken implements the credentials interface and performs limited validation

func (Authorization) GetSession

func (a Authorization) GetSession() string

GetSession implements the credentials interface session is not always required so no validation is provided

func (Authorization) SetAuthorizationHeader

func (a Authorization) SetAuthorizationHeader(req *http.Request)

SetAuthorizationHeader sets the authorization header on the request if not already set

func (Authorization) SetSessionCookie

func (a Authorization) SetSessionCookie(req *http.Request)

SetSessionCookie sets the session cookie on the request if the session is not empty

func (Authorization) WithAuthorization

func (a Authorization) WithAuthorization() clientv2.RequestInterceptor

WithAuthorization adds the authorization header and session to the client request

type Client added in v0.2.0

type Client struct {
	// RestClient is the REST client for the Openlane API performing REST operations such as login, switch org, etc.
	RestClient
	// GraphClient is the GraphQL client for the Openlane API performing GraphQL operations
	graphclient.GraphClient
}

Client wraps the Openlane API client methods to form a single client interface

func New

func New(opts ...ClientOption) (*Client, error)

New creates a new API v1 client that implements the Client interface

func (*Client) AccessToken added in v0.2.0

func (c *Client) AccessToken() (_ string, err error)

AccessToken returns the access token cached on the client or an error if it is not available. This method is primarily used for testing but can be used to fetch the access token for debugging or inspection if necessary.

func (*Client) ClearAuthTokens added in v0.2.0

func (c *Client) ClearAuthTokens()

ClearAuthTokens clears the access and refresh tokens on the client Jar.

func (*Client) Config added in v0.2.0

func (c *Client) Config() *Config

Config is the configuration for the APIv1 client

func (*Client) Cookies added in v0.2.0

func (c *Client) Cookies() ([]*http.Cookie, error)

Cookies returns the cookies set from the previous request(s) on the client Jar.

func (*Client) GetAuthTokensFromCookieJar added in v0.2.0

func (c *Client) GetAuthTokensFromCookieJar() *oauth2.Token

GetAuthTokensFromCookieJar gets the access and refresh tokens from the cookie jar and returns them as an oauth2.Token if they are set

func (*Client) GetSessionFromCookieJar added in v0.2.0

func (c *Client) GetSessionFromCookieJar() (sessionID string, err error)

GetSessionFromCookieJar parses the cookie jar for the session cookie

func (*Client) HTTPSlingRequester added in v0.2.0

func (c *Client) HTTPSlingRequester() *httpsling.Requester

HTTPSlingRequester is the http client for the APIv1 client

func (*Client) InitCSRF added in v0.2.0

func (c *Client) InitCSRF(ctx context.Context) (string, error)

InitCSRF fetches a CSRF token and sets it on the client for subsequent requests. It returns an error if the token cannot be obtained.

func (*Client) RefreshToken added in v0.2.0

func (c *Client) RefreshToken() (_ string, err error)

RefreshToken returns the refresh token cached on the client or an error if it is not available. This method is primarily used for testing but can be used to fetch the refresh token for debugging or inspection if necessary.

func (*Client) SetAuthTokens added in v0.2.0

func (c *Client) SetAuthTokens(access, refresh string) error

SetAuthTokens is a helper function to set the access and refresh tokens on the client cookie jar.

type ClientOption

type ClientOption func(c *APIv1) error

ClientOption allows us to configure the APIv1 client when it is created

func WithAPIToken added in v0.2.0

func WithAPIToken(apiToken string) ClientOption

WithAPIToken sets the API token for the APIv1 client This is the recommended way to authenticate using an API token or personal access token use WithCredentials for more advanced authentication methods

func WithBaseURL

func WithBaseURL(baseURL string) ClientOption

WithBaseURL sets the base URL for the APIv1 client

func WithCSRFToken

func WithCSRFToken(token string) ClientOption

WithCSRFToken sets the CSRF token header on the client for all requests

func WithClientV2Option

func WithClientV2Option(option clientv2.Options) ClientOption

WithClientV2Option sets the clientv2 options for the APIv1 client

func WithCredentials

func WithCredentials(creds Credentials) ClientOption

WithCredentials sets the credentials for the APIv1 client

func WithGraphQueryEndpoint

func WithGraphQueryEndpoint(endpoint string) ClientOption

WithGraphQueryEndpoint sets the graph query endpoint for the APIv1 client

func WithInterceptors

func WithInterceptors(interceptors clientv2.RequestInterceptor) ClientOption

WithInterceptors sets the interceptors for the APIv1 client

func WithTransport

func WithTransport(transport http.RoundTripper) ClientOption

WithTransport sets the transport for the APIv1 client

type Config

type Config struct {
	// BaseURL is the base URL for the API
	BaseURL *url.URL `json:"baseUrl" yaml:"base_url" default:"https://api.theopenlane.io"`
	// GraphQLPath is the path to the GraphQL endpoint
	GraphQLPath string `json:"graphqlPath" default:"/query"`
	// Interceptors are the request interceptors for the graph client
	Interceptors []clientv2.RequestInterceptor
	// Credentials are the credentials for the client
	Credentials Credentials
	// Clientv2Options are the options for the graph client
	Clientv2Options clientv2.Options
}

Config is the configuration for the API client

func NewDefaultConfig

func NewDefaultConfig() Config

NewDefaultConfig returns a new default configuration for the API client and connecting to the production environment

func NewLocalConfig added in v0.2.0

func NewLocalConfig() Config

NewLocalConfig returns a new default configuration for the API client for local development

type Credentials

type Credentials interface {
	AccessToken() (string, error)
	GetSession() string
}

Credentials provides a basic interface for loading credentials

type Reauthenticator

type Reauthenticator interface {
	Refresh(context.Context, *api.RefreshRequest) (*api.RefreshReply, error)
}

A Reauthenticator generates new access and refresh pair given a valid refresh token

type RequestError

type RequestError struct {
	// StatusCode is the http response code that was returned
	StatusCode int
	// Body of the response
	Body string
}

RequestError is a generic error when a request with the client fails

func (*RequestError) Error

func (e *RequestError) Error() string

Error returns the RequestError in string format

type RestClient added in v0.2.0

type RestClient interface {
	// Register a new user with the API
	Register(context.Context, *api.RegisterRequest) (*api.RegisterReply, error)
	// Login to the API
	Login(context.Context, *api.LoginRequest) (*api.LoginReply, error)
	// Refresh a user's access token
	Refresh(context.Context, *api.RefreshRequest) (*api.RefreshReply, error)
	// Switch the current organization context
	Switch(context.Context, *api.SwitchOrganizationRequest) (*api.SwitchOrganizationReply, error)
	// VerifyEmail verifies the email address of a user
	VerifyEmail(context.Context, *api.VerifyRequest) (*api.VerifyReply, error)
	// ResendEmail re-sends the verification email to the user
	ResendEmail(context.Context, *api.ResendRequest) (*api.ResendReply, error)
	// ForgotPassword sends a password reset email to the user
	ForgotPassword(context.Context, *api.ForgotPasswordRequest) (*api.ForgotPasswordReply, error)
	// ResetPassword resets the user's password
	ResetPassword(context.Context, *api.ResetPasswordRequest) (*api.ResetPasswordReply, error)
	// AcceptInvite accepts an invite to join an organization
	AcceptInvite(context.Context, *api.InviteRequest) (*api.InviteReply, error)
	// Webfinger retrieves SSO status information via the webfinger endpoint
	Webfinger(context.Context, string) (*api.SSOStatusReply, error)
	// OAuthRegister registers or logs in a user using an OAuth provider
	OAuthRegister(context.Context, *api.OauthTokenRequest) (*api.LoginReply, error)
	// ValidateTOTP validates a user's TOTP or recovery code
	ValidateTOTP(context.Context, *api.TFARequest) (*api.TFAReply, error)
	// AccountAccess checks if a subject has a specific relation to an object
	AccountAccess(context.Context, *api.AccountAccessRequest) (*api.AccountAccessReply, error)
	// AccountRoles lists the relations a subject has in relation to an object
	AccountRoles(context.Context, *api.AccountRolesRequest) (*api.AccountRolesReply, error)
	// AccountRolesOrganization lists roles a user has for an organization
	AccountRolesOrganization(context.Context, *api.AccountRolesOrganizationRequest) (*api.AccountRolesOrganizationReply, error)
	// AccountFeatures lists features a user has for an organization
	AccountFeatures(context.Context, *api.AccountFeaturesRequest) (*api.AccountFeaturesReply, error)
	// RegisterRunner registers a new job runner node with the server
	RegisterRunner(context.Context, *api.JobRunnerRegistrationRequest) (*api.JobRunnerRegistrationReply, error)
}

RestClient is the interface that wraps the openlane API REST client methods

func NewRestClient

func NewRestClient(config Config, opts ...ClientOption) (_ RestClient, err error)

NewRestClient creates a new API v1 client that implements the Openlane Client interface

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL