Expand description
.mkit/config parser / writer and XDG path helpers.
On-disk format: key = value, one per line, lines starting with #
ignored. User-facing short-hand values for user.identity:
ed25519:<hex>, mid:<u64>, or raw [kind][len][bytes] hex.
§Config scope
There are two layered config files. Higher-priority values win:
- Repo-scoped (
<repo>/.mkit/config) — per-project knobs that travel with a clone: branch defaults and remote endpoints. Security-sensitive keys are rejected here, seeREPO_FORBIDDEN_KEYS. - User-scoped (
$XDG_CONFIG_HOME/mkit/config, default~/.config/mkit/config) — per-user knobs that decide what gets signed, what gets executed, and what hosts to trust. A hostile cloned repo cannot influence these. - Built-in defaults — fall-back when neither file sets a value.
Merge order: defaults → user → repo (filtered). The repo file is
parsed last so its safe values take precedence over defaults; any
security-sensitive key in the repo file is rejected with a stderr
warning and otherwise ignored. See docs/THREAT-MODEL.md for the
threat model that motivates the split.
Structs§
- Attest
Config [attest]section. All fields optional with documented defaults; a fresh repo’s config file has none of them set.- Config
- Full in-memory representation of merged config (user + repo +
defaults). All fields default to empty / documented defaults;
readers that want a known-good default file should call
read_or_default. - KeyConfig
[key]section for keystore-backed signing. All fields are user-scoped.- Layered
Config - Parsed config with per-layer provenance preserved so callers can distinguish “repo configured this” from “user explicitly trusted this”.
- Remote
Entry - A named remote’s stored address.
typeis a dispatch hint derived from the URL scheme atmkit remote addtime. - Resolved
Remote - A resolved remote: its endpoint URL plus whether the repo-scoped
config selected it (
repo_chosen), which the #97 credential gate keys on. Returned byresolve_remote. - Upstream
- Per-branch upstream: the remote name plus the remote branch this
local branch tracks (
branch.<b>.mergestores the bare branch name, e.g.main).
Enums§
- Config
Error - Config
Scope - Source of a parsed config line — used to decide whether a key is
allowed (
ReporejectsREPO_FORBIDDEN_KEYS;Useraccepts everything).
Constants§
- CONFIG_
FILE - CORE_
ALLOWED_ KEYS - Inert
core.*keys accepted for git compatibility. They are stored and round-tripped but mkit does not act on them (it has no CRLF translation, honors exec bits natively, etc.). Repo-safe precisely because inert. - CORE_
DENIED_ KEYS - Dangerous
core.*keys that mkit refuses to store: they would change what commands or hooks mkit invokes if it honored them, so a hostile repo (or a typo) must not be able to set them. Rejected with a clear message. - DEFAULT_
BRANCH - DEFAULT_
KEY_ BACKEND - DEFAULT_
KEY_ REF - DEFAULT_
P256_ KEY_ REF - DEFAULT_
REMOTE_ NAME - The implicit name of the legacy flat
remote_endpoint/remote_typeremote. - DEFAULT_
SECP256 K1_ KEY_ REF - DEFAULT_
SIGNER - DEFAULT_
SIGNING_ KEY - REPO_
FORBIDDEN_ KEYS - Keys that MUST NOT be settable via the per-repo
<repo>/.mkit/configbecause a hostile clone could otherwise: - USER_
CONFIG_ SUBPATH
Functions§
- core_
allowed_ suffix - If
keyiscore.<x>(section matched case-insensitively) with<x>an allowlisted inert key, return the canonical lowercase suffix. git lowercases both the section and the variable name, soCore.AutoCRLF→autocrlf. - endpoint_
credential_ trust - Per-endpoint credential trust check for the shared dispatch choke
point (
crate::remote_dispatch::open_trusted) and named-remote callers.repo_chosenistruewhen the endpoint was selected by the repo-scoped config (the flatremote_endpointor aremote.<name>.urlentry),falsewhen it was supplied by the user (user-scoped config or an explicit CLI argument). Trust is keyed on the resolved ENDPOINT plus this provenance, never on a remote name. - enforce_
trusted_ remote_ endpoint - Refuse to use ambient HTTP/S3 environment credentials with a repo-configured endpoint unless the user has explicitly trusted that exact remote in user-scoped config.
- expand_
user_ identity - Expand a user-typed
user.identityinto the canonical hex form[kind:u8][len:u16 LE][bytes]. Seedocs/CLI.md. - home_
dir_ for_ euid - Resolve the home directory of the current effective uid via
getpwuid_r, ignoring$HOME. - is_
core_ section trueifkeyis in thecoresection (core.<x>), matched case-insensitively like git (Core.x,CORE.xall count).- parse_
pipe_ list - Split a pipe-separated argv string into argv tokens.
- read_
layered - Read both raw layers plus the merged config.
- read_
or_ default - Read the layered config: defaults → user-scoped → repo-scoped (filtered to non-sensitive keys). Missing files are not errors; the per-layer absence simply leaves the lower layer’s value in place.
- resolve_
key_ path - Resolve a configured signing-key path against
root. - resolve_
remote - Resolve a remote NAME to its endpoint + provenance.
- resolve_
upstream - Resolve the upstream (remote name, remote branch) for a local branch.
Falls back to the
defaultremote tracking the same-named branch when no explicitbranch.<b>.{remote,merge}is configured and a default remote exists. - user_
config_ path - Resolve the user-scoped config file path:
$XDG_CONFIG_HOME/mkit/config, falling back to$HOME/.config/mkit/config. - validate_
key_ path - validate_
value - Validate a config value has no control bytes below 0x20 (except tab) and no 0x7f.
- write
- Write the given
Configto<root>/.mkit/config. Only repo-scoped (non-forbidden) fields are emitted; security-sensitive fields live in the user-scoped file and must be written there explicitly. - write_
user_ kv - Write a single user-scoped key/value to
$XDG_CONFIG_HOME/mkit/config. Reads the existing file (if any), updates the matching line (or appends), and writes back. Caller is responsible for validatingvalue(control bytes, key-path traversal). - xdg_
cache_ home - xdg_
config_ home - xdg_
data_ home - xdg_
state_ home