fsx

package
v1.117.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package fsx contains small filesystem helpers shared across the dependency-firewall packages. Its current use is writing the end-of-run CI log (.gitlab/df/ci-log.json) via WriteOwnerOnly, which cilog.Save uses so the gate-controlling log is created 0o600 on every rewrite.

Why a parallel helper vs. internal/config.WriteFile

The CLI already ships internal/config.WriteFile, which wraps renameio for atomic writes. We keep this thin parallel helper for two reasons:

  1. Deterministic owner-only permissions. renameio.WriteFile applies WithExistingPermissions() by default, which preserves the *existing* mode when the target file is already on disk and ignores the perm argument. WriteOwnerOnly instead passes WithStaticPermissions(0o600) so the temp file is created 0o600 from the outset (ignoring the existing mode and umask, with no post-write chmod window) and a rewritten token-bearing file cannot silently retain a looser, pre-existing mode on a shared host or CI runner.

  2. Transitive dependency footprint. internal/config pulls in go-keyring, viper, and yaml — hundreds of transitive packages. Keeping the dependency-firewall core lean keeps the blast radius small when the config subsystem changes.

The write is atomic on POSIX (tempfile + rename); on Windows that guarantee is not available and the write degrades to os.WriteFile, matching how internal/config.WriteFile behaves on that platform.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func WithLock added in v1.117.0

func WithLock(lockPath string, fn func() error) (err error)

WithLock runs fn while holding an exclusive advisory lock on a sidecar lock file at lockPath, creating the lock file (and its parent directory) if needed. The lock is released when fn returns.

This serializes a read-modify-write sequence across processes. The Dependency Firewall's CI log is updated Load -> Append -> Save, and Save is a whole-file atomic rename; without a lock two concurrent "glab df run" invocations in one job race last-writer-wins, so the losing run's Blocked entries vanish and ci-summary exits 0. Holding this lock across the whole sequence makes the update atomic between processes.

The lock is flock(2)-based advisory locking: it only coordinates callers that also take this lock (the firewall does, on the same sidecar path), not arbitrary writers. The sidecar is separate from the log itself so locking never conflicts with the atomic rename that replaces the log inode.

func WriteOwnerOnly

func WriteOwnerOnly(path string, data []byte) error

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 cannot be used here: it always appends WithExistingPermissions(), which — when the target already exists — overrides any WithStaticPermissions/WithPermissions and creates the temp file with the existing target's (possibly loose) mode, only tightening it after the secret bytes are on disk. That leaves a window where token data is world/group-readable. Instead we drive renameio.NewPendingFile directly with only WithStaticPermissions(0o600), so the temp file is created 0o600 from the outset (ignoring the existing mode and umask) with no post-write chmod window, then atomically replace the target.

Use this for any file whose contents must stay owner-only even when a pre-existing target was created with a looser mode — currently the CI log (cilog.Save), whose integrity gates the firewall job's exit code on shared runners, and any future token-bearing file the firewall writes to disk.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL