Commit graph Heimdall/tests/config-secrets.test.ts
Author SHA1 Message Date
Meta Vens
0178d071c1 readSecretInput: never print the path, refuse relative paths and blank secrets
Soul F1: the unreadable-file error carried the NAME_FILE value, and Idunn
admits any string for a declared name, so a URL bound into
GC_ACCESS_DATABASE_URL_FILE by mistake was printed in full at startup. Errors
now name only the variable and an error code, and a NAME_FILE that is not an
absolute path is refused naming the variable alone.

Soul F2 and F6: a blank database URL file selected memory storage silently,
and a whitespace one selected postgres with a URL of " ". The reader now
refuses an empty or whitespace-only value from either form, so custody's own
"set but empty" check is redundant and is deleted; a short key still fails its
length check. The legacy service.env holds no blank secret-class value
(checked as name/blank booleans), so the legacy unit is unaffected.

Soul F3: tests pin that an empty NAME_FILE is refused rather than unset (S1),
and that each call site (token key, provider secret, app shared secret,
database URL, patron secret) refuses both forms, so no site can read the
plaintext name ahead of the reader (S6, S7, S8).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 13:50:53 +02:00
Meta Vens
9f0cd73299 Pin the newline and storage-selection rules StrykerJS found undefended
StrykerJS on the reader and its call sites left two findings about the
tests. Every trim fixture had its newline only at the end, so stripping the
first newline anywhere survived: a two-line value now pins "one trailing
newline". No fixture reached the memory branch of storage selection, so
forcing postgres, dropping the backend check or inverting it survived: the
memory default and an explicit backend of either kind are now pinned.

Idunn secret-files cut, Cut 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:49:23 +02:00
Meta Vens
ac86352972 Read every secret input from a credential file named by NAME_FILE
The recipe declared Heimdall's secrets as plain environment, so its admit
contract made the operator binding the only place their values could live,
and the binding was printed into a transcript. The recipe now declares each
secret only as its _FILE twin (GC_ACCESS_DATABASE_URL_FILE required, the rest
optional). A binding binds those under [workload.secret_files] to root:root
0400 credential files, and Idunn's rule that a binding binds only declared
names leaves a plaintext secret nowhere to go. GC_ACCESS_APP_SHARED_SECRET is
deleted outright: nothing reads it.

One reader, readSecretInput, serves every secret: it reads NAME_FILE and strips
one trailing newline, refuses NAME and NAME_FILE set together, and its errors
name the variable and path, never a value or file contents. Storage-backend
selection keys off the resolved database URL. The published provider witness
and the provider_not_configured body name the _FILE variables, and custody's
errors name GC_ACCESS_TOKEN_ENCRYPTION_KEY_BASE64_FILE.

The plaintext fallback (NAME read while NAME_FILE is absent) is a named shim
for the legacy EnvironmentFile unit only; secret-files Cut 5 deletes it.

Idunn secret-files cut, Cut 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:30:57 +02:00