Skip to content
Merged

kyber #408

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
c2366cc
feat(fish): update _kyber_function to use Tailscale for SSH access
shunkakinoki Dec 10, 2025
14d4e3a
feat(nix): update installation instructions to use Determinate Nix
shunkakinoki Dec 11, 2025
1f1a6c0
fix(flake.lock): update NUR lock details for consistency
shunkakinoki Dec 11, 2025
6a7d973
feat(settings): enhance security by adding read/write deny rules for …
shunkakinoki Dec 11, 2025
7a2b982
fix(config): update ampcode management restriction to allow remote ac…
shunkakinoki Dec 11, 2025
1f505b0
fix(config): restrict remote management access and enforce localhost-…
shunkakinoki Dec 11, 2025
0343b17
feat(config): inject CLIPROXY_MANAGEMENT_PASSWORD into config and upd…
shunkakinoki Dec 11, 2025
476871f
feat(fish): add _kybers_function for SSH to Kyber server via Tailscale
shunkakinoki Dec 12, 2025
afd3a68
fix(Makefile): add launchctl to switch target for Nix configuration a…
shunkakinoki Dec 12, 2025
ec66ff5
fix(flake.lock): update locked versions and hashes for dependencies
shunkakinoki Dec 12, 2025
4363561
fix(start.sh): export MANAGEMENT_PASSWORD for Management API
shunkakinoki Dec 12, 2025
75688a1
feat(settings): add dangerouslySkipPermissions flag to model configur…
shunkakinoki Dec 12, 2025
8146010
fix(settings): replace dangerouslySkipPermissions with disableBypassP…
shunkakinoki Dec 12, 2025
6dae014
fix(settings): add defaultMode to bypassPermissions in model configur…
shunkakinoki Dec 12, 2025
3516598
fix(settings): remove disableBypassPermissionsMode and clean up setti…
shunkakinoki Dec 12, 2025
a0048b0
fix(settings): update cleanupPeriodDays to 300 in settings.json
shunkakinoki Dec 12, 2025
3b6032c
fix(settings): revert cleanupPeriodDays to -1 in settings.json
shunkakinoki Dec 12, 2025
26a79e7
fix(settings): update cleanupPeriodDays to 99999 in settings.json
shunkakinoki Dec 12, 2025
030c48d
feat(security): add security.sh script to block dangerous Bash commands
shunkakinoki Dec 12, 2025
221c2de
Merge remote-tracking branch 'origin/main' into kyber
shunkakinoki Dec 12, 2025
96d36ec
fix(pushover): skip notifications for "other" session end reason
shunkakinoki Dec 12, 2025
d19f041
feat(tests): add ShellSpec tests and integrate into CI workflow
shunkakinoki Dec 12, 2025
3e56c76
feat(ci): streamline Shell workflow and add Nix dev shell testing
shunkakinoki Dec 12, 2025
8e1bbe2
feat(devenv): add ShellSpec to development environment packages
shunkakinoki Dec 12, 2025
19fd5e6
feat(ci): add ShellCheck to CI workflow and development environment
shunkakinoki Dec 12, 2025
d2132c3
feat(scripts): add shellcheck directives to notify and install scripts
shunkakinoki Dec 12, 2025
5b89d01
feat(tests): add ShellCheck directive to pushover_spec.sh
shunkakinoki Dec 12, 2025
e4851ed
feat(tests): add ShellCheck directive to security_spec.sh
shunkakinoki Dec 12, 2025
70814c9
feat(scripts): add ShellCheck directive to security.sh and sync.sh
shunkakinoki Dec 12, 2025
1b42be5
feat(tests): refactor test scripts for improved readability and consi…
shunkakinoki Dec 12, 2025
6c3bf11
feat(scripts): fix shellspec wrapper script to support symlink execution
shunkakinoki Dec 12, 2025
0ef2d9a
feat(tests): refactor pushover_spec.sh to use mock curl setup
shunkakinoki Dec 12, 2025
6df2499
fix(tests): adjust spacing in mock curl setup for consistency
shunkakinoki Dec 12, 2025
e33cb88
chore: update
shunkakinoki Dec 12, 2025
12b07a7
feat(tests): refactor notify_spec.sh to use mock osascript and cleanu…
shunkakinoki Dec 12, 2025
4b82fb0
fix(tests): update pushover_spec.sh to use fake HOME for credential h…
shunkakinoki Dec 12, 2025
0baa002
fix(tests): update notify_spec.sh to use fake HOME for notification t…
shunkakinoki Dec 12, 2025
6365552
fix(tests): update pushover_spec.sh to unset credentials before runni…
shunkakinoki Dec 12, 2025
fc5dcae
fix(tests): enhance pushover_spec.sh to unset credentials for credent…
shunkakinoki Dec 12, 2025
e949d4e
fix(tests): update notify_spec.sh to use echo for message input in tests
shunkakinoki Dec 13, 2025
c5a1a12
fix(tests): simplify credential handling in pushover_spec.sh tests
shunkakinoki Dec 13, 2025
5ec2977
fix(tests): change shellspec command to run in bash for compatibility
shunkakinoki Dec 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
# Copy to home-manager/.env and provide real values. The .env file stays local.
MY_SECRET=replace-me
# GITHUB_TOKEN=ghp_your_token_here
CLIPROXY_MANAGEMENT_PASSWORD=your-management-key-here

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Optional: reorder keys if dotenv-linter is enforced in CI.
If dotenv-linter warnings fail the pipeline, move CLIPROXY_MANAGEMENT_PASSWORD above MY_SECRET; otherwise this is fine.

🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 5-5: [UnorderedKey] The CLIPROXY_MANAGEMENT_PASSWORD key should go before the MY_SECRET key

(UnorderedKey)

🤖 Prompt for AI Agents
In .env.example around line 5, dotenv-linter may flag variable order; move
CLIPROXY_MANAGEMENT_PASSWORD above MY_SECRET to satisfy lint ordering. Edit the
file to place the CLIPROXY_MANAGEMENT_PASSWORD entry before the MY_SECRET entry
so dotenv-linter (if enforced in CI) no longer reports ordering warnings.

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example value 'your-management-key-here' should be more descriptive about what kind of value is expected. Consider using a more realistic placeholder like 'a-secure-random-password' or adding a comment explaining that this should be a strong, randomly generated password for the CLIProxyAPI Management API.

Suggested change
CLIPROXY_MANAGEMENT_PASSWORD=your-management-key-here
# This should be a strong, randomly generated password for the CLIProxyAPI Management API
CLIPROXY_MANAGEMENT_PASSWORD=a-secure-random-password

Copilot uses AI. Check for mistakes.
48 changes: 48 additions & 0 deletions .github/workflows/shell.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Shell
on:
push:
branches:
- main
pull_request:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.sha }}
cancel-in-progress: true
jobs:
shellspec:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- name: Run ShellSpec Tests (Dev Shell)
run: make shell-test-dev
shellcheck:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- name: Run ShellCheck (Dev Shell)
run: make shell-check-dev
shell-check:

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The job name 'shell-check' is inconsistent with the actual jobs defined above ('shellspec' and 'shellcheck'). While this is just the final status check job, the naming could be clearer - consider renaming to 'shell-tests-status' or similar to better indicate it's an aggregation of the shell testing jobs.

Suggested change
shell-check:
shell-tests-status:

Copilot uses AI. Check for mistakes.
if: always()
needs:
- shellspec
- shellcheck
runs-on: ubuntu-latest
timeout-minutes: 3
steps:
- name: Alls Green
uses: re-actors/alls-green@release/v1
with:
jobs: ${{ toJSON(needs) }}
3 changes: 3 additions & 0 deletions .shellspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--require spec_helper
--format progress
--shell bash
30 changes: 26 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ setup: nix-setup ## Basic Nix setup (alias for nix-setup).
setup-dev: nix-setup git-submodule-sync shell-install ## Set up local development environment (Nix + submodules + shell).

.PHONY: switch
switch: nix-switch ## Apply Nix configuration and restart launchd agents.
switch: nix-switch launchctl ## Apply Nix configuration and restart launchd agents.
Comment on lines 137 to +138

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge switch target now fails on non-macOS hosts

The switch target now depends on launchctl (lines 137‑138), but the launchctl target further down the Makefile unconditionally runs the macOS launchctl kickstart … commands. On Linux or CI runners, make switch (and any target that invokes it, e.g., make install/update) will now abort with launchctl: command not found, whereas previously it succeeded because switch only ran nix-switch. This makes the standard configuration apply workflow unusable off macOS.

Useful? React with 👍 / 👎.


.PHONY: test
test: neovim-test
test: neovim-test shell-test ## Run all tests (neovim + shell).

Comment on lines 137 to 142

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

make switch will fail on Linux now (because launchctl is a hard dependency).

This is especially problematic because named-hosts/kyber/README.md instructs running make switch on Ubuntu.

-.PHONY: switch
-switch: nix-switch launchctl ## Apply Nix configuration and restart launchd agents.
+.PHONY: switch
+switch: nix-switch ## Apply Nix configuration and restart launchd agents (macOS only).
+ifeq ($(OS),Darwin)
+	@$(MAKE) launchctl
+else
+	@echo "ℹ️ launchctl skipped on $(OS)"
+endif

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
Makefile lines 137-142: the switch target currently hard-depends on launchctl
which exists only on macOS, causing make switch to fail on Linux; change the
Makefile so the launchctl dependency is conditional: detect the OS (uname) or
set a variable (e.g., LAUNCHCTL := launchctl on Darwin, empty otherwise) and
make switch depend on that variable (or make launchctl a no-op on non-Darwin),
ensuring make switch runs on Linux without requiring launchctl.

.PHONY: update
update: nix-update shell-update neovim-update ## Update Nix flake and configurations.
Expand Down Expand Up @@ -202,8 +202,8 @@ devenv-cli: ## Build the packaged devenv CLI binary.
.PHONY: nix-install
nix-install: ## Install Nix if not already installed.
@if [ "$(NIX_ENV)" = "not_found" ]; then \
echo "🚀 Installing Nix environment for $(NIX_CONFIG_TYPE) on $(OS) $(ARCH) for USER=$(NIX_USERNAME)"; \
curl -L https://nixos.org/nix/install | sh; \
echo "🚀 Installing Determinate Nix environment for $(NIX_CONFIG_TYPE) on $(OS) $(ARCH) for USER=$(NIX_USERNAME)"; \
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install; \
fi
Comment on lines +205 to 207

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Determinate Nix installer official documentation recommended installation command

💡 Result:

Recommended one‑liner (from Determinate official docs):

curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --determinate

Sources: Determinate manual and installer repo. [1][2]

References
[1] Determinate Nix Quick Start / Introduction.
[2] Determinate Systems — nix-installer (GitHub / project page).


🌐 Web query:

Determinate Nix installer checksum signature verification security

💡 Result:

Short answer

  • The Determinate Nix installer is distributed over HTTPS from install.determinate.systems and its source is public on GitHub (DeterminateSystems/nix-installer). That gives TLS protection and an auditable source tree, but the common one‑liner (curl … | sh) does not, by itself, perform an independent checksum/GPG signature verification step in the client-side flow. [1][2]

What that means for security

  • TLS (HTTPS) protects against network interception/modification if you trust the CA and DNS; it does not protect you from a compromised server, supply‑chain compromise, or a malicious push to the repo. [2]
  • The project’s repo and releases are publicly auditable, so the strongest protections are: pinning to a specific, reviewed release (or commit) and verifying that release in ways you control (release artifacts, checksums, or Git tag signatures) before running installers. [1]

