Commit Graph
28 Commits
Author SHA1 Message Date
Pouzor 03e5ae939e ci(security): give pip-audit the same registry-outage retry as npm
pip-audit queries PyPI's advisory API and exits non-zero when it cannot
reach it, exactly as `npm audit` does — the same class of outage that
reddened #409 would have failed the Python half too.

Both now go through .github/scripts/audit-with-retry.sh, which retries
only when the output names a transport or availability failure and lets
a real finding fail on the first attempt, unretried. The npm loop added
in the previous commit is folded into it.

ha-relevant: no
2026-09-04 10:01:35 +02:00
Pouzor 37a3aee9cc ci(security): retry the npm audit when the registry endpoint is down
`npm audit` exits 1 both for a real advisory and for a registry that
refuses to answer, so a 503 from the audit endpoint reddened PRs that
changed no dependency at all — as it did on #409.

Retry up to three times, but only when the output names a transport or
availability failure. An advisory at or above high severity still fails
on the first attempt, unretried.

ha-relevant: no
2026-09-04 10:01:35 +02:00
Pouzor 97472b65ba fix(ci): run the install smoke test under bash, not dash
The runner hands container steps `sh -e {0}` unless told otherwise, so
every step died on `set: Illegal option -o pipefail` before the installer
ran. Pin the job's shell to bash; `[[ … ]]` in the assertions needs it too.

ha-relevant: no
2026-09-02 02:15:10 +02:00
Pouzor c5a49537ed test(ci): smoke-test the bare-metal installer in a debian:12 container
ShellCheck reads the installer but never runs it, so it cannot catch a
`set -euo pipefail` abort — the failure class that broke this script on a
fresh host. This job executes it for real in debian:12, which carries no
Node and gives the job no TTY, so both the nodesource path and the prompt
fallbacks are exercised on every run.

It asserts what the script promises: SECRET_KEY generated, the bcrypt hash
and the JSON values single-quoted (the systemd EnvironmentFile trap),
.env at mode 600, SQLITE_PATH under the install dir, the venv and the Vite
build present, the service user created, the unit's ExecStart and
EnvironmentFile correct. It then boots the backend by the unit's own
ExecStart and waits on /api/v1/health, which proves the generated .env
actually parses, and re-runs the installer to check the idempotency claim
leaves .env untouched.

systemd is out of reach in a container: systemctl is stubbed, so the unit
is written but never started, and the EnvironmentFile parse itself stays
untested. The job is gated on paths, since it costs roughly six minutes.

Also adds gnupg to the installer's apt list — the nodesource setup script
needs it and a minimal Debian does not have it.

Verified by running the same steps locally in debian:12: all assertions
pass, the backend answers /api/v1/health, and the second run keeps .env.

ha-relevant: no
2026-09-02 02:15:10 +02:00
Pouzor 56df462a8f ci: stop the secret scan reporting pytest names as Lob keys
The push that carried the whole branch through TruffleHog failed on a
"verified" Lob credential: `test_updates_an_existing_device_in_place`, a test
function in backend/tests/test_racks.py. Lob's detector matches any
`test_`-prefixed identifier of that length and reports it verified, because
Lob test-mode keys authenticate unconditionally — so verification proves
nothing here.

Lob is a direct-mail API this project does not use, and any pytest function
named that long trips it again, so the detector is excluded rather than the
test renamed.

ha-relevant: no
2026-08-09 20:35:23 +02:00
Pouzor 8f273e0201 fix: sync MCP edge type enum with frontend and gate both enums in CI
The node type fix left the same stale-enum bug in place for edges:
create_edge only advertised ethernet/wifi/iot/vlan/virtual, while the
frontend EdgeType union also defines cluster, fibre and electrical.
The backend's EdgeBase.type is a plain str, so those three were always
accepted server-side — only the MCP schema rejected them.

- Extract EDGE_TYPES in mcp/app/tools.py and use it for create_edge.
- Add mcp/tests/test_edge_types_sync.py, mirroring the NodeType guard:
  parses EdgeType out of frontend/src/types/index.ts and asserts set
  equality with EDGE_TYPES.
