Skip to content

fix(clients): remove embedded API key + URL defaults from palace-mode#12

Open
jphein wants to merge 1 commit intorboarescu:mainfrom
jphein:fix/palace-mode-no-embedded-defaults
Open

fix(clients): remove embedded API key + URL defaults from palace-mode#12
jphein wants to merge 1 commit intorboarescu:mainfrom
jphein:fix/palace-mode-no-embedded-defaults

Conversation

@jphein
Copy link
Copy Markdown
Contributor

@jphein jphein commented Apr 27, 2026

Why this is a separate PR rather than a quiet follow-up to PR #4

Two embedded user-specific defaults shipped in clients/palace-mode lines 19-20: a DEFAULT_URL pointing at my homelab daemon, and a real hex DEFAULT_KEY.

Both are leftovers from when the script was extracted from my own install. The URL is http://disks.jphe.in:8085 (my homelab). The key was a real value I authored.

The key has since been rotated so it no longer authenticates against my daemon — but I want to flag this on the record because:

  1. The literal hex value is still in upstream main's source today, not just commit history.
  2. Default palace-mode remote with no args writes my homelab URL into a fresh user's ~/.claude/settings.local.json, pointing their hooks at a daemon they have no auth for.
  3. The pattern ("hex strings as defaults") is bad hygiene to ship in maintained code; contributors might mirror it.

Fix

Read both from environment, no in-source defaults:

DEFAULT_URL="${PALACE_DAEMON_URL_DEFAULT:-${PALACE_DAEMON_URL:-}}"
DEFAULT_KEY="${PALACE_API_KEY:-}"

Plus fail-fast guards in set_mode_remote(): if either URL or key is unset, print a clear error pointing at the right env var and exit 2, instead of silently writing empty strings into settings.local.json.

Test plan

  • palace-mode remote (no env, no arg): exits 2 with URL error
  • palace-mode remote http://host:8085 (no key): exits 2 with key error
  • palace-mode remote http://host:8085 with PALACE_API_KEY=... exported: writes both into settings, prints success
  • palace-mode local: unchanged
  • palace-mode (no subcommand): unchanged

Scope

+11 / -1. Single file. No new dependencies.

Originally part of fork commit d450cef ("address upstream review on PR #4"); the portable-paths half of that commit shipped as PR #10. Sending the embedded-defaults half here standalone.

Copilot AI review requested due to automatic review settings April 27, 2026 17:06
jphein added a commit to jphein/palace-daemon that referenced this pull request Apr 27, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Removes user-specific embedded defaults (daemon URL + API key) from clients/palace-mode so the script no longer ships with an operator’s private config and avoids writing unintended values into a user’s ~/.claude/settings.local.json.

Changes:

  • Drop the hardcoded default URL and API key; read defaults from environment variables instead.
  • Add fail-fast validation in remote mode to avoid writing empty values into settings.local.json.
  • Update in-script guidance/comments around how to configure remote mode.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread clients/palace-mode
Comment on lines +54 to +58
if [ -z "$DEFAULT_KEY" ]; then
echo "error: PALACE_API_KEY not set — set it in your shell or in ~/.config/palace-daemon/env" >&2
echo " the daemon's auth check rejects requests without a matching key." >&2
exit 2
fi
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed — set_mode_remote no longer hard-fails on missing PALACE_API_KEY. Lines 56-60 now warn and proceed: if [ -z "$DEFAULT_KEY" ]; then echo "warning: PALACE_API_KEY not set — proceeding without auth header"; echo " if the daemon at $url enforces auth, the client will get 401s."; fi. The header comment at lines 22-26 documents the contract: PALACE_API_KEY is only required when the target daemon enforces auth (its own server-side PALACE_API_KEY is set).

Comment thread clients/palace-mode Outdated
Comment on lines +20 to +24
# Defaults are read from the environment so this script ships without any
# user-specific values. Override via the env vars below or pass an explicit
# URL on the `remote` subcommand. PALACE_API_KEY is required when switching
# to remote mode — set it in your shell or in ~/.config/palace-daemon/env
# (sourced by your shell rc).
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Reworded — header comment at lines 20-26 now reads: "Defaults are read from the environment so this script ships without any user-specific values. Override via the env vars below or pass an explicit URL on the `remote` subcommand… Export the env vars in your shell environment." No longer claims ~/.config/palace-daemon/env is sourced by the user's rc; readers can place defaults wherever their shell config is wired up.