Practical verification / hardening steps

  1. Pin a specific installer release or commit instead of using the floating one‑liner. Example: download a pinned tag from the repo/releases or the installer URL that includes a version. Then verify the content locally. [1]
  2. Verify the downloaded installer binary/script: check its SHA256 against a checksum you obtained from a trusted channel (release page, reproducible CI artifact) or verify a signed Git tag if the project provides one. If no signed checksum exists, prefer downloading the source and building/inspecting it locally. [1]
  3. Inspect the installer script before running it (curl … -o nix-installer && less ./nix-installer) and run it only after review. Use sh -x or run in a contained environment (VM/container) first. [1][4]
  4. Use reproducible/pinned Nix packages (pin nixpkgs or use Determinate Nix’s pinned flake outputs) so post-install provenance is bounded. Determinate docs encourage pinning and provide flake/module outputs. [2][6]
  5. Prefer platform packages (e.g., Determinate.pkg on macOS) or official release artifacts over the network one‑liner when possible. [2]

If you need absolute integrity guarantees

  • Ask the maintainers for cryptographic checksums and detached signatures, or check whether GitHub release artifacts are signed by a maintainer GPG key you trust. If those aren’t available, you must rely on TLS + pinning + review or build-from-source for higher assurance. (I couldn’t find a documented detached signature or signed checksum for the installer on the public pages I checked.) [1][2]

Sources

  • DeterminateSystems/nix-installer (GitHub repo, README — installer, pinning, usage notes). [1]
  • Determinate Systems documentation and install pages (install.determinate.systems, docs.determinate.systems — installer over HTTPS, recommended install flows, macOS package recommendation). [2][6]

If you want, I can: (a) check a specific release page for release artifacts/checksums/signatures, (b) show the exact curl+verify commands to pin and verify SHA256, or (c) walk you through verifying a downloaded installer on your machine. Which would you like?


Add --determinate flag to the Nix installer invocation.

The Determinate official documentation recommends: curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --determinate. The Makefile command is missing the --determinate flag, which enables Determinate's managed/pinned installation mode. Update line 206 to include this flag.

Note: The curl | sh pattern is Determinate's own recommended invocation. The HTTPS and TLS settings are appropriate. Cryptographic checksum or signature verification is not offered as part of Determinate's standard one-liner; if supply-chain hardening is required, custom pinning and verification steps would need to be added separately.

🤖 Prompt for AI Agents
Makefile around lines 205 to 207: the Determinate Nix installer invocation is
missing the --determinate flag; update the curl | sh command on line 206 to pass
--determinate to the installer (i.e., the sh -s -- install invocation should
include --determinate) so the installer runs in Determinate's managed/pinned
mode.

@echo "✅ Nix environment installed!"

Expand Down Expand Up @@ -624,3 +624,25 @@ git-submodule-sync: ## Sync and update git submodules.
@git submodule sync
@git submodule update --init --recursive
@echo "✅ Submodules synced and updated"

##@ Shell

.PHONY: shell-test
shell-test: ## Run shell script tests using ShellSpec.
@echo "🧪 Running shell tests..."
@bash -c "shellspec"

.PHONY: shell-test-dev
shell-test-dev: ## Run shell tests inside the Nix dev shell (mirrors CI).
@echo "🧪 Running shell tests inside the Nix dev shell..."
@DEVENV_ROOT=$(CURDIR) $(NIX_ALLOW_UNFREE) $(NIX_EXEC) develop $(NIX_FLAGS) .# --command $(MAKE) shell-test

.PHONY: shell-check
shell-check: ## Run ShellCheck on shell scripts.
@echo "🔍 Running ShellCheck..."
@find . -name '*.sh' -not -path './node_modules/*' -not -path './.git/*' -not -path './result/*' | xargs shellcheck

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using find ... | xargs can be problematic if filenames contain spaces or special characters. While less likely for shell scripts, it's more robust to use find -exec which handles all filenames correctly.

	@find . -name '*.sh' -not -path './node_modules/*' -not -path './.git/*' -not -path './result/*' -exec shellcheck {} +


.PHONY: shell-check-dev
shell-check-dev: ## Run ShellCheck inside the Nix dev shell (mirrors CI).
@echo "🔍 Running ShellCheck inside the Nix dev shell..."
@DEVENV_ROOT=$(CURDIR) $(NIX_ALLOW_UNFREE) $(NIX_EXEC) develop $(NIX_FLAGS) .# --command $(MAKE) shell-check
Comment on lines +630 to +648

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make shell-check robust to spaces/newlines and “no files found” cases.

find ... | xargs shellcheck is brittle. Prefer -exec ... {} +:

 shell-check: ## Run ShellCheck on shell scripts.
 	@echo "🔍 Running ShellCheck..."
-	@find . -name '*.sh' -not -path './node_modules/*' -not -path './.git/*' -not -path './result/*' | xargs shellcheck
+	@find . -name '*.sh' \
+	  -not -path './node_modules/*' -not -path './.git/*' -not -path './result/*' \
+	  -exec shellcheck {} +

