diff --git a/.env.example b/.env.example index 2b64db9f..5672140d 100644 --- a/.env.example +++ b/.env.example @@ -14,6 +14,7 @@ GIT_COMMIT=local # Service Ports PORT_PDP=8082 PORT_CE=8081 +PORT_PB=8083 PORT_OE=4000 PORT_AUDIT=3001 diff --git a/cmd/pb/.env.example b/cmd/pb/.env.example index b8dea638..5d12811a 100644 --- a/cmd/pb/.env.example +++ b/cmd/pb/.env.example @@ -15,7 +15,7 @@ PDP_SERVICE_URL=http://localhost:8082 # ARGUS_API_KEY=test-audit-token # Server Configuration -PORT=3000 +PORT=8083 CORS_ALLOWED_ORIGINS=* # Set to "true" only when you need to run migrations diff --git a/cmd/pb/Dockerfile b/cmd/pb/Dockerfile index 37a55d10..4384088f 100644 --- a/cmd/pb/Dockerfile +++ b/cmd/pb/Dockerfile @@ -45,7 +45,7 @@ RUN chown -R appuser:appuser /app USER 10001 # Expose port -EXPOSE 3000 +EXPOSE 8083 # Run the application -CMD ["./pb"] \ No newline at end of file +CMD ["./pb"] diff --git a/cmd/pb/README.md b/cmd/pb/README.md index 64a1b674..6821370d 100644 --- a/cmd/pb/README.md +++ b/cmd/pb/README.md @@ -64,14 +64,14 @@ go run ./cmd/pb go build -o pb ./cmd/pb && ./pb ``` -The service runs on port 3000 by default. +The service runs on port 8083 by default. ## Configuration ### Server Configuration ```bash -PORT=3000 # Server port (default: 3000) +PORT=8083 # Server port (default: 8083) CORS_ALLOWED_ORIGINS=* # CORS allowed origins ``` @@ -195,7 +195,7 @@ Request → CORS → JWT Validation → Authorization → Resource Access docker build -t portal-backend -f cmd/pb/Dockerfile . # Run container -docker run -p 3000:3000 \ +docker run -p 8083:8083 \ -e DB_HOST=host.docker.internal \ -e PDP_SERVICE_URL=http://host.docker.internal:8082 \ --env-file cmd/pb/.env \ diff --git a/cmd/pb/docker-compose.test.yml b/cmd/pb/docker-compose.test.yml index 3dc2e4c9..e093ea7b 100644 --- a/cmd/pb/docker-compose.test.yml +++ b/cmd/pb/docker-compose.test.yml @@ -21,7 +21,7 @@ services: dockerfile: cmd/pb/Dockerfile environment: - ENVIRONMENT=test - - PORT=3000 + - PORT=8083 - DB_HOST=postgres-test - DB_PORT=5432 - DB_USERNAME=test_user @@ -29,7 +29,7 @@ services: - DB_NAME=portal_backend_test - DB_SSLMODE=disable ports: - - "3001:3000" + - "3001:8083" depends_on: postgres-test: condition: service_healthy @@ -41,7 +41,7 @@ services: "--no-verbose", "--tries=1", "--spider", - "http://localhost:3000/health", + "http://localhost:8083/health", ] interval: 10s timeout: 5s diff --git a/cmd/pb/main.go b/cmd/pb/main.go index 804fe0a7..42023f8f 100644 --- a/cmd/pb/main.go +++ b/cmd/pb/main.go @@ -290,7 +290,7 @@ func main() { // Start server port := os.Getenv("PORT") if port == "" { - port = "3000" + port = "8083" } addr := ":" + port diff --git a/cmd/pb/openapi.yaml b/cmd/pb/openapi.yaml index b6666bc4..942356a1 100644 --- a/cmd/pb/openapi.yaml +++ b/cmd/pb/openapi.yaml @@ -35,7 +35,7 @@ servers: description: Choreo Production Environment - url: https://portal-backend-dev.choreo.dev description: Choreo Development Environment - - url: http://localhost:3000 + - url: http://localhost:8083 description: Local Development Environment paths: diff --git a/compose.yml b/compose.yml index c7cc9dd1..7cc2bfc2 100644 --- a/compose.yml +++ b/compose.yml @@ -26,7 +26,7 @@ services: - postgres-data:/var/lib/postgresql/data - ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-exchange} ${DB_NAME:-postgres}"] + test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-exchange} -d ${DB_NAME:-postgres}"] interval: 5s timeout: 5s retries: 10 @@ -227,6 +227,62 @@ services: networks: - openndx-network + portal-backend: + build: + context: . + dockerfile: cmd/pb/Dockerfile + container_name: pb-${ENVIRONMENT:-local} + ports: + - "${PORT_PB:-8083}:8083" + environment: + - PORT=8083 + - CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS:-*} + # Database configuration + - DB_HOST=${DB_HOST:-postgres} + - DB_PORT=${DB_PORT:-5432} + - DB_USERNAME=${DB_USER:-exchange} + - DB_PASSWORD=${DB_PASSWORD:-exchange} + - DB_NAME=${DB_NAME_PB:-portal_backend} + - DB_SSLMODE=${DB_SSLMODE:-disable} + - RUN_MIGRATION=${RUN_MIGRATION:-true} + - PDP_SERVICE_URL=http://policy-decision-point:8082 + # IDP configuration for validating incoming JWTs (ndx CLI, portal frontends). + # IDP_ISSUER must match ThunderID's externally-visible public_url (the `iss` + # claim it stamps into tokens) — NOT the container-network address below, + # which is only used to actually reach the JWKS endpoint from inside the + # compose network. + - IDP_ISSUER=${IDP_PUBLIC_URL:-https://localhost:8090} + - IDP_JWKS_URL=https://thunderid:8090/oauth2/jwks + - IDP_JWKS_INSECURE_SKIP_VERIFY=${IDP_JWKS_INSECURE_SKIP_VERIFY:-true} + - IDP_ADMIN_PORTAL_CLIENT_ID=${NDX_CLI_CLIENT_ID:-NDX_CLI} + # PB's own outbound calls to the IDP (creating application/user records — + # POST /applications, POST /members) go through idpfactory, which only + # implements the Asgardeo (WSO2) admin API today — see + # docs/DESIGN-esignet-citizen-authentication.md §3.1 and + # internal/pb/idp/idpfactory/factory.go. These vars only need to be + # non-empty for PB to boot; against ThunderID those specific endpoints + # (create application/member) will still fail, since ThunderID's admin + # API isn't Asgardeo-shaped. Everything else (list/get applications, + # the policy-update endpoint the ndx CLI uses) doesn't call the IDP at + # all and works fine. + - IDP_BASE_URL=https://thunderid:8090 + - IDP_CLIENT_ID=${NDX_CLI_CLIENT_ID:-NDX_CLI} + - IDP_CLIENT_SECRET=${IDP_CLIENT_SECRET:-unused-thunderid-has-no-secret} + # Authorization + - AUTHORIZATION_MODE=${AUTHORIZATION_MODE:-fail_open_admin_system} + - AUTHORIZATION_STRICT_MODE=${AUTHORIZATION_STRICT_MODE:-false} + # Audit (optional, degrades gracefully if unreachable) + - AUDIT_SERVICE_URL=${AUDIT_SERVICE_URL:-http://audit-service:3001} + - ARGUS_API_KEY=${ARGUS_API_KEY:-test-audit-token} + depends_on: + postgres: + condition: service_healthy + thunderid: + condition: service_healthy + restart: unless-stopped + networks: + - openndx-network + audit-service: build: context: https://github.com/LSFLK/argus.git#v1.0.1 diff --git a/init-db.sql b/init-db.sql index 41f3dfd1..8e0bb47b 100644 --- a/init-db.sql +++ b/init-db.sql @@ -10,3 +10,4 @@ SELECT 'CREATE DATABASE pdp' WHERE NOT EXISTS (SELECT FROM pg_database WHERE dat SELECT 'CREATE DATABASE consent_engine' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'consent_engine')\gexec SELECT 'CREATE DATABASE orchestration_engine' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'orchestration_engine')\gexec SELECT 'CREATE DATABASE audit' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'audit')\gexec +SELECT 'CREATE DATABASE portal_backend' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'portal_backend')\gexec diff --git a/observability/README.md b/observability/README.md index 6ee6a845..40436932 100644 --- a/observability/README.md +++ b/observability/README.md @@ -14,7 +14,7 @@ Collects real-time metrics from all Go services for debugging performance and er │ ┌──────────────┐ ┌───────────────┐ ┌──────────────┐ │ │ │ Portal │ │ Orchestration │ │ Policy │ ... │ │ │ Backend │ │ Engine │ │ Decision │ │ -│ │ :3000 │ │ :4000 │ │ Point :8082 │ │ +│ │ :8083 │ │ :4000 │ │ Point :8082 │ │ │ └──────┬───────┘ └───────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ │ └──────────────────┴─────────────────┘ │ @@ -94,7 +94,7 @@ Ensure all Go services are running and connected to the `openndx-network`: - Orchestration Engine (port 4000) - Consent Engine (port 8081) - Policy Decision Point (port 8082) -- Portal Backend (port 3000) +- Portal Backend (port 8083) --- @@ -279,13 +279,13 @@ To populate the Grafana dashboard with metrics, generate sample traffic: ./generate_sample_traffic.sh ``` -This sends requests to various endpoints on `portal-backend` (default: `http://localhost:3000`). +This sends requests to various endpoints on `portal-backend` (default: `http://localhost:8083`). ### Configuration ```bash # Change the base URL -PORTAL_BACKEND_URL=http://localhost:3000 ./generate_sample_traffic.sh +PORTAL_BACKEND_URL=http://localhost:8083 ./generate_sample_traffic.sh # Change request interval (default: 2 seconds) REQUEST_INTERVAL=5 ./generate_sample_traffic.sh @@ -476,7 +476,7 @@ Services automatically initialize OpenTelemetry metrics when first used. No expl 1. Check that metrics are initialized: - Look for log messages: "Initialized OpenTelemetry metrics with..." - - Check `/metrics` endpoint returns data: `curl http://localhost:3000/metrics` + - Check `/metrics` endpoint returns data: `curl http://localhost:8083/metrics` 2. For OTLP exporter: - Verify `OTEL_EXPORTER_OTLP_ENDPOINT` is set correctly diff --git a/observability/prometheus/prometheus.yml b/observability/prometheus/prometheus.yml index 6c312b59..17a6e6e8 100644 --- a/observability/prometheus/prometheus.yml +++ b/observability/prometheus/prometheus.yml @@ -39,8 +39,8 @@ scrape_configs: metrics_path: /metrics static_configs: - targets: - - portal-backend:3000 + - portal-backend:8083 labels: service: 'portal-backend' - port: '3000' + port: '8083' diff --git a/portals/apps/admin/.env.example b/portals/apps/admin/.env.example index 7ad74c6f..af453da4 100644 --- a/portals/apps/admin/.env.example +++ b/portals/apps/admin/.env.example @@ -26,7 +26,7 @@ VITE_PORT=5173 VITE_BASE_PATH=/ # --- Runtime (window.configs - see entrypoint.sh / public/config.js) --- -VITE_API_URL=http://localhost:3000 +VITE_API_URL=http://localhost:8083 VITE_LOGS_URL=http://localhost:3001 VITE_IDP_CLIENT_ID=your_client_id VITE_IDP_BASE_URL=https://api.asgardeo.io/t/your-org diff --git a/portals/apps/admin/README.md b/portals/apps/admin/README.md index e9609a00..b030eef8 100644 --- a/portals/apps/admin/README.md +++ b/portals/apps/admin/README.md @@ -58,18 +58,18 @@ The Admin Portal has two independent configuration layers: cp .env.example .env ``` -| Variable | Type | Example / Default | Description | -|---|---|---|---| -| `VITE_PORT` | Build-time | `5173` | Local dev server port | -| `VITE_BASE_PATH` | Build-time | `/` | Public base path Vite serves the app under | -| `VITE_API_URL` | Runtime | `http://localhost:3000` | Portal Backend API base URL | -| `VITE_LOGS_URL` | Runtime | `http://localhost:3001` | Audit Service base URL (audit log viewer) | -| `VITE_IDP_CLIENT_ID` | Runtime | `your_client_id` | IdP (Asgardeo) application client ID | -| `VITE_IDP_BASE_URL` | Runtime | `https://api.asgardeo.io/t/your-org` | IdP (Asgardeo) base URL | -| `VITE_IDP_SCOPE` | Runtime | `openid,profile` | Comma-separated OAuth scopes | -| `VITE_IDP_ADMIN_ROLE` | Runtime | `admin` | Role required to access the Admin Portal | -| `VITE_SIGN_IN_REDIRECT_URL` | Runtime | `http://localhost:5173` | OIDC sign-in redirect URL | -| `VITE_SIGN_OUT_REDIRECT_URL` | Runtime | `http://localhost:5173` | OIDC sign-out redirect URL | +| Variable | Type | Example / Default | Description | +|------------------------------|------------|--------------------------------------|--------------------------------------------| +| `VITE_PORT` | Build-time | `5173` | Local dev server port | +| `VITE_BASE_PATH` | Build-time | `/` | Public base path Vite serves the app under | +| `VITE_API_URL` | Runtime | `http://localhost:8083` | Portal Backend API base URL | +| `VITE_LOGS_URL` | Runtime | `http://localhost:3001` | Audit Service base URL (audit log viewer) | +| `VITE_IDP_CLIENT_ID` | Runtime | `your_client_id` | IdP (Asgardeo) application client ID | +| `VITE_IDP_BASE_URL` | Runtime | `https://api.asgardeo.io/t/your-org` | IdP (Asgardeo) base URL | +| `VITE_IDP_SCOPE` | Runtime | `openid,profile` | Comma-separated OAuth scopes | +| `VITE_IDP_ADMIN_ROLE` | Runtime | `admin` | Role required to access the Admin Portal | +| `VITE_SIGN_IN_REDIRECT_URL` | Runtime | `http://localhost:5173` | OIDC sign-in redirect URL | +| `VITE_SIGN_OUT_REDIRECT_URL` | Runtime | `http://localhost:5173` | OIDC sign-out redirect URL | ### Testing runtime configuration locally @@ -85,7 +85,7 @@ or create `portals/apps/admin/public/config.js` by hand: ```js window.configs = { - VITE_API_URL: 'http://localhost:3000', + VITE_API_URL: 'http://localhost:8083', VITE_LOGS_URL: 'http://localhost:3001', VITE_IDP_CLIENT_ID: 'your_client_id', VITE_IDP_BASE_URL: 'https://api.asgardeo.io/t/your-org', @@ -114,7 +114,7 @@ docker build -t admin-portal -f apps/admin/Dockerfile . # Run container docker run -p 5173:80 \ - -e VITE_API_URL=http://localhost:3000 \ + -e VITE_API_URL=http://localhost:8083 \ -e VITE_LOGS_URL=http://localhost:3001 \ -e VITE_IDP_CLIENT_ID=your_client_id \ -e VITE_IDP_BASE_URL=https://api.asgardeo.io/t/your-org \ diff --git a/portals/apps/member/.env.example b/portals/apps/member/.env.example index 79a03f18..0b6af33b 100644 --- a/portals/apps/member/.env.example +++ b/portals/apps/member/.env.example @@ -17,7 +17,7 @@ VITE_PORT=5173 VITE_BASE_PATH=/ # --- Runtime (window.configs - see entrypoint.sh / public/config.js) --- -VITE_API_URL=http://localhost:3000 +VITE_API_URL=http://localhost:8083 VITE_LOGS_URL=http://localhost:3001 VITE_CLIENT_ID=your_client_id VITE_BASE_URL=https://api.asgardeo.io/t/your-org diff --git a/portals/apps/member/README.md b/portals/apps/member/README.md index 17f7581f..3f7068cf 100644 --- a/portals/apps/member/README.md +++ b/portals/apps/member/README.md @@ -60,7 +60,7 @@ cp .env.example .env |------------------------------|------------|--------------------------------------|--------------------------------------------| | `VITE_PORT` | Build-time | `5173` | Local dev server port | | `VITE_BASE_PATH` | Build-time | `/` | Public base path Vite serves the app under | -| `VITE_API_URL` | Runtime | `http://localhost:3000` | Portal Backend API base URL | +| `VITE_API_URL` | Runtime | `http://localhost:8083` | Portal Backend API base URL | | `VITE_LOGS_URL` | Runtime | `http://localhost:3001` | Audit Service base URL (audit log viewer) | | `VITE_CLIENT_ID` | Runtime | `your_client_id` | IdP (Asgardeo) application client ID | | `VITE_BASE_URL` | Runtime | `https://api.asgardeo.io/t/your-org` | IdP (Asgardeo) base URL | @@ -75,7 +75,7 @@ cp .env.example .env ```js window.configs = { - API_URL: 'http://localhost:3000', + API_URL: 'http://localhost:8083', LOGS_URL: 'http://localhost:3001', CLIENT_ID: 'your_client_id', BASE_URL: 'https://api.asgardeo.io/t/your-org', @@ -103,7 +103,7 @@ docker build -t member-portal -f apps/member/Dockerfile . # Run container docker run -p 5173:80 \ - -e VITE_API_URL=http://localhost:3000 \ + -e VITE_API_URL=http://localhost:8083 \ -e VITE_LOGS_URL=http://localhost:3001 \ -e VITE_CLIENT_ID=your_client_id \ -e VITE_BASE_URL=https://api.asgardeo.io/t/your-org \ diff --git a/portals/setup-portals.sh b/portals/setup-portals.sh index 35d80a6b..77a6dbf4 100755 --- a/portals/setup-portals.sh +++ b/portals/setup-portals.sh @@ -15,7 +15,7 @@ BLUE='\033[0;34m' NC='\033[0m' # Test configuration values (can be overridden via environment variables) -TEST_API_URL="${TEST_API_URL:-http://localhost:3000}" +TEST_API_URL="${TEST_API_URL:-http://localhost:8083}" TEST_LOGS_URL="${TEST_LOGS_URL:-http://localhost:3001}" TEST_CLIENT_ID="${TEST_CLIENT_ID:-test-client-id-123}" TEST_BASE_URL="${TEST_BASE_URL:-https://api.asgardeo.io/t/test-org}" diff --git a/tests/integration/README.md b/tests/integration/README.md index 8dc9a04e..03050da1 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -171,7 +171,7 @@ The `docker-compose.test.yml` starts: - **Policy Decision Point** (8082) - Policy evaluation service - **Consent Engine** (8081) - Consent management service - **Orchestration Engine** (4000) - GraphQL orchestration service -- **Portal Backend** (3000) - Admin portal backend +- **Portal Backend** (8083) - Admin portal backend All services run on `test-network` Docker network.