From f13fc9cf50935b79e954d17982a331c86d84bc33 Mon Sep 17 00:00:00 2001 From: Ulises Chavarria Date: Thu, 30 Jul 2026 13:35:11 -0700 Subject: [PATCH 1/2] chore(railguard): allow lowercase ~/bitbucket dev root The fence matches path strings literally and Linux is case-sensitive, so "~/Bitbucket" never covered the actual ~/bitbucket checkouts. Co-Authored-By: Claude Fable 5 --- agentic-ai/Claude/railguard.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/agentic-ai/Claude/railguard.yaml b/agentic-ai/Claude/railguard.yaml index 9cbca6f..cf30a69 100644 --- a/agentic-ai/Claude/railguard.yaml +++ b/agentic-ai/Claude/railguard.yaml @@ -35,6 +35,11 @@ fence: - "/tmp" - "~/github" - "~/Github" + # Both cases: the fence matches literally and Linux paths are + # case-sensitive, so "~/Bitbucket" alone never matched the actual + # ~/bitbucket checkouts — which is why projects there had to enumerate + # every subpath by hand. + - "~/bitbucket" - "~/Bitbucket" denied_paths: - "~/.ssh" From f74b0a09074bd886fa4d9bf4ab4993adbb453212 Mon Sep 17 00:00:00 2001 From: Ulises Chavarria Date: Thu, 30 Jul 2026 13:35:11 -0700 Subject: [PATCH 2/2] feat(ssh): add agent timeout for passphrase-protected keys When a passphrase is set, prompt for how long ssh-agent keeps the key unlocked (minutes, default 15; 0 = never cache, ask on every use). The generated Host block gets a matching AddKeysToAgent interval so keys re-added on first use expire too, instead of staying unlocked forever. Co-Authored-By: Claude Fable 5 --- SSH_and_GPG/README.md | 3 +++ SSH_and_GPG/create_ssh_key.sh | 36 ++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/SSH_and_GPG/README.md b/SSH_and_GPG/README.md index ed8147a..fbdb29f 100644 --- a/SSH_and_GPG/README.md +++ b/SSH_and_GPG/README.md @@ -32,6 +32,7 @@ Creates an Ed25519 SSH key for authenticating to a Git host (GitHub, GitLab, Bit **What it does:** - Prompts for an email (used as the key comment), Git host, key filename, and optional passphrase +- For passphrase-protected keys: prompts for an agent timeout in minutes (default `15`) — `ssh-agent` keeps the key unlocked that long after each `ssh-add`, so you aren't re-typing the passphrase on every push; `0` disables caching entirely (passphrase asked on every use). The `Host` block gets a matching `AddKeysToAgent m` (needs OpenSSH 8.7+) so keys re-added on first use expire too - Generates the key in `~/.ssh/` (skips generation if the key already exists, with an overwrite prompt) - Adds the key to `ssh-agent` and updates `~/.ssh/config` with a `Host` block (idempotent) - For self-hosted servers: prompts for an SSH port (default `22`) and writes an alias with `HostName`, `Port`, and `User git` so you can clone as `git clone :/.git` @@ -43,6 +44,8 @@ Creates an Ed25519 SSH key for authenticating to a Git host (GitHub, GitLab, Bit bash create_ssh_key.sh # or pre-fill inputs via env vars: EMAIL="jane@example.com" GIT_HOST="github.com" KEY_NAME="github" bash create_ssh_key.sh +# Passphrase-protected key, cached in ssh-agent for 30 minutes: +EMAIL="jane@example.com" GIT_HOST="github.com" KEY_NAME="github" SSH_PASSPHRASE="..." AGENT_TIMEOUT=30 bash create_ssh_key.sh # Self-hosted Git server: EMAIL="jane@example.com" IS_SELF_HOSTED=true GIT_HOSTNAME="hostname.ts.net" GIT_HOST="gitserver" GIT_SSH_PORT=22 bash create_ssh_key.sh ``` diff --git a/SSH_and_GPG/create_ssh_key.sh b/SSH_and_GPG/create_ssh_key.sh index d8d0703..69acaac 100755 --- a/SSH_and_GPG/create_ssh_key.sh +++ b/SSH_and_GPG/create_ssh_key.sh @@ -102,6 +102,19 @@ if [[ -z "$SSH_PASSPHRASE" ]]; then esac fi +# ---- Agent timeout (passphrase-protected keys only) ---- +AGENT_TIMEOUT="${AGENT_TIMEOUT:-}" +if [[ -n "$SSH_PASSPHRASE" ]]; then + if [[ -z "$AGENT_TIMEOUT" ]]; then + read -r -p "Minutes ssh-agent keeps the key unlocked (0 = ask every time) [15]: " AGENT_TIMEOUT + AGENT_TIMEOUT="${AGENT_TIMEOUT:-15}" + fi + if [[ ! "$AGENT_TIMEOUT" =~ ^[0-9]+$ ]]; then + echo "Error: AGENT_TIMEOUT must be a whole number of minutes." >&2 + exit 1 + fi +fi + SSH_DIR="$HOME/.ssh" KEY_PATH="$SSH_DIR/$KEY_NAME" PUB_PATH="$KEY_PATH.pub" @@ -139,7 +152,24 @@ if [[ -z "${SSH_AUTH_SOCK:-}" ]]; then fi # ---- Add key to agent ---- -ssh-add "$KEY_PATH" +if [[ -n "$SSH_PASSPHRASE" && "$AGENT_TIMEOUT" == "0" ]]; then + echo "Not adding key to ssh-agent: passphrase will be asked on every use." +elif [[ -n "$SSH_PASSPHRASE" ]]; then + ssh-add -t "${AGENT_TIMEOUT}m" "$KEY_PATH" +else + ssh-add "$KEY_PATH" +fi + +# AddKeysToAgent with a time interval needs OpenSSH 8.7+; without it, a key +# re-added on first use would stay unlocked forever, defeating the timeout. +ADD_KEYS_TO_AGENT="yes" +if [[ -n "$SSH_PASSPHRASE" ]]; then + if [[ "$AGENT_TIMEOUT" == "0" ]]; then + ADD_KEYS_TO_AGENT="no" + else + ADD_KEYS_TO_AGENT="${AGENT_TIMEOUT}m" + fi +fi # ---- Update ~/.ssh/config idempotently ---- touch "$CFG_PATH" @@ -164,14 +194,14 @@ if [[ -n "$IS_SELF_HOSTED" ]]; then # Port 22 is the SSH default — only emit the line for a non-standard port. [[ -n "$GIT_SSH_PORT" && "$GIT_SSH_PORT" != "22" ]] && echo " Port $GIT_SSH_PORT" echo " User git" - echo " AddKeysToAgent yes" + echo " AddKeysToAgent $ADD_KEYS_TO_AGENT" echo " IdentityFile $KEY_PATH" } >> "$CFG_PATH" else { echo "" echo "Host $GIT_HOST" - echo " AddKeysToAgent yes" + echo " AddKeysToAgent $ADD_KEYS_TO_AGENT" # macOS keychain optional: # echo " UseKeychain yes" echo " IdentityFile $KEY_PATH"