Based on learnings, follow ShellCheck recommendations.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.PHONY: shell-test
shell-test: ## Run shell script tests using ShellSpec.
@echo "🧪 Running shell tests..."
@shellspec
.PHONY: shell-test-dev
shell-test-dev: ## Run shell tests inside the Nix dev shell (mirrors CI).
@echo "🧪 Running shell tests inside the Nix dev shell..."
@DEVENV_ROOT=$(CURDIR) $(NIX_ALLOW_UNFREE) $(NIX_EXEC) develop $(NIX_FLAGS) .# --command $(MAKE) shell-test
.PHONY: shell-check
shell-check: ## Run ShellCheck on shell scripts.
@echo "🔍 Running ShellCheck..."
@find . -name '*.sh' -not -path './node_modules/*' -not -path './.git/*' -not -path './result/*' | xargs shellcheck
.PHONY: shell-check-dev
shell-check-dev: ## Run ShellCheck inside the Nix dev shell (mirrors CI).
@echo "🔍 Running ShellCheck inside the Nix dev shell..."
@DEVENV_ROOT=$(CURDIR) $(NIX_ALLOW_UNFREE) $(NIX_EXEC) develop $(NIX_FLAGS) .# --command $(MAKE) shell-check
.PHONY: shell-test
shell-test: ## Run shell script tests using ShellSpec.
@echo "🧪 Running shell tests..."
@shellspec
.PHONY: shell-test-dev
shell-test-dev: ## Run shell tests inside the Nix dev shell (mirrors CI).
@echo "🧪 Running shell tests inside the Nix dev shell..."
@DEVENV_ROOT=$(CURDIR) $(NIX_ALLOW_UNFREE) $(NIX_EXEC) develop $(NIX_FLAGS) .# --command $(MAKE) shell-test
.PHONY: shell-check
shell-check: ## Run ShellCheck on shell scripts.
@echo "🔍 Running ShellCheck..."
@find . -name '*.sh' \
-not -path './node_modules/*' -not -path './.git/*' -not -path './result/*' \
-exec shellcheck {} +
.PHONY: shell-check-dev
shell-check-dev: ## Run ShellCheck inside the Nix dev shell (mirrors CI).
@echo "🔍 Running ShellCheck inside the Nix dev shell..."
@DEVENV_ROOT=$(CURDIR) $(NIX_ALLOW_UNFREE) $(NIX_EXEC) develop $(NIX_FLAGS) .# --command $(MAKE) shell-check
🧰 Tools
🪛 checkmake (0.2.2)

[warning] 645-645: Missing required phony target "all"

(minphony)


[warning] 645-645: Missing required phony target "clean"

(minphony)

🤖 Prompt for AI Agents
In Makefile around lines 630 to 648, the shell-check target uses "find ... |
xargs shellcheck", which breaks on filenames with spaces/newlines and when no
matches are found; replace the pipeline with a find -exec form (or use -print0
with xargs -0) so ShellCheck is invoked safely and gracefully when no files
exist, preserving the same exclusion patterns; update shell-check-dev similarly
to mirror the change inside the Nix dev shell.

Comment on lines +645 to +648

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

checkmake warns missing all / clean phony targets—add minimal stubs if you care about that policy.

If you want to satisfy checkmake’s minphony, consider adding:

+.PHONY: all
+all: help ## Default “all” target.
+
+.PHONY: clean
+clean: ## No-op clean (dotfiles repo).
+	@true

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 checkmake (0.2.2)

[warning] 645-645: Missing required phony target "all"

(minphony)


[warning] 645-645: Missing required phony target "clean"

(minphony)

🤖 Prompt for AI Agents
In Makefile around lines 645 to 648, checkmake warns that `all` and `clean` are
missing as phony targets; add minimal stub targets named `all` and `clean` and
mark them phony so the policy is satisfied. Create simple no-op implementations
(e.g., a brief echo or a `true`/`:` command) for each target and ensure they are
listed in the .PHONY declaration so they don’t conflict with files of the same
name.

4 changes: 2 additions & 2 deletions README-nix.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
This repo can build and expose all CLI tools declared in `package.json` using the exact versions from the lockfile, via [dream2nix].

## Prerequisites
- Nix installed
- Flakes enabled (see Nix docs)
- Nix installed (recommended: [Determinate Nix](https://determinate.systems/nix-installer/))
- Flakes enabled (automatically enabled with Determinate Nix)

## Typical usage

Expand Down
5 changes: 5 additions & 0 deletions config/claude/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@
source = ./notify.sh;
executable = true;
};

home.file.".claude/security.sh" = {
source = ./security.sh;
executable = true;
};
}
1 change: 1 addition & 0 deletions config/claude/notify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
if [ -z "$PUSHOVER_API_TOKEN" ] || [ -z "$PUSHOVER_USER_KEY" ]; then
if [ -f "$HOME/dotfiles/.env" ]; then
set -a
# shellcheck source=/dev/null
source "$HOME/dotfiles/.env" 2>/dev/null
set +a
fi
Expand Down
6 changes: 5 additions & 1 deletion config/claude/pushover.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
# inherit shell environment variables
if [ -z "$PUSHOVER_API_TOKEN" ] || [ -z "$PUSHOVER_USER_KEY" ]; then
if [ -f "$HOME/dotfiles/.env" ]; then
# shellcheck source=/dev/null
set -a
# shellcheck source=/dev/null
source "$HOME/dotfiles/.env" 2>/dev/null
set +a
fi
Expand Down Expand Up @@ -112,8 +112,12 @@ if echo "$input" | jq -e '.message' >/dev/null 2>&1; then
fi

# Handle SessionEnd hook (priority 0 = normal)
# Skip "other" reason - it's a generic/unknown reason that's noisy
if echo "$input" | jq -e '.reason' >/dev/null 2>&1; then
REASON=$(echo "$input" | jq -r '.reason')
if [ "$REASON" = "other" ]; then
exit 0
fi
send_notification "👋 Session ended: ${REASON}" 0
exit 0
fi
Expand Down
73 changes: 73 additions & 0 deletions config/claude/security.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env bash

# Claude Code Security Hook
# Blocks dangerous Bash commands by checking against deny patterns
# Based on: https://wasabeef.jp/blog/claude-code-secure-bash
#
# This script runs as a PreToolUse hook and returns:
# - Exit code 0: Command is allowed
# - Exit code 2: Command is blocked

set -euo pipefail

# Read JSON input from stdin
input=$(cat)

# Extract tool name - only process Bash commands
tool_name=$(echo "$input" | jq -r '.tool.name // empty' 2>/dev/null)
[[ $tool_name != "Bash" ]] && exit 0

# Extract the command to be executed
command=$(echo "$input" | jq -r '.tool.input.command // empty' 2>/dev/null)
[[ -z $command ]] && exit 0

