diff --git a/.env.example b/.env.example index 49d36b3..b339e15 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,6 @@ -INFRAPULSE_ENV=development -INFRAPULSE_SECRET_KEY=change-me -DATABASE_URL=postgresql+psycopg://infrapulse:infrapulse@postgres:5432/infrapulse +ORBITALWARD_ENV=development +ORBITALWARD_SECRET_KEY=change-me +DATABASE_URL=postgresql+psycopg://orbitalward:orbitalward@postgres:5432/orbitalward REDIS_URL=redis://redis:6379/0 FRONTEND_URL=http://localhost:5173 BACKEND_URL=http://localhost:8000 diff --git a/AGENTS.md b/AGENTS.md index faf5183..0cb87be 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ -# InfraPulse Agent Notes +# OrbitalWard Agent Notes -InfraPulse should be built incrementally. Keep the first release focused on a secure monitoring appliance with guided setup, website monitoring, alerts, and notifications. +OrbitalWard should be built incrementally. Keep the first release focused on a secure monitoring appliance with guided setup, website monitoring, alerts, and notifications. ## Product Guardrails diff --git a/LICENSE b/LICENSE index 835e547..668210d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 InfraPulse contributors +Copyright (c) 2026 OrbitalWard contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index ece76a2..03909b1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# InfraPulse +# OrbitalWard Beautiful, self-hosted infrastructure monitoring without the enterprise-tool headache. -InfraPulse is an open-source monitoring appliance for homelabs, small businesses, and internal IT teams. The first target is a secure and attractive monitoring foundation with guided setup, website checks, alerts, notifications, and clean dashboards. It is not trying to be a full Zabbix or LibreNMS replacement in the first release. +OrbitalWard is an open-source monitoring appliance for homelabs, small businesses, and internal IT teams. The first target is a secure and attractive monitoring foundation with guided setup, website checks, alerts, notifications, and clean dashboards. It is not trying to be a full Zabbix or LibreNMS replacement in the first release. ## Current Status @@ -57,7 +57,7 @@ Default local admin credentials come from `.env`: - `INITIAL_ADMIN_EMAIL=admin@example.com` - `INITIAL_ADMIN_PASSWORD=change-me` -Change these values before using InfraPulse anywhere beyond local development. +Change these values before using OrbitalWard anywhere beyond local development. ## Project Structure diff --git a/backend/alembic.ini b/backend/alembic.ini index f47786b..6d59d28 100644 --- a/backend/alembic.ini +++ b/backend/alembic.ini @@ -2,7 +2,7 @@ script_location = alembic prepend_sys_path = . -sqlalchemy.url = postgresql+psycopg://infrapulse:infrapulse@postgres:5432/infrapulse +sqlalchemy.url = postgresql+psycopg://orbitalward:orbitalward@postgres:5432/orbitalward [loggers] keys = root,sqlalchemy,alembic diff --git a/backend/alembic/versions/20260522_0001_initial_schema.py b/backend/alembic/versions/20260522_0001_initial_schema.py index 1428bda..64897f6 100644 --- a/backend/alembic/versions/20260522_0001_initial_schema.py +++ b/backend/alembic/versions/20260522_0001_initial_schema.py @@ -1,4 +1,4 @@ -"""Initial InfraPulse schema. +"""Initial OrbitalWard schema. Revision ID: 20260522_0001 Revises: diff --git a/backend/app/__init__.py b/backend/app/__init__.py index aa4c655..f399ca0 100644 --- a/backend/app/__init__.py +++ b/backend/app/__init__.py @@ -1 +1 @@ -"""InfraPulse backend package.""" +"""OrbitalWard backend package.""" diff --git a/backend/app/api/health.py b/backend/app/api/health.py index c634f59..5aaafd9 100644 --- a/backend/app/api/health.py +++ b/backend/app/api/health.py @@ -5,4 +5,4 @@ router = APIRouter(tags=["health"]) @router.get("/health") def health() -> dict[str, str]: - return {"status": "ok", "service": "infrapulse-backend"} + return {"status": "ok", "service": "orbitalward-backend"} diff --git a/backend/app/api/monitors.py b/backend/app/api/monitors.py index 6aaacd4..d55e3df 100644 --- a/backend/app/api/monitors.py +++ b/backend/app/api/monitors.py @@ -53,6 +53,8 @@ def create_website_monitor( "expected_text": payload.expected_text, "unexpected_text": payload.unexpected_text, "timeout_seconds": payload.timeout_seconds, + "check_tls_expiry": payload.check_tls_expiry, + "tls_warning_days": payload.tls_warning_days, }, interval_seconds=payload.interval_seconds, status="unknown", diff --git a/backend/app/api/notifications.py b/backend/app/api/notifications.py index 15bc306..4866741 100644 --- a/backend/app/api/notifications.py +++ b/backend/app/api/notifications.py @@ -14,7 +14,7 @@ router = APIRouter(prefix="/notifications/channels", tags=["notifications"]) def _channel_to_read(channel: NotificationChannel) -> NotificationChannelRead: settings = dict(channel.settings or {}) - settings.setdefault("username", "InfraPulse") + settings.setdefault("username", "OrbitalWard") return NotificationChannelRead( id=channel.id, name=channel.name, @@ -40,7 +40,7 @@ def create_channel( db: Session = Depends(get_db), ) -> NotificationChannelRead: channel_settings = dict(payload.settings or {}) - channel_settings.setdefault("username", "InfraPulse") + channel_settings.setdefault("username", "OrbitalWard") channel = NotificationChannel( name=payload.name, channel_type=payload.channel_type, @@ -70,8 +70,8 @@ def test_channel( response = httpx.post( url, json={ - "username": (channel.settings or {}).get("username") or "InfraPulse", - "text": f"InfraPulse test notification for {channel.name}", + "username": (channel.settings or {}).get("username") or "OrbitalWard", + "text": f"OrbitalWard test notification for {channel.name}", }, timeout=10, ) diff --git a/backend/app/auth/security.py b/backend/app/auth/security.py index d6204e1..e3d714b 100644 --- a/backend/app/auth/security.py +++ b/backend/app/auth/security.py @@ -20,12 +20,12 @@ def verify_password(plain_password: str, hashed_password: str) -> bool: def create_access_token(subject: str) -> str: expires_at = datetime.now(UTC) + timedelta(minutes=settings.access_token_expire_minutes) payload = {"sub": subject, "exp": expires_at} - return jwt.encode(payload, settings.infrapulse_secret_key, algorithm=ALGORITHM) + return jwt.encode(payload, settings.orbitalward_secret_key, algorithm=ALGORITHM) def decode_access_token(token: str) -> str | None: try: - payload = jwt.decode(token, settings.infrapulse_secret_key, algorithms=[ALGORITHM]) + payload = jwt.decode(token, settings.orbitalward_secret_key, algorithms=[ALGORITHM]) return payload.get("sub") except JWTError: return None diff --git a/backend/app/core/config.py b/backend/app/core/config.py index e46e82c..70b125d 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -7,9 +7,9 @@ from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): model_config = SettingsConfigDict(env_file=".env", extra="ignore") - infrapulse_env: str = "development" - infrapulse_secret_key: str = Field(default="change-me", min_length=8) - database_url: str = "postgresql+psycopg://infrapulse:infrapulse@postgres:5432/infrapulse" + orbitalward_env: str = "development" + orbitalward_secret_key: str = Field(default="change-me", min_length=8) + database_url: str = "postgresql+psycopg://orbitalward:orbitalward@postgres:5432/orbitalward" redis_url: str = "redis://redis:6379/0" frontend_url: AnyHttpUrl | str = "http://localhost:5173" backend_url: AnyHttpUrl | str = "http://localhost:8000" diff --git a/backend/app/core/secrets.py b/backend/app/core/secrets.py index 4570ba6..faf668d 100644 --- a/backend/app/core/secrets.py +++ b/backend/app/core/secrets.py @@ -7,7 +7,7 @@ from app.core.config import settings def _fernet() -> Fernet: - digest = hashlib.sha256(settings.infrapulse_secret_key.encode("utf-8")).digest() + digest = hashlib.sha256(settings.orbitalward_secret_key.encode("utf-8")).digest() return Fernet(base64.urlsafe_b64encode(digest)) diff --git a/backend/app/main.py b/backend/app/main.py index e316c06..7aee9fa 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -25,7 +25,7 @@ async def lifespan(_: FastAPI) -> AsyncIterator[None]: app = FastAPI( - title="InfraPulse API", + title="OrbitalWard API", version="0.1.0", description="Self-hosted infrastructure monitoring API", lifespan=lifespan, diff --git a/backend/app/schemas/core.py b/backend/app/schemas/core.py index 5fc8d34..a71fbaa 100644 --- a/backend/app/schemas/core.py +++ b/backend/app/schemas/core.py @@ -64,6 +64,8 @@ class WebsiteMonitorCreate(BaseModel): expected_text: str | None = None unexpected_text: str | None = None timeout_seconds: int = Field(default=10, ge=1, le=120) + check_tls_expiry: bool = False + tls_warning_days: int = Field(default=30, ge=1, le=365) interval_seconds: int = Field(default=60, ge=10) create_asset: bool = True alert_enabled: bool = True diff --git a/backend/pyproject.toml b/backend/pyproject.toml index cd9df5f..a1ec77d 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,7 +1,7 @@ [project] -name = "infrapulse-backend" +name = "orbitalward-backend" version = "0.1.0" -description = "InfraPulse FastAPI backend" +description = "OrbitalWard FastAPI backend" requires-python = ">=3.12" dependencies = [ "alembic>=1.13.3", @@ -27,6 +27,10 @@ test = [ [tool.pytest.ini_options] testpaths = ["tests"] +[tool.setuptools.packages.find] +include = ["app*"] +exclude = ["alembic*"] + [build-system] requires = ["setuptools>=75.0"] build-backend = "setuptools.build_meta" diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index b8bb651..2a6350d 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -2,13 +2,13 @@ services: postgres: image: postgres:16-alpine environment: - POSTGRES_USER: infrapulse - POSTGRES_PASSWORD: infrapulse - POSTGRES_DB: infrapulse + POSTGRES_USER: orbitalward + POSTGRES_PASSWORD: orbitalward + POSTGRES_DB: orbitalward volumes: - postgres-dev-data:/var/lib/postgresql/data healthcheck: - test: ["CMD-SHELL", "pg_isready -U infrapulse -d infrapulse"] + test: ["CMD-SHELL", "pg_isready -U orbitalward -d orbitalward"] interval: 10s timeout: 5s retries: 5 diff --git a/docker-compose.yml b/docker-compose.yml index 66cc988..067d26a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,13 +2,13 @@ services: postgres: image: postgres:16-alpine environment: - POSTGRES_USER: infrapulse - POSTGRES_PASSWORD: infrapulse - POSTGRES_DB: infrapulse + POSTGRES_USER: orbitalward + POSTGRES_PASSWORD: orbitalward + POSTGRES_DB: orbitalward volumes: - postgres-data:/var/lib/postgresql/data healthcheck: - test: ["CMD-SHELL", "pg_isready -U infrapulse -d infrapulse"] + test: ["CMD-SHELL", "pg_isready -U orbitalward -d orbitalward"] interval: 10s timeout: 5s retries: 5 diff --git a/docs/alerting-design.md b/docs/alerting-design.md index efaa496..95ae0c0 100644 --- a/docs/alerting-design.md +++ b/docs/alerting-design.md @@ -26,4 +26,4 @@ Initial channels: - Zoom Team Chat incoming webhook - Generic webhook -Alert messages should be human-readable and include asset, check, status, duration, timestamps, and a link back to InfraPulse. +Alert messages should be human-readable and include asset, check, status, duration, timestamps, and a link back to OrbitalWard. diff --git a/docs/architecture.md b/docs/architecture.md index 6c33210..0ab5688 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,6 +1,6 @@ # Architecture -InfraPulse is a monorepo with four main areas: +OrbitalWard is a monorepo with four main areas: - `backend`: FastAPI service exposing REST endpoints and owning database access. - `worker`: Background scheduler and collectors for checks and alert evaluation. diff --git a/docs/discovery-design.md b/docs/discovery-design.md index 06427b1..f11ca75 100644 --- a/docs/discovery-design.md +++ b/docs/discovery-design.md @@ -1,6 +1,6 @@ # Discovery Design -Guided discovery is a core InfraPulse workflow. +Guided discovery is a core OrbitalWard workflow. ```text Add target @@ -16,7 +16,7 @@ Create monitors and optional alert rules ## Monitor vs Alert Separation -InfraPulse must allow monitoring without alerting. Every discovered item should eventually support separate choices: +OrbitalWard must allow monitoring without alerting. Every discovered item should eventually support separate choices: - Collect metric - Graph metric diff --git a/docs/plugin-design.md b/docs/plugin-design.md index 73cf8e8..5b92e76 100644 --- a/docs/plugin-design.md +++ b/docs/plugin-design.md @@ -1,11 +1,11 @@ # Plugin Design -Plugins will let InfraPulse add collectors and discovery logic without hard-coding every integration into the core API. +Plugins will let OrbitalWard add collectors and discovery logic without hard-coding every integration into the core API. Target shape: ```python -class InfraPulsePlugin: +class OrbitalWardPlugin: name: str display_name: str diff --git a/docs/progress.md b/docs/progress.md index cd7ccd3..f99ccd6 100644 --- a/docs/progress.md +++ b/docs/progress.md @@ -1,10 +1,10 @@ -# InfraPulse Progress +# OrbitalWard Progress -Last updated: 2026-05-22 +Last updated: 2026-05-23 ## Current State -InfraPulse has a working Docker Compose development stack with PostgreSQL, Redis, FastAPI backend, Python worker, and React/Vite frontend. +OrbitalWard has a working Docker Compose development stack with PostgreSQL, Redis, FastAPI backend, Python worker, and React/Vite frontend. Implemented foundation: @@ -18,6 +18,7 @@ Implemented website-monitor slice: - Create, edit, delete website monitors from the UI. - HTTP status and expected-text checks. +- Optional TLS certificate expiry checks for HTTPS monitors. - Monitor status and recent incident visibility on dashboard. - Basic alert rules created with website monitors. - Incidents can be acknowledged and silenced from the UI. @@ -27,7 +28,7 @@ Implemented notification slice: - Create, edit, test, and delete notification channels from the UI. - Generic webhook, Mattermost, and Zoom Team Chat channel types. -- Webhook URLs encrypted at rest using `INFRAPULSE_SECRET_KEY`. +- Webhook URLs encrypted at rest using `ORBITALWARD_SECRET_KEY`. - Saved webhook URLs are not returned to the UI. - Configurable post username per notification channel. - Worker sends incident open and recovery notifications. @@ -42,7 +43,6 @@ Implemented notification slice: - Alert rule editing UI is not implemented. - Notification routing/policies are not implemented; all enabled webhook channels receive incident notifications. - Email/SMTP notifications are not implemented yet. -- TLS certificate expiry checks are not implemented yet. - Ping and TCP checks are not implemented yet. - Graphing exists only as placeholders; metric visualization is not implemented. - Worker scheduling is simple polling, not a Redis queue yet. @@ -51,16 +51,15 @@ Implemented notification slice: ## Recommended Next Work -1. Add TLS certificate expiry monitor support. -2. Add ping and TCP port monitors. -3. Add alert rule editing UI and richer alert conditions. -4. Add notification policy/routing controls. -5. Add email/SMTP notification channel. -6. Add audit event writes for auth, monitor, credential, notification, and incident actions. -7. Build credential vault UI with masked secret handling. -8. Add user administration UI. -9. Add graphs for website response time and monitor status history. -10. Add backend and worker tests for the website-monitor and notification flows. +1. Add ping and TCP port monitors. +2. Add alert rule editing UI and richer alert conditions. +3. Add notification policy/routing controls. +4. Add email/SMTP notification channel. +5. Add audit event writes for auth, monitor, credential, notification, and incident actions. +6. Build credential vault UI with masked secret handling. +7. Add user administration UI. +8. Add graphs for website response time and monitor status history. +9. Add backend and worker tests for the website-monitor and notification flows. ## Operational Notes @@ -75,4 +74,4 @@ Default local login comes from `.env`: - `INITIAL_ADMIN_EMAIL=admin@example.com` - `INITIAL_ADMIN_PASSWORD=change-me` -Change these values before using InfraPulse outside local development. +Change these values before using OrbitalWard outside local development. diff --git a/docs/security.md b/docs/security.md index d5dd416..0ecb9df 100644 --- a/docs/security.md +++ b/docs/security.md @@ -1,6 +1,6 @@ # Security -InfraPulse must be secure from the beginning because it will store infrastructure credentials. +OrbitalWard must be secure from the beginning because it will store infrastructure credentials. ## Authentication @@ -19,7 +19,7 @@ Credential records are modeled separately from monitors and assets. Secret field Rules: -- Use `INFRAPULSE_SECRET_KEY` from the environment. +- Use `ORBITALWARD_SECRET_KEY` from the environment. - Never log secrets. - Mask saved secrets in the UI. - Audit credential create, update, and delete events. diff --git a/docs/vision.md b/docs/vision.md index 9dcac86..d78e4ea 100644 --- a/docs/vision.md +++ b/docs/vision.md @@ -1,12 +1,12 @@ -# InfraPulse Vision +# OrbitalWard Vision -InfraPulse is a secure, self-hosted monitoring platform for homelabs, small businesses, and internal IT teams. +OrbitalWard is a secure, self-hosted monitoring platform for homelabs, small businesses, and internal IT teams. The v0.1 product should feel like a polished appliance, not a pile of raw monitoring configuration. Users should be guided through adding targets, testing connections, discovering useful items, choosing what to monitor, and separately choosing what should alert. ## Design Philosophy -InfraPulse exposes intent, not implementation details. +OrbitalWard exposes intent, not implementation details. Raw SNMP OIDs, probe internals, and collector details belong behind friendly profiles and advanced tools. The normal UI should say things like "Port 5 outbound traffic", "Graph this port", and "Alert if port goes down". diff --git a/frontend/index.html b/frontend/index.html index 43d0656..de63a13 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,7 +3,7 @@
-