Skip to content
Merged

140 #52

Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1709dc8
feat(checkmk): add Checkmk monitoring integration with Livestatus events
alvagante Jun 1, 2026
344e092
feat(monitoring): enhance Checkmk integration with effective attribut…
alvagante Jun 2, 2026
527371d
fix: checkmk fixes
alvagante Jun 2, 2026
df89d58
fix(checkmk): resolve TypeScript type casting in Facts object
alvagante Jun 2, 2026
cab1c53
fix(parallel-execution): handle Ansible package action format correctly
alvagante Jun 3, 2026
e0ab793
feat(monitoring): add home page dashboard integration with unhandled …
alvagante Jun 3, 2026
513f295
feat(monitoring): add acknowledged flag to Checkmk service problems a…
alvagante Jun 3, 2026
3b4bd58
feat(node-detail): add Checkmk monitoring summary to overview tab
alvagante Jun 3, 2026
04ccb52
feat(monitoring): add per-host service state summary to overview endp…
alvagante Jun 4, 2026
3dff7d1
feat(monitoring): add dedicated monitor page for service problems and…
alvagante Jun 4, 2026
efcd25f
feat(monitoring): add auto-refresh and manual refresh controls to mon…
alvagante Jun 4, 2026
1562448
feat(ansible): playbook browser with parameter detection
alvagante Jun 5, 2026
401679f
feat(monitoring,ansible): add playbook browser, dedicated monitor pag…
alvagante Jun 5, 2026
82e62b0
feat(multi): crash dumps page, host state summary, puppet confdir
alvagante Jun 5, 2026
92b6f35
feat(logging): add in-memory log buffer and admin logs API
alvagante Jun 5, 2026
38f9d9e
refactor(integrations): remove unconfigured integration reporting fro…
alvagante Jun 5, 2026
969786e
refactor(monitoring): add ServiceState type for Checkmk service states
alvagante Jun 5, 2026
de7ffd8
chore(pre-commit): update TypeScript check hook configuration
alvagante Jun 5, 2026
5ea2610
test(ansible): enhance ExecutePlaybookForm test coverage and fix manu…
alvagante Jun 5, 2026
66a3598
chore(pre-commit): add unit test hooks for backend and frontend
alvagante Jun 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .env.docker
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,16 @@ PROXMOX_ENABLED=false
# PROXMOX_TIMEOUT=30000
# PROXMOX_PRIORITY=7

# -----------------------------------------------------------------------------
# Checkmk integration
# -----------------------------------------------------------------------------
CHECKMK_ENABLED=false
# CHECKMK_SERVER_URL=https://checkmk.example.com
# CHECKMK_SITE=mysite
# CHECKMK_USERNAME=automation
# CHECKMK_PASSWORD= # pragma: allowlist secret
# CHECKMK_SSL_VERIFY=true

# -----------------------------------------------------------------------------
# AWS integration
# -----------------------------------------------------------------------------
Expand All @@ -166,6 +176,17 @@ AWS_ENABLED=false
# AWS_PROFILE=default
# AWS_ENDPOINT=

# -----------------------------------------------------------------------------
# MCP (Model Context Protocol) Server
# -----------------------------------------------------------------------------
# Enables the embedded MCP server at /mcp on the same port as the API.
# MCP_ENABLED=true

# Static bearer token for MCP client authentication (recommended).
# Generate with: openssl rand -hex 32
# If unset, MCP clients must use a valid JWT from /api/auth/login.
# MCP_AUTH_TOKEN= # pragma: allowlist secret

# -----------------------------------------------------------------------------
# Streaming, Cache, and Queue (advanced — defaults are usually fine)
# -----------------------------------------------------------------------------
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ dist/
build/
backend/public/

# Crash dumps
backend/crash-dumps/

# Environment variables
.env
.env.local
Expand Down
1 change: 1 addition & 0 deletions .kiro/specs/checkmk-integration/.config.kiro
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"specId": "b403e1a5-6b85-4922-8539-9e40aaf3d380", "workflowType": "requirements-first", "specType": "feature"}
689 changes: 689 additions & 0 deletions .kiro/specs/checkmk-integration/design.md

Large diffs are not rendered by default.

233 changes: 233 additions & 0 deletions .kiro/specs/checkmk-integration/requirements.md

Large diffs are not rendered by default.

231 changes: 231 additions & 0 deletions .kiro/specs/checkmk-integration/tasks.md

Large diffs are not rendered by default.

78 changes: 75 additions & 3 deletions .kirograph/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,82 @@
"minLogLevel": "warn",
"frameworkHints": [
"express",
"svelte"
"svelte",
"docker-compose"
],
"fuzzyResolutionThreshold": 0.5,
"enableArchitecture": true,
"cavemanMode": "off",
"syncWarningThreshold": 10
}
"shellCompressionLevel": "normal",
"syncWarningThreshold": 10,
"enableMemory": true,
"memorySearchAlpha": 0.5,
"memoryKeepRaw": false,
"memoryMaxObservations": 10000,
"memorySessionTimeout": 7200,
"memoryContextLimit": 3,
"memoryContextThreshold": 0.3,
"memoryExcludePatterns": [],
"enableDocs": true,
"docsInclude": [
"**/*.md",
"**/*.mdx",
"**/*.rst",
"**/*.adoc",
"**/*.asciidoc",
"**/*.rdoc",
"**/*.org",
"**/*.cheatmd",
"docs/**/*.txt",
"docs/**/*.html"
],
"docsExclude": [
"node_modules/**",
"**/CHANGELOG*",
"**/LICENSE*",
"**/CHANGES*",
"dist/**",
"build/**",
"coverage/**",
".git/**",
"**/generated/**",
"**/auto-generated/**",
"**/vendor/**",
"_build/**"
],
"docsLinkCode": true,
"docsContextLimit": 0,
"docsContextThreshold": 0.3,
"docsMaxFileSize": 1048576,
"docsSummarization": "first-sentence",
"enableData": true,
"dataInclude": [
"**/*.csv",
"**/*.tsv",
"**/*.jsonl",
"**/*.ndjson",
"**/*.xlsx",
"**/*.xls",
"**/*.parquet",
"data/**/*.json"
],
"dataExclude": [
"node_modules/**",
"dist/**",
"build/**",
".git/**",
"**/package-lock.json",
"**/yarn.lock",
"**/pnpm-lock.yaml",
"**/tsconfig.json",
"**/jsconfig.json",
"coverage/**",
"**/generated/**"
],
"dataLinkCode": true,
"dataContextLimit": 0,
"dataMaxFileSize": 52428800,
"dataMaxRows": 1000000,
"dataQueryLimit": 500,
"dataMaxResponseTokens": 8000
}
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ The plugin registry (`plugins/registry.ts`) is a declarative array of `PluginReg
- **`plugins/`** — `registry.ts` declares all integration plugins as a `PluginRegistryEntry[]` array with `resolveConfig()` and `create()` per entry
- **`config/`** — `ConfigService` wraps all env vars with Zod validation; always use this, never `process.env` directly. Secrets: `JWT_SECRET` (required), `PABAWI_LIFECYCLE_TOKEN` (optional, defaults to empty) <!-- pragma: allowlist secret -->
- **`integrations/<name>/`** — One directory per integration: `<Name>Plugin.ts` (lifecycle + routing) and `<Name>Service.ts` (business logic, CLI spawning, API calls)
- **`mcp/`** — MCP (Model Context Protocol) server: read-only infrastructure query interface for LLM clients. `McpServer.ts` (factory + RBAC gates), `McpToolHandlers.ts` (8 tools: `inventory_list`, `facts_get`, `reports_query`, `catalogs_get`, `hiera_lookup`, `executions_list`, `integrations_list`, `journal_query`), `McpOutputSummariser.ts` (strips verbose fields for LLM-friendly output), `McpServiceUser.ts` (idempotent provisioning of the `mcp-service` user). Enabled via `MCP_ENABLED=true`; session-based HTTP transport at `POST/GET/DELETE /mcp`.
- **`mcp/`** — MCP (Model Context Protocol) server: read-only infrastructure query interface for LLM clients. `McpServer.ts` (factory + RBAC gates), `McpToolHandlers.ts` (11 tools: `inventory_list`, `facts_get`, `facts_bulk`, `reports_query`, `catalogs_get`, `hiera_lookup`, `executions_list`, `integrations_list`, `journal_query`, `monitoring_services_get`, `monitoring_events_get`), `McpOutputSummariser.ts` (strips verbose fields for LLM-friendly output), `McpServiceUser.ts` (idempotent provisioning of the `mcp-service` user). Enabled via `MCP_ENABLED=true`; session-based HTTP transport at `POST/GET/DELETE /mcp`.
- **`services/`** — Cross-cutting services: `ExecutionQueue` (concurrent limiting, FIFO), `StreamingExecutionManager` (SSE real-time output), `CommandWhitelistService` (security), `DatabaseService`, `AuthenticationService`, `BatchExecutionService`, `JournalService` (audit trail of infrastructure events), `AuditLoggingService` (user-action audit log), `PuppetRunHistoryService` (persists Puppet run history), `NodeLinkingService` (correlates the same node across integration sources), `ExpertModeService` (debug/verbose UI toggle), and RBAC services (`UserService`, `RoleService`, `PermissionService`, `GroupService`)
- **`routes/`** — Express route factories. All export `createXxxRouter(container)` functions. All async handlers wrapped with `asyncHandler()` from `utils/`
- **`middleware/`** — Auth (JWT), RBAC, error handler, rate limiting, security headers, `deduplication.ts` (request deduplication)
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## [1.4.0] - Unreleased

### Added

- **Checkmk monitoring integration.** Connects to the Checkmk REST API v1 to provide live monitoring data: host inventory discovery, service status, and state-change events. All data is fetched live (no caching).
- **Monitor tab** on the node detail page displaying live service status from Checkmk, grouped by state (CRIT → WARN → UNKNOWN → OK) with colored badges, plugin output, and relative timestamps.
- **Journal integration** for Checkmk state-change events — monitoring events appear in the node journal timeline alongside events from other sources.
- `GET /api/nodes/:nodeId/services` endpoint returning live service monitoring data.
- `GET /api/nodes/:nodeId/monitoring-events` endpoint returning state-change events with configurable limit.
- `CHECKMK_ENABLED`, `CHECKMK_SERVER_URL`, `CHECKMK_SITE`, `CHECKMK_USERNAME`, `CHECKMK_PASSWORD`, `CHECKMK_SSL_VERIFY` environment variables for configuration.
- Checkmk integration documentation at `docs/integrations/checkmk.md`.
- `monitoring:read` RBAC permission for monitoring endpoints.
- Checkmk integration color (purple) in the integration color palette.

## [1.3.1] - 2026-06-01

### Added
Expand Down
39 changes: 39 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Pabawi

Infrastructure management web UI. A monorepo whose backend exposes a unified view over many infrastructure integrations (Bolt, PuppetDB, Puppetserver, Hiera, Ansible, SSH, AWS, Azure, Proxmox, and Checkmk) via a plugin system, and a Svelte SPA frontend.

## Language

### Checkmk integration

**Checkmk_Plugin**:
The Pabawi `InformationSourcePlugin` that reads monitoring data from a Checkmk site.

**Service**:
A single monitored check on a Checkmk host (e.g. "CPU load"), carrying a current **Service_State**.

**Service_State**:
The numeric monitoring state of a **Service**: 0 OK, 1 WARN, 2 CRIT, 3 UNKNOWN.

**State Change Event**:
A transition of a **Service** from one **Service_State** to another at a point in time. In Pabawi this is *not* a Checkmk Event Console event — it is a service state transition.
_Avoid_: "Event" unqualified (collides with Checkmk's Event Console, which is a different, log/trap-based concept this integration does not use).

**REST source**:
The Checkmk REST API v1 (`{serverUrl}/{site}/check_mk/api/1.0`, Bearer-authed over HTTPS). Source of host inventory and live **Service** status. Can also yield the *single most recent* **State Change Event** per service via the `last_state`/`state`/`last_state_change` columns.

**Livestatus source**:
The Checkmk Livestatus `log` table reached over TCP (default 6557). Source of *full* **State Change Event** history (multiple events per service over a time window). Optional and secondary to the **REST source**.

**Monitor_Tab**:
The node-detail-page tab that displays live **Service** status grouped by **Service_State**.

## Relationships

- A **Checkmk_Plugin** discovers hosts and live **Service** status from the **REST source**.
- **State Change Events** come from the **Livestatus source** when it is configured and reachable; otherwise the **Checkmk_Plugin** falls back to the **REST source**'s last-transition-per-service.
- A Checkmk host links to a Pabawi node by hostname (case-insensitive), via the existing NodeLinkingService.

## Flagged ambiguities

- "Event" was used in the original spec to mean a Checkmk Event Console event, but the data actually wanted is a **service state transition**. Resolved: the integration sources state transitions (REST `last_state`→`state`, or Livestatus `log` class=1 alerts), and does not use the Event Console.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ ARG BUILDPLATFORM
# Add metadata labels
LABEL org.opencontainers.image.title="Pabawi"
LABEL org.opencontainers.image.description="Puppet Ansible Bolt Awesome Web Interface"
LABEL org.opencontainers.image.version="1.3.1"
LABEL org.opencontainers.image.version="1.4.0"
LABEL org.opencontainers.image.vendor="example42"
LABEL org.opencontainers.image.source="https://github.com/example42/pabawi"

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.alpine
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ ARG BUILDPLATFORM
# Add metadata labels
LABEL org.opencontainers.image.title="Pabawi"
LABEL org.opencontainers.image.description="Puppet Ansible Bolt Awesome Web Interface"
LABEL org.opencontainers.image.version="1.3.1"
LABEL org.opencontainers.image.version="1.4.0"
LABEL org.opencontainers.image.vendor="example42"
LABEL org.opencontainers.image.source="https://github.com/example42/pabawi"

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.ubuntu
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ ARG BUILDPLATFORM
# Add metadata labels
LABEL org.opencontainers.image.title="Pabawi"
LABEL org.opencontainers.image.description="Puppet Ansible Bolt Awesome Web Interface"
LABEL org.opencontainers.image.version="1.3.1"
LABEL org.opencontainers.image.version="1.4.0"
LABEL org.opencontainers.image.vendor="example42"
LABEL org.opencontainers.image.source="https://github.com/example42/pabawi"

Expand Down
22 changes: 22 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,28 @@ AWS_ENABLED=false
# Custom endpoint (for LocalStack or other S3-compatible services)
# AWS_ENDPOINT=

# -----------------------------------------------------------------------------
# Checkmk integration (optional)
# -----------------------------------------------------------------------------
CHECKMK_ENABLED=false
# CHECKMK_SERVER_URL=https://checkmk.example.com
# CHECKMK_SITE=mysite
# CHECKMK_USERNAME=automation
# CHECKMK_PASSWORD= # pragma: allowlist secret
# Set to "false" to skip TLS certificate verification (self-signed certs)
# CHECKMK_SSL_VERIFY=true

# -----------------------------------------------------------------------------
# Checkmk integration (optional)
# -----------------------------------------------------------------------------
CHECKMK_ENABLED=false
# CHECKMK_SERVER_URL=https://checkmk.example.com
# CHECKMK_SITE=mysite
# CHECKMK_USERNAME=automation
# CHECKMK_PASSWORD= # pragma: allowlist secret
# Set to "false" to skip TLS certificate verification (self-signed certs)
# CHECKMK_SSL_VERIFY=true
Comment on lines +212 to +221
Comment on lines +201 to +221
Comment on lines +212 to +221

Comment on lines +201 to +222
# -----------------------------------------------------------------------------
# Azure integration (optional)
# -----------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "backend",
"version": "1.3.1",
"version": "1.4.0",
"description": "Backend API server for Pabawi",
"main": "dist/server.js",
"scripts": {
Expand Down
86 changes: 86 additions & 0 deletions backend/src/config/ConfigService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,21 @@ export class ConfigService {
subscriptionId?: string;
resourceGroups?: string[];
};
checkmk?: {
enabled: boolean;
serverUrl: string;
site?: string;
username: string;
password: string; // pragma: allowlist secret
sslVerify: boolean;
healthCheckIntervalMs?: number;
livestatus?: {
host: string;
port?: number;
tls?: boolean;
timeoutMs?: number;
};
};
} {
const integrations: ReturnType<typeof this.parseIntegrationsConfig> = {};

Expand Down Expand Up @@ -534,6 +549,64 @@ export class ConfigService {
};
}

// Parse Checkmk configuration
if (process.env.CHECKMK_ENABLED === "true") {
const serverUrl = process.env.CHECKMK_SERVER_URL;
const site = process.env.CHECKMK_SITE;
const username = process.env.CHECKMK_USERNAME;
const password = process.env.CHECKMK_PASSWORD; // pragma: allowlist secret

const missing: string[] = [];
if (!serverUrl) missing.push("CHECKMK_SERVER_URL");
if (!username) missing.push("CHECKMK_USERNAME");
if (!password) missing.push("CHECKMK_PASSWORD"); // pragma: allowlist secret

if (missing.length > 0) {
console.warn(
`[ConfigService] Checkmk enabled but required variables missing: ${missing.join(", ")}. Plugin will not be registered.`,
);
} else if (serverUrl && username && password) {
const sslVerify = process.env.CHECKMK_SSL_VERIFY !== "false";

const checkmkConfig: NonNullable<typeof integrations.checkmk> = {
enabled: true,
serverUrl,
...(site ? { site } : {}),
username,
password, // pragma: allowlist secret
sslVerify,
healthCheckIntervalMs: process.env.CHECKMK_HEALTHCHECK_INTERVAL_MS
? parseInt(process.env.CHECKMK_HEALTHCHECK_INTERVAL_MS, 10)
: undefined,
};

// Build livestatus sub-object only when CHECKMK_LIVESTATUS_HOST is non-empty
const livestatusHost = process.env.CHECKMK_LIVESTATUS_HOST;
if (livestatusHost) {
const livestatusTls = process.env.CHECKMK_LIVESTATUS_TLS === "true";

if (!livestatusTls) {
console.warn(
"[ConfigService] Checkmk Livestatus enabled without TLS — traffic will be unencrypted.",
);
Comment on lines +564 to +591
}

checkmkConfig.livestatus = {
host: livestatusHost,
port: process.env.CHECKMK_LIVESTATUS_PORT
? parseInt(process.env.CHECKMK_LIVESTATUS_PORT, 10)
: undefined,
tls: livestatusTls,
timeoutMs: process.env.CHECKMK_LIVESTATUS_TIMEOUT_MS
? parseInt(process.env.CHECKMK_LIVESTATUS_TIMEOUT_MS, 10)
: undefined,
};
}

integrations.checkmk = checkmkConfig;
}
}

return integrations;
}

Expand Down Expand Up @@ -886,4 +959,17 @@ export class ConfigService {
}
return null;
}

/**
* Get Checkmk configuration if enabled
*/
public getCheckmkConfig():
| (typeof this.config.integrations.checkmk & { enabled: true })
| null {
const checkmk = this.config.integrations.checkmk;
if (checkmk?.enabled) {
return checkmk as typeof checkmk & { enabled: true };
}
return null;
}
}
Loading
Loading