# Path to settings file with deny patterns
settings="$HOME/.claude/settings.json"
[[ ! -f $settings ]] && exit 0

# Read deny patterns from settings
mapfile -t deny_patterns < <(jq -r '.permissions.deny[]?' "$settings" 2>/dev/null)

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the settings file exists but has no deny patterns (or if jq fails), the deny_patterns array will be empty, which means the script will allow all commands. However, the script doesn't handle the case where jq fails to parse the settings.json file properly. Consider adding error handling to ensure that if the settings file is corrupted or unparseable, the script fails closed (blocks execution) rather than open (allows everything).

Suggested change
mapfile -t deny_patterns < <(jq -r '.permissions.deny[]?' "$settings" 2>/dev/null)
deny_patterns_jq_output=$(jq -r '.permissions.deny[]?' "$settings" 2>/dev/null)
jq_status=$?
if [[ $jq_status -ne 0 ]]; then
echo "BLOCKED by security.sh: Failed to parse settings file '$settings' (jq error)" >&2
exit 2
fi
mapfile -t deny_patterns <<< "$deny_patterns_jq_output"

Copilot uses AI. Check for mistakes.

Comment on lines +11 to +30

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fail-open safely when jq is missing or JSON is invalid (today it may fail-closed under set -euo pipefail).

With set -euo pipefail, any jq error in tool_name=$(echo ... | jq ...) / command=... / mapfile ... < <(jq ...) can exit the hook non-zero and unintentionally block all Bash tool usage.

 set -euo pipefail

+# If jq isn't available (or JSON is malformed), don't block tool execution.
+command -v jq >/dev/null 2>&1 || exit 0
+
 # Read JSON input from stdin
 input=$(cat)

 # Extract tool name - only process Bash commands
-tool_name=$(echo "$input" | jq -r '.tool.name // empty' 2>/dev/null)
+tool_name=$(echo "$input" | jq -r '.tool.name // empty' 2>/dev/null || true)
 [[ "$tool_name" != "Bash" ]] && exit 0

 # Extract the command to be executed
-command=$(echo "$input" | jq -r '.tool.input.command // empty' 2>/dev/null)
+command=$(echo "$input" | jq -r '.tool.input.command // empty' 2>/dev/null || true)
 [[ -z "$command" ]] && exit 0
@@
 # Read deny patterns from settings
-mapfile -t deny_patterns < <(jq -r '.permissions.deny[]?' "$settings" 2>/dev/null)
+mapfile -t deny_patterns < <(jq -r '.permissions.deny[]?' "$settings" 2>/dev/null || true)

