Documentation
¶
Overview ¶
Package fsx contains small filesystem helpers shared across the dependency-firewall packages.
Why a parallel helper vs. internal/config.WriteFile ¶
The CLI already ships internal/config.WriteFile, which wraps renameio for atomic writes. We considered reusing it and chose not to for two reasons:
Permissions mismatch on token-bearing files. renameio.WriteFile applies WithExistingPermissions() by default, which preserves the *existing* mode when the target file is already on disk and ignores the perm argument. That is the exact opposite of what dependency-firewall needs: the whole reason WriteOwnerOnly exists is to tighten a pre-existing, possibly world-readable .npmrc down to 0o600 so a live _authToken is not readable by other users on a shared host or CI runner. A straight call to config.WriteFile(path, data, 0o600) would silently keep a stale 0o644 and reintroduce the leak dbickford flagged on !3438.
npm itself does not help us here. npm's own save() writes the user config (~/.npmrc) at 0o600 because that is where credentials belong, but writes the project-level config (the sibling of package.json) at 0o666 because a project .npmrc is not expected to hold credentials. The dependency firewall deliberately embeds an inline _authToken in the project .npmrc to point npm at the CI-scoped proxy, which violates npm's own "auth goes in the user config" convention. So we cannot inherit npm's project-level 0o666 default; every write from this package must actively enforce 0o600.
Transitive dependency footprint. internal/config pulls in go-keyring, viper, and yaml — 291 transitive packages against fsx's 69. Keeping the dependency-firewall engine core lean lets the proxy binary link cleanly and keeps blast radius small when the config subsystem changes.
So this package wires renameio directly (already vendored) and layers an explicit os.Chmod on top to defeat WithExistingPermissions() on overwrites. The write itself is atomic on POSIX (tempfile + rename); on Windows the same guarantee is not available and the write degrades to os.WriteFile, which matches how internal/config.WriteFile behaves on that platform.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func WriteJSONFile ¶
WriteJSONFile creates path's parent directory (0o755), marshals v with two-space indent for user-editability, appends a trailing newline (POSIX text-file convention; keeps `git diff` clean when the file is hand-edited later), and writes the result to path with mode 0o644. The write is atomic via renameio. Use it for non-secret configuration and log files; token-bearing files must use WriteOwnerOnly instead.
func WriteOwnerOnly ¶
WriteOwnerOnly writes data to path atomically and forces mode 0o600.
On POSIX the write is a temp-file-plus-rename via renameio, so a reader concurrent with the write either sees the full old file or the full new file — never a half-written mix. If the process dies mid-write, the target is untouched and only an orphaned temp file may be left behind.
renameio.WriteFile defaults to WithExistingPermissions(), which preserves the existing mode when the target already exists. That is the wrong policy for token-bearing files (see the package-level doc comment for the full rationale), so we follow the write with an explicit Chmod to guarantee 0o600 in both the create and the overwrite paths.
Callers use this for any file that may embed an inline authentication token — for example, .npmrc, .yarnrc.yml, or a patched Pipfile — and for the token-bearing backups those files produce.
Types ¶
This section is empty.