Skip to content
Closed
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
25 changes: 25 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Environment configuration template for Exosphere State Manager
# Copy this file to .env and fill in your actual values.
# NEVER commit .env with real secrets to the repository.

# MongoDB connection string (required)
MONGO_URI=mongodb+srv://username:password@cluster.example.mongodb.net/

# MongoDB database name (optional, defaults to exosphere)
MONGO_DATABASE_NAME=exosphere

# API authentication secret - generate a secure random string (required)
# Example: openssl rand -hex 32
STATE_MANAGER_SECRET=changeme

# Encryption key for secrets - generate a secure random string (required)
# Example: openssl rand -hex 32
SECRETS_ENCRYPTION_KEY=changeme

# API key for dashboard access (required)
EXOSPHERE_API_KEY=changeme

# TTL in days for runs collection (optional, defaults to 30)
# Override with RUN_TTL_DAYS for runs-specific TTL
TTL_DAYS=30
RUN_TTL_DAYS=30
29 changes: 26 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
# Ignore temp directory and temp files at repository root
/temp*
!/temp/.gitkeep
# node
node_modules/
npm-debug.log
yarn-debug.log
yarn-error.log

# env (keep .env.example tracked as a safe template)
.env
.env.local
.env.*.local
.env.backup

# python
__pycache__/
*.py[cod]
.venv/
venv/

# OS / IDE
.DS_Store
.vscode/
.idea/

# logs
*.log
logs/
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,30 @@ Create the runtime and register your nodes:

Get Exosphere running locally in under 2 minutes:

### 1. Set up environment variables

```bash
# Copy the example environment file
cp .env.example .env

# Generate secure secrets (REQUIRED!)
# For STATE_MANAGER_SECRET and EXOSPHERE_API_KEY:
openssl rand -base64 32

# For SECRETS_ENCRYPTION_KEY (must be a valid Fernet key):
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

# Edit .env and add your generated secrets
nano .env
```

> **🔒 Security Note**: Never commit `.env` file or use default secrets in production! See [SECURITY_SETUP.md](SECURITY_SETUP.md) for detailed security configuration.

### 2. Start the services

```bash
# Option 1: With cloud MongoDB (recommended)
echo "MONGO_URI=your-mongodb-connection-string" > .env
# Ensure MONGO_URI is set in your .env file
curl -O https://raw.githubusercontent.com/exospherehost/exospherehost/main/docker-compose/docker-compose.yml
docker compose up -d

Expand All @@ -248,14 +269,15 @@ docker compose -f docker-compose-with-mongodb.yml up -d

**Environment Configuration:**
- Docker Compose automatically loads `.env` files from the working directory
- Create your `.env` file in the same directory as your docker-compose file
- All secrets must be configured before starting services
- Use `.env.example` as a template - never commit `.env` to version control

Access your services:

- **Dashboard**: `http://localhost:3000`
- **API**: `http://localhost:8000`

