234 lines
12 KiB
Markdown
234 lines
12 KiB
Markdown
# ArchNest — Open-Source Release Readiness (v1)
|
|
|
|
This document is the checklist + plan for publishing ArchNest as an open-source
|
|
project. It is an internal planning doc — **do not copy this file into the public
|
|
repo.** It covers what to copy, what to scrub, licensing, repo structure,
|
|
README/screenshots, the release cadence, and resume/LinkedIn framing.
|
|
|
|
The public OSS repo should be a **fresh repository with a clean history** (see
|
|
"Why a fresh repo" below), not a fork of the working repo.
|
|
|
|
---
|
|
|
|
## 1. Security sweep result (done 2026-06-22)
|
|
|
|
A full secret/credential sweep of tracked files **and entire git history**
|
|
(`git log --all -p`) was run. Result: **clean — no real secrets are committed.**
|
|
|
|
- No private keys, no hardcoded secret assignments in tracked source.
|
|
- No real `.env`, `.pem`, `.key`, or `.db` was ever committed at any point in
|
|
history. The only `BEGIN RSA PRIVATE KEY` / `AKIA…` matches are documentation
|
|
prose and AWS's official `AKIAIOSFODNN7EXAMPLE` placeholder.
|
|
- `.gitignore` correctly excludes `backend/.env`, `backend/data`, `*.db`.
|
|
- Both `.env.example` files contain only placeholders (empty / `change-me-…`).
|
|
|
|
### Code-level security review (solid)
|
|
- JWT auth (Fastify `@fastify/jwt`). Every route group registers a blanket
|
|
`addHook('onRequest', app.authenticate)` before its routes; the three
|
|
WebSocket routes (`terminal`, `docker`, `guacamole`) verify
|
|
`app.jwt.verify(query.token)` explicitly (WS can't use header hooks).
|
|
- Mutating shared-config endpoints (integrations, tunnels, data export/import,
|
|
user management) are gated by `adminOnly` / `requireAdmin`. `authenticate`
|
|
re-reads `role`/`active` from the DB each request, so demote/deactivate takes
|
|
effect immediately even with an older token.
|
|
- Integration secrets: `serialize()` returns only secret **key names**
|
|
(`secretKeys`), never values. Secrets are encrypted at rest (AES-256-GCM,
|
|
`backend/src/db/crypto.ts`).
|
|
- Docker agent ingest is a **separately registered** route with a constant-time
|
|
bearer-token check; returns 503 when `ARCHNEST_AGENT_TOKEN` is unset (disabled
|
|
by default), and is NOT behind the user-auth hook (by design).
|
|
- Command-injection surfaces are guarded: tmux session names validated against
|
|
`^[A-Za-z0-9_-]{1,64}$` before interpolation; `system.ts` uses `execFile` (no
|
|
shell); Docker-over-SSH single-quotes container refs.
|
|
|
|
### Things to improve / note for OSS (not leaks)
|
|
- **CORS default**: `server.ts` does `origin: process.env.ARCHNEST_CORS_ORIGIN ?? true`.
|
|
`true` reflects any origin. Fine for a self-hosted single-origin deploy, but the
|
|
OSS README should tell users to set `ARCHNEST_CORS_ORIGIN` in production, and the
|
|
default `.env.example` should point at `http://localhost:5173` (it already does
|
|
for the backend example).
|
|
- Default JWT/secret env values in `backend/.env.example` are `change-me-…` — the
|
|
README must stress generating real ones (`openssl rand -hex 32`). The server
|
|
already refuses to boot without `ARCHNEST_SECRET_KEY` + `ARCHNEST_JWT_SECRET`.
|
|
|
|
---
|
|
|
|
## 2. What to SCRUB / NOT copy to the public repo
|
|
|
|
None of these are security leaks, but they are personal/infra-specific or
|
|
internal working notes that don't belong in a public project:
|
|
|
|
| Item | Why | Action |
|
|
|---|---|---|
|
|
| `docs/rdp-debug-handoff.md` | Contains lab creds (`sam` / `happy2026`) + private VM IP `192.168.122.55` + personal host names | **Exclude** (or heavily genericize into a "Remote Desktop setup" guide with no creds/IPs) |
|
|
| `HANDOFF.md` | Internal session-to-session working notes | **Exclude** |
|
|
| `docs/OPEN-SOURCE-RELEASE.md` (this file) | Internal release plan | **Exclude** |
|
|
| `archnest.snsnetlabs.com` references in `.env.example`, `docker-compose.yml`, `.github/workflows/deploy.yml` | Personal domain/deploy target | **Genericize** to `example.com` / `localhost`; the deploy workflow should be removed or replaced with a generic CI (build + lint only, no SCP-to-my-server) |
|
|
| `.github/workflows/deploy.yml` | SSHes/SCPs to the personal `racknerd1` server | **Remove**; replace with a generic build/test CI workflow |
|
|
| `agent/` deploy specifics | Fine to include the agent script, but scrub any host-specific URLs/tokens in its README | **Review + genericize** |
|
|
| `assets/` personal background images | Large PNGs; keep the ones the UI needs (hero banner, logo, KPI backgrounds), drop unused experiments (`opt1.bg`, `settings-custom-bg`, `pics/`) | **Trim to what's referenced** |
|
|
| Test/scratch files | `backend/data/`, any `*.db`, session logs | Already gitignored — confirm none are force-added |
|
|
|
|
Keep `ROADMAP.md` and `TERMIX_MIGRATION.md`? — `ROADMAP.md` yes (genericize:
|
|
it's a fine public roadmap once paid-tier framing is softened). `TERMIX_MIGRATION.md`
|
|
is build history; optional — can keep as `docs/HISTORY.md` or drop.
|
|
|
|
---
|
|
|
|
## 3. Why a fresh repo (recommended)
|
|
|
|
The working repo's history contains personal commit author emails, the personal
|
|
deploy workflow, the lab-cred debug doc, and the personal domain. The simplest
|
|
clean cut for a public project:
|
|
|
|
1. Create a new empty public repo (e.g. `archnest` under the personal GitHub).
|
|
2. Copy the **working tree** (not `.git`) of the files in the "INCLUDE" list below.
|
|
3. Genericize the scrubbed items.
|
|
4. `git init`, single initial commit ("Initial public release — ArchNest v1"),
|
|
author set to the public identity.
|
|
5. Add `LICENSE`, public `README.md`, `CONTRIBUTING.md`, screenshots.
|
|
|
|
This avoids dragging history-scrubbing tooling (BFG/`git filter-repo`) and
|
|
guarantees nothing personal leaks via an old commit.
|
|
|
|
### INCLUDE (the actual app)
|
|
```
|
|
src/ # React frontend
|
|
backend/src/ # Fastify backend
|
|
backend/package.json, backend/tsconfig*.json, backend/Dockerfile
|
|
backend/.env.example # (placeholders only — already clean)
|
|
package.json, package-lock.json, tsconfig*.json, vite.config.*, index.html
|
|
Dockerfile, docker-compose.yml # genericized (no personal domain)
|
|
.env.example # genericized
|
|
.gitignore, .dockerignore
|
|
public/ # fonts + static assets actually referenced
|
|
assets/ # ONLY images the UI imports
|
|
agent/archnest-docker-agent.sh + a genericized agent/README.md
|
|
design-decisions.md, ROADMAP.md # genericized
|
|
.kiro/steering/design-rules.md # optional — useful for contributors
|
|
LICENSE, README.md, CONTRIBUTING.md, screenshots/ # new, written for OSS
|
|
```
|
|
|
|
### EXCLUDE
|
|
```
|
|
.git/ # fresh history instead
|
|
HANDOFF.md
|
|
docs/rdp-debug-handoff.md
|
|
docs/OPEN-SOURCE-RELEASE.md (this file)
|
|
.github/workflows/deploy.yml (replace with generic CI)
|
|
backend/data/, *.db, session logs, *.tsbuildinfo
|
|
unused assets/ experiments + pics/
|
|
```
|
|
|
|
---
|
|
|
|
## 4. License
|
|
|
|
Recommended: **MIT** or **Apache-2.0**.
|
|
- **MIT** — shortest, most permissive, maximum adoption, easiest "I built this"
|
|
story. Good default for a portfolio/resume project.
|
|
- **Apache-2.0** — same permissiveness plus an explicit patent grant and a
|
|
NOTICE mechanism; slightly more "enterprise-friendly."
|
|
|
|
Given the goal (resume/LinkedIn showcase, broad adoption, simple), **MIT** is the
|
|
recommendation. Add a `LICENSE` file with the chosen license and the author's name
|
|
+ year. Note third-party components keep their own licenses (Guacamole = Apache-2.0,
|
|
the bundled Nerd Font has its own license already in `public/fonts/NERD-FONTS-LICENSE.txt`).
|
|
|
|
---
|
|
|
|
## 5. README.md (public) — outline
|
|
|
|
1. **Hero**: one-line pitch + a screenshot/GIF of the Glance dashboard.
|
|
> "A self-hosted, web-based control panel for your homelab and cloud — SSH
|
|
> terminal, file manager, Docker, tunnels, RDP/VNC, host metrics, and
|
|
> integration dashboards, all in one browser tab."
|
|
2. **Screenshots** (see §6).
|
|
3. **Features** — bullet list grouped by page; mark paid add-ons / not-yet-done
|
|
honestly (mirror the in-app Help "Not in the open-source version" notes).
|
|
4. **Architecture** — short: React + Vite + TS frontend, Fastify + SQLite backend,
|
|
guacd sidecar for RDP/VNC. One diagram is plenty.
|
|
5. **Quick start** — `docker compose up` path + the required env vars (with
|
|
`openssl rand -hex 32` generation), and the local-dev path (`npm install` /
|
|
`npm run dev` in root and `backend/`).
|
|
6. **Configuration** — env var table (from `.env.example`), CORS note, first-run
|
|
`/api/setup` admin creation, the 10-user cap.
|
|
7. **Security notes** — secrets encrypted at rest; set a real CORS origin in prod;
|
|
it's designed to sit behind your own mesh/VPN, not be exposed raw to the
|
|
internet (mesh prerequisite gate exists, defaults off).
|
|
8. **Roadmap** — link `ROADMAP.md` + the "updates ~every 3 months" promise.
|
|
9. **Contributing** — link `CONTRIBUTING.md`.
|
|
10. **License** — MIT.
|
|
11. **Credits / "Built with AI"** — see §7.
|
|
|
|
---
|
|
|
|
## 6. Screenshots to capture (for README + LinkedIn)
|
|
|
|
Capture in the **default dark theme**, with demo/sanitized data (no real
|
|
hostnames, IPs, or tokens — use the placeholder-y names):
|
|
- Glance dashboard (hero shot)
|
|
- Infrastructure → Node Status with a couple of integrations
|
|
- Terminal with a split-pane / multiple tabs
|
|
- Files (SFTP browser) + a host-to-host transfer in progress
|
|
- Containers list + a container detail tab
|
|
- Remote Desktop showing a live XFCE session
|
|
- Host Metrics widgets
|
|
- Settings → Integrations (shows the breadth) and the locked Appearance "Paid
|
|
add-on" card (shows the free/paid split honestly)
|
|
- Help page (shows the per-page docs + OSS-edition note)
|
|
|
|
A short screen-recording GIF of opening a terminal or RDP session makes the
|
|
strongest LinkedIn post.
|
|
|
|
---
|
|
|
|
## 7. Resume / LinkedIn framing
|
|
|
|
Honest, specific, and ownership-forward. Suggested phrasing:
|
|
|
|
> **ArchNest** — a self-hosted, web-based homelab/cloud control panel
|
|
> (React + TypeScript + Fastify + SQLite, Dockerized). Single-pane access to SSH
|
|
> terminals, SFTP, Docker, SSH tunnels, browser-based RDP/VNC (Apache Guacamole),
|
|
> live host metrics, and pluggable infrastructure integrations (Proxmox, AWS,
|
|
> Cloudflare, NetBird, Uptime Kuma). Built with AI-assisted development; I owned
|
|
> the architecture, product decisions, security review, and integration/debugging
|
|
> (e.g. root-caused and fixed a FreeRDP/NLA + Guacamole tunnel-keepalive issue
|
|
> end-to-end across browser, proxy, and target VM). Open source under MIT, shipped
|
|
> v1, ongoing ~quarterly releases.
|
|
|
|
Notes for credibility:
|
|
- It's fine and increasingly normal to say "AI-assisted." Pair it with the
|
|
*engineering judgment* you provided (architecture, security, debugging) so it
|
|
reads as "I directed and verified," not "I prompted and pasted."
|
|
- The RDP debugging saga is a genuinely strong, concrete story — it shows
|
|
multi-layer debugging (browser ↔ guacd/FreeRDP ↔ xrdp/desktop) and root-cause
|
|
rigor. Worth a short LinkedIn write-up on its own.
|
|
|
|
---
|
|
|
|
## 8. Pre-publish checklist
|
|
|
|
- [ ] Create fresh public repo, copy INCLUDE list, exclude EXCLUDE list.
|
|
- [ ] Genericize personal domain → `example.com`/`localhost` in
|
|
`.env.example`, `docker-compose.yml`.
|
|
- [ ] Replace `.github/workflows/deploy.yml` with a generic build/lint CI (no SCP).
|
|
- [ ] Add `LICENSE` (MIT), public `README.md`, `CONTRIBUTING.md`.
|
|
- [ ] Capture + add screenshots (sanitized data, dark theme).
|
|
- [ ] Re-run a secret scan on the NEW repo before first push
|
|
(`git log -p | grep -iE 'AKIA|BEGIN .*PRIVATE KEY|password|secret'` plus a
|
|
tool like `gitleaks detect` for good measure).
|
|
- [ ] Confirm `npm run build` (root) and `npx tsc --noEmit` (backend) pass on the
|
|
copied tree.
|
|
- [ ] Confirm first-run works from a clean `docker compose up` with freshly
|
|
generated secrets and no prior DB.
|
|
- [ ] Tag `v1.0.0`.
|
|
|
|
---
|
|
|
|
## 9. Release cadence (commitment)
|
|
|
|
Public promise: **updates approximately every 3 months.** Keep a short
|
|
`CHANGELOG.md` in the public repo and cut a tagged release each cycle. The Help
|
|
page's "Open-source edition" note and the README both reference this cadence —
|
|
keep them in sync.
|