Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
59 changes: 59 additions & 0 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Python
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.sha }}
cancel-in-progress: true
jobs:
python-test:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version-file: "pyproject.toml"
- name: Run tests
Comment on lines +22 to +26

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Using python-version-file: pyproject.toml with actions/setup-python@v6 as intended. This is supported — v6 reads requires-python from pyproject.toml.

env:
PYTHONPATH: ${{ github.workspace }}
run: uv run --with pytest --no-project pytest tests
python-lint:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version-file: "pyproject.toml"
- name: Install ruff
run: uv pip install --system ruff
- name: Lint code with Ruff
run: ruff check --output-format=github
- name: Check code formatting with Ruff
run: ruff format --check --diff
python-check:
if: always()
needs:
- python-test
- python-lint
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Alls Green
uses: re-actors/alls-green@release/v1
with:
jobs: ${{ toJSON(needs) }}
25 changes: 24 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ dotagents-sync: ## Sync dotagents (commands, skills, MCP configuration).
@$(MAKE) -C dotagents sync

.PHONY: test
test: neovim-test nix-test shell-test ## Run all tests (neovim + nix + shell).
test: neovim-test nix-test shell-test python-test nix-inline-check ## Run all tests (neovim + nix + shell + python + nix-inline-check).

##@ Update

Expand Down Expand Up @@ -876,6 +876,29 @@ shell-check-dev: ## Run ShellCheck inside the Nix dev shell (mirrors CI).
.PHONY: shell-lint
shell-lint: shell-check ## Lint shell scripts (alias for shell-check).

.PHONY: nix-inline-check
nix-inline-check: ## Fail if any .nix file contains inline write*Script* strings.
@echo "🔍 Checking for inline scripts in Nix files..."
@bash scripts/check-nix-inline-scripts.sh

##@ Python

.PHONY: python-test
python-test: ## Run Python tests with pytest.
@echo "🧪 Running Python tests..."
@uv run --with pytest --no-project pytest tests

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

.PHONY: python-lint
python-lint: ## Lint Python files with Ruff.
@echo "🔍 Linting Python files with Ruff..."
@uv run --with ruff --no-project ruff check
@uv run --with ruff --no-project ruff format --check --diff

##@ Nix Tests

.PHONY: nix-test
Expand Down
15 changes: 9 additions & 6 deletions devenv.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
pkgs.gnumake
pkgs.gcc
pkgs.fish
(pkgs.writeShellScriptBin "fishtape" ''
exec ${pkgs.fish}/bin/fish \
-C "source ${pkgs.fishPlugins.fishtape_3.src}/functions/fishtape.fish" \
-c 'fishtape $argv' \
-- "$@"
'')
pkgs.statix
(pkgs.writeShellScriptBin "fishtape" (
builtins.readFile (
pkgs.replaceVars ./scripts/fishtape-wrapper.sh {
fish = pkgs.fish;
fishtape_3_src = pkgs.fishPlugins.fishtape_3.src;
}
)
))
];

containers = pkgs.lib.mkIf (!pkgs.stdenv.hostPlatform.isLinux) (pkgs.lib.mkForce { });
Expand Down
24 changes: 16 additions & 8 deletions home-manager/modules/yek/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,29 @@ let
};

# Create install-yek as a standalone script
installScript = pkgs.writeScriptBin "install-yek" ''
#!${pkgs.bash}/bin/bash
exec ${pkgs.bash}/bin/bash ${installYekScript} "$@"
'';
installScript = pkgs.writeScriptBin "install-yek" (
builtins.readFile (
pkgs.replaceVars ./install-yek-shim.sh {
bash = pkgs.bash;
install_yek_script = installYekScript;
}
)
);

# Wrapper script with install-yek path substituted
yekWrapperScript = pkgs.replaceVars ./yek.sh {
install_yek = "${installScript}/bin/install-yek";
};

