5 Commits

Author SHA1 Message Date
fc4e1c75ed agap-mcp: authenticate the :3100 listener (kb#180), pin bw CLI, add capture/classifier
Listener auth (kb#180, DESIGN-a2a-agents.md §4)
-----------------------------------------------
agap-mcp binds :3100 on every interface (network_mode: host) and the LAN
carries VPN-terminated peers, so an unauthenticated JSON-RPC listener handed
ha_call_service / gitea_wiki_write / wiki_edit / radicale+todoist writes and
POST /capture-idea to any LAN peer. Only vw_* was gated before (kb#147), and
only at ENFORCE=1.

src/listener-auth.js now requires `Authorization: Bearer <token>` resolving to
a known agent id on every route except /health, which stays open so a
misconfigured token map is still diagnosable. Two gates stay deliberately
layered and independently switchable: "are you an agent at all?" (this file)
vs "are you trusted enough for the vault?" (trust-gate.js), both reading the
same token map.

Also closes an SSE session-hijack hole: /messages previously trusted any
sessionId with no credential, so a guessed or leaked id was full tool access.
Sessions are now pinned to the caller identity captured at the /sse handshake,
comparing agent id *and* token.

Auth defaults ON, and boot fails loudly if the token map is empty rather than
serving 401 to everyone while /health reports ok. Rollback is
AGAP_MCP_REQUIRE_AUTH=0.

Verified live: unauthenticated and bad-token /mcp -> 401, unauthenticated
/capture-idea -> 401, /health -> 200, both real agent tokens -> 200 with 36
tools, including from inside the adolf container.

Pin the bw CLI
--------------
The Dockerfile installed @bitwarden/cli unpinned. Rebuilding jumped
2026.2.0 -> 2026.7.0, whose WASM cipher deserializer rejects any stored login
carrying `"uri": null` ("invalid type: JsValue(Object({...})), expected a
string") -- 33 of 49 items in this vault have that shape. `bw list` then exits
1, server init fails, and the container crash-loops. Pinned to 2026.2.0.

Do not unpin: 2026.7.0 cannot authenticate against this Vaultwarden
(2025.12.0) at all -- it refuses plain HTTP outright and 404s on the identity
endpoint over HTTPS. Updating the CLI requires upgrading Vaultwarden first.

capture / classifier
--------------------
Adds the POST /capture-idea REST endpoint and the idea classifier behind it
(consumed by the todoist-capture plugin), with tests. Carried in the same
commit because server.js wires both this and the auth boot path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 04:40:51 +00:00
0f9d83f3db agap-mcp: stop leaking BW master password via bw error messages
vaultwarden.js run() passed BW_PASSWORD as argv to `bw login`/`bw unlock`.
On any non-zero exit, execFileSync throws an Error whose message is
"Command failed: bw unlock <BW_PASSWORD> --raw", which propagated to
server.js's `console.error('Init failed:', e.message)` -> the master password
landed in container stdout / `docker logs` on every Vaultwarden init failure
(wrong password, server down, TLS reset). Empirically confirmed by a security
audit 2026-07-24.

run() now catches the exec error and re-throws with the argv stripped: only the
subcommand, exit code, and stderr survive, and BW_PASSWORD is scrubbed from
stderr defensively. Verified: a forced failure yields "bw unlock failed (exit 1)"
with no password substring.

Not yet active: the running agap-mcp container predates this file; a rebuild
(`docker compose build agap-mcp && docker compose up -d agap-mcp`) is needed to
deploy it. The live container is still vulnerable until then.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 06:07:51 +00:00
b548a8f345 agap-mcp: MediaWiki + Todoist tools, vault trust-gate, registry wiring
Commits a cluster of entangled agap-mcp / Adolf-tooling WIP that had accumulated
uncommitted in shared files (server.js, the three MCP-config layers). Bundled as
one commit because server.js interleaves all of it and cannot be cleanly split;
each stream is named here for the record. Authorized by alvis 2026-07-23.

- **kb#95 — family MediaWiki tools:** new src/mediawiki.js (wiki_search / wiki_read
  / wiki_edit, MediaWiki login->CSRF->edit flow, no new deps), registered in
  server.js and fetched from the family.alogins.net Vaultwarden login item.
  Proven standalone against family.alogins.net (search/read/edit, revid 1520 on a
  bot-userspace page). Wired into all three layers: openai/shared-mcp.json,
  adolf/openclaw.json, openai/agent-registry.yaml.

- **kb#147 — vault trust-gate (A2A-15), DORMANT:** new src/trust-gate.js (+ two
  test files), requireVaultAccess() around the vw_* tools, gated by
  AGAP_MCP_ENFORCE_VAULT_TRUST (docker-compose.yml, default 0). OFF by default —
  vw_* behaviour is byte-for-byte unchanged until an operator sets ENFORCE=1 and
  populates AGAP_MCP_AGENT_TOKENS from Vaultwarden. That activation is a separate
  human step; kb#147 remains escalated for human verification and is NOT verified
  by this commit. js-yaml added to read the registry. agent-registry.yaml mounted
  read-only as the trust-class source of truth.

- **Todoist tools:** new src/todoist.js (initTodoist + 6 todoist_* tools),
  registered in server.js, sourced from the TODOIST_TOKEN Vaultwarden item.

- **kanboard cutover cleanup:** removes src/kanboard.js and its imports — the
  kanboard_* slice moved to the standalone kanboard-mcp on 2026-07-06.

- **openai/validate_capability_grants.py:** cross-checks the registry against the
  live openclaw.json + shared-mcp.json layers; passes (exit 0).

No secrets committed: all tokens come from Vaultwarden via env/.env; the trust
gate's AGAP_MCP_AGENT_TOKENS defaults to `{}` (fail-closed). node_modules/ now
gitignored, package-lock.json tracked.

NOT YET ACTIVATED: agap-mcp has not been rebuilt and adolf-llm/adolf not
restarted, so the wiki/todoist tools are wired but not live. That restart is the
outstanding step on kb#95 (and stays a human/orchestrator action).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 06:48:07 +00:00
e74d28a808 agap-mcp: move master password to git-ignored .env
BW_PASSWORD referenced via ${BW_PASSWORD} from a git-ignored .env instead
of plaintext in the tracked compose. Also records the account repoint to
adolf46@proton.me (the shared bw dir's actually-working account; the old
allogn creds were stale). Restores Claude's vault MCP and backs Adolf's
vault access (kb#64).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
2026-07-16 09:16:30 +00:00
Alvis
b8efe4732d Sync infra config: HA/Zabbix relocation, Immich storage move, new services
Accumulated uncommitted infra changes:
- Caddyfile: repoint HA/Zabbix to 192.168.1.4/.3, add ~20 new site routes
- Immich: move media to /mnt/smsg, enable CUDA ML, mem limits, rewrite backup.sh
- Add service stacks: agap-mcp, anki, family, freshrss, iperf3, kanboard,
  linkwarden, qbittorrent, radicale, syncthing, vikunja, windows
- openwebui: enable API keys; ollama: drop CPU fallback
- seafile/zabbix: extra_hosts entries; matrix: add user juris
- Remove pihole stack and stale wiki/migrate.py
- Ignore marketplace-mcp (standalone repo) and linkwarden runtime data

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
2026-07-04 13:28:04 +00:00