From 8fa97234e481d62755cefed1b8aedc1a92cac9a3 Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 13:24:28 +0000 Subject: [PATCH 01/14] Add freeze command --- modules/home/terminal/hr/hr.sh | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/modules/home/terminal/hr/hr.sh b/modules/home/terminal/hr/hr.sh index cefeded..14ee834 100644 --- a/modules/home/terminal/hr/hr.sh +++ b/modules/home/terminal/hr/hr.sh @@ -2,7 +2,7 @@ set -e -if [ "$1" = "py" ] && [ "$2" = "init" ]; then +if [ "$1" = "init" ] && [ "$2" = "py" ]; then echo "Initializing python devenv..." # 1. Init devenv @@ -94,8 +94,23 @@ EOF exit 1 fi +elif [ "$1" = "freeze" ]; then + extra_index_url="https://europe-west1-python.pkg.dev/mk2-prod/python-packages/simple/" + + # Install the auth plugin and keyring CLI + uv pip install keyrings.google-artifactregistry-auth==1.1.2 keyring + + # Install project dependencies using the subprocess keyring provider + uv pip install --no-cache -e .[test] --extra-index-url "${extra_index_url}" --keyring-provider subprocess + + # Generate requirements.txt + echo "--extra-index-url ${extra_index_url}" > requirements.txt + uv pip freeze --exclude-editable >> requirements.txt + else - echo "Usage: hr py init" - echo " py init Initialize a python devenv environment (git-ignored)" + echo "Usage: hr " + echo "Commands:" + echo " init py Initialize a python devenv environment (git-ignored)" + echo " freeze Freeze dependencies to requirements.txt" exit 1 fi From 171c1e2e065acf52ebc06c3d6c43e4af3ec8343f Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 13:36:25 +0000 Subject: [PATCH 02/14] Add hr proxies --- modules/home/terminal/hr/default.nix | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/modules/home/terminal/hr/default.nix b/modules/home/terminal/hr/default.nix index eef1a98..c77bdfd 100644 --- a/modules/home/terminal/hr/default.nix +++ b/modules/home/terminal/hr/default.nix @@ -12,5 +12,35 @@ in { config = lib.mkIf cfg.hr.enable { home.packages = [hr]; + + systemd.user.services = { + google-db-proxy-test = { + Unit = { + Description = "Google Cloud SQL Proxy (Test)"; + After = ["network.target"]; + }; + Service = { + ExecStart = "${pkgs.google-cloud-sql-proxy}/bin/cloud-sql-proxy mk2-test:europe-west1:mk2-test-sql-instance -p 5436"; + Restart = "always"; + }; + Install = { + WantedBy = ["default.target"]; + }; + }; + + google-db-proxy-prod = { + Unit = { + Description = "Google Cloud SQL Proxy (Prod)"; + After = ["network.target"]; + }; + Service = { + ExecStart = "${pkgs.google-cloud-sql-proxy}/bin/cloud-sql-proxy mk2-prod:europe-west1:mk2-prod-sql-instance -p 5437"; + Restart = "always"; + }; + Install = { + WantedBy = ["default.target"]; + }; + }; + }; }; } From 169a75db16bbe241227aa9c6cd593632c0188a5b Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 13:40:07 +0000 Subject: [PATCH 03/14] Add service enable --- modules/home/terminal/hr/default.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/home/terminal/hr/default.nix b/modules/home/terminal/hr/default.nix index c77bdfd..653c43b 100644 --- a/modules/home/terminal/hr/default.nix +++ b/modules/home/terminal/hr/default.nix @@ -15,6 +15,7 @@ in { systemd.user.services = { google-db-proxy-test = { + enable = true; Unit = { Description = "Google Cloud SQL Proxy (Test)"; After = ["network.target"]; @@ -29,6 +30,7 @@ in { }; google-db-proxy-prod = { + enable = true; Unit = { Description = "Google Cloud SQL Proxy (Prod)"; After = ["network.target"]; From 181ad4416a34ccd47065c9e35673b7fd6038124b Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 14:10:08 +0000 Subject: [PATCH 04/14] Add hr switch --- modules/home/terminal/hr/default.nix | 4 +- modules/home/terminal/hr/hr.sh | 80 +++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/modules/home/terminal/hr/default.nix b/modules/home/terminal/hr/default.nix index 653c43b..a91d6f2 100644 --- a/modules/home/terminal/hr/default.nix +++ b/modules/home/terminal/hr/default.nix @@ -11,11 +11,10 @@ in { options.mods.terminal.hr.enable = lib.mkEnableOption "Hefring (Work Tooling)"; config = lib.mkIf cfg.hr.enable { - home.packages = [hr]; + programs.zsh.initExtra = builtins.readFile ./hr.sh; systemd.user.services = { google-db-proxy-test = { - enable = true; Unit = { Description = "Google Cloud SQL Proxy (Test)"; After = ["network.target"]; @@ -30,7 +29,6 @@ in { }; google-db-proxy-prod = { - enable = true; Unit = { Description = "Google Cloud SQL Proxy (Prod)"; After = ["network.target"]; diff --git a/modules/home/terminal/hr/hr.sh b/modules/home/terminal/hr/hr.sh index 14ee834..ebaa4fd 100644 --- a/modules/home/terminal/hr/hr.sh +++ b/modules/home/terminal/hr/hr.sh @@ -1,8 +1,17 @@ -#!/usr/bin/env bash +# Set default PROJECT_ID if not already set +if [[ -z "$PROJECT_ID" ]]; then + export PROJECT_ID="mk2-test" +fi -set -e +_hr_usage() { + echo "Usage: hr " + echo "Commands:" + echo " switch Switch PROJECT_ID between mk2-test and mk2-prod" + echo " init py Initialize a python devenv environment (git-ignored)" + echo " freeze Freeze dependencies to requirements.txt" +} -if [ "$1" = "init" ] && [ "$2" = "py" ]; then +_hr_init_py() { echo "Initializing python devenv..." # 1. Init devenv @@ -15,7 +24,7 @@ if [ "$1" = "init" ] && [ "$2" = "py" ]; then echo "Direnv allowed" else echo "Error: devenv not found in path." - exit 1 + return 1 fi if [ -f .gitignore.bak ]; then @@ -91,11 +100,12 @@ EOF echo "Direnv allowed" else echo "Error: direnv not found in path." - exit 1 + return 1 fi +} -elif [ "$1" = "freeze" ]; then - extra_index_url="https://europe-west1-python.pkg.dev/mk2-prod/python-packages/simple/" +_hr_freeze() { + local extra_index_url="https://europe-west1-python.pkg.dev/mk2-prod/python-packages/simple/" # Install the auth plugin and keyring CLI uv pip install keyrings.google-artifactregistry-auth==1.1.2 keyring @@ -106,11 +116,53 @@ elif [ "$1" = "freeze" ]; then # Generate requirements.txt echo "--extra-index-url ${extra_index_url}" > requirements.txt uv pip freeze --exclude-editable >> requirements.txt +} -else - echo "Usage: hr " - echo "Commands:" - echo " init py Initialize a python devenv environment (git-ignored)" - echo " freeze Freeze dependencies to requirements.txt" - exit 1 -fi +hr() { + if [[ $# -eq 0 ]]; then + _hr_usage + return 1 + fi + + local command="$1" + shift + + if [[ "$command" == "switch" ]]; then + if [[ -z "$1" ]]; then + # Toggle between test and prod + if [[ "$PROJECT_ID" == "mk2-test" ]]; then + export PROJECT_ID="mk2-prod" + echo "Switched PROJECT_ID to mk2-prod" + else + export PROJECT_ID="mk2-test" + echo "Switched PROJECT_ID to mk2-test" + fi + elif [[ "$1" == "test" ]]; then + export PROJECT_ID="mk2-test" + echo "Set PROJECT_ID to mk2-test" + elif [[ "$1" == "prod" ]]; then + export PROJECT_ID="mk2-prod" + echo "Set PROJECT_ID to mk2-prod" + else + echo "Usage: hr switch [test|prod]" + return 1 + fi + return 0 + fi + + # Run original logic in a subshell to preserve set -e behavior without affecting current shell + ( + set -e + # Restore arguments for processing + set -- "$command" "$@" + + if [ "$1" = "init" ] && [ "$2" = "py" ]; then + _hr_init_py + elif [ "$1" = "freeze" ]; then + _hr_freeze + else + _hr_usage + exit 1 + fi + ) +} From e2297dc00cc2be19b0a027a64f5a77dd301b34d1 Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 14:26:17 +0000 Subject: [PATCH 05/14] Add hr prompt --- modules/home/terminal/hr/default.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/home/terminal/hr/default.nix b/modules/home/terminal/hr/default.nix index a91d6f2..5109227 100644 --- a/modules/home/terminal/hr/default.nix +++ b/modules/home/terminal/hr/default.nix @@ -11,6 +11,12 @@ in { options.mods.terminal.hr.enable = lib.mkEnableOption "Hefring (Work Tooling)"; config = lib.mkIf cfg.hr.enable { + programs.starship.settings.custom.project_id = { + command = "if echo \"$PROJECT_ID\" | grep -q \"prod\"; then printf \"\\033[1;33m \\033[1;34m$PROJECT_ID\\033[0m\"; else printf \"\\033[1;34m$PROJECT_ID\\033[0m\"; fi"; + when = "test -n \"$PROJECT_ID\""; + format = "on $output "; + }; + programs.zsh.initExtra = builtins.readFile ./hr.sh; systemd.user.services = { From 59652e954f01061f20cf72020950072417f5e66b Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 14:34:17 +0000 Subject: [PATCH 06/14] Add musk to sops --- .sops.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.sops.yaml b/.sops.yaml index aaf3e03..e10bd39 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -3,6 +3,7 @@ keys: - &muho age1v4s4hg7u3vjjkarvrk7v6ev7w3wja2r5xm7f4t06culw3fuq7qns8sfju7 - &mups age1n7qz2w3hkf7fcdv92kxw9k6uef487na2tlc87486rcjwj8lyfuws5q46gn - &murk age1mgjhkqy9x27gv2t2xvq46dxcajkr9c8zes7rr3dj0ac7md2j6vas43dftp + - &musk age1m97a3eptxwpdd7h5kkqe9gkmhg6rquc64qjmlsfqfhfqv8q72crqrylhgc creation_rules: - path_regex: modules/nixos/sops/secrets.ya?ml$ @@ -12,6 +13,7 @@ creation_rules: - *muho - *mups - *murk + - *musk - path_regex: modules/home/sops/secrets.ya?ml$ key_groups: @@ -20,3 +22,4 @@ creation_rules: - *muho - *mups - *murk + - *musk From ee3321b408783c51845d04eeb997281191718f5b Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 14:40:39 +0000 Subject: [PATCH 07/14] Add hr db sops --- modules/home/sops/default.nix | 2 ++ modules/home/sops/secrets.yaml | 8 +++++--- modules/home/terminal/hr/hr.sh | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/home/sops/default.nix b/modules/home/sops/default.nix index 01b2b21..791fab8 100644 --- a/modules/home/sops/default.nix +++ b/modules/home/sops/default.nix @@ -17,5 +17,7 @@ in secrets.atuin-auth = {}; secrets.hr-password = {}; secrets.sops-key = {}; + secrets.google-db-test = {}; + secrets.google-db-prod = {}; }; } diff --git a/modules/home/sops/secrets.yaml b/modules/home/sops/secrets.yaml index 81d63e7..5ee893b 100644 --- a/modules/home/sops/secrets.yaml +++ b/modules/home/sops/secrets.yaml @@ -2,6 +2,8 @@ zipline-auth: ENC[AES256_GCM,data:RkJI6GuH7RzdcSlKn32gMGojjB6rkdDcnNUvsi/BTfJk2s atuin-auth: ENC[AES256_GCM,data:LDkiXWIwxor8Ro383gonJCyqu+nyxS7DrI2J8uo4Cqu2X61rBUlnpNR6YirUZS/lYAnWYJhZM7sR0G7ZNh9EgQ==,iv:UEs2KW8ImMnaQrSLrIGbVXEq86QiVPAPNIXBZpa3jFI=,tag:N0rhnPbasFzkoI3CJ9CV+Q==,type:str] hr-password: ENC[AES256_GCM,data:QZuzAnTJ2KgPnffHvdCWrJEM5d/FXxhX3dA1,iv:FgDw6aXDY0jCpJiYc9WOobR96TXNtnvN7neJu8drxMM=,tag:YT82wryVy3V+41w0YbMOrA==,type:str] sops-key: ENC[AES256_GCM,data:msX0EJqJauteOBICUsLcVgqNxqGcqvD+Xi/B2EhUX2OAoyBH5oDae8XWlQCi2RdOm4NtnrSTnG8FRQXfkXO+tne0VEfYTCjeVtU=,iv:qxpvofr56Ey17xcPpju/mQgiz+0cOYED5caAHs3myXw=,tag:oDFXh0rlc0tmV2IUJ1ezBQ==,type:str] +google-db-test: ENC[AES256_GCM,data:ZMm/BF/k+XnZZkHMDSV/fk3ds0LAOHAmag==,iv:tmfJ7ju5yAO6Oco3jXYNyqzJr7cgshyd/SkjfYnEl6U=,tag:jMD2N6TsgbRwefhJ/XYhtg==,type:str] +google-db-prod: ENC[AES256_GCM,data:fIPL9XKk9sAmpVsQBubSVbh3DlEEKadG9g==,iv:R34zkCIUDlk5/wg8eU8RZIanGayL+nX+7ZhyVmbcQC0=,tag:lu24b28742O46fjUaw2UBA==,type:str] sops: age: - recipient: age1m97a3eptxwpdd7h5kkqe9gkmhg6rquc64qjmlsfqfhfqv8q72crqrylhgc @@ -40,7 +42,7 @@ sops: a0V1N2VjUDE4Z3R5MGxMQVNmOVp0bVUK9cppJW33tKFOSvbIn/2Dga8k7/McaTpK m7M+83guMzNoOlpJ/WYU1BaePcM974AgjVR0WD/v+xGBvGKubKHqtw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-08-04T07:58:56Z" - mac: ENC[AES256_GCM,data:aJw3KK4GMj5/Q06v1C5rdSerdO21cNxpTIJYoxmfhBKudzD7lSL6l+d47kWoB0U4J5jtbs9obWz2MH3CvyPBapjJaSFnYEXk1JuGihf8GK3QrqLAt+dmF2ZD1FBLpQELripueneyHkzT32180hpXGnppNlgOuATlIMSPosvlpVI=,iv:SpGAyTqqbpuxcLkMq7VnLQUoR6oW0ERgnyPaqVHpaN8=,tag:OSNGT8/5E+PRhoR8dIyaSA==,type:str] + lastmodified: "2026-01-21T14:37:21Z" + mac: ENC[AES256_GCM,data:bxr3U1Ig0qjuOcxHeOlOrXO0xtZs0vKTuXn8GE1dJGCFDjVgakbIwiW6+2WNYUbIpipCAwdecgb0jBngwt3zKGS4PMzapUXxl7RoCr5DWCh6kSD4CCUH4v8guuy0k8SMQXDO3CdbUd/5/asIPfxlvEESCQL54X2OJlt5xpE7PsU=,iv:m/lrHHFYXFKCVEOK462II8bcFvw7k4rKEuMOHHmzT/8=,tag:jgEQso2bAShLJERsOHhrKw==,type:str] unencrypted_suffix: _unencrypted - version: 3.10.2 + version: 3.11.0 diff --git a/modules/home/terminal/hr/hr.sh b/modules/home/terminal/hr/hr.sh index ebaa4fd..cbb4966 100644 --- a/modules/home/terminal/hr/hr.sh +++ b/modules/home/terminal/hr/hr.sh @@ -114,8 +114,8 @@ _hr_freeze() { uv pip install --no-cache -e .[test] --extra-index-url "${extra_index_url}" --keyring-provider subprocess # Generate requirements.txt - echo "--extra-index-url ${extra_index_url}" > requirements.txt - uv pip freeze --exclude-editable >> requirements.txt + echo "--extra-index-url ${extra_index_url}" >requirements.txt + uv pip freeze --exclude-editable >>requirements.txt } hr() { From 814bcab5146e3bd06dd7740301581065c0748da4 Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 14:49:11 +0000 Subject: [PATCH 08/14] Add db env vars --- modules/home/terminal/hr/default.nix | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/home/terminal/hr/default.nix b/modules/home/terminal/hr/default.nix index 5109227..c395ee4 100644 --- a/modules/home/terminal/hr/default.nix +++ b/modules/home/terminal/hr/default.nix @@ -17,7 +17,16 @@ in { format = "on $output "; }; - programs.zsh.initExtra = builtins.readFile ./hr.sh; + programs.zsh.initExtra = '' + export MK2_TEST_SQL_INSTANCE_USER=gijs + export MK2_TEST_SQL_INSTANCE_PASSWORD="$(cat ${config.sops.secrets.google-db-test.path})" + export MK2_TEST_SQL_INSTANCE_PORT=5436 + export MK2_TEST_SQL_INSTANCE_HOST=localhost + export MK2_PROD_SQL_INSTANCE_USER=gijs + export MK2_PROD_SQL_INSTANCE_PASSWORD="$(cat ${config.sops.secrets.google-db-prod.path})" + export MK2_PROD_SQL_INSTANCE_HOST=localhost + export MK2_PROD_SQL_INSTANCE_PORT=5437 + '' + builtins.readFile ./hr.sh; systemd.user.services = { google-db-proxy-test = { From 64f27448ea559ed0a22184d1eec26e932a0e8927 Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 15:01:33 +0000 Subject: [PATCH 09/14] Add hr call --- modules/home/terminal/hr/hr.sh | 114 +++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/modules/home/terminal/hr/hr.sh b/modules/home/terminal/hr/hr.sh index cbb4966..6066add 100644 --- a/modules/home/terminal/hr/hr.sh +++ b/modules/home/terminal/hr/hr.sh @@ -7,6 +7,8 @@ _hr_usage() { echo "Usage: hr " echo "Commands:" echo " switch Switch PROJECT_ID between mk2-test and mk2-prod" + echo " call Call a Cloud Run service route" + echo " cf Call a Cloud Function" echo " init py Initialize a python devenv environment (git-ignored)" echo " freeze Freeze dependencies to requirements.txt" } @@ -118,6 +120,112 @@ _hr_freeze() { uv pip freeze --exclude-editable >>requirements.txt } +_hr_call() { + local route_arg="$1" + shift + + if [[ -z "$route_arg" ]]; then + echo "Usage: hr call [/path] " + return 1 + fi + + local service_name + local url_path + + if [[ "$route_arg" == */* ]]; then + service_name="${route_arg%%/*}" + url_path="/${route_arg#*/}" + else + service_name="$route_arg" + url_path="" + fi + + local project_number + if [[ "$PROJECT_ID" == "mk2-prod" ]]; then + project_number="1013087376822" + else + project_number="322048751601" + fi + + local json_payload="{}" + + while [[ $# -gt 0 ]]; do + if [[ "$1" == -* ]]; then + local key="${1#-}" + if [[ -z "$2" || "$2" == -* ]]; then + echo "Error: Missing value for option $key" + return 1 + fi + local value="$2" + + # Use jq to safely construct JSON + if command -v jq >/dev/null; then + json_payload=$(echo "$json_payload" | jq --arg k "$key" --arg v "$value" '.[$k] = $v') + else + echo "Error: jq is required but not installed." + return 1 + fi + shift 2 + else + echo "Error: Unexpected argument '$1'" + return 1 + fi + done + + local url="https://${service_name}-${project_number}.europe-west1.run.app${url_path}" + + echo "Calling $url..." + + curl "$url" \ + -H "Authorization: bearer $(gcloud auth print-identity-token)" \ + -H "Content-Type: application/json" \ + -d "$json_payload" +} + +_hr_cf() { + local function_name="$1" + shift + + if [[ -z "$function_name" ]]; then + echo "Usage: hr cf " + return 1 + fi + + local json_payload="{}" + + while [[ $# -gt 0 ]]; do + if [[ "$1" == -* ]]; then + local key="${1#-}" + if [[ -z "$2" || "$2" == -* ]]; then + echo "Error: Missing value for option $key" + return 1 + fi + local value="$2" + + # Use jq to safely construct JSON + if command -v jq >/dev/null; then + json_payload=$(echo "$json_payload" | jq --arg k "$key" --arg v "$value" '.[$k] = $v') + else + echo "Error: jq is required but not installed." + return 1 + fi + shift 2 + else + echo "Error: Unexpected argument '$1'" + return 1 + fi + done + + local url="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/${function_name}" + + echo "Calling $url..." + + curl "$url" \ + -H "Authorization: bearer $(gcloud auth print-identity-token)" \ + -H "Content-Type: application/json" \ + -d "$json_payload" +} + hr() { if [[ $# -eq 0 ]]; then _hr_usage @@ -160,6 +268,12 @@ hr() { _hr_init_py elif [ "$1" = "freeze" ]; then _hr_freeze + elif [ "$1" = "call" ]; then + shift + _hr_call "$@" + elif [ "$1" = "cf" ]; then + shift + _hr_cf "$@" else _hr_usage exit 1 From 0e654267292056ba8c645b88e26a8f629ca9b793 Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 15:18:17 +0000 Subject: [PATCH 10/14] Fix parsing --- modules/home/terminal/hr/hr.sh | 54 +++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/modules/home/terminal/hr/hr.sh b/modules/home/terminal/hr/hr.sh index 6066add..32196f7 100644 --- a/modules/home/terminal/hr/hr.sh +++ b/modules/home/terminal/hr/hr.sh @@ -120,6 +120,34 @@ _hr_freeze() { uv pip freeze --exclude-editable >>requirements.txt } +_hr_add_json_field() { + local json="$1" + local key="$2" + local value="$3" + local jq_opt="--arg" + + # Check if explicit boolean + if [[ "$value" == "true" || "$value" == "false" ]]; then + jq_opt="--argjson" + # Check if number (integer or float, no leading zeros unless just 0) + elif [[ "$value" =~ ^-?(0|[1-9][0-9]*)(\.[0-9]+)?$ ]]; then + jq_opt="--argjson" + # Check if object or array + elif [[ "$value" == "["* || "$value" == "{"* ]]; then + if echo "$value" | jq empty >/dev/null 2>&1; then + jq_opt="--argjson" + else + # Warn to stderr, but proceed as string + echo "Warning: Value for '$key' looks like JSON but is invalid. Treating as string." >&2 + fi + fi + + # Apply the value at the path defined by the key (dot-notation supported) + # paths like items.0.id are converted to ["items", 0, "id"] + echo "$json" | jq --arg k "$key" $jq_opt v "$value" \ + 'setpath($k | split(".") | map(if test("^[0-9]+$") then tonumber else . end); $v)' +} + _hr_call() { local route_arg="$1" shift @@ -147,6 +175,11 @@ _hr_call() { project_number="322048751601" fi + if ! command -v jq >/dev/null; then + echo "Error: jq is required but not installed." + return 1 + fi + local json_payload="{}" while [[ $# -gt 0 ]]; do @@ -158,13 +191,7 @@ _hr_call() { fi local value="$2" - # Use jq to safely construct JSON - if command -v jq >/dev/null; then - json_payload=$(echo "$json_payload" | jq --arg k "$key" --arg v "$value" '.[$k] = $v') - else - echo "Error: jq is required but not installed." - return 1 - fi + json_payload=$(_hr_add_json_field "$json_payload" "$key" "$value") shift 2 else echo "Error: Unexpected argument '$1'" @@ -191,6 +218,11 @@ _hr_cf() { return 1 fi + if ! command -v jq >/dev/null; then + echo "Error: jq is required but not installed." + return 1 + fi + local json_payload="{}" while [[ $# -gt 0 ]]; do @@ -202,13 +234,7 @@ _hr_cf() { fi local value="$2" - # Use jq to safely construct JSON - if command -v jq >/dev/null; then - json_payload=$(echo "$json_payload" | jq --arg k "$key" --arg v "$value" '.[$k] = $v') - else - echo "Error: jq is required but not installed." - return 1 - fi + json_payload=$(_hr_add_json_field "$json_payload" "$key" "$value") shift 2 else echo "Error: Unexpected argument '$1'" From c10bde6db481fbff01b87d5debb2e0f6a9d20e9e Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 15:41:03 +0000 Subject: [PATCH 11/14] Add payload view --- modules/home/terminal/hr/hr.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/home/terminal/hr/hr.sh b/modules/home/terminal/hr/hr.sh index 32196f7..37df0f0 100644 --- a/modules/home/terminal/hr/hr.sh +++ b/modules/home/terminal/hr/hr.sh @@ -202,6 +202,7 @@ _hr_call() { local url="https://${service_name}-${project_number}.europe-west1.run.app${url_path}" echo "Calling $url..." + echo "$json_payload" curl "$url" \ -H "Authorization: bearer $(gcloud auth print-identity-token)" \ @@ -245,6 +246,7 @@ _hr_cf() { local url="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/${function_name}" echo "Calling $url..." + echo "$json_payload" curl "$url" \ -H "Authorization: bearer $(gcloud auth print-identity-token)" \ From b59b4a82676528399d6c23788b24d1cd52c0644f Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 15:59:27 +0000 Subject: [PATCH 12/14] Refactor --- modules/home/terminal/hr/default.nix | 70 +++++++++++++--------------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/modules/home/terminal/hr/default.nix b/modules/home/terminal/hr/default.nix index c395ee4..e5ac06f 100644 --- a/modules/home/terminal/hr/default.nix +++ b/modules/home/terminal/hr/default.nix @@ -6,7 +6,8 @@ }: let cfg = config.mods.terminal; - hr = pkgs.writeShellScriptBin "hr" (builtins.readFile ./hr.sh); + test-port = "5436"; + prod-port = "5437"; in { options.mods.terminal.hr.enable = lib.mkEnableOption "Hefring (Work Tooling)"; @@ -17,45 +18,38 @@ in { format = "on $output "; }; - programs.zsh.initExtra = '' - export MK2_TEST_SQL_INSTANCE_USER=gijs - export MK2_TEST_SQL_INSTANCE_PASSWORD="$(cat ${config.sops.secrets.google-db-test.path})" - export MK2_TEST_SQL_INSTANCE_PORT=5436 - export MK2_TEST_SQL_INSTANCE_HOST=localhost - export MK2_PROD_SQL_INSTANCE_USER=gijs - export MK2_PROD_SQL_INSTANCE_PASSWORD="$(cat ${config.sops.secrets.google-db-prod.path})" - export MK2_PROD_SQL_INSTANCE_HOST=localhost - export MK2_PROD_SQL_INSTANCE_PORT=5437 - '' + builtins.readFile ./hr.sh; + programs.zsh.initExtra = + '' + export MK2_TEST_SQL_INSTANCE_USER=gijs + export MK2_TEST_SQL_INSTANCE_PASSWORD="$(cat ${config.sops.secrets.google-db-test.path})" + export MK2_TEST_SQL_INSTANCE_PORT=${test-port} + export MK2_TEST_SQL_INSTANCE_HOST=localhost + export MK2_PROD_SQL_INSTANCE_USER=gijs + export MK2_PROD_SQL_INSTANCE_PASSWORD="$(cat ${config.sops.secrets.google-db-prod.path})" + export MK2_PROD_SQL_INSTANCE_HOST=localhost + export MK2_PROD_SQL_INSTANCE_PORT=${prod-port} + '' + + builtins.readFile ./hr.sh; - systemd.user.services = { - google-db-proxy-test = { - Unit = { - Description = "Google Cloud SQL Proxy (Test)"; - After = ["network.target"]; - }; - Service = { - ExecStart = "${pkgs.google-cloud-sql-proxy}/bin/cloud-sql-proxy mk2-test:europe-west1:mk2-test-sql-instance -p 5436"; - Restart = "always"; - }; - Install = { - WantedBy = ["default.target"]; + systemd.user.services = let + proxy-service = name: port: { + "google-db-proxy-${name}" = { + Unit = { + Description = "Google Cloud SQL Proxy (${name})"; + After = ["network.target"]; + }; +Service = { + Type = "simple"; + ExecStart = "${pkgs.google-cloud-sql-proxy}/bin/cloud-sql-proxy mk2-${name}:europe-west1:mk2-${name}-sql-instance -p ${port}"; + Restart = "always"; + }; + Install = { + WantedBy = ["default.target"]; + }; }; }; - - google-db-proxy-prod = { - Unit = { - Description = "Google Cloud SQL Proxy (Prod)"; - After = ["network.target"]; - }; - Service = { - ExecStart = "${pkgs.google-cloud-sql-proxy}/bin/cloud-sql-proxy mk2-prod:europe-west1:mk2-prod-sql-instance -p 5437"; - Restart = "always"; - }; - Install = { - WantedBy = ["default.target"]; - }; - }; - }; + in + proxy-service "test" test-port + // proxy-service "prod" prod-port; }; } From 8307d2dc6058c12442b8c1e2bfede0af76f534aa Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 16:10:56 +0000 Subject: [PATCH 13/14] Add proxy auth --- modules/home/terminal/hr/default.nix | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/modules/home/terminal/hr/default.nix b/modules/home/terminal/hr/default.nix index e5ac06f..887f9b7 100644 --- a/modules/home/terminal/hr/default.nix +++ b/modules/home/terminal/hr/default.nix @@ -38,18 +38,21 @@ in { Description = "Google Cloud SQL Proxy (${name})"; After = ["network.target"]; }; -Service = { - Type = "simple"; - ExecStart = "${pkgs.google-cloud-sql-proxy}/bin/cloud-sql-proxy mk2-${name}:europe-west1:mk2-${name}-sql-instance -p ${port}"; - Restart = "always"; - }; + Service = { + Type = "simple"; + Environment = [ + "GOOGLE_APPLICATION_CREDENTIALS=${config.home.homeDirectory}/.config/gcloud/application_default_credentials.json" + ]; + ExecStart = "${pkgs.google-cloud-sql-proxy}/bin/cloud-sql-proxy mk2-${name}:europe-west1:mk2-${name}-sql-instance -p ${port}"; + Restart = "always"; + }; Install = { WantedBy = ["default.target"]; }; }; }; in - proxy-service "test" test-port - // proxy-service "prod" prod-port; +proxy-service "test" test-port + // proxy-service "prod" prod-port; }; } From 6e7b541d65501f413ce25add6600f8cdf95a9ad5 Mon Sep 17 00:00:00 2001 From: Sage Date: Wed, 21 Jan 2026 16:41:09 +0000 Subject: [PATCH 14/14] Fix freeze --- modules/home/terminal/hr/hr.sh | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/modules/home/terminal/hr/hr.sh b/modules/home/terminal/hr/hr.sh index 37df0f0..7cdffca 100644 --- a/modules/home/terminal/hr/hr.sh +++ b/modules/home/terminal/hr/hr.sh @@ -113,7 +113,7 @@ _hr_freeze() { uv pip install keyrings.google-artifactregistry-auth==1.1.2 keyring # Install project dependencies using the subprocess keyring provider - uv pip install --no-cache -e .[test] --extra-index-url "${extra_index_url}" --keyring-provider subprocess + uv pip install --no-cache -e ".[test]" --extra-index-url "${extra_index_url}" --keyring-provider subprocess # Generate requirements.txt echo "--extra-index-url ${extra_index_url}" >requirements.txt @@ -128,18 +128,18 @@ _hr_add_json_field() { # Check if explicit boolean if [[ "$value" == "true" || "$value" == "false" ]]; then - jq_opt="--argjson" + jq_opt="--argjson" # Check if number (integer or float, no leading zeros unless just 0) elif [[ "$value" =~ ^-?(0|[1-9][0-9]*)(\.[0-9]+)?$ ]]; then - jq_opt="--argjson" + jq_opt="--argjson" # Check if object or array elif [[ "$value" == "["* || "$value" == "{"* ]]; then - if echo "$value" | jq empty >/dev/null 2>&1; then - jq_opt="--argjson" - else - # Warn to stderr, but proceed as string - echo "Warning: Value for '$key' looks like JSON but is invalid. Treating as string." >&2 - fi + if echo "$value" | jq empty >/dev/null 2>&1; then + jq_opt="--argjson" + else + # Warn to stderr, but proceed as string + echo "Warning: Value for '$key' looks like JSON but is invalid. Treating as string." >&2 + fi fi # Apply the value at the path defined by the key (dot-notation supported) @@ -181,16 +181,16 @@ _hr_call() { fi local json_payload="{}" - + while [[ $# -gt 0 ]]; do if [[ "$1" == -* ]]; then local key="${1#-}" if [[ -z "$2" || "$2" == -* ]]; then - echo "Error: Missing value for option $key" - return 1 + echo "Error: Missing value for option $key" + return 1 fi local value="$2" - + json_payload=$(_hr_add_json_field "$json_payload" "$key" "$value") shift 2 else @@ -200,10 +200,10 @@ _hr_call() { done local url="https://${service_name}-${project_number}.europe-west1.run.app${url_path}" - + echo "Calling $url..." echo "$json_payload" - + curl "$url" \ -H "Authorization: bearer $(gcloud auth print-identity-token)" \ -H "Content-Type: application/json" \ @@ -225,16 +225,16 @@ _hr_cf() { fi local json_payload="{}" - + while [[ $# -gt 0 ]]; do if [[ "$1" == -* ]]; then local key="${1#-}" if [[ -z "$2" || "$2" == -* ]]; then - echo "Error: Missing value for option $key" - return 1 + echo "Error: Missing value for option $key" + return 1 fi local value="$2" - + json_payload=$(_hr_add_json_field "$json_payload" "$key" "$value") shift 2 else @@ -244,10 +244,10 @@ _hr_cf() { done local url="https://europe-west1-${PROJECT_ID}.cloudfunctions.net/${function_name}" - + echo "Calling $url..." echo "$json_payload" - + curl "$url" \ -H "Authorization: bearer $(gcloud auth print-identity-token)" \ -H "Content-Type: application/json" \