# Create yek wrapper as a standalone script
yekWrapper = pkgs.writeScriptBin "yek" ''
#!${pkgs.bash}/bin/bash
exec ${pkgs.bash}/bin/bash ${yekWrapperScript} "$@"
'';
yekWrapper = pkgs.writeScriptBin "yek" (
builtins.readFile (
pkgs.replaceVars ./yek-shim.sh {
bash = pkgs.bash;
yek_wrapper_script = yekWrapperScript;
}
)
);
in
{
home.packages = [
Expand Down
4 changes: 4 additions & 0 deletions home-manager/modules/yek/install-yek-shim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
# Thin shim that delegates to the Nix-store install-yek script.
# @bash@ and @install_yek_script@ are substituted by pkgs.replaceVars.
exec @bash@/bin/bash @install_yek_script@ "$@"
4 changes: 4 additions & 0 deletions home-manager/modules/yek/yek-shim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
# Thin shim that delegates to the Nix-store yek wrapper script.
# @bash@ and @yek_wrapper_script@ are substituted by pkgs.replaceVars.
exec @bash@/bin/bash @yek_wrapper_script@ "$@"
27 changes: 9 additions & 18 deletions home-manager/services/cliproxyapi/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,15 @@ let
# Smart wrapper that handles both NixOS and non-NixOS Linux
# On NixOS: docker group is properly inherited, or use /run/wrappers/bin/sg
# On non-NixOS: systemd user session may lack docker group, use /usr/bin/sg
dockerStartScript = pkgs.writeShellScript "cliproxyapi-docker-start" ''
SCRIPT="${pkgs.bash}/bin/bash ${startScript}"

# Try docker directly first (works on NixOS or when user has docker group)
if ${pkgs.docker}/bin/docker info >/dev/null 2>&1; then
exec $SCRIPT
fi

# Docker not accessible directly, try sg to switch group
if [ -x /run/wrappers/bin/sg ]; then
exec /run/wrappers/bin/sg docker -c "$SCRIPT"
elif [ -x /usr/bin/sg ]; then
exec /usr/bin/sg docker -c "$SCRIPT"
else
echo "ERROR: Cannot access Docker. User not in docker group and no sg binary found." >&2
exit 1
fi
'';
dockerStartScript = pkgs.writeShellScript "cliproxyapi-docker-start" (
builtins.readFile (
pkgs.replaceVars ./scripts/docker-start.sh {
bash = pkgs.bash;
start_script = startScript;
docker = pkgs.docker;
}
)
);

wrapperScript = pkgs.replaceVars ./scripts/wrapper.sh {
common = commonScript;
Expand Down
21 changes: 21 additions & 0 deletions home-manager/services/cliproxyapi/scripts/docker-start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Smart wrapper that handles both NixOS and non-NixOS Linux.
# On NixOS: docker group is properly inherited, or use /run/wrappers/bin/sg.
# On non-NixOS: systemd user session may lack docker group, use /usr/bin/sg.
# @bash@, @start_script@, @docker@ are substituted by pkgs.replaceVars.
SCRIPT="@bash@/bin/bash @start_script@"

# Try docker directly first (works on NixOS or when user has docker group)
if @docker@/bin/docker info >/dev/null 2>&1; then
exec $SCRIPT
fi

# Docker not accessible directly, try sg to switch group
if [ -x /run/wrappers/bin/sg ]; then
exec /run/wrappers/bin/sg docker -c "$SCRIPT"
elif [ -x /usr/bin/sg ]; then
exec /usr/bin/sg docker -c "$SCRIPT"
else
echo "ERROR: Cannot access Docker. User not in docker group and no sg binary found." >&2
exit 1
fi
29 changes: 9 additions & 20 deletions home-manager/services/docker-postgres/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,15 @@ let
# Smart wrapper that handles both NixOS and non-NixOS Linux
# On NixOS: docker group is properly inherited, or use /run/wrappers/bin/sg
# On non-NixOS: systemd user session may lack docker group, use /usr/bin/sg
startPostgresWrapper = pkgs.writeShellScript "start-postgres-wrapper" ''
SCRIPT="${pkgs.bash}/bin/bash ${startScript}"

# Try docker directly first (works on NixOS or when user has docker group)
if ${pkgs.docker}/bin/docker info >/dev/null 2>&1; then
exec $SCRIPT
fi

# Docker not accessible directly, try sg to switch group
# NixOS: /run/wrappers/bin/sg (SUID wrapper)
# Non-NixOS: /usr/bin/sg (system binary with SUID)
if [ -x /run/wrappers/bin/sg ]; then
exec /run/wrappers/bin/sg docker -c "$SCRIPT"
elif [ -x /usr/bin/sg ]; then
exec /usr/bin/sg docker -c "$SCRIPT"
else
echo "ERROR: Cannot access Docker. User not in docker group and no sg binary found." >&2
exit 1
fi
'';
startPostgresWrapper = pkgs.writeShellScript "start-postgres-wrapper" (
builtins.readFile (
pkgs.replaceVars ./start-postgres-wrapper.sh {
bash = pkgs.bash;
start_script = startScript;
docker = pkgs.docker;
}
)
);
in
{
launchd.agents.docker-postgres = lib.mkIf pkgs.stdenv.isDarwin {
Expand Down
21 changes: 21 additions & 0 deletions home-manager/services/docker-postgres/start-postgres-wrapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Smart wrapper that handles both NixOS and non-NixOS Linux.
# On NixOS: docker group is properly inherited, or use /run/wrappers/bin/sg (SUID wrapper).
# On non-NixOS: systemd user session may lack docker group, use /usr/bin/sg (system binary with SUID).
# @bash@, @start_script@, @docker@ are substituted by pkgs.replaceVars.
SCRIPT="@bash@/bin/bash @start_script@"

# Try docker directly first (works on NixOS or when user has docker group)
if @docker@/bin/docker info >/dev/null 2>&1; then
exec $SCRIPT
fi

# Docker not accessible directly, try sg to switch group
if [ -x /run/wrappers/bin/sg ]; then
exec /run/wrappers/bin/sg docker -c "$SCRIPT"
elif [ -x /usr/bin/sg ]; then
exec /usr/bin/sg docker -c "$SCRIPT"
else
echo "ERROR: Cannot access Docker. User not in docker group and no sg binary found." >&2
exit 1
fi
79 changes: 26 additions & 53 deletions home-manager/services/docker/default.nix
Original file line number Diff line number Diff line change
@@ -1,64 +1,37 @@
{ pkgs, lib, ... }:
let
# Systemd service file for Docker daemon
dockerServiceFile = pkgs.writeText "docker.service" ''
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
ExecStart=${pkgs.docker}/bin/dockerd
ExecReload=${pkgs.coreutils}/bin/kill -s HUP $MAINPID
Restart=always
RestartSec=10s

[Install]
WantedBy=multi-user.target
'';
dockerServiceFile = pkgs.writeText "docker.service" (
builtins.readFile (
pkgs.replaceVars ./docker.service {
docker = pkgs.docker;
coreutils = pkgs.coreutils;
}
)
);

# Script to ensure user is in docker group and system docker is running
setupDockerScript = pkgs.writeShellScript "setup-docker" ''
set -euo pipefail

# Define paths
GROUPS=${pkgs.shadow}/bin/groups
GREP=${pkgs.gnugrep}/bin/grep
USERMOD=${pkgs.shadow}/bin/usermod
SYSTEMCTL=${pkgs.systemd}/bin/systemctl
TEE=${pkgs.coreutils}/bin/tee
DOCKER_SERVICE_FILE=${dockerServiceFile}

# Check if docker group exists and user is in it
if ! $GROUPS | $GREP -q docker; then
echo "Adding user to docker group..."
sudo $USERMOD -aG docker $USER
echo "✅ Added to docker group. Please log out and back in, or run: newgrp docker"
fi

# Check if system docker service exists and is running
if ! $SYSTEMCTL is-active --quiet docker 2>/dev/null; then
echo "Starting Docker daemon..."
if [ ! -f /etc/systemd/system/docker.service ]; then
echo "Installing Docker systemd service..."
sudo $TEE /etc/systemd/system/docker.service > /dev/null < "$DOCKER_SERVICE_FILE"
sudo $SYSTEMCTL daemon-reload
sudo $SYSTEMCTL enable docker
fi
sudo $SYSTEMCTL start docker
echo "✅ Docker daemon started"
else
echo "✅ Docker daemon is already running"
fi
'';
setupDockerScript = pkgs.writeShellScript "setup-docker" (
builtins.readFile (
pkgs.replaceVars ./setup-docker.sh {
shadow = pkgs.shadow;
gnugrep = pkgs.gnugrep;
systemd = pkgs.systemd;
coreutils = pkgs.coreutils;
docker_service_file = dockerServiceFile;
}
)
);
in
{
# Provide setup script for system Docker
home.packages = lib.mkIf pkgs.stdenv.isLinux [
(pkgs.writeShellScriptBin "docker-setup" ''
exec ${setupDockerScript}
'')
(pkgs.writeShellScriptBin "docker-setup" (
builtins.readFile (
pkgs.replaceVars ./docker-setup.sh {
setup_docker_script = setupDockerScript;
}
)
))
];
}
4 changes: 4 additions & 0 deletions home-manager/services/docker/docker-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
# Thin wrapper exposing setup-docker as a user-facing command.
# @setup_docker_script@ is substituted by pkgs.replaceVars.
exec @setup_docker_script@
15 changes: 15 additions & 0 deletions home-manager/services/docker/docker.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
ExecStart=@docker@/bin/dockerd
ExecReload=@coreutils@/bin/kill -s HUP $MAINPID
Restart=always
RestartSec=10s

[Install]
WantedBy=multi-user.target
Loading
Loading