Files
deepseek-harness/packages/credentials/credentials-local
Yichen Jiang 90c3118302 fix(credentials-local): one operation chain, read-modify-write under the shared writer lock, and a quote-aware line editor
Review round three, credentials half. dsh-atomic-write grows the
cross-process writer-lock primitive (withFileLock: wx sentinel, bounded
backoff, stale takeover via onStaleBreak, deadline failure) plus a dirMode
option, and settings-local migrates its private copy to it; both providers
now create harness-home directories 0700.

credentials-local reuses the reviewed settings-local shape: watcher
reloads and line edits share one settled operation chain; every write
re-reads the document under the lock and publishes unobserved external
entries before editing, so an edit inside the debounce window (or another
process's write) can never be overwritten; the watcher's ready signal
queues one reconcile closing the startup gap.

The line editor is now physical-line aware: continuation lines of a
quoted multi-line value are never mistaken for assignments, untouched
lines keep their exact bytes (CRLF included), an edited line keeps its
own terminator, and appends use the document's dominant ending. A
multi-line entry reports writable: false, matching what set() would do.

The Credentials base class owns a contained notifyUpdated fan-out:
providers publish only after the commit, every listener runs, sync throws
and async rejections are logged without failing the committed write, and
INVARIANT-coded failures rethrow after the fan-out.
2026-07-30 15:40:09 +08:00
..

dsh-credentials-local

English | 中文

File-backed credentials provider: two layers, one honest precedence.

Layer Source id Writable Wins
Live process environment env no always
$DSH_HOME/.env document file yes (set/unset) otherwise

The environment wins because a launch-time override (DEEPSEEK_API_KEY=… dsh, CI secrets, a dev shell sourcing the repo .env) is operator intent for this run — and because it cannot be edited from inside, it must be visibly read-only: describe() reports source: 'env', writable: false, and set/unset reject instead of writing a change the reader would never see. Resolution reads process.env live and never writes it back.

Config

Field Default Meaning
path <harness home>/.env Credentials document location.
dshHome $DSH_HOME or ~/.dsh Harness home used when path is omitted.
watch true Hot-publish external edits.
debounceMs 100 Watcher write-settle window.

The document

dotenv format, parsed with dotenv and edited by a line editor that preserves every byte it does not own: set rewrites the first assignment of its key in place (dropping later duplicates, which dotenv's last-wins reading would otherwise let override the edit), unset removes only the owning line, comments and unrelated lines survive verbatim. Writes go through dsh-atomic-write with mode 0600.

Values are rendered in the narrowest style dotenv reads back verbatim — bare, then single-quoted (fully literal), then double-quoted (only without backslashes, which double-quote reading expands). A value no style can represent, and any entry that already spans multiple physical lines, fails loud instead of being corrupted silently. An empty stored value is absent, per the seam rule.

Hot reload

External edits publish credentials/updated per changed reference after the snapshot is replaced wholesale — an entry deleted on disk never lingers in memory. The provider's own writes are recognized by content and publish exactly their one commit event. An unreadable document at runtime keeps the last good snapshot and warns; an absent file is an empty store; an unreadable file at boot fails loud. Keys that are not POSIX identifiers are preserved file content the seam cannot address.

Model Experience

Indirectly, through the consuming LLM adapters: stored values authorize their provider requests, and the adapter owns every model-visible surface.

KV Cache effect

No direct invalidation; credentials never enter a request prefix.

Known Limitations and Deferred Work

  • Multi-line entries refuse set/unset — the line editor will not rewrite an entry it would corrupt; edit the file directly.
  • Unrepresentable values fail loud — control characters, or a mix of both quote styles with backslashes, cannot round-trip the dotenv line format.
  • Environment changes are invisibleprocess.env is read live per resolution, but no event can announce a change there.
  • Atomic, not crash-durable — inherited from dsh-atomic-write; the store re-reads on boot.