mirror of
https://github.com/open-webui/oikb.git
synced 2026-07-09 16:00:53 +00:00
0.3.4: validate --deep, fix stale docker-compose.yaml
validate --deep pings Open WebUI API to verify connectivity, API key validity, and that each KB ID exists. Catches config errors before deployment. Also applies defaults and env var interpolation in validate (was missing). docker-compose.yaml updated from stale watch mode to production daemon mode with healthcheck, LOG_FORMAT, and OIKB_API_KEY.
This commit is contained in:
parent
fe3a94961f
commit
597bb6c9d9
7 changed files with 74 additions and 11 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
|
||||
## [0.3.4] - 2025-05-21
|
||||
|
||||
### Added
|
||||
|
||||
- `oikb validate --deep` — verifies Open WebUI connectivity, API key validity, and that each KB ID exists. Catches config errors before deployment.
|
||||
|
||||
### Fixed
|
||||
|
||||
- `docker-compose.yaml` updated from stale `watch` mode to production `daemon` mode with healthcheck, `LOG_FORMAT=json`, and `OIKB_API_KEY` support.
|
||||
- `validate` now applies `defaults:` and env var interpolation to entries before checking (was only doing raw yaml).
|
||||
|
||||
## [0.3.3] - 2025-05-21
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -6,18 +6,25 @@ services:
|
|||
volumes:
|
||||
- open-webui:/app/backend/data
|
||||
|
||||
# One-shot sync on container start, then watch for changes
|
||||
oikb:
|
||||
image: ghcr.io/open-webui/oikb:latest
|
||||
environment:
|
||||
- OPEN_WEBUI_URL=http://open-webui:8080
|
||||
- OPEN_WEBUI_API_KEY=${OPEN_WEBUI_API_KEY}
|
||||
- OIKB_API_KEY=${OIKB_API_KEY}
|
||||
- LOG_FORMAT=json
|
||||
volumes:
|
||||
- ./docs:/data
|
||||
command: watch /data --kb ${KB_ID}
|
||||
- ./.oikb.yaml:/app/.oikb.yaml:ro
|
||||
command: daemon
|
||||
ports:
|
||||
- "8080:8080"
|
||||
depends_on:
|
||||
- open-webui
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health/ready"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
|
||||
volumes:
|
||||
open-webui:
|
||||
|
|
|
|||
|
|
@ -645,6 +645,7 @@ oikb daemon --log-format json JSON logging
|
|||
oikb daemon --config /path/to/yaml Custom config path
|
||||
oikb diff <source> --kb-id ID Preview changes
|
||||
oikb validate Check .oikb.yaml syntax
|
||||
oikb validate --deep Verify API, auth, and KB existence
|
||||
oikb ls --kb-id ID List files in a KB
|
||||
oikb status --kb-id ID Show KB info
|
||||
oikb history View sync history
|
||||
|
|
@ -686,7 +687,8 @@ You're running `oikb sync` without arguments and there's no `.oikb.yaml` in the
|
|||
### Daemon won't start
|
||||
|
||||
```bash
|
||||
oikb validate # Check config syntax first
|
||||
oikb validate # Check config syntax
|
||||
oikb validate --deep # Verify API + KB connectivity
|
||||
```
|
||||
|
||||
### How do I find my KB ID?
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "oikb"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
description = "Sync anything to Open WebUI Knowledge Bases"
|
||||
readme = "README.md"
|
||||
authors = [
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
"""oikb — Open WebUI Knowledge Base CLI."""
|
||||
|
||||
__version__ = "0.3.3"
|
||||
__version__ = "0.3.4"
|
||||
|
|
|
|||
|
|
@ -830,13 +830,23 @@ def init(force: bool):
|
|||
|
||||
@cli.command()
|
||||
@click.option("--config", "config_file", default=None, type=click.Path(), help="Path to .oikb.yaml (default: ./.oikb.yaml).")
|
||||
def validate(config_file: str | None):
|
||||
"""Validate .oikb.yaml without running anything."""
|
||||
@click.option("--deep", is_flag=True, help="Verify connectivity: ping Open WebUI, check API key, confirm each KB exists.")
|
||||
def validate(config_file: str | None, deep: bool):
|
||||
"""Validate .oikb.yaml without running anything.
|
||||
|
||||
By default, checks YAML structure and source syntax.
|
||||
With --deep, also verifies the Open WebUI API is reachable,
|
||||
the API key is valid, and each Knowledge Base ID exists.
|
||||
"""
|
||||
if config_file:
|
||||
import yaml
|
||||
with open(config_file) as f:
|
||||
data = yaml.safe_load(f)
|
||||
data = _interpolate_env(data) if data else data
|
||||
entries = (data.get("sources") or data.get("sync", [])) if data else []
|
||||
defaults = data.get("defaults", {}) if data else {}
|
||||
if defaults and entries:
|
||||
entries = [_deep_merge(defaults, e) for e in entries]
|
||||
else:
|
||||
entries = _load_oikb_yaml()
|
||||
|
||||
|
|
@ -844,6 +854,20 @@ def validate(config_file: str | None):
|
|||
click.echo(click.style("No .oikb.yaml found or file is empty.", fg="red"), err=True)
|
||||
sys.exit(1)
|
||||
|
||||
# Deep validation: create a client and verify connectivity first.
|
||||
client = None
|
||||
if deep:
|
||||
click.echo(click.style("Deep validation\n", bold=True))
|
||||
try:
|
||||
client = _make_client(
|
||||
url=entries[0].get("url"),
|
||||
token=entries[0].get("token"),
|
||||
)
|
||||
click.echo(click.style(" ✓ API reachable", fg="green") + f" {client._http.base_url}")
|
||||
except Exception as e:
|
||||
click.echo(click.style(f" ✗ Cannot reach Open WebUI: {e}", fg="red"))
|
||||
sys.exit(1)
|
||||
|
||||
has_errors = False
|
||||
for i, entry in enumerate(entries, 1):
|
||||
entry_name = entry.get("name", f"entry #{i}")
|
||||
|
|
@ -855,13 +879,32 @@ def validate(config_file: str | None):
|
|||
has_errors = True
|
||||
continue
|
||||
|
||||
# Try resolving the connector to catch bad source strings.
|
||||
# Syntax check: resolve the connector.
|
||||
try:
|
||||
_resolve_connector(source)
|
||||
click.echo(click.style(f" ✓ {entry_name}", fg="green") + f" {source} → {kb_id}")
|
||||
except Exception as e:
|
||||
click.echo(click.style(f" ✗ {entry_name}: {e}", fg="red"))
|
||||
has_errors = True
|
||||
continue
|
||||
|
||||
# Deep check: verify the KB exists.
|
||||
if deep and client:
|
||||
try:
|
||||
kb = client.get_kb(kb_id)
|
||||
kb_name = kb.get("name", "?")
|
||||
file_count = len(kb.get("files", []))
|
||||
click.echo(
|
||||
click.style(f" ✓ {entry_name}", fg="green")
|
||||
+ f" {source} → {kb_name} ({file_count} files)"
|
||||
)
|
||||
except Exception as e:
|
||||
click.echo(click.style(f" ✗ {entry_name}: KB {kb_id} — {e}", fg="red"))
|
||||
has_errors = True
|
||||
else:
|
||||
click.echo(click.style(f" ✓ {entry_name}", fg="green") + f" {source} → {kb_id}")
|
||||
|
||||
if client:
|
||||
client.close()
|
||||
|
||||
if has_errors:
|
||||
sys.exit(1)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ async def verify_api_key(
|
|||
app = FastAPI(
|
||||
title="oikb",
|
||||
description="Sync engine for Open WebUI Knowledge Bases. Trigger syncs, check status, and query history.",
|
||||
version="0.3.3",
|
||||
version="0.3.4",
|
||||
)
|
||||
|
||||
# Runtime state populated by start_daemon().
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue