Commit graph

31 commits

Author SHA1 Message Date
Ubuntu
5be002cb03 test(adapters): fix mock settings to use dicts instead of JSON strings
Now that routes.py no longer calls json.loads() on settings, the test
mocks must return dicts directly (as asyncpg does with jsonb).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 21:35:51 +00:00
Ubuntu
0f127399b3 fix(gui): remove JSONB double-encoding in adapter updates
The GUI pool has init=_setup_json_codec registered, which makes asyncpg
auto-serialize Python dicts to JSONB. Calling json.dumps() on a dict
before passing it to asyncpg double-encodes - the value gets stored as
a JSON-encoded string rather than a JSON object.

Changes:
- Remove json.dumps() from UPDATE statement in adapters_edit_submit
- Remove defensive isinstance(settings, str) checks that masked the bug
- Add regression tests to verify settings is passed as dict, not string

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 21:33:48 +00:00
Matt Johnson
dec8ce8545 feat(gui): add adapters list and edit UI (1b-4)
- Add GET /adapters route for listing all adapters
- Add GET /adapters/{name} for edit form with per-adapter fields
- Add POST /adapters/{name} for validation, update, and audit
- Add ADAPTER_UPDATE audit constant
- Add Adapters nav link to base.html
- Server-side validation for cadence (60-3600), email format,
  api_key_alias existence, satellites, and feed values
- Region displayed read-only with 1b-5 placeholder
- Hot reload via existing NOTIFY trigger (no new mechanism)
- Add comprehensive tests (9 tests)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 21:19:40 +00:00
Matt Johnson
736b637d31 feat(gui): add read-only dashboard with HTMX polling
- Add NATS connection module (nats.py) for JetStream access
- Add three dashboard cards: events (24h), stream sizes, poll times
- Replace placeholder index with HTMX-polling dashboard
- Graceful degradation when NATS unavailable (200 with error, not 500)
- Per-stream/adapter failure isolation
- Add comprehensive dashboard tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 20:09:05 +00:00
Matt Johnson
6b5f6709e4 fix(archive): subscribe to all event streams
- One durable consumer per event-bearing stream (CENTRAL_WX,
  CENTRAL_FIRE, CENTRAL_QUAKE) for independent ack tracking
- max_deliver=5 prevents poison-message infinite loops
- Orphaned 'archive' consumer on CENTRAL_WX cleaned up on startup
- Consumer naming: archive-{stream_name_lower}

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 19:29:38 +00:00
Matt Johnson
83b1e45fa8 docs: add test database setup, restore geom to test fixture
- Add docs/test-database.md with one-time setup, DSN convention, reset
  instructions, and explanation of why PostGIS is not in migrations
- Update docs/migrations.md with "Extensions are not in migrations"
  section explaining superuser requirement
- Restore geom GEOMETRY(Geometry, 4326) column to test fixture now that
  central_test has PostGIS installed
- Add CREATE EXTENSION IF NOT EXISTS postgis to test fixture for
  self-bootstrap (central_test is superuser)
- Add Testing section to README.md pointing to docs/test-database.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 18:26:48 +00:00
Matt Johnson
a25b4af4e8 fix(tests): remove geom column from test fixture (no PostGIS in test DB)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 17:40:24 +00:00
Matt Johnson
98e9d95810 fix(tests): replace stub tests with real DB migration tests
- Replace pytest.skip stubs with actual DB tests against central_test
- Test backfill for all three adapters (nws, firms, usgs_quake)
- Test FK RESTRICT, NOT NULL, and FK validation constraints
- Test schema changes (source dropped, adapter exists with constraints)
- Delete stale sql/schema.sql (migrations are sole source of truth)
- Update docs/migrations.md with schema.sql removal note

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 17:39:38 +00:00
Ubuntu
8601a19f60 feat(schema): add adapter column to events, drop source
Replaces module-path-based source column (e.g. "central/adapters/nws")
with stable adapter identifier (e.g. "nws") that foreign-keys to
config.adapters.name.

Migration 011:
- ADD COLUMN adapter TEXT
- Backfill via REPLACE(source, 'central/adapters/', '')
- SET NOT NULL + FK RESTRICT
- CREATE INDEX (adapter, received DESC) for dashboard queries
- DROP COLUMN source

Code changes:
- Event model: source field renamed to adapter
- All adapters: use adapter="name" instead of source="central/adapters/name"
- Archive: write adapter column instead of source

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 16:09:59 +00:00
Matt Johnson
b1ba2d1863 fix(tests): update tests for lazy app loading and 302 redirect
- test_gui_scaffold.py: use standalone router instead of importing app
  to avoid triggering settings load during test collection
- test_setup_gate.py: expect 302 (not 307) for setup gate redirect

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 06:14:25 +00:00
Matt Johnson
f059f982bc feat(gui): add auth core, setup gate, and first-run operator creation
- Add migrations 007-010 for system config, operators, sessions, audit_log
- Implement argon2id password hashing via argon2-cffi
- Implement session-based authentication with database-stored tokens
- Add SetupGateMiddleware to redirect to /setup until first operator created
- Add SessionMiddleware to load session from cookie and attach operator
- Create /setup, /login, /logout, /change-password routes with CSRF protection
- Add periodic session cleanup task (hourly)
- Add audit logging for auth events
- Update systemd unit with EnvironmentFile for /etc/central/central.env
- Add comprehensive tests for auth, middleware, and audit modules

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 05:30:49 +00:00
Matt Johnson
614312db36 feat(gui): add FastAPI + Jinja2 + HTMX scaffold
- FastAPI app with Jinja2 templates and Pico CSS + HTMX from CDN
- Routes: GET / (placeholder page), GET /health (JSON healthcheck)
- systemd unit (no Install section - manual start only)
- TestClient tests for both endpoints

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 04:32:39 +00:00
Matt Johnson
374a8c067f chore: normalize line endings to LF 2026-05-16 22:26:12 +00:00
Matt Johnson
aacf06499b feat(adapters): add USGS earthquake adapter
USGS Earthquake Hazards Program adapter:
- Polls GeoJSON feed (all_hour default, configurable)
- Magnitude tier classification (minor/light/moderate/strong/major/great)
- Deduplication via USGS stable event ID
- Region filter via shapely point-in-bbox
- Skips events with null magnitude (quarry blasts, etc.)

Includes comprehensive unit tests.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 20:51:36 +00:00
Matt Johnson
22c50d3176 fix(firms): use public is_published/mark_published methods
Match NWS adapter pattern for supervisor compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 20:03:34 +00:00
Matt Johnson
0097163edf feat(adapters): add FIRMS fire hotspot adapter
NASA FIRMS adapter for VIIRS satellite fire detections:
- Polls VIIRS_SNPP_NRT and VIIRS_NOAA20_NRT satellites
- Deduplication via stable ID (satellite📅time:lat:lon)
- Hot-reload support for region, satellites, and API key
- Confidence mapping: l/n/h -> low/nominal/high
- Severity: high=3, nominal=2, low=1

Includes comprehensive unit tests for:
- CSV parsing and event generation
- Deduplication logic
- URL building and config application

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 19:58:31 +00:00
Matt Johnson
5b028b38e8 test: remove ineffective hot-reload tests
These tests pass on both fixed and unfixed code, meaning they do
not actually exercise the cadence-decrease bug. The tests were
added as part of PR #4 but direct verification showed they
do not catch the issue they claim to test.

A follow-up issue should be filed for proper regression tests
that reproduce the actual bug (AsyncLimiter blocking).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 17:19:27 +00:00
Matt Johnson
35de09ea93 test: add hot-reload integration tests for cadence changes
Add tests that exercise the ACTUAL running loop with cancel_event
signaling, not just AdapterState math in isolation.

Test cases:
- Test 1: Cadence decrease (60->30) wakes loop immediately
- Test 2: Cadence increase (10->20) extends wait correctly
- Test 3: Enable/disable/enable with gap > cadence polls immediately
- Test 4: Enable/disable/enable with gap < cadence waits

These tests verify the cancel_event mechanism properly interrupts
the sleeping loop when config changes occur via _on_config_change.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 05:59:35 +00:00
Ubuntu
a362b7b93e test: remove TomlConfigSource and config_source flag tests
TOML-related tests no longer needed after Phase C retirement.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 03:42:43 +00:00
Matt Johnson
c39e3174b8 fix: preserve last_completed_poll across adapter disable/enable
Previously, _stop_adapter() used pop() to remove adapter state,
which lost last_completed_poll. On re-enable, a fresh state was
created, causing immediate poll and violating rate-limit guarantee.

Changes:
- Add is_running property to AdapterState
- _stop_adapter: preserve state, just cancel task
- _start_adapter: reuse existing stopped state if present
- Add _remove_adapter for full cleanup when adapter is deleted
- _on_config_change: call _remove_adapter for deleted adapters

Integration tests verify:
- Test A: gap > cadence -> immediate poll (correct)
- Test B: gap < cadence -> wait until last_poll + cadence (was broken)
- Test C: delete + re-add -> fresh state (correct)

Tests-fail-before-fix verified: Test A/B failed on unfixed code
with "State was removed on stop!", pass with fix.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 02:37:57 +00:00
Ubuntu
1abdf45375 test: add ConfigSource and hot-reload rate-limit tests
- TomlConfigSource tests: list/get adapters, watch_for_changes no-op
- DbConfigSource tests: list/get adapters with DB fixtures
- create_config_source factory tests
- NOTIFY integration test for DbConfigSource
- Rate-limit guarantee tests:
  - Cadence change respects last_poll time
  - Gap exceeding new cadence polls immediately
  - Enable/disable/enable respects rate limit
  - Multiple rapid changes no extra polls
- Bootstrap flag validation tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 01:55:47 +00:00
Ubuntu
25909b0f4d fix(tests): replace echo6 reference with central.local
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 01:36:44 +00:00
Ubuntu
826141c71a docs(tests): add README documenting CENTRAL_TEST_DB_DSN env var
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 01:36:40 +00:00
Ubuntu
b183a621bb feat(config_store): add listener reconnect with exponential backoff
Listener now automatically reconnects on connection loss with
exponential backoff (1s-30s). Cancellation propagates cleanly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 01:36:35 +00:00
Ubuntu
8c5349c880 feat(config): add database-backed config store
Add ConfigStore class providing async access to config schema:

- get_adapter/list_adapters/upsert_adapter for adapter config
- pause_adapter/unpause_adapter for runtime control
- set_api_key/get_api_key with encryption via crypto.py
- listen_for_changes using Postgres LISTEN/NOTIFY

Includes Pydantic models (AdapterConfig, ApiKeyInfo) and tests
using real Postgres test database.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-15 23:07:56 +00:00
Ubuntu
fab452aa02 feat(config): add AES-256-GCM crypto primitives
Add encrypt/decrypt functions using AES-256-GCM for secret storage.
Master key loaded from file path specified in bootstrap config.

Features:
- 32-byte key from base64-encoded file
- 12-byte random nonce per encryption
- AEAD authentication (detects tampering)
- Key caching with clear_key_cache() for rotation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-15 23:07:41 +00:00
Ubuntu
e126569a4d feat(config): add bootstrap config from environment
Add pydantic-settings based Settings class for loading configuration
from environment variables or .env file. Provides early-stage config
before database-backed config store is available.

Includes:
- CENTRAL_DB_DSN, CENTRAL_NATS_URL, CENTRAL_MASTER_KEY_PATH, CENTRAL_LOG_LEVEL
- Cached loader with get_settings()
- Tests for env vars, .env file, validation, caching

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-15 23:07:33 +00:00
Matt Johnson
4a7f1a76c7 refactor: rename CloudEvents extension attributes hub* → central*
Rename extension attributes for consistency with project naming:
- hubschemaversion → centralschemaversion
- hubcategory → centralcategory
- hubseverity → centralseverity

Non-breaking change - no consumers depend on these names yet.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-15 21:47:50 +00:00
Matt Johnson
31be17430d runtime: NWS adapter, supervisor, archive consumer, systemd units
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-15 21:29:08 +00:00
Matt Johnson
714971fe99 foundation: models, adapter ABC, config, CE wire, schema
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-15 21:08:56 +00:00
Matt Johnson
36ebbcb250 scaffold: initial repository structure 2026-05-15 19:16:24 +00:00