Skip to content

Commit 8468158

Browse files
author
Peter Gustafsson
committed
Merge remote-tracking branch 'upstream/main' into fix/docling-chunk-metadata
Signed-off-by: Peter Gustafsson <peter.gustafsson6@gmail.com>
2 parents 1510e2d + 59872d4 commit 8468158

17 files changed

Lines changed: 366 additions & 68 deletions

File tree

client-sdks/stainless/openapi.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13928,6 +13928,7 @@ components:
1392813928
anyOf:
1392913929
- type: string
1393013930
- type: 'null'
13931+
description: Name of the ranking algorithm. Supported values are "weighted", "rrf", "neural", and "classifier". Other string values are accepted for OpenAI API compatibility but are not supported.
1393113932
score_threshold:
1393213933
anyOf:
1393313934
- type: number

docs/docs/distributions/configuration.mdx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,24 @@ This allows you to:
308308

309309
The server supports multiple authentication providers:
310310

311+
#### Local API Key Provider
312+
313+
Validates a shared secret API key against a list of allowed keys:
314+
315+
```yaml
316+
server:
317+
auth:
318+
provider_config:
319+
type: "local_api_key"
320+
api_keys:
321+
- "ogk_mykey1"
322+
- "ogk_mykey2"
323+
```
324+
325+
This is the simplest authentication provider — any key in the list authenticates successfully and is granted `admin` and `owner` [roles](../configuration.mdx#access-control) so the default owner-based access-controls work out of the box. Use it for development, internal services, or when you prefer to manage keys outside an identity provider.
326+
327+
The token is validated as `Authorization: Bearer <key>` and the key string itself becomes the user principal. Because this provider does not resolve a `tenant_id`, it is only compatible with `server.tenancy.mode` `single` or `disabled` — startup will fail with `multi`.
328+
311329
#### OAuth 2.0/OpenID Connect Provider with Kubernetes
312330

313331
The server can be configured to use service account tokens for authorization, validating these against the Kubernetes API server, e.g.:

docs/static/deprecated-ogx-spec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7572,6 +7572,7 @@ components:
75727572
anyOf:
75737573
- type: string
75747574
- type: 'null'
7575+
description: Name of the ranking algorithm. Supported values are "weighted", "rrf", "neural", and "classifier". Other string values are accepted for OpenAI API compatibility but are not supported.
75757576
score_threshold:
75767577
anyOf:
75777578
- type: number

docs/static/experimental-ogx-spec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8942,6 +8942,7 @@ components:
89428942
anyOf:
89438943
- type: string
89448944
- type: 'null'
8945+
description: Name of the ranking algorithm. Supported values are "weighted", "rrf", "neural", and "classifier". Other string values are accepted for OpenAI API compatibility but are not supported.
89458946
score_threshold:
89468947
anyOf:
89478948
- type: number

docs/static/ogx-spec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12444,6 +12444,7 @@ components:
1244412444
anyOf:
1244512445
- type: string
1244612446
- type: 'null'
12447+
description: Name of the ranking algorithm. Supported values are "weighted", "rrf", "neural", and "classifier". Other string values are accepted for OpenAI API compatibility but are not supported.
1244712448
score_threshold:
1244812449
anyOf:
1244912450
- type: number

docs/static/stainless-ogx-spec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13928,6 +13928,7 @@ components:
1392813928
anyOf:
1392913929
- type: string
1393013930
- type: 'null'
13931+
description: Name of the ranking algorithm. Supported values are "weighted", "rrf", "neural", and "classifier". Other string values are accepted for OpenAI API compatibility but are not supported.
1393113932
score_threshold:
1393213933
anyOf:
1393313934
- type: number

scripts/check_file_size.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
# Remove entries from this list as files get refactored.
2727
GRANDFATHERED_FILES = {
2828
"scripts/openapi_generator/schema_transforms.py",
29+
"src/ogx/cli/stack/lets_go.py",
2930
"src/ogx/core/datatypes.py",
3031
"src/ogx/core/library_client.py",
3132
"src/ogx/providers/inline/responses/builtin/responses/openai_responses.py",

src/ogx/cli/stack/lets_go.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import inspect
1313
import logging # allow-direct-logging :: for direct logging control in _suppress_provider_logs
1414
import os
15+
import secrets
1516
import shutil
1617
import subprocess
1718
import sys
@@ -210,6 +211,18 @@ def add_letsgo_arguments(parser: argparse.ArgumentParser) -> None:
210211
default=False,
211212
help="Allow running without TLS certificates. Disables FIPS enforcement. For local development only.",
212213
)
214+
parser.add_argument(
215+
"--host",
216+
type=str,
217+
default="127.0.0.1",
218+
help="Host to bind the server to",
219+
)
220+
parser.add_argument(
221+
"--no-auth",
222+
action="store_true",
223+
default=False,
224+
help="Disable authentication entirely (generates no server.auth block in config).",
225+
)
213226

214227

215228
def _add_file_search_and_responses(run_config: StackConfig) -> None:
@@ -471,6 +484,23 @@ async def _run_letsgo_cmd_impl(args: argparse.Namespace, parser: argparse.Argume
471484
config_dict["server"]["insecure"] = False
472485
cprint(f" ✓ Generated self-signed TLS certificate → {cert_path}", color="green")
473486

487+
config_dict["server"]["host"] = args.host
488+
489+
if not args.no_auth:
490+
api_keys = [f"ogk_{secrets.token_urlsafe(24)}" for _ in range(3)]
491+
if "server" not in config_dict:
492+
config_dict["server"] = {}
493+
config_dict["server"]["auth"] = {
494+
"provider_config": {"type": "local_api_key", "api_keys": api_keys},
495+
}
496+
cprint(" ✓ Simple authentication enabled", color="green")
497+
cprint(" Here are keys you can use for authentication:", color="green")
498+
for key in api_keys:
499+
cprint(f" {key}", color="yellow")
500+
cprint(f' curl -k -H "Authorization: Bearer {api_keys[0]}" \\', color="cyan")
501+
cprint(f" https://localhost:{args.port}/v1/chat/completions", color="cyan")
502+
cprint("", color="green")
503+
474504
config_file = distro_dir / "config.yaml"
475505
logger.info("Writing generated config to", config_file=config_file)
476506
with open(config_file, "w") as f:
@@ -552,6 +582,7 @@ async def _autodetect_providers(debug: bool = False) -> tuple[str, tuple[Qualifi
552582
("remote::anthropic", None, "https://api.anthropic.com/v1", "ANTHROPIC_API_KEY", None),
553583
("remote::gemini", None, "https://generativelanguage.googleapis.com/v1beta/openai", "GEMINI_API_KEY", None),
554584
("remote::azure", "AZURE_API_BASE", "", "AZURE_API_KEY", None),
585+
("remote::meta", None, "https://api.meta.ai/v1", "META_API_KEY", None),
555586
]
556587

557588
passed: list[str] = []

src/ogx/core/datatypes.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ class OAuth2IntrospectionConfig(BaseModel):
202202
class AuthProviderType(StrEnum):
203203
"""Supported authentication provider types."""
204204

205+
LOCAL_API_KEY = "local_api_key"
205206
OAUTH2_TOKEN = "oauth2_token"
206207
GITHUB_TOKEN = "github_token"
207208
CUSTOM = "custom"
@@ -303,6 +304,15 @@ class CustomAuthConfig(BaseModel):
303304
)
304305

305306

307+
class LocalApiKeyAuthConfig(BaseModel):
308+
"""Simple API key authentication for single-key deployments."""
309+
310+
type: Literal[AuthProviderType.LOCAL_API_KEY] = AuthProviderType.LOCAL_API_KEY
311+
api_keys: list[str] = Field(
312+
description="API keys that clients can send via the Authorization: Bearer header.",
313+
)
314+
315+
306316
class GitHubTokenAuthConfig(BaseModel):
307317
"""Configuration for GitHub token authentication."""
308318

@@ -394,6 +404,7 @@ class UpstreamHeaderAuthConfig(BaseModel):
394404

395405
AuthProviderConfig = Annotated[
396406
OAuth2TokenAuthConfig
407+
| LocalApiKeyAuthConfig
397408
| GitHubTokenAuthConfig
398409
| CustomAuthConfig
399410
| KubernetesAuthProviderConfig

src/ogx/core/server/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ server/
99
__init__.py
1010
server.py # Main FastAPI app, route dispatch, SSE streaming, lifespan
1111
auth.py # AuthenticationMiddleware (Bearer token validation)
12-
auth_providers.py # Auth provider implementations (Kubernetes, custom endpoint)
12+
auth_providers.py # Auth provider implementations (Kubernetes, custom endpoint, local API key)
1313
metrics.py # RequestMetricsMiddleware (per-API request metrics)
1414
routes.py # Route initialization and matching from FastAPI routers
1515
fastapi_router_registry.py # Auto-discovery of FastAPI routers from ogx_api packages
@@ -30,7 +30,7 @@ Routes are defined as native FastAPI routers. `fastapi_router_registry.py` auto-
3030
### Middleware
3131

3232
- **`RequestMetricsMiddleware`** (`metrics.py`): Tracks per-API request counts and latency metrics. Runs as the outermost middleware.
33-
- **`AuthenticationMiddleware`** (`auth.py`): Validates Bearer tokens using a configured auth provider (Kubernetes, custom endpoint). Extracts user identity, attributes, and `tenant_id` for access control. Each auth provider resolves `tenant_id` from its source (JWT claim, HTTP header, K8s claim, or custom endpoint field). Endpoints can opt out by setting `openapi_extra={PUBLIC_ROUTE_KEY: True}` on their route.
33+
- **`AuthenticationMiddleware`** (`auth.py`): Validates Bearer tokens using a configured auth provider (Kubernetes, custom endpoint, local API key). Extracts user identity, attributes, and `tenant_id` for access control. Each auth provider resolves `tenant_id` from its source (JWT claim, HTTP header, K8s claim, or custom endpoint field). The local API key provider returns attributes (`roles`, `teams`) but **does not** resolve `tenant_id` — it only supports `single` or `disabled` tenancy modes. Endpoints can opt out by setting `openapi_extra={PUBLIC_ROUTE_KEY: True}` on their route.
3434
- **`TenancyMiddleware`** (`auth.py`): Enforces the configured tenancy mode after authentication. In `disabled` mode: passthrough. In `single` mode: overrides `tenant_id` to the configured default (works with or without auth). In `multi` mode: rejects requests with no `tenant_id` (401).
3535
- **`RouteAuthorizationMiddleware`** (`auth.py`): Enforces route-level access policies based on user roles.
3636
- **`ClientVersionMiddleware`** (`server.py`): Rejects requests from clients with incompatible major.minor versions.

0 commit comments

Comments
 (0)