# SPDX-License-Identifier: GPL-2.0-only # Project: AstraDesk # File: .env.example # Website: https://www.astradesk.dev # Repository: https://github.com/SSobol77/astradesk # # Description: Implements AstraDesk functionality for .env.example. # # Copyright (c) 2026 Siergej Sobolewski # # This file is part of AstraDesk. # # AstraDesk is licensed under the GNU General Public License version 2 only. # See the LICENSE file in the project root for the full license text. # ============================================================================= # AstraDesk Environment Example # Copy this file to `.env` and fill in the values that apply to your setup. # # Each section groups variables by the service/module that consumes them so you # can tell at a glance which component needs the value. # ============================================================================= # ----------------------------------------------------------------------------- # Global / Shared Settings # ----------------------------------------------------------------------------- # Generic log level used by multiple services (Python API, auditor, etc.). LOG_LEVEL=INFO # Deployment tier. Drives fail-closed startup checks shared by the OIDC # ingress verifier (ISSUE 009) and the durable audit sink (ISSUE 019). # Defaults to "production" when unset — the safe default is deployed-tier # behavior, not local convenience. One of: production/prod/staging/stage # (deployed — requires real OIDC config and AUDIT_LOG_PATH) or # development/dev/test/local/ci (non-deployed — local-dev auth mode allowed). ENVIRONMENT=dev # Event bus address shared by the API gateway and the auditor stream processor. NATS_URL=nats://localhost:4222 # ISSUE 028 fail-closed policy choke point (services/api-gateway/src/runtime/policy_enforcer.py). # POLICY_MODE selects the enforcer: 'opa' (real OPA server, any tier), 'local' # (deterministic allow-all; refused on a deployed tier), or unset (safe # default — deployed tiers require OPA, same fail-closed default as # ENVIRONMENT above; non-deployed tiers use the local mode). POLICY_MODE= # Open Policy Agent URL used by the API gateway for authorization decisions. # Required (and startup aborts if missing) whenever POLICY_MODE=opa, or on a # deployed tier under the default POLICY_MODE. OPA_URL=http://localhost:8181 # Rego data path queried for the allow decision (POST {OPA_URL}/v1/data/{path}). OPA_POLICY_PATH=astradesk/tools/allow # Per-request timeout (seconds) for the OPA policy check; a timeout is a # fail-closed deny, not a fail-open allow. OPA_TIMEOUT_SECONDS=2.0 # LLM provider selector for services/api-gateway (openai | bedrock | vllm). MODEL_PROVIDER=openai # Runtime policy loading for services/api-gateway/src/runtime/policy.py. POLICY_JSON= POLICY_FILE= POLICY_TTL_SECONDS=300 # Kubernetes namespace used by packages/domain-ops/tools/actions.py. KUBERNETES_NAMESPACE=default # ----------------------------------------------------------------------------- # API Gateway (services/api-gateway — FastAPI) # ----------------------------------------------------------------------------- # Primary data stores. DATABASE_URL=postgresql://astradesk:astrapass@localhost:5432/astradesk REDIS_URL=redis://localhost:6379/0 # Admin API proxy configuration. ADMIN_API_URL=http://localhost:8080/api/admin/v1 # Metrics endpoint consumed by tools/metrics.py. MONITORING_API_URL=http://localhost:9090 # Ticket adapter proxy configuration consumed by tools/tickets_proxy.py. TICKETS_BASE_URL=http://localhost:8082 TICKETS_API_TOKEN= TICKETS_DISABLE_STUB=false SERVICE_CERT=/etc/istio/certs/cert-chain.pem SERVICE_KEY=/etc/istio/certs/key.pem ROOT_CA=/etc/istio/certs/ca-cert.pem # Optional integrations exposed through API tools. WEATHER_API_KEY= # Durable audit sink for side-effecting (write/execute) tool calls # (ISSUE 019/039), selected by AUDIT_MODE. # # AUDIT_MODE=jsonl (default when unset): append-only JSON-Lines file at # AUDIT_LOG_PATH. On ENVIRONMENT in {production, prod, staging, stage} # (ENVIRONMENT defaults to "production" when unset, matching the OIDC # fail-closed default) AUDIT_LOG_PATH is REQUIRED in this mode: startup # aborts with AuditConfigError if it is missing, so a deployed tier can # never silently run without a durable audit trail. Outside a deployed tier # (e.g. ENVIRONMENT=dev for local/CI), leaving it unset falls back to a # non-durable in-process writer with a startup warning — fine for # tests/dev, never for production (INV-LOCAL-MODE-EXPLICIT). # # AUDIT_MODE=jetstream: durable NATS JetStream sink (ISSUE 039). A # side-effecting tool call is not reported successful until the audit event # is acknowledged as durably stored by JetStream; if the JetStream broker is # unreachable or does not acknowledge within AUDIT_PUBLISH_TIMEOUT_MS (after # AUDIT_PUBLISH_RETRIES retries and a best-effort DLQ publish), the tool call # fails closed with AuditWriteError instead of running unaudited. Explicit # and non-default on every tier, including dev — set it only where a real # NATS JetStream broker (see NATS_URL above) is actually available. The # consumer that persists these events to Elasticsearch/S3 is the Auditor # Service; see its section below for the matching AUDIT_JETSTREAM_* values # and its own consumer-only settings. AUDIT_MODE=jsonl AUDIT_LOG_PATH= # AUDIT_MODE=jetstream only. AUDIT_NATS_URL falls back to NATS_URL (above) # when unset, so it only needs to be set if the audit stream lives on a # different NATS deployment than the general event bus. AUDIT_NATS_URL= AUDIT_JETSTREAM_STREAM=ASTRADESK_AUDIT AUDIT_JETSTREAM_SUBJECT=astradesk.audit AUDIT_JETSTREAM_DLQ_SUBJECT=astradesk.audit.dlq # Bounded publish timeout/retries so a broker outage fails closed quickly # instead of hanging the side-effecting tool call indefinitely. AUDIT_PUBLISH_TIMEOUT_MS=2000 AUDIT_PUBLISH_RETRIES=2 # --- LLM Provider Configuration (services/api-gateway/model_gateway) --- OPENAI_API_KEY= OPENAI_BASE_URL=https://api.openai.com/v1 OPENAI_MODEL=gpt-4o-mini OPENAI_TIMEOUT_SEC=30 BEDROCK_MODEL_ID=anthropic.claude-3-sonnet-v1 AWS_REGION=us-east-1 VLLM_BASE_URL=http://localhost:8000/v1 VLLM_MODEL=meta-llama/Llama-3-8B-Instruct VLLM_API_KEY= VLLM_TIMEOUT_SEC=60 # ----------------------------------------------------------------------------- # OIDC / JWT Ingress Verification (ISSUE 009) # core/src/astradesk_core/utils/oidc.py, wired at API Gateway startup via # gateway/auth_dependency.install_verifier() (services/api-gateway/src/gateway/main.py). # # The same variables independently configure the Admin API's own verifier # (services/admin_api/src/astradesk_admin/auth.py, NEW-SEC): the API Gateway's # /api/admin/v1/{path} proxy requires an authenticated 'admin' principal # before forwarding, and the Admin API independently re-verifies the same # bearer token rather than trusting the proxy or network placement # (defense-in-depth). Set these identically for both services in production. # ----------------------------------------------------------------------------- # AUTH_MODE selects the verifier. Defaults to "production" (JWKS/RS256 — # the only verifier deployed tiers may use). "local-dev" is the sole # non-default, explicitly-named local convenience (INV-LOCAL-MODE-EXPLICIT); # it is refused at startup (AuthConfigError) whenever ENVIRONMENT is a # deployed tier (production/prod/staging/stage). AUTH_MODE=local-dev # Required in AUTH_MODE=production (i.e. every deployed tier). Startup # aborts with AuthConfigError before DB/Redis/RAG initialization if any is # missing on a deployed tier. OIDC_ISSUER=https://your-issuer.example.com/ OIDC_AUDIENCE=astradesk-api OIDC_JWKS_URL=https://your-issuer.example.com/.well-known/jwks.json # Optional production-verifier tuning (defaults shown). OIDC_ALGORITHMS=RS256 OIDC_LEEWAY_SECONDS=30 OIDC_JWKS_CACHE_TTL=600 # OIDC_ROLES_CLAIM: claim holding the caller's roles (dotted paths supported, # e.g. "realm_access.roles" for Keycloak). For /api/admin/v1/* (Gateway) and # every Admin API operation except /health and /docs|/redoc|/openapi.json # (NEW-SEC), this list must contain "admin" (case-insensitive) or the # request is rejected with 403. OIDC_ROLES_CLAIM=roles OIDC_SCOPE_CLAIM=scope OIDC_REQUIRED_SCOPES= # AUTH_MODE=local-dev only: symmetric HS256 secret for locally-minted test # tokens. Never set/used on a deployed tier; unrelated to the JWKS keys above. ASTRADESK_DEV_JWT_SECRET=change-me-local-dev-only # ----------------------------------------------------------------------------- # Admin Portal (services/admin-portal — Next.js) # ----------------------------------------------------------------------------- NEXT_PUBLIC_API_BASE_URL=http://localhost:8080/api/admin/v1 NEXT_PUBLIC_SIMULATION_MODE=false # Server-side bearer tokens the Admin Portal attaches as # `Authorization: Bearer ` when calling the Gateway's /api/admin/v1 # proxy (src/api/client.ts uses ASTRADESK_API_TOKEN; src/clients/adminApi.ts # uses ADMIN_API_TOKEN — two existing client wrappers, same target route). # Since NEW-SEC, both the Gateway proxy and the Admin API independently # require a verified Bearer JWT whose role claim includes 'admin' — set # these to a real OIDC-issued admin-scoped token (or a locally-minted # AUTH_MODE=local-dev token for dev). An arbitrary string is no longer # accepted: it is rejected with 401 (invalid token) or 403 (missing 'admin' # role) at both layers. ASTRADESK_API_TOKEN= ADMIN_API_TOKEN= # Front-channel OIDC for the Admin Portal's browser session (ISSUE 021, # services/admin-portal/lib/auth/). Distinct from the server-side tokens # above: this is what lets each signed-in admin's own OIDC access token flow # into client-side Admin API calls (`Authorization: Bearer `), # instead of every browser sharing one static token. Unset means admin login # is unconfigured and the portal's protected views stay blocked (fail-closed) # outside NEXT_PUBLIC_SIMULATION_MODE=true. See # services/admin-portal/.env.example for the full set of NEXT_PUBLIC_OIDC_* # variables and their defaults; the same OIDC_ISSUER/OIDC_AUDIENCE realm as # above is typically reused, with a separate public/SPA client registration. NEXT_PUBLIC_OIDC_ISSUER= NEXT_PUBLIC_OIDC_CLIENT_ID= NEXT_PUBLIC_OIDC_AUDIENCE= NEXT_PUBLIC_OIDC_REDIRECT_URI=http://localhost:3000/callback # Optional override for the OpenAPI spec used by tooling scripts. ASTRA_OPENAPI_SPEC= # ----------------------------------------------------------------------------- # Auditor Service (services/auditor — async worker, ISSUE 039) # ----------------------------------------------------------------------------- # Consumes audit events from a NATS JetStream durable pull consumer and # persists them to S3/Elasticsearch, acking each batch only after both sinks # durably accept it. AUDIT_JETSTREAM_STREAM/SUBJECT/DLQ_SUBJECT must match # the API Gateway's producer-side values above — the two services share one # JetStream stream. A crash between fetch and ack loses nothing: nothing is # buffered only in this process's memory, so JetStream redelivers the # unacked batch to the next consumer instance under the same durable name. S3_BUCKET=astradesk-audit ES_URL=http://localhost:9200 ES_INDEX=astradesk-audit AUDIT_JETSTREAM_STREAM=ASTRADESK_AUDIT AUDIT_JETSTREAM_SUBJECT=astradesk.audit AUDIT_JETSTREAM_DLQ_SUBJECT=astradesk.audit.dlq AUDIT_JETSTREAM_DURABLE_CONSUMER=astradesk-auditor AUDIT_FETCH_BATCH_SIZE=100 AUDIT_FETCH_TIMEOUT_SEC=5 # Bounded sink-persist retries before a batch is routed to the DLQ subject # instead of being retried forever or dropped (INV-AUD-3). AUDIT_SINK_RETRIES=3 AUDIT_SINK_RETRY_BACKOFF_SEC=1 # How long JetStream waits for an ack before redelivering an unacked message # to another consumer instance (crash-recovery window). AUDIT_ACK_WAIT_SEC=30 # ----------------------------------------------------------------------------- # Ticket Adapter (services/ticket-adapter-java — Spring WebFlux) # ----------------------------------------------------------------------------- # Database connectivity (R2DBC + legacy JDBC fallbacks used by gradle bootRun). MYSQL_URL=jdbc:mysql://localhost:3306/tickets?useSSL=false MYSQL_URL_R2DBC=r2dbc:mysql://localhost:3306/tickets MYSQL_USER=tickets MYSQL_PASSWORD=tickets MYSQL_DATABASE=tickets # Spring configuration properties (application.yml) for ticket storage. TICKET_DB_R2DBC_URL=r2dbc:mysql://localhost:3306/tickets TICKET_DB_USER=tickets TICKET_DB_PASSWORD=tickets # External integrations configured via integration.* properties. FRONTEND_BASE_URL=http://localhost:5173 JIRA_ENABLED=false JIRA_BASE_URL=https://example.atlassian.net JIRA_USERNAME=jira-bot@example.com JIRA_API_TOKEN= JIRA_PROJECT_KEY=ASTRA JIRA_ISSUE_TYPE=Task JIRA_DEFAULT_PRIORITY=Medium SLACK_ENABLED=false SLACK_WEBHOOK_URL= SLACK_DEFAULT_CHANNEL= # ----------------------------------------------------------------------------- # Domain Packs & External Tools (packages/domain-*) # ----------------------------------------------------------------------------- # Generic Admin API credentials used by sample domain pack adapters and gRPC tools. API_URL=http://localhost:8080/api/admin/v1 API_TOKEN= API_PORT=8080 PYTHONPATH=/app/src # Ensure src is in PYTHONPATH