Skip to content

Commit 5bed676

Browse files
committed
auth, readme
1 parent 0f5dc82 commit 5bed676

File tree

6 files changed

+323
-12
lines changed

6 files changed

+323
-12
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Manifest Runner
2+
3+
An HTTP server for running Airbyte declarative connectors via their manifest files.
4+
5+
## Quick Start
6+
7+
### Installation
8+
9+
The manifest runner is available as an extra dependency:
10+
11+
```bash
12+
# Using Poetry (preferred)
13+
poetry install --extras manifest-runner
14+
15+
# Using pip
16+
pip install airbyte-cdk[manifest-runner]
17+
```
18+
19+
### Running the Server
20+
21+
```bash
22+
# Start the server (default port 8000)
23+
manifest-runner start
24+
25+
# Start on a specific port
26+
manifest-runner start --port 8080
27+
28+
# Or using Python module
29+
python -m airbyte_cdk.cli.manifest_runner._run start
30+
```
31+
32+
The server will start on `http://localhost:8000` by default.
33+
34+
## API Endpoints
35+
36+
### `/manifest/test_read`
37+
Test reading from a specific stream in the manifest.
38+
39+
**POST** - Test stream reading with configurable limits for records, pages, and slices.
40+
41+
### `/manifest/resolve`
42+
Resolve a manifest to its final configuration.
43+
44+
**POST** - Returns the resolved manifest without dynamic stream generation.
45+
46+
### `/manifest/full_resolve`
47+
Fully resolve a manifest including dynamic streams.
48+
49+
**POST** - Generates dynamic streams up to specified limits and includes them in the resolved manifest.
50+
51+
## Authentication
52+
53+
The manifest runner supports optional JWT bearer token authentication:
54+
55+
### Configuration
56+
Set the environment variable to enable authentication:
57+
```bash
58+
export AB_JWT_SIGNATURE_SECRET="your-jwt-secret-key"
59+
```
60+
61+
### Usage
62+
When authentication is enabled, include a valid JWT token in the Authorization header:
63+
```bash
64+
curl -H "Authorization: Bearer <your-jwt-token>" \
65+
http://localhost:8000/manifest/test_read
66+
```
67+
68+
### Behavior
69+
- **Without `AB_JWT_SIGNATURE_SECRET`**: All requests pass through
70+
- **With `AB_JWT_SIGNATURE_SECRET`**: Requires valid JWT bearer token using HS256 algorithm
71+
72+
## OpenAPI Specification
73+
74+
The manifest runner provides an OpenAPI specification for API client generation:
75+
76+
### Generating the OpenAPI Spec
77+
```bash
78+
# Generate OpenAPI YAML (default location)
79+
manifest-runner generate-openapi
80+
81+
# Generate to custom location
82+
manifest-runner generate-openapi --output /path/to/openapi.yaml
83+
```
84+
85+
The generated OpenAPI specification is consumed by other applications and tools to:
86+
- Generate API clients in various programming languages
87+
- Create SDK bindings for the manifest runner
88+
- Provide API documentation and validation
89+
- Enable integration with API development tools
90+
91+
### Interactive API Documentation
92+
93+
When running, interactive API documentation is available at:
94+
- Swagger UI: `http://localhost:8000/docs`
95+
- ReDoc: `http://localhost:8000/redoc`
96+
97+
## Testing
98+
99+
Run the manifest runner tests from the repository root:
100+
101+
```bash
102+
# Run all manifest runner tests
103+
poetry run pytest unit_tests/manifest_runner/ -v
104+
```
105+
106+
## Docker
107+
108+
The manifest runner can be containerized using the included Dockerfile. Build from the repository root:
109+
110+
```bash
111+
# Build from repository root (not from manifest_runner subdirectory)
112+
docker build -f airbyte_cdk/manifest_runner/Dockerfile -t manifest-runner .
113+
114+
# Run the container
115+
docker run -p 8080:8080 manifest-runner
116+
```
117+
118+
Note: The container runs on port 8080 by default.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import os
2+
from typing import Optional
3+
4+
import jwt
5+
from fastapi import HTTPException, Security, status
6+
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
7+
8+
security = HTTPBearer(auto_error=False)
9+
10+
11+
def verify_jwt_token(
12+
credentials: Optional[HTTPAuthorizationCredentials] = Security(security),
13+
) -> None:
14+
"""
15+
Verify JWT token if AB_JWT_SIGNATURE_SECRET is set, otherwise allow through.
16+
17+
Args:
18+
credentials: Bearer token credentials from request header
19+
20+
Raises:
21+
HTTPException: If token is invalid or missing when secret is configured
22+
"""
23+
jwt_secret = os.getenv("AB_JWT_SIGNATURE_SECRET")
24+
25+
# If no secret is configured, allow all requests through
26+
if not jwt_secret:
27+
return
28+
29+
if not credentials:
30+
raise HTTPException(
31+
status_code=status.HTTP_401_UNAUTHORIZED,
32+
detail="Bearer token required",
33+
headers={"WWW-Authenticate": "Bearer"},
34+
)
35+
36+
try:
37+
jwt.decode(credentials.credentials, jwt_secret, algorithms=["HS256"])
38+
except jwt.InvalidTokenError:
39+
raise HTTPException(
40+
status_code=status.HTTP_401_UNAUTHORIZED,
41+
detail="Invalid token",
42+
headers={"WWW-Authenticate": "Bearer"},
43+
)

airbyte_cdk/manifest_runner/routers/manifest.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from dataclasses import asdict
33
from typing import Any, Dict, List
44

5-
from fastapi import APIRouter
5+
from fastapi import APIRouter, Depends
66

77
from airbyte_cdk.models import AirbyteStateMessageSerializer
88
from airbyte_cdk.sources.declarative.parsers.custom_code_compiler import (
@@ -17,12 +17,14 @@
1717
StreamRead,
1818
StreamTestReadRequest,
1919
)
20+
from ..auth import verify_jwt_token
2021
from ..manifest_runner.runner import ManifestRunner
2122
from ..manifest_runner.utils import build_catalog, build_source
2223

2324
router = APIRouter(
2425
prefix="/manifest",
2526
tags=["manifest"],
27+
dependencies=[Depends(verify_jwt_token)],
2628
)
2729

2830

poetry.lock

Lines changed: 11 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ pytest-cov = "*"
111111
pytest-httpserver = "*"
112112
pytest-mock = "*"
113113
requests-mock = "*"
114+
httpx = "*" # Required for FastAPI TestClient
114115
# Stubs packages for mypy typing
115116
types-requests = "^2.32.0.20241016"
116117
types-python-dateutil = "^2.9.0.20241003"

0 commit comments

Comments
 (0)