Commit Graph

208 Commits

Author SHA1 Message Date
hsiegeln
dbf53aa8e8 Auto-discover ClickHouse migration files instead of hardcoded list
All checks were successful
CI / build (push) Successful in 1m11s
CI / docker (push) Successful in 41s
CI / deploy (push) Successful in 29s
Replace the static SCHEMA_FILES array with classpath pattern matching
(classpath:clickhouse/*.sql). Migration files are discovered and sorted
by filename, so adding a new numbered .sql file is all that's needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:26:33 +01:00
hsiegeln
9f9e677103 Add display_name_claim migration to schema init list
Some checks failed
CI / build (push) Successful in 1m12s
CI / docker (push) Successful in 42s
CI / deploy (push) Has been cancelled
The 06-oidc-display-name-claim.sql migration was not registered in
ClickHouseConfig.SCHEMA_FILES, so the ALTER TABLE never ran on
existing deployments, causing startup failure when the repository
tried to SELECT the missing column.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:24:31 +01:00
hsiegeln
86f905e672 Preserve created_at on user upsert to avoid accumulating un-merged rows
Some checks failed
CI / build (push) Successful in 1m12s
CI / docker (push) Successful in 42s
CI / deploy (push) Has been cancelled
On re-login the upsert was inserting a new row with created_at=now(),
causing ClickHouse ReplacingMergeTree to accumulate rows until
background compaction. Now preserves the original created_at via
INSERT...SELECT from the existing record.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:18:12 +01:00
hsiegeln
a6f94e8a70 Full OIDC logout with id_token_hint for provider session termination
Some checks failed
CI / build (push) Successful in 1m10s
CI / docker (push) Successful in 48s
CI / deploy (push) Has been cancelled
Return the OIDC id_token in the callback response so the frontend can
store it and pass it as id_token_hint to the provider's end-session
endpoint on logout. This lets Authentik (or any OIDC provider) honor
the post_logout_redirect_uri and redirect back to the Cameleer login
page instead of showing the provider's own logout page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:14:07 +01:00
hsiegeln
463cab1196 Add displayName to auth response and configurable display name claim for OIDC
Some checks failed
CI / build (push) Successful in 1m11s
CI / docker (push) Successful in 49s
CI / deploy (push) Failing after 2m9s
- Add displayName field to AuthTokenResponse so the UI shows human-readable
  names instead of internal JWT subjects (e.g. user:oidc:<hash>)
- Add displayNameClaim to OIDC config (default: "name") allowing admins to
  configure which ID token claim contains the user's display name
- Support dot-separated claim paths (e.g. profile.display_name) like rolesClaim
- Add admin UI field for Display Name Claim on the OIDC config page
- ClickHouse migration: ALTER TABLE adds display_name_claim column

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:09:24 +01:00
hsiegeln
6676e209c7 Fix OIDC login immediate logout — rename JWT subject prefix ui: → user:
All checks were successful
CI / build (push) Successful in 1m12s
CI / docker (push) Successful in 41s
CI / deploy (push) Successful in 30s
OIDC tokens had subject "oidc:<sub>" which didn't match the "ui:" prefix
check in JwtAuthenticationFilter, causing every post-login API call to
return 401 and trigger automatic logout. Renamed the prefix from "ui:"
to "user:" across all auth code for clarity (it covers both browser and
API clients, not just UI).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:55:10 +01:00
hsiegeln
465f210aee Contract-first API with DTOs, validation, and server-side OpenAPI post-processing
All checks were successful
CI / build (push) Successful in 1m27s
CI / docker (push) Successful in 2m6s
CI / deploy (push) Successful in 30s
Add dedicated request/response DTOs for all controllers, replacing raw
JsonNode parameters with validated types. Move OpenAPI path-prefix stripping
and ProcessorNode children injection into OpenApiCustomizer beans so the
spec served at /api/v1/api-docs is already clean — eliminating the need for
the ui/scripts/process-openapi.mjs post-processing script.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:33:37 +01:00
hsiegeln
50bb22d6f6 Add OIDC logout, fix OpenAPI schema types, expose end_session_endpoint
All checks were successful
CI / build (push) Successful in 1m8s
CI / docker (push) Successful in 51s
CI / deploy (push) Successful in 29s
Backend:
- Expose end_session_endpoint from OIDC provider metadata in /auth/oidc/config
- Add getEndSessionEndpoint() to OidcTokenExchanger

Frontend:
- On OIDC logout, redirect to provider's end_session_endpoint to clear SSO session
- Strip /api/v1 prefix from OpenAPI paths to match client baseUrl convention
- Add schema-types.ts with convenience type re-exports from generated schema
- Fix all type imports to use schema-types instead of raw generated schema
- Fix optional field access (processors, children, duration) with proper typing
- Fix AgentInstance.state → status field name

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:43:18 +01:00
hsiegeln
0d82304cf0 Fix SPA forward for /oidc/callback and /admin/* routes
Some checks failed
CI / build (push) Failing after 47s
CI / docker (push) Has been skipped
CI / deploy (push) Has been skipped
The SPA catch-all was missing these paths, causing 404 when Authentik
redirected back to /oidc/callback after authentication.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:33:14 +01:00
hsiegeln
84f4c505a2 Add OIDC login flow to UI and fix dark mode datetime picker icons
All checks were successful
CI / build (push) Successful in 1m16s
CI / docker (push) Successful in 50s
CI / deploy (push) Successful in 31s
- Add "Sign in with SSO" button on login page (shown when OIDC is configured)
- Add /oidc/callback route to exchange authorization code for JWT tokens
- Add loginWithOidcCode action to auth store
- Treat issuer URI as complete discovery URL (no auto-append of .well-known)
- Update admin page placeholder to show full discovery URL format
- Fix datetime picker calendar icon visibility in dark mode (color-scheme)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:19:06 +01:00
hsiegeln
b024f83c26 Add ALTER TABLE migration for auto_signup column on existing ClickHouse
All checks were successful
CI / build (push) Successful in 1m14s
CI / docker (push) Successful in 43s
CI / deploy (push) Successful in 31s
The CREATE TABLE IF NOT EXISTS won't add new columns to an existing table.
Add 05-oidc-auto-signup.sql with ALTER TABLE ADD COLUMN IF NOT EXISTS and
register it in ClickHouseConfig startup schema + test init.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:01:45 +01:00
hsiegeln
0c47ac9b1a Add OIDC admin config page with auto-signup toggle
Some checks failed
CI / build (push) Successful in 1m12s
CI / docker (push) Successful in 50s
CI / deploy (push) Failing after 2m10s
Backend: add autoSignup field to OidcConfig, ClickHouse schema, repository,
and admin controller. Gate OIDC login when auto-signup is disabled and user
is not pre-created (returns 403).

Frontend: add OIDC admin page with full CRUD (save/test/delete), role-gated
Admin nav link parsed from JWT, and matching design system styles.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 13:56:02 +01:00
hsiegeln
9d2e6f30a7 Move OIDC config from env vars to database with admin API
All checks were successful
CI / build (push) Successful in 1m9s
CI / docker (push) Successful in 41s
CI / deploy (push) Successful in 2m11s
OIDC provider settings (issuer, client ID/secret, roles claim) are
now stored in ClickHouse and managed via admin REST API at
/api/v1/admin/oidc. This allows runtime configuration from the UI
without server restarts.

- New oidc_config table (ReplacingMergeTree, singleton row)
- OidcConfig record + OidcConfigRepository interface in core
- ClickHouseOidcConfigRepository implementation
- OidcConfigAdminController: GET/PUT/DELETE config, POST test
  connectivity, client_secret masked in responses
- OidcTokenExchanger: reads config from DB, invalidateCache()
  on config change
- OidcAuthController: always registered (no @ConditionalOnProperty),
  returns 404 when OIDC not configured
- Startup seeder: env vars seed DB on first boot only, then admin
  API takes over
- HOWTO.md updated with admin OIDC config API examples

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 13:01:05 +01:00
hsiegeln
a4de2a7b79 Add RBAC with role-based endpoint authorization and OIDC support
Some checks failed
CI / build (push) Successful in 1m19s
CI / docker (push) Successful in 1m38s
CI / deploy (push) Has been cancelled
Implement three-phase security upgrade:

Phase 1 - RBAC: Extend JWT with roles claim, populate Spring
GrantedAuthority in filter, enforce role-based access (AGENT for
data/heartbeat/SSE, VIEWER+ for search/diagrams, OPERATOR+ for
commands, ADMIN for user management). Configurable JWT secret via
CAMELEER_JWT_SECRET env var for token persistence across restarts.

Phase 2 - User persistence: ClickHouse users table with
ReplacingMergeTree, UserRepository interface + ClickHouse impl,
UserAdminController for CRUD at /api/v1/admin/users. Local login
upserts user on each authentication.

Phase 3 - OIDC: Token exchange flow where SPA sends auth code,
server exchanges it server-side (keeping client_secret secure),
validates id_token via JWKS, resolves roles (DB override > OIDC
claim > default), issues internal JWT. Conditional on
CAMELEER_OIDC_ENABLED=true. Uses oauth2-oidc-sdk for standards
compliance.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:35:45 +01:00
hsiegeln
cb600be1f1 Fix nan-to-int64 crash when avg/quantile runs on empty result set
All checks were successful
CI / build (push) Successful in 1m9s
CI / docker (push) Successful in 39s
CI / deploy (push) Successful in 29s
ClickHouse avg() and quantile() return nan/inf on zero rows, which
toInt64() cannot convert. Wrap with ifNotFinite(..., 0) to default to
zero. Applied to both stats and timeseries queries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 09:37:19 +01:00
hsiegeln
3641dffecc Add comparison stats: failure rate %, vs-yesterday change, today total
All checks were successful
CI / build (push) Successful in 1m11s
CI / docker (push) Successful in 48s
CI / deploy (push) Successful in 37s
Stats endpoint now returns current + previous period (24h shift) values
plus today's total count. UI shows:
- Total Matches: "of 12.3K today"
- Avg Duration: arrow + % vs yesterday
- Failure Rate: percentage of errors vs total, arrow + % vs yesterday
- P99 Latency: arrow + % vs yesterday
- In-Flight: unchanged (running executions)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 09:29:14 +01:00
hsiegeln
393d19e3f4 Move failed count and avg duration from page-derived to backend stats
Some checks failed
CI / build (push) Successful in 1m11s
CI / deploy (push) Has been cancelled
CI / docker (push) Has been cancelled
All stat card values now come from the /search/stats endpoint which
queries the full time window, not just the current page of results.
Consolidated into a single ClickHouse query for efficiency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 22:51:43 +01:00
hsiegeln
4cdf2ac012 Fix ClickHouse OOM on batch insert: reduce batch size, increase memory
All checks were successful
CI / build (push) Successful in 1m3s
CI / docker (push) Successful in 41s
CI / deploy (push) Successful in 46s
Execution rows are wide (29 cols with serialized arrays/JSON), so 500
rows can exceed ClickHouse's memory limit. Reduce default batch size
from 500 to 100 and bump ClickHouse memory limit from 2Gi to 4Gi.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 22:44:03 +01:00
hsiegeln
f156a2aab0 Fix quantile overflow: wrap p99 query with toInt64() for JDBC compat
Some checks failed
CI / build (push) Successful in 1m11s
CI / docker (push) Has been cancelled
CI / deploy (push) Has been cancelled
quantile(0.99) returns Float64 which ClickHouse JDBC cannot cast to
Long directly. Same toInt64() pattern already used in timeseries query.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 22:42:52 +01:00
hsiegeln
cdf4c93630 Make stats endpoint respect selected time window instead of hardcoded last hour
All checks were successful
CI / build (push) Successful in 1m10s
CI / docker (push) Successful in 48s
CI / deploy (push) Successful in 28s
P99 latency and active count now use the same from/to parameters as the
timeseries sparklines, so all stat cards are consistent with the user's
selected time range.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 22:19:59 +01:00
hsiegeln
d1940b98e5 Fix timeseries query: use epoch-based bucketing for DateTime64 compatibility
All checks were successful
CI / build (push) Successful in 1m1s
CI / docker (push) Successful in 41s
CI / deploy (push) Successful in 29s
Replace toStartOfInterval with intDiv on epoch seconds, and cast
avg/quantile results to Int64 to avoid Float64 JDBC mapping issues.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 18:33:14 +01:00
hsiegeln
9e6e1b350a Add stat card sparkline graphs with timeseries backend endpoint
All checks were successful
CI / build (push) Successful in 1m0s
CI / docker (push) Successful in 45s
CI / deploy (push) Successful in 23s
New /search/stats/timeseries endpoint returns bucketed counts/metrics
over a time window using ClickHouse toStartOfInterval(). Frontend
Sparkline component renders SVG polyline + gradient fill on each
stat card, driven by a useStatsTimeseries query hook.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 18:20:08 +01:00
hsiegeln
4253751ef1 Redirect to login on expired/invalid auth
All checks were successful
CI / build (push) Successful in 1m1s
CI / docker (push) Successful in 46s
CI / deploy (push) Successful in 29s
Backend now returns 401 instead of 403 for unauthenticated requests
via HttpStatusEntryPoint. UI middleware handles both 401 and 403,
triggering token refresh and redirecting to /login on failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 17:39:29 +01:00
hsiegeln
3f98467ba5 Fix status filter OR logic and add P99/active stats endpoint
All checks were successful
CI / build (push) Successful in 1m1s
CI / docker (push) Successful in 47s
CI / deploy (push) Successful in 29s
Status filter now parses comma-separated values into SQL IN clause
instead of exact match, so filtering by multiple statuses works.

Added GET /api/v1/search/stats returning P99 latency (last hour) and
active execution count, wired into the UI stat cards with 10s polling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 17:34:11 +01:00
hsiegeln
86e016874a Fix command palette: agent ID propagation, result selection, and scope tabs
All checks were successful
CI / build (push) Successful in 59s
CI / docker (push) Successful in 46s
CI / deploy (push) Successful in 25s
- Propagate authenticated agent identity through write buffers via
  TaggedExecution/TaggedDiagram wrappers so ClickHouse rows get real
  agent IDs instead of empty strings
- Add execution_id to text search LIKE clause so selecting an execution
  by ID in the palette actually finds it
- Clear status filter to all three statuses on palette selection so the
  chosen execution/agent isn't filtered out
- Add disabled Routes and Exchanges scope tabs with "coming soon" state

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 17:13:14 +01:00
hsiegeln
64b03a4e2f Add Cmd+K command palette for searching executions and agents
All checks were successful
CI / build (push) Successful in 59s
CI / docker (push) Successful in 56s
CI / deploy (push) Successful in 26s
Backend: add routeId, agentId, processorType filter fields to SearchRequest
and ClickHouseSearchEngine. Expand global text search to match route_id and
agent_id columns.

Frontend: new command palette component (portal overlay, Zustand store,
TanStack Query search hook with 300ms debounce, filter chip parsing,
keyboard navigation, scope tabs). Search bar in SearchFilters and TopNav
now open the palette. Selecting a result writes filters to the execution
search store to drive the results table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 16:28:16 +01:00
hsiegeln
3eb83f97d3 Add React UI with Execution Explorer, auth, and standalone deployment
Some checks failed
CI / build (push) Failing after 1m53s
CI / docker (push) Has been skipped
CI / deploy (push) Has been skipped
- Scaffold Vite + React + TypeScript frontend in ui/ with full design
  system (dark/light themes) matching the HTML mockups
- Implement Execution Explorer page: search filters, results table with
  expandable processor tree and exchange detail sidebar, pagination
- Add UI authentication: UiAuthController (login/refresh endpoints),
  JWT filter handles ui: subject prefix, CORS configuration
- Shared components: StatusPill, DurationBar, StatCard, AppBadge,
  FilterChip, Pagination — all using CSS Modules with design tokens
- API client layer: openapi-fetch with auth middleware, TanStack Query
  hooks for search/detail/snapshot queries, Zustand for state
- Standalone deployment: Nginx Dockerfile, K8s Deployment + ConfigMap +
  NodePort (30080), runtime config.js for API base URL
- Embedded mode: maven-resources-plugin copies ui/dist into JAR static
  resources, SPA forward controller for client-side routing
- CI/CD: UI build step, Docker build/push for server-ui image, K8s
  deploy step for UI, UI credential secrets

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 13:59:22 +01:00
hsiegeln
88da1a0dd8 Fix ClickHouse OOM during Proxmox nightly backups
All checks were successful
CI / build (push) Successful in 48s
CI / docker (push) Successful in 1m36s
CI / deploy (push) Successful in 20s
Increase ClickHouse memory limit from 1Gi to 2Gi and reduce default
batch size from 5000 to 500. During VM backup snapshots, I/O contention
prevents ClickHouse from flushing writes fast enough, causing buffer
accumulation that exceeds the 1Gi container limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:55:46 +01:00
hsiegeln
a44a0c970b Revert to JdbcTemplate for schema init, keep comment-stripping fix
All checks were successful
CI / build (push) Successful in 48s
CI / docker (push) Successful in 36s
CI / deploy (push) Successful in 9s
The DriverManager-based approach likely failed because the ClickHouse
JDBC driver wasn't registered with DriverManager. The original
JdbcTemplate approach worked for route_diagrams and agent_metrics —
only route_executions was skipped due to the comment-parsing bug.

Reverts to simple JdbcTemplate-based init with unqualified table names
(DataSource targets cameleer3 database). The CLICKHOUSE_DB env var on
the ClickHouse container handles database creation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:05:12 +01:00
hsiegeln
a2cbd115ee Fix SQL parser skipping statements that follow comment lines
All checks were successful
CI / build (push) Successful in 47s
CI / docker (push) Successful in 41s
CI / deploy (push) Successful in 10s
split(';') produced chunks starting with '--' comment lines, causing
the startsWith('--') check to skip the entire CREATE TABLE statement
for route_executions. Now strips comment lines before splitting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 21:55:36 +01:00
hsiegeln
ce0eb58b0c Fix schema init: bypass DataSource, use direct JDBC with qualified table names
All checks were successful
CI / build (push) Successful in 48s
CI / docker (push) Successful in 40s
CI / deploy (push) Successful in 7s
The auto-configured DataSource targets jdbc:ch://.../cameleer3 which fails
if the database doesn't exist yet. Schema init now uses a direct JDBC
connection to the root URL, creates the database first, then applies all
schema SQL with fully qualified cameleer3.* table names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 21:50:47 +01:00
hsiegeln
48bdb46760 Server fully owns ClickHouse schema — create database + tables on startup
All checks were successful
CI / build (push) Successful in 48s
CI / docker (push) Successful in 39s
CI / deploy (push) Successful in 9s
ClickHouseConfig.ensureDatabaseExists() connects without the database path
to run CREATE DATABASE IF NOT EXISTS before the main DataSource is used.
Removes the ConfigMap-based init scripts from the K8s manifest — the server
is now the single owner of all ClickHouse schema management.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 21:41:35 +01:00
hsiegeln
9dffa9ea81 Move schema initialization from ClickHouse init scripts to server startup
All checks were successful
CI / build (push) Successful in 49s
CI / docker (push) Successful in 43s
CI / deploy (push) Successful in 15s
Server now applies schema via @PostConstruct using classpath SQL files.
All statements use IF NOT EXISTS/IF NOT EXISTS so it's idempotent and
safe to run on every startup. Removes ConfigMap and init script mount
from K8s manifest since ClickHouse no longer needs to manage the schema.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 19:59:33 +01:00
hsiegeln
539b85f307 test(04-02): adapt all ITs for JWT auth and add 4 security integration tests
- Replace TestSecurityConfig permit-all with real SecurityConfig active in tests
- Create TestSecurityHelper for JWT-authenticated test requests
- Update 15 existing ITs to use JWT Bearer auth and bootstrap token headers
- Add SecurityFilterIT: protected/public endpoint access control (6 tests)
- Add BootstrapTokenIT: registration requires valid bootstrap token (4 tests)
- Add RegistrationSecurityIT: registration returns tokens + public key (3 tests)
- Add JwtRefreshIT: refresh flow with valid/invalid/mismatched tokens (5 tests)
- Add /error to SecurityConfig permitAll for proper error page forwarding
- Exclude register and refresh paths from ProtocolVersionInterceptor
- All 91 tests pass (18 new security + 73 existing)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:38:28 +01:00
hsiegeln
0215fd96ae feat(04-03): implement SSE payload signing with Ed25519
- SsePayloadSigner signs JSON payloads and adds signature field before SSE delivery
- SseConnectionManager signs all command payloads via SsePayloadSigner before sendEvent
- Signed payload parsed to JsonNode for correct SseEmitter serialization
- Integration tests use bootstrap token + JWT auth (adapts to Plan 02 security layer)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:29:54 +01:00
hsiegeln
387e2e66b2 feat(04-02): wire Spring Security filter chain with JWT auth, bootstrap registration, and refresh endpoint
- JwtAuthenticationFilter extracts JWT from Authorization header or query param, validates via JwtService
- SecurityConfig creates stateless SecurityFilterChain with public/protected endpoint split
- AgentRegistrationController requires bootstrap token, returns accessToken + refreshToken + serverPublicKey
- New POST /agents/{id}/refresh endpoint issues new access JWT from valid refresh token

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:13:53 +01:00
hsiegeln
b3b4e62d34 test(04-03): add failing tests for SSE payload signing
- SsePayloadSignerTest: 7 unit tests for sign/verify roundtrip and edge cases
- SseSigningIT: 2 integration tests for end-to-end SSE signature verification

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:13:44 +01:00
hsiegeln
ac9e8ae4dd feat(04-01): implement security service foundation
- JwtServiceImpl: HMAC-SHA256 via Nimbus JOSE+JWT with ephemeral 256-bit secret
- Ed25519SigningServiceImpl: JDK 17 KeyPairGenerator with ephemeral keypair
- BootstrapTokenValidator: constant-time comparison with dual-token rotation
- SecurityBeanConfig: bean wiring with fail-fast validation for CAMELEER_AUTH_TOKEN
- SecurityProperties: config binding for token expiry and bootstrap tokens
- TestSecurityConfig: permit-all filter chain to keep existing tests green
- application.yml: security config with env var mapping
- All 18 security unit tests pass, all 71 tests pass in full verify

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:08:30 +01:00
hsiegeln
51a02700dd test(04-01): add failing tests for security services
- JwtService: 7 tests for access/refresh token creation and validation
- Ed25519SigningService: 5 tests for keypair, signing, verification
- BootstrapTokenValidator: 6 tests for token matching and rotation
- Core interfaces and stub implementations (all throw UnsupportedOperationException)
- Added nimbus-jose-jwt and spring-boot-starter-security dependencies

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 19:58:59 +01:00
hsiegeln
a1909baad6 test(03-02): integration tests for SSE and command endpoints
- AgentSseControllerIT: connect, 404 unknown, config-update/deep-trace/replay delivery, ping keepalive, Last-Event-ID
- AgentCommandControllerIT: single/group/broadcast commands, ack, ack-unknown, command-to-unregistered
- Test config with 1s ping interval for faster SSE keepalive testing
- All 71 tests pass with mvn clean verify

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 19:16:25 +01:00
hsiegeln
5746886a0b feat(03-02): SSE connection manager, SSE endpoint, and command controller
- SseConnectionManager with per-agent SseEmitter, ping keepalive, event delivery
- AgentSseController GET /{id}/events SSE endpoint with Last-Event-ID support
- AgentCommandController with single/group/broadcast command targeting + ack
- WebConfig excludes SSE events path from protocol version interceptor

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 18:45:47 +01:00
hsiegeln
0372be2334 feat(03-01): add agent registration controller, config, lifecycle monitor
- AgentRegistryConfig: heartbeat, stale, dead, ping, command expiry settings
- AgentRegistryBeanConfig: wires AgentRegistryService as Spring bean
- AgentLifecycleMonitor: @Scheduled lifecycle check + command expiry sweep
- AgentRegistrationController: POST /register, POST /{id}/heartbeat, GET /agents
- Updated Cameleer3ServerApplication with AgentRegistryConfig
- Updated application.yml with agent-registry section and async timeout
- 7 integration tests: register, re-register, heartbeat, list, filter, invalid status

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 18:40:57 +01:00
hsiegeln
34c831040a feat(02-04): populate diagram_content_hash during ingestion and fix test stability
- Inject DiagramRepository into ClickHouseExecutionRepository for hash lookup
- Replace empty string placeholder with actual SHA-256 diagram hash in insertBatch
- Add Surefire/Failsafe forkCount=1 reuseForks=false for classloader isolation
- Add failsafe-plugin integration-test/verify goals for IT execution
- Create DiagramLinkingIT with positive (hash populated) and negative (empty fallback) cases
- Fix flaky awaitility assertions with ignoreExceptions for EmptyResultDataAccess
- Increase IngestionSchemaIT timeouts to 30s for reliable batch flush waits
- Adjust SearchControllerIT pagination assertion to match correct seed data count

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 17:36:33 +01:00
hsiegeln
ea9d81213f test(02-04): add failing DiagramLinkingIT for diagram hash linking
- Test 1: diagram_content_hash populated with SHA-256 when RouteGraph exists
- Test 2: diagram_content_hash empty when no RouteGraph exists for route

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:51:34 +01:00
hsiegeln
079dce5daf fix(02-03): make search tests resilient to shared ClickHouse data
- Use correlationId scoping and >= assertions for status/duration tests
- Prevents false failures when other test classes seed data in same container

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:32:50 +01:00
hsiegeln
0615a9851d feat(02-03): detail controller, tree reconstruction, processor snapshot endpoint
- Implement findRawById and findProcessorSnapshot in ClickHouseExecutionRepository
- DetailController with GET /executions/{id} returning nested processor tree
- GET /executions/{id}/processors/{index}/snapshot for per-processor exchange data
- 5 unit tests for tree reconstruction (linear, branching, multiple roots, empty)
- 6 integration tests for detail endpoint, snapshot, and 404 handling
- Added assertj and mockito test dependencies to core module

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:29:53 +01:00
hsiegeln
82a190c8e2 feat(02-03): ClickHouse search engine, search controller, and 13 integration tests
- ClickHouseSearchEngine with dynamic WHERE clause building and LIKE escape
- SearchController with GET (basic filters) and POST (advanced JSON body)
- SearchBeanConfig wiring SearchEngine, SearchService, DetailService beans
- 13 integration tests covering all filter types, combinations, pagination, empty results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:23:20 +01:00
hsiegeln
c1bc32d50a feat(02-02): implement ELK diagram renderer with SVG/JSON content negotiation
- ElkDiagramRenderer: ELK layered layout (top-to-bottom) with JFreeSVG rendering
- Color-coded nodes: blue endpoints, green processors, red errors, purple EIPs, cyan cross-route
- Compound node support for CHOICE/SPLIT/TRY_CATCH swimlane groups
- DiagramRenderController: GET /api/v1/diagrams/{hash}/render with Accept header negotiation
- DiagramBeanConfig for Spring wiring
- 11 unit tests (layout, SVG structure, colors, compound nodes)
- 4 integration tests (SVG, JSON, 404, default format)
- Added xtext xbase lib dependency for ELK compatibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:17:13 +01:00
hsiegeln
f6ff279a60 feat(02-01): extend ingestion to populate Phase 2 columns with integration tests
- Refactored flattenProcessors to flattenWithMetadata (FlatProcessor record with depth/parentIndex)
- INSERT now populates 12 new columns: exchange_bodies, exchange_headers, processor_depths,
  processor_parent_indexes, processor_error_messages, processor_error_stacktraces,
  processor_input_bodies, processor_output_bodies, processor_input_headers,
  processor_output_headers, processor_diagram_node_ids, diagram_content_hash
- Exchange bodies/headers concatenated from all processor snapshots + route-level snapshots
- Null ExchangeSnapshot handled gracefully (empty string defaults)
- Headers serialized to JSON via Jackson ObjectMapper
- IngestionSchemaIT verifies 3-level tree metadata, body concatenation, null snapshot handling
- DiagramRenderer/DiagramLayout stubs created to fix pre-existing compilation error (Rule 3)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:15:41 +01:00
hsiegeln
c0922430c4 test(02-01): add failing IngestionSchemaIT for new column population
- Tests processor tree metadata (depths, parent indexes)
- Tests exchange body concatenation for search
- Tests null snapshot graceful handling
- AbstractClickHouseIT loads 02-search-columns.sql
- DiagramRenderer/DiagramLayout stubs to fix pre-existing compilation error

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:09:45 +01:00