Skip to content

2026-07-26: The Secret That Was Never Missing

A pencil-sketched glass display case holding a single ornate key, lit by a teal halo. A mechanical hand reaches in from the left and stops flat against the glass, able to see the key but not reach it. A small handwritten note lies at the base of the case, and an Abyssinian cat lounges on top looking down, unimpressed.

A background job had been failing quietly and reporting missing credential. The credential was not missing. It had never been missing. It sat in the keychain the entire time, and the daemon asking for it simply was not allowed to look.

Picture the hero image. A key under glass, a mechanical hand flat against the pane, and Tommy the Abyssinian lounging on top of the case, unimpressed — because from where he sits, the thing everyone is hunting for is right there in plain view. That gap, between what an error says and what is true, is the whole story. It cost more time than the bug deserved.

com.sanctum.bridge-manifest-sync keeps the Sanctum bridge’s manifest current. The bridge is how Triptyq skills reach SharePoint, so when it drifts, filing quietly stops being trustworthy.

The log was almost comically unhelpful:

no change
no change
… (nineteen times)
missing credential: set $CF_ACCESS_ID or keychain entry 'sanctum-bridge-cf-access-client-id'

Nineteen clean runs, then failure — with nothing deleted, nothing rotated, and nothing edited. The obvious reading is “someone removed the secret.” The obvious reading was wrong. We have been burned by quiet failures before, for seventeen days once; the reflex now is to distrust the message before the machine.

security find-generic-password has three outcomes, and only two of them are usually considered:

OutcomeExitMeans
found + returned0you have it
not found44it genuinely does not exist
found, refused36errSecInteractionNotAllowed — it exists, you may not read it

A LaunchAgent has no GUI session, so an unlocked-keychain prompt cannot be shown. macOS therefore returns 36. The script treated any falsy result as absence and printed missing credential.

The two states need opposite responses. “Absent” means mint a new token. “Present but locked” means do not mint a new token — you would be revoking a perfectly good credential to solve a permissions problem.

Two changes, and the second matters more than the first.

Resolution order. env → SOPS-first resolver → raw keychain. The middle rung is ~/.sanctum/scripts/keychain-read.sh, which reads SOPS before the keychain. SOPS has no interactive-session constraint, which is exactly why the trifecta defaults to it for anything a daemon must read. The raw keychain stays last so interactive machines keep working.

Honest diagnosis. The error now distinguishes the two states and says what not to do:

credential 'sanctum-bridge-cf-access-client-id' EXISTS in the keychain but is not
readable from here (errSecInteractionNotAllowed / exit 36). This is a
headless-context problem, NOT a missing secret — do not go re-minting it.

An error message is an interface. This one now teaches instead of misleading.

The part still open, and why it is not ours to close

Section titled “The part still open, and why it is not ours to close”

The sync is not green yet, and deliberately so. The credential must land somewhere a daemon can read — but it is a Triptyq credential (a Cloudflare Access token fronting Triptyq SharePoint), and Triptyq secrets live in the corporate vault, not the haus store.

Dropping it into the personal SOPS store would fix the job tonight and quietly erode the boundary that keeps the haus independent of corporate infrastructure. So the job stays amber, with an accurate message, until the value is placed deliberately.

  1. Test in both directions. A guard nobody has watched fail is not a guard — the harness asserts the new message appears and that the old missing credential string does not.
  2. Classify honestly. The two credential checks report PENDING, not FAIL: they are blocked on a human-gated secret, not broken. A harness that cries wolf trains you to ignore it.
  3. Leave the boundary decision to the person who owns it.

Result: 8 passed, 0 failed, 2 pending.

SharePoint was already on disk. While tracing the bridge, the documented filing destination turned out to be a local path — the OneDrive shared-libraries mount carries 02_<Fund> I SEC/02_Financial/ verbatim. A pipeline that was assumed to need a Graph client may need a file copy. Worth checking before building the API integration nobody asked for.

A plugin that could not be installed. The skills repo shipped plugin.json but no marketplace.json, so there was nothing for /plugin marketplace add to enumerate. Nine skills, zero of them installable. Added.

An error message is not a diagnosis. This one named the right variable and drew the wrong conclusion from it, and because it sounded specific, it was believed.

When a check reports something missing, ask whether it can tell missing from forbidden. If it cannot, it is not reporting a fact — it is reporting the absence of permission to establish one.