fuse

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 28, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package fuse is the STATE half of the ingestion fuse: reading and writing the box, the JSON file the two emergency powers live in. cmd/nova-fuse is the thin command on top of it. The box's path always comes from the caller — there is no default location and no environment variable, per this repo's no-guessed-paths rule.

WHAT IS ACTUALLY DECIDED HERE, and why each one is not arbitrary:

  1. THE READ HAS THREE ANSWERS, NEVER TWO. "no box" is a VERIFIED FACT -- a fuse box that was never created holds no blown fuses. "cannot read the box" is a THIRD answer and it is never the reassuring one. A reader that collapses them (an exists-style probe answers false both when the file is absent AND when the directory above it cannot be stat'd) turns a permissions change into "nothing blown" -- a fail-open in a safety control. os.ReadFile + errors.Is(err, fs.ErrNotExist) tells UNREADABLE apart from NONEXISTENT, which is why the read is written with the stdlib primitive that distinguishes those two rather than the one that does not. What that primitive does NOT distinguish: a missing box file from a missing parent directory -- both come back fs.ErrNotExist, so `--box /no/such/dir/fuses.json` also answers VERIFIED CLEAR. Accepted, deliberately, not overlooked: --box is a locator, the caller's statement of where the box lives, and a caller that names the wrong box gets that box's truth -- here, an empty one. The case is pinned by test (TestCheckIntoANonexistentDirectoryIsAlsoClear in cmd/nova-fuse), so changing this answer is a decision, never a drive-by.

  2. MALFORMED IS UNREADABLE. A JSON array, a bare string, a truncated file, a lockdown whose value is not an object -- every one fails the unmarshal and comes back as CANNOT TELL, which every caller must treat as BLOWN. Reaching the fail-closed answer by a crash deep inside a caller is not a design; this is.

  3. THE WRITE IS TEMP-FILE + RENAME. The file whose corruption means PERMANENT LOCKDOWN must never be left torn: a truncating write can leave half a file if the process dies, and a half file is an unreadable box that only your person can clear, by hand, live. Rename within one directory is atomic, so a reader sees the old box or the new one and never a fragment. Two copies of the tool blowing fuses at once lose one WRITE, but neither can produce a corrupt box.

  4. SURFACE NAMES ARE MATCHED NORMALIZED, AND THAT CUTS BOTH WAYS. Raw string comparison lets `quarantine Discord` then `check discord` answer CLEAR -- a fail-OPEN in a safety control, reached by a capital letter. Normalizing collapses spellings into one surface, and the honest statement of what that does is not "it can only ever block more": it is that EQUIVALENT SPELLINGS ARE ONE SURFACE, IN BOTH DIRECTIONS. `check` refuses on any spelling, so the class blocks more. LiftQuarantine removes EVERY spelling in the class, so a lift lifts more too -- deliberately, because a lift that left one spelling behind would verify its own failure, and because an operator who lifts a surface means the surface. It is not silent either way: each removal is returned under its stored spelling so the caller can announce it on its own line. The consequence to know: a box holding two keys that fold together holds ONE surface, not two.

  5. THE ESCAPE LIVES AT PRINT TIME, because the tool cannot trust what it did not write. The box is world-readable on purpose (a fuse nobody else can see is a fuse that stops nothing) and hand-editable on purpose (that is the only lockdown-replacement mechanism there is), so on a shared machine the reason, the `at` stamp and the stored surface names are authored by whoever can write the file. Echoed raw into a one-line output grammar, a newline forges a SECOND event line beneath a real one -- a `FUSE OK lockdown=clear` under a `FUSE FAIL`, which a caller scanning the grammar reads as permission -- and an ESC sequence does the same to an operator's terminal. OneLine escapes every control character as the text is printed, which holds for a box this tool never wrote; Fold only tidies what this tool writes itself, and is never a refusal, because a fuse you cannot blow is not a fuse. Constraining writes alone would defend exactly the case that needs no defending. The escaped set is category Cc plus U+2028 and U+2029, which break a line for readers that follow Unicode rather than counting newlines. Folding also widens the surface classes of note 4, in both directions -- see there.

Index

Constants

View Source
const UnreadableSuffix = ".unreadable"

UnreadableSuffix names where the bytes of an unreadable box are kept when a lockdown has to clobber it. Back up before mutating what cannot be reconstructed: a corrupt fuse box is evidence -- of a torn write, a bad hand-edit, or something worse -- and blowing an emergency power must not be the thing that destroys it.

Variables

This section is empty.

Functions

func Fold added in v0.8.0

func Fold(s string) string

Fold tidies text this tool is about to WRITE: every control character becomes a space, then runs of whitespace collapse to a single ASCII space and the ends are trimmed. The collapse is Unicode-aware, so a non-breaking space or a line separator inside the text becomes an ordinary space too. It is not the defense -- OneLine is, because a box written by another hand still arrives holding anything at all (note 5). And it is never a REFUSAL: a fuse you cannot blow is not a fuse, so a reason is accepted whatever it contains and only its spelling in the file is tidied.

func OneLine added in v0.8.0

func OneLine(s string) string

OneLine renders free text for an event line. See note 5: the box is hand-editable and world-readable by design, so a reason, a stored surface name or an `at` stamp is authored by whoever can write the file -- and one line per event is a promise this tool makes to every caller scanning the grammar in SPEC.md.

The escape itself lives in internal/oneline, because the promise is made by every binary in this repo and has to be met the same way by each: OneLine is oneline.Escape under the name this package has always used, and the table test here pins that the two never drift. See oneline.Escape for the escaped set (category Cc, U+2028 and U+2029, and the bidi controls) and the escape form.

func PreserveUnreadable

func PreserveUnreadable(path string) (string, error)

PreserveUnreadable copies an unreadable box aside before it is replaced. It returns the destination it TRIED, so the caller can name it either way -- reporting where the bytes went and reporting that they could not be saved are both better than silence.

func Surface

func Surface(s string) string

Surface normalizes a surface name for storage and for matching. See notes 4 and 5: control characters fold to spaces before the lower-casing, which widens the class of spellings that count as one surface exactly as the lower-casing does. That is not a one-way "blocks more" guarantee -- it makes `check` refuse on more spellings AND makes `lift quarantine` remove more of them, because they are one surface in both directions.

func WriteBox

func WriteBox(path string, b Box) error

WriteBox replaces the fuse box atomically. See note 3.

Types

type Box

type Box struct {
	Lockdown   *Fuse           `json:"lockdown"`
	Quarantine map[string]Fuse `json:"quarantine"`
}

Box is the whole fuse box. Lockdown is a pointer so that absent, null and present are three distinguishable states rather than one zero value.

func ReadBox

func ReadBox(path string) (Box, error)

ReadBox returns the fuse box, or the reason it could not be read. See note 1.

A nil error with an empty Box means VERIFIED CLEAR. A non-nil error means CANNOT TELL, and the only correct treatment of that is BLOWN.

func (Box) LiftQuarantine

func (b Box) LiftQuarantine(surface string) map[string]Fuse

LiftQuarantine removes EVERY quarantine entry matching surface (normalized, see note 4) and returns the removed entries under their stored keys, so the caller can announce exactly what was lifted and why it had been blown. An empty surface matches NOTHING, mirroring Quarantined: a missing argument must never empty the box.

Every match is removed, not just the first: the box is hand-editable, so two spellings of one surface can coexist, and a lift that removed only one would leave the surface still answering as quarantined -- a lift that verifies its own failure.

So the normalization in note 4 WIDENS this: the coarser the equivalence, the more spellings one lift removes. `lift "dis cord"` on a box holding "dis cord", "dis\tcord" and "DIS\x01CORD" removes all three, where a build without the fold removed one. That is the same design case already had (lifting "discord" removes "Discord"), it is what "they are one surface" means, and nothing is hidden by it: every removed entry is returned here under its stored spelling for the caller to announce.

THE SOFT HALF ONLY. The fuse design separates the powers: quarantine is your own decision in both directions, so this function exists; lockdown is hard -- a blown fuse is not reset, it is REPLACED, and only in a live conversation with your person -- so no LiftLockdown exists here, and none may be added.

func (Box) Quarantined

func (b Box) Quarantined(surface string) (string, Fuse, bool)

Quarantined answers whether this surface is blocked, returning the key AS STORED so a refusal can quote the file rather than the caller's spelling of it.

An empty surface matches NOTHING, and the caller must say so out loud: a check with no surface has verified only that there is no lockdown, and a printed claim must never outrun what was measured.

func (Box) Surfaces

func (b Box) Surfaces() []string

Surfaces lists the quarantined surfaces in a fixed order. Map iteration is randomized, so an unsorted listing would print a different order every run -- and a status output that reorders itself is one a reader stops diffing.

type Fuse

type Fuse struct {
	At     string `json:"at"`
	Reason string `json:"reason"`
}

Fuse is one blown fuse: when, and why. Both are recorded so a fuse found at 2am can be audited without asking anyone, and both are read back defensively because your person HAND-EDITS this file -- that is the only lockdown-replacement mechanism there is.

Jump to

Keyboard shortcuts

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