{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "name": { "type": "string", "maxLength": 63, "pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$" }, "host": { "type": "string", "maxLength": 200, "pattern": "^([a-z][a-z0-9]*(-[a-z0-9]+)*\\.)?pharos$" }, "profile": { "enum": [ "pharos", "platform", "aai", "storage", "argocd", "gitlab", "waldur", "themelio-compat", "pharos-site", "llm-chat", "llm-api", "zammad", "kserve", "kubeflow", "llm-inference", "mcp" ] }, "backend": { "type": "object", "additionalProperties": false, "required": [ "namespace", "service", "port", "protocol" ], "properties": { "namespace": { "$ref": "#/$defs/name" }, "service": { "$ref": "#/$defs/name" }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "protocol": { "enum": [ "http", "https" ] }, "tls": { "type": "object", "additionalProperties": false, "required": [ "trust", "sni" ], "properties": { "trust": { "$ref": "#/$defs/name" }, "sni": { "type": "string", "maxLength": 253, "pattern": "^[a-z0-9]([-a-z0-9.]*[a-z0-9])?$" }, "subjectAltName": { "type": "string", "maxLength": 253, "pattern": "^[a-z0-9]([-a-z0-9.]*[a-z0-9])?$" } } } }, "allOf": [ { "if": { "properties": { "protocol": { "const": "https" } }, "required": [ "protocol" ] }, "then": { "required": [ "tls" ] } }, { "if": { "properties": { "protocol": { "const": "http" } }, "required": [ "protocol" ] }, "then": { "properties": { "tls": false } } } ] }, "service": { "type": "object", "additionalProperties": false, "required": [ "host", "path", "profile", "gateway", "access", "transport", "backend", "websocket", "timeout" ], "properties": { "host": { "$ref": "#/$defs/host" }, "path": { "type": "string", "pattern": "^(/([a-z][a-z0-9-]*/)*([a-z][a-z0-9-]*)?|/\\.well-known/oauth-protected-resource/mcp)$" }, "profile": { "$ref": "#/$defs/profile" }, "gateway": { "$ref": "#/$defs/name" }, "access": { "enum": [ "public", "management" ] }, "transport": { "enum": [ "http", "grpc" ] }, "backend": { "$ref": "#/$defs/backend" }, "websocket": { "type": "boolean" }, "timeout": { "type": "string", "pattern": "^[1-9][0-9]{0,3}s$" }, "rewrite": { "type": "object", "additionalProperties": false, "required": [ "uri" ], "properties": { "uri": { "type": "string", "pattern": "^/[a-z0-9._~/-]*$" }, "forwarded_prefix": { "type": "string", "pattern": "^/[a-z0-9._~/-]*$" } } }, "body": { "type": "object", "additionalProperties": false, "required": [ "limit", "buffering" ], "properties": { "limit": { "type": "string", "pattern": "^(0|[1-9][0-9]{0,4}[km]?)$" }, "buffering": { "type": "boolean" } } }, "git": { "const": { "service": "gitlab" } }, "auth": { "type": "object", "additionalProperties": false, "required": [ "provider", "identityHeaders" ], "properties": { "provider": { "$ref": "#/$defs/name" }, "identityHeaders": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "enum": [ "kubeflow-userid", "x-auth-request-user" ] } }, "notPaths": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "pattern": "^/([a-z][a-z0-9-]*/)*([a-z][a-z0-9-]*)?$" } } } } } }, "catalogue": { "type": "object", "additionalProperties": false, "required": [ "version", "namespaces", "gateways", "services" ], "properties": { "version": { "const": 1 }, "namespaces": { "type": "object", "minProperties": 1, "propertyNames": { "$ref": "#/$defs/name" }, "additionalProperties": { "type": "object", "additionalProperties": false, "required": [ "mesh" ], "properties": { "mesh": { "const": false } } } }, "gateways": { "type": "object", "minProperties": 1, "propertyNames": { "$ref": "#/$defs/name" }, "additionalProperties": { "type": "object", "additionalProperties": false, "required": [ "namespace" ], "properties": { "namespace": { "$ref": "#/$defs/name" } } } }, "services": { "type": "object", "minProperties": 1, "propertyNames": { "$ref": "#/$defs/name" }, "additionalProperties": { "$ref": "#/$defs/service" } } } }, "environment": { "type": "object", "additionalProperties": false, "required": [ "version", "domain", "edge", "access", "profiles", "routes", "routing" ], "properties": { "version": { "const": 1 }, "domain": { "type": [ "string", "null" ], "pattern": "^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$" }, "edge": { "type": "object", "additionalProperties": false, "required": [ "mode", "port" ], "properties": { "mode": { "enum": [ "dev-ca", "public-cert" ] }, "port": { "enum": [ 443, 8443 ] }, "block_indexing": { "type": "boolean" }, "sources": { "type": "array", "uniqueItems": true, "items": { "type": "string", "maxLength": 43, "pattern": "^[0-9a-f:.]+/[0-9]{1,3}$" } } } }, "routing": { "type": "object", "additionalProperties": false, "required": [ "mode", "node_port" ], "properties": { "mode": { "enum": [ "nodeports", "istio" ] }, "node_port": { "type": "integer", "minimum": 30000, "maximum": 32767 } } }, "access": { "type": "object", "additionalProperties": false, "required": [ "management" ], "properties": { "management": { "type": "array", "uniqueItems": true, "items": { "type": "string", "maxLength": 50 } }, "services": { "description": "A profile's own source rule (#1123): every route of the profile admits only these networks, except the listed path prefixes, which stay open to everyone. The management list is not involved.", "type": "object", "propertyNames": { "enum": [ "gitlab", "waldur" ] }, "additionalProperties": { "type": "object", "additionalProperties": false, "required": [ "cidrs" ], "properties": { "cidrs": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "maxLength": 50 } }, "public_paths": { "type": "array", "uniqueItems": true, "items": { "type": "string", "pattern": "^/[a-z0-9][a-z0-9-]{0,62}/$" } } } } } } }, "profiles": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/profile" } }, "routes": { "type": "object", "minProperties": 1, "propertyNames": { "$ref": "#/$defs/name" }, "additionalProperties": { "type": "object", "additionalProperties": false, "required": [ "enabled" ], "properties": { "enabled": { "type": "boolean" }, "node_port": { "type": "integer", "minimum": 30000, "maximum": 32767 } } } }, "hosts": { "type": "object", "additionalProperties": false, "properties": { "pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "web.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "platform.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "api.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "site.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "ceph.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "argo.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "gitlab.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "waldur.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "themelio-compat.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "open-webui.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "llm-api.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "kubeflow.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } }, "zammad.pharos": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$", "not": { "pattern": "(^|\\.)(sslip\\.io|localtest\\.me|localhost|invalid)$" } } } }, "browser_hosts": { "type": "object", "default": {}, "additionalProperties": false, "properties": { "web.pharos": { "const": "platform.localtest.me" }, "api.pharos": { "const": "api.localtest.me" }, "platform.pharos": { "const": "platform.localtest.me" }, "themelio-compat.pharos": { "const": "themelio.localtest.me" }, "gitlab.pharos": { "const": "gitlab.localtest.me" }, "waldur.pharos": { "const": "waldur.localtest.me" }, "argo.pharos": { "const": "argo.localtest.me" }, "ceph.pharos": { "const": "ceph.localtest.me" }, "open-webui.pharos": { "const": "open-webui.localtest.me" }, "zammad.pharos": { "const": "zammad.localtest.me" }, "kubeflow.pharos": { "const": "kubeflow.localtest.me" }, "mcp.pharos": { "const": "mcp.localtest.me" } } }, "serving": { "type": "object", "additionalProperties": false, "required": [ "domain" ], "properties": { "domain": { "type": "string", "maxLength": 200, "pattern": "^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" } } } }, "allOf": [ { "if": { "properties": { "edge": { "properties": { "mode": { "const": "dev-ca" } } } } }, "then": { "properties": { "domain": { "const": "127.0.0.1.sslip.io" }, "edge": { "properties": { "port": { "const": 8443 } } }, "hosts": { "maxProperties": 0 }, "profiles": { "contains": { "const": "aai" } }, "browser_hosts": { "minProperties": 7 } }, "required": [ "browser_hosts" ] } }, { "if": { "properties": { "edge": { "properties": { "mode": { "const": "public-cert" } } } } }, "then": { "required": [ "hosts" ], "properties": { "edge": { "properties": { "port": { "const": 443 } } }, "hosts": { "minProperties": 1 }, "profiles": { "not": { "contains": { "const": "aai" } } }, "domain": { "const": null }, "browser_hosts": { "maxProperties": 0 } } } } ] }, "extension": { "type": "object", "additionalProperties": false, "required": [ "version", "name", "namespace", "routes" ], "properties": { "version": { "const": 1 }, "name": { "$ref": "#/$defs/name" }, "namespace": { "$ref": "#/$defs/name" }, "routes": { "type": "object", "minProperties": 1, "propertyNames": { "$ref": "#/$defs/name" }, "additionalProperties": { "$ref": "#/$defs/extension_route" } } } }, "extension_route": { "type": "object", "additionalProperties": false, "required": [ "host", "path", "access", "transport", "backend", "websocket", "timeout" ], "properties": { "host": { "$ref": "#/$defs/service/properties/host" }, "path": { "$ref": "#/$defs/service/properties/path" }, "access": { "$ref": "#/$defs/service/properties/access" }, "transport": { "$ref": "#/$defs/service/properties/transport" }, "websocket": { "$ref": "#/$defs/service/properties/websocket" }, "timeout": { "$ref": "#/$defs/service/properties/timeout" }, "body": { "$ref": "#/$defs/service/properties/body" }, "backend": { "type": "object", "additionalProperties": false, "required": [ "service", "port", "protocol" ], "properties": { "service": { "$ref": "#/$defs/backend/properties/service" }, "port": { "$ref": "#/$defs/backend/properties/port" }, "protocol": { "$ref": "#/$defs/backend/properties/protocol" } } } } } } }