- Add create_edge cases for the three previously-rejected types plus a
  schema test pinning the enum contents and the ethernet default.
- Add an `mcp` job to quality.yml. Both sync guards were unreachable
  from CI before: quality.yml only ran frontend and backend, so the
  enums could drift again with nothing to catch it. The job runs from a
  full checkout because the guards read the frontend sources, which are
  not in the mcp Docker build context.
- Pin mcp[cli]>=1.26,<2. The bound is load-bearing: SDK 2.0 dropped the
  low-level Server.list_resources/list_tools decorator API that
  app/resources.py and app/tools.py are built on, so an unbounded spec
  breaks both the tests and the Docker image at import time.
- Move pytest/pytest-anyio/trio into mcp/requirements.txt, matching how
  backend/requirements.txt carries its own test deps. trio is required
  because pytest-anyio parametrises every async test over both backends.

Tested: 114 passed in mcp/, both in the existing venv and in a clean
Python 3.13 venv installed the way the new CI job does.

ha-relevant: no
2026-07-30 01:05:48 +02:00
Pouzor 37ad9c6933 fix(ci): scope dependency-audit npm audit to runtime deps
The dependency-audit job failed on vulnerabilities from `shadcn` and its
transitive tree (hono, fast-uri, body-parser, @modelcontextprotocol/sdk).
`shadcn` is a build-time scaffolding CLI plus a CSS `@import`, never shipped
in the browser bundle, so it belongs in devDependencies.

- move `shadcn` to devDependencies (regenerated lockfile: dev flags only,
  no version changes)
- run `npm audit` with `--omit=dev`, matching the runtime-only intent of the
  pip-audit step

npm audit --omit=dev --audit-level=high now reports 0 vulnerabilities; the
production build still resolves the shadcn CSS import.

ha-relevant: no
2026-07-21 23:34:34 +02:00
ypso 99e7b9a343 ci(security): enforce unsuppressed Python audit 2026-07-21 00:37:32 +02:00
Pouzor 7c2417f5a9 fix(security): resolve code scanning alerts
Add least-privilege 'permissions: contents: read' to quality, security
and docker-ci workflows (actions/missing-workflow-permissions).

Harden markdown table cell escaping in exportMarkdown: escape backslash
before pipe and collapse newlines so untrusted values can't break the
table (js/incomplete-sanitization). Add regression tests.

ha-relevant: maybe
2026-06-09 17:15:26 +02:00
Pouzor fc765fa255 ci(docker): publish homelable-mcp image to GHCR
Add mcp matrix entry in docker-publish workflow so the MCP server
image is built and pushed alongside backend/frontend. Also wire the
prebuilt compose file so users can pull and run it directly.