Comment thread clients/palace-mode Outdated
set_mode_remote() {
url="${1:-$DEFAULT_URL}"
if [ -z "$url" ]; then
echo "error: no daemon URL — pass one as the first arg or set PALACE_DAEMON_URL[_DEFAULT]" >&2
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done — error text at line 53 now names both variables explicitly: error: no daemon URL — pass one as the first arg or set PALACE_DAEMON_URL_DEFAULT or PALACE_DAEMON_URL in env. No more [_DEFAULT] ambiguity.

@jphein jphein force-pushed the fix/palace-mode-no-embedded-defaults branch from 5b0b8b0 to 84172ac Compare April 27, 2026 17:09
`clients/palace-mode` shipped with two embedded user-specific defaults
on lines 19-20: a `DEFAULT_URL` pointing at my homelab daemon and a
real hex `DEFAULT_KEY`. Both are leftovers from when the script was
extracted from my own install — the URL is my homelab address, and
the hex string is a real API key I authored (it has since been
rotated, so it doesn't authenticate against my daemon anymore — but
the literal value is still in upstream main's source).

## Fix

Read both from environment, no in-source defaults:

```bash
DEFAULT_URL="${PALACE_DAEMON_URL_DEFAULT:-${PALACE_DAEMON_URL:-}}"
DEFAULT_KEY="${PALACE_API_KEY:-}"
```

Plus fail-fast guards in `set_mode_remote()` so silent empty-string
writes don't end up in `~/.claude/settings.local.json`. If either URL
or key is unset, the script prints a clear error pointing at the right
env vars and exits 2 instead of writing broken config.

## Why now

Three reasons even though the embedded key is no longer live:

1. Trains contributors that hex defaults are normal — anyone reading
   the source might assume embedding their own key is fine.
2. Default `palace-mode remote` (no args) writes my homelab URL into
   a fresh user's `settings.local.json`, sending their hooks to a
   daemon they have no auth for.
3. Reviewable provenance — removing the literal makes future audits
   cleaner.

## Scope

+11 / -1. Single file. No new dependencies. No behavior change for
operators who set `PALACE_DAEMON_URL` and `PALACE_API_KEY` in their
shell rc. Operators who relied on the embedded defaults get a clear
error pointing at what they need to set.

Originally part of fork commit `d450cef` ("address upstream review on
PR #4"); the portable-paths half of that commit shipped as PR rboarescu#10.
Sending the embedded-defaults half standalone.
@jphein jphein force-pushed the fix/palace-mode-no-embedded-defaults branch from 84172ac to 9a957d8 Compare April 27, 2026 17:50
jphein added a commit to jphein/palace-daemon that referenced this pull request Apr 27, 2026
…boarescu#10/rboarescu#12/rboarescu#13 to main

The amendments to those open upstream PRs caught real bugs that exist
on fork main too — production at disks runs fork main, so these were
shipping live until now.

## main.py — /graph endpoint (from PR rboarescu#13)

- `_read_wings_rooms_direct()`: build `rooms` from union of
  `wings.keys()` + `rooms_by_wing.keys()` rather than just wings.
  Otherwise a partial schema-drift (one query OperationalError-ed
  but the other succeeded) silently drops the half that worked.
  Real data-loss bug for the SME / /viz consumers.
- `/graph` handler: gate the direct-sqlite reads on `_read_sem` via
  a `_direct_under_sem` helper. Coordinates with `_exclusive_palace()`
  used by `/repair mode=rebuild` (so /graph yields rather than racing
  delete-then-create on chroma.sqlite3) and rate-limits unbounded
  `asyncio.to_thread` reads under load (was 2 threads/request × N
  concurrent requests).
- `_canonical_topic()` (from PR rboarescu#8): drop the `topic: str` annotation
  and add a non-string isinstance guard at the top, coerce
  `None`/numbers/lists to `CHECKPOINT_TOPIC` with a warning. A
  malformed `{"topic": null}` JSON payload no longer leaks `None`
  through to `tool_diary_write`.

## scripts/verify-routes.sh (from PR rboarescu#9)

- `set -euo pipefail` (was `set -e`) — pipeline failures and unset
  vars now surface instead of being masked.
- `curl -fsS` instead of `-sS` on every probe so HTTP non-2xx
  (e.g. `/health` 503 when palace is degraded) fails curl directly.
  Without this, a 503 body with `"daemon":"palace-daemon"` slips
  through the body-grep as a pass.
- Limit-check rewrite: split curl exit code from JSON parse so a
  connection error or non-JSON response `?`-flags rather than
  fails-with-traceback (the previous `2>&1` redirect captured
  Python tracebacks into `$COUNT`, which then triggered the fail
  path with a confusing message).

## clients/palace-mcp-dispatch.sh (from PR rboarescu#10)

- Replace `readlink -f` (GNU-specific, fails on macOS BSD readlink)
  with `cd "$(dirname …)" && pwd -P`. POSIX-portable; covers the
  actual common case (parent directory is a symlink under the
  Claude Code plugin cache).
- Add explicit existence check on `$MCP_CLIENT` before exec, with
  a clear error message instead of a generic Python "can't open
  file" trace.

## clients/palace-mode (from PR rboarescu#12)

- Make `PALACE_API_KEY` optional in `set_mode_remote`. Server-side
  `_check_auth` only enforces auth when its own `PALACE_API_KEY` is
  set, so a daemon running without auth accepts unauthenticated
  clients. The previous fail-fast was overly strict for that case.
  Warn-but-proceed instead.

All five fixes are amendments on the corresponding upstream PR
branches (force-pushed earlier today). No behavior change for the
healthy path; the changes harden failure modes that were caught in
review.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants