Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
73 changes: 73 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# LFX V2 Survey Service — Local Development Environment
# Copy this file to .env and fill in the required values.
# The .env file is gitignored and will never be committed.
#
# Quickstart: set the LOCAL DEV OVERRIDES below, get ITX credentials from
# 1Password (LFX V2 vault -> LFX Platform Chart Values Secrets - Local Development), then run:
# source .env && make run

# =============================================================================
# SERVER
# =============================================================================

export PORT=8080
export LOG_LEVEL=debug
# Add source file and line number to log output
export LOG_ADD_SOURCE=true

# =============================================================================
# AUTHENTICATION (Heimdall JWT)
# =============================================================================

export JWKS_URL=http://heimdall:4457/.well-known/jwks
# Must match the audience claim in incoming JWTs
export AUDIENCE=lfx-v2-survey-service

# LOCAL DEV OVERRIDE: set to any string to skip JWT validation entirely.
# Remove or leave empty in non-local environments.
export JWT_AUTH_DISABLED_MOCK_LOCAL_PRINCIPAL=test-user@example.com

# =============================================================================
# ITX PROXY — credentials required to call the ITX API
# Find these in 1Password: Linux Foundation org -> LFX V2 vault ->
# "LFX Platform Chart Values Secrets - Local Development" (secure note).
# Store the private key at tmp/local.private.key (gitignored).
# =============================================================================

export ITX_BASE_URL=https://api.dev.itx.linuxfoundation.org/
export ITX_AUTH0_DOMAIN=linuxfoundation-dev.auth0.com
# Auth0 API audience for ITX M2M token requests
export ITX_AUDIENCE=https://api.dev.itx.linuxfoundation.org/

# REQUIRED — see 1Password note above
export ITX_CLIENT_ID=
# RSA private key in raw PEM format (not base64-encoded)
export ITX_CLIENT_PRIVATE_KEY=

# To load the key from a file instead of inlining it, run:
# export ITX_CLIENT_PRIVATE_KEY="$(cat tmp/local.private.key)"

# =============================================================================
# NATS / ID MAPPING
# =============================================================================

# Default assumes the lfx-platform Helm chart is running locally.
# Override with nats://localhost:4222 if your NATS server is on that port instead.
export NATS_URL=nats://lfx-platform-nats.lfx.svc.cluster.local:4222

# LOCAL DEV OVERRIDE: set to true to skip NATS ID mapping (no NATS needed).
export ID_MAPPING_DISABLED=true

# =============================================================================
# EVENT PROCESSING
# Consumes NATS JetStream events to sync v1 survey data to the v2 indexer and FGA.
# See docs/event-processing.md for details.
# =============================================================================

# LOCAL DEV OVERRIDE: set to false to skip NATS event processing (no NATS needed).
export EVENT_PROCESSING_ENABLED=false

# JetStream consumer name — must be unique per service instance
export EVENT_CONSUMER_NAME=survey-service-kv-consumer
# JetStream stream to consume from
export EVENT_STREAM_NAME=KV_v1-objects
92 changes: 30 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ The LFX V2 Survey Service acts as a secure intermediary between LFX Platform V2
- **Authorization**: Fine-grained access control via OpenFGA
- **Path Translation**: Shorter proxy paths (`/surveys/{id}`) → ITX paths (`/v2/surveys/{id}/schedule`)

The service also processes real-time NATS events to sync v1 survey data to the v2 indexer and FGA. See [Event Processing Documentation](docs/event-processing.md) for details.

See [ITX Proxy Implementation Architecture](docs/itx-proxy-implementation.md) for detailed information.

## Features
Expand Down Expand Up @@ -123,17 +125,18 @@ make build

Binary is output to `bin/survey-api`.

### Run Locally
### Run

Copy `.env.example` to `.env`, fill in the required values (see the `REQUIRED` comments, credentials from 1Password), then source it and run:

```bash
# Set required environment variables
export ITX_CLIENT_ID="your-client-id"
export ITX_CLIENT_PRIVATE_KEY="$(cat path/to/private-key.pem)"
export JWT_AUTH_DISABLED_MOCK_LOCAL_PRINCIPAL="test-user" # For local dev only
export ID_MAPPING_DISABLED="true" # For local dev without NATS
cp .env.example .env
# edit .env and set ITX_CLIENT_ID and ITX_CLIENT_PRIVATE_KEY
source .env

# Run the service
make run
# or for debug logging
make debug
```

The service will start on port 8080 by default.
Expand All @@ -151,70 +154,45 @@ make lint
make fmt
```

## Configuration

The service is configured via environment variables:

### Server Configuration

- `PORT` - HTTP server port (default: 8080)
- `LOG_LEVEL` - Logging level: debug, info, warn, error (default: info)
- `LOG_ADD_SOURCE` - Add source file info to logs (default: true)

### Authentication

- `JWKS_URL` - Heimdall JWKS endpoint for JWT validation
- `AUDIENCE` - Expected JWT audience (default: lfx-v2-survey-service)
- `JWT_AUTH_DISABLED_MOCK_LOCAL_PRINCIPAL` - Mock principal for local dev (disables JWT validation)
## Kubernetes Deployment

### ITX Integration
### Install with Helm

- `ITX_BASE_URL` - ITX API base URL
- `ITX_AUTH0_DOMAIN` - Auth0 domain for M2M authentication
- `ITX_CLIENT_ID` - Auth0 client ID
- `ITX_CLIENT_PRIVATE_KEY` - RSA private key in PEM format (not base64-encoded)
- `ITX_AUDIENCE` - Auth0 API audience
#### Create Kubernetes Secret

### ID Mapping
Before installing the chart, you must create a Kubernetes secret with the required credentials. Get the values from the **LFX Platform Chart Values Secrets - Local Development** note in the **LFX V2** vault in 1Password.

- `NATS_URL` - NATS server URL for ID mapping
- `ID_MAPPING_DISABLED` - Disable ID mapping for local dev (default: false)
```bash
kubectl create secret generic lfx-v2-survey-service -n lfx \
--from-literal=ITX_CLIENT_ID="<from-1password>" \
--from-file=ITX_CLIENT_PRIVATE_KEY=/path/to/private.key
```

### Event Processing
#### Install from GHCR (no local code changes)

- `EVENT_PROCESSING_ENABLED` - Enable/disable event processing (default: true)
- `EVENT_CONSUMER_NAME` - JetStream consumer name (default: survey-service-kv-consumer)
- `EVENT_STREAM_NAME` - JetStream stream name (default: KV_v1-objects)
- `EVENT_FILTER_SUBJECT` - NATS subject filter (default: $KV.v1-objects.>)
To install the latest published image directly from GHCR without any local modifications:

See [Event Processing Documentation](docs/event-processing.md) for details.
```bash
make helm-install
```

## Docker
#### Install with Local Code Changes

### Build Image
Copy the local values example file:

```bash
make docker-build
cp charts/lfx-v2-survey-service/values.local.example.yaml charts/lfx-v2-survey-service/values.local.yaml
```

### Run Container
After making code changes, build the Docker image:

```bash
docker run -p 8080:8080 \
-e ITX_CLIENT_ID="your-client-id" \
-e ITX_CLIENT_PRIVATE_KEY="$(cat private-key.pem)" \
linuxfoundation/lfx-v2-survey-service:latest
make docker-build
```

## Kubernetes Deployment

### Install with Helm
Install the chart using your local image:

```bash
# Install with default values
make helm-install

# Install with local values file
make helm-install-local
```

Expand Down Expand Up @@ -274,16 +252,6 @@ kubectl logs -n lfx -l app=lfx-v2-survey-service
└── go.mod # Go module definition
```

## Development Workflow

1. **Design API**: Modify `api/survey/v1/design/*.go`
2. **Generate Code**: Run `make apigen`
3. **Implement Logic**: Add/update files in `internal/service/`
4. **Test**: Run `make test`
5. **Format & Lint**: Run `make fmt lint`
6. **Build**: Run `make build`
7. **Verify**: Run `make verify` to ensure generated code is up to date

## Contributing

### Code Style
Expand Down
8 changes: 8 additions & 0 deletions charts/lfx-v2-survey-service/values.local.example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright The Linux Foundation and each contributor to LFX.
# SPDX-License-Identifier: MIT
---
# Image configuration
image:
repository: linuxfoundation/lfx-v2-survey-service
tag: "" # Overrides appVersion from Chart.yaml
pullPolicy: IfNotPresent
26 changes: 23 additions & 3 deletions charts/lfx-v2-survey-service/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ image:
tag: "" # Overrides appVersion from Chart.yaml
pullPolicy: IfNotPresent

replicaCount: 3
replicaCount: 1

# Resource limits and requests
resources:
Expand All @@ -27,43 +27,63 @@ app:
# Server configuration
PORT:
value: "8080"
# Logging level: debug, info, warn, error
LOG_LEVEL:
value: info
# Add source file and line number to log output
LOG_ADD_SOURCE:
value: "true"

# JWT authentication (Heimdall)
JWKS_URL:
value: http://lfx-platform-heimdall.lfx.svc.cluster.local:4457/.well-known/jwks
# Must match the audience claim in incoming JWTs
AUDIENCE:
value: lfx-v2-survey-service
# Set to a non-empty string to skip JWT validation (local dev only — never set in production)
JWT_AUTH_DISABLED_MOCK_LOCAL_PRINCIPAL:
value: ''

# ITX service configuration
ITX_BASE_URL:
value: https://api.dev.itx.linuxfoundation.org/
# Auth0 domain used for M2M token requests to ITX
ITX_AUTH0_DOMAIN:
value: linuxfoundation.auth0.com
value: linuxfoundation-dev.auth0.com
# Auth0 client ID — loaded from Kubernetes secret (see externalSecretsOperator below)
ITX_CLIENT_ID:
valueFrom:
secretKeyRef:
name: lfx-v2-survey-service
key: ITX_CLIENT_ID
# RSA private key in raw PEM format (not base64-encoded) — loaded from Kubernetes secret
ITX_CLIENT_PRIVATE_KEY:
valueFrom:
secretKeyRef:
name: lfx-v2-survey-service
key: ITX_CLIENT_PRIVATE_KEY
# Auth0 API audience for ITX M2M token requests
ITX_AUDIENCE:
value: https://api.dev.itx.linuxfoundation.org/

# NATS configuration
NATS_URL:
value: nats://lfx-platform-nats.lfx.svc.cluster.local:4222
# Set to true to disable NATS ID mapping (local dev without NATS)
ID_MAPPING_DISABLED:
value: false

# Event processing — consumes JetStream events to sync v1 survey data to v2 indexer and FGA
# See docs/event-processing.md for details
EVENT_PROCESSING_ENABLED:
value: true
# JetStream consumer name — must be unique per service instance
EVENT_CONSUMER_NAME:
value: survey-service-kv-consumer
# JetStream stream to consume from
EVENT_STREAM_NAME:
value: KV_v1-objects

# OpenTelemetry configuration (optional)
# OTEL_SERVICE_NAME:
# value: lfx-v2-survey-service
Expand Down Expand Up @@ -123,7 +143,7 @@ heimdall:
# External Secrets Operator
externalSecretsOperator:
# Enable/disable External Secrets Operator integration
enabled: true
enabled: false

# ExternalSecret configuration
externalSecret:
Expand Down
13 changes: 5 additions & 8 deletions cmd/survey-api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,14 +286,11 @@ func loadConfig() config {

// validate checks that required configuration values are set
func (c config) validate() error {
// Only validate ITX credentials if JWT auth is not disabled (not in local dev mode)
if c.MockLocalPrincipal == "" {
if c.ITXClientID == "" {
return fmt.Errorf("ITX_CLIENT_ID is required")
}
if c.ITXPrivateKey == "" {
return fmt.Errorf("ITX_CLIENT_PRIVATE_KEY is required")
}
if c.ITXClientID == "" {
return fmt.Errorf("ITX_CLIENT_ID is required")
}
if c.ITXPrivateKey == "" {
return fmt.Errorf("ITX_CLIENT_PRIVATE_KEY is required")
}
return nil
}
Expand Down
4 changes: 2 additions & 2 deletions docs/itx-proxy-implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ JWT_AUTH_DISABLED_MOCK_LOCAL_PRINCIPAL=test-user

```bash
ITX_BASE_URL=https://api.dev.itx.linuxfoundation.org
ITX_AUTH0_DOMAIN=linuxfoundation-dev.us.auth0.com
ITX_AUTH0_DOMAIN=linuxfoundation-dev.auth0.com
ITX_CLIENT_ID=<client-id>
ITX_CLIENT_PRIVATE_KEY=<rsa-private-key-pem>
ITX_AUDIENCE=https://api.dev.itx.linuxfoundation.org/
Expand Down Expand Up @@ -575,7 +575,7 @@ app:
ITX_BASE_URL:
value: https://api.dev.itx.linuxfoundation.org
ITX_AUTH0_DOMAIN:
value: linuxfoundation-dev.us.auth0.com
value: linuxfoundation-dev.auth0.com
ITX_AUDIENCE:
value: https://api.dev.itx.linuxfoundation.org/
NATS_URL:
Expand Down
Loading