diff --git a/.github/workflows/conventions.yml b/.github/workflows/conventions.yml index f40c1cd..222eda1 100644 --- a/.github/workflows/conventions.yml +++ b/.github/workflows/conventions.yml @@ -5,4 +5,4 @@ on: pull_request: jobs: conventions: - uses: robertblust/conventions/.github/workflows/check.yml@v1.56.0 + uses: robertblust/conventions/.github/workflows/check.yml@v1.57.0 diff --git a/.gitignore b/.gitignore index e891cd6..7216875 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ node_modules .vscode .claudian .superpowers +# A tool's local settings can hold a secret; conventions-sync keeps the lines below. +**/.claude/settings.local.json diff --git a/AGENTS.md b/AGENTS.md index b6e6d8e..a99ff59 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ - + Shared conventions of the robertblust, guestgraph and companygraph organizations live in `conventions/`, vendored from robertblust/conventions at the release `conventions.json` names. Read them before writing or committing anything here. - `conventions/WRITING.md` — how we write: one voice, three registers, English and German. diff --git a/conventions.json b/conventions.json index 3b7a7b8..7559555 100644 --- a/conventions.json +++ b/conventions.json @@ -1 +1 @@ -{ "repo": "robertblust/conventions", "tag": "v1.56.0" } +{ "repo": "robertblust/conventions", "tag": "v1.57.0" } diff --git a/conventions/AGENTS.md b/conventions/AGENTS.md index ce2684b..7853d59 100644 --- a/conventions/AGENTS.md +++ b/conventions/AGENTS.md @@ -1,4 +1,4 @@ - + Shared conventions of the robertblust, guestgraph and companygraph organizations live in `conventions/`, vendored from robertblust/conventions at the release `conventions.json` names. Read them before writing or committing anything here. - `conventions/WRITING.md` — how we write: one voice, three registers, English and German. diff --git a/conventions/WORKING.md b/conventions/WORKING.md index 92139f2..5884a69 100644 --- a/conventions/WORKING.md +++ b/conventions/WORKING.md @@ -66,4 +66,4 @@ A review finding is an input to the person who merges, never a verdict. One find ## What is never written -Closed-source predecessor projects are not mentioned — in code, documentation, commits, pull requests, issues or release notes. Secrets are never printed, not to check them and not in a debug line; a value that reaches a transcript has to be rotated. +Closed-source predecessor projects are not mentioned — in code, documentation, commits, pull requests, issues or release notes. Secrets are never printed, not to check them and not in a debug line; a value that reaches a transcript has to be rotated. Nor is a secret written into a command: the command reads it from the environment or the keychain where it runs. A tool that may run a command unasked keeps that command in its local settings, secret and all, and a clone that does not ignore those settings commits them with the rest; `conventions-sync` keeps the line that ignores them in every member's own `.gitignore`, so the rule travels with every clone rather than living on one machine. diff --git a/conventions/conventions-sync b/conventions/conventions-sync index c5719b9..e88a718 100755 --- a/conventions/conventions-sync +++ b/conventions/conventions-sync @@ -43,6 +43,16 @@ ROOT_FILES=".markdownlint-cli2.jsonc CLAUDE.md" # holds a member's file to it — the settings key, the recommended ids — and to nothing else. SEEDS="conventions/vscode-settings.json:.vscode/settings.json conventions/vscode-extensions.json:.vscode/extensions.json" +# Lines every member's own .gitignore carries, because an ignore kept on one machine protects +# that machine only, and a clone made anywhere else commits what it never heard of. An agent +# harness writes each command a person allowed it to run unasked into its local settings, and a +# command allowed with a secret on its line keeps the secret there, so a clone that does not +# ignore the file pushes the secret with the rest. sync appends a missing line and leaves the +# rest of the file the member's; check names a missing line, and names the file wherever it is +# tracked, which an ignore cannot undo once it is committed. +IGNORES="**/.claude/settings.local.json" +IGNORE_NOTE="# A tool's local settings can hold a secret; conventions-sync keeps the lines below." + # What an earlier release vendored and this one does not. sync deletes them, so a member that # upgrades is left with one copy of a rule rather than two, and check names one still lying # around, which is a member that has not synced. @@ -128,6 +138,19 @@ hooks_path() { echo "✓ conventions: core.hooksPath is now $DIR/hooks; it is local config and not cloned, so a fresh clone runs sync once, or git config core.hooksPath $DIR/hooks" } +# ignores: append each line of IGNORES the member's .gitignore lacks, under one comment that +# says who keeps it. set -f keeps the shell from expanding the patterns against the disk. +ignores() { + set -f + for p in $IGNORES; do + [ -f .gitignore ] && grep -qxF "$p" .gitignore && continue + if [ -s .gitignore ] && [ "$(tail -c 1 .gitignore)" != "" ]; then printf '\n' >> .gitignore; fi + grep -qxF "$IGNORE_NOTE" .gitignore 2> /dev/null || printf '%s\n' "$IGNORE_NOTE" >> .gitignore + printf '%s\n' "$p" >> .gitignore + done + set +f +} + sync() { mkdir -p "$DIR" # A member running an older conventions-sync has an older FILES list, missing whatever file @@ -169,6 +192,7 @@ sync() { fi done for f in $RETIRED; do rm -f "$f"; done + ignores chmod +x "$DIR/conventions-sync" chmod +x "$DIR/conventions-check" chmod +x "$DIR/conventions-format" @@ -221,6 +245,18 @@ check() { echo "✗ conventions: $f is what an earlier release vendored and $TAG does not — run sync"; fail=1 fi done + set -f + for p in $IGNORES; do + if ! { [ -f .gitignore ] && grep -qxF "$p" .gitignore; }; then + echo "✗ conventions: .gitignore does not carry $p — run sync"; fail=1 + fi + if [ "$(git rev-parse --is-inside-work-tree 2> /dev/null)" = "true" ]; then + for t in $(git ls-files -- ":(top,glob)$p"); do + echo "✗ conventions: $t is committed — remove it with git rm --cached, and rotate every secret it ever held, because the history keeps it"; fail=1 + done + fi + done + set +f have="" [ -f AGENTS.md ] && have=$(block_of AGENTS.md) want=$(block_of "$DIR/AGENTS.md") diff --git a/conventions/manifest.json b/conventions/manifest.json index 5d08029..cab207b 100644 --- a/conventions/manifest.json +++ b/conventions/manifest.json @@ -1,9 +1,9 @@ { "repo": "robertblust/conventions", - "tag": "v1.56.0", + "tag": "v1.57.0", "files": { "conventions/WRITING.md": "sha256:51d9a902ec3038392160df07f86aba98d34db1d4dbfaa5f4a647590eaccfb390", - "conventions/WORKING.md": "sha256:3a7a6b4ab1bd23f2407fc6ada2dd0512710a49d233fa7c3342951f6fc526ab23", + "conventions/WORKING.md": "sha256:e3edb79a514d4d0accc5c515b0b751081dd47a43db59c70ca0840459f87204fa", "conventions/REPOSITORIES.md": "sha256:75ffac1aaf2523ba7d8fcd1175d6a63b7a42516883ef4a7af5dde52c564bee85", "conventions/PINS.md": "sha256:68df67ae820a8673d3130582aa829d4283176d3c8ec0a69adda3132a1a755b93", "conventions/WRITER.md": "sha256:bc3b92683130b75993f824f0e34073d4344846c91be2009fd90c39099fd4fd48", @@ -12,8 +12,8 @@ "conventions/GERMAN.md": "sha256:6a0ab79fd52f93d1361aceb83a1771ce6448124d5ea707af3d71baf9efe35e11", "conventions/EDITOR.md": "sha256:e65d0b2893ac841faefede9b873f7e33c1fd7b02bedf97d37d5362c0e83c08ea", "conventions/BACKREADER.md": "sha256:36b12d4bee8e4fe190469e2f550d50d8a7f6dcab6bec573da17eb1c165c417cd", - "conventions/AGENTS.md": "sha256:5b05af4f2355c57d05a18c3607cf0d625db72cb908f597f389daddd8b0e5515b", - "conventions/conventions-sync": "sha256:a190ff79c2d8d3f6f6d9a597e9f261654f2419d30e2ac43abf6c64ebe2c47ed9", + "conventions/AGENTS.md": "sha256:a3509fea1f90fb99e9cb673eee29b4605d875420fe7fcee01a29a5cf752908b8", + "conventions/conventions-sync": "sha256:77ad68826a42bbd3b20e240175831baeb83bcde3dc7edab0e0222520f15c70af", "conventions/conventions-check": "sha256:4a633cc53579f4577939702350c439bbb58ebed4ccbf6736d94c01e5fc160147", "conventions/conventions-format": "sha256:2911a0d30dda1bc0f621522a9538b3e39704eee03458e65ba320eccbf39b5c7f", "conventions/markdown-rules.cjs": "sha256:5cbf6120bf16e358b3a4e362015d054f0cd6e47ddfb0e5fe5ac17143b2bdef26",