As per coding guidelines (shellcheck resiliency for **/*.{sh,bash}), this also prevents “tool broke because jq glitched” failures. Based on learnings, follow ShellCheck recommendations.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
set -euo pipefail
# Read JSON input from stdin
input=$(cat)
# Extract tool name - only process Bash commands
tool_name=$(echo "$input" | jq -r '.tool.name // empty' 2>/dev/null)
[[ "$tool_name" != "Bash" ]] && exit 0
# Extract the command to be executed
command=$(echo "$input" | jq -r '.tool.input.command // empty' 2>/dev/null)
[[ -z "$command" ]] && exit 0
# Path to settings file with deny patterns
settings="$HOME/.claude/settings.json"
[[ ! -f "$settings" ]] && exit 0
# Read deny patterns from settings
mapfile -t deny_patterns < <(jq -r '.permissions.deny[]?' "$settings" 2>/dev/null)
set -euo pipefail
# If jq isn't available (or JSON is malformed), don't block tool execution.
command -v jq >/dev/null 2>&1 || exit 0
# Read JSON input from stdin
input=$(cat)
# Extract tool name - only process Bash commands
tool_name=$(echo "$input" | jq -r '.tool.name // empty' 2>/dev/null || true)
[[ "$tool_name" != "Bash" ]] && exit 0
# Extract the command to be executed
command=$(echo "$input" | jq -r '.tool.input.command // empty' 2>/dev/null || true)
[[ -z "$command" ]] && exit 0
# Path to settings file with deny patterns
settings="$HOME/.claude/settings.json"
[[ ! -f "$settings" ]] && exit 0
# Read deny patterns from settings
mapfile -t deny_patterns < <(jq -r '.permissions.deny[]?' "$settings" 2>/dev/null || true)

# Function to check if a command matches a pattern
# Supports glob-style wildcards
matches_pattern() {
local cmd="$1"
local pattern="$2"

# Extract pattern from Bash(...) format
if [[ $pattern =~ ^Bash\((.+)\)$ ]]; then
local check_pattern="${BASH_REMATCH[1]}"
# Remove trailing :* if present (legacy format)
check_pattern="${check_pattern%:*}"

# Use bash glob matching (extended globbing)
shopt -s extglob
# shellcheck disable=SC2053
if [[ $cmd == $check_pattern ]]; then
return 0
fi
shopt -u extglob
fi
return 1
}
Comment on lines +33 to +52

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Restore extglob even on a successful match (currently it can stay enabled until process exit).

Right now, return 0 happens before shopt -u extglob. Easy to make deterministic:

 matches_pattern() {
   local cmd="$1"
   local pattern="$2"
@@
     # Use bash glob matching (extended globbing)
-    shopt -s extglob
-    # shellcheck disable=SC2053
-    if [[ "$cmd" == $check_pattern ]]; then
-      return 0
-    fi
-    shopt -u extglob
+    local extglob_was_set=0 matched=1
+    shopt -q extglob && extglob_was_set=1
+    shopt -s extglob
+    # shellcheck disable=SC2053
+    [[ "$cmd" == $check_pattern ]] && matched=0
+    (( extglob_was_set == 1 )) || shopt -u extglob
+    return "$matched"
   fi
   return 1
 }
🤖 Prompt for AI Agents
In config/claude/security.sh around lines 33 to 52, extglob is enabled with
shopt -s but on a successful match the function returns before shopt -u is
called, leaving extglob enabled for the rest of the shell; fix by saving the
prior extglob state before enabling and restoring it before any return (or use a
subshell), e.g., capture the output of shopt -q extglob to a variable, enable
extglob, perform the match, then restore extglob to its original state (call
shopt -s extglob if it was on, or shopt -u extglob if it was off) before
returning.


# Split command at logical operators to catch hidden dangerous commands
# This handles: cmd1 ; cmd2, cmd1 && cmd2, cmd1 || cmd2, cmd1 | cmd2
# shellcheck disable=SC2001
IFS=$'\n' read -r -d '' -a segments < <(echo "$command" | sed 's/[;&|]\+/\n/g' && printf '\0') || true

@cubic-dev-ai cubic-dev-ai Bot Dec 12, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Security bypass: Command substitution ($(...) and backticks) is not handled. A malicious command like echo $(rm -rf /) bypasses detection since the entire string is treated as one segment starting with echo, not rm. Consider parsing nested commands or documenting this limitation.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At config/claude/security.sh, line 57:

<comment>Security bypass: Command substitution (`$(...)` and backticks) is not handled. A malicious command like `echo $(rm -rf /)` bypasses detection since the entire string is treated as one segment starting with `echo`, not `rm`. Consider parsing nested commands or documenting this limitation.</comment>

<file context>
@@ -0,0 +1,73 @@
+# Split command at logical operators to catch hidden dangerous commands
+# This handles: cmd1 ; cmd2, cmd1 &amp;&amp; cmd2, cmd1 || cmd2, cmd1 | cmd2
+# shellcheck disable=SC2001
+IFS=$&#39;\n&#39; read -r -d &#39;&#39; -a segments &lt; &lt;(echo &quot;$command&quot; | sed &#39;s/[;&amp;|]\+/\n/g&#39; &amp;&amp; printf &#39;\0&#39;) || true
+
+for segment in &quot;${segments[@]}&quot;; do
</file context>
Fix with Cubic


for segment in "${segments[@]}"; do
# Trim leading/trailing whitespace
segment=$(echo "$segment" | xargs 2>/dev/null) || continue

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using echo ... | xargs to trim whitespace is a classic trick, but it's not very efficient as it involves a subshell and an external command. A more modern and efficient Bash-native approach is to use read with a here-string, which avoids creating a subshell.

Suggested change
segment=$(echo "$segment" | xargs 2>/dev/null) || continue
read -r segment <<< "$segment"

@cubic-dev-ai cubic-dev-ai Bot Dec 12, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: xargs for trimming whitespace can interpret quotes and backslashes, potentially transforming the command before the security check. Consider using sed 's/^[[:space:]]*//;s/[[:space:]]*$//' or bash parameter expansion instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At config/claude/security.sh, line 61:

<comment>`xargs` for trimming whitespace can interpret quotes and backslashes, potentially transforming the command before the security check. Consider using `sed &#39;s/^[[:space:]]*//;s/[[:space:]]*$//&#39;` or bash parameter expansion instead.</comment>

<file context>
@@ -0,0 +1,73 @@
+
+for segment in &quot;${segments[@]}&quot;; do
+  # Trim leading/trailing whitespace
+  segment=$(echo &quot;$segment&quot; | xargs 2&gt;/dev/null) || continue
+  [[ -z &quot;$segment&quot; ]] &amp;&amp; continue
+
</file context>
Fix with Cubic

[[ -z $segment ]] && continue

Comment on lines +54 to +63

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid xargs for trimming: it normalizes whitespace and can change what you’re matching.

For a security hook, don’t mutate the command string more than necessary—use a trim that preserves internal spacing:

 for segment in "${segments[@]}"; do
   # Trim leading/trailing whitespace
-  segment=$(echo "$segment" | xargs 2>/dev/null) || continue
+  segment=$(printf '%s' "$segment" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') || continue
   [[ -z "$segment" ]] && continue

Based on learnings, follow ShellCheck recommendations.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Split command at logical operators to catch hidden dangerous commands
# This handles: cmd1 ; cmd2, cmd1 && cmd2, cmd1 || cmd2, cmd1 | cmd2
# shellcheck disable=SC2001
IFS=$'\n' read -r -d '' -a segments < <(echo "$command" | sed 's/[;&|]\+/\n/g' && printf '\0') || true
for segment in "${segments[@]}"; do
# Trim leading/trailing whitespace
segment=$(echo "$segment" | xargs 2>/dev/null) || continue
[[ -z "$segment" ]] && continue
# Split command at logical operators to catch hidden dangerous commands
# This handles: cmd1 ; cmd2, cmd1 && cmd2, cmd1 || cmd2, cmd1 | cmd2
# shellcheck disable=SC2001
IFS=$'\n' read -r -d '' -a segments < <(echo "$command" | sed 's/[;&|]\+/\n/g' && printf '\0') || true
for segment in "${segments[@]}"; do
# Trim leading/trailing whitespace
segment=$(printf '%s' "$segment" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') || continue
[[ -z "$segment" ]] && continue
🤖 Prompt for AI Agents
In config/claude/security.sh around lines 54 to 63, the trimming uses "xargs"
which normalizes internal whitespace and can change the command being inspected;
replace the xargs-based trim with a safe leading/trailing-only trim that
preserves internal spacing (use POSIX shell parameter expansion to remove
leading and trailing whitespace, or use sed with explicit ^[[:space:]]* and
[[:space:]]*$ patterns), ensure you do not spawn unnecessary subshells or
collapse internal spaces, and keep the check that skips empty segments.

for pattern in "${deny_patterns[@]}"; do
if matches_pattern "$segment" "$pattern"; then
echo "BLOCKED by security.sh: Command '$segment' matches deny pattern '$pattern'" >&2
exit 2
fi
done
done

# Command passed all checks
exit 0
37 changes: 32 additions & 5 deletions config/claude/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"cleanupPeriodDays": 99999,

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting cleanupPeriodDays to 99999 effectively disables automatic cleanup of old sessions (approximately 273 years). While this preserves history, it could lead to unbounded storage growth over time. Consider whether this is intentional for debugging purposes or if a more reasonable retention period (e.g., 90-180 days) would be more appropriate for production use.

Suggested change
"cleanupPeriodDays": 99999,
"cleanupPeriodDays": 180,

Copilot uses AI. Check for mistakes.
"permissions": {
Comment on lines 1 to 3

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Revisit cleanupPeriodDays: 99999 retention choice
That’s effectively “keep almost forever”; if the goal is privacy or disk hygiene, consider a more bounded value (or document why extremely long retention is desired).

🤖 Prompt for AI Agents
In config/claude/settings.json around lines 1 to 3, the cleanupPeriodDays is set
to an effectively permanent value (99999); change this to a sensible bounded
retention (e.g., 30, 90, or 365 days) or replace the literal with a named
constant/env var and add a short comment or documentation explaining why a long
retention is required if you must keep it long-term; update tests/config docs
accordingly.

"allow": [
"Bash(bun:*)",
Expand Down Expand Up @@ -37,7 +38,6 @@
"Bash(git status:*)",
"Bash(git tag:*)",
"Bash(git worktree:*)",
"Bash(go:*)",
"Bash(grep:*)",
"Bash(kubectl:*)",
"Bash(lsof:*)",
Expand All @@ -52,8 +52,6 @@
"Bash(pip:*)",
"Bash(pip3:*)",
"Bash(pnpm:*)",
"Bash(python:*)",
"Bash(python3:*)",
"Bash(scutil:*)",
"Bash(timeout:*)",
"Bash(uv:*)",
Expand All @@ -69,7 +67,30 @@
"Bash(chmod -R 777:*)",
"Bash(mkfs:*)",
"Bash(dd if=:*)"
]
],
"read": {
"deny": [
"**/.env",
"**/.env.local",
"**/*.pem",
"**/*.key",
"**/secrets/**",
"**/credentials/**",
"**/.aws/**",
"**/.ssh/**",
"**/docker-compose*.yml",

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The read deny pattern includes '**/docker-compose*.yml' which could prevent legitimate reads of docker-compose files for debugging or development purposes. While protecting sensitive configuration is important, docker-compose files often don't contain secrets directly (they reference env files instead). Consider whether this pattern is too restrictive, or document that docker-compose files should be read-only through other means.

Suggested change
"**/docker-compose*.yml",

Copilot uses AI. Check for mistakes.
"**/config/database.yml"
]
},
"write": {
"deny": [
"**/secrets/**",
"**/credentials/**",
"**/.ssh/**",
"**/config/database.yml",
"**/docker-compose*.yml"
]
}
},
"hooks": {
"UserPromptSubmit": [
Expand Down Expand Up @@ -103,6 +124,11 @@
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$HOME/.claude/security.sh",
"timeout": 5
},
{
"type": "command",
"command": "$HOME/.claude/notify.sh",
Expand Down Expand Up @@ -201,5 +227,6 @@
"type": "command",
"command": "node -e \"const fs=require('fs'),path=require('path'),rl=require('readline');let i='';process.stdin.on('data',c=>i+=c);process.stdin.on('end',async()=>{try{const d=JSON.parse(i);const m=d.model?.display_name||'claude-sonnet-4';const dir=d.workspace?.current_dir?.replace(process.env.HOME,'~')||path.basename(process.cwd());const sid=d.session_id;let t=0;if(sid){const pdir=path.join(process.env.HOME,'.claude','projects');if(fs.existsSync(pdir)){for(const pd of fs.readdirSync(pdir).map(d=>path.join(pdir,d)).filter(d=>fs.statSync(d).isDirectory())){const tf=path.join(pd,sid+'.jsonl');if(fs.existsSync(tf)){const rs=fs.createReadStream(tf);const r=rl.createInterface({input:rs});let lu=null;r.on('line',l=>{try{const e=JSON.parse(l);if(e.type==='assistant'&&e.message?.usage)lu=e.message.usage}catch{}});await new Promise(res=>{r.on('close',()=>{if(lu)t=(lu.input_tokens||0)+(lu.output_tokens||0)+(lu.cache_creation_input_tokens||0)+(lu.cache_read_input_tokens||0);res()})});break}}}}const getContextLimit=m=>{if(m.includes('sonnet-4'))return 500000;if(m.includes('3-5-sonnet')||m.includes('sonnet-3.5'))return 200000;if(m.includes('haiku'))return 200000;if(m.includes('opus'))return 200000;return 200000};const cl=getContextLimit(m);const p=Math.min(100,Math.round(t/cl*100));const td=t>=1000000?(t/1000000).toFixed(1)+'M':t>=1000?(t/1000).toFixed(1)+'K':t.toString();const ld=cl>=1000000?(cl/1000000).toFixed(0)+'M':cl>=1000?(cl/1000).toFixed(0)+'K':cl.toString();const c=p>=90?'\\x1b[31m':p>=70?'\\x1b[33m':'\\x1b[32m';console.log('\\x1b[34m'+process.env.USER+'@'+require('os').hostname().split('.')[0]+'\\x1b[0m:\\x1b[34m'+dir+'\\x1b[0m ['+m+'] 🪙 '+td+'/'+ld+' '+c+p+'%\\x1b[0m '+new Date().toLocaleTimeString('en-US',{hour12:false}))}catch{console.log('\\x1b[34m'+process.env.USER+'@'+require('os').hostname().split('.')[0]+'\\x1b[0m:\\x1b[34m'+(process.cwd().replace(process.env.HOME,'~'))+'\\x1b[0m [claude-sonnet-4] 🪙 0 \\x1b[31m❌\\x1b[0m '+new Date().toLocaleTimeString('en-US',{hour12:false}))}});\""
},
"model": "sonnet"
"model": "sonnet",
"defaultMode": "bypassPermissions"

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting "defaultMode" to "bypassPermissions" means Claude Code will bypass permission checks by default. This effectively disables the security restrictions defined in the permissions section (allow/deny lists, read/write deny patterns) unless explicitly changed. Consider whether this is the intended security posture, as it reduces the protection provided by the carefully configured permissions.

Suggested change
"defaultMode": "bypassPermissions"
"defaultMode": "enforcePermissions"

Copilot uses AI. Check for mistakes.
}
4 changes: 2 additions & 2 deletions config/cliproxyapi/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ port: 8317
remote-management:
# Whether to allow remote (non-localhost) management access.
# When false, only localhost can access management endpoints (a key is still required).
allow-remote: true
allow-remote: false
# Management key. If a plaintext value is provided here, it will be hashed on startup.
# All management requests (even from localhost) require this key.
# Leave empty to disable the Management API entirely (404 for all /v0/management routes).
secret-key: ""
secret-key: "__CLIPROXY_MANAGEMENT_PASSWORD__"

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The placeholder CLIPROXY_MANAGEMENT_PASSWORD is being used for the secret-key, but if the CLIPROXY_MANAGEMENT_PASSWORD environment variable is empty or unset, this will result in an empty secret-key in the config. According to the comment on line 10, an empty secret-key disables the Management API entirely (404 for all /v0/management routes). Consider whether this is the intended behavior, or if the service should fail to start when the password is not provided for security reasons.

Copilot uses AI. Check for mistakes.
# Disable the bundled management control panel asset download and HTTP route when true.
disable-control-panel: false
Comment on lines 4 to 13

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

❓ Verification inconclusive

🏁 Script executed:

# First, let's find the start.sh file mentioned in the comment
find . -name "start.sh" -type f

Repository: shunkakinoki/dotfiles

Length of output: 186


🏁 Script executed:

# Search for Management API implementation and secret-key handling
rg -i "secret.?key|management.*password" --type yaml --type py --type js --type ts -A 3 -B 1

Repository: shunkakinoki/dotfiles

Length of output: 186


🏁 Script executed:

# Check the YAML file itself for formatting compliance
cat -n config/cliproxyapi/config.yaml | head -20

Repository: shunkakinoki/dotfiles

Length of output: 186


🏁 Script executed:

# Search for how MANAGEMENT_PASSWORD env var is used
rg "MANAGEMENT_PASSWORD|CLIPROXY_MANAGEMENT_PASSWORD" -A 3 -B 1

Repository: shunkakinoki/dotfiles

Length of output: 186


Prevent deploying a config with the literal placeholder as the management key.

If template substitution fails, secret-key becomes a predictable non-empty credential. Consider enforcing "no placeholders remain" validation in the generator (as mentioned in start.sh), or defaulting secret-key to empty and relying on MANAGEMENT_PASSWORD environment variable exclusively.

Verification needed: Confirm whether secret-key being set to a non-empty value always enables management auth (even if MANAGEMENT_PASSWORD is empty), and whether an empty string is guaranteed to disable /v0/management routes.

🤖 Prompt for AI Agents
config/cliproxyapi/config.yaml lines 4-13: the template leaves the literal
placeholder "__CLIPROXY_MANAGEMENT_PASSWORD__" in secret-key which can become a
predictable credential if substitution fails; update the generator/start.sh to
detect this placeholder and either (a) fail generation with a clear error, or
(b) replace the placeholder with an empty string so secret-key is default-empty,
and add a unit/integration check that validates no placeholders remain in the
rendered config; additionally verify in code that a non-empty secret-key always
enables management auth and that an empty string reliably disables
/v0/management routes, and add tests or runtime log messages to assert this
behavior.

# Authentication directory (supports ~ for home directory). If you use Windows, please set the directory like this: `C:/cli-proxy-api/`
Expand Down
2 changes: 2 additions & 0 deletions devenv.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
pkgs.nodejs
pkgs.bun
pkgs.neovim
pkgs.shellcheck
pkgs.shellspec
];

containers = pkgs.lib.mkIf (!pkgs.stdenv.hostPlatform.isLinux) (pkgs.lib.mkForce { });
Expand Down
12 changes: 6 additions & 6 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions home-manager/packages/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ with pkgs;
ripgrep
rustup
sccache
shellcheck
shellspec
speedtest-cli
sqlite
stern
Expand Down
2 changes: 2 additions & 0 deletions home-manager/programs/fish/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
grco = "_grco_function";
grcr = "_grcr_function";
kyber = "_kyber_function";
kybers = "_kybers_function";
fch = "_fzf_cmd_history --allow-execute";
fdp = "_fzf_directory_picker --allow-cd --prompt-name Projects ~/";
ffp = "_fzf_file_picker --allow-open-in-editor --prompt-name Files";
Expand Down Expand Up @@ -133,6 +134,7 @@
"_grcr_function"
"_hm_load_env_file"
"_kyber_function"
"_kybers_function"
"fish_user_key_bindings"
]
);
Expand Down
10 changes: 2 additions & 8 deletions home-manager/programs/fish/functions/_kyber_function.fish
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
function _kyber_function --description "SSH to Kyber server"
set -l password (security find-generic-password -s "ssh ubuntu@91.242.214.231" -w 2>/dev/null)
if test -n "$password"
sshpass -p $password ssh ubuntu@$KYBER_IP_ADDR
else
echo "Password not found in Keychain. Run: security add-generic-password -s 'ssh ubuntu@91.242.214.231' -a ubuntu -w"
ssh ubuntu@$KYBER_IP_ADDR
end
function _kyber_function --description "SSH to Kyber server via Tailscale"
tailscale ssh ubuntu@kyber
end
Loading
Loading