Documentation
¶
Overview ¶
Package config owns credential and endpoint resolution for the CLI.
There are two credentials in play and they are deliberately never conflated:
- the session (an OAuth access token) is user scoped and only ever sent to the auth host (console.tabstack.ai);
- an API key is organisation scoped and only ever sent to the product host (api.tabstack.ai).
Because API keys are org scoped, the on-disk shape keys them by organisation id: one user can belong to several orgs and hold a different key in each.
Index ¶
- Constants
- Variables
- func ConfigPath() (string, error)
- func PermissionsOK(path string) (os.FileMode, bool)
- func Redact(s string) string
- func SchemasDir() (string, error)
- type Config
- func (c *Config) HasKey(id string) bool
- func (c *Config) Org(id string) *OrgCreds
- func (c *Config) OrgName(id string) string
- func (c *Config) ResolveAPIKey(req KeyRequest) (KeyResolution, error)
- func (c *Config) ResolveAuthURL(flag string) string
- func (c *Config) ResolveBaseURL(flag string) string
- func (c *Config) UpsertOrg(id, name string) *OrgCreds
- type CredentialStore
- type FileStore
- type KeyRequest
- type KeyResolution
- type KeySource
- type OrgCreds
- type Session
Constants ¶
const ( // EnvAPIKey is exported so `auth status` can name the variable it is // reporting on without re-declaring the string. EnvAPIKey = envAPIKey // DefaultBaseURL is the production product API root. Every extract, // generate, automate, and research endpoint hangs off this. DefaultBaseURL = "https://api.tabstack.ai/v1" // DefaultAuthURL is the auth and management host. OAuth and every /cli/* // management endpoint hangs off this. The session token goes here and // nowhere else. DefaultAuthURL = "https://console.tabstack.ai" // CurrentVersion is the schema version written into the config file. A file // with no version predates org-scoped keys and gets migrated on load. CurrentVersion = 1 )
Variables ¶
var ErrNoAPIKey = errors.New("no API key found")
ErrNoAPIKey is returned when no credential can be resolved at all.
Functions ¶
func ConfigPath ¶
ConfigPath returns the path the config file is read from and written to.
func PermissionsOK ¶ added in v1.0.2
PermissionsOK reports a config file's permission bits and whether they are owner-only. A missing file counts as fine: there is nothing exposed yet.
func Redact ¶ added in v1.0.2
Redact shortens a secret for display: first four and last four characters, elided in the middle. Anything too short to redact meaningfully collapses entirely, so a short token cannot be reconstructed from its own preview.
func SchemasDir ¶ added in v1.0.1
SchemasDir returns the default directory pre-defined schemas are pulled into (`schema pull`). It sits alongside the config file under the tabstack config home. The `--storage` flag overrides it per invocation.
Types ¶
type Config ¶
type Config struct {
AuthURL string `toml:"auth_url,omitempty"`
BaseURL string `toml:"base_url,omitempty"`
ActiveOrg string `toml:"active_org,omitempty"`
LegacyAPIKey string `toml:"legacy_api_key,omitempty"`
Version int `toml:"version"`
Session *Session `toml:"session,omitempty"`
Orgs map[string]*OrgCreds `toml:"orgs,omitempty"`
}
Config is the on-disk configuration, decoded as TOML.
Field order matters for encoding: TOML tables must follow the scalars of the table they sit in, so Session and Orgs are declared last. Reordering them above a scalar would emit a file that no longer parses.
func (*Config) HasKey ¶ added in v1.0.2
HasKey reports whether an organisation has a stored API key.
func (*Config) OrgName ¶ added in v1.0.2
OrgName returns an organisation's display name, falling back to the id when we have never seen a name for it.
func (*Config) ResolveAPIKey ¶ added in v1.0.2
func (c *Config) ResolveAPIKey(req KeyRequest) (KeyResolution, error)
ResolveAPIKey picks the product credential for this invocation. It is the one place precedence is decided, so every command resolves identically:
- --key/--api-key flag
- TABSTACK_API_KEY
- the stored key for the --org override, when given
- the stored key for the active org
- LegacyAPIKey, only while no active org is set
A --org override that has no stored key is an error, never a fallback. Using org A's credential while the user believes they are acting as org B is the worst failure available here, so it is made impossible rather than unlikely.
func (*Config) ResolveAuthURL ¶ added in v1.0.2
ResolveAuthURL returns the auth and management host, with the same precedence as ResolveBaseURL.
func (*Config) ResolveBaseURL ¶ added in v1.0.2
ResolveBaseURL returns the product API root: config file, then environment, then flag, each overriding the last.
type CredentialStore ¶ added in v1.0.2
CredentialStore is the whole surface commands use to read and write credentials. Everything goes through it so an OS keychain implementation can be added later without touching command code.
type FileStore ¶ added in v1.0.2
type FileStore struct {
// Warn is where permission warnings go. Defaults to os.Stderr; tests
// substitute a buffer.
Warn io.Writer
// contains filtered or unexported fields
}
FileStore is the shipped CredentialStore: a single TOML file, 0600, inside a 0700 directory.
func NewFileStore ¶ added in v1.0.2
NewFileStore builds a store over the default config path.
func NewFileStoreAt ¶ added in v1.0.2
NewFileStoreAt builds a store over an explicit path. Used by tests and by anything that needs to point at a throwaway config.
func (*FileStore) Load ¶ added in v1.0.2
Load reads and decodes the config. A missing file is not an error: it yields an empty config at the current version, which is what a fresh install looks like.
Migration is applied in memory only. Nothing is written until the next successful Save, so simply running a read-only command never rewrites a user's file.
type KeyRequest ¶ added in v1.0.2
type KeyRequest struct {
// Flag is the value of --api-key/--key ("" when unset).
Flag string
// OrgOverride is an already-resolved organisation id from --org ("" when
// unset). It selects which stored key to use for this invocation only and
// never mutates config.
OrgOverride string
}
KeyRequest is the per-invocation input to API key resolution.
type KeyResolution ¶ added in v1.0.2
type KeyResolution struct {
APIKey string
Source KeySource
// OrgID is the organisation the key belongs to, when it came from stored
// per-org credentials. Empty for flag, env, and legacy keys.
OrgID string
OrgName string
// EnvOverriding is true when TABSTACK_API_KEY won, which means the active
// org is not authoritative for product calls this invocation.
EnvOverriding bool
}
KeyResolution is the outcome of resolving a product credential.
type KeySource ¶ added in v1.0.2
type KeySource string
KeySource describes where a resolved API key came from, so `auth status` can explain the resolution without ever printing the key.
type OrgCreds ¶ added in v1.0.2
type OrgCreds struct {
Name string `toml:"name"`
APIKey string `toml:"api_key,omitempty"`
APIKeyID string `toml:"api_key_id,omitempty"`
APIKeyName string `toml:"api_key_name,omitempty"`
}
OrgCreds is one organisation's product credential. Name is display only and can change server-side, which is why Orgs is keyed by organisation id.
type Session ¶ added in v1.0.2
type Session struct {
AccessToken string `toml:"access_token"`
RefreshToken string `toml:"refresh_token"`
ExpiresAt time.Time `toml:"expires_at"`
Scope string `toml:"scope,omitempty"`
UserEmail string `toml:"user_email,omitempty"`
}
Session is the OAuth session: user scoped, auth host only.