diff --git a/backend/api/models.py b/backend/api/models.py index e1fe9487e..f79238d2f 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -6,10 +6,7 @@ ) from uuid import uuid4 from datetime import timedelta -from backend.api.kv import write -import json from django.utils import timezone -from django.conf import settings from api.services import Providers, ServiceConfig from api.tasks.syncing import trigger_sync_tasks, detect_and_trigger_referencing_syncs from backend.quotas import ( @@ -20,9 +17,6 @@ from django.core.exceptions import ValidationError from api.utils.access.roles import MANAGED_ROLE_CHOICES -CLOUD_HOSTED = settings.APP_HOST == "cloud" - - class CustomUserManager(BaseUserManager): def create_user(self, username, email, password=None): """ @@ -231,6 +225,8 @@ class App(models.Model): ) name = models.CharField(max_length=64) description = models.TextField(null=True, blank=True) + # Retired KMS fields are retained for upgrade compatibility and historical + # data preservation. They are not credentials for any supported API. identity_key = models.CharField(max_length=256) app_version = models.IntegerField(null=False, blank=False, default=1) app_token = models.CharField(max_length=64) @@ -244,17 +240,6 @@ class App(models.Model): objects = AppManager() - def save(self, *args, **kwargs): - super().save(*args, **kwargs) # Call the "real" save() method. - if CLOUD_HOSTED: - key = self.app_token - value = self.wrapped_key_share - meta = {"appId": self.id, "appName": self.name, "live": True} - try: - write(key, value, json.dumps(meta)) - except: - pass - def __str__(self): return self.name diff --git a/backend/api/views/apps.py b/backend/api/views/apps.py index 3b1f2709e..804da5a0e 100644 --- a/backend/api/views/apps.py +++ b/backend/api/views/apps.py @@ -10,14 +10,6 @@ service_account_can_access_app, ) from api.utils.access.roles import ADMIN_ROLE_KEY, OWNER_ROLE_KEY -from api.utils.crypto import ( - encrypt_raw, - env_keypair, - get_server_keypair, - random_hex, - split_secret_hex, - wrap_share_hex, -) from api.utils.audit_logging import audit_app_cascade_envs, log_audit_event, get_actor_info, build_change_values from api.utils.environments import create_environment from api.utils.rest import METHOD_TO_ACTION, get_resolver_request_meta, validate_text_field @@ -31,14 +23,10 @@ from rest_framework.response import Response from rest_framework import status from djangorestframework_camel_case.render import CamelCaseJSONRenderer -from django.conf import settings from django.db import transaction logger = logging.getLogger(__name__) -CLOUD_HOSTED = settings.APP_HOST == "cloud" - - class PublicAppsView(APIView): authentication_classes = [PhaseTokenAuthentication] permission_classes = [IsAuthenticated, IsIPAllowed] @@ -189,19 +177,6 @@ def post(self, request, *args, **kwargs): status=status.HTTP_403_FORBIDDEN, ) - # --- Generate cryptographic material (server-side, SSE) --- - app_seed = random_hex(32) - app_token = random_hex(32) - wrap_key = random_hex(32) - - identity_key_pub, identity_key_priv = env_keypair(app_seed) - - _share0, share1 = split_secret_hex(identity_key_priv) - wrapped_key_share = wrap_share_hex(share1, wrap_key) - - _server_pk, server_sk = get_server_keypair() - encrypted_app_seed = bytes(encrypt_raw(app_seed, server_sk)).hex() - # --- Determine requesting account --- requesting_user = None requesting_sa = None @@ -217,11 +192,6 @@ def post(self, request, *args, **kwargs): organisation=org, name=name, description=description, - identity_key=identity_key_pub, - app_version=1, - app_token=app_token, - app_seed=encrypted_app_seed, - wrapped_key_share=wrapped_key_share, sse_enabled=True, ) @@ -409,19 +379,6 @@ def delete(self, request, app_id, *args, **kwargs): app_name = app.name org = app.organisation - if CLOUD_HOSTED: - from backend.api.kv import delete as kv_delete, purge as kv_purge - - deleted = kv_delete(app.app_token) - purged = kv_purge( - f"phApp:v{app.app_version}:{app.identity_key}/{app.app_token}" - ) - if not deleted or not purged: - return Response( - {"error": "Failed to delete app keys from CDN. Please try again."}, - status=status.HTTP_500_INTERNAL_SERVER_ERROR, - ) - actor_type, actor_id, actor_meta = get_actor_info(request) ip_address, user_agent = get_resolver_request_meta(request) @@ -429,8 +386,6 @@ def delete(self, request, app_id, *args, **kwargs): app, actor_type, actor_id, actor_meta, ip_address, user_agent ) - app.wrapped_key_share = "" - app.save() app.delete() log_audit_event( diff --git a/backend/api/views/kms.py b/backend/api/views/kms.py deleted file mode 100644 index 0e1d6df75..000000000 --- a/backend/api/views/kms.py +++ /dev/null @@ -1,41 +0,0 @@ -from datetime import datetime -from api.utils.access.ip import get_client_ip -from rest_framework.decorators import api_view, permission_classes -from rest_framework.permissions import AllowAny -from django.http import JsonResponse, HttpResponse - -from logs.models import KMSDBLog -from api.models import ( - App, -) - - -@api_view(["GET"]) -@permission_classes([AllowAny]) -def kms(request, app_id): - auth_token = request.headers["authorization"] - event_type = request.headers["eventtype"] - phase_node = request.headers["phasenode"] - ph_size = request.headers["phsize"] - ip_address = get_client_ip(request) - app_token = auth_token.split("Bearer ")[1] - - if not app_token: - return HttpResponse(status=404) - try: - app = App.objects.get(app_token=app_token) - try: - timestamp = datetime.now().timestamp() * 1000 - KMSDBLog.objects.create( - app_id=app_id, - event_type=event_type, - phase_node=phase_node, - ph_size=float(ph_size), - ip_address=ip_address, - timestamp=timestamp, - ) - except: - pass - return JsonResponse({"wrappedKeyShare": app.wrapped_key_share}) - except: - return HttpResponse(status=404) diff --git a/backend/backend/api/kv.py b/backend/backend/api/kv.py deleted file mode 100644 index b57a8bb99..000000000 --- a/backend/backend/api/kv.py +++ /dev/null @@ -1,85 +0,0 @@ -import requests -import time -from django.conf import settings - - -def write(key, value, meta): - account_id = settings.CLOUDFLARE['ACCOUNT_ID'] - kv_namespace = settings.CLOUDFLARE['KV_NAMESPACE'] - api_key = settings.CLOUDFLARE['API_KEY'] - - url = f"https://api.cloudflare.com/client/v4/accounts/{account_id}/storage/kv/namespaces/{kv_namespace}/bulk" - - payload = [ - { - "base64": False, - "key": key, - "value": value, - "metadata": meta - } - ] - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {api_key}" - } - - response = requests.request("PUT", url, json=payload, headers=headers) - if response.status_code == 200: - return True - print('Error writing to KV:', response) - return False - - -def delete(key): - account_id = settings.CLOUDFLARE['ACCOUNT_ID'] - kv_namespace = settings.CLOUDFLARE['KV_NAMESPACE'] - api_key = settings.CLOUDFLARE['API_KEY'] - - url = f"https://api.cloudflare.com/client/v4/accounts/{account_id}/storage/kv/namespaces/{kv_namespace}/values/{key}" - - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {api_key}" - } - - response = requests.request("DELETE", url, headers=headers) - - if response.status_code == 200: - return True - print('Error deleting from KV:', response) - return False - - -def purge(resource): - api_key = settings.CLOUDFLARE['API_KEY'] - zone_id = settings.CLOUDFLARE['ZONE_ID'] - - url = f"https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" - - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {api_key}" - } - - payload = { - "files": [f"https://kms.phase.dev/{resource}"] - } - - responses = [] - - responses.append(requests.request("POST", url, headers=headers, json=payload)) - - time.sleep(0.1) - - responses.append(requests.request("POST", url, headers=headers, json=payload)) - - time.sleep(0.1) - - responses.append(requests.request("POST", url, headers=headers, json=payload)) - - for response in responses: - if response.status_code != 200: - print('Error purging from cache:', response) - return False - - return True diff --git a/backend/backend/graphene/mutations/app.py b/backend/backend/graphene/mutations/app.py index efd7b8885..452c69bea 100644 --- a/backend/backend/graphene/mutations/app.py +++ b/backend/backend/graphene/mutations/app.py @@ -1,4 +1,3 @@ -from backend.api.kv import delete, purge from backend.graphene.mutations.environment import ( EnvironmentKeyInput, validate_member_environment_keys, @@ -25,13 +24,9 @@ from backend.graphene.types import AppType, MemberType from api.utils.audit_logging import audit_app_cascade_envs, log_audit_event, get_actor_info_from_graphql, get_member_display_name from api.utils.rest import get_resolver_request_meta -from django.conf import settings from django.db import transaction from django.utils import timezone -CLOUD_HOSTED = settings.APP_HOST == "cloud" - - def _upsert_active_env_key(condition, defaults): """Like `update_or_create` but scoped to active rows only — the unique constraint allows soft-deleted dupes to coexist with one @@ -77,11 +72,13 @@ class Arguments: id = graphene.ID(required=True) organisation_id = graphene.ID(required=True) name = graphene.String(required=True) - identity_key = graphene.String(required=True) - app_token = graphene.String(required=True) - app_seed = graphene.String(required=True) - wrapped_key_share = graphene.String(required=True) - app_version = graphene.Int(required=True) + # Accepted only for clients cached before the KMS retirement. These + # optional inputs are ignored and are never persisted or published. + identity_key = graphene.String(deprecation_reason="Legacy KMS is retired; ignored.") + app_token = graphene.String(deprecation_reason="Legacy KMS is retired; ignored.") + app_seed = graphene.String(deprecation_reason="Legacy KMS is retired; ignored.") + wrapped_key_share = graphene.String(deprecation_reason="Legacy KMS is retired; ignored.") + app_version = graphene.Int(deprecation_reason="Legacy KMS is retired; ignored.") app = graphene.Field(AppType) @@ -93,11 +90,11 @@ def mutate( id, organisation_id, name, - identity_key, - app_token, - app_seed, - wrapped_key_share, - app_version, + identity_key=None, + app_token=None, + app_seed=None, + wrapped_key_share=None, + app_version=None, ): user = info.context.user org = Organisation.objects.get(id=organisation_id) @@ -107,18 +104,10 @@ def mutate( if not user_has_permission(info.context.user, "create", "Apps", org): raise GraphQLError("You don't have permission to create Apps") - if App.objects.filter(identity_key=identity_key).exists(): - raise GraphQLError("This app already exists") - app = App.objects.create( id=id, organisation=org, name=name, - identity_key=identity_key, - app_token=app_token, - app_seed=app_seed, - wrapped_key_share=wrapped_key_share, - app_version=app_version, ) org_member = OrganisationMember.objects.get( @@ -155,41 +144,6 @@ def mutate( return CreateAppMutation(app=app) -class RotateAppKeysMutation(graphene.Mutation): - class Arguments: - id = graphene.ID(required=True) - app_token = graphene.String(required=True) - wrapped_key_share = graphene.String(required=True) - - app = graphene.Field(AppType) - - @classmethod - def mutate(cls, root, info, id, app_token, wrapped_key_share): - user = info.context.user - app = App.objects.get(id=id) - - if not user_can_access_app(user.userId, app.id): - raise GraphQLError("You don't have access to this app") - - if CLOUD_HOSTED: - # delete current keys from cloudflare KV - deleted = delete(app.app_token) - - # purge keys from cloudflare cache - purged = purge( - f"phApp:v{app.app_version}:{app.identity_key}/{app.app_token}" - ) - - if not deleted or not purged: - raise GraphQLError("Failed to delete app keys. Please try again.") - - app.app_token = app_token - app.wrapped_key_share = wrapped_key_share - app.save() - - return RotateAppKeysMutation(app=app) - - class UpdateAppInfoMutation(graphene.Mutation): class Arguments: id = graphene.ID(required=True) @@ -286,18 +240,6 @@ def mutate(cls, root, info, id): ): raise GraphQLError("You don't have permission to delete Apps") - if CLOUD_HOSTED: - # delete current keys from cloudflare KV - deleted = delete(app.app_token) - - # purge keys from cloudflare cache - purged = purge( - f"phApp:v{app.app_version}:{app.identity_key}/{app.app_token}" - ) - - if not deleted or not purged: - raise GraphQLError("Failed to delete app keys. Please try again.") - app_name = app.name app_id = app.id app_org = app.organisation @@ -309,8 +251,6 @@ def mutate(cls, root, info, id): app, actor_type, actor_id, actor_metadata, ip_address, user_agent ) - app.wrapped_key_share = "" - app.save() app.delete() log_audit_event( diff --git a/backend/backend/graphene/types.py b/backend/backend/graphene/types.py index 1aa82f7da..7a638274d 100644 --- a/backend/backend/graphene/types.py +++ b/backend/backend/graphene/types.py @@ -9,8 +9,7 @@ from ee.integrations.secrets.dynamic.graphene.types import DynamicSecretType from backend.quotas import PLAN_CONFIG import graphene -from enum import Enum -from graphene import ObjectType, relay, NonNull +from graphene import ObjectType, NonNull from graphene_django import DjangoObjectType from api.models import ( ActivatedPhaseLicense, @@ -49,7 +48,6 @@ SCIMToken, SCIMEvent, ) -from logs.dynamodb_models import KMSLog from django.utils import timezone from api.utils.access.roles import OWNER_ROLE_KEY, get_default_role_template from graphql import GraphQLError @@ -841,6 +839,14 @@ class AppType(DjangoObjectType): environments = graphene.NonNull(graphene.List(EnvironmentType)) members = graphene.NonNull(graphene.List(OrganisationMemberType)) service_accounts = graphene.NonNull(graphene.List(lambda: ServiceAccountType)) + # Old clients include these fields in ordinary app queries. Keep inert + # compatibility fields so a rolling upgrade does not fail the whole query; + # never resolve them from the retained legacy database columns. + identity_key = graphene.String(required=True, deprecation_reason="Legacy KMS is retired; always empty.") + app_token = graphene.String(required=True, deprecation_reason="Legacy KMS is retired; always empty.") + app_seed = graphene.String(required=True, deprecation_reason="Legacy KMS is retired; always empty.") + wrapped_key_share = graphene.String(required=True, deprecation_reason="Legacy KMS is retired; always empty.") + app_version = graphene.Int(required=True, deprecation_reason="Legacy KMS is retired; always 1.") class Meta: model = App @@ -848,17 +854,27 @@ class Meta: "id", "name", "description", - "identity_key", - "wrapped_key_share", "created_at", "updated_at", - "app_token", - "app_seed", - "app_version", "sse_enabled", "service_accounts", ) + def resolve_identity_key(self, info): + return "" + + def resolve_app_token(self, info): + return "" + + def resolve_app_seed(self, info): + return "" + + def resolve_wrapped_key_share(self, info): + return "" + + def resolve_app_version(self, info): + return 1 + def resolve_environments(self, info): if hasattr(self, "filtered_environments"): @@ -1168,59 +1184,6 @@ class Meta: fields = ("id", "name", "color") -class KMSLogType(ObjectType): - class Meta: - model = KMSLog - fields = ( - "id", - "app_id", - "timestamp", - "phase_node", - "event_type", - "ip_address", - "ph_size", - "edge_location", - "country", - "city", - "latitude", - "longitude", - ) - interfaces = (relay.Node,) - - id = graphene.ID(required=True) - timestamp = graphene.BigInt() - app_id = graphene.String() - phase_node = graphene.String() - event_type = graphene.String() - ip_address = graphene.String() - ph_size = graphene.Int() - asn = graphene.Int() - isp = graphene.String() - edge_location = graphene.String() - country = graphene.String() - city = graphene.String() - latitude = graphene.Float() - longitude = graphene.Float() - - -class ChartDataPointType(graphene.ObjectType): - index = graphene.Int() - date = graphene.BigInt() - data = graphene.Int() - - -class TimeRange(Enum): - HOUR = "hour" - DAY = "day" - WEEK = "week" - MONTH = "month" - YEAR = "year" - ALL_TIME = "allTime" - - -class KMSLogsResponseType(ObjectType): - logs = graphene.List(KMSLogType) - count = graphene.Int() class SecretLogsResponseType(ObjectType): @@ -1454,8 +1417,7 @@ def resolve_members(self, info): ) def resolve_apps(self, info): - # Gate to apps the caller can access — AppType exposes app_seed, - # wrapped_key_share, app_token, which would leak via teams. + # Gate to apps the caller can access, including through teams. user_id = info.context.user.userId app_ids = ( self.app_environments.values_list("app_id", flat=True).distinct() diff --git a/backend/backend/schema.py b/backend/backend/schema.py index cb9596cc4..ec0260f37 100644 --- a/backend/backend/schema.py +++ b/backend/backend/schema.py @@ -272,7 +272,6 @@ DeleteAppMutation, MemberType, RemoveAppMemberMutation, - RotateAppKeysMutation, UpdateAppInfoMutation, ) from .graphene.mutations.account import ( @@ -313,12 +312,10 @@ AppType, AuditEventType, AuditLogsResponseType, - ChartDataPointType, EnvironmentKeyType, EnvironmentSyncType, EnvironmentTokenType, EnvironmentType, - KMSLogsResponseType, NetworkAccessPolicyType, OrganisationMemberInviteType, OrganisationMemberType, @@ -341,7 +338,6 @@ TeamType, SCIMTokenType, SCIMEventsResponseType, - TimeRange, UserTokenType, AWSValidationResultType, IdentityType, @@ -367,10 +363,7 @@ TeamMembership, UserToken, ) -from logs.queries import get_app_log_count, get_app_log_count_range, get_app_logs from datetime import datetime, timedelta, timezone as dt_timezone -from django.conf import settings -from logs.models import KMSDBLog from django.utils import timezone from itertools import chain import time @@ -380,9 +373,6 @@ logger = logging.getLogger(__name__) -CLOUD_HOSTED = settings.APP_HOST == "cloud" - - class Query(graphene.ObjectType): client_ip = graphene.String() @@ -456,13 +446,6 @@ class Query(graphene.ObjectType): AppType, organisation_id=graphene.ID(), app_id=graphene.ID(required=False) ) - kms_logs = graphene.Field( - KMSLogsResponseType, - app_id=graphene.ID(), - start=graphene.BigInt(), - end=graphene.BigInt(), - ) - secret_logs = graphene.Field( SecretLogsResponseType, app_id=graphene.ID(), @@ -488,12 +471,6 @@ class Query(graphene.ObjectType): limit=graphene.Int(), ) - app_activity_chart = graphene.List( - ChartDataPointType, - app_id=graphene.ID(), - period=graphene.Argument(graphene.Enum.from_enum(TimeRange)), - ) - app_environments = graphene.List( EnvironmentType, app_id=graphene.ID(), @@ -1098,43 +1075,6 @@ def resolve_user_tokens(root, info, organisation_id): resolve_service_accounts = resolve_service_accounts resolve_service_account_handlers = resolve_service_account_handlers - def resolve_kms_logs(root, info, app_id, start=0, end=0): - if not user_can_access_app(info.context.user.userId, app_id): - raise GraphQLError("You don't have access to this app") - - app = App.objects.get(id=app_id) - - if end == 0: - end = datetime.now().timestamp() * 1000 - - if CLOUD_HOSTED: - try: - kms_logs = get_app_logs( - f"phApp:v{app.app_version}:{app.identity_key}", start, end, 25 - ) - count = get_app_log_count( - f"phApp:v{app.app_version}:{app.identity_key}" - ) - except: - print("Error fetching KMS logs") - kms_logs = [] - count = 0 - - else: - kms_logs = list( - KMSDBLog.objects.filter( - app_id=f"phApp:v{app.app_version}:{app.identity_key}", - timestamp__lte=end, - timestamp__gte=start, - ) - .order_by("-timestamp")[:25] - .values() - ) - count = KMSDBLog.objects.filter( - app_id=f"phApp:v{app.app_version}:{app.identity_key}" - ).count() - - return SecretLogsResponseType(logs=kms_logs, count=count) def resolve_audit_logs( root, @@ -1375,91 +1315,6 @@ def resolve_secret_logs( return SecretLogsResponseType(logs=logs_qs, count=count) - def resolve_app_activity_chart(root, info, app_id, period=TimeRange.DAY): - """ - Converts app log activity for the chosen time period into time series data that can be used to draw a chart - Args: - app_id (string): app uuid - period (TimeRange, optional): The desired time period. Defaults to 'day'. - Raises: - GraphQLError: If the requesting user does not have access to this app - Returns: - List[ChartDataPointType]: Time series decrypt count data - """ - - app = App.objects.get(id=app_id) - if not user_can_access_app(info.context.user.userId, app_id): - raise GraphQLError("You don't have access to this app") - - end_date = datetime.now() # current time - - # default values for period='day' - # 24 hours before current time - start_date = end_date - timedelta(hours=24) - time_iteration = timedelta(hours=1) - - match period: - case TimeRange.HOUR: - # 7 days before current time - start_date = end_date - timedelta(hours=1) - time_iteration = timedelta(minutes=5) - case TimeRange.WEEK: - # 7 days before current time - start_date = end_date - timedelta(days=7) - time_iteration = timedelta(days=1) - case TimeRange.MONTH: - # 30 days before current time - start_date = end_date - timedelta(days=30) - time_iteration = timedelta(days=1) - case TimeRange.YEAR: - # 365 days before current time - start_date = end_date - timedelta(days=365) - time_iteration = timedelta(days=5) - case TimeRange.ALL_TIME: - # 365 days before current time - start_date = end_date - timedelta(days=365) - time_iteration = timedelta(days=7) - - time_series_logs = [] - - # initialize the iterators - current_date = start_date - index = 0 - - # loop through each iteration in the period and calculate the number of decrypts per time_iteration - while current_date <= end_date: - # Get the start and end of the current measurement period as datetime objects - start_of_measurement_period = current_date.replace(second=0, microsecond=0) - if (current_date + time_iteration) > end_date: - end_of_measurement_period = end_date - else: - end_of_measurement_period = start_of_measurement_period + time_iteration - - # Convert the start and end of the measurement period to unix timestamps - start_unix = int(start_of_measurement_period.timestamp() * 1000) - end_unix = int(end_of_measurement_period.timestamp() * 1000) - - # Get the count of decrypts in the measurement period - if CLOUD_HOSTED: - decrypts = get_app_log_count_range( - f"phApp:v{app.app_version}:{app.identity_key}", start_unix, end_unix - ) - else: - decrypts = KMSDBLog.objects.filter( - app_id=f"phApp:v{app.app_version}:{app.identity_key}", - timestamp__lte=end_unix, - timestamp__gte=start_unix, - ).count() - - time_series_logs.append( - ChartDataPointType(index=str(index), date=end_unix, data=decrypts) - ) - - # Increment current_date by one time iteration - current_date += time_iteration - index += 1 - - return time_series_logs resolve_stripe_checkout_details = resolve_stripe_checkout_details resolve_stripe_subscription_details = resolve_stripe_subscription_details @@ -1490,7 +1345,6 @@ class Mutation(graphene.ObjectType): delete_invitation = DeleteInviteMutation.Field() create_app = CreateAppMutation.Field() - rotate_app_keys = RotateAppKeysMutation.Field() delete_app = DeleteAppMutation.Field() update_app_info = UpdateAppInfoMutation.Field() add_app_member = AddAppMemberMutation.Field() diff --git a/backend/backend/settings.py b/backend/backend/settings.py index 3a2e9969e..65c07ffa0 100644 --- a/backend/backend/settings.py +++ b/backend/backend/settings.py @@ -409,11 +409,6 @@ def get_version(): }, } -DYNAMODB = { - "TABLE": os.getenv("DYNAMODB_LOGS_TABLE"), - "INDEX": os.getenv("DYNAMODB_LOGS_TIMESTAMP_INDEX"), - "REGION": os.getenv("DYNAMODB_REGION"), -} # Password validation @@ -457,13 +452,6 @@ def get_version(): DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -CLOUDFLARE = { - "ACCOUNT_ID": os.getenv("CF_ACCOUNT_ID"), - "KV_NAMESPACE": os.getenv("CF_KV_NAMESPACE"), - "API_KEY": get_secret("CF_API_KEY"), - "ZONE_ID": os.getenv("CF_ZONE_ID"), -} - SLACK_WEBHOOK_URI = f"https://hooks.slack.com/services/{os.getenv('SLACK_NOTIFIER')}" # Whether the app is self-hosted or cloud-hosted diff --git a/backend/backend/urls.py b/backend/backend/urls.py index 7a9dd1661..7a2e12334 100644 --- a/backend/backend/urls.py +++ b/backend/backend/urls.py @@ -56,7 +56,6 @@ from api.views.auth_mfa import mfa_verify from api.views.identities.aws.iam import aws_iam_auth from api.views.identities.azure.entra import azure_entra_auth -from api.views.kms import kms CLOUD_HOSTED = settings.APP_HOST == "cloud" @@ -156,7 +155,6 @@ from ee.billing.webhooks.stripe import stripe_webhook cloud_urls = [ - path("kms/", kms), path("stripe/webhook/", stripe_webhook, name="stripe-webhook"), ] urlpatterns.extend(cloud_urls) diff --git a/backend/ee/integrations/secrets/rotation/utils.py b/backend/ee/integrations/secrets/rotation/utils.py index ca4e436bd..edb057c41 100644 --- a/backend/ee/integrations/secrets/rotation/utils.py +++ b/backend/ee/integrations/secrets/rotation/utils.py @@ -88,7 +88,6 @@ def validate_provider_config(provider_id: str, config: dict) -> None: def auto_enable_sse(app) -> None: - from backend.api.kv import write # noqa: F401 (only to keep dependency parity) if app.sse_enabled: return diff --git a/backend/logs/dynamodb_models.py b/backend/logs/dynamodb_models.py deleted file mode 100644 index 33bf6095f..000000000 --- a/backend/logs/dynamodb_models.py +++ /dev/null @@ -1,35 +0,0 @@ -from pynamodb.models import Model -from pynamodb.indexes import GlobalSecondaryIndex, AllProjection -from pynamodb.attributes import ( - UnicodeAttribute, - NumberAttribute, -) -from django.conf import settings - -class TimestampIndex(GlobalSecondaryIndex): - class Meta: - index_name = settings.DYNAMODB['INDEX'] - projection = AllProjection() - app_id = UnicodeAttribute(hash_key=True, null=False) - timestamp = NumberAttribute(range_key=True, null=False) - -class KMSLog(Model): - class Meta: - table_name = settings.DYNAMODB['TABLE'] - region = settings.DYNAMODB['REGION'] - - id = UnicodeAttribute(hash_key=True,null=False) - timestamp = NumberAttribute(null=False) - app_id = UnicodeAttribute(null=False) - phase_node = UnicodeAttribute(null=False) - event_type = UnicodeAttribute(null=False) - ip_address = UnicodeAttribute() - ph_size = NumberAttribute() - asn = NumberAttribute() - isp = UnicodeAttribute() - edge_location = UnicodeAttribute() - country = UnicodeAttribute() - city = UnicodeAttribute() - latitude = NumberAttribute() - longitude = NumberAttribute() - timestamp_index = TimestampIndex() \ No newline at end of file diff --git a/backend/logs/models.py b/backend/logs/models.py index 684b32909..059565dd3 100644 --- a/backend/logs/models.py +++ b/backend/logs/models.py @@ -3,7 +3,8 @@ class KMSDBLog(models.Model): """ - DB model for Logs + Retained legacy KMS history. No supported runtime path reads or writes it. + Keep the model and migration history so upgrades do not delete stored logs. """ id = models.CharField(default=uuid4, primary_key=True, editable=False) diff --git a/backend/logs/queries.py b/backend/logs/queries.py deleted file mode 100644 index 11b00fb80..000000000 --- a/backend/logs/queries.py +++ /dev/null @@ -1,60 +0,0 @@ -import logging -from django.db import DatabaseError -from logs.dynamodb_models import KMSLog - -# Configure logging at the top of your module -logger = logging.getLogger(__name__) - -PAGE_SIZE = 25 - -def get_app_logs(app_id, start, end, limit): - """ - Get logs for a given app id within a specified time period - - Args: - app_id (string): the app_id - start (int): The start of the time period as a unix timestamp in ms. - end (int): The end of the time period as a unix timestamp in ms. - limit (int): The limit for number of items to fetch. - - Returns: - List[KMSLog]: list of log entries - """ - - try: - return [log.attribute_values for log in KMSLog.timestamp_index.query(app_id, KMSLog.timestamp.between(start, end), limit=limit, scan_index_forward=False)] - except Exception as e: - logger.exception('Error fetching logs for app_id %s: %s', app_id, e) - raise DatabaseError('Error fetching logs. Please try again later.') - -def get_app_log_count(app_id): - """ - Get the count of total logs for the given app. - - Args: - app_id (string): app_id - - Returns: - number: Count of total logs for this app - """ - try: - return KMSLog.timestamp_index.count(app_id) - except Exception as e: - logger.exception('Error fetching log count for app_id %s: %s', app_id, e) - raise DatabaseError('Error fetching logs. Please try again later.') - -def get_app_log_count_range(app_id, start, end): - """ - Get the count of total logs for the given app in a specific time range. - - Args: - app_id (string): app_id - - Returns: - number: Count of total logs for this app - """ - try: - return KMSLog.timestamp_index.count(app_id, KMSLog.timestamp.between(start, end)) - except Exception as e: - logger.exception('Error fetching log count range for app_id %s: %s', app_id, e) - raise DatabaseError('Error fetching logs. Please try again later.') diff --git a/backend/requirements.txt b/backend/requirements.txt index 6c9082498..cce8e2a25 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -48,7 +48,6 @@ pycodestyle==2.10.0 pycparser==2.21 PyJWT==2.13.0 PyNaCl==1.5.0 -pynamodb==5.5.1 pyOpenSSL==26.4.0 pyotp==2.9.0 python-dateutil==2.8.2 diff --git a/backend/tests/api/views/test_apps_api.py b/backend/tests/api/views/test_apps_api.py index 5a103bd0e..7db3b9eb6 100644 --- a/backend/tests/api/views/test_apps_api.py +++ b/backend/tests/api/views/test_apps_api.py @@ -271,19 +271,12 @@ def setup(self, settings): @patch("api.views.apps.Role") @patch("api.views.apps.App") @patch("api.views.apps.transaction") - @patch("api.views.apps.encrypt_raw", return_value=bytearray(b"\x00" * 104)) - @patch("api.views.apps.get_server_keypair", return_value=(b"\x00" * 32, b"\x01" * 32)) - @patch("api.views.apps.wrap_share_hex", return_value="wrapped_share") - @patch("api.views.apps.split_secret_hex", return_value=("share0", "share1")) - @patch("api.views.apps.env_keypair", return_value=("pub_hex", "priv_hex")) - @patch("api.views.apps.random_hex", return_value="aa" * 32) @patch("api.views.apps.can_add_app", return_value=True) @patch("api.views.apps.user_has_permission", return_value=True) @patch("api.views.apps.PlanBasedRateThrottle.allow_request", return_value=True) @patch("api.views.apps.IsIPAllowed.has_permission", return_value=True) def test_create_app_success( self, _ip, _throttle, _perm, _quota, - _random, _keypair, _split, _wrap, _server_kp, _encrypt, _txn, mock_app_model, mock_role, mock_org_member, mock_create_env, mock_serializer, ): new_app = _make_app(org=self.org, name="test-app") @@ -303,6 +296,9 @@ def test_create_app_success( assert response.status_code == status.HTTP_201_CREATED mock_app_model.objects.create.assert_called_once() + assert not { + "identity_key", "app_version", "app_token", "app_seed", "wrapped_key_share" + } & mock_app_model.objects.create.call_args.kwargs.keys() # Verify create_environment was called 3 times (dev, staging, prod) assert mock_create_env.call_count == 3 @@ -444,12 +440,6 @@ def test_create_custom_envs_free_plan_returns_403(self, _ip, _throttle, _perm, _ @patch("api.views.apps.Role") @patch("api.views.apps.App") @patch("api.views.apps.transaction") - @patch("api.views.apps.encrypt_raw", return_value=bytearray(b"\x00" * 104)) - @patch("api.views.apps.get_server_keypair", return_value=(b"\x00" * 32, b"\x01" * 32)) - @patch("api.views.apps.wrap_share_hex", return_value="wrapped_share") - @patch("api.views.apps.split_secret_hex", return_value=("share0", "share1")) - @patch("api.views.apps.env_keypair", return_value=("pub_hex", "priv_hex")) - @patch("api.views.apps.random_hex", return_value="aa" * 32) @patch("api.views.apps.can_add_environments", return_value=True) @patch("api.views.apps.can_add_app", return_value=True) @patch("api.views.apps.can_use_custom_envs", return_value=True) @@ -458,7 +448,6 @@ def test_create_custom_envs_free_plan_returns_403(self, _ip, _throttle, _perm, _ @patch("api.views.apps.IsIPAllowed.has_permission", return_value=True) def test_create_app_with_custom_envs( self, _ip, _throttle, _perm, _custom, _quota, _env_quota, - _random, _keypair, _split, _wrap, _server_kp, _encrypt, _txn, mock_app_model, mock_role, mock_org_member, mock_create_env, mock_serializer, ): new_app = _make_app(org=self.org, name="test-app") @@ -666,7 +655,6 @@ def setup(self, settings): self.org = _make_org() self.app = _make_app(org=self.org) - @patch("api.views.apps.CLOUD_HOSTED", False) @patch("api.views.apps.user_has_permission", return_value=True) @patch("api.views.apps.PlanBasedRateThrottle.allow_request", return_value=True) @patch("api.views.apps.IsIPAllowed.has_permission", return_value=True) @@ -678,9 +666,9 @@ def test_delete_app_success(self, _ip, _throttle, _perm): response = self.view(request, app_id=self.app.id) assert response.status_code == status.HTTP_204_NO_CONTENT - self.app.save.assert_called_once() + self.app.save.assert_not_called() self.app.delete.assert_called_once() - assert self.app.wrapped_key_share == "" + assert self.app.wrapped_key_share == "wrapped_share" # Cascade-audit must fire BEFORE app.delete() so the envs still # exist when the helper enumerates them. cascade_audit.assert_called_once() diff --git a/backend/tests/fixtures/legacy_kms_client.graphql b/backend/tests/fixtures/legacy_kms_client.graphql new file mode 100644 index 000000000..df29cbaae --- /dev/null +++ b/backend/tests/fixtures/legacy_kms_client.graphql @@ -0,0 +1,154 @@ +# Cached-client operations from the release before KMS retirement. + +query GetApps($organisationId: ID!, $appId: ID) { + apps(organisationId: $organisationId, appId: $appId) { + id + name + description + identityKey + createdAt + updatedAt + sseEnabled + members { + id + email + fullName + avatarUrl + } + serviceAccounts { + id + name + } + environments { + id + name + envType + syncs { + id + serviceInfo { + id + name + provider { + id + name + } + } + status + } + } + } +} + +query GetAppDetail($organisationId: ID!, $appId: ID!) { + apps(organisationId: $organisationId, appId: $appId) { + id + name + description + identityKey + createdAt + appToken + appSeed + appVersion + sseEnabled + } +} + +query GetOrganisationSyncs($orgId: ID!) { + syncs(orgId: $orgId) { + id + environment { + id + name + envType + app { + id + name + } + } + path + serviceInfo { + id + name + provider { + id + } + } + options + isActive + lastSync + status + authentication { + id + name + } + createdAt + history { + id + status + createdAt + completedAt + meta + } + } + apps(organisationId: $orgId, appId: null) { + id + name + identityKey + createdAt + sseEnabled + members { + id + fullName + avatarUrl + email + } + serviceAccounts { + id + name + } + environments { + id + name + syncs { + id + serviceInfo { + id + name + provider { + id + name + } + } + status + } + } + } +} + +mutation CreateApplication( + $id: ID! + $organisationId: ID! + $name: String! + $identityKey: String! + $appToken: String! + $appSeed: String! + $wrappedKeyShare: String! + $appVersion: Int! +) { + createApp( + id: $id + organisationId: $organisationId + name: $name + identityKey: $identityKey + appToken: $appToken + appSeed: $appSeed + wrappedKeyShare: $wrappedKeyShare + appVersion: $appVersion + ) { + app { + id + name + identityKey + } + } +} diff --git a/backend/tests/test_legacy_kms_retirement.py b/backend/tests/test_legacy_kms_retirement.py new file mode 100644 index 000000000..57d41d66e --- /dev/null +++ b/backend/tests/test_legacy_kms_retirement.py @@ -0,0 +1,221 @@ +"""Retire KMS runtime surfaces without dropping historical storage.""" + +from contextlib import ExitStack +from pathlib import Path +from types import SimpleNamespace +from unittest.mock import Mock, PropertyMock, patch + +import pytest +from django.apps import apps +from django.db import models +from django.db.migrations.loader import MigrationLoader +from django.db.migrations.state import ModelState +from django.test import RequestFactory +from django.urls import Resolver404, resolve +from graphql import get_operation_ast, parse, validate + +from api.models import App, Team +from api.services import Providers, ServiceConfig +from api.utils.syncing.cloudflare.pages import sync_cloudflare_secrets +from api.utils.syncing.cloudflare.workers import sync_cloudflare_worker_secrets +from backend.graphene.mutations.app import UpdateAppInfoMutation +from backend.middleware import ServicePrefixMiddleware +from backend.schema import schema + + +@pytest.mark.parametrize("prefix", ["", "/public", "/service", "/service/public"]) +@pytest.mark.parametrize("trailing_slash", ["", "/"]) +def test_retired_endpoint_has_no_route(prefix, trailing_slash): + request = RequestFactory().get(f"{prefix}/kms/phApp:v1:old-key{trailing_slash}") + ServicePrefixMiddleware(Mock())(request) + with pytest.raises(Resolver404): + resolve(request.path_info) + + +def test_schema_exposes_only_inert_deprecated_kms_compatibility_fields(): + gql = schema.graphql_schema + assert {"kmsLogs", "appActivityChart"}.isdisjoint(gql.query_type.fields) + assert "rotateAppKeys" not in gql.mutation_type.fields + compatibility_fields = {"appToken", "appSeed", "appVersion", "identityKey", "wrappedKeyShare"} + app_fields = gql.get_type("AppType").fields + create_args = gql.mutation_type.fields["createApp"].args + for field in compatibility_fields: + assert app_fields[field].deprecation_reason + assert create_args[field].deprecation_reason + assert not str(create_args[field].type).endswith("!") + assert {"id", "name", "environments", "sseEnabled"} <= gql.get_type("AppType").fields.keys() + # Current Cloudflare secret sync is separate from the retired KMS product. + assert {"cloudflarePagesProjects", "cloudflareWorkers"} <= gql.query_type.fields.keys() + assert {"createCloudflarePagesSync", "createCloudflareWorkersSync"} <= gql.mutation_type.fields.keys() + assert "serviceTokens" not in gql.query_type.fields + assert "createServiceToken" not in gql.mutation_type.fields + + +def test_retired_graphql_calls_fail_validation_before_accessing_storage(): + with patch("api.models.App.objects.get") as get_app: + for operation in ( + '{ kmsLogs(appId: "old-app") { count } }', + '{ appActivityChart(appId: "old-app") { data } }', + 'mutation { rotateAppKeys(id: "old-app", appToken: "old-token", wrappedKeyShare: "old-share") { app { id } } }', + ): + result = schema.execute(operation) + assert result.errors + assert result.data is None + get_app.assert_not_called() + + +def test_cached_ordinary_client_documents_still_validate(): + document = parse((Path(__file__).parent / "fixtures" / "legacy_kms_client.graphql").read_text()) + assert validate(schema.graphql_schema, document) == [] + for operation_name in ("GetApps", "GetAppDetail", "GetOrganisationSyncs", "CreateApplication"): + assert get_operation_ast(document, operation_name) is not None + + +def test_compatibility_fields_never_read_stored_values_even_through_nested_apps(): + app = App(id="existing-app", name="App", app_version=17, app_token="retained-token", + app_seed="retained-seed", identity_key="retained-identity", wrapped_key_share="retained-share") + team = Team(id="team", name="Team") + gql = schema.graphql_schema + with ExitStack() as stack: + stack.enter_context(patch.object(gql.query_type.fields["apps"], "resolve", return_value=[app])) + stack.enter_context(patch.object(gql.query_type.fields["teams"], "resolve", return_value=[team])) + stack.enter_context(patch.object(gql.get_type("TeamType").fields["apps"], "resolve", return_value=[app])) + for field in ("identity_key", "app_token", "app_seed", "wrapped_key_share", "app_version"): + stack.enter_context(patch.object(App, field, new_callable=PropertyMock, + side_effect=AssertionError("Legacy storage must not be read"))) + result = schema.execute('''{ + apps { id name identityKey appToken appSeed wrappedKeyShare appVersion } + teams(organisationId: "org") { + apps { id name identityKey appToken appSeed wrappedKeyShare appVersion } + } + }''') + assert result.errors is None + expected = {"id": "existing-app", "name": "App", "identityKey": "", "appToken": "", + "appSeed": "", "wrappedKeyShare": "", "appVersion": 1} + assert result.data == {"apps": [expected], "teams": [{"apps": [expected]}]} + assert (app.app_token, app.app_seed, app.identity_key, app.wrapped_key_share, app.app_version) == ( + "retained-token", "retained-seed", "retained-identity", "retained-share", 17 + ) + + +@pytest.mark.parametrize("legacy_inputs", [{}, { + "identity_key": "ignored-identity", "app_token": "ignored-token", + "app_seed": "ignored-seed", "wrapped_key_share": "ignored-share", "app_version": 17, +}]) +def test_graphql_app_creation_does_not_store_kms_material(legacy_inputs): + org = Mock() + org.users.filter.return_value = [] + member = Mock() + app = App(id="new-app", name="New app") + info = SimpleNamespace(context=SimpleNamespace(user=SimpleNamespace(userId="user"))) + module = "backend.graphene.mutations.app" + with patch(f"{module}.Organisation.objects.get", return_value=org), patch( + f"{module}.user_is_org_member", return_value=True + ), patch(f"{module}.user_has_permission", return_value=True), patch( + f"{module}.App.objects.create", return_value=app + ) as create, patch(f"{module}.OrganisationMember.objects.get", return_value=member), patch( + f"{module}.Role.objects.filter", return_value=[] + ), patch(f"{module}.get_actor_info_from_graphql", return_value=("user", "user", {})), patch( + f"{module}.get_resolver_request_meta", return_value=(None, None) + ), patch(f"{module}.log_audit_event"): + if legacy_inputs: + document = (Path(__file__).parent / "fixtures" / "legacy_kms_client.graphql").read_text() + result = schema.execute(document, operation_name="CreateApplication", context_value=info.context, + variable_values={ + "id": "new-app", "organisationId": "org", "name": "New app", + "identityKey": legacy_inputs["identity_key"], + "appToken": legacy_inputs["app_token"], + "appSeed": legacy_inputs["app_seed"], + "wrappedKeyShare": legacy_inputs["wrapped_key_share"], + "appVersion": legacy_inputs["app_version"], + }) + else: + result = schema.execute('''mutation { + createApp(id: "new-app", organisationId: "org", name: "New app") { app { id name } } + }''', context_value=info.context) + create.assert_called_once_with(id="new-app", organisation=org, name="New app") + member.apps.add.assert_called_once_with(app) + assert result.errors is None + expected = {"id": "new-app", "name": "New app"} + if legacy_inputs: + expected["identityKey"] = "" + assert result.data == {"createApp": {"app": expected}} + assert app.app_version == 1 + assert all(getattr(app, field) == "" for field in ( + "identity_key", "app_token", "app_seed", "wrapped_key_share" + )) + + +@pytest.mark.parametrize("host", ["self", "cloud"]) +def test_app_save_does_not_publish_or_change_retained_credentials(settings, host): + settings.APP_HOST = host + app = App( + id="existing-app", app_token="old-token", app_seed="old-seed", + wrapped_key_share="old-share", identity_key="old-identity", app_version=1, + ) + assert App.save is models.Model.save + with patch.object(models.Model, "save") as save: + app.name = "Renamed" + app.save() + save.assert_called_once() + assert (app.app_token, app.app_seed, app.wrapped_key_share, app.identity_key, app.app_version) == ( + "old-token", "old-seed", "old-share", "old-identity", 1 + ) + + +def test_app_metadata_update_preserves_old_credentials(): + app = Mock(name="old-app") + app.name = "Old name" + app.description = "Old description" + app.app_token, app.app_seed, app.wrapped_key_share = "token", "seed", "share" + info = SimpleNamespace(context=SimpleNamespace(user=SimpleNamespace(userId="user"))) + module = "backend.graphene.mutations.app" + with patch(f"{module}.App.objects.get", return_value=app), patch( + f"{module}.user_can_access_app", return_value=True + ), patch(f"{module}.user_has_permission", return_value=True), patch( + f"{module}.get_actor_info_from_graphql", return_value=("user", "user", {}) + ), patch(f"{module}.get_resolver_request_meta", return_value=(None, None)), patch( + f"{module}.log_audit_event" + ): + result = UpdateAppInfoMutation.mutate(None, info, "existing-app", name="Renamed") + assert result.app.name == "Renamed" + assert (app.app_token, app.app_seed, app.wrapped_key_share) == ("token", "seed", "share") + + +@pytest.mark.parametrize("label,name", [("api", "App"), ("logs", "KMSDBLog")]) +def test_retained_persistence_matches_existing_migration_state(label, name): + historical = MigrationLoader(None).project_state().models[(label, name.lower())] + current = ModelState.from_model(apps.get_model(label, name)) + assert historical.options == current.options + assert historical.fields.keys() == current.fields.keys() + for field_name in historical.fields: + # Rendering a migration state can bind Field.name; the dictionary key + # above already checks names. Compare the actual field definition. + assert historical.fields[field_name].deconstruct()[1:] == current.fields[field_name].deconstruct()[1:] + + +def test_supported_cloudflare_pages_sync_still_uses_saved_provider_credentials(): + assert Providers.CLOUDFLARE["id"] == "cloudflare" + assert ServiceConfig.CLOUDFLARE_PAGES["provider"] == Providers.CLOUDFLARE + module = "api.utils.syncing.cloudflare.pages" + with patch(f"{module}.requests.get", return_value=Mock(status_code=200, json=lambda: {"result": {}})), patch( + f"{module}.requests.patch", return_value=Mock(status_code=200) + ) as update: + ok, _ = sync_cloudflare_secrets([("SECRET", "value", "")], "account", "token", "project", "production") + assert ok + assert update.call_args.args[0] == "https://api.cloudflare.com/client/v4/accounts/account/pages/projects/project" + assert update.call_args.kwargs["headers"]["Authorization"] == "Bearer token" + assert update.call_args.kwargs["json"]["deployment_configs"]["production"]["env_vars"]["SECRET"]["value"] == "value" + + +def test_supported_cloudflare_workers_sync_still_uses_saved_provider_credentials(): + assert ServiceConfig.CLOUDFLARE_WORKERS["provider"] == Providers.CLOUDFLARE + module = "api.utils.syncing.cloudflare.workers" + with patch(f"{module}.requests.get", return_value=Mock(status_code=200, json=lambda: {"result": []})), patch( + f"{module}.requests.put", return_value=Mock(status_code=200) + ) as update: + ok, _ = sync_cloudflare_worker_secrets([("SECRET", "value", "")], "account", "token", "worker") + assert ok + assert update.call_args.args[0] == "https://api.cloudflare.com/client/v4/accounts/account/workers/scripts/worker/secrets" + assert update.call_args.kwargs["headers"]["Authorization"] == "Bearer token" + assert update.call_args.kwargs["json"] == {"name": "SECRET", "text": "value", "type": "secret_text"} diff --git a/frontend/apollo/gql.ts b/frontend/apollo/gql.ts index c148e60a5..ccbf1e6d5 100644 --- a/frontend/apollo/gql.ts +++ b/frontend/apollo/gql.ts @@ -45,7 +45,7 @@ type Documents = { "mutation ModifyStripeSubscription($organisationId: ID!, $subscriptionId: String!, $planType: PlanTypeEnum!, $billingPeriod: BillingPeriodEnum!) {\n modifySubscription(\n organisationId: $organisationId\n subscriptionId: $subscriptionId\n planType: $planType\n billingPeriod: $billingPeriod\n ) {\n success\n message\n status\n }\n}": typeof types.ModifyStripeSubscriptionDocument, "mutation ResumeStripeSubscription($organisationId: ID!, $subscriptionId: String!) {\n resumeSubscription(\n organisationId: $organisationId\n subscriptionId: $subscriptionId\n ) {\n success\n message\n cancelledAt\n status\n }\n}": typeof types.ResumeStripeSubscriptionDocument, "mutation SetDefaultStripePaymentMethodOp($organisationId: ID!, $paymentMethodId: String!) {\n setDefaultPaymentMethod(\n organisationId: $organisationId\n paymentMethodId: $paymentMethodId\n ) {\n ok\n }\n}": typeof types.SetDefaultStripePaymentMethodOpDocument, - "mutation CreateApplication($id: ID!, $organisationId: ID!, $name: String!, $identityKey: String!, $appToken: String!, $appSeed: String!, $wrappedKeyShare: String!, $appVersion: Int!) {\n createApp(\n id: $id\n organisationId: $organisationId\n name: $name\n identityKey: $identityKey\n appToken: $appToken\n appSeed: $appSeed\n wrappedKeyShare: $wrappedKeyShare\n appVersion: $appVersion\n ) {\n app {\n id\n name\n identityKey\n }\n }\n}": typeof types.CreateApplicationDocument, + "mutation CreateApplication($id: ID!, $organisationId: ID!, $name: String!) {\n createApp(id: $id, organisationId: $organisationId, name: $name) {\n app {\n id\n name\n }\n }\n}": typeof types.CreateApplicationDocument, "mutation CreateOrg($id: ID!, $name: String!, $identityKey: String!, $wrappedKeyring: String!, $wrappedRecovery: String!) {\n createOrganisation(\n id: $id\n name: $name\n identityKey: $identityKey\n wrappedKeyring: $wrappedKeyring\n wrappedRecovery: $wrappedRecovery\n ) {\n organisation {\n id\n name\n memberId\n }\n }\n}": typeof types.CreateOrgDocument, "mutation DeleteApplication($id: ID!) {\n deleteApp(id: $id) {\n ok\n }\n}": typeof types.DeleteApplicationDocument, "mutation BulkProcessSecrets($secretsToCreate: [SecretInput!]!, $secretsToUpdate: [SecretInput!]!, $secretsToDelete: [ID!]!) {\n createSecrets(secretsData: $secretsToCreate) {\n secrets {\n id\n }\n }\n editSecrets(secretsData: $secretsToUpdate) {\n secrets {\n id\n }\n }\n deleteSecrets(ids: $secretsToDelete) {\n secrets {\n id\n }\n }\n}": typeof types.BulkProcessSecretsDocument, @@ -95,7 +95,6 @@ type Documents = { "mutation TransferOrgOwnership($organisationId: ID!, $newOwnerId: ID!, $billingEmail: String) {\n transferOrganisationOwnership(\n organisationId: $organisationId\n newOwnerId: $newOwnerId\n billingEmail: $billingEmail\n ) {\n ok\n }\n}": typeof types.TransferOrgOwnershipDocument, "mutation UpdateMemberRole($memberId: ID!, $roleId: ID!) {\n updateOrganisationMemberRole(memberId: $memberId, roleId: $roleId) {\n orgMember {\n id\n role {\n name\n }\n }\n }\n}": typeof types.UpdateMemberRoleDocument, "mutation UpdateWrappedSecrets($orgId: ID!, $identityKey: String!, $wrappedKeyring: String!, $wrappedRecovery: String!) {\n updateMemberWrappedSecrets(\n orgId: $orgId\n identityKey: $identityKey\n wrappedKeyring: $wrappedKeyring\n wrappedRecovery: $wrappedRecovery\n ) {\n orgMember {\n id\n }\n }\n}": typeof types.UpdateWrappedSecretsDocument, - "mutation RotateAppKey($id: ID!, $appToken: String!, $wrappedKeyShare: String!) {\n rotateAppKeys(id: $id, appToken: $appToken, wrappedKeyShare: $wrappedKeyShare) {\n app {\n id\n }\n }\n}": typeof types.RotateAppKeyDocument, "mutation CreateSCIMTokenOp($organisationId: ID!, $name: String!, $expiryDays: Int) {\n createScimToken(\n organisationId: $organisationId\n name: $name\n expiryDays: $expiryDays\n ) {\n token\n scimToken {\n id\n name\n tokenPrefix\n createdBy {\n id\n fullName\n email\n avatarUrl\n }\n createdAt\n expiresAt\n lastUsedAt\n }\n }\n}": typeof types.CreateScimTokenOpDocument, "mutation DeleteSCIMTokenOp($tokenId: ID!) {\n deleteScimToken(tokenId: $tokenId) {\n ok\n }\n}": typeof types.DeleteScimTokenOpDocument, "mutation ToggleSCIMOp($organisationId: ID!, $enabled: Boolean!) {\n toggleScim(organisationId: $organisationId, enabled: $enabled) {\n ok\n }\n}": typeof types.ToggleScimOpDocument, @@ -160,10 +159,8 @@ type Documents = { "query GetCustomerPortalLink($organisationId: ID!) {\n stripeCustomerPortalUrl(organisationId: $organisationId)\n}": typeof types.GetCustomerPortalLinkDocument, "query GetSubscriptionDetails($organisationId: ID!) {\n stripeSubscriptionDetails(organisationId: $organisationId) {\n subscriptionId\n planName\n planType\n billingPeriod\n status\n nextPaymentAmount\n currentPeriodStart\n currentPeriodEnd\n renewalDate\n cancelAt\n cancelAtPeriodEnd\n paymentMethods {\n id\n brand\n last4\n expMonth\n expYear\n isDefault\n }\n }\n}": typeof types.GetSubscriptionDetailsDocument, "query GetStripeSubscriptionEstimate($organisationId: ID!, $planType: PlanTypeEnum!, $billingPeriod: BillingPeriodEnum!, $previewV2: Boolean) {\n estimateStripeSubscription(\n organisationId: $organisationId\n planType: $planType\n billingPeriod: $billingPeriod\n previewV2: $previewV2\n ) {\n estimatedTotal\n seatCount\n unitPrice\n currency\n priceId\n }\n}": typeof types.GetStripeSubscriptionEstimateDocument, - "query GetAppActivityChart($appId: ID!, $period: TimeRange) {\n appActivityChart(appId: $appId, period: $period) {\n index\n date\n data\n }\n}": typeof types.GetAppActivityChartDocument, - "query GetAppDetail($organisationId: ID!, $appId: ID!) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n identityKey\n createdAt\n appToken\n appSeed\n appVersion\n sseEnabled\n }\n}": typeof types.GetAppDetailDocument, - "query GetAppKmsLogs($appId: ID!, $start: BigInt, $end: BigInt) {\n kmsLogs(appId: $appId, start: $start, end: $end) {\n logs {\n id\n timestamp\n phaseNode\n eventType\n ipAddress\n country\n city\n phSize\n }\n count\n }\n}": typeof types.GetAppKmsLogsDocument, - "query GetApps($organisationId: ID!, $appId: ID) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n identityKey\n createdAt\n updatedAt\n sseEnabled\n members {\n id\n email\n fullName\n avatarUrl\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n envType\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}": typeof types.GetAppsDocument, + "query GetAppDetail($organisationId: ID!, $appId: ID!) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n createdAt\n sseEnabled\n }\n}": typeof types.GetAppDetailDocument, + "query GetApps($organisationId: ID!, $appId: ID) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n createdAt\n updatedAt\n sseEnabled\n members {\n id\n email\n fullName\n avatarUrl\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n envType\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}": typeof types.GetAppsDocument, "query GetDashboard($organisationId: ID!) {\n apps(organisationId: $organisationId) {\n id\n name\n sseEnabled\n }\n userTokens(organisationId: $organisationId) {\n id\n }\n organisationInvites(orgId: $organisationId) {\n id\n }\n organisationMembers(organisationId: $organisationId, role: null) {\n id\n }\n savedCredentials(orgId: $organisationId) {\n id\n }\n syncs(orgId: $organisationId) {\n id\n }\n}": typeof types.GetDashboardDocument, "query GetOrganisations {\n organisations {\n id\n name\n identityKey\n createdAt\n plan\n planDetail {\n name\n maxUsers\n maxApps\n maxEnvsPerApp\n seatsUsed {\n users\n serviceAccounts\n total\n }\n appCount\n }\n role {\n name\n description\n color\n permissions\n }\n memberId\n memberScimManaged\n keyring\n recovery\n pricingVersion\n requireSso\n ssoProviders {\n name\n providerType\n enabled\n }\n scimEnabled\n }\n}": typeof types.GetOrganisationsDocument, "query GetAwsStsEndpoints {\n awsStsEndpoints\n}": typeof types.GetAwsStsEndpointsDocument, @@ -210,7 +207,7 @@ type Documents = { "query GetServiceAccountTokens($orgId: ID!, $id: ID) {\n serviceAccounts(orgId: $orgId, serviceAccountId: $id) {\n id\n tokens {\n id\n name\n createdAt\n expiresAt\n createdBy {\n fullName\n avatarUrl\n self\n }\n createdByServiceAccount {\n id\n name\n identityKey\n }\n lastUsed\n }\n }\n}": typeof types.GetServiceAccountTokensDocument, "query GetServiceAccounts($orgId: ID!, $id: ID) {\n serviceAccounts(orgId: $orgId, serviceAccountId: $id) {\n id\n name\n identityKey\n role {\n id\n name\n description\n color\n }\n team {\n id\n name\n }\n handlers {\n id\n wrappedKeyring\n wrappedRecovery\n user {\n self\n }\n }\n createdAt\n }\n}": typeof types.GetServiceAccountsDocument, "query GetOrgSSOProviders {\n organisations {\n id\n name\n requireSso\n ssoProviders {\n id\n providerType\n name\n publicConfig\n enabled\n createdAt\n createdBy {\n fullName\n avatarUrl\n self\n }\n updatedAt\n updatedBy {\n fullName\n avatarUrl\n self\n }\n }\n }\n serverPublicKey\n}": typeof types.GetOrgSsoProvidersDocument, - "query GetOrganisationSyncs($orgId: ID!) {\n syncs(orgId: $orgId) {\n id\n environment {\n id\n name\n envType\n app {\n id\n name\n }\n }\n path\n serviceInfo {\n id\n name\n provider {\n id\n }\n }\n options\n isActive\n lastSync\n status\n authentication {\n id\n name\n }\n createdAt\n history {\n id\n status\n createdAt\n completedAt\n meta\n }\n }\n apps(organisationId: $orgId, appId: null) {\n id\n name\n identityKey\n createdAt\n sseEnabled\n members {\n id\n fullName\n avatarUrl\n email\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}": typeof types.GetOrganisationSyncsDocument, + "query GetOrganisationSyncs($orgId: ID!) {\n syncs(orgId: $orgId) {\n id\n environment {\n id\n name\n envType\n app {\n id\n name\n }\n }\n path\n serviceInfo {\n id\n name\n provider {\n id\n }\n }\n options\n isActive\n lastSync\n status\n authentication {\n id\n name\n }\n createdAt\n history {\n id\n status\n createdAt\n completedAt\n meta\n }\n }\n apps(organisationId: $orgId, appId: null) {\n id\n name\n createdAt\n sseEnabled\n members {\n id\n fullName\n avatarUrl\n email\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}": typeof types.GetOrganisationSyncsDocument, "query GetAwsSecrets($credentialId: ID!) {\n awsSecrets(credentialId: $credentialId) {\n name\n arn\n }\n}": typeof types.GetAwsSecretsDocument, "query ValidateAWSAssumeRoleAuth {\n validateAwsAssumeRoleAuth {\n valid\n message\n method\n error\n }\n}": typeof types.ValidateAwsAssumeRoleAuthDocument, "query ValidateAWSAssumeRoleCredentials($roleArn: String!, $region: String, $externalId: String) {\n validateAwsAssumeRoleCredentials(\n roleArn: $roleArn\n region: $region\n externalId: $externalId\n ) {\n valid\n message\n error\n assumedRoleArn\n }\n}": typeof types.ValidateAwsAssumeRoleCredentialsDocument, @@ -268,7 +265,7 @@ const documents: Documents = { "mutation ModifyStripeSubscription($organisationId: ID!, $subscriptionId: String!, $planType: PlanTypeEnum!, $billingPeriod: BillingPeriodEnum!) {\n modifySubscription(\n organisationId: $organisationId\n subscriptionId: $subscriptionId\n planType: $planType\n billingPeriod: $billingPeriod\n ) {\n success\n message\n status\n }\n}": types.ModifyStripeSubscriptionDocument, "mutation ResumeStripeSubscription($organisationId: ID!, $subscriptionId: String!) {\n resumeSubscription(\n organisationId: $organisationId\n subscriptionId: $subscriptionId\n ) {\n success\n message\n cancelledAt\n status\n }\n}": types.ResumeStripeSubscriptionDocument, "mutation SetDefaultStripePaymentMethodOp($organisationId: ID!, $paymentMethodId: String!) {\n setDefaultPaymentMethod(\n organisationId: $organisationId\n paymentMethodId: $paymentMethodId\n ) {\n ok\n }\n}": types.SetDefaultStripePaymentMethodOpDocument, - "mutation CreateApplication($id: ID!, $organisationId: ID!, $name: String!, $identityKey: String!, $appToken: String!, $appSeed: String!, $wrappedKeyShare: String!, $appVersion: Int!) {\n createApp(\n id: $id\n organisationId: $organisationId\n name: $name\n identityKey: $identityKey\n appToken: $appToken\n appSeed: $appSeed\n wrappedKeyShare: $wrappedKeyShare\n appVersion: $appVersion\n ) {\n app {\n id\n name\n identityKey\n }\n }\n}": types.CreateApplicationDocument, + "mutation CreateApplication($id: ID!, $organisationId: ID!, $name: String!) {\n createApp(id: $id, organisationId: $organisationId, name: $name) {\n app {\n id\n name\n }\n }\n}": types.CreateApplicationDocument, "mutation CreateOrg($id: ID!, $name: String!, $identityKey: String!, $wrappedKeyring: String!, $wrappedRecovery: String!) {\n createOrganisation(\n id: $id\n name: $name\n identityKey: $identityKey\n wrappedKeyring: $wrappedKeyring\n wrappedRecovery: $wrappedRecovery\n ) {\n organisation {\n id\n name\n memberId\n }\n }\n}": types.CreateOrgDocument, "mutation DeleteApplication($id: ID!) {\n deleteApp(id: $id) {\n ok\n }\n}": types.DeleteApplicationDocument, "mutation BulkProcessSecrets($secretsToCreate: [SecretInput!]!, $secretsToUpdate: [SecretInput!]!, $secretsToDelete: [ID!]!) {\n createSecrets(secretsData: $secretsToCreate) {\n secrets {\n id\n }\n }\n editSecrets(secretsData: $secretsToUpdate) {\n secrets {\n id\n }\n }\n deleteSecrets(ids: $secretsToDelete) {\n secrets {\n id\n }\n }\n}": types.BulkProcessSecretsDocument, @@ -318,7 +315,6 @@ const documents: Documents = { "mutation TransferOrgOwnership($organisationId: ID!, $newOwnerId: ID!, $billingEmail: String) {\n transferOrganisationOwnership(\n organisationId: $organisationId\n newOwnerId: $newOwnerId\n billingEmail: $billingEmail\n ) {\n ok\n }\n}": types.TransferOrgOwnershipDocument, "mutation UpdateMemberRole($memberId: ID!, $roleId: ID!) {\n updateOrganisationMemberRole(memberId: $memberId, roleId: $roleId) {\n orgMember {\n id\n role {\n name\n }\n }\n }\n}": types.UpdateMemberRoleDocument, "mutation UpdateWrappedSecrets($orgId: ID!, $identityKey: String!, $wrappedKeyring: String!, $wrappedRecovery: String!) {\n updateMemberWrappedSecrets(\n orgId: $orgId\n identityKey: $identityKey\n wrappedKeyring: $wrappedKeyring\n wrappedRecovery: $wrappedRecovery\n ) {\n orgMember {\n id\n }\n }\n}": types.UpdateWrappedSecretsDocument, - "mutation RotateAppKey($id: ID!, $appToken: String!, $wrappedKeyShare: String!) {\n rotateAppKeys(id: $id, appToken: $appToken, wrappedKeyShare: $wrappedKeyShare) {\n app {\n id\n }\n }\n}": types.RotateAppKeyDocument, "mutation CreateSCIMTokenOp($organisationId: ID!, $name: String!, $expiryDays: Int) {\n createScimToken(\n organisationId: $organisationId\n name: $name\n expiryDays: $expiryDays\n ) {\n token\n scimToken {\n id\n name\n tokenPrefix\n createdBy {\n id\n fullName\n email\n avatarUrl\n }\n createdAt\n expiresAt\n lastUsedAt\n }\n }\n}": types.CreateScimTokenOpDocument, "mutation DeleteSCIMTokenOp($tokenId: ID!) {\n deleteScimToken(tokenId: $tokenId) {\n ok\n }\n}": types.DeleteScimTokenOpDocument, "mutation ToggleSCIMOp($organisationId: ID!, $enabled: Boolean!) {\n toggleScim(organisationId: $organisationId, enabled: $enabled) {\n ok\n }\n}": types.ToggleScimOpDocument, @@ -383,10 +379,8 @@ const documents: Documents = { "query GetCustomerPortalLink($organisationId: ID!) {\n stripeCustomerPortalUrl(organisationId: $organisationId)\n}": types.GetCustomerPortalLinkDocument, "query GetSubscriptionDetails($organisationId: ID!) {\n stripeSubscriptionDetails(organisationId: $organisationId) {\n subscriptionId\n planName\n planType\n billingPeriod\n status\n nextPaymentAmount\n currentPeriodStart\n currentPeriodEnd\n renewalDate\n cancelAt\n cancelAtPeriodEnd\n paymentMethods {\n id\n brand\n last4\n expMonth\n expYear\n isDefault\n }\n }\n}": types.GetSubscriptionDetailsDocument, "query GetStripeSubscriptionEstimate($organisationId: ID!, $planType: PlanTypeEnum!, $billingPeriod: BillingPeriodEnum!, $previewV2: Boolean) {\n estimateStripeSubscription(\n organisationId: $organisationId\n planType: $planType\n billingPeriod: $billingPeriod\n previewV2: $previewV2\n ) {\n estimatedTotal\n seatCount\n unitPrice\n currency\n priceId\n }\n}": types.GetStripeSubscriptionEstimateDocument, - "query GetAppActivityChart($appId: ID!, $period: TimeRange) {\n appActivityChart(appId: $appId, period: $period) {\n index\n date\n data\n }\n}": types.GetAppActivityChartDocument, - "query GetAppDetail($organisationId: ID!, $appId: ID!) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n identityKey\n createdAt\n appToken\n appSeed\n appVersion\n sseEnabled\n }\n}": types.GetAppDetailDocument, - "query GetAppKmsLogs($appId: ID!, $start: BigInt, $end: BigInt) {\n kmsLogs(appId: $appId, start: $start, end: $end) {\n logs {\n id\n timestamp\n phaseNode\n eventType\n ipAddress\n country\n city\n phSize\n }\n count\n }\n}": types.GetAppKmsLogsDocument, - "query GetApps($organisationId: ID!, $appId: ID) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n identityKey\n createdAt\n updatedAt\n sseEnabled\n members {\n id\n email\n fullName\n avatarUrl\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n envType\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}": types.GetAppsDocument, + "query GetAppDetail($organisationId: ID!, $appId: ID!) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n createdAt\n sseEnabled\n }\n}": types.GetAppDetailDocument, + "query GetApps($organisationId: ID!, $appId: ID) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n createdAt\n updatedAt\n sseEnabled\n members {\n id\n email\n fullName\n avatarUrl\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n envType\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}": types.GetAppsDocument, "query GetDashboard($organisationId: ID!) {\n apps(organisationId: $organisationId) {\n id\n name\n sseEnabled\n }\n userTokens(organisationId: $organisationId) {\n id\n }\n organisationInvites(orgId: $organisationId) {\n id\n }\n organisationMembers(organisationId: $organisationId, role: null) {\n id\n }\n savedCredentials(orgId: $organisationId) {\n id\n }\n syncs(orgId: $organisationId) {\n id\n }\n}": types.GetDashboardDocument, "query GetOrganisations {\n organisations {\n id\n name\n identityKey\n createdAt\n plan\n planDetail {\n name\n maxUsers\n maxApps\n maxEnvsPerApp\n seatsUsed {\n users\n serviceAccounts\n total\n }\n appCount\n }\n role {\n name\n description\n color\n permissions\n }\n memberId\n memberScimManaged\n keyring\n recovery\n pricingVersion\n requireSso\n ssoProviders {\n name\n providerType\n enabled\n }\n scimEnabled\n }\n}": types.GetOrganisationsDocument, "query GetAwsStsEndpoints {\n awsStsEndpoints\n}": types.GetAwsStsEndpointsDocument, @@ -433,7 +427,7 @@ const documents: Documents = { "query GetServiceAccountTokens($orgId: ID!, $id: ID) {\n serviceAccounts(orgId: $orgId, serviceAccountId: $id) {\n id\n tokens {\n id\n name\n createdAt\n expiresAt\n createdBy {\n fullName\n avatarUrl\n self\n }\n createdByServiceAccount {\n id\n name\n identityKey\n }\n lastUsed\n }\n }\n}": types.GetServiceAccountTokensDocument, "query GetServiceAccounts($orgId: ID!, $id: ID) {\n serviceAccounts(orgId: $orgId, serviceAccountId: $id) {\n id\n name\n identityKey\n role {\n id\n name\n description\n color\n }\n team {\n id\n name\n }\n handlers {\n id\n wrappedKeyring\n wrappedRecovery\n user {\n self\n }\n }\n createdAt\n }\n}": types.GetServiceAccountsDocument, "query GetOrgSSOProviders {\n organisations {\n id\n name\n requireSso\n ssoProviders {\n id\n providerType\n name\n publicConfig\n enabled\n createdAt\n createdBy {\n fullName\n avatarUrl\n self\n }\n updatedAt\n updatedBy {\n fullName\n avatarUrl\n self\n }\n }\n }\n serverPublicKey\n}": types.GetOrgSsoProvidersDocument, - "query GetOrganisationSyncs($orgId: ID!) {\n syncs(orgId: $orgId) {\n id\n environment {\n id\n name\n envType\n app {\n id\n name\n }\n }\n path\n serviceInfo {\n id\n name\n provider {\n id\n }\n }\n options\n isActive\n lastSync\n status\n authentication {\n id\n name\n }\n createdAt\n history {\n id\n status\n createdAt\n completedAt\n meta\n }\n }\n apps(organisationId: $orgId, appId: null) {\n id\n name\n identityKey\n createdAt\n sseEnabled\n members {\n id\n fullName\n avatarUrl\n email\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}": types.GetOrganisationSyncsDocument, + "query GetOrganisationSyncs($orgId: ID!) {\n syncs(orgId: $orgId) {\n id\n environment {\n id\n name\n envType\n app {\n id\n name\n }\n }\n path\n serviceInfo {\n id\n name\n provider {\n id\n }\n }\n options\n isActive\n lastSync\n status\n authentication {\n id\n name\n }\n createdAt\n history {\n id\n status\n createdAt\n completedAt\n meta\n }\n }\n apps(organisationId: $orgId, appId: null) {\n id\n name\n createdAt\n sseEnabled\n members {\n id\n fullName\n avatarUrl\n email\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}": types.GetOrganisationSyncsDocument, "query GetAwsSecrets($credentialId: ID!) {\n awsSecrets(credentialId: $credentialId) {\n name\n arn\n }\n}": types.GetAwsSecretsDocument, "query ValidateAWSAssumeRoleAuth {\n validateAwsAssumeRoleAuth {\n valid\n message\n method\n error\n }\n}": types.ValidateAwsAssumeRoleAuthDocument, "query ValidateAWSAssumeRoleCredentials($roleArn: String!, $region: String, $externalId: String) {\n validateAwsAssumeRoleCredentials(\n roleArn: $roleArn\n region: $region\n externalId: $externalId\n ) {\n valid\n message\n error\n assumedRoleArn\n }\n}": types.ValidateAwsAssumeRoleCredentialsDocument, @@ -601,7 +595,7 @@ export function graphql(source: "mutation SetDefaultStripePaymentMethodOp($organ /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "mutation CreateApplication($id: ID!, $organisationId: ID!, $name: String!, $identityKey: String!, $appToken: String!, $appSeed: String!, $wrappedKeyShare: String!, $appVersion: Int!) {\n createApp(\n id: $id\n organisationId: $organisationId\n name: $name\n identityKey: $identityKey\n appToken: $appToken\n appSeed: $appSeed\n wrappedKeyShare: $wrappedKeyShare\n appVersion: $appVersion\n ) {\n app {\n id\n name\n identityKey\n }\n }\n}"): (typeof documents)["mutation CreateApplication($id: ID!, $organisationId: ID!, $name: String!, $identityKey: String!, $appToken: String!, $appSeed: String!, $wrappedKeyShare: String!, $appVersion: Int!) {\n createApp(\n id: $id\n organisationId: $organisationId\n name: $name\n identityKey: $identityKey\n appToken: $appToken\n appSeed: $appSeed\n wrappedKeyShare: $wrappedKeyShare\n appVersion: $appVersion\n ) {\n app {\n id\n name\n identityKey\n }\n }\n}"]; +export function graphql(source: "mutation CreateApplication($id: ID!, $organisationId: ID!, $name: String!) {\n createApp(id: $id, organisationId: $organisationId, name: $name) {\n app {\n id\n name\n }\n }\n}"): (typeof documents)["mutation CreateApplication($id: ID!, $organisationId: ID!, $name: String!) {\n createApp(id: $id, organisationId: $organisationId, name: $name) {\n app {\n id\n name\n }\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -798,10 +792,6 @@ export function graphql(source: "mutation UpdateMemberRole($memberId: ID!, $role * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "mutation UpdateWrappedSecrets($orgId: ID!, $identityKey: String!, $wrappedKeyring: String!, $wrappedRecovery: String!) {\n updateMemberWrappedSecrets(\n orgId: $orgId\n identityKey: $identityKey\n wrappedKeyring: $wrappedKeyring\n wrappedRecovery: $wrappedRecovery\n ) {\n orgMember {\n id\n }\n }\n}"): (typeof documents)["mutation UpdateWrappedSecrets($orgId: ID!, $identityKey: String!, $wrappedKeyring: String!, $wrappedRecovery: String!) {\n updateMemberWrappedSecrets(\n orgId: $orgId\n identityKey: $identityKey\n wrappedKeyring: $wrappedKeyring\n wrappedRecovery: $wrappedRecovery\n ) {\n orgMember {\n id\n }\n }\n}"]; -/** - * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. - */ -export function graphql(source: "mutation RotateAppKey($id: ID!, $appToken: String!, $wrappedKeyShare: String!) {\n rotateAppKeys(id: $id, appToken: $appToken, wrappedKeyShare: $wrappedKeyShare) {\n app {\n id\n }\n }\n}"): (typeof documents)["mutation RotateAppKey($id: ID!, $appToken: String!, $wrappedKeyShare: String!) {\n rotateAppKeys(id: $id, appToken: $appToken, wrappedKeyShare: $wrappedKeyShare) {\n app {\n id\n }\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -1061,19 +1051,11 @@ export function graphql(source: "query GetStripeSubscriptionEstimate($organisati /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "query GetAppActivityChart($appId: ID!, $period: TimeRange) {\n appActivityChart(appId: $appId, period: $period) {\n index\n date\n data\n }\n}"): (typeof documents)["query GetAppActivityChart($appId: ID!, $period: TimeRange) {\n appActivityChart(appId: $appId, period: $period) {\n index\n date\n data\n }\n}"]; -/** - * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. - */ -export function graphql(source: "query GetAppDetail($organisationId: ID!, $appId: ID!) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n identityKey\n createdAt\n appToken\n appSeed\n appVersion\n sseEnabled\n }\n}"): (typeof documents)["query GetAppDetail($organisationId: ID!, $appId: ID!) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n identityKey\n createdAt\n appToken\n appSeed\n appVersion\n sseEnabled\n }\n}"]; -/** - * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. - */ -export function graphql(source: "query GetAppKmsLogs($appId: ID!, $start: BigInt, $end: BigInt) {\n kmsLogs(appId: $appId, start: $start, end: $end) {\n logs {\n id\n timestamp\n phaseNode\n eventType\n ipAddress\n country\n city\n phSize\n }\n count\n }\n}"): (typeof documents)["query GetAppKmsLogs($appId: ID!, $start: BigInt, $end: BigInt) {\n kmsLogs(appId: $appId, start: $start, end: $end) {\n logs {\n id\n timestamp\n phaseNode\n eventType\n ipAddress\n country\n city\n phSize\n }\n count\n }\n}"]; +export function graphql(source: "query GetAppDetail($organisationId: ID!, $appId: ID!) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n createdAt\n sseEnabled\n }\n}"): (typeof documents)["query GetAppDetail($organisationId: ID!, $appId: ID!) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n createdAt\n sseEnabled\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "query GetApps($organisationId: ID!, $appId: ID) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n identityKey\n createdAt\n updatedAt\n sseEnabled\n members {\n id\n email\n fullName\n avatarUrl\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n envType\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}"): (typeof documents)["query GetApps($organisationId: ID!, $appId: ID) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n identityKey\n createdAt\n updatedAt\n sseEnabled\n members {\n id\n email\n fullName\n avatarUrl\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n envType\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}"]; +export function graphql(source: "query GetApps($organisationId: ID!, $appId: ID) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n createdAt\n updatedAt\n sseEnabled\n members {\n id\n email\n fullName\n avatarUrl\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n envType\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}"): (typeof documents)["query GetApps($organisationId: ID!, $appId: ID) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n description\n createdAt\n updatedAt\n sseEnabled\n members {\n id\n email\n fullName\n avatarUrl\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n envType\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -1261,7 +1243,7 @@ export function graphql(source: "query GetOrgSSOProviders {\n organisations {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "query GetOrganisationSyncs($orgId: ID!) {\n syncs(orgId: $orgId) {\n id\n environment {\n id\n name\n envType\n app {\n id\n name\n }\n }\n path\n serviceInfo {\n id\n name\n provider {\n id\n }\n }\n options\n isActive\n lastSync\n status\n authentication {\n id\n name\n }\n createdAt\n history {\n id\n status\n createdAt\n completedAt\n meta\n }\n }\n apps(organisationId: $orgId, appId: null) {\n id\n name\n identityKey\n createdAt\n sseEnabled\n members {\n id\n fullName\n avatarUrl\n email\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}"): (typeof documents)["query GetOrganisationSyncs($orgId: ID!) {\n syncs(orgId: $orgId) {\n id\n environment {\n id\n name\n envType\n app {\n id\n name\n }\n }\n path\n serviceInfo {\n id\n name\n provider {\n id\n }\n }\n options\n isActive\n lastSync\n status\n authentication {\n id\n name\n }\n createdAt\n history {\n id\n status\n createdAt\n completedAt\n meta\n }\n }\n apps(organisationId: $orgId, appId: null) {\n id\n name\n identityKey\n createdAt\n sseEnabled\n members {\n id\n fullName\n avatarUrl\n email\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}"]; +export function graphql(source: "query GetOrganisationSyncs($orgId: ID!) {\n syncs(orgId: $orgId) {\n id\n environment {\n id\n name\n envType\n app {\n id\n name\n }\n }\n path\n serviceInfo {\n id\n name\n provider {\n id\n }\n }\n options\n isActive\n lastSync\n status\n authentication {\n id\n name\n }\n createdAt\n history {\n id\n status\n createdAt\n completedAt\n meta\n }\n }\n apps(organisationId: $orgId, appId: null) {\n id\n name\n createdAt\n sseEnabled\n members {\n id\n fullName\n avatarUrl\n email\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}"): (typeof documents)["query GetOrganisationSyncs($orgId: ID!) {\n syncs(orgId: $orgId) {\n id\n environment {\n id\n name\n envType\n app {\n id\n name\n }\n }\n path\n serviceInfo {\n id\n name\n provider {\n id\n }\n }\n options\n isActive\n lastSync\n status\n authentication {\n id\n name\n }\n createdAt\n history {\n id\n status\n createdAt\n completedAt\n meta\n }\n }\n apps(organisationId: $orgId, appId: null) {\n id\n name\n createdAt\n sseEnabled\n members {\n id\n fullName\n avatarUrl\n email\n }\n serviceAccounts {\n id\n name\n }\n environments {\n id\n name\n syncs {\n id\n serviceInfo {\n id\n name\n provider {\n id\n name\n }\n }\n status\n }\n }\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/frontend/apollo/graphql.ts b/frontend/apollo/graphql.ts index ce815fe33..359e3e8d3 100644 --- a/frontend/apollo/graphql.ts +++ b/frontend/apollo/graphql.ts @@ -490,19 +490,24 @@ export type AppMembershipType = { export type AppType = { __typename?: 'AppType'; + /** @deprecated Legacy KMS is retired; always empty. */ appSeed: Scalars['String']['output']; + /** @deprecated Legacy KMS is retired; always empty. */ appToken: Scalars['String']['output']; + /** @deprecated Legacy KMS is retired; always 1. */ appVersion: Scalars['Int']['output']; createdAt?: Maybe; description?: Maybe; environments: Array>; id: Scalars['String']['output']; + /** @deprecated Legacy KMS is retired; always empty. */ identityKey: Scalars['String']['output']; members: Array>; name: Scalars['String']['output']; serviceAccounts: Array>; sseEnabled: Scalars['Boolean']['output']; updatedAt: Scalars['DateTime']['output']; + /** @deprecated Legacy KMS is retired; always empty. */ wrappedKeyShare: Scalars['String']['output']; }; @@ -614,13 +619,6 @@ export type ChangeAccountPasswordMutation = { orgMember?: Maybe; }; -export type ChartDataPointType = { - __typename?: 'ChartDataPointType'; - data?: Maybe; - date?: Maybe; - index?: Maybe; -}; - export type CloudFlarePagesType = { __typename?: 'CloudFlarePagesType'; deploymentId?: Maybe; @@ -1285,30 +1283,6 @@ export type InviteInput = { roleId: Scalars['ID']['input']; }; -export type KmsLogType = Node & { - __typename?: 'KMSLogType'; - appId?: Maybe; - asn?: Maybe; - city?: Maybe; - country?: Maybe; - edgeLocation?: Maybe; - eventType?: Maybe; - id: Scalars['ID']['output']; - ipAddress?: Maybe; - isp?: Maybe; - latitude?: Maybe; - longitude?: Maybe; - phSize?: Maybe; - phaseNode?: Maybe; - timestamp?: Maybe; -}; - -export type KmsLogsResponseType = { - __typename?: 'KMSLogsResponseType'; - count?: Maybe; - logs?: Maybe>>; -}; - export type KeyMap = { __typename?: 'KeyMap'; id?: Maybe; @@ -1625,7 +1599,6 @@ export type Mutation = { retryLogStreamDelivery?: Maybe; revokeDynamicSecretLease?: Maybe; revokeRotatingSecretCredential?: Maybe; - rotateAppKeys?: Maybe; rotateRotatingSecret?: Maybe; setDefaultPaymentMethod?: Maybe; testLogStreamConnection?: Maybe; @@ -1750,14 +1723,14 @@ export type MutationConfirmEmailChangeArgs = { export type MutationCreateAppArgs = { - appSeed: Scalars['String']['input']; - appToken: Scalars['String']['input']; - appVersion: Scalars['Int']['input']; + appSeed?: InputMaybe; + appToken?: InputMaybe; + appVersion?: InputMaybe; id: Scalars['ID']['input']; - identityKey: Scalars['String']['input']; + identityKey?: InputMaybe; name: Scalars['String']['input']; organisationId: Scalars['ID']['input']; - wrappedKeyShare: Scalars['String']['input']; + wrappedKeyShare?: InputMaybe; }; @@ -2371,13 +2344,6 @@ export type MutationRevokeRotatingSecretCredentialArgs = { }; -export type MutationRotateAppKeysArgs = { - appToken: Scalars['String']['input']; - id: Scalars['ID']['input']; - wrappedKeyShare: Scalars['String']['input']; -}; - - export type MutationRotateRotatingSecretArgs = { rotatingSecretId: Scalars['ID']['input']; }; @@ -2650,12 +2616,6 @@ export type NetworkAccessPolicyType = { updatedBy?: Maybe; }; -/** An object with an ID */ -export type Node = { - /** The ID of the object */ - id: Scalars['ID']['output']; -}; - export type OpenAiProjectType = { __typename?: 'OpenAIProjectType'; id: Scalars['String']['output']; @@ -2837,7 +2797,6 @@ export type Query = { __typename?: 'Query'; accountDeletionReadiness?: Maybe; accountIdentities?: Maybe; - appActivityChart?: Maybe>>; appEnvironments?: Maybe>>; appServiceAccounts?: Maybe>>; appUsers?: Maybe>>; @@ -2864,7 +2823,6 @@ export type Query = { gitlabProjects?: Maybe>>; identities?: Maybe>>; identityProviders?: Maybe>>; - kmsLogs?: Maybe; license?: Maybe; logStreamDeliveries?: Maybe; logStreamProviders?: Maybe>>; @@ -2919,12 +2877,6 @@ export type Query = { }; -export type QueryAppActivityChartArgs = { - appId?: InputMaybe; - period?: InputMaybe; -}; - - export type QueryAppEnvironmentsArgs = { appId?: InputMaybe; environmentId?: InputMaybe; @@ -3062,13 +3014,6 @@ export type QueryIdentitiesArgs = { }; -export type QueryKmsLogsArgs = { - appId?: InputMaybe; - end?: InputMaybe; - start?: InputMaybe; -}; - - export type QueryLogStreamDeliveriesArgs = { limit?: InputMaybe; offset?: InputMaybe; @@ -3439,11 +3384,6 @@ export type RoleType = { permissions?: Maybe; }; -export type RotateAppKeysMutation = { - __typename?: 'RotateAppKeysMutation'; - app?: Maybe; -}; - export type RotatingSecretCredentialType = { __typename?: 'RotatingSecretCredentialType'; createdAt?: Maybe; @@ -3806,15 +3746,6 @@ export type TestOrganisationSsoProviderMutation = { success?: Maybe; }; -export enum TimeRange { - AllTime = 'ALL_TIME', - Day = 'DAY', - Hour = 'HOUR', - Month = 'MONTH', - Week = 'WEEK', - Year = 'YEAR' -} - export type ToggleLogStreamMutation = { __typename?: 'ToggleLogStreamMutation'; logStream?: Maybe; @@ -4305,15 +4236,10 @@ export type CreateApplicationMutationVariables = Exact<{ id: Scalars['ID']['input']; organisationId: Scalars['ID']['input']; name: Scalars['String']['input']; - identityKey: Scalars['String']['input']; - appToken: Scalars['String']['input']; - appSeed: Scalars['String']['input']; - wrappedKeyShare: Scalars['String']['input']; - appVersion: Scalars['Int']['input']; }>; -export type CreateApplicationMutation = { __typename?: 'Mutation', createApp?: { __typename?: 'CreateAppMutation', app?: { __typename?: 'AppType', id: string, name: string, identityKey: string } | null } | null }; +export type CreateApplicationMutation = { __typename?: 'Mutation', createApp?: { __typename?: 'CreateAppMutation', app?: { __typename?: 'AppType', id: string, name: string } | null } | null }; export type CreateOrgMutationVariables = Exact<{ id: Scalars['ID']['input']; @@ -4782,15 +4708,6 @@ export type UpdateWrappedSecretsMutationVariables = Exact<{ export type UpdateWrappedSecretsMutation = { __typename?: 'Mutation', updateMemberWrappedSecrets?: { __typename?: 'UpdateUserWrappedSecretsMutation', orgMember?: { __typename?: 'OrganisationMemberType', id: string } | null } | null }; -export type RotateAppKeyMutationVariables = Exact<{ - id: Scalars['ID']['input']; - appToken: Scalars['String']['input']; - wrappedKeyShare: Scalars['String']['input']; -}>; - - -export type RotateAppKeyMutation = { __typename?: 'Mutation', rotateAppKeys?: { __typename?: 'RotateAppKeysMutation', app?: { __typename?: 'AppType', id: string } | null } | null }; - export type CreateScimTokenOpMutationVariables = Exact<{ organisationId: Scalars['ID']['input']; name: Scalars['String']['input']; @@ -5362,30 +5279,13 @@ export type GetStripeSubscriptionEstimateQueryVariables = Exact<{ export type GetStripeSubscriptionEstimateQuery = { __typename?: 'Query', estimateStripeSubscription?: { __typename?: 'StripePlanEstimate', estimatedTotal?: number | null, seatCount?: number | null, unitPrice?: number | null, currency?: string | null, priceId?: string | null } | null }; -export type GetAppActivityChartQueryVariables = Exact<{ - appId: Scalars['ID']['input']; - period?: InputMaybe; -}>; - - -export type GetAppActivityChartQuery = { __typename?: 'Query', appActivityChart?: Array<{ __typename?: 'ChartDataPointType', index?: number | null, date?: any | null, data?: number | null } | null> | null }; - export type GetAppDetailQueryVariables = Exact<{ organisationId: Scalars['ID']['input']; appId: Scalars['ID']['input']; }>; -export type GetAppDetailQuery = { __typename?: 'Query', apps?: Array<{ __typename?: 'AppType', id: string, name: string, description?: string | null, identityKey: string, createdAt?: any | null, appToken: string, appSeed: string, appVersion: number, sseEnabled: boolean } | null> | null }; - -export type GetAppKmsLogsQueryVariables = Exact<{ - appId: Scalars['ID']['input']; - start?: InputMaybe; - end?: InputMaybe; -}>; - - -export type GetAppKmsLogsQuery = { __typename?: 'Query', kmsLogs?: { __typename?: 'KMSLogsResponseType', count?: number | null, logs?: Array<{ __typename?: 'KMSLogType', id: string, timestamp?: any | null, phaseNode?: string | null, eventType?: string | null, ipAddress?: string | null, country?: string | null, city?: string | null, phSize?: number | null } | null> | null } | null }; +export type GetAppDetailQuery = { __typename?: 'Query', apps?: Array<{ __typename?: 'AppType', id: string, name: string, description?: string | null, createdAt?: any | null, sseEnabled: boolean } | null> | null }; export type GetAppsQueryVariables = Exact<{ organisationId: Scalars['ID']['input']; @@ -5393,7 +5293,7 @@ export type GetAppsQueryVariables = Exact<{ }>; -export type GetAppsQuery = { __typename?: 'Query', apps?: Array<{ __typename?: 'AppType', id: string, name: string, description?: string | null, identityKey: string, createdAt?: any | null, updatedAt: any, sseEnabled: boolean, members: Array<{ __typename?: 'OrganisationMemberType', id: string, email?: string | null, fullName?: string | null, avatarUrl?: string | null } | null>, serviceAccounts: Array<{ __typename?: 'ServiceAccountType', id: string, name: string } | null>, environments: Array<{ __typename?: 'EnvironmentType', id: string, name: string, envType: ApiEnvironmentEnvTypeChoices, syncs: Array<{ __typename?: 'EnvironmentSyncType', id: string, status: ApiEnvironmentSyncStatusChoices, serviceInfo?: { __typename?: 'ServiceType', id?: string | null, name?: string | null, provider?: { __typename?: 'ProviderType', id: string, name: string } | null } | null } | null> } | null> } | null> | null }; +export type GetAppsQuery = { __typename?: 'Query', apps?: Array<{ __typename?: 'AppType', id: string, name: string, description?: string | null, createdAt?: any | null, updatedAt: any, sseEnabled: boolean, members: Array<{ __typename?: 'OrganisationMemberType', id: string, email?: string | null, fullName?: string | null, avatarUrl?: string | null } | null>, serviceAccounts: Array<{ __typename?: 'ServiceAccountType', id: string, name: string } | null>, environments: Array<{ __typename?: 'EnvironmentType', id: string, name: string, envType: ApiEnvironmentEnvTypeChoices, syncs: Array<{ __typename?: 'EnvironmentSyncType', id: string, status: ApiEnvironmentSyncStatusChoices, serviceInfo?: { __typename?: 'ServiceType', id?: string | null, name?: string | null, provider?: { __typename?: 'ProviderType', id: string, name: string } | null } | null } | null> } | null> } | null> | null }; export type GetDashboardQueryVariables = Exact<{ organisationId: Scalars['ID']['input']; @@ -5755,7 +5655,7 @@ export type GetOrganisationSyncsQueryVariables = Exact<{ }>; -export type GetOrganisationSyncsQuery = { __typename?: 'Query', syncs?: Array<{ __typename?: 'EnvironmentSyncType', id: string, path: string, options: any, isActive: boolean, lastSync?: any | null, status: ApiEnvironmentSyncStatusChoices, createdAt?: any | null, environment: { __typename?: 'EnvironmentType', id: string, name: string, envType: ApiEnvironmentEnvTypeChoices, app: { __typename?: 'AppMembershipType', id: string, name: string } }, serviceInfo?: { __typename?: 'ServiceType', id?: string | null, name?: string | null, provider?: { __typename?: 'ProviderType', id: string } | null } | null, authentication?: { __typename?: 'ProviderCredentialsType', id: string, name: string } | null, history: Array<{ __typename?: 'EnvironmentSyncEventType', id: string, status: ApiEnvironmentSyncEventStatusChoices, createdAt?: any | null, completedAt?: any | null, meta?: any | null }> } | null> | null, apps?: Array<{ __typename?: 'AppType', id: string, name: string, identityKey: string, createdAt?: any | null, sseEnabled: boolean, members: Array<{ __typename?: 'OrganisationMemberType', id: string, fullName?: string | null, avatarUrl?: string | null, email?: string | null } | null>, serviceAccounts: Array<{ __typename?: 'ServiceAccountType', id: string, name: string } | null>, environments: Array<{ __typename?: 'EnvironmentType', id: string, name: string, syncs: Array<{ __typename?: 'EnvironmentSyncType', id: string, status: ApiEnvironmentSyncStatusChoices, serviceInfo?: { __typename?: 'ServiceType', id?: string | null, name?: string | null, provider?: { __typename?: 'ProviderType', id: string, name: string } | null } | null } | null> } | null> } | null> | null }; +export type GetOrganisationSyncsQuery = { __typename?: 'Query', syncs?: Array<{ __typename?: 'EnvironmentSyncType', id: string, path: string, options: any, isActive: boolean, lastSync?: any | null, status: ApiEnvironmentSyncStatusChoices, createdAt?: any | null, environment: { __typename?: 'EnvironmentType', id: string, name: string, envType: ApiEnvironmentEnvTypeChoices, app: { __typename?: 'AppMembershipType', id: string, name: string } }, serviceInfo?: { __typename?: 'ServiceType', id?: string | null, name?: string | null, provider?: { __typename?: 'ProviderType', id: string } | null } | null, authentication?: { __typename?: 'ProviderCredentialsType', id: string, name: string } | null, history: Array<{ __typename?: 'EnvironmentSyncEventType', id: string, status: ApiEnvironmentSyncEventStatusChoices, createdAt?: any | null, completedAt?: any | null, meta?: any | null }> } | null> | null, apps?: Array<{ __typename?: 'AppType', id: string, name: string, createdAt?: any | null, sseEnabled: boolean, members: Array<{ __typename?: 'OrganisationMemberType', id: string, fullName?: string | null, avatarUrl?: string | null, email?: string | null } | null>, serviceAccounts: Array<{ __typename?: 'ServiceAccountType', id: string, name: string } | null>, environments: Array<{ __typename?: 'EnvironmentType', id: string, name: string, syncs: Array<{ __typename?: 'EnvironmentSyncType', id: string, status: ApiEnvironmentSyncStatusChoices, serviceInfo?: { __typename?: 'ServiceType', id?: string | null, name?: string | null, provider?: { __typename?: 'ProviderType', id: string, name: string } | null } | null } | null> } | null> } | null> | null }; export type GetAwsSecretsQueryVariables = Exact<{ credentialId: Scalars['ID']['input']; @@ -5956,7 +5856,7 @@ export const MigratePricingOpDocument = {"kind":"Document","definitions":[{"kind export const ModifyStripeSubscriptionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ModifyStripeSubscription"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"subscriptionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"planType"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PlanTypeEnum"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"billingPeriod"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"BillingPeriodEnum"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"modifySubscription"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"subscriptionId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"subscriptionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"planType"},"value":{"kind":"Variable","name":{"kind":"Name","value":"planType"}}},{"kind":"Argument","name":{"kind":"Name","value":"billingPeriod"},"value":{"kind":"Variable","name":{"kind":"Name","value":"billingPeriod"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]} as unknown as DocumentNode; export const ResumeStripeSubscriptionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ResumeStripeSubscription"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"subscriptionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resumeSubscription"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"subscriptionId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"subscriptionId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"cancelledAt"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]} as unknown as DocumentNode; export const SetDefaultStripePaymentMethodOpDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetDefaultStripePaymentMethodOp"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"paymentMethodId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setDefaultPaymentMethod"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"paymentMethodId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"paymentMethodId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const CreateApplicationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateApplication"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appToken"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appSeed"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appVersion"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createApp"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"identityKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}}},{"kind":"Argument","name":{"kind":"Name","value":"appToken"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appToken"}}},{"kind":"Argument","name":{"kind":"Name","value":"appSeed"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appSeed"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedKeyShare"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}}},{"kind":"Argument","name":{"kind":"Name","value":"appVersion"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appVersion"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}}]}}]} as unknown as DocumentNode; +export const CreateApplicationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateApplication"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createApp"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateOrgDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOrg"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyring"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedRecovery"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOrganisation"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"identityKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedKeyring"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyring"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedRecovery"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedRecovery"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"memberId"}}]}}]}}]}}]} as unknown as DocumentNode; export const DeleteApplicationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteApplication"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteApp"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const BulkProcessSecretsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"BulkProcessSecrets"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"secretsToCreate"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SecretInput"}}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"secretsToUpdate"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SecretInput"}}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"secretsToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createSecrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"secretsData"},"value":{"kind":"Variable","name":{"kind":"Name","value":"secretsToCreate"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"secrets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"editSecrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"secretsData"},"value":{"kind":"Variable","name":{"kind":"Name","value":"secretsToUpdate"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"secrets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleteSecrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ids"},"value":{"kind":"Variable","name":{"kind":"Name","value":"secretsToDelete"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"secrets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; @@ -6006,7 +5906,6 @@ export const InitAccountKeysDocument = {"kind":"Document","definitions":[{"kind" export const TransferOrgOwnershipDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TransferOrgOwnership"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"newOwnerId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"billingEmail"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"transferOrganisationOwnership"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"newOwnerId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"newOwnerId"}}},{"kind":"Argument","name":{"kind":"Name","value":"billingEmail"},"value":{"kind":"Variable","name":{"kind":"Name","value":"billingEmail"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const UpdateMemberRoleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateMemberRole"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"memberId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"roleId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateOrganisationMemberRole"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"memberId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"memberId"}}},{"kind":"Argument","name":{"kind":"Name","value":"roleId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"roleId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"orgMember"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const UpdateWrappedSecretsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateWrappedSecrets"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyring"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedRecovery"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateMemberWrappedSecrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"identityKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedKeyring"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyring"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedRecovery"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedRecovery"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"orgMember"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; -export const RotateAppKeyDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RotateAppKey"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appToken"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"rotateAppKeys"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"appToken"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appToken"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedKeyShare"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateScimTokenOpDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateSCIMTokenOp"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"expiryDays"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createScimToken"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"expiryDays"},"value":{"kind":"Variable","name":{"kind":"Name","value":"expiryDays"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"token"}},{"kind":"Field","name":{"kind":"Name","value":"scimToken"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"tokenPrefix"}},{"kind":"Field","name":{"kind":"Name","value":"createdBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}},{"kind":"Field","name":{"kind":"Name","value":"lastUsedAt"}}]}}]}}]}}]} as unknown as DocumentNode; export const DeleteScimTokenOpDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteSCIMTokenOp"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteScimToken"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"tokenId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const ToggleScimOpDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ToggleSCIMOp"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"enabled"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"toggleScim"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"enabled"},"value":{"kind":"Variable","name":{"kind":"Name","value":"enabled"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; @@ -6071,10 +5970,8 @@ export const GetCheckoutDetailsDocument = {"kind":"Document","definitions":[{"ki export const GetCustomerPortalLinkDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetCustomerPortalLink"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stripeCustomerPortalUrl"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}]}]}}]} as unknown as DocumentNode; export const GetSubscriptionDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSubscriptionDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stripeSubscriptionDetails"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptionId"}},{"kind":"Field","name":{"kind":"Name","value":"planName"}},{"kind":"Field","name":{"kind":"Name","value":"planType"}},{"kind":"Field","name":{"kind":"Name","value":"billingPeriod"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"nextPaymentAmount"}},{"kind":"Field","name":{"kind":"Name","value":"currentPeriodStart"}},{"kind":"Field","name":{"kind":"Name","value":"currentPeriodEnd"}},{"kind":"Field","name":{"kind":"Name","value":"renewalDate"}},{"kind":"Field","name":{"kind":"Name","value":"cancelAt"}},{"kind":"Field","name":{"kind":"Name","value":"cancelAtPeriodEnd"}},{"kind":"Field","name":{"kind":"Name","value":"paymentMethods"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"brand"}},{"kind":"Field","name":{"kind":"Name","value":"last4"}},{"kind":"Field","name":{"kind":"Name","value":"expMonth"}},{"kind":"Field","name":{"kind":"Name","value":"expYear"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetStripeSubscriptionEstimateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetStripeSubscriptionEstimate"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"planType"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PlanTypeEnum"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"billingPeriod"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"BillingPeriodEnum"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"previewV2"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"estimateStripeSubscription"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"planType"},"value":{"kind":"Variable","name":{"kind":"Name","value":"planType"}}},{"kind":"Argument","name":{"kind":"Name","value":"billingPeriod"},"value":{"kind":"Variable","name":{"kind":"Name","value":"billingPeriod"}}},{"kind":"Argument","name":{"kind":"Name","value":"previewV2"},"value":{"kind":"Variable","name":{"kind":"Name","value":"previewV2"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"estimatedTotal"}},{"kind":"Field","name":{"kind":"Name","value":"seatCount"}},{"kind":"Field","name":{"kind":"Name","value":"unitPrice"}},{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"priceId"}}]}}]}}]} as unknown as DocumentNode; -export const GetAppActivityChartDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppActivityChart"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"period"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"TimeRange"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"appActivityChart"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"period"},"value":{"kind":"Variable","name":{"kind":"Name","value":"period"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"index"}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"data"}}]}}]}}]} as unknown as DocumentNode; -export const GetAppDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apps"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"appToken"}},{"kind":"Field","name":{"kind":"Name","value":"appSeed"}},{"kind":"Field","name":{"kind":"Name","value":"appVersion"}},{"kind":"Field","name":{"kind":"Name","value":"sseEnabled"}}]}}]}}]} as unknown as DocumentNode; -export const GetAppKmsLogsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppKmsLogs"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"start"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"end"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"kmsLogs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"start"},"value":{"kind":"Variable","name":{"kind":"Name","value":"start"}}},{"kind":"Argument","name":{"kind":"Name","value":"end"},"value":{"kind":"Variable","name":{"kind":"Name","value":"end"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"logs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"phaseNode"}},{"kind":"Field","name":{"kind":"Name","value":"eventType"}},{"kind":"Field","name":{"kind":"Name","value":"ipAddress"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"city"}},{"kind":"Field","name":{"kind":"Name","value":"phSize"}}]}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}}]}}]} as unknown as DocumentNode; -export const GetAppsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetApps"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apps"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sseEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"environments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"envType"}},{"kind":"Field","name":{"kind":"Name","value":"syncs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"serviceInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"provider"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetAppDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apps"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"sseEnabled"}}]}}]}}]} as unknown as DocumentNode; +export const GetAppsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetApps"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apps"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sseEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"environments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"envType"}},{"kind":"Field","name":{"kind":"Name","value":"syncs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"serviceInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"provider"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const GetDashboardDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetDashboard"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apps"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"sseEnabled"}}]}},{"kind":"Field","name":{"kind":"Name","value":"userTokens"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"organisationInvites"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"organisationMembers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"role"},"value":{"kind":"NullValue"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"savedCredentials"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"syncs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const GetOrganisationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrganisations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"plan"}},{"kind":"Field","name":{"kind":"Name","value":"planDetail"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"maxUsers"}},{"kind":"Field","name":{"kind":"Name","value":"maxApps"}},{"kind":"Field","name":{"kind":"Name","value":"maxEnvsPerApp"}},{"kind":"Field","name":{"kind":"Name","value":"seatsUsed"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"users"}},{"kind":"Field","name":{"kind":"Name","value":"serviceAccounts"}},{"kind":"Field","name":{"kind":"Name","value":"total"}}]}},{"kind":"Field","name":{"kind":"Name","value":"appCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"color"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"}}]}},{"kind":"Field","name":{"kind":"Name","value":"memberId"}},{"kind":"Field","name":{"kind":"Name","value":"memberScimManaged"}},{"kind":"Field","name":{"kind":"Name","value":"keyring"}},{"kind":"Field","name":{"kind":"Name","value":"recovery"}},{"kind":"Field","name":{"kind":"Name","value":"pricingVersion"}},{"kind":"Field","name":{"kind":"Name","value":"requireSso"}},{"kind":"Field","name":{"kind":"Name","value":"ssoProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"providerType"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}}]}},{"kind":"Field","name":{"kind":"Name","value":"scimEnabled"}}]}}]}}]} as unknown as DocumentNode; export const GetAwsStsEndpointsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAwsStsEndpoints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"awsStsEndpoints"}}]}}]} as unknown as DocumentNode; @@ -6121,7 +6018,7 @@ export const GetServiceAccountHandlersDocument = {"kind":"Document","definitions export const GetServiceAccountTokensDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetServiceAccountTokens"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serviceAccounts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"serviceAccountId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"tokens"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"self"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdByServiceAccount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lastUsed"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetServiceAccountsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetServiceAccounts"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serviceAccounts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"serviceAccountId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"handlers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedKeyring"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedRecovery"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"self"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]} as unknown as DocumentNode; export const GetOrgSsoProvidersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrgSSOProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"requireSso"}},{"kind":"Field","name":{"kind":"Name","value":"ssoProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"providerType"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"publicConfig"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"self"}}]}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"self"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"serverPublicKey"}}]}}]} as unknown as DocumentNode; -export const GetOrganisationSyncsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrganisationSyncs"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"syncs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"envType"}},{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"serviceInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"provider"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"authentication"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"history"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"completedAt"}},{"kind":"Field","name":{"kind":"Name","value":"meta"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"apps"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"NullValue"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"sseEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"email"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"environments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"syncs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"serviceInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"provider"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetOrganisationSyncsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrganisationSyncs"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"syncs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"envType"}},{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"serviceInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"provider"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"authentication"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"history"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"completedAt"}},{"kind":"Field","name":{"kind":"Name","value":"meta"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"apps"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"NullValue"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"sseEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"email"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"environments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"syncs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"serviceInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"provider"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const GetAwsSecretsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAwsSecrets"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"awsSecrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"arn"}}]}}]}}]} as unknown as DocumentNode; export const ValidateAwsAssumeRoleAuthDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ValidateAWSAssumeRoleAuth"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"validateAwsAssumeRoleAuth"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"valid"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"method"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]}}]} as unknown as DocumentNode; export const ValidateAwsAssumeRoleCredentialsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ValidateAWSAssumeRoleCredentials"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"roleArn"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"region"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"externalId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"validateAwsAssumeRoleCredentials"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"roleArn"},"value":{"kind":"Variable","name":{"kind":"Name","value":"roleArn"}}},{"kind":"Argument","name":{"kind":"Name","value":"region"},"value":{"kind":"Variable","name":{"kind":"Name","value":"region"}}},{"kind":"Argument","name":{"kind":"Name","value":"externalId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"externalId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"valid"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"assumedRoleArn"}}]}}]}}]} as unknown as DocumentNode; diff --git a/frontend/apollo/schema.graphql b/frontend/apollo/schema.graphql index e1acce8b1..e0651b8a5 100644 --- a/frontend/apollo/schema.graphql +++ b/frontend/apollo/schema.graphql @@ -21,10 +21,8 @@ type Query { pendingInvitesForUser: [OrganisationMemberInviteType] validateInvite(inviteId: ID): OrganisationMemberInviteType apps(organisationId: ID, appId: ID): [AppType] - kmsLogs(appId: ID, start: BigInt, end: BigInt): KMSLogsResponseType secretLogs(appId: ID, start: BigInt, end: BigInt, eventTypes: [String], memberId: ID, memberType: MemberType, environmentId: ID): SecretLogsResponseType auditLogs(organisationId: ID!, start: BigInt, end: BigInt, resourceType: String, resourceTypes: [String], resourceId: ID, eventTypes: [String], actorId: ID, offset: Int, limit: Int): AuditLogsResponseType - appActivityChart(appId: ID, period: TimeRange): [ChartDataPointType] appEnvironments(appId: ID, environmentId: ID, memberId: ID, memberType: MemberType): [EnvironmentType] appUsers(appId: ID): [OrganisationMemberType] appServiceAccounts(appId: ID): [ServiceAccountType] @@ -362,17 +360,17 @@ type AppType { id: String! name: String! description: String - identityKey: String! - appVersion: Int! - appToken: String! - appSeed: String! - wrappedKeyShare: String! createdAt: DateTime updatedAt: DateTime! sseEnabled: Boolean! serviceAccounts: [ServiceAccountType]! environments: [EnvironmentType]! members: [OrganisationMemberType]! + identityKey: String! @deprecated(reason: "Legacy KMS is retired; always empty.") + appToken: String! @deprecated(reason: "Legacy KMS is retired; always empty.") + appSeed: String! @deprecated(reason: "Legacy KMS is retired; always empty.") + wrappedKeyShare: String! @deprecated(reason: "Legacy KMS is retired; always empty.") + appVersion: Int! @deprecated(reason: "Legacy KMS is retired; always 1.") } type TeamAppEnvironmentType { @@ -938,34 +936,6 @@ type OrganisationMemberInviteType { expiresAt: DateTime! } -type KMSLogsResponseType { - logs: [KMSLogType] - count: Int -} - -type KMSLogType implements Node { - id: ID! - timestamp: BigInt - appId: String - phaseNode: String - eventType: String - ipAddress: String - phSize: Int - asn: Int - isp: String - edgeLocation: String - country: String - city: String - latitude: Float - longitude: Float -} - -"""An object with an ID""" -interface Node { - """The ID of the object""" - id: ID! -} - type SecretLogsResponseType { logs: [SecretEventType] count: Int @@ -1068,21 +1038,6 @@ enum ApiAuditEventActorTypeChoices { SA } -type ChartDataPointType { - index: Int - date: BigInt - data: Int -} - -enum TimeRange { - HOUR - DAY - WEEK - MONTH - YEAR - ALL_TIME -} - type EnvironmentKeyType { id: String! environment: EnvironmentType! @@ -1728,8 +1683,7 @@ type Mutation { disableMfa(code: String, recoveryCode: String): DisableMfaMutation regenerateRecoveryCodes(code: String, recoveryCode: String): RegenerateRecoveryCodesMutation deleteInvitation(inviteId: ID!): DeleteInviteMutation - createApp(appSeed: String!, appToken: String!, appVersion: Int!, id: ID!, identityKey: String!, name: String!, organisationId: ID!, wrappedKeyShare: String!): CreateAppMutation - rotateAppKeys(appToken: String!, id: ID!, wrappedKeyShare: String!): RotateAppKeysMutation + createApp(appSeed: String @deprecated(reason: "Legacy KMS is retired; ignored."), appToken: String @deprecated(reason: "Legacy KMS is retired; ignored."), appVersion: Int @deprecated(reason: "Legacy KMS is retired; ignored."), id: ID!, identityKey: String @deprecated(reason: "Legacy KMS is retired; ignored."), name: String!, organisationId: ID!, wrappedKeyShare: String @deprecated(reason: "Legacy KMS is retired; ignored.")): CreateAppMutation deleteApp(id: ID!): DeleteAppMutation updateAppInfo(description: String, id: ID!, name: String): UpdateAppInfoMutation addAppMember(appId: ID, envKeys: [EnvironmentKeyInput], memberId: ID, memberType: MemberType): AddAppMemberMutation @@ -2019,10 +1973,6 @@ type CreateAppMutation { app: AppType } -type RotateAppKeysMutation { - app: AppType -} - type DeleteAppMutation { ok: Boolean } diff --git a/frontend/app/[team]/apps/[app]/access/layout.tsx b/frontend/app/[team]/apps/[app]/access/layout.tsx index 388ee9031..aeb823e00 100644 --- a/frontend/app/[team]/apps/[app]/access/layout.tsx +++ b/frontend/app/[team]/apps/[app]/access/layout.tsx @@ -31,11 +31,6 @@ export default function AccessLayout({ name: 'Teams', link: 'teams', }, - { - name: 'KMS', - link: 'tokens', - isLegacy: true, - }, ], [] ) @@ -74,12 +69,7 @@ export default function AccessLayout({ : ' border-transparent text-zinc-600 dark:text-zinc-400 hover:text-zinc-900 dark:hover:text-zinc-100' )} > - {tab.name}{' '} - {tab.isLegacy && ( - - Legacy - - )} + {tab.name} )} diff --git a/frontend/app/[team]/apps/[app]/access/tokens/page.tsx b/frontend/app/[team]/apps/[app]/access/tokens/page.tsx deleted file mode 100644 index 6a8cceeb7..000000000 --- a/frontend/app/[team]/apps/[app]/access/tokens/page.tsx +++ /dev/null @@ -1,267 +0,0 @@ -'use client' - -import { GetAppDetail } from '@/graphql/queries/getAppDetail.gql' -import { RotateAppKey } from '@/graphql/mutations/rotateAppKeys.gql' -import { useMutation, useQuery } from '@apollo/client' -import { AppType } from '@/apollo/graphql' -import { Fragment, useContext, useState } from 'react' -import { Button } from '@/components/common/Button' -import { copyToClipBoard } from '@/utils/clipboard' -import { FaBan, FaCopy, FaExclamationTriangle, FaInfo, FaTimes } from 'react-icons/fa' -import { MdContentCopy, MdOutlineRotateLeft } from 'react-icons/md' -import { toast } from 'react-toastify' -import { Dialog, Transition } from '@headlessui/react' -import { Alert } from '@/components/common/Alert' -import { KeyringContext } from '@/contexts/keyringContext' -import { organisationContext } from '@/contexts/organisationContext' -import { - newAppWrapKey, - newAppToken, - decryptedEnvSeed, - appKeyring, - splitSecret, - getWrappedKeyShare, -} from '@/utils/crypto' -import { useAppPermissions } from '@/hooks/useAppPermissions' -import { EmptyState } from '@/components/common/EmptyState' - -export default function Tokens({ params }: { params: { team: string; app: string } }) { - const { activeOrganisation: organisation } = useContext(organisationContext) - - const { hasPermission } = useAppPermissions(params.app) - - const userCanReadTokens = hasPermission('Tokens', 'read', true) - - const { data } = useQuery(GetAppDetail, { - variables: { - organisationId: organisation?.id, - appId: params.app, - }, - skip: !organisation, - }) - - const app = data?.apps[0] as AppType - - const { keyring } = useContext(KeyringContext) - - const handleCopy = (val: string) => { - copyToClipBoard(val) - toast.info('Copied') - } - - const KmsPanel = () => { - const appId = `phApp:v${app?.appVersion}:${app?.identityKey}` - - const [appSecret, setAppSecret] = useState('') - - const appSecretPlaceholder = '*'.repeat(295) - - const RotateAppDialog = () => { - const [pw, setPw] = useState('') - const [showPw, setShowPw] = useState(false) - const [loading, setLoading] = useState(false) - const [isOpen, setIsOpen] = useState(false) - const [rotateAppKeys] = useMutation(RotateAppKey) - - const closeModal = () => { - setPw('') - setIsOpen(false) - } - - const handleGenerateNewAppKey = async () => { - const APP_VERSION = 1 - - return new Promise(async (resolve, reject) => { - setTimeout(async () => { - setLoading(true) - try { - const wrapKey = await newAppWrapKey() - const appToken = await newAppToken() - const appSeed = await decryptedEnvSeed(app.appSeed, keyring!.symmetricKey) - - const appKeys = await appKeyring(appSeed) - const appKeyShares = await splitSecret(appKeys.privateKey) - const wrappedShare = await getWrappedKeyShare(appKeyShares[1], wrapKey) - await rotateAppKeys({ - variables: { - id: app.id, - appToken, - wrappedKeyShare: wrappedShare, - }, - }) - - setAppSecret(`pss:v${APP_VERSION}:${appToken}:${appKeyShares[0]}:${wrapKey}`) - - setLoading(false) - resolve(true) - } catch (error) { - console.log(error) - setLoading(false) - reject() - } - }, 500) - }) - } - - const handleSubmit = async (event: { preventDefault: () => void }) => { - event.preventDefault() - toast - .promise(handleGenerateNewAppKey, { - pending: 'Generating app keys', - success: 'Success!', - error: 'Something went wrong! Please check your password and try again.', - }) - .then(() => closeModal()) - } - - return ( - <> - - - {}}> - -
- - -
-
- - - -

- Generate new app secret -

- -
- - - Generate a new app secret for {app.name} - - -
-
-
- -
- -
- Warning: This will revoke your current app keys. Your application - won't be able to decrypt data using the current keys. -
-
-
- - -
- -
- Your new keys will be available to use immediately. You will be - able to decrypt any existing data with your new keys. Please allow - up to 60 seconds for your old keys to be revoked. -
-
-
-
- -
- - -
-
-
-
-
-
-
-
-
- - ) - } - - return ( -
-
-
- app id - -
- {appId} -
- -
-
- app secret -
- {appSecret && ( -
- -
{"Copy this value. You won't see it again!"}
-
- )} - {appSecret && ( - - )} -
- {!appSecret && } -
- - {appSecret || appSecretPlaceholder} - -
-
- ) - } - - return ( -
- {userCanReadTokens ? ( -
- {keyring !== null && app && organisation?.role?.name?.toLowerCase() === 'owner' && ( - - )} -
- ) : ( - - -
- } - > - <> - - )} - - ) -} diff --git a/frontend/app/[team]/apps/[app]/logs/page.tsx b/frontend/app/[team]/apps/[app]/logs/page.tsx index e7c1574d9..b93045aeb 100644 --- a/frontend/app/[team]/apps/[app]/logs/page.tsx +++ b/frontend/app/[team]/apps/[app]/logs/page.tsx @@ -1,31 +1,13 @@ 'use client' import Spinner from '@/components/common/Spinner' -import KMSLogs from '@/components/logs/KmsLogs' import SecretLogs from '@/components/logs/SecretLogs' import { organisationContext } from '@/contexts/organisationContext' -import { Tab } from '@headlessui/react' -import clsx from 'clsx' -import { useState, Fragment, useContext } from 'react' - -// The historical start date for all log data (May 1st, 2023) -const LOGS_START_DATE = 1682904457000 +import { useContext } from 'react' export default function Logs({ params }: { params: { team: string; app: string } }) { - const [tabIndex, setTabIndex] = useState(0) const { activeOrganisation: organisation } = useContext(organisationContext) - const tabs = [ - { - label: 'Secrets', - component: , - }, - { - label: 'KMS', - component: , - }, - ] - if (!organisation) return (
@@ -35,40 +17,7 @@ export default function Logs({ params }: { params: { team: string; app: string } return (
- {organisation?.role!.name!.toLowerCase() === 'owner' ? ( - setTabIndex(index)}> - - {tabs.map((tab) => ( - - {({ selected }) => ( -
- {tab.label}{' '} - {tab.label === 'KMS' && ( - - Legacy - - )} -
- )} -
- ))} -
- - {tabs.map((tab) => ( - {tab.component} - ))} - -
- ) : ( - - )} +
) } diff --git a/frontend/components/apps/DeleteAppDialog.tsx b/frontend/components/apps/DeleteAppDialog.tsx index 201ea97f4..8230416f6 100644 --- a/frontend/components/apps/DeleteAppDialog.tsx +++ b/frontend/components/apps/DeleteAppDialog.tsx @@ -135,10 +135,6 @@ export default function DeleteAppDialog(props: { associated with it.

-

- Once you delete this App, you will not be able to decrypt any data that - was encrypted with this App's KMS keys. -

diff --git a/frontend/components/common/CommandPalette.tsx b/frontend/components/common/CommandPalette.tsx index e611e0f3c..b9a0c4032 100644 --- a/frontend/components/common/CommandPalette.tsx +++ b/frontend/components/common/CommandPalette.tsx @@ -258,14 +258,6 @@ const CommandPalette: React.FC = () => { action: () => handleNavigation(`/${activeOrganisation?.name}/apps/${app.id}/environments/${env.id}`), })) || []), - { - id: `${app.id}-tokens`, - name: `KMS`, - description: `Manage legacy KMS keys for ${app.name}`, - icon: , - action: () => - handleNavigation(`/${activeOrganisation?.name}/apps/${app.id}/access/tokens`), - }, { id: `${app.id}-members`, name: `Members`, diff --git a/frontend/components/logs/KmsLogs.tsx b/frontend/components/logs/KmsLogs.tsx deleted file mode 100644 index 03b917fa2..000000000 --- a/frontend/components/logs/KmsLogs.tsx +++ /dev/null @@ -1,342 +0,0 @@ -'use client' - -import { GetAppKmsLogs } from '@/graphql/queries/getAppKmsLogs.gql' -import { useLazyQuery } from '@apollo/client' -import { KmsLogType } from '@/apollo/graphql' -import { Disclosure, Transition } from '@headlessui/react' -import clsx from 'clsx' -import { FaChevronRight } from 'react-icons/fa' -import { SiNodedotjs, SiPython } from 'react-icons/si' -import { FiRefreshCw, FiChevronsDown } from 'react-icons/fi' -import getUnicodeFlagIcon from 'country-flag-icons/unicode' -import { relativeTimeFromDates } from '@/utils/time' -import { humanFileSize } from '@/utils/dataUnits' -import { ReactNode, useEffect, useRef, useState } from 'react' -import { Button } from '@/components/common/Button' -import { Count } from 'reaviz' - -// The historical start date for all log data (May 1st, 2023) -const LOGS_START_DATE = 1682904457000 - -export default function KMSLogs(props: { app: string }) { - const DEFAULT_PAGE_SIZE = 25 - const loglistEndRef = useRef(null) - const tableBodyRef = useRef(null) - const [getAppLogs, { data, loading }] = useLazyQuery(GetAppKmsLogs) - const [totalCount, setTotalCount] = useState(0) - const [logList, setLogList] = useState([]) - - const [endofList, setEndofList] = useState(false) - - const getCurrentTimeStamp = () => Date.now() - const getLastLogTimestamp = () => - logList.length > 0 ? logList[logList.length - 1].timestamp : getCurrentTimeStamp() - - /** - * Fetches logs for the app with the given start and end timestamps, - * and then adds the result of the query to the current log list. - * - * @param {number} start - Start datetime as unix timestamp (ms) - * @param {number} end - End datetime as unix timestamp (ms) - * - * @returns {void} - */ - const fetchLogs = (start: number, end: number) => { - getAppLogs({ - variables: { - appId: props.app, - start, - end, - }, - fetchPolicy: 'network-only', - }).then((result) => { - if (result.data?.kmsLogs.logs.length) { - setLogList(logList.concat(result.data.kmsLogs.logs)) - } - if (result.data?.kmsLogs.logs.length < DEFAULT_PAGE_SIZE) setEndofList(true) - }) - } - - const clearLogList = () => setLogList([]) - - /** - * Gets the first page of logs, by resetting the log list and fetching logs using the current unix timestamp. - * - * @returns {void} - */ - const getFirstPage = () => { - setEndofList(false) - fetchLogs(LOGS_START_DATE, getCurrentTimeStamp()) - } - - /** - * Gets the new page of logs by using the last available timestamp from the current log list - * - * @returns {void} - */ - const getNextPage = () => { - fetchLogs(LOGS_START_DATE, getLastLogTimestamp()) - } - - /** - * Hook to get the first page of logs on page load, or when the loglist is reset to empty - */ - useEffect(() => { - if (logList.length === 0) getFirstPage() - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.app, logList]) - - /** - * Hook to update the log count once it's available - */ - useEffect(() => { - if (data?.kmsLogs.count) setTotalCount(data.kmsLogs.count) - }, [data]) - - // useEffect(() => { - // const options = { - // root: null, - // rootMargin: '0px', - // threshold: 1.0, - // } - // const observer = new IntersectionObserver((entries) => { - // const [entry] = entries - // if (entry.isIntersecting) getNextPage() - // }, options) - - // if (loglistEndRef.current) { - // if (endofList) observer.unobserve(loglistEndRef.current) - // else observer.observe(loglistEndRef.current) - // } - - // return () => { - // if (loglistEndRef.current) observer.unobserve(loglistEndRef.current) - // } - - // // eslint-disable-next-line react-hooks/exhaustive-deps - // }, [loglistEndRef]) - - const LogRow = (props: { log: KmsLogType }) => { - const { log } = props - - const SDKIcon = (sdkName: string) => { - const sdks = [ - { - name: 'node-js', - label: 'Node.js', - icon: , - color: 'bg-[#339933]', - }, - { - name: 'python', - label: 'Python', - icon: , - color: 'bg-[#3776AB]', - }, - ] - - const sdk = sdks.find((sdk) => sdkName.toLowerCase().includes(sdk.name)) || sdks[0] - - return ( -
- {sdk.icon} -
- ) - } - - const relativeTimeStamp = () => { - return relativeTimeFromDates(new Date(log.timestamp)) - } - - const verboseTimeStamp = () => { - const date = new Date(log.timestamp) - return date.toISOString() - } - - const LogField = (props: { label: string; children: ReactNode }) => { - return ( -
- {props.label}: - {props.children} -
- ) - } - - return ( - - {({ open }) => ( - <> - - {/* */} - - - - {SDKIcon(log.phaseNode!)} - {log.eventType} - - {humanFileSize(log.phSize!)} - - - {log.city} {log.country ? getUnicodeFlagIcon(log.country) : 'Not available'} - - - {relativeTimeStamp()} - - {/* */} - - - - -
- Log ID: - {log.id} -
-
- -
- {SDKIcon(log.phaseNode!)} {log.phaseNode} -
-
- - - {log.eventType} - - - {humanFileSize(log.phSize!)} - - {(log.city || log.country) && ( - - {' '} - {log.city}, {log.country}{' '} - {log.country ? getUnicodeFlagIcon(log.country) : 'Not available'} - - )} - - {log.ipAddress} - - {verboseTimeStamp()} -
-
- -
- - )} -
- ) - } - - const SkeletonRow = (props: { rows: number }) => { - const SKELETON_BASE_STYLE = 'dark:bg-neutral-700 bg-neutral-300 animate-pulse' - return ( - <> - {[...Array(props.rows)].map((_, n) => ( - - - - - -
- - -
- - -
- - -
- - -
- - - ))} - - ) - } - - return ( -
-
- - {totalCount && } {totalCount === 1 ? 'event' : 'events'} - - -
-
- - {/* sticky is md+ only: below md the overflow-x-auto wrapper is the scrollport, - so the offset would permanently shift the thead down over the first rows */} - - - - - - - - - - - - {logList.map((log, n) => ( - - ))} - {loading && } - - - - -
SDKEventDataLocationTime
-
- {!endofList && ( - - )} - {endofList && `No${logList.length ? ' more ' : ' '}logs to show`} -
-
-
-
- ) -} diff --git a/frontend/graphql/mutations/createApp.gql b/frontend/graphql/mutations/createApp.gql index 008c79408..f01d270a0 100644 --- a/frontend/graphql/mutations/createApp.gql +++ b/frontend/graphql/mutations/createApp.gql @@ -2,26 +2,15 @@ mutation CreateApplication( $id: ID! $organisationId: ID! $name: String! - $identityKey: String! - $appToken: String! - $appSeed: String! - $wrappedKeyShare: String! - $appVersion: Int! ) { createApp( id: $id organisationId: $organisationId name: $name - identityKey: $identityKey - appToken: $appToken - appSeed: $appSeed - wrappedKeyShare: $wrappedKeyShare - appVersion: $appVersion ) { app { id name - identityKey } } } diff --git a/frontend/graphql/mutations/rotateAppKeys.gql b/frontend/graphql/mutations/rotateAppKeys.gql deleted file mode 100644 index 95b8ede33..000000000 --- a/frontend/graphql/mutations/rotateAppKeys.gql +++ /dev/null @@ -1,7 +0,0 @@ -mutation RotateAppKey($id: ID!, $appToken: String!, $wrappedKeyShare: String!) { - rotateAppKeys(id: $id, appToken: $appToken, wrappedKeyShare: $wrappedKeyShare) { - app { - id - } - } -} diff --git a/frontend/graphql/queries/getAppActivityChart.gql b/frontend/graphql/queries/getAppActivityChart.gql deleted file mode 100644 index 5bc7a181d..000000000 --- a/frontend/graphql/queries/getAppActivityChart.gql +++ /dev/null @@ -1,7 +0,0 @@ -query GetAppActivityChart($appId: ID!, $period: TimeRange) { - appActivityChart(appId: $appId, period: $period) { - index - date - data - } -} diff --git a/frontend/graphql/queries/getAppDetail.gql b/frontend/graphql/queries/getAppDetail.gql index a38dce42e..b41eb9459 100644 --- a/frontend/graphql/queries/getAppDetail.gql +++ b/frontend/graphql/queries/getAppDetail.gql @@ -3,11 +3,7 @@ query GetAppDetail($organisationId: ID!, $appId: ID!) { id name description - identityKey createdAt - appToken - appSeed - appVersion sseEnabled } } diff --git a/frontend/graphql/queries/getAppKmsLogs.gql b/frontend/graphql/queries/getAppKmsLogs.gql deleted file mode 100644 index ec01fc181..000000000 --- a/frontend/graphql/queries/getAppKmsLogs.gql +++ /dev/null @@ -1,15 +0,0 @@ -query GetAppKmsLogs($appId: ID!, $start: BigInt, $end: BigInt) { - kmsLogs(appId: $appId, start: $start, end: $end) { - logs { - id - timestamp - phaseNode - eventType - ipAddress - country - city - phSize - } - count - } -} diff --git a/frontend/graphql/queries/getApps.gql b/frontend/graphql/queries/getApps.gql index f63b4a868..71bd6d49c 100644 --- a/frontend/graphql/queries/getApps.gql +++ b/frontend/graphql/queries/getApps.gql @@ -3,7 +3,6 @@ query GetApps($organisationId: ID!, $appId: ID) { id name description - identityKey createdAt updatedAt sseEnabled diff --git a/frontend/graphql/queries/syncing/GetOrgSyncs.gql b/frontend/graphql/queries/syncing/GetOrgSyncs.gql index b85f316da..82c6e2ffa 100644 --- a/frontend/graphql/queries/syncing/GetOrgSyncs.gql +++ b/frontend/graphql/queries/syncing/GetOrgSyncs.gql @@ -38,7 +38,6 @@ query GetOrganisationSyncs($orgId: ID!) { apps(organisationId: $orgId, appId: null) { id name - identityKey createdAt sseEnabled members { diff --git a/frontend/tests/utils/app.test.ts b/frontend/tests/utils/app.test.ts new file mode 100644 index 000000000..615d3b7a7 --- /dev/null +++ b/frontend/tests/utils/app.test.ts @@ -0,0 +1,57 @@ +import { createApplication } from '@/utils/app' +import { graphQlClient } from '@/apollo/client' +import { createNewEnv } from '@/utils/crypto' +import { ApiEnvironmentEnvTypeChoices, OrganisationType } from '@/apollo/graphql' + +jest.mock('@/apollo/client', () => ({ graphQlClient: { mutate: jest.fn(), query: jest.fn() } })) +jest.mock('@/utils/crypto', () => ({ createNewEnv: jest.fn() })) +jest.mock('@/graphql/mutations/createApp.gql', () => ({ CreateApplication: 'create-app' })) +jest.mock('@/graphql/mutations/environments/initAppEnvironments.gql', () => ({ InitAppEnvironments: 'init-envs' })) +jest.mock('@/graphql/mutations/environments/bulkProcessSecrets.gql', () => ({ BulkProcessSecrets: 'bulk-secrets' })) +jest.mock('@/graphql/queries/secrets/getAppEnvironments.gql', () => ({ GetAppEnvironments: 'get-envs' })) +jest.mock('@/graphql/queries/getApps.gql', () => ({ GetApps: 'get-apps' })) +jest.mock('@/graphql/mutations/apps/updateAppInfo.gql', () => ({ UpdateAppInfoOp: 'update-app' })) + +test('app creation initializes encrypted environments without legacy KMS credentials', async () => { + const originalCrypto = globalThis.crypto + Object.defineProperty(globalThis, 'crypto', { + value: { randomUUID: () => '00000000-0000-0000-0000-000000000001' }, + configurable: true, + }) + const mutate = graphQlClient.mutate as jest.Mock + const query = graphQlClient.query as jest.Mock + const createEnv = createNewEnv as jest.Mock + const recipients = [{ id: 'owner' }, { id: 'creator' }] + mutate.mockResolvedValueOnce({ data: { createApp: { app: { id: 'new-app' } } } }).mockResolvedValue({ data: {} }) + query.mockResolvedValue({ data: {} }) + createEnv.mockImplementation(async (appId, name, type) => ({ + createEnvPayload: { appId, name, type, wrappedSeed: 'encrypted-seed', wrappedSalt: 'encrypted-salt' }, + adminKeysPayload: [{ userId: 'creator', wrappedSeed: 'creator-seed' }], + })) + + try { + const result = await createApplication({ + name: 'My app', organisation: { id: 'org' } as OrganisationType, + keyring: { publicKey: 'public', privateKey: 'private', symmetricKey: 'symmetric' }, + globalAccessUsers: recipients, + }) + expect(result).toBe('new-app') + expect(mutate.mock.calls[0][0]).toEqual({ + mutation: 'create-app', + variables: { id: '00000000-0000-0000-0000-000000000001', name: 'My app', organisationId: 'org' }, + }) + expect(createEnv.mock.calls).toEqual([ + ['new-app', 'Development', ApiEnvironmentEnvTypeChoices.Dev, recipients], + ['new-app', 'Staging', ApiEnvironmentEnvTypeChoices.Staging, recipients], + ['new-app', 'Production', ApiEnvironmentEnvTypeChoices.Prod, recipients], + ]) + const initialization = mutate.mock.calls[1][0] + expect(initialization.mutation).toBe('init-envs') + expect(initialization.variables.devEnv.wrappedSeed).toBe('encrypted-seed') + expect(initialization.variables.devAdminKeys).toEqual([{ userId: 'creator', wrappedSeed: 'creator-seed' }]) + expect(query).toHaveBeenCalledWith({ query: 'get-apps', variables: { organisationId: 'org' }, fetchPolicy: 'network-only' }) + } finally { + Object.defineProperty(globalThis, 'crypto', { value: originalCrypto, configurable: true }) + jest.clearAllMocks() + } +}) diff --git a/frontend/tests/utils/crypto/app.test.ts b/frontend/tests/utils/crypto/app.test.ts deleted file mode 100644 index 86f78b12c..000000000 --- a/frontend/tests/utils/crypto/app.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -/** - * @jest-environment node - */ - -/* - 👆 - overrides: testEnvironment: 'jsdom' in jest.config.js - to fix: ReferenceError: TextDecoder is not defined - -*/ - -import { - appKeyring, - decryptAppSeed, - encryptAppSeed, - newAppSeed, - newAppToken, - newAppWrapKey, -} from '@/utils/crypto' - - - - - - - - - - - - - - - - - - -describe('New App Key Generation Tests', () => { - const expectedHexLength = 64 // Keygen returns 32 bytes - - test('newAppSeed returns hex string of correct length', async () => { - const seed = await newAppSeed() - expect(seed).toMatch(/^[a-f0-9]{64}$/) - expect(seed.length).toBe(expectedHexLength) - }) - - test('newAppSeed produces unique seeds', async () => { - const seed1 = await newAppSeed() - const seed2 = await newAppSeed() - expect(seed1).not.toBe(seed2) - }) - - test('newAppToken returns hex string of correct length', async () => { - const token = await newAppToken() - expect(token).toMatch(/^[a-f0-9]{64}$/) - expect(token.length).toBe(expectedHexLength) - }) - - test('newAppToken produces unique tokens', async () => { - const token1 = await newAppToken() - const token2 = await newAppToken() - expect(token1).not.toBe(token2) - }) - - test('newAppWrapKey returns hex string of correct length', async () => { - const key = await newAppWrapKey() - expect(key).toMatch(/^[a-f0-9]{64}$/) - expect(key.length).toBe(expectedHexLength) - }) - - test('newAppWrapKey produces unique keys', async () => { - const key1 = await newAppWrapKey() - const key2 = await newAppWrapKey() - expect(key1).not.toBe(key2) - }) -}) - -describe('App Seed Encryption and Decryption Tests', () => { - const exampleSeed = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' // Example seed, 64-character hex string - const encryptionKey = 'fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210' // Example key, 64-character hex string - - test('encryptAppSeed returns hex encoded string', async () => { - const encryptedSeed = await encryptAppSeed(exampleSeed, encryptionKey) - expect(encryptedSeed).toMatch(/^[a-f0-9]+$/) - }) - - test('decryptAppSeed retrieves original seed', async () => { - const encryptedSeed = await encryptAppSeed(exampleSeed, encryptionKey) - const decryptedSeed = await decryptAppSeed(encryptedSeed, encryptionKey) - expect(decryptedSeed).toBe(exampleSeed) - }) - - test('decryptAppSeed with incorrect key fails', async () => { - const encryptedSeed = await encryptAppSeed(exampleSeed, encryptionKey) - const wrongKey = '00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff' - - await expect(decryptAppSeed(encryptedSeed, wrongKey)).rejects.toThrow() - }) - - test('decryptAppSeed with incorrect encrypted seed fails', async () => { - const incorrectEncryptedSeed = 'abcdef' - - await expect(decryptAppSeed(incorrectEncryptedSeed, encryptionKey)).rejects.toThrow() - }) -}) - -describe('App Keyring Derivation Tests', () => { - const exampleSeed = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' // Example seed, 64-character hex string - - test('appKeyring produces consistent key pair for same seed', async () => { - const keyring1 = await appKeyring(exampleSeed) - const keyring2 = await appKeyring(exampleSeed) - expect(keyring1).toEqual(keyring2) - }) - - test('key pair is in hex format and of correct lengths', async () => { - const keyring = await appKeyring(exampleSeed) - expect(keyring.publicKey).toMatch(/^[a-f0-9]+$/) - expect(keyring.privateKey).toMatch(/^[a-f0-9]+$/) - // Length check depends on the specific key length your implementation uses - }) - - test('different seeds produce different key pairs', async () => { - const differentSeed = 'fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210' - const keyring1 = await appKeyring(exampleSeed) - const keyring2 = await appKeyring(differentSeed) - expect(keyring1).not.toEqual(keyring2) - }) -}) diff --git a/frontend/tests/utils/crypto/environments.test.ts b/frontend/tests/utils/crypto/environments.test.ts index 8e94b878d..86c265699 100644 --- a/frontend/tests/utils/crypto/environments.test.ts +++ b/frontend/tests/utils/crypto/environments.test.ts @@ -5,7 +5,7 @@ import { newEnvWrapKey, encryptedEnvSeed, envKeyring, - decryptAppSeed, + decryptedEnvSeed, } from '@/utils/crypto' describe('New Environment Key Generation Tests', () => { @@ -73,23 +73,23 @@ describe('Environment Seed Encryption and Decryption Tests', () => { expect(encryptedSeed).toMatch(/^[a-f0-9]+$/) }) - test('decryptedAppSeed retrieves original seed', async () => { + test('decryptedEnvSeed retrieves original seed', async () => { const encryptedSeed = await encryptedEnvSeed(exampleSeed, encryptionKey) - const decryptedSeed = await decryptAppSeed(encryptedSeed, encryptionKey) + const decryptedSeed = await decryptedEnvSeed(encryptedSeed, encryptionKey) expect(decryptedSeed).toBe(exampleSeed) }) - test('decryptedAppSeed with incorrect key fails', async () => { + test('decryptedEnvSeed with incorrect key fails', async () => { const encryptedSeed = await encryptedEnvSeed(exampleSeed, encryptionKey) const wrongKey = 'f1e2d3c4b5a697887766554433221100ffeeddccbbaa99887766554433221100' - await expect(decryptAppSeed(encryptedSeed, wrongKey)).rejects.toThrow() + await expect(decryptedEnvSeed(encryptedSeed, wrongKey)).rejects.toThrow() }) - test('decryptedAppSeed with incorrect encrypted seed fails', async () => { + test('decryptedEnvSeed with incorrect encrypted seed fails', async () => { const incorrectEncryptedSeed = 'abcdef' - await expect(decryptAppSeed(incorrectEncryptedSeed, encryptionKey)).rejects.toThrow() + await expect(decryptedEnvSeed(incorrectEncryptedSeed, encryptionKey)).rejects.toThrow() }) }) diff --git a/frontend/utils/app.ts b/frontend/utils/app.ts index fe1f3fa70..1100441a7 100644 --- a/frontend/utils/app.ts +++ b/frontend/utils/app.ts @@ -21,18 +21,9 @@ import { encryptAsymmetric, digest, createNewEnv, - splitSecret, - appKeyring, - newAppSeed, - newAppToken, - newAppWrapKey, - encryptAppSeed, - getWrappedKeyShare, } from '@/utils/crypto' import { graphQlClient as client } from '@/apollo/client' -const APP_VERSION = 1 - const EXAMPLE_APP_README = `## Example App This is an example application with some dummy secrets to help you get started with Phase. @@ -404,28 +395,14 @@ export async function createApplication({ globalAccessUsers, createExampleSecrets: withExampleSecrets = false, // Explicitly false by default }: CreateAppOptions): Promise { - const appSeed = await newAppSeed() - const appToken = await newAppToken() - const wrapKey = await newAppWrapKey() const id = crypto.randomUUID() - const encryptedAppSeed = await encryptAppSeed(appSeed, keyring.symmetricKey) - const appKeys = await appKeyring(appSeed) - const appKeyShares = await splitSecret(appKeys.privateKey) - - const wrappedShare = await getWrappedKeyShare(appKeyShares[1], wrapKey) - const { data } = await client.mutate({ mutation: CreateApplication, variables: { id, name, organisationId: organisation.id, - appSeed: encryptedAppSeed, - appToken, - wrappedKeyShare: wrappedShare, - identityKey: appKeys.publicKey, - appVersion: APP_VERSION, } as MutationCreateAppArgs, }) diff --git a/frontend/utils/crypto/app.ts b/frontend/utils/crypto/app.ts deleted file mode 100644 index d0ce341cf..000000000 --- a/frontend/utils/crypto/app.ts +++ /dev/null @@ -1,96 +0,0 @@ -// Crypto utils used for KMS - -import _sodium from 'libsodium-wrappers-sumo' -import { encryptRaw, decryptRaw } from './general' -import { AppKeyring } from './types' - -/** - * Create a random seed for a new app - * - * @returns {Promise} - hex encoded app seed - */ -export const newAppSeed = async () => { - await _sodium.ready - const sodium = _sodium - - const seed = sodium.crypto_kdf_keygen() - return sodium.to_hex(seed) -} - -/** - * Create a random token for a new app - * - * @returns {Promise} - hex encoded app token - */ -export const newAppToken = async () => { - await _sodium.ready - const sodium = _sodium - - const token = sodium.crypto_kdf_keygen() - return sodium.to_hex(token) -} - -/** - * Create a wrapping key for new app - * - * @returns {Promise} - hex encoded wrapping key - */ -export const newAppWrapKey = async () => { - await _sodium.ready - const sodium = _sodium - - const key = sodium.crypto_kdf_keygen() - return sodium.to_hex(key) -} - -/** - * Encrypts an app seed with the given key - * - * @param seed - App seed as a hex string - * @param key - Encryption key as a hex string - * @returns {Promise} - */ -export const encryptAppSeed = async (seed: string, key: string) => { - await _sodium.ready - const sodium = _sodium - - const keyBytes = sodium.from_hex(key) - const encryptedSeed = await encryptRaw(seed, keyBytes) - return sodium.to_hex(encryptedSeed) -} - -/** - * Decrypts an app seed with the given key - * - * @param encryptedSeed - Encrypted app seed as a hex string - * @param key - Decryption key as a hex string - * @returns {Promise} - hex encoded plaintext app seed - */ -export const decryptAppSeed = async (encryptedSeed: string, key: string) => { - await _sodium.ready - const sodium = _sodium - - const ciphertextBytes = sodium.from_hex(encryptedSeed) - const keyBytes = sodium.from_hex(key) - - const seedBytes = await decryptRaw(ciphertextBytes, keyBytes) - return sodium.to_string(seedBytes) -} - -/** - * Derives an app keyring from the given seed - * - * @param {string} appSeed - App seed as a hex string - * @returns {Promise} - */ -export const appKeyring = async (appSeed: string): Promise => { - await _sodium.ready - const sodium = _sodium - - const seedBytes = sodium.from_hex(appSeed) - const appKeypair = sodium.crypto_kx_seed_keypair(seedBytes) - - const { publicKey, privateKey } = appKeypair - - return { publicKey: sodium.to_hex(publicKey), privateKey: sodium.to_hex(privateKey) } -} diff --git a/frontend/utils/crypto/index.ts b/frontend/utils/crypto/index.ts index 6c2dd5851..f116b7a6f 100644 --- a/frontend/utils/crypto/index.ts +++ b/frontend/utils/crypto/index.ts @@ -1,4 +1,3 @@ -export * from './app' export * from './constants' export * from './environments' export * from './general' diff --git a/frontend/utils/crypto/types.ts b/frontend/utils/crypto/types.ts index 12ab54833..7aa6e8f89 100644 --- a/frontend/utils/crypto/types.ts +++ b/frontend/utils/crypto/types.ts @@ -4,11 +4,6 @@ export type OrganisationKeyring = { privateKey: string } -export type AppKeyring = { - publicKey: string - privateKey: string -} - export type EnvKeyring = { privateKey: string publicKey: string