engine

package
v0.0.6 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: Apache-2.0 Imports: 33 Imported by: 0

Documentation

Overview

Package engine implements the export and reconcile logic behind the courier binary: pulling organization controls and mappings out of the Openlane API into controlfile documents, diffing local documents against the live system, and applying creates and updates back through the API

Index

Constants

View Source
const (
	// DefaultHost is the Openlane API host used when none is configured
	DefaultHost = "https://api.theopenlane.io"
	// DefaultDir is the store directory used when none is configured
	DefaultDir = "./data"
)
View Source
const DefaultConfigFile = "./config/.config.yaml"

DefaultConfigFile is the config file loaded from the working directory when no explicit path is given

Variables

View Source
var (
	// ErrMissingToken is returned when no API token is configured
	ErrMissingToken = errors.New("missing API token, set COURIER_TOKEN, add token to config/.config.yaml, or pass --token")

	// ErrMissingHost is returned when no API host is configured
	ErrMissingHost = errors.New("missing API host, set COURIER_HOST, add host to config/.config.yaml, or pass --host")

	// ErrMultipleControlsFound is returned when a mapped control refCode matches more than one control
	ErrMultipleControlsFound = errors.New("multiple controls found for refCode")

	// ErrMissingMarkdown is returned when a policy manifest entry references a markdown file that does not exist
	ErrMissingMarkdown = errors.New("policy markdown file not found")

	// ErrUnrecognizedFile is returned when a file does not validate as a control inventory or a policy manifest
	ErrUnrecognizedFile = errors.New("file is not a recognizable control inventory or policy manifest")

	// ErrPaginationStalled is returned when the API reports another page but does not advance the cursor
	ErrPaginationStalled = errors.New("pagination stalled, the API reported another page without advancing the cursor")
)

Functions

func LoadFile added in v0.0.2

func LoadFile(path string) (*Store, []Kind, error)

LoadFile parses a single YAML file and resolves whether it holds controls or a policy manifest by validating against the document schemas, the file name carries no meaning. Policy documents resolve relative to the file's directory

Types

type ApplyOptions added in v0.0.2

type ApplyOptions struct {
	// DryRun reports what apply would change without writing anything
	DryRun bool
}

ApplyOptions configures an apply run

type ApplyResult

type ApplyResult struct {
	// CreatedControls are the controls created, in order
	CreatedControls []Change `json:"createdControls,omitempty"`
	// UpdatedControls are the controls updated, in order, with the fields that differ
	UpdatedControls []Change `json:"updatedControls,omitempty"`
	// UnchangedControls counts controls that already match Openlane
	UnchangedControls int `json:"unchangedControls"`
	// CreatedMappings are the mappings created, in order, with the targets added
	CreatedMappings []Change `json:"createdMappings,omitempty"`
	// UpdatedMappings are the mappings courier already owned and extended
	UpdatedMappings []Change `json:"updatedMappings,omitempty"`
	// CreatedPolicies are the policies created, in order
	CreatedPolicies []Change `json:"createdPolicies,omitempty"`
	// UpdatedPolicies are the policies updated, in order, with the fields that differ
	UpdatedPolicies []Change `json:"updatedPolicies,omitempty"`
	// UnchangedPolicies counts policies that already match Openlane
	UnchangedPolicies int `json:"unchangedPolicies"`
	// Warnings are non-fatal issues such as mapped control refCodes that
	// could not be resolved and were skipped
	Warnings []string `json:"warnings,omitempty"`
	// Errors are per-record failures, the run continues past them so one
	// rejected record does not abort the batch
	Errors []string `json:"errors,omitempty"`
}

ApplyResult summarizes what an apply changed in the API

type Change added in v0.0.2

type Change struct {
	// Ref is the control refCode or the policy name
	Ref string `json:"ref"`
	// Detail is the managed fields that differ, or the mapping targets added,
	// empty when the record is created outright
	Detail []string `json:"detail,omitempty"`
}

Change is one record apply wrote, or would write on a dry run

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client wraps the generated Openlane GraphQL client

func NewClient

func NewClient(config Config, opts ...Option) (*Client, error)

NewClient builds a Client from the given config

func (*Client) Apply

func (c *Client) Apply(ctx context.Context, store *Store, kinds []Kind, opts ApplyOptions) (*ApplyResult, error)

Apply pushes the store files through the API for the selected kinds in registry order. Remote state is fetched first and every record is compared against it, so only entries that actually differ are written and a repeated apply is a no-op. With DryRun the same comparison runs and the result reports what would change without writing anything. Nothing is ever deleted

func (*Client) FetchState

func (c *Client) FetchState(ctx context.Context, kinds []Kind) (*RemoteState, error)

FetchState pulls the remote state for the selected kinds from the API

func (*Client) Pull

func (c *Client) Pull(ctx context.Context, dir string, kinds []Kind) (*PullResult, error)

Pull exports the selected kinds into the store, rewriting each kind's files from the server's current state and removing stale documents

type Config

type Config struct {
	// Host is the base URL of the Openlane API
	Host string
	// Token is the API token used for authentication
	Token string
	// OrganizationID optionally scopes requests to a specific organization
	OrganizationID string
}

Config holds the connection settings for the Openlane API

type FormatResult

type FormatResult struct {
	// Changed are the relative paths whose content differs from canonical form
	Changed []string
}

FormatResult reports what Format changed or would change

func Format

func Format(dir string, check bool) (*FormatResult, error)

Format rewrites controls.yaml and policies.yaml into canonical form, markdown documents are left untouched. With check set the files are not rewritten

type Kind added in v0.0.2

type Kind string

Kind identifies a syncable object kind

const (
	// KindControls covers organization controls and their control mappings
	KindControls Kind = "controls"
	// KindPolicies covers internal policies, their documents, and their control references
	KindPolicies Kind = "policies"
)

func AllKinds added in v0.0.2

func AllKinds() []Kind

AllKinds lists every registered kind in apply order

func SelectKinds added in v0.0.2

func SelectKinds(selected map[Kind]bool) []Kind

SelectKinds resolves per-kind flag selections into the kinds to operate on, no selection means every kind, order always follows the registry

type Option added in v0.0.2

type Option func(*Client)

Option configures a Client

func WithGraphClient added in v0.0.2

func WithGraphClient(typed graphclient.GraphClient) Option

WithGraphClient supplies the GraphQL client instead of building one from the config, so the pull, plan, and apply paths can be driven against a fake

type PullResult

type PullResult struct {
	// TotalControls is the number of organization controls exported
	TotalControls int `json:"totalControls"`
	// TotalPolicies is the number of internal policies exported
	TotalPolicies int `json:"totalPolicies"`
	// Written are the relative paths created or updated
	Written []string `json:"written,omitempty"`
	// Removed are the relative paths of stale documents deleted
	Removed []string `json:"removed,omitempty"`
	// Warnings are records the export could not represent, such as a
	// subcontrol whose parent control is not itself exported
	Warnings []string `json:"warnings,omitempty"`
}

PullResult summarizes what a pull wrote to the store

type RemoteControl

type RemoteControl struct {
	// ID is the Openlane ULID of the control
	ID string `json:"id"`
	// RefCode is the unique reference code of the control
	RefCode string `json:"refCode"`
	// Title is the human readable title of the control
	Title string `json:"title"`
	// Description describes what the control is supposed to accomplish
	Description string `json:"description"`
	// Category is the category of the control
	Category string `json:"category"`
	// Subcategory is the subcategory of the control
	Subcategory string `json:"subcategory"`
	// ReferenceFramework is the framework short name when the control derives from a standard
	ReferenceFramework string `json:"referenceFramework"`
	// Tags associated with the control
	Tags []string `json:"tags"`
}

RemoteControl is the authorable view of a control as it exists in the API

type RemoteMapping

type RemoteMapping struct {
	// ID is the Openlane ULID of the mapped control record
	ID string `json:"id"`
	// Source is how the mapping was created, courier owns the imported ones
	Source string `json:"source"`
	// From are the controls and subcontrols on the from side of the mapping
	From []RemoteRef `json:"from"`
	// To are the controls and subcontrols on the to side of the mapping
	To []RemoteRef `json:"to"`
}