Closes #162
2026-05-27 21:32:55 +02:00
findtheloraxandRemy adb2088752 revert: restore workflow to upstream version 2026-04-24 00:42:00 +02:00
Brett FerranteandRemy 3ccdde0bea Update Docker image references to use repository owner 2026-04-24 00:42:00 +02:00
findtheloraxandRemy fe5e3c9858 revert: restore workflow to upstream version 2026-04-22 22:41:01 +02:00
Brett FerranteandRemy 1a3cde3a02 Update Docker image references to use repository owner 2026-04-22 22:41:01 +02:00
findtheloraxandRemy a8ca4f1cca revert: restore workflow to upstream version 2026-04-21 16:08:40 +02:00
Brett FerranteandRemy 0204a7ddeb Update Docker image references to use repository owner 2026-04-21 16:08:40 +02:00
Pouzor d9f3477780 fix(ci): inject bcrypt hash via compose environment with $$ escaping, remove dynamic hash generation 2026-03-28 13:03:28 +01:00
Pouzor c9d6642b26 ci: pass DL3008 ignore directly to hadolint action 2026-03-28 12:58:03 +01:00
Pouzor fd8735ce7f fix(ci): quote CTID path, fix bcrypt hash shell expansion, npm audit fix 2026-03-28 12:49:50 +01:00
Pouzor 0bdf835a3d fix(ci): expose backend port in CI, fix shellcheck warnings in lxc-install.sh 2026-03-28 12:45:01 +01:00
Pouzor cc68fcf1c1 test: add deployment test tiers (shellcheck, hadolint, Docker smoke, integration)
Tier 1 — quality.yml: ShellCheck on lxc-install.sh, hadolint on both Dockerfiles
Tier 2 — docker-ci.yml: build images, smoke-test backend health + frontend 200
Tier 3 — test_integration.py: full stack pytest (auth, canvas save/reload, dimensions)
Also adds Docker healthcheck to backend service in docker-compose.yml
2026-03-28 12:33:35 +01:00
Pouzor 7ba5e888b4 feat: add standalone (frontend-only) mode via VITE_STANDALONE build flag
- App.tsx: bypass auth gate, swap canvas save/load to localStorage
- Sidebar.tsx: hide scan views and Scan Network button
- useStatusPolling.ts: skip WebSocket connection
- Dockerfile.frontend: accept VITE_STANDALONE build arg
- docker-publish.yml: build ghcr.io/pouzor/homelable-frontend-standalone image
- docker-compose.standalone.yml: frontend-only compose file
- install.sh: add --standalone flag

Usage:
  curl -fsSL .../install.sh | bash -s -- --standalone
  cd homelable && docker compose up -d
2026-03-09 14:00:25 +01:00
Pouzor 1cd93ed250 fix: add linux/arm64 to Docker build platforms for Apple Silicon support 2026-03-09 13:33:49 +01:00
Pouzor 6a7113193f feat: add GitHub Actions Docker publish workflow and prebuilt install
- Build and push backend/frontend images to ghcr.io on every push to main and on version tags
- Add docker-compose.prebuilt.yml for pull-based install (no clone needed)
- Update README Quick Start with inline install one-liner using prebuilt images
2026-03-09 12:01:04 +01:00
Pouzor 1811afa749 fix: upgrade fastapi to 0.135.1, fix starlette CVEs, update auth test assertions
- fastapi 0.115.0 → 0.135.1 pulls starlette 0.52.1 (fixes CVE-2024-47874, CVE-2025-54121)
- pip-audit: ignore CVE-2024-23342 (ecdsa Minerva attack, no fix exists; app uses HS256 only)
- Update auth guard tests: FastAPI 0.135 returns 401 (not 403) when Bearer token is missing
2026-03-07 15:18:28 +01:00
Pouzor e5262b4b71 fix: replace safety scan with pip-audit (no login required)
safety scan requires interactive account login, breaking CI.
pip-audit provides equivalent vulnerability scanning without auth.
2026-03-07 15:11:59 +01:00
Pouzor fccbdad409 fix: patch CVEs — upgrade python-jose 3.3→3.5, python-multipart 0.0.12→0.0.22; use safety scan 2026-03-07 15:08:04 +01:00
Pouzor 4310a5cc2d feat: Phase 1 scaffold — frontend canvas + backend skeleton
Frontend:
- Vite + React 18 + TypeScript + Tailwind v4 + Shadcn/ui
- React Flow v12 canvas with all 11 node types and 5 edge types
- Dark theme with project design system (cyan, green, orange, purple accents)
- Collapsible sidebar, toolbar, detail panel
- Zustand store for canvas state
- Demo data with 10 nodes and 10 edges

Backend:
- FastAPI + SQLAlchemy async + SQLite (Python 3.13)
- DB models: Node, Edge, CanvasState, PendingDevice, ScanRun
- REST API routes: auth, nodes, edges, canvas, scan, status (WebSocket)
- JWT auth + bcrypt via config.yml
- Pydantic v2 schemas

Infra:
- GitHub Actions quality + security workflows
- .gitignore, .env.example, verify-tooling.sh, security-check.sh
2026-03-06 23:14:34 +01:00