diff --git a/.agents/operations/agent-enrollment.md b/.agents/operations/agent-enrollment.md index 55c3e2b..6377aa3 100644 --- a/.agents/operations/agent-enrollment.md +++ b/.agents/operations/agent-enrollment.md @@ -81,7 +81,7 @@ If DNS isn't an option at all, override the URLs at bootstrap time: ```bash sudo HOMELAB_GITEA_TOKEN=... \ - HOMELAB_REPO_URL=http://192.168.8.121:3000/dtoro/Homelab-Docs.git \ + HOMELAB_REPO_URL=http://192.168.8.121:3000/dtoro/oikos.git \ HOMELAB_ISSUANCE_NETBIRD=http://192.168.8.205:9820/issue \ HOMELAB_MCP_URL=http://192.168.8.205:9810/mcp \ bash /tmp/bootstrap.sh --with-mcp @@ -129,7 +129,7 @@ TOKEN=... # your Gitea PAT, scope read:repository # Fetch bootstrap.sh from gitea (HTTPS uses split-DNS → caddy). curl -fsSL -u "dtoro:$TOKEN" \ - https://git.hubris.network/dtoro/Homelab-Docs/raw/branch/main/bootstrap.sh \ + https://git.hubris.network/dtoro/oikos/raw/branch/main/bootstrap.sh \ -o /tmp/bootstrap.sh # Run it. @@ -333,7 +333,7 @@ The CLI prints a follow-up checklist that the operator must do manually: | --- | --- | --- | | `no hosts/.yaml in the repo` | Hostname doesn't match inventory entry | Rename either side (see above) | | `fatal: could not read Username for 'http://192.168.8.121:3000'` | bootstrap.sh's credentials file has wrong scheme | Fixed in commit `de6f8be`; pull latest `bootstrap.sh` | -| `gnutls_handshake() failed: TLS connection was non-properly terminated` cloning `git.hubris.network` | Client DNS resolves `*.hubris.network` to the public VPS IP | Configure split-DNS (LXC 180 / Netbird forwarder) or `/etc/hosts` override; or use `HOMELAB_REPO_URL=http://192.168.8.121:3000/dtoro/Homelab-Docs.git` | +| `gnutls_handshake() failed: TLS connection was non-properly terminated` cloning `git.hubris.network` | Client DNS resolves `*.hubris.network` to the public VPS IP | Configure split-DNS (LXC 180 / Netbird forwarder) or `/etc/hosts` override; or use `HOMELAB_REPO_URL=http://192.168.8.121:3000/dtoro/oikos.git` | | `TLS/SSL connection has been closed (EOF)` connecting MCP | Same — `mcp.hubris.network` resolves to public VPS without this vhost | Same DNS fix | | `Invalid Host header` from MCP server | FastMCP's DNS-rebinding protection (default whitelist is 127.0.0.1 only) | Fixed in commit `6848640`; pull latest `mcp/server.py` and redeploy | | `python3-yaml` install fails on Fedora | Wrong package name | Use `python3-pyyaml` (Fedora) instead of `python3-yaml` (Debian) | diff --git a/.agents/operations/hermes-agent.md b/.agents/operations/hermes-agent.md index 9646cfb..2a3598e 100644 --- a/.agents/operations/hermes-agent.md +++ b/.agents/operations/hermes-agent.md @@ -36,7 +36,7 @@ homelab client add new-machine # 3. On new-machine: bootstrap with --with-hermes. TOKEN=... # gitea PAT, read:repository curl -fsSL -u "dtoro:$TOKEN" \ - https://git.hubris.network/dtoro/Homelab-Docs/raw/branch/main/bootstrap.sh \ + https://git.hubris.network/dtoro/oikos/raw/branch/main/bootstrap.sh \ -o /tmp/bootstrap.sh sudo HOMELAB_GITEA_TOKEN=$TOKEN bash /tmp/bootstrap.sh --with-mcp --with-hermes diff --git a/.gitignore b/.gitignore index e680c87..f56f8ab 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ oikos/state.json # Compiled binaries (Go rewrite — bin/oikos, bin/hermes) bin/oikos bin/hermes +oikos/oikos # Legacy Python oikos (superseded by cmd/oikos Go binary — Phase 1-6 rewrite). # oikos/ kernel files are still imported by bin/homelab for operational CLI diff --git a/CLIENTS.md b/CLIENTS.md index ab592f7..9e5500b 100644 --- a/CLIENTS.md +++ b/CLIENTS.md @@ -37,7 +37,7 @@ via the Oikos API. To enroll: ```bash # Run from any machine with mesh connectivity -curl -fsSL https://git.hubris.network/dtoro/Homelab-Docs/raw/main/bootstrap.sh | sudo bash +curl -fsSL https://git.hubris.network/dtoro/oikos/raw/main/bootstrap.sh | sudo bash # Or with optional tooling: curl ... | sudo bash -s -- --with-mcp # wire Claude's MCP config diff --git a/bootstrap.sh b/bootstrap.sh index 908db45..d7b6b1f 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -8,7 +8,7 @@ # context poller replaces the old 5-minute git pull. # # Usage: -# curl -fsSL https://git.hubris.network/dtoro/Homelab-Docs/raw/main/bootstrap.sh \ +# curl -fsSL https://git.hubris.network/dtoro/oikos/raw/main/bootstrap.sh \ # | sudo bash # curl ... | sudo bash -s -- --with-mcp # wire Claude's .mcp.json # curl ... | sudo bash -s -- --with-hermes # install Goose + Hermes @@ -24,7 +24,7 @@ set -euo pipefail # ── defaults ───────────────────────────────────────────────────────── -REPO_RAW_URL="${HOMELAB_RAW_URL:-https://git.hubris.network/dtoro/Homelab-Docs/raw/main}" +REPO_RAW_URL="${HOMELAB_RAW_URL:-https://git.hubris.network/dtoro/oikos/raw/main}" OIKOS_API_URL="${HOMELAB_OIKOS_URL:-https://oikos.hubris.network/api/v1}" CLONE_DIR="${HOMELAB_CONTEXT_DIR:-/opt/homelab}" MCP_URL="${HOMELAB_MCP_URL:-https://mcp.hubris.network/mcp}" @@ -171,6 +171,14 @@ for tmpl in git_log.txt git_status.txt test_results.txt; do fi done +# ── detect control-plane (use localhost if API is reachable directly) ─ +if [ -z "${HOMELAB_OIKOS_URL:-}" ]; then + if curl -s --connect-timeout 2 http://localhost:8090/api/v1/health >/dev/null 2>&1; then + OIKOS_API_URL="http://localhost:8090/api/v1" + log "API reachable on localhost, using direct connection" + fi +fi + # ── enroll via Oikos API (replaces archived Python secrets-issuance) ─ log "enrolling via Oikos API..." diff --git a/internal/httpapi/server.go b/internal/httpapi/server.go index 57c9974..f958098 100644 --- a/internal/httpapi/server.go +++ b/internal/httpapi/server.go @@ -94,6 +94,25 @@ func NewHandler(ctx context.Context, pool *db.Pool, cfg config.Config) http.Hand w.Write([]byte(`{"status":"ok"}`)) }) + // Client enrollment — unauthenticated (IP-gated in handler). + // Registered on base router BEFORE HandlerWithOptions so it + // bypasses the combinedAuth middleware applied to all /api/v1/*. + r.Post("/api/v1/clients/enroll", func(w http.ResponseWriter, req *http.Request) { + var body gen.EnrollRequest + if err := json.NewDecoder(req.Body).Decode(&body); err != nil { + writeProblem(w, req, http.StatusBadRequest, "invalid request body", err.Error()) + return + } + resp, err := s.EnrollClient(req.Context(), gen.EnrollClientRequestObject{Body: &body}) + if err != nil { + writeProblemFromErr(w, req, err) + return + } + if err := resp.VisitEnrollClientResponse(w); err != nil { + writeProblem(w, req, http.StatusInternalServerError, "response encoding failed", err.Error()) + } + }) + strict := gen.NewStrictHandlerWithOptions(s, nil, gen.StrictHTTPServerOptions{ RequestErrorHandlerFunc: func(w http.ResponseWriter, req *http.Request, err error) { writeProblem(w, req, http.StatusBadRequest, "bad request", err.Error()) diff --git a/inventory.yaml b/inventory.yaml index 3f5f087..01cc8ca 100644 --- a/inventory.yaml +++ b/inventory.yaml @@ -139,7 +139,7 @@ services: public_host: mcp.hubris.network endpoint: https://mcp.hubris.network/mcp doc_page: knowledge/wiki/infrastructure/homelab-context.md - config_repo: dtoro/Homelab-Docs + config_repo: dtoro/oikos note: MCP server. Read-only context + management. Reachable on the LAN via Caddy and from off-LAN via Netbird (192.168.8.0/24 is a network resource routed through hubris). @@ -151,7 +151,7 @@ services: public_host: secrets.hubris.network endpoint: https://secrets.hubris.network/issue doc_page: .agents/operations/agent-enrollment.md - config_repo: dtoro/Homelab-Docs + config_repo: dtoro/oikos note: Issues per-client age private keys. Gated at source-IP layer (mesh + LAN subnets in MESH_SUBNETS). risk_notes: identity issuance — any change is security-sensitive; key operations are destructive-class diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 43cd4a4..d83e7e5 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Oikos deploy script — triggered by Gitea webhook on push to dtoro/Homelab-Docs. +# Oikos deploy script — triggered by Gitea webhook on push to dtoro/oikos. # Runs on mac-mini as non-root user via systemd unit oikos-deploy-webhook.service. # Phase 6: CI-gated, SHA-tagged images, rolling restart, pre-deploy pg_dump. diff --git a/seeds/inventory.yaml b/seeds/inventory.yaml index 267c20e..0cdc0ff 100644 --- a/seeds/inventory.yaml +++ b/seeds/inventory.yaml @@ -289,7 +289,7 @@ entities: - {slug: "repo:mule-image", type: config-repo, name: dtoro/mule-image} - {slug: "repo:artifacto", type: config-repo, name: dtoro/Artifacto} - {slug: "repo:terminalito", type: config-repo, name: dtoro/terminalito} - - {slug: "repo:homelab-docs", type: config-repo, name: dtoro/Homelab-Docs} + - {slug: "repo:homelab-docs", type: config-repo, name: dtoro/oikos} # ─── Ingress routes (Caddy, *.hubris.network) ────────────────────── - {slug: "ingress:proxmox.hubris.network", type: ingress-route, name: proxmox.hubris.network} diff --git a/seeds/knowledge.yaml b/seeds/knowledge.yaml index e263a3f..7a6d553 100644 --- a/seeds/knowledge.yaml +++ b/seeds/knowledge.yaml @@ -137,7 +137,7 @@ documents: \ Rejected. |\n| **SMB on host** | Same host-blast-radius problem, plus 30–50% lower throughput than NFS on Linux↔Linux.\ \ Rejected. |\n| **NFS in a dedicated LXC** ← this | Within ~2% of host performance (LXC is namespace isolation; IO path\ \ is unchanged), zero new daemons on hubris, matches the existing fleet pattern. Selected. |\n\nRationale lives in [the\ - \ install plan](https://git.hubris.network/dtoro/Homelab-Docs) `/root/.claude/plans/i-wannt-you-to-nifty-muffin.md` on\ + \ install plan](https://git.hubris.network/dtoro/oikos) `/root/.claude/plans/i-wannt-you-to-nifty-muffin.md` on\ \ hubris.\n\n## Operations\n\n- **Reload exports** after editing `/etc/exports`: `pct exec 102 -- exportfs -ra`\n- **List\ \ active exports:** `pct exec 102 -- exportfs -v`\n- **Watch from outside:** `showmount -e 192.168.8.200`\n- **Service\ \ health:** `pct exec 102 -- systemctl is-active nfs-server rpcbind`\n- **Restart cleanly:** `pct restart 102` (ZimaOS\ @@ -392,7 +392,7 @@ documents: \ The Go MCP uses the official MCP Go SDK (Streamable HTTP, not\n> FastMCP) with 15 tools including `get_blast_radius`,\ \ `request_execution`, and\n> `get_agent_activity`. Source: `internal/mcp/server.go`.\n\n**Current (Python) implementation\ \ — DO NOT MODIFY, awaiting cutover:**\nFastMCP server (Python venv at `/opt/homelab-mcp/.venv`). Reads from\n`/opt/homelab-context/`\ - \ (this LXC is itself an enrolled\n[homelab-context](../infrastructure/homelab-context.md) client). Source\nis `dtoro/Homelab-Docs/mcp/server.py`;\ + \ (this LXC is itself an enrolled\n[homelab-context](../infrastructure/homelab-context.md) client). Source\nis `dtoro/oikos/mcp/server.py`;\ \ service unit\n`homelab-mcp.service` binds `0.0.0.0:9810`. DNS-rebinding protection\ndisabled at the FastMCP layer because\ \ mesh+LAN gating is the actual\ntrust boundary.\n\n- Endpoint: `https://mcp.hubris.network/mcp` (Caddy → `:9810`). StreamableHTTP\ \ transport (POST `/mcp`).\n- 14 tools registered: `get_host`, `list_services`, `find_service`,\n `get_topology`, `search_docs`,\ @@ -400,7 +400,7 @@ documents: \ `get_lxc_state`, `ping_service` (read-only management).\n- Management tools shell out via SSH using a dedicated `mcp-reader`\ \ key\n (planned; not provisioned yet — management tools fail until then).\n\n#### Auto-deploy pipeline (homelab-mcp)\n\ Receiver at `/opt/homelab-mcp/mcp/deploy/webhook/` (in-tree alongside\nthe server code). Listens on `0.0.0.0:9811`, secret\ - \ in\n`/etc/homelab-mcp-deploy/secret`, systemd unit\n`homelab-mcp-deploy.service`. Gitea webhook id 10 on\n`dtoro/Homelab-Docs`.\ + \ in\n`/etc/homelab-mcp-deploy/secret`, systemd unit\n`homelab-mcp-deploy.service`. Gitea webhook id 10 on\n`dtoro/oikos`.\ \ Deploy script reinstalls the service unit and\nrestarts on push.\n\n### secrets-issuance (`/opt/secrets-issuance/`)\ \ — DEPRECATED (Go Phase 5)\n\n> **Status:** Replaced by `internal/secrets/` in the Go rewrite. Machine identities\n>\ \ are now managed via Infisical (`docker compose --profile infisical up`).\nTiny HTTP service that issues per-client age\ @@ -3917,15 +3917,15 @@ documents: \ |\n| `dtoro/claudio-bot` | ~~[claudio-bot (123)](../containers/archive/123-claudio-bot.md)~~ (destroyed\ \ 2026-06-04) | ⊘ | `http://192.168.8.230:9797/deploy` (dead) | (archived) | Repo archived — LXC destroyed |\n| `dtoro/backup-library`\ \ | [hubris host](../hosts/hubris.md) `/opt/backup-library/` | A | `http://192.168.8.77:9798/deploy` | (orig)\ - \ | runs `deploy.sh` (preserves admin-edited `/etc/restic/include-*.list`) |\n| `dtoro/Homelab-Docs` → homelab-mcp | [apps\ + \ | runs `deploy.sh` (preserves admin-edited `/etc/restic/include-*.list`) |\n| `dtoro/oikos` → homelab-mcp | [apps\ \ (105)](../containers/105-apps.md) `/opt/homelab-mcp/` | B | `http://192.168.8.205:9811/deploy` | 10 (deprecated) | ~~reinstalls\ - \ `homelab-mcp.service` + restart~~ → replaced by Go Docker stack on mac-mini |\n| `dtoro/Homelab-Docs` → secrets-issuance\ + \ `homelab-mcp.service` + restart~~ → replaced by Go Docker stack on mac-mini |\n| `dtoro/oikos` → secrets-issuance\ \ | [apps (105)](../containers/105-apps.md) `/opt/secrets-issuance/` | B | `http://192.168.8.205:9821/deploy` | 11 (deprecated)\ \ | ~~reinstalls `secrets-issuance.service` + restart~~ → replaced by `internal/secrets/` Go package |\n| `dtoro/terminalito`\ \ | [trmnl (128)](../containers/128-trmnl.md) `/opt/terminalito/` | B | `http://192.168.8.211:9797/deploy`\ - \ | 12 | reinstalls units + `systemctl restart trmnl-plugins` |\n| `dtoro/Homelab-Docs` → oikos-console | [apps (105)](../containers/105-apps.md)\ + \ | 12 | reinstalls units + `systemctl restart trmnl-plugins` |\n| `dtoro/oikos` → oikos-console | [apps (105)](../containers/105-apps.md)\ \ `/opt/oikos-console/` | B | `http://192.168.8.205:9831/deploy` | 14 | reinstalls `oikos-console.service` + restart —\ - \ see [oikos/console/deploy/README.md](../../../oikos/console/deploy/README.md) |\n\n> Note: `dtoro/Homelab-Docs` has\ + \ see [oikos/console/deploy/README.md](../../../oikos/console/deploy/README.md) |\n\n> Note: `dtoro/oikos` has\ \ **three webhooks** firing on the same push.\n> Each owns its own clone on LXC 105. They don't conflict because each\n\ > deploy.sh only touches its own service unit + venv.\n\n> **Not yet wired:** `dtoro/claudio-monitor` (push, then `/opt/claudio-monitor/scripts/deploy.sh`\ \ manually). The former authentik LXC (124) is destroyed — Authentik runs on the [VPS](../../../hosts/netbird-vps.yaml).\ @@ -3934,7 +3934,7 @@ documents: \ ↔ `dtoro/gitea-customizations` (auto-deploys)\n- `/opt/artifacto/` ↔ `dtoro/Artifacto` (auto-deploys)\n- `/opt/mule-image/`\ \ ↔ `dtoro/mule-image` (auto-deploys)\n- ~~`/opt/plato/app/` ↔ `dtoro/Plato`~~ (destroyed 2026-06-28)\n- ~~`/opt/claudio-bot/`\ \ ↔ `dtoro/claudio-bot`~~ (destroyed 2026-06-04)\n- `/opt/backup-library/` ↔ `dtoro/backup-library` (auto-deploys)\n-\ - \ `/opt/homelab-mcp/` + `/opt/secrets-issuance/` ↔ `dtoro/Homelab-Docs` (auto-deploys both, see [homelab-context](homelab-context.md))\n\ + \ `/opt/homelab-mcp/` + `/opt/secrets-issuance/` ↔ `dtoro/oikos` (auto-deploys both, see [homelab-context](homelab-context.md))\n\ \n## Per-pipeline notes / gotchas\n\n### caddy-conf\n- Repo includes `scripts/webhook/install.sh`. Editing the systemd\ \ unit *inside the repo* does **not** auto-reinstall — re-run `install.sh` manually after unit edits.\n- The unit has\ \ `ReadWritePaths=/etc/caddy` — load-bearing (`ProtectSystem=full` would otherwise block `git pull`).\n\n### gitea-customizations\n\ @@ -3950,7 +3950,7 @@ documents: \ auth (not bearer), so cleanup couldn't be automated.\n\n### backup-library\n- Currently the only deploy that targets\ \ the host directly (`192.168.8.77:9798`).\n- `deploy.sh` is careful to preserve admin edits to `/etc/restic/include-*.list`\ \ — canonical source is `config/` in the repo, but the install path is treated as authoritative once `deploy.sh` has run.\n\ - \n### homelab-mcp / secrets-issuance\n- Both ride a single push to `dtoro/Homelab-Docs`. Two clones on LXC 105\n (`/opt/homelab-mcp`,\ + \n### homelab-mcp / secrets-issuance\n- Both ride a single push to `dtoro/oikos`. Two clones on LXC 105\n (`/opt/homelab-mcp`,\ \ `/opt/secrets-issuance`) — each is an independent\n Shape-B target with its own webhook receiver.\n- The deploy script\ \ restarts the service it just updated. Because the\n webhook receiver itself is a separate systemd unit (`*-deploy.service`),\n\ \ it does NOT restart itself — but `deploy.sh` running `systemctl\n restart homelab-mcp-deploy.service` (or the secrets-issuance\ @@ -3981,7 +3981,7 @@ documents: \ on [trmnl (128)](../containers/128-trmnl.md). Shape B (`server/deploy/webhook.py` receiver, in-repo `server/deploy/deploy.sh`;\ \ secret `/etc/terminalito-deploy/secret`). `app.ini` `ALLOWED_HOST_LIST` extended with `192.168.8.211`. Verified end-to-end\ \ with a push. Repo-local `credential.helper` in `/opt/terminalito/.git/config` (the unit can't read root's global git\ - \ config).\n\n### 2026-05-20 — homelab-mcp + secrets-issuance pipelines added\nWebhook ids 10 + 11 on `dtoro/Homelab-Docs`\ + \ config).\n\n### 2026-05-20 — homelab-mcp + secrets-issuance pipelines added\nWebhook ids 10 + 11 on `dtoro/oikos`\ \ (ports `9811` + `9821` on [apps (105)](../containers/105-apps.md)). Two webhooks on one repo — each owns its own clone\ \ (`/opt/homelab-mcp`, `/opt/secrets-issuance`) and only restarts its own service. See [homelab-context](homelab-context.md)\ \ for why both services live in one repo.\n\n### 2026-05-13 — Plato pipeline added\nWebhook id 8 on `dtoro/Plato` (port\ @@ -4008,7 +4008,7 @@ documents: in `/opt/terminalito/.git/config` (the unit can't read root's global git config). - date: '2026-05-20' title: homelab-mcp + secrets-issuance pipelines added - body: Webhook ids 10 + 11 on `dtoro/Homelab-Docs` (ports `9811` + `9821` on [apps (105)](../containers/105-apps.md)). + body: Webhook ids 10 + 11 on `dtoro/oikos` (ports `9811` + `9821` on [apps (105)](../containers/105-apps.md)). Two webhooks on one repo — each owns its own clone (`/opt/homelab-mcp`, `/opt/secrets-issuance`) and only restarts its own service. See [homelab-context](homelab-context.md) for why both services live in one repo. - date: '2026-05-13' @@ -4531,7 +4531,7 @@ documents: Code, Hermes Agent, future MCP-capable clients) on every machine in the lab\nself-locating and able to read the same source\ \ of truth.\n\nOperational walkthrough for enrolling a new client lives in\n[operations/agent-enrollment.md](../../../.agents/operations/agent-enrollment.md);\ \ this\npage is the architecture reference.\n\n## What's where\n\n| Piece | Host | Path | Role |\n| --- | --- | --- |\ - \ --- |\n| Source of truth | [gitea (104)](../containers/104-gitea.md) | `dtoro/Homelab-Docs.git` | Inventory + wiki +\ + \ --- |\n| Source of truth | [gitea (104)](../containers/104-gitea.md) | `dtoro/oikos.git` | Inventory + wiki +\ \ service code |\n| Per-client clone | every enrolled client | `/opt/homelab-context/` | Read by `homelab` CLI, MCP server,\ \ Hermes Agent |\n| `homelab` CLI | every enrolled client | `/usr/local/bin/homelab` → `/opt/homelab-context/bin/homelab`\ \ (symlink) | Operator surface for enroll/secret/ssh/pct |\n| Per-client age key | every enrolled client | `/etc/age/key.txt`\ @@ -4541,10 +4541,10 @@ documents: \ | `secrets-issuance.service` on port 9820 (https://secrets.hubris.network/issue) | Generates per-client age keypair\ \ on first bootstrap; idempotent; admin-token-gated `/revoke` |\n| Sync timer | every enrolled client | `homelab-context-sync.timer`\ \ (Linux) / `network.hubris.homelab-context-sync.plist` (macOS) | `git pull --ff-only` every 5 min |\n| Encrypted secrets\ - \ | `dtoro/Homelab-Docs` | `secrets/*.yaml` (SOPS+age) | Recipients declared in `.sops.yaml` |\n| Read-only context PAT\ + \ | `dtoro/oikos` | `secrets/*.yaml` (SOPS+age) | Recipients declared in `.sops.yaml` |\n| Read-only context PAT\ \ | `dtoro` Gitea user, scope `read:repository` | given to operators out-of-band | Bootstrap-only — for the initial clone\ \ before SOPS works |\n| Write-scoped PAT | `secrets/gitea-pat.yaml` (SOPS) | `homelab refresh-creds` swaps it into `/etc/homelab-context/git-credentials`\ - \ | All post-bootstrap pushes (client lifecycle, wiki edits) |\n\n## Data flow\n\n```\n dtoro/Homelab-Docs\ + \ | All post-bootstrap pushes (client lifecycle, wiki edits) |\n\n## Data flow\n\n```\n dtoro/oikos\ \ (gitea)\n │\n ┌────────── push ────────┤ ◀── git push (write PAT or SSH)\n \ \ │ │\n │ ┌────── push ──────┘\n │ │ │\n │ │ \ \ ▼ webhook (push event)\n │ │ ┌─── homelab-mcp-deploy ──── (LXC 105:9811)\n │ \ @@ -5936,8 +5936,8 @@ investigations: content: "# mac-mini onboarding — post-mortem & lessons learned\n\nOnboarded the `mac-mini` workstation (macOS Sequoia,\ \ arm64) into the hubris\nhomelab context system with the `--with-hermes` profile. What follows is a\nchronological recap\ \ of every hitch, the fix, and the systemic improvements\nneeded so the next workstation takes 5 min instead of an hour.\n\ - \n## Session log\n\n### Step 1 — clone + symlink\n- Manually cloned `git.hubris.network/dtoro/Homelab-Docs` to `/Users/dtoro/Homelab-Docs`.\n\ - - Created `/opt/homelab-context` → `/Users/dtoro/Homelab-Docs` symlink.\n- **Lesson:** bootstrap.sh was designed to do\ + \n## Session log\n\n### Step 1 — clone + symlink\n- Manually cloned `git.hubris.network/dtoro/oikos` to `/Users/dtoro/oikos`.\n\ + - Created `/opt/homelab-context` → `/Users/dtoro/oikos` symlink.\n- **Lesson:** bootstrap.sh was designed to do\ \ this from scratch, but we'd\n already cloned by hand. The bootstrap's `clone exists; pulling` path handled\n it gracefully.\n\ \n### Step 2 — hostname mismatch\n- `scutil --get LocalHostName` → `Davids-Mac-mini`\n- `hostname -s` → `Mac`\n- Inventory\ \ file: `hosts/mac-mini.yaml`\n- **Fix:** `sudo scutil --set LocalHostName mac-mini && sudo scutil --set HostName mac-mini`\n\ @@ -5990,7 +5990,7 @@ investigations: \ as a default credential helper. Even after configuring the `store` helper,\n git calls osxkeychain after every successful\ \ `get`, which prompts for\n macOS keychain access.\n - `credential.helper = \"\"` does NOT disable the compiled-in\ \ default\n - The `store` helper's `.lock` file in `/etc/homelab-context/` also failed\n silently, causing fallback\ - \ behaviour\n - **Fix:** Embed the credential in the remote URL directly:\n `https://dtoro:TOKEN@git.hubris.network/dtoro/Homelab-Docs.git`\n\ + \ behaviour\n - **Fix:** Embed the credential in the remote URL directly:\n `https://dtoro:TOKEN@git.hubris.network/dtoro/oikos.git`\n\ \ - This bypasses all credential helpers entirely\n\n3. **refresh-creds:** The credential is now managed by the remote\ \ URL.\n If the PAT is rotated, `homelab refresh-creds` won't update the URL.\n - **Workaround:** Run `git remote\ \ set-url origin` after `refresh-creds`\n\n### Step 12 — `homelab` CLI hostname detection\n- `homelab whoami` failed with\ diff --git a/tools/context-poller.sh b/tools/context-poller.sh index 21572e8..e7c5039 100644 --- a/tools/context-poller.sh +++ b/tools/context-poller.sh @@ -9,7 +9,7 @@ set -euo pipefail OIKOS_URL="${OIKOS_API_URL:-https://oikos.hubris.network/api/v1}" HNAME=$(scutil --get LocalHostName 2>/dev/null || hostname -s) CONTEXT_DIR="${HOMELAB_CONTEXT_DIR:-/opt/homelab}" -RAW_URL="${HOMELAB_RAW_URL:-https://git.hubris.network/dtoro/Homelab-Docs/raw/main}" +RAW_URL="${HOMELAB_RAW_URL:-https://git.hubris.network/dtoro/oikos/raw/main}" STATE_FILE="$CONTEXT_DIR/.context_since" SINCE="" diff --git a/tools/post-pull.sh b/tools/post-pull.sh index ccbc3e6..73f89ca 100644 --- a/tools/post-pull.sh +++ b/tools/post-pull.sh @@ -17,7 +17,7 @@ if command -v realpath &>/dev/null; then elif command -v grealpath &>/dev/null; then REPO_REAL=$(grealpath "$CONTEXT_DIR") else - REPO_REAL=$(perl -e 'print Cwd::abs_path(shift)' "$CONTEXT_DIR" 2>/dev/null || echo "/Users/dtoro/Homelab-Docs") + REPO_REAL=$(perl -e 'print Cwd::abs_path(shift)' "$CONTEXT_DIR" 2>/dev/null || echo "/Users/dtoro/oikos") fi REPO_OWNER=$(stat -f "%Su" "$REPO_REAL" 2>/dev/null || echo "dtoro")