diff --git a/api/app/settings/common.py b/api/app/settings/common.py index 219e6aba9437..ad7434644c62 100644 --- a/api/app/settings/common.py +++ b/api/app/settings/common.py @@ -1160,6 +1160,10 @@ "USER_FILTER_PARSER": "scim.filters.UserFilterQuery", } +EDGE_PROXY_INSTALLED = importlib.util.find_spec("edge_proxy") is not None +if EDGE_PROXY_INSTALLED: + INSTALLED_APPS.append("edge_proxy") + DEFAULT_AUTO_FIELD = "django.db.models.AutoField" # Used to keep edge identities in sync by forwarding the http requests diff --git a/api/app/urls.py b/api/app/urls.py index 1b45a36d8732..5be04f462455 100644 --- a/api/app/urls.py +++ b/api/app/urls.py @@ -1,6 +1,7 @@ import importlib from common.core.urls import urlpatterns as core_urlpatterns +from common.core.utils import is_saas from django.conf import settings from django.contrib import admin from django.urls import include, path, re_path @@ -124,6 +125,16 @@ ), ] +# SaaS images ship the private wheel, so is_saas() is the gate, not module presence. +if settings.EDGE_PROXY_INSTALLED and not is_saas(): # pragma: no cover + urlpatterns += [ + path( + "api/v1/organisations//edge-proxy/", + include("edge_proxy.management_urls"), + ), + path("api/v1/proxy/", include("edge_proxy.urls")), + ] + if settings.WORKFLOWS_LOGIC_INSTALLED: # pragma: no cover workflow_views = importlib.import_module("workflows_logic.views") urlpatterns += [ diff --git a/api/pyproject.toml b/api/pyproject.toml index aa4ebcd30818..b6530ccca85a 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -242,6 +242,10 @@ ignore_missing_imports = true module = ["rbac.*"] ignore_missing_imports = true +[[tool.mypy.overrides]] +module = ["edge_proxy.*"] +ignore_missing_imports = true + [[tool.mypy.overrides]] module = ["saml.*"] ignore_missing_imports = true diff --git a/openapi.yaml b/openapi.yaml index 78578f6e6a84..1853cdc33f36 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -9819,6 +9819,179 @@ paths: - Master API Key: [] tags: - Audit + '/api/v1/organisations/{organisation_pk}/edge-proxy/keys/': + get: + operationId: api_v1_organisations_edge_proxy_keys_list + parameters: + - name: organisation_pk + in: path + required: true + schema: + type: integer + responses: + '200': + description: '' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ProxyKey' + security: + - tokenAuth: [] + - Master API Key: [] + tags: + - Organisations + post: + operationId: api_v1_organisations_edge_proxy_keys_create + parameters: + - name: organisation_pk + in: path + required: true + schema: + type: integer + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProxyKey' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ProxyKey' + multipart/form-data: + schema: + $ref: '#/components/schemas/ProxyKey' + responses: + '201': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ProxyKey' + security: + - tokenAuth: [] + - Master API Key: [] + tags: + - Organisations + '/api/v1/organisations/{organisation_pk}/edge-proxy/keys/{prefix}/': + get: + operationId: api_v1_organisations_edge_proxy_keys_retrieve + parameters: + - name: organisation_pk + in: path + required: true + schema: + type: integer + - name: prefix + in: path + required: true + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ProxyKey' + security: + - tokenAuth: [] + - Master API Key: [] + tags: + - Organisations + put: + operationId: api_v1_organisations_edge_proxy_keys_update + parameters: + - name: organisation_pk + in: path + required: true + schema: + type: integer + - name: prefix + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProxyKey' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ProxyKey' + multipart/form-data: + schema: + $ref: '#/components/schemas/ProxyKey' + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ProxyKey' + security: + - tokenAuth: [] + - Master API Key: [] + tags: + - Organisations + patch: + operationId: api_v1_organisations_edge_proxy_keys_partial_update + parameters: + - name: organisation_pk + in: path + required: true + schema: + type: integer + - name: prefix + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedProxyKey' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedProxyKey' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedProxyKey' + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ProxyKey' + security: + - tokenAuth: [] + - Master API Key: [] + tags: + - Organisations + delete: + operationId: api_v1_organisations_edge_proxy_keys_destroy + parameters: + - name: organisation_pk + in: path + required: true + schema: + type: integer + - name: prefix + in: path + required: true + schema: + type: string + responses: + '204': + description: No response body + security: + - tokenAuth: [] + - Master API Key: [] + tags: + - Organisations '/api/v1/organisations/{organisation_pk}/github/create-cleanup-issue/': post: operationId: api_v1_organisations_github_create_cleanup_issue_create @@ -18644,6 +18817,20 @@ paths: - Master API Key: [] tags: - Projects + /api/v1/proxy/config/: + get: + operationId: api_v1_proxy_config_list + responses: + '200': + description: '' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EdgeProxyEnvironment' + tags: + - Other '/api/v1/segments/get-by-uuid/{uuid}/': get: operationId: api_v1_segments_get_by_uuid_retrieve @@ -20542,6 +20729,48 @@ components: required: - multivariate_feature_option - percentage_allocation + EdgeProxyEnvironment: + type: object + properties: + id: + type: integer + readOnly: true + name: + type: string + maxLength: 2000 + client_side_key: + type: string + server_side_keys: + type: array + items: + $ref: '#/components/schemas/EdgeProxyServerSideKey' + updated_at: + description: 'Tracks changes to self and related entities, e.g. FeatureStates.' + type: string + format: date-time + project_id: + type: integer + readOnly: true + organisation_id: + type: integer + readOnly: true + required: + - client_side_key + - name + - server_side_keys + EdgeProxyServerSideKey: + type: object + properties: + key: + type: string + maxLength: 100 + active: + type: boolean + expires_at: + type: + - string + - 'null' + format: date-time EdgeV2MigrationStatusEnum: description: |- * `NOT_STARTED` - Not Started @@ -25549,6 +25778,47 @@ components: enforce_feature_owners: description: Require at least one user or group owner when creating a feature. type: boolean + PatchedProxyKey: + type: object + properties: + prefix: + type: string + readOnly: true + created: + type: string + format: date-time + readOnly: true + name: + description: A free-form name for the API key. Need not be unique. 50 characters max. + type: string + maxLength: 50 + revoked: + description: 'If the API key is revoked, clients cannot use it anymore. (This cannot be undone.)' + type: boolean + expiry_date: + description: 'Once API key expires, clients cannot use it anymore.' + type: + - string + - 'null' + format: date-time + title: Expires + key: + description: 'Only the key hash is stored, so the full key is returned on create and is unavailable from every other endpoint.' + type: string + readOnly: true + has_expired: + type: boolean + readOnly: true + created_by_user: + type: + - integer + - 'null' + readOnly: true + created_by_master_api_key: + type: + - string + - 'null' + readOnly: true PatchedReleasePipeline: type: object properties: @@ -27080,6 +27350,47 @@ components: type: boolean required: - name + ProxyKey: + type: object + properties: + prefix: + type: string + readOnly: true + created: + type: string + format: date-time + readOnly: true + name: + description: A free-form name for the API key. Need not be unique. 50 characters max. + type: string + maxLength: 50 + revoked: + description: 'If the API key is revoked, clients cannot use it anymore. (This cannot be undone.)' + type: boolean + expiry_date: + description: 'Once API key expires, clients cannot use it anymore.' + type: + - string + - 'null' + format: date-time + title: Expires + key: + description: 'Only the key hash is stored, so the full key is returned on create and is unavailable from every other endpoint.' + type: string + readOnly: true + has_expired: + type: boolean + readOnly: true + created_by_user: + type: + - integer + - 'null' + readOnly: true + created_by_master_api_key: + type: + - string + - 'null' + readOnly: true ReleasePipeline: type: object properties: