Skip to content

Commit 4f0e022

Browse files
authored
Merge branch 'main' into konflux-google-lightspeed-agent
2 parents 48da700 + dd89b9e commit 4f0e022

60 files changed

Lines changed: 573 additions & 593 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,18 @@ AGENT_REQUIRED_SCOPE=agent:insights
3535
# Red Hat Lightspeed MCP Server Configuration
3636
# -----------------------------------------------------------------------------
3737
# The MCP server provides tools to access Red Hat Insights APIs.
38-
# It runs as a sidecar container and authenticates with console.redhat.com
39-
# using Lightspeed service account credentials.
38+
# It runs as a sidecar container. The agent forwards the caller's JWT token
39+
# to the MCP server, which uses it to authenticate with console.redhat.com
40+
# on behalf of the calling user.
4041
#
41-
# To obtain Lightspeed credentials:
42-
# 1. Go to console.redhat.com
43-
# 2. Navigate to Settings -> Integrations -> Red Hat Lightspeed
44-
# 3. Create a service account
45-
# 4. Copy the Client ID and Client Secret
46-
#
47-
# These credentials allow the MCP server to access:
42+
# The MCP server can access:
4843
# - Advisor (recommendations)
4944
# - Inventory (registered systems)
5045
# - Vulnerability (CVE data)
5146
# - Remediations (playbooks)
5247
# - Patch (system updates)
5348
# - Image Builder (custom images)
5449
#
55-
LIGHTSPEED_CLIENT_ID=your_lightspeed_client_id
56-
LIGHTSPEED_CLIENT_SECRET=your_lightspeed_client_secret
5750

5851
# MCP server transport mode:
5952
# - stdio: Agent spawns MCP server as subprocess (development)

.github/workflows/ci.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
lint:
11+
name: Lint
12+
runs-on: ubuntu-latest
13+
container:
14+
image: quay.io/centos/centos:stream9
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Install Python
19+
run: dnf install -y python3.12 python3.12-pip python3.12-devel
20+
21+
- name: Install dependencies
22+
run: python3.12 -m pip install -e ".[agent,dev]"
23+
24+
- name: Run ruff
25+
run: python3.12 -m ruff check src/ tests/
26+
27+
- name: Run mypy
28+
run: python3.12 -m mypy src/lightspeed_agent/ --ignore-missing-imports
29+
30+
test:
31+
name: Test
32+
runs-on: ubuntu-latest
33+
container:
34+
image: quay.io/centos/centos:stream9
35+
steps:
36+
- uses: actions/checkout@v4
37+
38+
- name: Install Python
39+
run: dnf install -y python3.12 python3.12-pip python3.12-devel
40+
41+
- name: Install dependencies
42+
run: python3.12 -m pip install -e ".[agent,dev]"
43+
44+
- name: Run tests
45+
run: python3.12 -m pytest tests/ -v
46+
47+
build:
48+
name: Build container image
49+
runs-on: ubuntu-latest
50+
steps:
51+
- uses: actions/checkout@v4
52+
53+
- name: Build image
54+
run: podman build -t lightspeed-agent:ci -f Containerfile .
55+
56+
ci-gate:
57+
name: CI Gate
58+
if: always()
59+
needs: [lint, test, build]
60+
runs-on: ubuntu-latest
61+
steps:
62+
- name: Check all jobs passed
63+
run: |
64+
if [[ "${{ needs.lint.result }}" != "success" || "${{ needs.test.result }}" != "success" || "${{ needs.build.result }}" != "success" ]]; then
65+
echo "One or more CI jobs failed or were cancelled."
66+
echo " lint: ${{ needs.lint.result }}"
67+
echo " test: ${{ needs.test.result }}"
68+
echo " build: ${{ needs.build.result }}"
69+
exit 1
70+
fi
71+
echo "All CI jobs passed."

Makefile

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Red Hat Lightspeed Agent for Google Cloud - Makefile
22
# Common development and deployment commands
33

4-
.PHONY: help build run stop logs logs-mcp clean test lint dev check-env
4+
.PHONY: help build build-agent build-marketplace run stop logs logs-mcp clean test lint dev check-env
55

66
# Default target
77
help:
@@ -13,7 +13,9 @@ help:
1313
@echo " make lint - Run linter and type checker"
1414
@echo ""
1515
@echo "Container (Podman):"
16-
@echo " make build - Build container image"
16+
@echo " make build - Build all container images (agent + marketplace handler)"
17+
@echo " make build-agent - Build agent container image only"
18+
@echo " make build-marketplace - Build marketplace handler container image only"
1719
@echo " make run - Start the pod with all services"
1820
@echo " make stop - Stop and remove the pod"
1921
@echo " make logs - View agent container logs"
@@ -27,8 +29,6 @@ help:
2729
@echo ""
2830
@echo "Required Environment Variables:"
2931
@echo " GOOGLE_API_KEY - Google AI Studio API key"
30-
@echo " LIGHTSPEED_CLIENT_ID - Red Hat Insights service account ID"
31-
@echo " LIGHTSPEED_CLIENT_SECRET - Red Hat Insights service account secret"
3232
@echo ""
3333

3434
# =============================================================================
@@ -54,13 +54,20 @@ lint:
5454
# =============================================================================
5555

5656
IMAGE_NAME ?= localhost/lightspeed-agent
57+
MARKETPLACE_IMAGE_NAME ?= localhost/marketplace-handler
5758
IMAGE_TAG ?= latest
5859
POD_NAME = lightspeed-agent-pod
5960

60-
build:
61-
@echo "Building container image..."
61+
build: build-agent build-marketplace
62+
63+
build-agent:
64+
@echo "Building agent container image..."
6265
podman build -t $(IMAGE_NAME):$(IMAGE_TAG) -f Containerfile .
6366

67+
build-marketplace:
68+
@echo "Building marketplace handler container image..."
69+
podman build -t $(MARKETPLACE_IMAGE_NAME):$(IMAGE_TAG) -f Containerfile.marketplace-handler .
70+
6471
run: check-env build
6572
@echo "Starting pod..."
6673
@if podman pod exists $(POD_NAME); then \
@@ -87,6 +94,10 @@ stop:
8794
podman pod rm $(POD_NAME) 2>/dev/null || true
8895
@echo "Pod stopped and removed."
8996

97+
cve-scan:
98+
@echo "Scanning for CVEs with trivy"
99+
podman run --rm -v $$(pwd):/app:Z aquasec/trivy fs --file-patterns pip:requirements-.*\.txt /app
100+
90101
logs:
91102
@echo "Showing agent logs..."
92103
podman logs -f $(POD_NAME)-lightspeed-agent
@@ -119,18 +130,6 @@ check-env:
119130
else \
120131
echo " ✓ GOOGLE_API_KEY is set (or using Vertex AI)"; \
121132
fi; \
122-
if [ -z "$$LIGHTSPEED_CLIENT_ID" ]; then \
123-
echo " ✗ LIGHTSPEED_CLIENT_ID is not set"; \
124-
missing=1; \
125-
else \
126-
echo " ✓ LIGHTSPEED_CLIENT_ID is set"; \
127-
fi; \
128-
if [ -z "$$LIGHTSPEED_CLIENT_SECRET" ]; then \
129-
echo " ✗ LIGHTSPEED_CLIENT_SECRET is not set"; \
130-
missing=1; \
131-
else \
132-
echo " ✓ LIGHTSPEED_CLIENT_SECRET is set"; \
133-
fi; \
134133
if [ $$missing -eq 1 ]; then \
135134
echo ""; \
136135
echo "Missing required environment variables!"; \
@@ -146,8 +145,9 @@ check-env:
146145
# =============================================================================
147146

148147
clean: stop
149-
@echo "Removing container image..."
148+
@echo "Removing container images..."
150149
podman rmi $(IMAGE_NAME):$(IMAGE_TAG) 2>/dev/null || true
150+
podman rmi $(MARKETPLACE_IMAGE_NAME):$(IMAGE_TAG) 2>/dev/null || true
151151
@echo "Removing dangling images..."
152152
podman image prune -f
153153
@echo "Cleanup complete."

