Documentation
¶
Overview ¶
Package config reads driftgate.yaml and locates the project's files (Layout): with baselines: local all of them in the project's .driftgate/ folder, which git ignores; with baselines: git the driftgate/ folder in the repository and the local store outside it.
Index ¶
- Constants
- Variables
- func Find(dir string) (string, error)
- func HomeRelative(path string) (string, bool)
- func Locate(path, mode string) (root, at string, err error)
- func MainWorktreeProject(dir string) (here, main string)
- type Bisect
- type Component
- type Concurrency
- type Config
- type Data
- type DataDB
- type DataFiles
- type Duration
- type From
- type Generate
- type Guard
- type Identity
- type Layout
- type Observe
- type PII
- type Param
- type Project
- func (p *Project) Baseline(name string) (*snapshot.Set, error)
- func (p *Project) Capture(tag string) (*snapshot.Set, error)
- func (p *Project) CheckoutID() string
- func (p *Project) CreateKey() (string, error)
- func (p *Project) Current() error
- func (p *Project) KeyConflict() string
- func (p *Project) KeySource() string
- func (p *Project) LoadKey() (secret.Key, error)
- func (p *Project) Path(elem ...string) string
- func (p *Project) Private() (*snapshot.PrivateStore, error)
- func (p *Project) Save() error
- func (p *Project) StoreDir() (string, error)
- func (p *Project) UploadsDir() (string, error)
- func (p *Project) WriteStore() (string, error)
- type RateLimit
- type Secret
- type Storage
- type Switch
- type Target
- type Tokens
- type Uploads
Constants ¶
const ( Version = 1 FileName = "driftgate.yaml" Dir = "driftgate" EnvStore = "DRIFTGATE_STORE" )
const ( Freeze = "freeze" Evolve = "evolve" )
Modes.
const ( MySQL = "mysql" Postgres = "postgres" )
Drivers.
const ( // BaselinesLocal keeps everything in the project's .driftgate/ folder, // which git ignores: the configuration, catalog, allowlist, baselines, // the store and the key. Nothing goes outside the project. BaselinesLocal = "local" // BaselinesGit is the layout earlier releases used: driftgate.yaml // and driftgate/ in the repository, the store in // ~/.driftgate/<project>. BaselinesGit = "git" )
Where a project keeps its files (baselines: in driftgate.yaml).
const EnvUploads = "DRIFTGATE_UPLOADS"
EnvUploads overrides uploads.dir, for a machine that keeps the files elsewhere.
const LocalDir = ".driftgate"
LocalDir is the project's own folder of baselines: local.
Variables ¶
var ErrInvalid = errors.New("invalid configuration")
ErrInvalid marks an error of the configuration that is found only when it is used (the cli exits 2 for it, not 3 as for the environment).
var ErrNoConfig = errors.New(FileName + " not found")
ErrNoConfig means driftgate.yaml was not found.
var ErrSwitched = errors.New("already in that mode")
ErrSwitched means the project already has the mode.
var Templates = []string{"ok", "not-found", "invalid-param", "anonymous", "identities", "json", "empty-body"}
Templates of generated requests.
Functions ¶
func Find ¶
Find walks up from dir to the configuration of the project dir is in: the first folder with driftgate.yaml (baselines: git) or .driftgate/driftgate.yaml (baselines: local). It stops at the top of the git work tree, or of the file system outside one.
func HomeRelative ¶
HomeRelative reports a path written from the home folder, ~/… or, on Windows, also ~\…, and returns the rest after the ~ and the separator.
func Locate ¶
Locate is the project folder and mode of a new project whose driftgate.yaml goes to path, which decides the mode; with an empty path the project is the working folder, laid out as mode says (default: local).
func MainWorktreeProject ¶
MainWorktreeProject finds, for a folder of a worktree added with git worktree add, the baselines: local project of the main worktree that it is a checkout of: .driftgate/ is not in git, so a new worktree has none. here is the project folder in this worktree, main the one in the main worktree; both are "" when there is no such project, or when this worktree has a configuration of its own.
Types ¶
type Bisect ¶
type Bisect struct {
Checkout []string `yaml:"checkout,omitempty"` // builds or restarts the application from the worktree; failing skips the commit
Ready []string `yaml:"ready,omitempty"` // repeated until it succeeds; failing within ready_timeout skips the commit
Finish []string `yaml:"finish,omitempty"` // once at the end, e.g. to start the application from the checkout again
Timeout Duration `yaml:"timeout,omitempty"` // limit of the checkout command; default 10m
ReadyTimeout Duration `yaml:"ready_timeout,omitempty"` // default 1m
}
Bisect configures driftgate bisect: the commands that put the application on a commit checked out in a separate worktree, and wait until it answers. They run without a shell, from the project folder, with the worktree and the commit in DRIFTGATE_BISECT_DIR and DRIFTGATE_BISECT_COMMIT.
type Component ¶
type Component struct {
Driver string `yaml:"driver,omitempty"` // mysql (also MariaDB) or postgres; empty: commands
DSN Secret `yaml:"dsn,omitempty"`
Working string `yaml:"working,omitempty"` // database the application uses
Pristine string `yaml:"pristine,omitempty"` // its pristine copy; default <working>_pristine
Exclude []string `yaml:"exclude,omitempty"` // tables never fingerprinted or restored (globs)
RowTracking []string `yaml:"row_tracking,omitempty"`
// AllowRemote lets the database be on a host outside target.allow_hosts.
// A restore rewrites its tables, so a wrong DSN must not reach a server
// that is not a copy.
AllowRemote bool `yaml:"allow_remote,omitempty"`
Restore []string `yaml:"restore,omitempty"`
Fingerprint []string `yaml:"fingerprint,omitempty"`
}
Component is one part of the state the application runs on: a database with a built-in driver, or anything else through restore and fingerprint commands.
func (Component) ReadDSN ¶
ReadDSN reads the DSN of a database component (Secret.Read). When the project's setting it reads names a database, that must be working: the file is followed when a command runs, working is not, and a restore of another database than the one the application runs on would reset the wrong one. That error is ErrInvalid and names only the databases.
type Concurrency ¶
type Concurrency int
Concurrency is how many read-only requests of a service are sent at once: a number (0 and 1: one at a time), or auto, which the first baseline decides by measuring and records in its meta.json.
const ConcurrencyAuto Concurrency = -1
ConcurrencyAuto is concurrency: auto.
func (Concurrency) Fixed ¶
func (c Concurrency) Fixed() int
Fixed is the number of requests at once without a decision of auto: auto and anything below 1 mean one at a time.
func (Concurrency) MarshalYAML ¶
func (c Concurrency) MarshalYAML() (any, error)
func (*Concurrency) UnmarshalYAML ¶
func (c *Concurrency) UnmarshalYAML(n *yaml.Node) error
type Config ¶
type Config struct {
Version int `yaml:"version"`
Project string `yaml:"project"`
Mode string `yaml:"mode"`
Level string `yaml:"level"`
Baselines string `yaml:"baselines,omitempty"` // local or git; default: where driftgate.yaml is (Layout)
Store string `yaml:"store,omitempty"`
Key secret.Source `yaml:"key,omitempty"`
Target Target `yaml:"target,omitempty"` // one service
Targets map[string]Target `yaml:"targets,omitempty"` // several services, by name (an API, a frontend, microservices)
Identities map[string]Identity `yaml:"identities,omitempty"`
Tokens Tokens `yaml:"tokens,omitempty"`
State map[string]Component `yaml:"state,omitempty"`
Seed [][]string `yaml:"seed,omitempty"` // load the data into the working state; driftgate seed then copies it to the pristine one
Prepare [][]string `yaml:"prepare,omitempty"` // run after every restore (migrations and the like)
Guards []Guard `yaml:"guards,omitempty"`
PII PII `yaml:"pii,omitempty"`
Discover []discover.Adapter `yaml:"discover,omitempty"`
Generate Generate `yaml:"generate,omitempty"`
Templates []string `yaml:"templates,omitempty"`
Params []Param `yaml:"params,omitempty"`
Storage Storage `yaml:"storage,omitempty"`
Observe []Observe `yaml:"observe,omitempty"`
Bisect Bisect `yaml:"bisect,omitempty"`
Data Data `yaml:"data,omitempty"`
Uploads Uploads `yaml:"uploads,omitempty"`
}
Config is driftgate.yaml. An unknown key is an error, not a warning.
func (Config) AllowHostLists ¶
AllowHostLists returns the allow_hosts of every service that has them, the lists a database under state: or a data target is checked against.
func (Config) Canonical ¶
Canonical is the name a request, route or rule should carry: the empty name means the only service when there is one.
func (Config) Services ¶
Services returns the targets by name; a configuration with one target has it under the empty name.
func (Config) TargetFor ¶
TargetFor returns the target of a request or adapter. With several targets the name is required; with one, it must be empty or that name.
func (Config) TargetNames ¶
TargetNames lists the services in name order.
type Data ¶
type Data struct {
Driver string `yaml:"driver,omitempty"` // mysql (also MariaDB) or postgres
Source DataDB `yaml:"source,omitempty"`
Target DataDB `yaml:"target,omitempty"`
// AllowRemote lets the target be on a host outside target.allow_hosts.
// The target is dropped and created again, so a wrong DSN must not
// reach a server that is not a copy.
AllowRemote bool `yaml:"allow_remote,omitempty"`
// Key replaces values deterministically; default: the project key.
Key secret.Source `yaml:"key,omitempty"`
// Files is the folder of uploaded files and the folder that receives
// their placeholders (same names, neutral content); relative to the
// project root.
Files DataFiles `yaml:"files,omitempty"`
}
Data configures driftgate data: the database that is read (a copy of production data, never written) and the database that receives the anonymized copy.
type DataDB ¶
type DataDB struct {
DSN Secret `yaml:"dsn,omitempty"` // the server; for the target, default the source's
Database string `yaml:"database,omitempty"` // the database on it
}
DataDB is one database of the data module.
type DataFiles ¶
type DataFiles struct {
Source string `yaml:"source,omitempty"`
Target string `yaml:"target,omitempty"`
}
DataFiles are the folders of driftgate data's file placeholders.
type Duration ¶
Duration is a time.Duration written as "30s" in YAML.
func (Duration) MarshalYAML ¶
type From ¶
type From struct {
Request string `yaml:"request" json:"request"`
Path string `yaml:"path" json:"path"` // JSON path in its body, e.g. $.entry.id
}
From takes a value from the response of another request.
type Generate ¶
type Generate struct {
Identity string `yaml:"identity,omitempty"` // for routes that need an authenticated user
}
Generate configures driftgate generate.
type Layout ¶
type Layout struct {
Mode string // BaselinesLocal or BaselinesGit
Root string // the project folder (.gitignore, .env and the application's files)
Config string // driftgate.yaml
Dir string // the folder of the catalog, allowlist, routes, exclusions and baselines
Catalog string // catalog.json
Allowlist string // allowlist.yaml
Baselines string // the folder of the baselines, one folder each
// The local store: captures, encrypted private bodies, pristine
// records, the last comparisons and the lock. Empty when store: is not
// usable; StoreDir says why.
Store string
Captures string // one folder per tag
Private string // encrypted private bodies
Pristine string // records of the pristine copies
Lock string // the lock of the commands that write the store
// Key is the key file; empty when the key comes from elsewhere only
// (the environment, 1Password, the macOS Keychain).
Key string
// Ignored is the folder git must ignore before anything sensitive is
// written into it (the key, captures, private bodies, baselines); empty
// when none of them is inside the project.
Ignored string
}
Layout is where the files of a project are. Only this package knows the mode: the layout is computed once, when the configuration is loaded, and every other package takes its paths from it.
func NewLayout ¶
NewLayout is the layout of a project at root in mode, with the store of configuration c (store:, DRIFTGATE_STORE). The error is the one of an unusable store, which matters only to a command that uses it; the layout is complete apart from the store's paths.
func (Layout) Committed ¶
Committed reports whether the project's files (configuration, catalog, allowlist, baselines) belong in its git repository, for the messages that say to commit them.
func (Layout) WriteIgnores ¶
WriteIgnores adds the layout's own folder to the project's .gitignore (made when missing) and .dockerignore (when there is one, or a Dockerfile or compose file that would copy the folder into an image). A file that has the entry already is left as it is; line endings are kept.
type Observe ¶
type Observe struct {
Target string `yaml:"target,omitempty"` // only requests of this service
Match string `yaml:"match"` // glob over "METHOD /route/path", "/route/path" or the request ID
Reason string `yaml:"reason,omitempty"` // why it cannot be compared
}
Observe marks generated requests that are measured but never compared: their outcome depends on timing or on a cache of the application.
type PII ¶
type PII struct {
Allow []string `yaml:"allow,omitempty"` // regular expressions of values that may appear in public bodies
}
PII configures the detector of personal data in public bodies.
type Param ¶
type Param struct {
Target string `yaml:"target,omitempty"` // only routes of this service
Name string `yaml:"name"`
Route string `yaml:"route,omitempty"` // glob over route paths; empty: every route with the parameter
Value string `yaml:"value,omitempty"`
Values []string `yaml:"values,omitempty"`
SQL string `yaml:"sql,omitempty"`
State string `yaml:"state,omitempty"` // component the query runs on; default: the only database
From *From `yaml:"from,omitempty"`
Foreach bool `yaml:"foreach,omitempty"` // one request per value instead of the first value only
}
Param says where the value of a route parameter comes from: a fixed value, a list, a read-only query on the pristine database, or another response during the capture.
type Project ¶
type Project struct {
Config
Root string // the project folder; driftgate.yaml is in it or in its .driftgate/
Level compare.Level
Layout Layout // where the project's files are
// contains filtered or unexported fields
}
Project is a loaded configuration with resolved locations.
func Adopt ¶
Adopt makes the project of the main worktree (main, as MainWorktreeProject finds it) this worktree's (here): its configuration, catalog, allowlist, routes, exclusions, classify rules, baselines with their acceptance logs, the key, and the private bodies those baselines name. Not its captures, pristine records or other private bodies: they are of the main worktree's code and databases. Git must ignore here's .driftgate/ first (the ignore files are written). The configuration is copied as it is, its state: too: a worktree that runs on another database must say so in it.
func Create ¶
Create validates the configuration of a new project (Locate); the file is not written. A project that has a configuration already is refused.
func Load ¶
Load reads the configuration file; an empty path is the configuration of the project the working folder is in (Find).
func New ¶
New validates a configuration for a project rooted at root, laid out as its baselines: says (default git, as earlier releases laid out every project).
func (*Project) Baseline ¶
Baseline is a snapshot set in the repository; its private bodies are in the local store, so another machine has only their refs. An invalid name is ErrInvalid; any other error is one of the store.
func (*Project) Capture ¶
Capture is a snapshot set in the local store. An invalid tag is ErrInvalid; any other error is one of the store (it cannot be made).
func (*Project) CheckoutID ¶
CheckoutID names the checkout of the project (its folder) in a store that several checkouts share: its run capture and last comparison.
func (*Project) CreateKey ¶
CreateKey makes the project key where LoadKey finds it: in the layout's key file (once git ignores its folder), else in the macOS Keychain. It returns where it is.
func (*Project) Current ¶
Current says whether the project is still laid out as it was loaded: a command that waited for the store lock while driftgate baselines moved the project must not write into the old place.
func (*Project) KeyConflict ¶
KeyConflict says, when DRIFTGATE_KEY is set and holds another key than the layout's key file, that the variable wins; "" otherwise.
func (*Project) LoadKey ¶
LoadKey returns the project key (key: in the configuration, then DRIFTGATE_KEY, then the layout's key file or, without one, the macOS Keychain); it is loaded once, on first use.
func (*Project) Private ¶
func (p *Project) Private() (*snapshot.PrivateStore, error)
Private is the local store of encrypted private bodies, of captures and baselines alike: a private body never enters the repository.
func (*Project) StoreDir ¶
StoreDir is the local store (Layout.Store), made when missing. A store folder DriftGate makes is open to its owner only.
func (*Project) UploadsDir ¶
UploadsDir returns the uploads folder: DRIFTGATE_UPLOADS, then uploads.dir (relative to the folder of driftgate.yaml). A folder inside the git repository of the project is refused.
func (*Project) WriteStore ¶
WriteStore is StoreDir for a command that writes the store: a store in the project's own folder is used only once git ignores that folder.
type Secret ¶
type Secret struct {
Env string `yaml:"env,omitempty"`
Op string `yaml:"op,omitempty"`
// A file of the project, relative to its root, by its format; Key says
// where the setting is in it and Host replaces its host[:port].
Dotenv string `yaml:"dotenv,omitempty"`
AppSettings string `yaml:"appsettings,omitempty"`
Properties string `yaml:"properties,omitempty"`
YAML string `yaml:"yaml,omitempty"`
PHP string `yaml:"php,omitempty"`
Python string `yaml:"python,omitempty"`
Compose string `yaml:"compose,omitempty"`
Key string `yaml:"key,omitempty"`
Host string `yaml:"host,omitempty"`
}
Secret is a DSN that never sits in the configuration itself: it comes from an environment variable, a 1Password reference, or a setting of the project's own files (internal/appconf), read when a command runs.
func (Secret) Read ¶
Read returns the DSN for a database with driver (mysql or postgres) of a project rooted at root. A DSN of the environment or 1Password may also be a JDBC URL, an ADO.NET connection string or libpq's keyword form; one of a file is converted from the file's form (appconf.Ref.DSN). No error quotes a value.
type Storage ¶
type Storage struct {
Default string `yaml:"default,omitempty"`
Public []string `yaml:"public,omitempty"`
}
Storage of generated requests: private unless a glob over the request ID says public.
type Switch ¶
type Switch struct {
From *Project // the project as it is laid out now
To Layout // where its files go
// contains filtered or unexported fields
}
Switch moves a project to the other baselines: mode (driftgate baselines). It writes the new place fully, then puts the new configuration in place, then removes the old place; one stopped at any point is finished by running it again.
func PrepareSwitch ¶
PrepareSwitch reads the project a switch to mode starts from: the one of path, or of the working folder (as Load finds it). Nothing is written.
func (*Switch) Run ¶
func (s *Switch) Run(ctx context.Context, enterGit func(*Project) error, out, errOut io.Writer) error
Run makes the switch. enterGit checks what a switch to git puts into the repository (the baselines) and refuses with an error; it runs before anything is written. errOut gets the messages of a wait for a store lock.
type Target ¶
type Target struct {
BaseURL string `yaml:"base_url,omitempty"`
AllowHosts []string `yaml:"allow_hosts,omitempty"` // host names or CIDR ranges; default: local and private
UserAgent string `yaml:"user_agent,omitempty"`
Timeout Duration `yaml:"timeout,omitempty"`
Concurrency Concurrency `yaml:"concurrency,omitempty"`
FollowRedirects bool `yaml:"follow_redirects,omitempty"`
RateLimits []RateLimit `yaml:"rate_limits,omitempty"`
// Aliases are other origins under which the application writes its
// own URLs. A comparison of sets captured from different origins takes
// every side's own origin and these as the same.
Aliases []string `yaml:"aliases,omitempty"`
}
Target is where requests go.
type Tokens ¶
type Tokens struct {
Command []string `yaml:"command,omitempty"`
File string `yaml:"file,omitempty"`
}
Tokens is a source of a JSON object {"<identity>": "<token>"}: a command that prints it or a file that holds it (kept outside the repository).
type Uploads ¶
type Uploads struct {
Dir string `yaml:"dir,omitempty"` // ~/ is the home folder; relative to the project root otherwise
}
Uploads is the folder of the real files catalog requests upload. It lives outside the repository: the files may hold real data, and only their paths and keyed hashes are committed.