Documentation
¶
Overview ¶
Package airlock provides a client SDK for the Airlock Gateway API.
The client covers all enforcer-side endpoints: artifact submission, exchange polling, pairing management, presence tracking, and gateway discovery.
Index ¶
- type AirlockAuthClient
- func (c *AirlockAuthClient) CurrentAccessToken() string
- func (c *AirlockAuthClient) Discover(ctx context.Context) (*OidcDiscoveryResult, error)
- func (c *AirlockAuthClient) ExchangeCode(ctx context.Context, code, redirectURI, codeVerifier string) (*TokenResponse, error)
- func (c *AirlockAuthClient) GetAccessToken(ctx context.Context) (string, error)
- func (c *AirlockAuthClient) GetAuthorizationURL(ctx context.Context, redirectURI string) (*AuthCodeRequest, error)
- func (c *AirlockAuthClient) GetTokenState() (string, string, time.Time)
- func (c *AirlockAuthClient) IsLoggedIn() bool
- func (c *AirlockAuthClient) IsTokenExpired() bool
- func (c *AirlockAuthClient) Login(ctx context.Context, onUserCode func(*DeviceCodeInfo)) (*TokenResponse, error)
- func (c *AirlockAuthClient) LoginWithAuthCode(ctx context.Context, onBrowserURL func(string), redirectPort int) (*TokenResponse, error)
- func (c *AirlockAuthClient) Logout(ctx context.Context) error
- func (c *AirlockAuthClient) RefreshToken(ctx context.Context) (*TokenResponse, error)
- func (c *AirlockAuthClient) RestoreTokens(access, refresh string, expiresAt time.Time)
- type AirlockAuthOptions
- type ArtifactSubmitBody
- type ArtifactSubmitRequest
- type AuthCodeRequest
- type CiphertextRef
- type Client
- func (c *Client) CheckConsent() (string, error)
- func (c *Client) Echo() (*EchoResponse, error)
- func (c *Client) GetEffectiveDndPolicies(enforcerID, workspaceID, sessionID string) (*DndEffectiveResponse, error)
- func (c *Client) GetExchangeStatus(requestID string) (*ExchangeStatusResponse, error)
- func (c *Client) GetPairingStatus(nonce string) (*PairingStatusResponse, error)
- func (c *Client) InitiatePairing(req PairingInitiateRequest) (*PairingInitiateResponse, error)
- func (c *Client) RevokePairing(routingToken string) (*PairingRevokeResponse, error)
- func (c *Client) SendHeartbeat(req PresenceHeartbeatRequest) error
- func (c *Client) SetBearerToken(token string) *Client
- func (c *Client) SubmitArtifact(req ArtifactSubmitRequest) (string, error)
- func (c *Client) WaitForDecision(requestID string, timeoutSec int) (*DecisionDeliverEnvelope, error)
- func (c *Client) WithHTTPClient(hc *http.Client) *Client
- func (c *Client) WithdrawExchange(requestID string) error
- type ConsentErrorInfo
- type DecisionDeliverBody
- type DecisionDeliverEnvelope
- type DeviceCodeInfo
- type DndEffectiveResponse
- type DndPolicy
- type EchoResponse
- type ExchangeStatusBody
- type ExchangeStatusResponse
- type GatewayError
- type HarpEnvelope
- type OidcDiscoveryResult
- type PairingInitiateRequest
- type PairingInitiateResponse
- type PairingRevokeResponse
- type PairingStatusResponse
- type PresenceHeartbeatRequest
- type RecipInfo
- type SenderInfo
- type TokenErrorResponse
- type TokenResponse
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AirlockAuthClient ¶
type AirlockAuthClient struct {
Options AirlockAuthOptions
// contains filtered or unexported fields
}
AirlockAuthClient handles user authentication via Device Authorization Grant (RFC 8628) and Authorization Code + PKCE (RFC 7636).
func NewAirlockAuthClient ¶
func NewAirlockAuthClient(opts AirlockAuthOptions) *AirlockAuthClient
NewAirlockAuthClient creates a new AirlockAuthClient.
func (*AirlockAuthClient) CurrentAccessToken ¶
func (c *AirlockAuthClient) CurrentAccessToken() string
CurrentAccessToken returns the cached access token, or empty if none.
func (*AirlockAuthClient) Discover ¶
func (c *AirlockAuthClient) Discover(ctx context.Context) (*OidcDiscoveryResult, error)
Discover fetches the OIDC discovery document from Keycloak.
func (*AirlockAuthClient) ExchangeCode ¶
func (c *AirlockAuthClient) ExchangeCode(ctx context.Context, code, redirectURI, codeVerifier string) (*TokenResponse, error)
ExchangeCode exchanges an authorization code for tokens (Auth Code + PKCE).
func (*AirlockAuthClient) GetAccessToken ¶
func (c *AirlockAuthClient) GetAccessToken(ctx context.Context) (string, error)
GetAccessToken returns a valid access token, auto-refreshing if needed.
func (*AirlockAuthClient) GetAuthorizationURL ¶
func (c *AirlockAuthClient) GetAuthorizationURL(ctx context.Context, redirectURI string) (*AuthCodeRequest, error)
GetAuthorizationURL builds the authorization URL for the Auth Code + PKCE flow. Use this when you manage the browser redirect yourself.
func (*AirlockAuthClient) GetTokenState ¶
func (c *AirlockAuthClient) GetTokenState() (string, string, time.Time)
GetTokenState gets tokens for persistent storage.
func (*AirlockAuthClient) IsLoggedIn ¶
func (c *AirlockAuthClient) IsLoggedIn() bool
IsLoggedIn returns true if we have a token.
func (*AirlockAuthClient) IsTokenExpired ¶
func (c *AirlockAuthClient) IsTokenExpired() bool
IsTokenExpired returns true if the token is expired and needs refresh.
func (*AirlockAuthClient) Login ¶
func (c *AirlockAuthClient) Login(ctx context.Context, onUserCode func(*DeviceCodeInfo)) (*TokenResponse, error)
Login starts the Device Authorization Grant flow. It calls onUserCode so the user can be prompted to open the verification URI and enter code. It polls the token endpoint until the user grants access or it times out.
func (*AirlockAuthClient) LoginWithAuthCode ¶
func (c *AirlockAuthClient) LoginWithAuthCode(ctx context.Context, onBrowserURL func(string), redirectPort int) (*TokenResponse, error)
LoginWithAuthCode starts the Authorization Code + PKCE flow. It starts a local HTTP server to receive the callback and exchanges the code for tokens. Best for Web and Mobile enforcer apps.
func (*AirlockAuthClient) Logout ¶
func (c *AirlockAuthClient) Logout(ctx context.Context) error
Logout revokes the refresh token and clears state.
func (*AirlockAuthClient) RefreshToken ¶
func (c *AirlockAuthClient) RefreshToken(ctx context.Context) (*TokenResponse, error)
RefreshToken refreshes the access token.
func (*AirlockAuthClient) RestoreTokens ¶
func (c *AirlockAuthClient) RestoreTokens(access, refresh string, expiresAt time.Time)
RestoreTokens restores tokens from persistent storage.
type AirlockAuthOptions ¶
type AirlockAuthOptions struct {
// KeycloakRealmURL is the base URL of the realm (e.g. "https://auth.airlocks.io/realms/airlock").
KeycloakRealmURL string
// OIDCClientID is the client ID for device authorization. Defaults to "airlock-integrations".
OIDCClientID string
// HTTPClient is an optional custom HTTP client.
HTTPClient *http.Client
}
AirlockAuthOptions configures the AirlockAuthClient.
type ArtifactSubmitBody ¶
type ArtifactSubmitBody struct {
ArtifactType string `json:"artifactType"`
ArtifactHash string `json:"artifactHash"`
Ciphertext CiphertextRef `json:"ciphertext"`
ExpiresAt string `json:"expiresAt"`
Metadata map[string]string `json:"metadata,omitempty"`
}
ArtifactSubmitBody is the body of an artifact.submit envelope.
type ArtifactSubmitRequest ¶
type ArtifactSubmitRequest struct {
EnforcerID string
ArtifactType string
ArtifactHash string
Ciphertext CiphertextRef
ExpiresAt *time.Time
Metadata map[string]string
RequestID string
}
ArtifactSubmitRequest holds options for building an artifact submission.
type AuthCodeRequest ¶
type AuthCodeRequest struct {
AuthorizationURL string
State string
CodeVerifier string
RedirectURI string
}
AuthCodeRequest holds the authorization URL and PKCE verifier for apps that manage the browser redirect themselves.
type CiphertextRef ¶
type CiphertextRef struct {
Alg string `json:"alg"`
Data string `json:"data"`
Nonce string `json:"nonce,omitempty"`
Tag string `json:"tag,omitempty"`
Aad string `json:"aad,omitempty"`
}
CiphertextRef is an encrypted payload reference.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is an HTTP client for the Airlock Integrations Gateway API. Supports both Bearer token and enforcer app (ClientId/ClientSecret) auth.
func NewClient ¶
NewClient creates a new Airlock Gateway client with Bearer token auth. The baseURL should be the gateway's root URL (e.g., "https://igw.example.com").
func NewClientWithCredentials ¶
NewClientWithCredentials creates a new Airlock Gateway client with enforcer app (ClientId/ClientSecret) authentication.
func (*Client) CheckConsent ¶
CheckConsent calls GET /v1/consent/status to check if the user has consented to this enforcer app. Returns the consent status string (e.g. "approved"). Throws GatewayError with error_code "app_consent_required", "app_consent_pending", or "app_consent_denied" if consent is not granted.
func (*Client) Echo ¶
func (c *Client) Echo() (*EchoResponse, error)
Echo calls GET /echo for gateway discovery and health.
func (*Client) GetEffectiveDndPolicies ¶
func (c *Client) GetEffectiveDndPolicies(enforcerID, workspaceID, sessionID string) (*DndEffectiveResponse, error)
GetEffectiveDndPolicies calls GET /v1/policy/dnd/effective and returns the effective policies for the given enforcer/workspace/session.
func (*Client) GetExchangeStatus ¶
func (c *Client) GetExchangeStatus(requestID string) (*ExchangeStatusResponse, error)
GetExchangeStatus calls GET /v1/exchanges/{requestId}.
func (*Client) GetPairingStatus ¶
func (c *Client) GetPairingStatus(nonce string) (*PairingStatusResponse, error)
GetPairingStatus calls GET /v1/pairing/{nonce}/status.
func (*Client) InitiatePairing ¶
func (c *Client) InitiatePairing(req PairingInitiateRequest) (*PairingInitiateResponse, error)
InitiatePairing calls POST /v1/pairing/initiate.
func (*Client) RevokePairing ¶
func (c *Client) RevokePairing(routingToken string) (*PairingRevokeResponse, error)
RevokePairing calls POST /v1/pairing/revoke.
func (*Client) SendHeartbeat ¶
func (c *Client) SendHeartbeat(req PresenceHeartbeatRequest) error
SendHeartbeat calls POST /v1/presence/heartbeat.
func (*Client) SetBearerToken ¶
SetBearerToken sets (or clears) the user Bearer token for dual-auth scenarios.
func (*Client) SubmitArtifact ¶
func (c *Client) SubmitArtifact(req ArtifactSubmitRequest) (string, error)
SubmitArtifact posts an artifact for approval. Returns the request ID.
func (*Client) WaitForDecision ¶
func (c *Client) WaitForDecision(requestID string, timeoutSec int) (*DecisionDeliverEnvelope, error)
WaitForDecision calls GET /v1/exchanges/{requestId}/wait with long-poll. Returns nil, nil if the server returns 204 (no decision yet).
func (*Client) WithHTTPClient ¶
WithHTTPClient sets a custom http.Client (useful for testing).
func (*Client) WithdrawExchange ¶
WithdrawExchange calls POST /v1/exchanges/{requestId}/withdraw.
type ConsentErrorInfo ¶
type ConsentErrorInfo struct {
Error string
Message string
ConsentURL string
AppName string
AppID string
}
ConsentErrorInfo contains details about a required/pending consent.
func ParseConsentError ¶
func ParseConsentError(statusCode int, responseBody []byte) *ConsentErrorInfo
ParseConsentError parses a consent error from an HTTP response payload.
type DecisionDeliverBody ¶
type DecisionDeliverBody struct {
ArtifactHash string `json:"artifactHash"`
Decision string `json:"decision"`
Reason string `json:"reason,omitempty"`
SignerKeyID string `json:"signerKeyId,omitempty"`
Nonce string `json:"nonce,omitempty"`
Signature string `json:"signature,omitempty"`
DecisionHash string `json:"decisionHash,omitempty"`
}
DecisionDeliverBody is the body of a decision.deliver envelope.
func (*DecisionDeliverBody) IsApproved ¶
func (d *DecisionDeliverBody) IsApproved() bool
IsApproved returns true if the decision is "approve".
func (*DecisionDeliverBody) IsRejected ¶
func (d *DecisionDeliverBody) IsRejected() bool
IsRejected returns true if the decision is "reject".
type DecisionDeliverEnvelope ¶
type DecisionDeliverEnvelope struct {
MsgID string `json:"msgId,omitempty"`
MsgType string `json:"msgType"`
RequestID string `json:"requestId"`
Body *DecisionDeliverBody `json:"body,omitempty"`
}
DecisionDeliverEnvelope wraps a decision.deliver response.
type DeviceCodeInfo ¶
type DeviceCodeInfo struct {
DeviceCode string `json:"device_code"`
UserCode string `json:"user_code"`
VerificationURI string `json:"verification_uri"`
VerificationURIComplete string `json:"verification_uri_complete,omitempty"`
ExpiresIn int `json:"expires_in"`
Interval int `json:"interval,omitempty"`
}
DeviceCodeInfo is the response from the device_authorization endpoint.
type DndEffectiveResponse ¶
type DndEffectiveResponse struct {
MsgType string `json:"msgType"`
RequestID string `json:"requestId"`
Body []DndPolicy `json:"body"`
}
DndEffectiveResponse is the response from GET /v1/policy/dnd/effective.
type DndPolicy ¶
type DndPolicy struct {
RequestID string `json:"requestId"`
ObjectType string `json:"objectType"`
WorkspaceID string `json:"workspaceId"`
SessionID string `json:"sessionId,omitempty"`
EnforcerID string `json:"enforcerId"`
PolicyMode string `json:"policyMode"`
TargetArtifactType string `json:"targetArtifactType,omitempty"`
ActionSelector map[string]interface{} `json:"actionSelector,omitempty"`
SelectorHash string `json:"selectorHash,omitempty"`
CreatedAt string `json:"createdAt,omitempty"`
ExpiresAt string `json:"expiresAt"`
}
DndPolicy represents a DND policy object as returned by the gateway.
type EchoResponse ¶
type EchoResponse struct {
UTC string `json:"utc"`
Local string `json:"local"`
Timezone string `json:"timezone"`
OffsetMinutes int `json:"offsetMinutes"`
}
EchoResponse is the response from GET /echo.
type ExchangeStatusBody ¶
type ExchangeStatusBody struct {
RequestID string `json:"requestId"`
State string `json:"state"`
CreatedAt string `json:"createdAt,omitempty"`
ExpiresAt string `json:"expiresAt,omitempty"`
ArtifactHash string `json:"artifactHash,omitempty"`
Decision interface{} `json:"decision,omitempty"`
}
ExchangeStatusBody holds exchange state information.
type ExchangeStatusResponse ¶
type ExchangeStatusResponse struct {
MsgType string `json:"msgType"`
RequestID string `json:"requestId"`
Body *ExchangeStatusBody `json:"body,omitempty"`
}
ExchangeStatusResponse wraps a GET /v1/exchanges/{id} response.
type GatewayError ¶
type GatewayError struct {
// HTTP status code.
StatusCode int
// Error code from the gateway (e.g., "no_approver", "quota_exceeded").
ErrorCode string
// Human-readable error message.
Message string
// Raw response body.
ResponseBody string
// Request ID associated with the failed operation.
RequestID string
}
GatewayError represents an error response from the Airlock Gateway.
func (*GatewayError) Error ¶
func (e *GatewayError) Error() string
func (*GatewayError) IsConflict ¶
func (e *GatewayError) IsConflict() bool
IsConflict returns true if the error is an idempotency conflict (409).
func (*GatewayError) IsExpired ¶
func (e *GatewayError) IsExpired() bool
IsExpired returns true if the error indicates an expired resource.
func (*GatewayError) IsPairingRevoked ¶
func (e *GatewayError) IsPairingRevoked() bool
IsPairingRevoked returns true if the pairing was revoked.
func (*GatewayError) IsQuotaExceeded ¶
func (e *GatewayError) IsQuotaExceeded() bool
IsQuotaExceeded returns true if the error is a rate-limit (429) or quota-exceeded response.
type HarpEnvelope ¶
type HarpEnvelope struct {
MsgID string `json:"msgId,omitempty"`
MsgType string `json:"msgType"`
RequestID string `json:"requestId"`
CreatedAt string `json:"createdAt,omitempty"`
ExpiresAt string `json:"expiresAt,omitempty"`
Sender *SenderInfo `json:"sender,omitempty"`
Recipient *RecipInfo `json:"recipient,omitempty"`
Body interface{} `json:"body,omitempty"`
}
HarpEnvelope is the HARP Gateway Wire Envelope.
type OidcDiscoveryResult ¶
type OidcDiscoveryResult struct {
TokenEndpoint string `json:"token_endpoint"`
DeviceAuthorizationEndpoint string `json:"device_authorization_endpoint"`
RevocationEndpoint string `json:"revocation_endpoint"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
}
OidcDiscoveryResult is the subset of OIDC config we need.
type PairingInitiateRequest ¶
type PairingInitiateRequest struct {
DeviceID string `json:"deviceId"`
EnforcerID string `json:"enforcerId"`
GatewayURL string `json:"gatewayUrl,omitempty"`
X25519PublicKey string `json:"x25519PublicKey,omitempty"`
EnforcerLabel string `json:"enforcerLabel,omitempty"`
WorkspaceName string `json:"workspaceName,omitempty"`
}
PairingInitiateRequest is the request body for POST /v1/pairing/initiate.
type PairingInitiateResponse ¶
type PairingInitiateResponse struct {
PairingNonce string `json:"pairingNonce"`
PairingCode string `json:"pairingCode"`
DeviceID string `json:"deviceId"`
GatewayURL string `json:"gatewayUrl,omitempty"`
ExpiresAt string `json:"expiresAt,omitempty"`
}
PairingInitiateResponse is the response from POST /v1/pairing/initiate.
type PairingRevokeResponse ¶
type PairingRevokeResponse struct {
Status string `json:"status"`
EnforcerID string `json:"enforcerId,omitempty"`
}
PairingRevokeResponse is the response from POST /v1/pairing/revoke.
type PairingStatusResponse ¶
type PairingStatusResponse struct {
PairingNonce string `json:"pairingNonce"`
State string `json:"state"`
ResponseJSON string `json:"responseJson,omitempty"`
RoutingToken string `json:"routingToken,omitempty"`
ExpiresAt string `json:"expiresAt,omitempty"`
}
PairingStatusResponse is the response from GET /v1/pairing/{nonce}/status.
type PresenceHeartbeatRequest ¶
type PresenceHeartbeatRequest struct {
EnforcerID string `json:"enforcerId"`
WorkspaceName string `json:"workspaceName,omitempty"`
EnforcerLabel string `json:"enforcerLabel,omitempty"`
}
PresenceHeartbeatRequest is the request body for POST /v1/presence/heartbeat.
type RecipInfo ¶
type RecipInfo struct {
EnforcerID string `json:"enforcerId,omitempty"`
ApproverID string `json:"approverId,omitempty"`
}
RecipInfo identifies the recipient of a HARP message.
type SenderInfo ¶
type SenderInfo struct {
EnforcerID string `json:"enforcerId,omitempty"`
ApproverID string `json:"approverId,omitempty"`
GatewayID string `json:"gatewayId,omitempty"`
}
SenderInfo identifies the sender of a HARP message.
type TokenErrorResponse ¶
type TokenErrorResponse struct {
Error string `json:"error"`
ErrorDescription string `json:"error_description,omitempty"`
}
TokenErrorResponse is the standard OAuth2 error response.