RemoteMapping is a mapped-control record as it exists in the API, the participant edges derive mappedControls lists and the source identifies the records courier owns and may edit in place

type RemotePolicy

type RemotePolicy struct {
	// ID is the Openlane ULID of the policy
	ID string `json:"id"`
	// Name is the unique name of the policy
	Name string `json:"name"`
	// KindName is the policy kind, e.g. Security, Operational
	KindName *string `json:"internalPolicyKindName"`
	// Status is the document status, e.g. PUBLISHED, DRAFT
	Status string `json:"status"`
	// Revision is the document revision, e.g. v1.0.0
	Revision string `json:"revision"`
	// Details is the stored policy body
	Details *string `json:"details"`
	// Tags associated with the policy
	Tags []string `json:"tags"`
	// Controls are the controls linked to the policy
	Controls []RemoteRef `json:"controls"`
}

RemotePolicy is an internal policy as it exists in the API

type RemoteRef

type RemoteRef struct {
	// ID is the Openlane ULID of the referenced record
	ID string `json:"id"`
	// RefCode is the reference code of the referenced record
	RefCode string `json:"refCode"`
	// Framework is the short name of the framework the record derives from,
	// empty for organization custom controls
	Framework string `json:"framework"`
	// Subcontrol reports whether the reference is a subcontrol rather than a
	// control, the two live in separate edge sets on a mapping
	Subcontrol bool `json:"subcontrol,omitempty"`
}

RemoteRef identifies a control or subcontrol participating in a mapping or policy edge

type RemoteState

type RemoteState struct {
	// Controls are the organization-owned controls not derived from a framework
	Controls []RemoteControl
	// Subcontrols are the organization-owned subcontrols of those controls
	Subcontrols []RemoteSubcontrol
	// Mappings are the organization-owned mapped-control records
	Mappings []RemoteMapping
	// Policies are the organization-owned internal policies
	Policies []RemotePolicy
}

RemoteState is the full set of organization controls, mappings, and policies pulled from the API

type RemoteSubcontrol added in v0.0.2

type RemoteSubcontrol struct {
	// RemoteControl holds the fields a subcontrol shares with a control
	RemoteControl
	// ControlID is the Openlane ULID of the parent control
	ControlID string `json:"controlID"`
}

RemoteSubcontrol is a subcontrol as it exists in the API, it carries the same authorable fields as a control plus the control it belongs to

type Settings

type Settings struct {
	// Host is the base URL of the Openlane API
	Host string `koanf:"host"`
	// Token is the API token used for authentication
	Token string `koanf:"token" sensitive:"true"`
	// OrganizationID optionally scopes requests to a specific organization, only needed for multi-organization tokens
	OrganizationID string `koanf:"organization-id"`
	// Dir is the directory holding the exported files
	Dir string `koanf:"dir"`
}

Settings are the connection and store settings for the binary

func DefaultSettings added in v0.0.2

func DefaultSettings() Settings

DefaultSettings are the settings used before any source is merged in

func LoadSettings

func LoadSettings(path string, flags *pflag.FlagSet) (Settings, error)

LoadSettings merges settings from the config file at path (DefaultConfigFile when empty), COURIER_-prefixed environment variables, and set flags, later sources win. A missing default config file is not an error, a missing explicit one is

type Store added in v0.0.2

type Store struct {
	// Dir is the directory the files were loaded from
	Dir string
	// Controls is the parsed control inventory
	Controls []*controlfile.Control
	// Policies is the parsed policy manifest
	Policies []*controlfile.Policy
	// PolicyMarkdown holds the raw markdown document per manifest entry
	PolicyMarkdown map[string][]byte
}

Store is the parsed content of an export directory: the control inventory, the policy manifest, and the raw policy markdown documents keyed by store-relative path

func NewStore added in v0.0.2

func NewStore(dir string) (*Store, error)

NewStore parses controls.yaml, policies.yaml, and every referenced markdown document under dir, missing files load as empty

Jump to

Keyboard shortcuts

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