> **📝 Note**: This configuration is for **development and testing only**. For production deployments, environment variable customization, and advanced configuration options, please read the complete **[Docker Compose Setup Guide](https://docs.exosphere.host/docker-compose-setup)**.
> **📝 Note**: This configuration requires proper environment setup. For production deployments, environment variable customization, and advanced configuration options, please read the complete **[Docker Compose Setup Guide](https://docs.exosphere.host/docker-compose-setup)** and **[Security Setup Guide](SECURITY_SETUP.md)**.

## 📚 Documentation & Resources

Expand Down
58 changes: 58 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
## Security: Configure via .env (local only). Never commit real secrets.
## Use .env.example for placeholder values and copy to .env for local runs.
services:
exosphere-state-manager:
build:
context: ./state-manager
dockerfile: Dockerfile
image: exosphere-state-manager:local
container_name: exosphere-state-manager
restart: unless-stopped
environment:
- MONGO_URI=${MONGO_URI:?MONGO_URI must be set}
- STATE_MANAGER_SECRET=${STATE_MANAGER_SECRET:?STATE_MANAGER_SECRET must be set}
- MONGO_DATABASE_NAME=${MONGO_DATABASE_NAME:-exosphere}
- SECRETS_ENCRYPTION_KEY=${SECRETS_ENCRYPTION_KEY:?SECRETS_ENCRYPTION_KEY must be set}
- TTL_DAYS=${TTL_DAYS:-30}
- RUN_TTL_DAYS=${RUN_TTL_DAYS:-30}

ports:
- "8000:8000"
networks:
- exosphere-network
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s

exosphere-dashboard:
image: ghcr.io/exospherehost/exosphere-dashboard:${EXOSPHERE_TAG:-latest}
pull_policy: always
container_name: exosphere-dashboard
restart: unless-stopped
environment:
# Server-side secure configuration (NOT exposed to browser)
- EXOSPHERE_STATE_MANAGER_URI=${EXOSPHERE_STATE_MANAGER_URI:-http://exosphere-state-manager:8000}
- EXOSPHERE_API_KEY=${EXOSPHERE_API_KEY:?EXOSPHERE_API_KEY must be set}
# Client-side configuration (exposed to browser)
- NEXT_PUBLIC_DEFAULT_NAMESPACE=${NEXT_PUBLIC_DEFAULT_NAMESPACE:-default}
depends_on:
exosphere-state-manager:
condition: service_healthy
ports:
- "3000:3000"
networks:
- exosphere-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/", "||", "exit", "1"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s

networks:
exosphere-network:
driver: bridge
attachable: true
162 changes: 162 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"mongodb": "^7.0.0"
}
}
7 changes: 6 additions & 1 deletion state-manager/app/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ class Settings(BaseModel):
secrets_encryption_key: str = Field(..., description="Key for encrypting secrets")
trigger_workers: int = Field(default=1, description="Number of workers to run the trigger cron")
trigger_retention_hours: int = Field(default=720, description="Number of hours to retain completed/failed triggers before cleanup")
ttl_days: int = Field(default=30, description="TTL in days for TTL indexes")
# Specific TTL for runs collection; overrides ttl_days when used for runs
run_ttl_days: int = Field(30, env="RUN_TTL_DAYS", description="TTL in days for runs collection")
Comment on lines +17 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

TTL settings and env fallbacks look correct; optional Pydantic simplification

ttl_days and run_ttl_days with the RUN_TTL_DAYS -> TTL_DAYS -> 30 precedence match the intended flexibility and line up with the compose defaults. The direct int(os.getenv(...)) parsing also matches how trigger_workers and trigger_retention_hours are handled.

If you later consolidate config handling, consider letting Pydantic drive env parsing (e.g., using env="TTL_DAYS" / env="RUN_TTL_DAYS" plus a custom @classmethod or validator for fallback) to centralize defaults and get more consistent error messages on bad env values, but current behavior is fine.

Also applies to: 29-31

🤖 Prompt for AI Agents
In state-manager/app/config/settings.py around lines 17-19 and 29-31,
consolidate TTL env parsing into Pydantic-driven logic: declare both fields with
env names (env="TTL_DAYS" and env="RUN_TTL_DAYS") and implement a validator or
root_validator that applies the precedence RUN_TTL_DAYS -> TTL_DAYS -> 30,
converting and validating values as ints; this centralizes parsing, avoids
manual os.getenv int casts elsewhere, and ensures clear validation errors when
env values are invalid.


@classmethod
def from_env(cls) -> "Settings":
Expand All @@ -23,7 +26,9 @@ def from_env(cls) -> "Settings":
state_manager_secret=os.getenv("STATE_MANAGER_SECRET"), # type: ignore
secrets_encryption_key=os.getenv("SECRETS_ENCRYPTION_KEY"), # type: ignore
trigger_workers=int(os.getenv("TRIGGER_WORKERS", 1)), # type: ignore
trigger_retention_hours=int(os.getenv("TRIGGER_RETENTION_HOURS", 720)) # type: ignore
trigger_retention_hours=int(os.getenv("TRIGGER_RETENTION_HOURS", 720)), # type: ignore
ttl_days=int(os.getenv("TTL_DAYS", 30)), # type: ignore
run_ttl_days=int(os.getenv("RUN_TTL_DAYS", os.getenv("TTL_DAYS", 30))) # type: ignore
)


Expand Down
Loading
Loading