README.md

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,9 @@ See [Container Deployment](#container-deployment) for full details.
183183

184184
#### Option 3: Development without MCP (Limited)
185185

186-
If MCP credentials are not configured, the agent will start without tools (limited functionality):
186+
If the MCP server is not running, the agent will start without tools (limited functionality):
187187

188188
```bash
189-
# Unset MCP credentials to skip MCP connection
190-
unset LIGHTSPEED_CLIENT_ID
191-
unset LIGHTSPEED_CLIENT_SECRET
192-
193189
# Run agent (will work but without Insights API access)
194190
adk web agents
195191
```
@@ -203,30 +199,11 @@ See `.env.example` for all available configuration options.
203199
| Variable | Description |
204200
|----------|-------------|
205201
| `GOOGLE_API_KEY` | Google AI Studio API key |
206-
| `LIGHTSPEED_CLIENT_ID` | Red Hat Insights service account ID |
207-
| `LIGHTSPEED_CLIENT_SECRET` | Red Hat Insights service account secret |
208202
| `RED_HAT_SSO_CLIENT_ID` | OAuth client ID for Red Hat SSO |
209203
| `RED_HAT_SSO_CLIENT_SECRET` | OAuth client secret for Red Hat SSO |
210204

211205
### Obtaining Credentials
212206

213-
#### Lightspeed Service Account (for MCP Server)
214-
215-
The MCP server uses Lightspeed service account credentials to authenticate with console.redhat.com APIs. To obtain these:
216-
217-
1. Go to [console.redhat.com](https://console.redhat.com)
218-
2. Navigate to **Settings****Integrations****Red Hat Lightspeed**
219-
3. Create a new service account
220-
4. Copy the **Client ID** and **Client Secret**
221-
222-
These credentials allow the MCP server to access:
223-
- Advisor (system recommendations)
224-
- Inventory (registered systems)
225-
- Vulnerability (CVE information)
226-
- Remediations (playbook management)
227-
- Patch (system updates)
228-
- Image Builder (custom RHEL images)
229-
230207
#### Red Hat SSO OAuth Credentials
231208

232209
For user authentication via OAuth 2.0:
@@ -320,7 +297,6 @@ The system is deployed as **three separate pods**:
320297

321298
- Podman 4.0+
322299
- Access to Red Hat container registry (for RHEL-based images)
323-
- Red Hat Insights Lightspeed service account credentials
324300
- Google API key or Vertex AI access
325301

326302
### Build the Container Images
@@ -362,8 +338,6 @@ podman build -t localhost/a2a-inspector:latest /tmp/a2a-inspector
362338

363339
**API Credentials:**
364340
- `GOOGLE_API_KEY`: Your Google AI Studio API key
365-
- `LIGHTSPEED_CLIENT_ID`: Red Hat Insights service account ID
366-
- `LIGHTSPEED_CLIENT_SECRET`: Red Hat Insights service account secret
367341
- `RED_HAT_SSO_CLIENT_ID`: OAuth client ID for Red Hat SSO
368342
- `RED_HAT_SSO_CLIENT_SECRET`: OAuth client secret for Red Hat SSO
369343

@@ -455,14 +429,14 @@ for i in {1..70}; do
455429
code=$(curl -s -o /tmp/resp.json -w "%{http_code}" \
456430
-X POST http://localhost:8000/ \
457431
-H "Content-Type: application/json" \
458-
-d '{"jsonrpc":"2.0","method":"message/send","id":"'$i'","params":{"message":{"role":"user","parts":[{"type":"text","text":"test"}]}}}')
432+
-d '{"jsonrpc":"2.0","method":"message/send","id":"'$i'","params":{"message":{"messageId":"'$i'","role":"user","parts":[{"type":"text","text":"test"}]}}}')
459433
echo "$i -> $code"
460434
done
461435

462436
# Inspect 429 details and headers
463437
curl -i -X POST http://localhost:8000/ \
464438
-H "Content-Type: application/json" \
465-
-d '{"jsonrpc":"2.0","method":"message/send","id":"x","params":{"message":{"role":"user","parts":[{"type":"text","text":"test"}]}}}'
439+
-d '{"jsonrpc":"2.0","method":"message/send","id":"x","params":{"message":{"messageId":"x","role":"user","parts":[{"type":"text","text":"test"}]}}}'
466440

467441
# Inspect Redis rate-limit keys
468442
podman exec -it lightspeed-redis-redis redis-cli KEYS "lightspeed:ratelimit:*"
@@ -548,6 +522,7 @@ curl -X POST http://localhost:8000/ \
548522
"method": "message/send",
549523
"params": {
550524
"message": {
525+
"messageId": "1",
551526
"role": "user",
552527
"parts": [{"type": "text", "text": "Show my systems"}]
553528
}
@@ -860,12 +835,12 @@ This separation ensures:
860835
The MCP server runs as a sidecar container and provides tools for the agent to interact with Red Hat Insights APIs:
861836

862837
1. **Agent receives a request** (e.g., "Show me my system vulnerabilities")
863-
2. **Agent calls MCP tools** via HTTP to the MCP server (localhost:8081), passing credentials in headers
864-
3. **MCP server authenticates** with console.redhat.com using the credentials from headers
838+
2. **Agent calls MCP tools** via HTTP to the MCP server (localhost:8081), forwarding the caller's JWT token in the Authorization header
839+
3. **MCP server authenticates** with console.redhat.com using the forwarded JWT token
865840
4. **MCP server calls Insights APIs** and returns results to the agent
866841
5. **Agent formats the response** and returns it to the user
867842

868-
The Lightspeed credentials (`LIGHTSPEED_CLIENT_ID` and `LIGHTSPEED_CLIENT_SECRET`) are configured on the **agent** container, which passes them to the MCP server via HTTP headers on each request. The MCP server itself does not need credentials configured.
843+
The agent forwards the caller's JWT token to the MCP server via the `Authorization: Bearer` header on each request. The MCP server itself does not need credentials configured.
869844

870845
### Persistent Storage
871846

cloudbuild.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ steps:
8282
- '--set-env-vars'
8383
- 'GOOGLE_GENAI_USE_VERTEXAI=TRUE,GOOGLE_CLOUD_PROJECT=${PROJECT_ID},GOOGLE_CLOUD_LOCATION=${_REGION},AGENT_HOST=0.0.0.0,AGENT_PORT=8000,LOG_FORMAT=json'
8484
- '--set-secrets'
85-
- 'LIGHTSPEED_CLIENT_ID=lightspeed-client-id:latest,LIGHTSPEED_CLIENT_SECRET=lightspeed-client-secret:latest,RED_HAT_SSO_CLIENT_ID=redhat-sso-client-id:latest,RED_HAT_SSO_CLIENT_SECRET=redhat-sso-client-secret:latest,DATABASE_URL=database-url:latest,REDIS_URL=redis-url:latest'
85+
- 'RED_HAT_SSO_CLIENT_ID=redhat-sso-client-id:latest,RED_HAT_SSO_CLIENT_SECRET=redhat-sso-client-secret:latest,DATABASE_URL=database-url:latest,REDIS_URL=redis-url:latest'
8686
- '--service-account'
8787
- 'lightspeed-agent@${PROJECT_ID}.iam.gserviceaccount.com'
8888
- '--allow-unauthenticated'

deploy/cloudrun/README.md

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ The deployment consists of **two separate Cloud Run services** plus **Cloud Memo
6262
2. **Deploy Marketplace Handler first** - Must be running to receive provisioning events
6363
3. **Deploy Agent after provisioning** - Can be deployed when customers are ready to use the agent
6464

65-
The MCP server runs as a sidecar in the Agent service. The agent forwards the caller's JWT token to the MCP server, which uses it to authenticate with console.redhat.com on behalf of the user. Alternatively, if Lightspeed service account credentials are configured, the agent sends those instead (see [MCP Authentication](#mcp-authentication)).
65+
The MCP server runs as a sidecar in the Agent service. The agent forwards the caller's JWT token to the MCP server, which uses it to authenticate with console.redhat.com on behalf of the user (see [MCP Authentication](#mcp-authentication)).
6666

6767
## Service Accounts
6868

@@ -551,30 +551,20 @@ When the agent needs to access Insights data (e.g., system vulnerabilities, reco
551551

552552
### MCP Authentication
553553

554-
The agent supports two modes for authenticating with the MCP server, determined
555-
by whether Lightspeed credentials are configured:
556-
557-
| Mode | When | Headers sent to MCP |
558-
|------|------|---------------------|
559-
| **JWT pass-through** (default) | `LIGHTSPEED_CLIENT_ID/SECRET` not set | `Authorization: Bearer <caller's token>` |
560-
| **Lightspeed credentials** | `LIGHTSPEED_CLIENT_ID/SECRET` set | `lightspeed-client-id` + `lightspeed-client-secret` |
561-
562-
**JWT pass-through** is the recommended mode. The caller's Red Hat SSO token
563-
is forwarded to the MCP server, which uses it to call console.redhat.com APIs
564-
on behalf of the user.
554+
The agent forwards the caller's JWT token to the MCP server via the
555+
`Authorization: Bearer` header. The MCP server uses this token to call
556+
console.redhat.com APIs on behalf of the user.
565557

566558
### Credential Flow
567559

568-
**Mode A: JWT pass-through (default)**
569-
570560
```
571561
Client Agent MCP Server console.redhat.com
572562
│ │ │ │
573563
│ POST / (A2A) │ │ │
574564
│ Authorization: Bearer T │ │ │
575565
├─────────────────────────►│ │ │
576566
│ │ MCP tool call │ │
577-
│ │ Authorization: Bearer T|
567+
│ │ Authorization: Bearer T
578568
│ ├────────────────────────►│ │
579569
│ │ │ API Request + T │
580570
│ │ ├────────────────────►│
@@ -586,24 +576,6 @@ Client Agent MCP Server console.red
586576
│◄─────────────────────────┤ │ │
587577
```
588578
589-
**Mode B: Lightspeed credentials (optional)**
590-
591-
```
592-
Secret Manager MCP Server console.redhat.com
593-
│ │ │
594-
│ LIGHTSPEED_CLIENT_ID │ │
595-
│ LIGHTSPEED_CLIENT_SECRET │ │
596-
├──────────────────────────────►│ │
597-
│ │ OAuth2 Token Request │
598-
│ ├──────────────────────────►│
599-
│ │ Access Token │
600-
│ │◄──────────────────────────┤
601-
│ │ API Request + Token │
602-
│ ├──────────────────────────►│
603-
│ │ API Response │
604-
│ │◄──────────────────────────┤
605-
```
606-
607579
## Authentication
608580
609581
The agent uses **Red Hat SSO** (Keycloak) for authentication via **token
@@ -635,7 +607,7 @@ Bearer token that is active and carries the `agent:insights` scope.
635607
│ ├───────────────────►│ │ │
636608
│ │ │ │ │
637609
│ │ 5. MCP tool call │ │ │
638-
│ │ + Bearer token (or Lightspeed creds) │ │
610+
│ │ + Bearer token │ │
639611
│ ├───────────────────────────────────────►│ │
640612
│ │ │ │ 6. Insights API │
641613
│ │ │ │ (using token) │
@@ -650,7 +622,7 @@ Bearer token that is active and carries the `agent:insights` scope.
650622
651623
**Credential sets:**
652624
- **Red Hat SSO credentials** (`RED_HAT_SSO_CLIENT_ID/SECRET`): Used by the agent as Resource Server credentials for token introspection (step 4)
653-
- **MCP authentication** (step 5): By default the caller's Bearer token is forwarded. If `LIGHTSPEED_CLIENT_ID/SECRET` are configured, those are sent instead (see [MCP Authentication](#mcp-authentication))
625+
- **MCP authentication** (step 5): The caller's Bearer token is forwarded to the MCP server (see [MCP Authentication](#mcp-authentication))
654626
655627
### Configuration
656628

0 commit comments

Comments
 (0)