Skip to content

A non-regular agentsync.toml hangs every reading surface (check refuses, everything else blocks) #238

Description

@spxrogers

Split out of #228 / PR #237, where the same report-vs-read asymmetry was found and closed twice — first for the age identity, then for the age vault. This is the third instance, one level up, and it is the config file itself.

Measured

Binary built at 38a3803, a 0600 FIFO at ~/.agentsync/agentsync.toml, neutral cwd:

command result
check rc=1, refuses cleanly: agentsync home … has an agentsync.toml that is not a regular file
secret list rc=124 — hangs, zero output
status rc=124 — hangs, zero output
doctor rc=124 — hangs after printing its header

Verbatim the symptom PR #237 closed for the two age paths.

Why

probeSourceInit (internal/cli/sourceinit.go) gates the shape of agentsync.toml and is run by check. The surfaces that actually read the file do not go through it:

  • loadSecretsConfiginternal/cli/secrets.go
  • source.loadConfiginternal/source/loader.go

Both reach for os.ReadFile, and os.ReadFile blocks in the open on a FIFO with no writer, so no error path below it ever runs. A directory or socket fails rather than hangs; the FIFO is the sharp shape.

Note this is not a regression from PR #237 — at base e452f7d check hung too. That PR fixed the report surface and left the reading surfaces as they were.

Why it was deferred rather than fixed in PR #237

Scope: the read sites include internal/source, which that PR does not otherwise touch, and its subject is the [secrets] block. The known-exception note in internal/cli/sourceinit_guard_internal_test.go has been updated to record the measured gap and to retract the reason it previously gave for declining — that folding the check in "would mean stat-ing a file it is about to read". Both secrets.CheckIdentityPermissions and secrets.openVault now do exactly that, deliberately, because a stat is the only way to learn a path's shape without an open that may never return. The remaining objection is scope, not principle.

Suggested fix

Apply the shape rule at the point of the read, in the shape PR #237 settled on: prefer a helper that returns the data or the handle over a separate Check* predicate the callers must remember to call first, so the bytes cannot be obtained without passing the gate. secrets.openVault / secrets.ReadVault (internal/secrets/age.go) are the precedent. A stat failure should keep falling through to the read so a genuinely missing agentsync.toml still gets its existing "run agentsync init" message rather than a shape error.

Test note

Nothing currently tests sourceInitConfigNotFile, and there is no Mkfifo anywhere in internal/cli's tests. A regression test here must be timeout-bounded — this class of bug hangs rather than fails, so a plain call wedges CI with no diagnostic. See TestVaultShapeGate (internal/secrets/age_fifo_unix_test.go) and TestWriteSecretsVerifiedSurvivesNonRegularVault (internal/cli/secrets_vault_shape_unix_internal_test.go) for the pattern.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions