From cd62dcbd0d1769c66edfe0d120d4c3676e933f14 Mon Sep 17 00:00:00 2001 From: Evan Alter Date: Sun, 12 Jul 2026 20:05:58 -0500 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=F0=9F=94=90=20make?= =?UTF-8?q?=20.extra.tmpl=20actually=20renderable=20by=20op=20inject?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit op inject parses the entire template — comments included — and errors on any curly-brace pair or bare op:// text that isn't a real secret reference. The template's self-documenting comments contained both, so every render failed (including bootstrap's, which misreported it as an auth failure). Instructions move to CLAUDE.md where literal syntax is safe; the template keeps only a pointer and the parser warning. Verified: `op inject -i .extra.tmpl` now renders cleanly, with no auth needed while the template holds no references. Co-Authored-By: Claude Fable 5 --- .extra.tmpl | 26 ++++++-------------------- CLAUDE.md | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/.extra.tmpl b/.extra.tmpl index 4a828deb1db..ffa481e9bf2 100644 --- a/.extra.tmpl +++ b/.extra.tmpl @@ -2,24 +2,10 @@ # # ~/.extra — machine-local secrets / overrides, sourced last by .zshrc. # -# This TEMPLATE is tracked in the repo. bootstrap.sh renders it to ~/.extra -# with 1Password's `op inject` (output mode 0600), so real secret *values* -# never touch the repo — only op:// reference paths do. The rendered ~/.extra -# is gitignored. +# Rendered to ~/.extra by 1Password's `op inject` (bootstrap.sh runs it when +# ~/.extra is missing). See CLAUDE.md "Machine-local secrets" for the exact +# reference format and workflow. # -# To add a secret: -# 1. Store it in 1Password. -# 2. Add an export below whose value is the secret's reference path, WRAPPED -# IN DOUBLE CURLY BRACES. The commented examples show the path format; -# to activate one, uncomment it and wrap the op://... path in {{ }}. -# (In the 1Password app: right-click a field -> "Copy Secret Reference".) -# 3. Re-render (bootstrap.sh only renders when ~/.extra is missing): -# op inject -i .extra.tmpl -o ~/.extra -f -# -# With no braced references present, this renders to an (inert) ~/.extra. -# -# --- Examples — path format only; uncomment + add {{ }} to activate --------- - -# export GITHUB_TOKEN="op://Private/GitHub PAT/token" -# export ANTHROPIC_API_KEY="op://Private/Anthropic API/credential" -# export HOMEBREW_GITHUB_API_TOKEN="op://Private/GitHub PAT/token" +# WARNING: op inject parses this ENTIRE file, comments included. Never write +# curly-brace pairs or an "op" URI scheme anywhere in it except as a real, +# brace-wrapped secret reference — anything else is a render error. diff --git a/CLAUDE.md b/CLAUDE.md index c397cbf0a71..82a2753bd1e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -86,3 +86,20 @@ only exists locally). There is **no GPG keypair** in this setup despite the ### Machine-local customization Add `~/.extra` (not committed) for per-machine overrides. Add `~/.path` for per-machine PATH entries. The `.macos` script skips the computer name block if `$COMPUTER_NAME` is unset. + +### Machine-local secrets (~/.extra) + +`~/.extra` is rendered from the tracked `.extra.tmpl` by 1Password's +`op inject`. bootstrap.sh runs it automatically when `~/.extra` is missing; +re-render manually with `op inject -i .extra.tmpl -o ~/.extra -f`. The +template stores only secret *references*, never values: + + export GITHUB_TOKEN="{{ op://Private/GitHub PAT/token }}" + +Get a reference path from the 1Password app: right-click a field → +"Copy Secret Reference". + +CAUTION: `op inject` parses the whole template, comments included, and +errors on any curly-brace pair or bare `op://` text that isn't a real +brace-wrapped reference. That's why these instructions live here and not in +the template itself. `tests/extra-tmpl.bats` enforces the invariant. From f4cb63bd757369f53426c82dc823a1d4be423cf7 Mon Sep 17 00:00:00 2001 From: Evan Alter Date: Sun, 12 Jul 2026 20:06:12 -0500 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=85=20test:=20enforce=20op-inject-saf?= =?UTF-8?q?e=20invariants=20on=20.extra.tmpl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guards the constraint that broke rendering: comment lines must never contain brace pairs or op:// text, and any real reference must be brace-wrapped with vault/item/field segments. Runs on CI without the op CLI. Co-Authored-By: Claude Fable 5 --- tests/extra-tmpl.bats | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/extra-tmpl.bats diff --git a/tests/extra-tmpl.bats b/tests/extra-tmpl.bats new file mode 100644 index 00000000000..9cd4b59c666 --- /dev/null +++ b/tests/extra-tmpl.bats @@ -0,0 +1,31 @@ +#!/usr/bin/env bats + +# op inject parses ALL of .extra.tmpl — comments included — and errors on +# any curly-brace pair or bare op:// text that isn't a real brace-wrapped +# secret reference. These tests enforce that invariant without needing the +# op CLI (CI runners don't have it); real references only ever appear on +# non-comment export lines. + +TMPL=".extra.tmpl" + +@test "extra.tmpl comment lines contain no curly braces" { + cd "$BATS_TEST_DIRNAME/.." + run grep -nE '^[[:space:]]*#.*(\{\{|\}\})' "$TMPL" + [ "$status" -ne 0 ] +} + +@test "extra.tmpl comment lines contain no op:// references" { + cd "$BATS_TEST_DIRNAME/.." + run grep -nE '^[[:space:]]*#.*op://' "$TMPL" + [ "$status" -ne 0 ] +} + +@test "extra.tmpl secret references are brace-wrapped and well-formed" { + cd "$BATS_TEST_DIRNAME/.." + # Any op:// on an active line must look like "{{ op://vault/item/field }}" + # (at least three path segments) — a bare or malformed reference is a + # render error waiting to happen. + while IFS= read -r line; do + [[ "$line" =~ \{\{\ *op://[^/]+/[^/]+/[^}]+\ *\}\} ]] + done < <(grep -E '^[^#]*op://' "$TMPL" || true) +}