From 02dd4be603908da462ccabede5849bd6f67d08e3 Mon Sep 17 00:00:00 2001 From: rohan Date: Sat, 30 Aug 2025 14:06:54 +0530 Subject: [PATCH 001/117] feat: add DynamicSecret and DynamicSecretLease models with related fields and events Signed-off-by: rohan --- ...namicsecret_dynamicsecretlease_and_more.py | 59 ++++++ ...dynamicsecretlease_credentials_and_more.py | 76 +++++++ ...amicsecretlease_cleanup_job_id_and_more.py | 24 +++ backend/api/models.py | 186 ++++++++++++++++-- 4 files changed, 332 insertions(+), 13 deletions(-) create mode 100644 backend/api/migrations/0106_dynamicsecret_dynamicsecretlease_and_more.py create mode 100644 backend/api/migrations/0107_dynamicsecret_key_map_dynamicsecretlease_credentials_and_more.py create mode 100644 backend/api/migrations/0108_dynamicsecretlease_cleanup_job_id_and_more.py diff --git a/backend/api/migrations/0106_dynamicsecret_dynamicsecretlease_and_more.py b/backend/api/migrations/0106_dynamicsecret_dynamicsecretlease_and_more.py new file mode 100644 index 000000000..afa21edf2 --- /dev/null +++ b/backend/api/migrations/0106_dynamicsecret_dynamicsecretlease_and_more.py @@ -0,0 +1,59 @@ +# Generated by Django 4.2.22 on 2025-08-20 08:11 + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0105_environmentkey_unique_envkey_user_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='DynamicSecret', + fields=[ + ('id', models.TextField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('name', models.TextField()), + ('description', models.TextField(blank=True)), + ('path', models.TextField(default='/')), + ('default_ttl', models.DurationField(help_text='Default TTL for leases (must be <= max_ttl).')), + ('max_ttl', models.DurationField(help_text='Maximum allowed TTL for leases.')), + ('provider', models.CharField(choices=[('aws', 'AWS')], help_text='Which provider this secret is associated with.', max_length=50)), + ('config', models.JSONField()), + ('created_at', models.DateTimeField(auto_now_add=True, null=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('deleted_at', models.DateTimeField(blank=True, null=True)), + ('authentication', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='api.providercredentials')), + ('environment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.environment')), + ('folder', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='api.secretfolder')), + ], + ), + migrations.CreateModel( + name='DynamicSecretLease', + fields=[ + ('id', models.TextField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('name', models.TextField()), + ('description', models.TextField(blank=True)), + ('ttl', models.DurationField()), + ('status', models.CharField(choices=[('active', 'Active'), ('renewed', 'Renewed'), ('revoked', 'Revoked'), ('expired', 'Expired')], default='active', help_text='Current status of the lease', max_length=50)), + ('created_at', models.DateTimeField(auto_now_add=True, null=True)), + ('renewed_at', models.DateTimeField(null=True)), + ('expires_at', models.DateTimeField(null=True)), + ('revoked_at', models.DateTimeField(null=True)), + ('deleted_at', models.DateTimeField(null=True)), + ('organisation_member', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='api.organisationmember')), + ('secret', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leases', to='api.dynamicsecret')), + ('service_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='api.serviceaccount')), + ], + ), + migrations.CreateModel( + name='DynamicSecretLeaseEvent', + fields=[ + ('id', models.TextField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('lease', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.dynamicsecretlease')), + ], + ), + ] diff --git a/backend/api/migrations/0107_dynamicsecret_key_map_dynamicsecretlease_credentials_and_more.py b/backend/api/migrations/0107_dynamicsecret_key_map_dynamicsecretlease_credentials_and_more.py new file mode 100644 index 000000000..f2647489a --- /dev/null +++ b/backend/api/migrations/0107_dynamicsecret_key_map_dynamicsecretlease_credentials_and_more.py @@ -0,0 +1,76 @@ +# Generated by Django 4.2.22 on 2025-08-26 09:16 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0106_dynamicsecret_dynamicsecretlease_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='dynamicsecret', + name='key_map', + field=models.JSONField(default=list, help_text="Provider-agnostic mapping of keys: [{'id': '', 'name': ''}, ...]"), + ), + migrations.AddField( + model_name='dynamicsecretlease', + name='credentials', + field=models.JSONField(default=list), + ), + migrations.AddField( + model_name='dynamicsecretleaseevent', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='dynamicsecretleaseevent', + name='event_type', + field=models.CharField(choices=[('created', 'Created'), ('active', 'Active'), ('renewed', 'Renewed'), ('revoked', 'Revoked'), ('expired', 'Expired')], default='created', max_length=50), + ), + migrations.AddField( + model_name='dynamicsecretleaseevent', + name='ip_address', + field=models.GenericIPAddressField(blank=True, null=True), + ), + migrations.AddField( + model_name='dynamicsecretleaseevent', + name='metadata', + field=models.JSONField(blank=True, default=dict), + ), + migrations.AddField( + model_name='dynamicsecretleaseevent', + name='organisation_member', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='lease_events', to='api.organisationmember'), + ), + migrations.AddField( + model_name='dynamicsecretleaseevent', + name='service_account', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='lease_events', to='api.serviceaccount'), + ), + migrations.AddField( + model_name='dynamicsecretleaseevent', + name='user_agent', + field=models.TextField(blank=True, null=True), + ), + migrations.AlterField( + model_name='dynamicsecretlease', + name='status', + field=models.CharField(choices=[('created', 'Created'), ('active', 'Active'), ('renewed', 'Renewed'), ('revoked', 'Revoked'), ('expired', 'Expired')], default='active', help_text='Current status of the lease', max_length=50), + ), + migrations.AlterField( + model_name='dynamicsecretleaseevent', + name='id', + field=models.BigAutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='dynamicsecretleaseevent', + name='lease', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to='api.dynamicsecretlease'), + ), + ] diff --git a/backend/api/migrations/0108_dynamicsecretlease_cleanup_job_id_and_more.py b/backend/api/migrations/0108_dynamicsecretlease_cleanup_job_id_and_more.py new file mode 100644 index 000000000..76b0c149e --- /dev/null +++ b/backend/api/migrations/0108_dynamicsecretlease_cleanup_job_id_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.22 on 2025-08-28 08:49 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0107_dynamicsecret_key_map_dynamicsecretlease_credentials_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='dynamicsecretlease', + name='cleanup_job_id', + field=models.TextField(default=uuid.uuid4), + ), + migrations.AlterField( + model_name='dynamicsecretlease', + name='credentials', + field=models.JSONField(default=dict), + ), + ] diff --git a/backend/api/models.py b/backend/api/models.py index e71b18ac8..1b3a5eb86 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -17,7 +17,7 @@ can_add_environment, can_add_service_token, ) - +from django.core.exceptions import ValidationError CLOUD_HOSTED = settings.APP_HOST == "cloud" @@ -609,12 +609,12 @@ class Meta: ] def delete(self, *args, **kwargs): - env = self.environment - super().delete(*args, **kwargs) - # Update the 'updated_at' timestamp of the associated Environment - if env: - env.updated_at = timezone.now() - env.save() + env = self.environment + super().delete(*args, **kwargs) + # Update the 'updated_at' timestamp of the associated Environment + if env: + env.updated_at = timezone.now() + env.save() class SecretTag(models.Model): @@ -651,15 +651,175 @@ def save(self, *args, **kwargs): self.environment.updated_at = timezone.now() self.environment.save() + def delete(self, *args, **kwargs): + env = self.environment + super().delete(*args, **kwargs) + # Update the 'updated_at' timestamp of the associated Environment + if env: + env.updated_at = timezone.now() + env.save() + + +class DynamicSecret(models.Model): + + PROVIDER_CHOICES = [("aws", "AWS")] + + id = models.TextField(default=uuid4, primary_key=True, editable=False) + name = models.TextField() + description = models.TextField(blank=True) + environment = models.ForeignKey(Environment, on_delete=models.CASCADE) + folder = models.ForeignKey(SecretFolder, on_delete=models.CASCADE, null=True) + path = models.TextField(default="/") + default_ttl = models.DurationField( + help_text="Default TTL for leases (must be <= max_ttl)." + ) + max_ttl = models.DurationField(help_text="Maximum allowed TTL for leases.") + authentication = models.ForeignKey( + ProviderCredentials, on_delete=models.SET_NULL, null=True + ) + provider = models.CharField( + max_length=50, + choices=PROVIDER_CHOICES, + help_text="Which provider this secret is associated with.", + ) + config = models.JSONField() + key_map = models.JSONField( + help_text="Provider-agnostic mapping of keys: " + "[{'id': '', 'name': ''}, ...]", + default=list, + ) + created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True) + updated_at = models.DateTimeField(auto_now=True) + deleted_at = models.DateTimeField(blank=True, null=True) + + def save(self, *args, **kwargs): + # Call the "real" save() method to save the Secret + super().save(*args, **kwargs) + + # Update the 'updated_at' timestamp of the associated Environment + if self.environment: + self.environment.updated_at = timezone.now() + self.environment.save() def delete(self, *args, **kwargs): - env = self.environment - super().delete(*args, **kwargs) - # Update the 'updated_at' timestamp of the associated Environment - if env: - env.updated_at = timezone.now() - env.save() + env = self.environment + super().delete(*args, **kwargs) + # Update the 'updated_at' timestamp of the associated Environment + if env: + env.updated_at = timezone.now() + env.save() + + +class DynamicSecretLease(models.Model): + + CREATED = "created" + ACTIVE = "active" + RENEWED = "renewed" + REVOKED = "revoked" + EXPIRED = "expired" + + STATUS_OPTIONS = [ + (CREATED, "Created"), + (ACTIVE, "Active"), + (RENEWED, "Renewed"), + (REVOKED, "Revoked"), + (EXPIRED, "Expired"), + ] + + id = models.TextField(default=uuid4, primary_key=True, editable=False) + name = models.TextField() + description = models.TextField(blank=True) + secret = models.ForeignKey( + DynamicSecret, on_delete=models.CASCADE, related_name="leases" + ) + organisation_member = models.ForeignKey( + OrganisationMember, null=True, blank=True, on_delete=models.CASCADE + ) + service_account = models.ForeignKey( + ServiceAccount, null=True, blank=True, on_delete=models.CASCADE + ) + ttl = models.DurationField() + status = models.CharField( + max_length=50, + choices=STATUS_OPTIONS, + default=ACTIVE, + help_text="Current status of the lease", + ) + credentials = models.JSONField( + default=dict, + ) + created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True) + renewed_at = models.DateTimeField(null=True) + expires_at = models.DateTimeField(null=True) + revoked_at = models.DateTimeField(null=True) + deleted_at = models.DateTimeField(null=True) + cleanup_job_id = models.TextField(default=uuid4) + + def clean(self): + """ + Ensure only one of organisation_member or service_account is set. + """ + if not (self.organisation_member or self.service_account): + raise ValidationError( + "Must set either organisation_member or service_account" + ) + if self.organisation_member and self.service_account: + raise ValidationError( + "Only one of organisation_member or service_account may be set" + ) + + def get_account(self): + """ + Return whichever account is associated with this lease. + """ + return self.organisation_member or self.service_account + + +class DynamicSecretLeaseEvent(models.Model): + + EVENT_TYPES = DynamicSecretLease.STATUS_OPTIONS + + id = models.BigAutoField(primary_key=True) + lease = models.ForeignKey( + DynamicSecretLease, on_delete=models.CASCADE, related_name="events" + ) + event_type = models.CharField( + max_length=50, choices=EVENT_TYPES, default=DynamicSecretLease.CREATED + ) + organisation_member = models.ForeignKey( + OrganisationMember, + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="lease_events", + ) + service_account = models.ForeignKey( + ServiceAccount, + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="lease_events", + ) + ip_address = models.GenericIPAddressField(null=True, blank=True) + user_agent = models.TextField(blank=True, null=True) + metadata = models.JSONField(default=dict, blank=True) + created_at = models.DateTimeField(auto_now_add=True) + + def clean(self): + """ + Ensure only one of organisation_member or service_account is set. + """ + if not (self.organisation_member or self.service_account): + raise ValidationError( + "Must set either organisation_member or service_account" + ) + if self.organisation_member and self.service_account: + raise ValidationError( + "Only one of organisation_member or service_account may be set" + ) + def get_actor(self): + return self.organisation_member or self.service_account class SecretEvent(models.Model): From 7dbe60d04c6599c7b4aeef6afdbf7f40827aab39 Mon Sep 17 00:00:00 2001 From: rohan Date: Sat, 30 Aug 2025 14:28:33 +0530 Subject: [PATCH 002/117] feat: backend utils, resolvers and types Signed-off-by: rohan --- backend/backend/schema.py | 45 +- .../secrets/dynamic/aws/graphene/mutations.py | 212 ++++++ .../secrets/dynamic/aws/graphene/types.py | 18 + .../integrations/secrets/dynamic/aws/utils.py | 601 ++++++++++++++++++ .../secrets/dynamic/graphene/mutations.py | 228 +++++++ .../secrets/dynamic/graphene/queries.py | 85 +++ .../secrets/dynamic/graphene/types.py | 90 +++ .../integrations/secrets/dynamic/providers.py | 65 ++ .../ee/integrations/secrets/dynamic/utils.py | 48 ++ 9 files changed, 1390 insertions(+), 2 deletions(-) create mode 100644 backend/ee/integrations/secrets/dynamic/aws/graphene/mutations.py create mode 100644 backend/ee/integrations/secrets/dynamic/aws/graphene/types.py create mode 100644 backend/ee/integrations/secrets/dynamic/aws/utils.py create mode 100644 backend/ee/integrations/secrets/dynamic/graphene/mutations.py create mode 100644 backend/ee/integrations/secrets/dynamic/graphene/queries.py create mode 100644 backend/ee/integrations/secrets/dynamic/graphene/types.py create mode 100644 backend/ee/integrations/secrets/dynamic/providers.py create mode 100644 backend/ee/integrations/secrets/dynamic/utils.py diff --git a/backend/backend/schema.py b/backend/backend/schema.py index 66a34f6f1..8bd2e4943 100644 --- a/backend/backend/schema.py +++ b/backend/backend/schema.py @@ -5,6 +5,24 @@ from api.utils.syncing.gitlab.main import GitLabGroupType, GitLabProjectType from api.utils.syncing.railway.main import RailwayProjectType from api.utils.syncing.render.main import RenderEnvGroupType, RenderServiceType +from ee.integrations.secrets.dynamic.graphene.mutations import ( + DeleteDynamicSecretMutation, + LeaseDynamicSecret, + RenewLeaseMutation, + RevokeLeaseMutation, +) +from ee.integrations.secrets.dynamic.graphene.types import ( + DynamicSecretProviderType, + DynamicSecretType, +) +from ee.integrations.secrets.dynamic.aws.graphene.mutations import ( + CreateAWSDynamicSecretMutation, + UpdateAWSDynamicSecretMutation, +) +from ee.integrations.secrets.dynamic.graphene.queries import ( + resolve_dynamic_secret_providers, + resolve_dynamic_secrets, +) from backend.graphene.mutations.service_accounts import ( CreateServiceAccountMutation, CreateServiceAccountTokenMutation, @@ -33,7 +51,7 @@ StripeSubscriptionDetails, resolve_stripe_checkout_details, resolve_stripe_subscription_details, - resolve_stripe_customer_portal_url + resolve_stripe_customer_portal_url, ) from ee.billing.graphene.mutations.stripe import ( CancelSubscriptionMutation, @@ -389,7 +407,19 @@ class Query(graphene.ObjectType): StripeSubscriptionDetails, organisation_id=graphene.ID() ) - stripe_customer_portal_url = graphene.String(organisation_id=graphene.ID(required=True)) + stripe_customer_portal_url = graphene.String( + organisation_id=graphene.ID(required=True) + ) + + # Dynamic secrets + dynamic_secret_providers = graphene.List(DynamicSecretProviderType) + dynamic_secrets = graphene.List( + DynamicSecretType, + secret_id=graphene.ID(required=False), + app_id=graphene.ID(required=False), + env_id=graphene.ID(required=False), + org_id=graphene.ID(), + ) # -------------------------------------------------------------------- @@ -437,6 +467,9 @@ class Query(graphene.ObjectType): resolve_validate_aws_assume_role_credentials ) + resolve_dynamic_secret_providers = resolve_dynamic_secret_providers + resolve_dynamic_secrets = resolve_dynamic_secrets + def resolve_organisations(root, info): memberships = OrganisationMember.objects.filter( user=info.context.user, deleted_at=None @@ -1015,5 +1048,13 @@ class Mutation(graphene.ObjectType): create_setup_intent = CreateSetupIntentMutation.Field() set_default_payment_method = SetDefaultPaymentMethodMutation.Field() + # Dynamic Secrets + create_aws_dynamic_secret = CreateAWSDynamicSecretMutation.Field() + update_aws_dynamic_secret = UpdateAWSDynamicSecretMutation.Field() + delete_dynamic_secret = DeleteDynamicSecretMutation.Field() + create_dynamic_secret_lease = LeaseDynamicSecret.Field() + renew_dynamic_secret_lease = RenewLeaseMutation.Field() + revoke_dynamic_secret_lease = RevokeLeaseMutation.Field() + schema = graphene.Schema(query=Query, mutation=Mutation) diff --git a/backend/ee/integrations/secrets/dynamic/aws/graphene/mutations.py b/backend/ee/integrations/secrets/dynamic/aws/graphene/mutations.py new file mode 100644 index 000000000..80bffe505 --- /dev/null +++ b/backend/ee/integrations/secrets/dynamic/aws/graphene/mutations.py @@ -0,0 +1,212 @@ +from api.utils.access.permissions import ( + user_can_access_environment, + user_has_permission, + user_is_org_member, +) +from api.utils.secrets import create_environment_folder_structure +from ee.integrations.secrets.dynamic.aws.graphene.types import ( + AwsCredentialsType, +) +from ee.integrations.secrets.dynamic.graphene.types import ( + DynamicSecretLeaseType, + DynamicSecretType, + KeyMapInput, +) +from ee.integrations.secrets.dynamic.aws.utils import ( + create_dynamic_secret, + create_aws_dynamic_secret_lease, +) +from datetime import timedelta +import graphene +from graphql import GraphQLError +from django.core.exceptions import ValidationError +from api.models import ( + DynamicSecret, + Organisation, + Environment, + OrganisationMember, + ProviderCredentials, +) +from graphene.types.generic import GenericScalar + + +class AWSConfigInput(graphene.InputObjectType): + username_template = graphene.String(required=True) + iam_path = graphene.String(required=False, default_value="/") + permission_boundary_arn = graphene.String(required=False) + groups = graphene.List(graphene.String) + policy_arns = graphene.List(graphene.String) + policy_document = GenericScalar(required=False) + + +class CreateAWSDynamicSecretMutation(graphene.Mutation): + class Arguments: + organisation_id = graphene.ID(required=True) + environment_id = graphene.ID(required=True) + name = graphene.String(required=True) + description = graphene.String(required=False) + path = graphene.String(required=False) + default_ttl = graphene.Int() # seconds + max_ttl = graphene.Int() # seconds + authentication_id = graphene.ID(required=False) + config = AWSConfigInput(required=True) + key_map = graphene.List(KeyMapInput, required=True) + + dynamic_secret = graphene.Field(DynamicSecretType) + + @classmethod + def mutate( + cls, + root, + info, + organisation_id, + environment_id, + name, + config, + key_map, + description="", + path="/", + default_ttl=None, + max_ttl=None, + authentication_id=None, + ): + user = info.context.user + + # --- permission checks --- + if not user_is_org_member(user.userId, organisation_id): + raise GraphQLError("You don't have access to this organisation") + + org = Organisation.objects.get(id=organisation_id) + + if not user_has_permission(user, "create", "Secrets", org, True): + raise GraphQLError("You don't have permission to create Dynamic Secrets") + + if not user_can_access_environment(user.userId, environment_id): + raise GraphQLError("You don't have access to this environment") + + env = Environment.objects.get(id=environment_id) + + if not env.app.sse_enabled: + raise GraphQLError("SSE is not enabled!") + + folder = None + if path and path != "/": + folder = create_environment_folder_structure(path, environment_id) + + authentication = None + if authentication_id: + try: + authentication = ProviderCredentials.objects.get( + id=authentication_id, organisation=org + ) + except ProviderCredentials.DoesNotExist: + raise GraphQLError("Invalid authentication credentials") + + # --- create secret --- + + try: + dynamic_secret = create_dynamic_secret( + environment=Environment.objects.get(id=environment_id), + folder=folder, + name=name, + description=description, + default_ttl=timedelta(seconds=default_ttl), + max_ttl=timedelta(seconds=max_ttl), + authentication=authentication, + provider="aws", + config=config, + key_map=key_map, + ) + except ValidationError as e: + raise GraphQLError(e.message) + + return CreateAWSDynamicSecretMutation(dynamic_secret=dynamic_secret) + + +class UpdateAWSDynamicSecretMutation(graphene.Mutation): + class Arguments: + dynamic_secret_id = graphene.ID(required=True) + organisation_id = graphene.ID(required=True) + name = graphene.String(required=True) + description = graphene.String(required=False) + path = graphene.String(required=False) + default_ttl = graphene.Int() # seconds + max_ttl = graphene.Int() # seconds + authentication_id = graphene.ID(required=False) + config = AWSConfigInput(required=True) + key_map = graphene.List(KeyMapInput, required=True) + + dynamic_secret = graphene.Field(DynamicSecretType) + + @classmethod + def mutate( + cls, + root, + info, + dynamic_secret_id, + organisation_id, + name, + config, + key_map, + description="", + path=None, + default_ttl=None, + max_ttl=None, + authentication_id=None, + ): + user = info.context.user + + # --- permission checks --- + if not user_is_org_member(user.userId, organisation_id): + raise GraphQLError("You don't have access to this organisation") + + org = Organisation.objects.get(id=organisation_id) + + dynamic_secret = DynamicSecret.objects.get(id=dynamic_secret_id) + + env = Environment.objects.get(id=dynamic_secret.environment.id) + + if not user_has_permission(user, "update", "Secrets", org, True): + raise GraphQLError("You don't have permission to update Dynamic Secrets") + + if not user_can_access_environment(user.userId, dynamic_secret.environment.id): + raise GraphQLError("You don't have access to this environment") + + if not env.app.sse_enabled: + raise GraphQLError("SSE is not enabled!") + + folder = None + if path is not None and path != "/": + folder = create_environment_folder_structure( + path, dynamic_secret.environment.id + ) + + authentication = None + if authentication_id: + try: + authentication = ProviderCredentials.objects.get( + id=authentication_id, organisation=org + ) + except ProviderCredentials.DoesNotExist: + raise GraphQLError("Invalid authentication credentials") + + # --- update secret fields --- + dynamic_secret.name = name + dynamic_secret.description = description + if folder is not None: + dynamic_secret.folder = folder + dynamic_secret.default_ttl = ( + timedelta(seconds=default_ttl) if default_ttl else None + ) + dynamic_secret.max_ttl = timedelta(seconds=max_ttl) if max_ttl else None + dynamic_secret.authentication = authentication + dynamic_secret.config = config + dynamic_secret.key_map = key_map + + try: + # dynamic_secret.full_clean() + dynamic_secret.save() + except ValidationError as e: + raise GraphQLError(f"Validation error:{e}") + + return UpdateAWSDynamicSecretMutation(dynamic_secret=dynamic_secret) diff --git a/backend/ee/integrations/secrets/dynamic/aws/graphene/types.py b/backend/ee/integrations/secrets/dynamic/aws/graphene/types.py new file mode 100644 index 000000000..81146a824 --- /dev/null +++ b/backend/ee/integrations/secrets/dynamic/aws/graphene/types.py @@ -0,0 +1,18 @@ +import graphene + +from graphene.types.generic import GenericScalar # JSON-safe scalar + + +class AWSConfigType(graphene.ObjectType): + username_template = graphene.String(required=True) + iam_path = graphene.String(required=False, default_value="/") + permission_boundary_arn = graphene.String(required=False) + groups = graphene.List(graphene.String, required=False) + policy_arns = graphene.List(graphene.String, required=False) + policy_document = GenericScalar(required=False) # JSON object + + +class AwsCredentialsType(graphene.ObjectType): + access_key_id = graphene.String() + secret_access_key = graphene.String() + username = graphene.String() diff --git a/backend/ee/integrations/secrets/dynamic/aws/utils.py b/backend/ee/integrations/secrets/dynamic/aws/utils.py new file mode 100644 index 000000000..7b53cdb4e --- /dev/null +++ b/backend/ee/integrations/secrets/dynamic/aws/utils.py @@ -0,0 +1,601 @@ +from django.utils import timezone +from django.core.exceptions import ValidationError +from uuid import uuid4 +from api.models import DynamicSecret +from api.utils.crypto import decrypt_asymmetric, encrypt_asymmetric, get_server_keypair +from api.utils.syncing.aws.auth import get_aws_sts_session +from api.utils.secrets import get_environment_keys +from backend.utils.secrets import get_secret +from ee.integrations.secrets.dynamic.providers import DynamicSecretProviders +import logging +from datetime import datetime, timedelta +import boto3 +from botocore.exceptions import ClientError, BotoCoreError +from api.models import DynamicSecret, DynamicSecretLease +import string +import random +import re +import django_rq + + +logger = logging.getLogger(__name__) + + +def generate_random_string(length=8): + """Generate random alphanumeric suffix.""" + return "".join(random.choices(string.ascii_lowercase + string.digits, k=length)) + + +def render_username_template(template: str) -> str: + """ + Render a username template by replacing {{ random }} placeholders. + + Examples: + 'prefix-{{ random }}' -> 'prefix-x8f2k9' + '{{ random }}-suffix' -> 'q1z9xk-suffix' + 'plain-username' -> 'plain-username' + """ + + def replace_placeholder(match): + return generate_random_string( + random.randint(6, 18) + ) # random length between 6–18 + + return re.sub(r"\{\{\s*random\s*\}\}", replace_placeholder, template) + + +def get_aws_access_key_credentials(provider_credentials): + """ + Get AWS integration Access Key credentials from ProviderCredentials object. + + Args: + provider_credentials: ProviderCredentials object with access key credentials + + Returns: + dict: Decrypted credentials containing access_key_id, secret_access_key, and region + """ + pk, sk = get_server_keypair() + + access_key_id = decrypt_asymmetric( + provider_credentials.credentials["access_key_id"], sk.hex(), pk.hex() + ) + secret_access_key = decrypt_asymmetric( + provider_credentials.credentials["secret_access_key"], + sk.hex(), + pk.hex(), + ) + region = decrypt_asymmetric( + provider_credentials.credentials["region"], sk.hex(), pk.hex() + ) + + return { + "access_key_id": access_key_id, + "secret_access_key": secret_access_key, + "region": region, + } + + +def get_aws_assume_role_credentials(provider_credentials): + """ + Get AWS integratio Assume Role credentials from ProviderCredentials object. + + Args: + provider_credentials: ProviderCredentials object with assume role credentials + + Returns: + dict: Decrypted credentials containing role_arn, region, and external_id + """ + pk, sk = get_server_keypair() + + role_arn = decrypt_asymmetric( + provider_credentials.credentials["role_arn"], sk.hex(), pk.hex() + ) + + region = None + if "region" in provider_credentials.credentials: + region = decrypt_asymmetric( + provider_credentials.credentials["region"], sk.hex(), pk.hex() + ) + + external_id = None + if "external_id" in provider_credentials.credentials: + external_id = decrypt_asymmetric( + provider_credentials.credentials["external_id"], sk.hex(), pk.hex() + ) + + return { + "role_arn": role_arn, + "region": region, + "external_id": external_id, + } + + +def build_dynamic_secret_config(provider: str, user_config: dict) -> dict: + """ + Merge user-supplied config with provider defaults for key_map. + - All non-key_map fields are preserved exactly as user provided. + - key_map is filled with defaults where user did not specify. + """ + # --- find provider definition --- + provider_def = None + for prov in DynamicSecretProviders.__dict__.values(): + if isinstance(prov, dict) and prov.get("id") == provider: + provider_def = prov + break + if not provider_def: + raise ValidationError(f"Unsupported provider: {provider}") + + # --- start with user config --- + merged_config = dict(user_config or {}) + + # --- build key_map --- + key_map = merged_config.get("key_map", {}) + merged_key_map = {} + for cred in provider_def.get("credentials", []): + cid = cred["id"] + default_key = cred.get("default_key_name") + merged_key_map[cid] = key_map.get(cid, default_key) + + merged_config["key_map"] = merged_key_map + return merged_config + + +def create_dynamic_secret( + *, + environment, + folder, + name: str, + description="", + default_ttl, + max_ttl, + authentication=None, + provider: str, + config: dict, + key_map: list, +) -> DynamicSecret: + """ + Create a DynamicSecret with validated provider config. + Used by both GraphQL resolvers and REST API. + """ + + # --- validate provider --- + provider_def = None + for prov in DynamicSecretProviders.__dict__.values(): + if isinstance(prov, dict) and prov.get("id") == provider: + provider_def = prov + break + if not provider_def: + raise ValidationError(f"Unsupported provider: {provider}") + + # --- validate required config fields --- + validated_config = {} + for field in provider_def.get("config_map", []): + fid = field["id"] + required = field.get("required", False) + default = field.get("default") + + if fid in config: + validated_config[fid] = config[fid] + elif required and default is None: + raise ValidationError(f"Missing required config field: {fid}") + elif default is not None: + validated_config[fid] = default + + # --- validate key_map --- + valid_creds = {c["id"]: c for c in provider_def.get("credentials", [])} + validated_key_map = [] + + for entry in key_map: + if not isinstance(entry, dict): + raise ValidationError(f"Invalid key_map entry (must be dict): {entry}") + + key_id = entry.get("id") + key_name = entry.get("key_name") + + if key_id not in valid_creds: + raise ValidationError( + f"Invalid key id '{key_id}' for provider '{provider}'" + ) + + # fallback to provider default_key_name + if not key_name: + key_name = valid_creds[key_id].get("default_key_name") + + if not key_name: + raise ValidationError( + f"No key name provided for key id '{key_id}', and no default defined" + ) + + validated_key_map.append({"id": key_id, "key_name": key_name}) + + # --- construct DynamicSecret --- + dynamic_secret = DynamicSecret.objects.create( + id=uuid4(), + environment=environment, + folder=folder, + path="/", + name=name, + description=description, + default_ttl=default_ttl, + max_ttl=max_ttl, + authentication=authentication, + provider=provider, + config=validated_config, + key_map=validated_key_map, + ) + + # Update environment timestamp + environment.updated_at = timezone.now() + environment.save(update_fields=["updated_at"]) + + return dynamic_secret + + +def create_temporary_user(user_config, iam_client): + """ + Create a temporary IAM user with specified configuration. + + Args: + user_config (dict): Configuration for user creation + - username_template (str): Base name for user + - groups (list of str, optional): Comma separated list of groups to add user to + - policy_arns (list of str, optional): Policy ARN to attach + - iam_user_path (str, optional): User path + - permission_boundary_arn (str, optional): Permission boundary ARN + - ttl_seconds (int): Time to live in seconds + + Returns: + dict: User creation result with username and metadata + """ + try: + # Generate unique username + base_template = user_config.get( + "username_template", "phase-dynamic-{{ random }}" + ) + username = render_username_template(base_template) + + # Prepare user creation parameters + path = user_config.get("iam_user_path", "/") or "/" + + # ensure leading slash + if not path.startswith("/"): + path = "/" + path + + # ensure trailing slash + if not path.endswith("/"): + path = path + "/" + + create_params = { + "UserName": username, + "Path": path, + } + + # Add permission boundary if specified + if user_config.get("permission_boundary_arn"): + create_params["PermissionsBoundary"] = user_config[ + "permission_boundary_arn" + ] + + # Create IAM user + response = iam_client.create_user(**create_params) + + # Add tags to track the user + creation_time = datetime.utcnow() + expiry_time = creation_time + timedelta( + seconds=user_config.get("ttl_seconds", 60) + ) + + iam_client.tag_user( + UserName=username, + Tags=[ + {"Key": "CreatedBy", "Value": "phase-dynamic-secrets"}, + {"Key": "CreationTime", "Value": creation_time.isoformat()}, + {"Key": "ExpiryTime", "Value": expiry_time.isoformat()}, + {"Key": "TTL", "Value": str(user_config.get("ttl_seconds", 60))}, + ], + ) + + # Attach policies if specified + policy_arns = user_config.get("policy_arns") + if policy_arns: + # Support both comma-separated string and list + if isinstance(policy_arns, str): + policy_arns = [p.strip() for p in policy_arns.split(",") if p.strip()] + for policy_arn in policy_arns: + try: + iam_client.attach_user_policy( + UserName=username, PolicyArn=policy_arn + ) + logger.info(f"Attached policy {policy_arn} to user {username}") + except ClientError as e: + logger.error( + f"Failed to attach policy {policy_arn} to user {username}: {str(e)}" + ) + raise + + # Add user to specified groups + groups = user_config.get("groups") + if groups: + # If groups is a string (legacy), split by comma + if isinstance(groups, str): + groups = [g.strip() for g in groups.split(",") if g.strip()] + for group_name in groups: + try: + iam_client.add_user_to_group( + GroupName=group_name, UserName=username + ) + logger.info(f"Added user {username} to group {group_name}") + except ClientError as e: + logger.error( + f"Failed to add user {username} to group {group_name}: {str(e)}" + ) + raise + + logger.info(f"Successfully created temporary IAM user: {username}") + + return { + "username": username, + "arn": response["User"]["Arn"], + "creation_time": creation_time.isoformat(), + "expiry_time": expiry_time.isoformat(), + } + + except ClientError as e: + logger.error(f"AWS client error creating user: {str(e)}") + raise + except Exception as e: + logger.error(f"Unexpected error creating user: {str(e)}") + raise + + +def create_access_key(username, iam_client): + """ + Create access key for IAM user. + + Args: + username (str): IAM username + + Returns: + dict: Access key details + """ + try: + response = iam_client.create_access_key(UserName=username) + access_key = response["AccessKey"] + + logger.info(f"Successfully created access key for user: {username}") + + return { + "access_key_id": access_key["AccessKeyId"], + "secret_access_key": access_key["SecretAccessKey"], + "status": access_key["Status"], + } + + except ClientError as e: + logger.error(f"AWS client error creating access key: {str(e)}") + raise + except Exception as e: + logger.error(f"Unexpected error creating access key: {str(e)}") + raise + + +def get_sts_client(region="us-east-1"): + + aws_access_key_id = get_secret("AWS_INTEGRATION_ACCESS_KEY_ID") + aws_secret_access_key = get_secret("AWS_INTEGRATION_SECRET_ACCESS_KEY") + + sts_client = boto3.client( + "sts", + region_name=region, + aws_access_key_id=aws_access_key_id, + aws_secret_access_key=aws_secret_access_key, + ) + + return sts_client + + +import boto3 + + +def get_iam_client(secret: DynamicSecret) -> tuple[boto3.client, dict]: + """ + Construct an IAM client using the given DynamicSecret's authentication config. + Returns (iam_client, aws_credentials). + """ + sts_client = get_sts_client() + + # Determine authentication method + has_role_arn = "role_arn" in secret.authentication.credentials + aws_credentials = {} + + if has_role_arn: + integration_credentials = get_aws_assume_role_credentials(secret.authentication) + role_arn = integration_credentials.get("role_arn") + assumed_role = sts_client.assume_role( + RoleArn=role_arn, RoleSessionName="phase-dynamic-secret-session" + ) + aws_credentials = assumed_role["Credentials"] + else: + integration_credentials = get_aws_access_key_credentials(secret.authentication) + aws_credentials["AccessKeyId"] = integration_credentials.get("access_key_id") + aws_credentials["SecretAccessKey"] = integration_credentials.get( + "secret_access_key" + ) + + region = integration_credentials.get("region") + + # Construct IAM client kwargs + iam_client_kwargs = { + "service_name": "iam", + "region_name": region, + "aws_access_key_id": aws_credentials["AccessKeyId"], + "aws_secret_access_key": aws_credentials["SecretAccessKey"], + } + if "SessionToken" in aws_credentials: + iam_client_kwargs["aws_session_token"] = aws_credentials["SessionToken"] + + return boto3.client(**iam_client_kwargs), aws_credentials + + +def create_aws_dynamic_secret_lease( + *, + secret: DynamicSecret, + lease_name, + organisation_member=None, + service_account=None, + ttl_seconds, +) -> dict: + """ + Create a new lease for dynamic AWS credentials. + """ + + lease_config = secret.config + + if not organisation_member and not service_account: + raise ValidationError("Must set either organisation_member or service_account") + if organisation_member and service_account: + raise ValidationError( + "Only one of organisation_member or service_account may be set" + ) + + iam_client, _ = get_iam_client(secret) + + # Build config for user creation + user_config = { + "username_template": lease_config.get("username_template"), + "groups": lease_config.get("groups"), + "policy_arns": lease_config.get("policy_arns"), + "iam_user_path": lease_config.get("iam_path", "/"), + "permission_boundary_arn": lease_config.get("permission_boundary_arn"), + "ttl_seconds": ttl_seconds, + } + + user_result = create_temporary_user(user_config, iam_client) + username = user_result["username"] + + # Create access key for the user + access_key_result = create_access_key(username, iam_client) + + lease_data = { + "username": username, + "user_arn": user_result["arn"], + "access_key_id": access_key_result["access_key_id"], + "secret_access_key": access_key_result["secret_access_key"], + "creation_time": user_result["creation_time"], + "expiry_time": user_result["expiry_time"], + "ttl_seconds": user_config.get("ttl_seconds", 60), + } + + env_pubkey, _ = get_environment_keys(secret.environment.id) + + encrypted_credentials = { + "access_key_id": encrypt_asymmetric( + access_key_result["access_key_id"], env_pubkey + ), + "secret_access_key": encrypt_asymmetric( + access_key_result["secret_access_key"], env_pubkey + ), + "username": encrypt_asymmetric(username, env_pubkey), + } + + lease = DynamicSecretLease.objects.create( + secret=secret, + name=lease_name, + organisation_member=organisation_member, + service_account=service_account, + ttl=timedelta(seconds=ttl_seconds), + expires_at=timezone.now() + timedelta(seconds=ttl_seconds), + credentials=encrypted_credentials, + ) + + # --- Schedule revocation --- + scheduler = django_rq.get_scheduler("scheduled-jobs") + job = scheduler.enqueue_at( + lease.expires_at, + revoke_aws_dynamic_secret_lease, + lease.id, + ) + + lease.cleanup_job_id = job.id + lease.save() + + return lease, lease_data + + +def revoke_aws_dynamic_secret_lease(lease_id, manual=False): + """ + Delete IAM user and all associated credentials. + + Args: + lease_id (DynamicSecretLease): id for the lease containing IAM username to delete + manual (boolean): Whether this is a manual revoke or automatically scheduled expiry. Defaults to false + + Returns: + bool: True if successful, False otherwise + """ + lease = DynamicSecretLease.objects.get(id=lease_id) + + if lease.revoked_at is not None: + logger.info(f"Lease {lease.id} already revoked at {lease.revoked_at}") + return + + iam_client, _ = get_iam_client(lease.secret) + + try: + # Decrypt username + env_pubkey, env_privkey = get_environment_keys(lease.secret.environment.id) + encrypted_username = lease.credentials.get("username") + username = decrypt_asymmetric(encrypted_username, env_privkey, env_pubkey) + + # List and delete all access keys for the user + access_keys = iam_client.list_access_keys(UserName=username) + for key in access_keys["AccessKeyMetadata"]: + iam_client.delete_access_key( + UserName=username, AccessKeyId=key["AccessKeyId"] + ) + logger.info(f"Deleted access key {key['AccessKeyId']} for user {username}") + + # Detach all managed policies + attached_policies = iam_client.list_attached_user_policies(UserName=username) + for policy in attached_policies["AttachedPolicies"]: + iam_client.detach_user_policy( + UserName=username, PolicyArn=policy["PolicyArn"] + ) + logger.info(f"Detached policy {policy['PolicyArn']} from user {username}") + + # Delete all inline policies + inline_policies = iam_client.list_user_policies(UserName=username) + for policy_name in inline_policies["PolicyNames"]: + iam_client.delete_user_policy(UserName=username, PolicyName=policy_name) + logger.info(f"Deleted inline policy {policy_name} from user {username}") + + # Remove user from all groups + groups_resp = iam_client.list_groups_for_user(UserName=username) + for group in groups_resp["Groups"]: + iam_client.remove_user_from_group( + UserName=username, GroupName=group["GroupName"] + ) + logger.info(f"Removed user {username} from group {group['GroupName']}") + + # Finally, delete the user + iam_client.delete_user(UserName=username) + logger.info(f"Successfully deleted IAM user: {username}") + + if manual: + lease.status = DynamicSecretLease.REVOKED + else: + lease.status = DynamicSecretLease.EXPIRED + lease.credentials = {} + lease.revoked_at = timezone.now() + lease.save() + + return True + + except iam_client.exceptions.NoSuchEntityException: + logger.warning(f"User {username} does not exist, treating as already revoked") + return True + except ClientError as e: + logger.error(f"AWS client error deleting user: {str(e)}") + raise ValidationError(f"AWS client error deleting user: {str(e)}") + except Exception as e: + logger.error(f"Unexpected error deleting user: {str(e)}") + raise Exception(f"Unexpected error deleting user: {str(e)}") diff --git a/backend/ee/integrations/secrets/dynamic/graphene/mutations.py b/backend/ee/integrations/secrets/dynamic/graphene/mutations.py new file mode 100644 index 000000000..ed123d7a7 --- /dev/null +++ b/backend/ee/integrations/secrets/dynamic/graphene/mutations.py @@ -0,0 +1,228 @@ +from datetime import timedelta +from api.utils.access.permissions import ( + user_can_access_environment, + user_has_permission, + user_is_org_member, +) +from ee.integrations.secrets.dynamic.utils import renew_dynamic_secret_lease +from ee.integrations.secrets.dynamic.aws.graphene.types import ( + AwsCredentialsType, +) +from ee.integrations.secrets.dynamic.aws.utils import ( + create_aws_dynamic_secret_lease, + revoke_aws_dynamic_secret_lease, +) +from ee.integrations.secrets.dynamic.graphene.types import DynamicSecretLeaseType +import graphene +from graphql import GraphQLError +from api.models import ( + DynamicSecret, + DynamicSecretLease, + OrganisationMember, +) +from django.utils import timezone +from django.core.exceptions import ValidationError +import logging + +logger = logging.getLogger(__name__) + + +class DeleteDynamicSecretMutation(graphene.Mutation): + class Arguments: + secret_id = graphene.ID(required=True) + + ok = graphene.Boolean() + + @classmethod + def mutate( + cls, + root, + info, + secret_id, + ): + user = info.context.user + + secret = DynamicSecret.objects.get(id=secret_id, deleted_at=None) + org = secret.environment.app.organisation + + # --- permission checks --- + if not user_has_permission(user, "delete", "Secrets", org, True): + raise GraphQLError( + "You don't have permission to delete secrets in this organisation" + ) + + secret.updated_at = timezone.now() + secret.deleted_at = timezone.now() + secret.save() + + return DeleteDynamicSecretMutation(ok=True) + + +class LeaseDynamicSecret(graphene.Mutation): + class Arguments: + secret_id = graphene.ID(required=True) + name = graphene.String(required=False) + ttl = graphene.Int() # seconds + + lease = graphene.Field(DynamicSecretLeaseType) + + @classmethod + def mutate( + cls, + root, + info, + secret_id, + name=None, + ttl=3600, + ): + user = info.context.user + + secret = DynamicSecret.objects.get(id=secret_id, deleted_at=None) + org = secret.environment.app.organisation + + # --- permission checks --- + if not user_is_org_member(user.userId, org.id): + raise GraphQLError("You don't have access to this organisation") + + if not user_has_permission(user, "create", "Secrets", org, True): + raise GraphQLError("You don't have permission to create Dynamic Secrets") + + if not user_can_access_environment(user.userId, secret.environment.id): + raise GraphQLError("You don't have access to this environment") + + org_member = OrganisationMember.objects.get(organisation=org, user=user) + + # create lease + lease_name = secret.name if name is None else name + try: + if secret.provider == "aws": + lease, lease_data = create_aws_dynamic_secret_lease( + secret=secret, + lease_name=lease_name, + organisation_member=org_member, + ttl_seconds=ttl, + ) + + lease._credentials = AwsCredentialsType( + access_key_id=lease_data["access_key_id"], + secret_access_key=lease_data["secret_access_key"], + username=lease_data["username"], + ) + + except ValidationError as e: + logger.error(f"Error creating dynamic secret lease: {e}") + raise GraphQLError(e.message) + + return LeaseDynamicSecret(lease=lease) + + +class RenewLeaseMutation(graphene.Mutation): + class Arguments: + lease_id = graphene.ID(required=True) + ttl = graphene.Int() # seconds + + lease = graphene.Field(DynamicSecretLeaseType) + + @classmethod + def mutate( + cls, + root, + info, + lease_id, + ttl=3600, + ): + + user = info.context.user + + lease = DynamicSecretLease.objects.get(id=lease_id) + org = lease.secret.environment.app.organisation + org_member = OrganisationMember.objects.get(organisation=org, user=user) + + # --- permission checks --- + if not user_is_org_member(user.userId, org.id): + raise GraphQLError("You don't have access to this organisation") + + if not user_has_permission(user, "create", "Secrets", org, True): + raise GraphQLError("You don't have permission to create Dynamic Secrets") + + if not user_can_access_environment(user.userId, lease.secret.environment.id): + raise GraphQLError("You don't have access to this environment") + + # if timedelta(seconds=ttl) > lease.secret.max_ttl: + # raise GraphQLError( + # "The specified TTL exceeds the maximum TTL for this dynamic secret." + # ) + + # if lease.expires_at <= timezone.now(): + # raise GraphQLError("This lease has expired and cannot be renewed") + + # else: + # lease.expires_at = timezone.now() + timedelta(seconds=ttl) + # lease.updated_at = timezone.now() + + # # --- reschedule cleanup job --- + # scheduler = django_rq.get_scheduler("scheduled-jobs") + + # # cancel the old job if it exists + # if lease.cleanup_job_id: + # try: + # old_job = Job.fetch(lease.cleanup_job_id, connection=scheduler.connection) + # old_job.cancel() + # except Exception: + # # job might already have run or been deleted + # pass + + # # enqueue a new revocation job + # job = scheduler.enqueue_at( + # lease.expires_at, + # revoke_aws_dynamic_secret_lease, + # lease.id, + # ) + # lease.cleanup_job_id = job.id + # lease.save() + + lease = renew_dynamic_secret_lease(lease, ttl) + + return RenewLeaseMutation(lease=lease) + + +class RevokeLeaseMutation(graphene.Mutation): + class Arguments: + lease_id = graphene.ID(required=True) + + lease = graphene.Field(DynamicSecretLeaseType) + + @classmethod + def mutate( + cls, + root, + info, + lease_id, + ): + + user = info.context.user + + lease = DynamicSecretLease.objects.get(id=lease_id) + org = lease.secret.environment.app.organisation + org_member = OrganisationMember.objects.get(organisation=org, user=user) + + # --- permission checks --- + if not user_is_org_member(user.userId, org.id): + raise GraphQLError("You don't have access to this organisation") + + if not user_has_permission(user, "create", "Secrets", org, True): + raise GraphQLError("You don't have permission to create Dynamic Secrets") + + if not user_can_access_environment(user.userId, lease.secret.environment.id): + raise GraphQLError("You don't have access to this environment") + + if lease.organisation_member.id != org_member.id: + raise GraphQLError( + "You cannot revoke this lease as it wasn't created by you" + ) + + else: + if lease.secret.provider == "aws": + revoke_aws_dynamic_secret_lease(lease.id, manual=True) + + return RevokeLeaseMutation(lease=lease) diff --git a/backend/ee/integrations/secrets/dynamic/graphene/queries.py b/backend/ee/integrations/secrets/dynamic/graphene/queries.py new file mode 100644 index 000000000..aad308d68 --- /dev/null +++ b/backend/ee/integrations/secrets/dynamic/graphene/queries.py @@ -0,0 +1,85 @@ +from ee.integrations.secrets.dynamic.graphene.types import DynamicSecretProviderType +from ee.integrations.secrets.dynamic.providers import DynamicSecretProviders +from graphql import GraphQLError +from api.models import DynamicSecret, App, Environment, Organisation +from api.utils.access.permissions import ( + user_has_permission, + user_can_access_app, + user_can_access_environment, +) + + +def resolve_dynamic_secret_providers(self, info): + providers = [ + DynamicSecretProviderType( + id=provider["id"], + name=provider["name"], + credentials=provider["credentials"], + config_map=provider["config_map"], + ) + for provider in DynamicSecretProviders.__dict__.values() + if isinstance(provider, dict) + ] + return providers + + +def resolve_dynamic_secrets( + root, info, secret_id=None, app_id=None, env_id=None, org_id=None +): + user = info.context.user + filters = {"deleted_at": None} + + if secret_id: + filters["id"] = secret_id + + org = None + + # Figure out which org to use + if app_id: + app = App.objects.get(id=app_id) + org = app.organisation + elif env_id: + env = Environment.objects.get(id=env_id) + org = env.app.organisation + elif org_id: + org = Organisation.objects.get(id=org_id) + else: + raise GraphQLError( + "You must provide an app ID, an environment ID, or an organisation ID" + ) + + # Permission check (common to all cases) + if not user_has_permission(user, "read", "Secrets", org, True): + return [] + + # Build filters + access checks + if app_id and env_id: + if not user_can_access_app(user.userId, app_id): + raise GraphQLError("You don't have access to this app") + if not user_can_access_environment(user.userId, env_id): + raise GraphQLError("You don't have access to this environment") + + filters.update({"environment__app__id": app_id, "environment_id": env_id}) + return DynamicSecret.objects.filter(**filters) + + if app_id: + if not user_can_access_app(user.userId, app_id): + raise GraphQLError("You don't have access to this app") + + filters.update({"environment__app__id": app_id}) + return DynamicSecret.objects.filter(**filters) + + if env_id: + if not user_can_access_environment(user.userId, env_id): + raise GraphQLError("You don't have access to this environment") + + filters.update({"environment_id": env_id}) + return DynamicSecret.objects.filter(**filters) + + if org_id: + filters.update({"environment__app__organisation_id": org_id}) + return [ + ds + for ds in DynamicSecret.objects.filter(**filters) + if user_can_access_app(user.userId, ds.environment.app.id) + ] diff --git a/backend/ee/integrations/secrets/dynamic/graphene/types.py b/backend/ee/integrations/secrets/dynamic/graphene/types.py new file mode 100644 index 000000000..5539614f4 --- /dev/null +++ b/backend/ee/integrations/secrets/dynamic/graphene/types.py @@ -0,0 +1,90 @@ +from api.models import DynamicSecret, DynamicSecretLease +import graphene +from graphene_django import DjangoObjectType +from graphene.types.generic import GenericScalar +from ee.integrations.secrets.dynamic.aws.graphene.types import ( + AWSConfigType, + AwsCredentialsType, +) + + +class KeyMap(graphene.ObjectType): + id = graphene.String() + key_name = graphene.String() + + +class KeyMapInput(graphene.InputObjectType): + id = graphene.String(required=True) + key_name = graphene.String(required=True) + + +class DynamicSecretProviderType(graphene.ObjectType): + id = graphene.String(required=True) + name = graphene.String(required=True) + credentials = GenericScalar(required=True) + config_map = GenericScalar(required=True) + + +class DynamicSecretConfigUnion(graphene.Union): + class Meta: + types = (AWSConfigType,) + + +class LeaseCredentialsUnion(graphene.Union): + class Meta: + types = (AwsCredentialsType,) + + +class DynamicSecretType(DjangoObjectType): + # Expose JSON config safely + config = graphene.Field(DynamicSecretConfigUnion) + key_map = graphene.List(KeyMap) + + # Convenience fields for TTLs + default_ttl_seconds = graphene.Int() + max_ttl_seconds = graphene.Int() + + class Meta: + model = DynamicSecret + fields = ( + "id", + "name", + "description", + "environment", + "folder", + "path", + "authentication", + "provider", + "config", + "key_map", + "leases", + "created_at", + "updated_at", + "deleted_at", + ) + + def resolve_config(self, info): + if self.provider == "aws": + return AWSConfigType(**self.config) + return None + + def resolve_default_ttl_seconds(self, info): + return int(self.default_ttl.total_seconds()) if self.default_ttl else None + + def resolve_max_ttl_seconds(self, info): + return int(self.max_ttl.total_seconds()) if self.max_ttl else None + + def resolve_leases(self, info): + return self.leases.order_by("-created_at") + + +class DynamicSecretLeaseType(DjangoObjectType): + + credentials = graphene.Field(LeaseCredentialsUnion) + + class Meta: + model = DynamicSecretLease + fields = "__all__" + + def resolve_credentials(self, info): + return getattr(self, "_credentials", None) diff --git a/backend/ee/integrations/secrets/dynamic/providers.py b/backend/ee/integrations/secrets/dynamic/providers.py new file mode 100644 index 000000000..888de58d7 --- /dev/null +++ b/backend/ee/integrations/secrets/dynamic/providers.py @@ -0,0 +1,65 @@ +class DynamicSecretProviders: + AWS = { + "id": "aws", + "name": "AWS IAM", + "credentials": [ + {"id": "username", "type": "string", "default_key_name": "AWS_USERNAME"}, + { + "id": "access_key_id", + "type": "string", + "default_key_name": "AWS_ACCESS_KEY_ID", + }, + { + "id": "secret_access_key", + "type": "string", + "default_key_name": "AWS_SECRET_ACCESS_KEY", + }, + ], + "config_map": [ + { + "id": "username_template", + "label": "Username template", + "input_type": "string", + "required": True, + "default": "{{ random }}", + "help_text": "A template for usernames created per credential", + }, + { + "id": "iam_path", + "label": "AWS IAM Path", + "input_type": "string", + "required": False, + "default": "/", + "help_text": "Optional IAM user path. Defaults to '/'.", + }, + { + "id": "policy_arns", + "label": "AWS Policy ARNs", + "input_type": "list", + "required": False, + "help_text": "Generated users will be attached to the specified policy ARNs.", + }, + { + "id": "groups", + "label": "AWS IAM Groups", + "input_type": "list", # accept comma-separated or array + "required": False, + "help_text": "Generated users will be attached to the specified IAM groups.", + }, + { + "id": "permission_boundary_arn", + "label": "IAM User Permission Boundary ARN", + "input_type": "string", + "required": False, + "help_text": "ARN attached to the generated user for AWS Permission Boundary.", + }, + ], + } + + @classmethod + def get_service_choices(cls): + return [ + (provider["id"], provider["name"]) + for provider in cls.__dict__.values() + if isinstance(provider, dict) + ] diff --git a/backend/ee/integrations/secrets/dynamic/utils.py b/backend/ee/integrations/secrets/dynamic/utils.py new file mode 100644 index 000000000..493c53374 --- /dev/null +++ b/backend/ee/integrations/secrets/dynamic/utils.py @@ -0,0 +1,48 @@ +from datetime import timedelta +from ee.integrations.secrets.dynamic.aws.utils import ( + revoke_aws_dynamic_secret_lease, +) +from graphql import GraphQLError +from django.utils import timezone +import django_rq +from rq.job import Job +import logging + +logger = logging.getLogger(__name__) + + +def renew_dynamic_secret_lease(lease, ttl): + if timedelta(seconds=ttl) > lease.secret.max_ttl: + raise GraphQLError( + "The specified TTL exceeds the maximum TTL for this dynamic secret." + ) + + if lease.expires_at <= timezone.now(): + raise GraphQLError("This lease has expired and cannot be renewed") + + else: + lease.expires_at = timezone.now() + timedelta(seconds=ttl) + lease.updated_at = timezone.now() + + # --- reschedule cleanup job --- + scheduler = django_rq.get_scheduler("scheduled-jobs") + + # cancel the old job if it exists + if lease.cleanup_job_id: + try: + old_job = Job.fetch(lease.cleanup_job_id, connection=scheduler.connection) + old_job.cancel() + except Exception as e: + logger.info(f"Failed to delete job: {e}") + pass + + # enqueue a new revocation job + job = scheduler.enqueue_at( + lease.expires_at, + revoke_aws_dynamic_secret_lease, + lease.id, + ) + lease.cleanup_job_id = job.id + lease.save() + + return lease From fbb40b31e35aee9146c15dabfe07d085e5315968 Mon Sep 17 00:00:00 2001 From: rohan Date: Sat, 30 Aug 2025 14:28:48 +0530 Subject: [PATCH 003/117] feat: generate schema and types Signed-off-by: rohan --- frontend/apollo/client.ts | 8 +- frontend/apollo/gql.ts | 49 +++++- frontend/apollo/graphql.ts | 309 ++++++++++++++++++++++++++++++++- frontend/apollo/schema.graphql | 147 ++++++++++++++++ 4 files changed, 508 insertions(+), 5 deletions(-) diff --git a/frontend/apollo/client.ts b/frontend/apollo/client.ts index fb5c426f5..78fd6491e 100644 --- a/frontend/apollo/client.ts +++ b/frontend/apollo/client.ts @@ -51,7 +51,13 @@ const errorLink = onError(({ graphQLErrors, networkError }) => { export const graphQlClient = new ApolloClient({ link: from([errorLink, httpLink]), - cache: new InMemoryCache(), + cache: new InMemoryCache({ + typePolicies: { + KeyMap: { + keyFields: ["id", "keyName"], // composite key + }, + }, +}), defaultOptions: { watchQuery: { skipPollAttempt: () => document.hidden, diff --git a/frontend/apollo/gql.ts b/frontend/apollo/gql.ts index 601d00997..0c62d6b7e 100644 --- a/frontend/apollo/gql.ts +++ b/frontend/apollo/gql.ts @@ -53,6 +53,12 @@ const documents = { "mutation LogSecretReads($ids: [ID]!) {\n readSecret(ids: $ids) {\n ok\n }\n}": types.LogSecretReadsDocument, "mutation RemovePersonalSecret($secretId: ID!) {\n removeOverride(secretId: $secretId) {\n ok\n }\n}": types.RemovePersonalSecretDocument, "mutation RenameEnv($environmentId: ID!, $name: String!) {\n renameEnvironment(environmentId: $environmentId, name: $name) {\n environment {\n id\n name\n updatedAt\n }\n }\n}": types.RenameEnvDocument, + "mutation CreateNewAWSDynamicSecret($organisationId: ID!, $environmentId: ID!, $path: String, $name: String!, $description: String, $defaultTtl: Int, $maxTtl: Int, $authenticationId: ID, $config: AWSConfigInput!, $keyMap: [KeyMapInput]!) {\n createAwsDynamicSecret(\n organisationId: $organisationId\n environmentId: $environmentId\n path: $path\n name: $name\n description: $description\n defaultTtl: $defaultTtl\n maxTtl: $maxTtl\n authenticationId: $authenticationId\n config: $config\n keyMap: $keyMap\n ) {\n dynamicSecret {\n id\n name\n description\n provider\n createdAt\n updatedAt\n }\n }\n}": types.CreateNewAwsDynamicSecretDocument, + "mutation CreateDynamicSecretLease($secretId: ID!, $ttl: Int!, $name: String!) {\n createDynamicSecretLease(secretId: $secretId, ttl: $ttl, name: $name) {\n lease {\n id\n name\n credentials {\n ... on AwsCredentialsType {\n accessKeyId\n secretAccessKey\n username\n }\n }\n expiresAt\n }\n }\n}": types.CreateDynamicSecretLeaseDocument, + "mutation DeleteDynamicSecretOP($secretId: ID!) {\n deleteDynamicSecret(secretId: $secretId) {\n ok\n }\n}": types.DeleteDynamicSecretOpDocument, + "mutation RenewDynamicSecretLeaseOP($leaseId: ID!, $ttl: Int!) {\n renewDynamicSecretLease(leaseId: $leaseId, ttl: $ttl) {\n lease {\n id\n name\n expiresAt\n status\n }\n }\n}": types.RenewDynamicSecretLeaseOpDocument, + "mutation RevokeDynamicSecretLeaseOP($leaseId: ID!) {\n revokeDynamicSecretLease(leaseId: $leaseId) {\n lease {\n id\n name\n expiresAt\n revokedAt\n status\n }\n }\n}": types.RevokeDynamicSecretLeaseOpDocument, + "mutation UpdateDynamicSecret($dynamicSecretId: ID!, $organisationId: ID!, $path: String, $name: String!, $description: String, $defaultTtl: Int, $maxTtl: Int, $authenticationId: ID, $config: AWSConfigInput!, $keyMap: [KeyMapInput]!) {\n updateAwsDynamicSecret(\n organisationId: $organisationId\n dynamicSecretId: $dynamicSecretId\n path: $path\n name: $name\n description: $description\n defaultTtl: $defaultTtl\n maxTtl: $maxTtl\n authenticationId: $authenticationId\n config: $config\n keyMap: $keyMap\n ) {\n dynamicSecret {\n id\n name\n description\n provider\n createdAt\n updatedAt\n }\n }\n}": types.UpdateDynamicSecretDocument, "mutation CreateSharedSecret($input: LockboxInput!) {\n createLockbox(input: $input) {\n lockbox {\n id\n allowedViews\n expiresAt\n }\n }\n}": types.CreateSharedSecretDocument, "mutation SwapEnvOrder($environment1Id: ID!, $environment2Id: ID!) {\n swapEnvironmentOrder(\n environment1Id: $environment1Id\n environment2Id: $environment2Id\n ) {\n ok\n }\n}": types.SwapEnvOrderDocument, "mutation AcceptOrganisationInvite($orgId: ID!, $identityKey: String!, $wrappedKeyring: String!, $wrappedRecovery: String!, $inviteId: ID!) {\n createOrganisationMember(\n orgId: $orgId\n identityKey: $identityKey\n wrappedKeyring: $wrappedKeyring\n wrappedRecovery: $wrappedRecovery\n inviteId: $inviteId\n ) {\n orgMember {\n id\n email\n createdAt\n role {\n name\n }\n }\n }\n}": types.AcceptOrganisationInviteDocument, @@ -111,6 +117,9 @@ const documents = { "query GetOrganisationPlan($organisationId: ID!) {\n organisationPlan(organisationId: $organisationId) {\n name\n maxUsers\n maxApps\n maxEnvsPerApp\n seatsUsed {\n users\n serviceAccounts\n total\n }\n seatLimit\n appCount\n }\n}": types.GetOrganisationPlanDocument, "query GetRoles($orgId: ID!) {\n roles(orgId: $orgId) {\n id\n name\n description\n color\n permissions\n isDefault\n }\n}": types.GetRolesDocument, "query VerifyInvite($inviteId: ID!) {\n validateInvite(inviteId: $inviteId) {\n id\n organisation {\n id\n name\n }\n inviteeEmail\n invitedBy {\n fullName\n email\n }\n apps {\n id\n name\n }\n }\n}": types.VerifyInviteDocument, + "query GetDynamicSecrets($orgId: ID!, $appId: ID, $envId: ID) {\n dynamicSecrets(orgId: $orgId, appId: $appId, envId: $envId) {\n id\n name\n environment {\n id\n name\n index\n app {\n id\n name\n }\n }\n path\n description\n provider\n config {\n ... on AWSConfigType {\n usernameTemplate\n iamPath\n }\n }\n keyMap {\n id\n keyName\n }\n defaultTtlSeconds\n maxTtlSeconds\n authentication {\n id\n name\n }\n createdAt\n }\n}": types.GetDynamicSecretsDocument, + "query GetDynamicSecretProviders {\n dynamicSecretProviders {\n id\n name\n credentials\n configMap\n }\n}": types.GetDynamicSecretProvidersDocument, + "query GetDynamicSecretLeases($secretId: ID!, $orgId: ID!) {\n dynamicSecrets(secretId: $secretId, orgId: $orgId) {\n id\n leases {\n id\n name\n createdAt\n expiresAt\n revokedAt\n status\n organisationMember {\n id\n fullName\n email\n avatarUrl\n self\n }\n serviceAccount {\n id\n name\n }\n }\n }\n}": types.GetDynamicSecretLeasesDocument, "query GetAppEnvironments($appId: ID!, $memberId: ID, $memberType: MemberType) {\n appEnvironments(\n appId: $appId\n environmentId: null\n memberId: $memberId\n memberType: $memberType\n ) {\n id\n name\n envType\n identityKey\n wrappedSeed\n wrappedSalt\n createdAt\n app {\n name\n id\n }\n secretCount\n folderCount\n index\n members {\n email\n fullName\n avatarUrl\n }\n }\n sseEnabled(appId: $appId)\n serverPublicKey\n}": types.GetAppEnvironmentsDocument, "query GetAppSecrets($appId: ID!, $memberId: ID, $memberType: MemberType, $path: String) {\n appEnvironments(\n appId: $appId\n environmentId: null\n memberId: $memberId\n memberType: $memberType\n ) {\n id\n name\n envType\n identityKey\n wrappedSeed\n wrappedSalt\n createdAt\n app {\n name\n id\n }\n secretCount\n folderCount\n index\n members {\n email\n fullName\n avatarUrl\n }\n folders {\n id\n name\n path\n }\n secrets(path: $path) {\n id\n key\n value\n comment\n path\n }\n }\n sseEnabled(appId: $appId)\n serverPublicKey\n}": types.GetAppSecretsDocument, "query GetAppSecretsLogs($appId: ID!, $start: BigInt, $end: BigInt, $eventTypes: [String], $memberId: ID, $memberType: MemberType, $environmentId: ID) {\n secretLogs(\n appId: $appId\n start: $start\n end: $end\n eventTypes: $eventTypes\n memberId: $memberId\n memberType: $memberType\n environmentId: $environmentId\n ) {\n logs {\n id\n path\n key\n value\n tags {\n id\n name\n color\n }\n version\n comment\n timestamp\n ipAddress\n userAgent\n user {\n email\n username\n fullName\n avatarUrl\n }\n serviceToken {\n id\n name\n }\n serviceAccount {\n id\n name\n deletedAt\n }\n serviceAccountToken {\n id\n name\n deletedAt\n }\n eventType\n environment {\n id\n envType\n name\n }\n secret {\n id\n path\n }\n }\n count\n }\n environmentKeys(appId: $appId) {\n id\n identityKey\n wrappedSeed\n wrappedSalt\n environment {\n id\n }\n }\n}": types.GetAppSecretsLogsDocument, @@ -121,7 +130,7 @@ const documents = { "query GetSecretHistory($appId: ID!, $envId: ID!, $id: ID!) {\n secrets(envId: $envId, id: $id) {\n id\n history {\n id\n key\n value\n path\n tags {\n id\n name\n color\n }\n version\n comment\n timestamp\n ipAddress\n userAgent\n user {\n email\n username\n fullName\n avatarUrl\n }\n serviceToken {\n id\n name\n }\n serviceAccount {\n id\n name\n deletedAt\n }\n eventType\n }\n }\n environmentKeys(appId: $appId, environmentId: $envId) {\n id\n identityKey\n wrappedSeed\n wrappedSalt\n }\n}": types.GetSecretHistoryDocument, "query GetEnvSecretsKV($envId: ID!) {\n folders(envId: $envId, path: \"/\") {\n id\n name\n }\n secrets(envId: $envId, path: \"/\") {\n id\n key\n value\n comment\n path\n }\n environmentKeys(environmentId: $envId) {\n id\n identityKey\n wrappedSeed\n wrappedSalt\n }\n}": types.GetEnvSecretsKvDocument, "query GetSecretTags($orgId: ID!) {\n secretTags(orgId: $orgId) {\n id\n name\n color\n }\n}": types.GetSecretTagsDocument, - "query GetSecrets($appId: ID!, $envId: ID!, $path: String) {\n secrets(envId: $envId, path: $path) {\n id\n key\n value\n path\n tags {\n id\n name\n color\n }\n comment\n createdAt\n updatedAt\n override {\n value\n isActive\n }\n environment {\n id\n app {\n id\n }\n }\n }\n folders(envId: $envId, path: $path) {\n id\n name\n path\n createdAt\n folderCount\n secretCount\n }\n appEnvironments(appId: $appId, environmentId: $envId) {\n id\n name\n envType\n identityKey\n app {\n name\n }\n }\n environmentKeys(appId: $appId, environmentId: $envId) {\n id\n identityKey\n wrappedSeed\n wrappedSalt\n }\n envSyncs(envId: $envId) {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n options\n isActive\n status\n lastSync\n createdAt\n }\n}": types.GetSecretsDocument, + "query GetSecrets($appId: ID!, $envId: ID!, $path: String) {\n secrets(envId: $envId, path: $path) {\n id\n key\n value\n path\n tags {\n id\n name\n color\n }\n comment\n createdAt\n updatedAt\n override {\n value\n isActive\n }\n environment {\n id\n app {\n id\n }\n }\n }\n folders(envId: $envId, path: $path) {\n id\n name\n path\n createdAt\n folderCount\n secretCount\n }\n appEnvironments(appId: $appId, environmentId: $envId) {\n id\n name\n envType\n identityKey\n app {\n id\n name\n sseEnabled\n }\n }\n environmentKeys(appId: $appId, environmentId: $envId) {\n id\n identityKey\n wrappedSeed\n wrappedSalt\n }\n envSyncs(envId: $envId) {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n options\n isActive\n status\n lastSync\n createdAt\n }\n dynamicSecrets(envId: $envId) {\n id\n name\n description\n provider\n keyMap {\n id\n keyName\n }\n config {\n ... on AWSConfigType {\n usernameTemplate\n groups\n iamPath\n permissionBoundaryArn\n policyArns\n policyDocument\n }\n }\n defaultTtlSeconds\n maxTtlSeconds\n authentication {\n id\n name\n }\n createdAt\n }\n}": types.GetSecretsDocument, "query GetServiceTokens($appId: ID!) {\n serviceTokens(appId: $appId) {\n id\n name\n createdAt\n createdBy {\n fullName\n avatarUrl\n self\n }\n expiresAt\n keys {\n id\n identityKey\n }\n }\n}": types.GetServiceTokensDocument, "query GetServiceAccountDetail($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 permissions\n }\n createdAt\n handlers {\n id\n wrappedKeyring\n wrappedRecovery\n user {\n self\n }\n }\n appMemberships {\n id\n name\n environments {\n id\n name\n }\n sseEnabled\n }\n networkPolicies {\n id\n name\n allowedIps\n isGlobal\n }\n }\n}": types.GetServiceAccountDetailDocument, "query GetServiceAccountHandlers($orgId: ID!) {\n serviceAccountHandlers(orgId: $orgId) {\n id\n email\n role {\n name\n permissions\n }\n identityKey\n self\n }\n}": types.GetServiceAccountHandlersDocument, @@ -323,6 +332,30 @@ export function graphql(source: "mutation RemovePersonalSecret($secretId: ID!) { * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "mutation RenameEnv($environmentId: ID!, $name: String!) {\n renameEnvironment(environmentId: $environmentId, name: $name) {\n environment {\n id\n name\n updatedAt\n }\n }\n}"): (typeof documents)["mutation RenameEnv($environmentId: ID!, $name: String!) {\n renameEnvironment(environmentId: $environmentId, name: $name) {\n environment {\n id\n name\n updatedAt\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 CreateNewAWSDynamicSecret($organisationId: ID!, $environmentId: ID!, $path: String, $name: String!, $description: String, $defaultTtl: Int, $maxTtl: Int, $authenticationId: ID, $config: AWSConfigInput!, $keyMap: [KeyMapInput]!) {\n createAwsDynamicSecret(\n organisationId: $organisationId\n environmentId: $environmentId\n path: $path\n name: $name\n description: $description\n defaultTtl: $defaultTtl\n maxTtl: $maxTtl\n authenticationId: $authenticationId\n config: $config\n keyMap: $keyMap\n ) {\n dynamicSecret {\n id\n name\n description\n provider\n createdAt\n updatedAt\n }\n }\n}"): (typeof documents)["mutation CreateNewAWSDynamicSecret($organisationId: ID!, $environmentId: ID!, $path: String, $name: String!, $description: String, $defaultTtl: Int, $maxTtl: Int, $authenticationId: ID, $config: AWSConfigInput!, $keyMap: [KeyMapInput]!) {\n createAwsDynamicSecret(\n organisationId: $organisationId\n environmentId: $environmentId\n path: $path\n name: $name\n description: $description\n defaultTtl: $defaultTtl\n maxTtl: $maxTtl\n authenticationId: $authenticationId\n config: $config\n keyMap: $keyMap\n ) {\n dynamicSecret {\n id\n name\n description\n provider\n createdAt\n updatedAt\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 CreateDynamicSecretLease($secretId: ID!, $ttl: Int!, $name: String!) {\n createDynamicSecretLease(secretId: $secretId, ttl: $ttl, name: $name) {\n lease {\n id\n name\n credentials {\n ... on AwsCredentialsType {\n accessKeyId\n secretAccessKey\n username\n }\n }\n expiresAt\n }\n }\n}"): (typeof documents)["mutation CreateDynamicSecretLease($secretId: ID!, $ttl: Int!, $name: String!) {\n createDynamicSecretLease(secretId: $secretId, ttl: $ttl, name: $name) {\n lease {\n id\n name\n credentials {\n ... on AwsCredentialsType {\n accessKeyId\n secretAccessKey\n username\n }\n }\n expiresAt\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 DeleteDynamicSecretOP($secretId: ID!) {\n deleteDynamicSecret(secretId: $secretId) {\n ok\n }\n}"): (typeof documents)["mutation DeleteDynamicSecretOP($secretId: ID!) {\n deleteDynamicSecret(secretId: $secretId) {\n ok\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 RenewDynamicSecretLeaseOP($leaseId: ID!, $ttl: Int!) {\n renewDynamicSecretLease(leaseId: $leaseId, ttl: $ttl) {\n lease {\n id\n name\n expiresAt\n status\n }\n }\n}"): (typeof documents)["mutation RenewDynamicSecretLeaseOP($leaseId: ID!, $ttl: Int!) {\n renewDynamicSecretLease(leaseId: $leaseId, ttl: $ttl) {\n lease {\n id\n name\n expiresAt\n status\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 RevokeDynamicSecretLeaseOP($leaseId: ID!) {\n revokeDynamicSecretLease(leaseId: $leaseId) {\n lease {\n id\n name\n expiresAt\n revokedAt\n status\n }\n }\n}"): (typeof documents)["mutation RevokeDynamicSecretLeaseOP($leaseId: ID!) {\n revokeDynamicSecretLease(leaseId: $leaseId) {\n lease {\n id\n name\n expiresAt\n revokedAt\n status\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 UpdateDynamicSecret($dynamicSecretId: ID!, $organisationId: ID!, $path: String, $name: String!, $description: String, $defaultTtl: Int, $maxTtl: Int, $authenticationId: ID, $config: AWSConfigInput!, $keyMap: [KeyMapInput]!) {\n updateAwsDynamicSecret(\n organisationId: $organisationId\n dynamicSecretId: $dynamicSecretId\n path: $path\n name: $name\n description: $description\n defaultTtl: $defaultTtl\n maxTtl: $maxTtl\n authenticationId: $authenticationId\n config: $config\n keyMap: $keyMap\n ) {\n dynamicSecret {\n id\n name\n description\n provider\n createdAt\n updatedAt\n }\n }\n}"): (typeof documents)["mutation UpdateDynamicSecret($dynamicSecretId: ID!, $organisationId: ID!, $path: String, $name: String!, $description: String, $defaultTtl: Int, $maxTtl: Int, $authenticationId: ID, $config: AWSConfigInput!, $keyMap: [KeyMapInput]!) {\n updateAwsDynamicSecret(\n organisationId: $organisationId\n dynamicSecretId: $dynamicSecretId\n path: $path\n name: $name\n description: $description\n defaultTtl: $defaultTtl\n maxTtl: $maxTtl\n authenticationId: $authenticationId\n config: $config\n keyMap: $keyMap\n ) {\n dynamicSecret {\n id\n name\n description\n provider\n createdAt\n updatedAt\n }\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -555,6 +588,18 @@ export function graphql(source: "query GetRoles($orgId: ID!) {\n roles(orgId: $ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "query VerifyInvite($inviteId: ID!) {\n validateInvite(inviteId: $inviteId) {\n id\n organisation {\n id\n name\n }\n inviteeEmail\n invitedBy {\n fullName\n email\n }\n apps {\n id\n name\n }\n }\n}"): (typeof documents)["query VerifyInvite($inviteId: ID!) {\n validateInvite(inviteId: $inviteId) {\n id\n organisation {\n id\n name\n }\n inviteeEmail\n invitedBy {\n fullName\n email\n }\n apps {\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. + */ +export function graphql(source: "query GetDynamicSecrets($orgId: ID!, $appId: ID, $envId: ID) {\n dynamicSecrets(orgId: $orgId, appId: $appId, envId: $envId) {\n id\n name\n environment {\n id\n name\n index\n app {\n id\n name\n }\n }\n path\n description\n provider\n config {\n ... on AWSConfigType {\n usernameTemplate\n iamPath\n }\n }\n keyMap {\n id\n keyName\n }\n defaultTtlSeconds\n maxTtlSeconds\n authentication {\n id\n name\n }\n createdAt\n }\n}"): (typeof documents)["query GetDynamicSecrets($orgId: ID!, $appId: ID, $envId: ID) {\n dynamicSecrets(orgId: $orgId, appId: $appId, envId: $envId) {\n id\n name\n environment {\n id\n name\n index\n app {\n id\n name\n }\n }\n path\n description\n provider\n config {\n ... on AWSConfigType {\n usernameTemplate\n iamPath\n }\n }\n keyMap {\n id\n keyName\n }\n defaultTtlSeconds\n maxTtlSeconds\n authentication {\n id\n name\n }\n createdAt\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 GetDynamicSecretProviders {\n dynamicSecretProviders {\n id\n name\n credentials\n configMap\n }\n}"): (typeof documents)["query GetDynamicSecretProviders {\n dynamicSecretProviders {\n id\n name\n credentials\n configMap\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 GetDynamicSecretLeases($secretId: ID!, $orgId: ID!) {\n dynamicSecrets(secretId: $secretId, orgId: $orgId) {\n id\n leases {\n id\n name\n createdAt\n expiresAt\n revokedAt\n status\n organisationMember {\n id\n fullName\n email\n avatarUrl\n self\n }\n serviceAccount {\n id\n name\n }\n }\n }\n}"): (typeof documents)["query GetDynamicSecretLeases($secretId: ID!, $orgId: ID!) {\n dynamicSecrets(secretId: $secretId, orgId: $orgId) {\n id\n leases {\n id\n name\n createdAt\n expiresAt\n revokedAt\n status\n organisationMember {\n id\n fullName\n email\n avatarUrl\n self\n }\n serviceAccount {\n id\n name\n }\n }\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -598,7 +643,7 @@ export function graphql(source: "query GetSecretTags($orgId: ID!) {\n secretTag /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "query GetSecrets($appId: ID!, $envId: ID!, $path: String) {\n secrets(envId: $envId, path: $path) {\n id\n key\n value\n path\n tags {\n id\n name\n color\n }\n comment\n createdAt\n updatedAt\n override {\n value\n isActive\n }\n environment {\n id\n app {\n id\n }\n }\n }\n folders(envId: $envId, path: $path) {\n id\n name\n path\n createdAt\n folderCount\n secretCount\n }\n appEnvironments(appId: $appId, environmentId: $envId) {\n id\n name\n envType\n identityKey\n app {\n name\n }\n }\n environmentKeys(appId: $appId, environmentId: $envId) {\n id\n identityKey\n wrappedSeed\n wrappedSalt\n }\n envSyncs(envId: $envId) {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n options\n isActive\n status\n lastSync\n createdAt\n }\n}"): (typeof documents)["query GetSecrets($appId: ID!, $envId: ID!, $path: String) {\n secrets(envId: $envId, path: $path) {\n id\n key\n value\n path\n tags {\n id\n name\n color\n }\n comment\n createdAt\n updatedAt\n override {\n value\n isActive\n }\n environment {\n id\n app {\n id\n }\n }\n }\n folders(envId: $envId, path: $path) {\n id\n name\n path\n createdAt\n folderCount\n secretCount\n }\n appEnvironments(appId: $appId, environmentId: $envId) {\n id\n name\n envType\n identityKey\n app {\n name\n }\n }\n environmentKeys(appId: $appId, environmentId: $envId) {\n id\n identityKey\n wrappedSeed\n wrappedSalt\n }\n envSyncs(envId: $envId) {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n options\n isActive\n status\n lastSync\n createdAt\n }\n}"]; +export function graphql(source: "query GetSecrets($appId: ID!, $envId: ID!, $path: String) {\n secrets(envId: $envId, path: $path) {\n id\n key\n value\n path\n tags {\n id\n name\n color\n }\n comment\n createdAt\n updatedAt\n override {\n value\n isActive\n }\n environment {\n id\n app {\n id\n }\n }\n }\n folders(envId: $envId, path: $path) {\n id\n name\n path\n createdAt\n folderCount\n secretCount\n }\n appEnvironments(appId: $appId, environmentId: $envId) {\n id\n name\n envType\n identityKey\n app {\n id\n name\n sseEnabled\n }\n }\n environmentKeys(appId: $appId, environmentId: $envId) {\n id\n identityKey\n wrappedSeed\n wrappedSalt\n }\n envSyncs(envId: $envId) {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n options\n isActive\n status\n lastSync\n createdAt\n }\n dynamicSecrets(envId: $envId) {\n id\n name\n description\n provider\n keyMap {\n id\n keyName\n }\n config {\n ... on AWSConfigType {\n usernameTemplate\n groups\n iamPath\n permissionBoundaryArn\n policyArns\n policyDocument\n }\n }\n defaultTtlSeconds\n maxTtlSeconds\n authentication {\n id\n name\n }\n createdAt\n }\n}"): (typeof documents)["query GetSecrets($appId: ID!, $envId: ID!, $path: String) {\n secrets(envId: $envId, path: $path) {\n id\n key\n value\n path\n tags {\n id\n name\n color\n }\n comment\n createdAt\n updatedAt\n override {\n value\n isActive\n }\n environment {\n id\n app {\n id\n }\n }\n }\n folders(envId: $envId, path: $path) {\n id\n name\n path\n createdAt\n folderCount\n secretCount\n }\n appEnvironments(appId: $appId, environmentId: $envId) {\n id\n name\n envType\n identityKey\n app {\n id\n name\n sseEnabled\n }\n }\n environmentKeys(appId: $appId, environmentId: $envId) {\n id\n identityKey\n wrappedSeed\n wrappedSalt\n }\n envSyncs(envId: $envId) {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n options\n isActive\n status\n lastSync\n createdAt\n }\n dynamicSecrets(envId: $envId) {\n id\n name\n description\n provider\n keyMap {\n id\n keyName\n }\n config {\n ... on AWSConfigType {\n usernameTemplate\n groups\n iamPath\n permissionBoundaryArn\n policyArns\n policyDocument\n }\n }\n defaultTtlSeconds\n maxTtlSeconds\n authentication {\n id\n name\n }\n createdAt\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 41d614bca..3e72aeac9 100644 --- a/frontend/apollo/graphql.ts +++ b/frontend/apollo/graphql.ts @@ -32,6 +32,12 @@ export type Scalars = { * [iso8601](https://en.wikipedia.org/wiki/ISO_8601). */ DateTime: { input: any; output: any; } + /** + * The `GenericScalar` scalar type represents a generic + * GraphQL scalar value that could be: + * String, Boolean, Int, Float, List or Object. + */ + GenericScalar: { input: any; output: any; } /** * Allows use of a JSON String for input / output from the GraphQL schema. * @@ -41,6 +47,25 @@ export type Scalars = { JSONString: { input: any; output: any; } }; +export type AwsConfigInput = { + groups?: InputMaybe>>; + iamPath?: InputMaybe; + permissionBoundaryArn?: InputMaybe; + policyArns?: InputMaybe>>; + policyDocument?: InputMaybe; + usernameTemplate: Scalars['String']['input']; +}; + +export type AwsConfigType = { + __typename?: 'AWSConfigType'; + groups?: Maybe>>; + iamPath?: Maybe; + permissionBoundaryArn?: Maybe; + policyArns?: Maybe>>; + policyDocument?: Maybe; + usernameTemplate: Scalars['String']['output']; +}; + export type AwsSecretType = { __typename?: 'AWSSecretType'; arn?: Maybe; @@ -99,6 +124,24 @@ export enum ApiActivatedPhaseLicensePlanChoices { Pr = 'PR' } +export enum ApiDynamicSecretLeaseStatusChoices { + /** Active */ + Active = 'ACTIVE', + /** Created */ + Created = 'CREATED', + /** Expired */ + Expired = 'EXPIRED', + /** Renewed */ + Renewed = 'RENEWED', + /** Revoked */ + Revoked = 'REVOKED' +} + +export enum ApiDynamicSecretProviderChoices { + /** AWS */ + Aws = 'AWS' +} + export enum ApiEnvironmentEnvTypeChoices { /** Custom */ Custom = 'CUSTOM', @@ -187,6 +230,13 @@ export type AppType = { wrappedKeyShare: Scalars['String']['output']; }; +export type AwsCredentialsType = { + __typename?: 'AwsCredentialsType'; + accessKeyId?: Maybe; + secretAccessKey?: Maybe; + username?: Maybe; +}; + export enum BillingPeriodEnum { Monthly = 'MONTHLY', Yearly = 'YEARLY' @@ -237,6 +287,11 @@ export type CloudflareWorkerType = { scriptId?: Maybe; }; +export type CreateAwsDynamicSecretMutation = { + __typename?: 'CreateAWSDynamicSecretMutation'; + dynamicSecret?: Maybe; +}; + export type CreateAwsSecretsManagerSync = { __typename?: 'CreateAWSSecretsManagerSync'; sync?: Maybe; @@ -398,6 +453,11 @@ export type DeleteCustomRoleMutation = { ok?: Maybe; }; +export type DeleteDynamicSecretMutation = { + __typename?: 'DeleteDynamicSecretMutation'; + ok?: Maybe; +}; + export type DeleteEnvironmentMutation = { __typename?: 'DeleteEnvironmentMutation'; ok?: Maybe; @@ -468,6 +528,57 @@ export type DeleteUserTokenMutation = { ok?: Maybe; }; +export type DynamicSecretConfigUnion = AwsConfigType; + +export type DynamicSecretLeaseType = { + __typename?: 'DynamicSecretLeaseType'; + cleanupJobId: Scalars['String']['output']; + createdAt?: Maybe; + credentials?: Maybe; + deletedAt?: Maybe; + description: Scalars['String']['output']; + expiresAt?: Maybe; + id: Scalars['String']['output']; + name: Scalars['String']['output']; + organisationMember?: Maybe; + renewedAt?: Maybe; + revokedAt?: Maybe; + secret: DynamicSecretType; + serviceAccount?: Maybe; + /** Current status of the lease */ + status: ApiDynamicSecretLeaseStatusChoices; + ttl: Scalars['Float']['output']; +}; + +export type DynamicSecretProviderType = { + __typename?: 'DynamicSecretProviderType'; + configMap: Scalars['GenericScalar']['output']; + credentials: Scalars['GenericScalar']['output']; + id: Scalars['String']['output']; + name: Scalars['String']['output']; +}; + +export type DynamicSecretType = { + __typename?: 'DynamicSecretType'; + authentication?: Maybe; + config?: Maybe; + createdAt?: Maybe; + defaultTtlSeconds?: Maybe; + deletedAt?: Maybe; + description: Scalars['String']['output']; + environment: EnvironmentType; + folder?: Maybe; + id: Scalars['String']['output']; + keyMap?: Maybe>>; + leases: Array; + maxTtlSeconds?: Maybe; + name: Scalars['String']['output']; + path: Scalars['String']['output']; + /** Which provider this secret is associated with. */ + provider: ApiDynamicSecretProviderChoices; + updatedAt: Scalars['DateTime']['output']; +}; + export type EditSecretMutation = { __typename?: 'EditSecretMutation'; secret?: Maybe; @@ -659,6 +770,24 @@ export type KmsLogsResponseType = { logs?: Maybe>>; }; +export type KeyMap = { + __typename?: 'KeyMap'; + id?: Maybe; + keyName?: Maybe; +}; + +export type KeyMapInput = { + id: Scalars['String']['input']; + keyName: Scalars['String']['input']; +}; + +export type LeaseCredentialsUnion = AwsCredentialsType; + +export type LeaseDynamicSecret = { + __typename?: 'LeaseDynamicSecret'; + lease?: Maybe; +}; + export type LockboxInput = { allowedViews?: InputMaybe; data?: InputMaybe; @@ -687,10 +816,12 @@ export type Mutation = { bulkInviteOrganisationMembers?: Maybe; cancelSubscription?: Maybe; createApp?: Maybe; + createAwsDynamicSecret?: Maybe; createAwsSecretSync?: Maybe; createCloudflarePagesSync?: Maybe; createCloudflareWorkersSync?: Maybe; createCustomRole?: Maybe; + createDynamicSecretLease?: Maybe; createEnvironment?: Maybe; createEnvironmentKey?: Maybe; createEnvironmentToken?: Maybe; @@ -719,6 +850,7 @@ export type Mutation = { createVercelSync?: Maybe; deleteApp?: Maybe; deleteCustomRole?: Maybe; + deleteDynamicSecret?: Maybe; deleteEnvSync?: Maybe; deleteEnvironment?: Maybe; deleteInvitation?: Maybe; @@ -742,7 +874,9 @@ export type Mutation = { removeAppMember?: Maybe; removeOverride?: Maybe; renameEnvironment?: Maybe; + renewDynamicSecretLease?: Maybe; resumeSubscription?: Maybe; + revokeDynamicSecretLease?: Maybe; rotateAppKeys?: Maybe; setDefaultPaymentMethod?: Maybe; swapEnvironmentOrder?: Maybe; @@ -750,6 +884,7 @@ export type Mutation = { triggerSync?: Maybe; updateAccountNetworkAccessPolicies?: Maybe; updateAppName?: Maybe; + updateAwsDynamicSecret?: Maybe; updateCustomRole?: Maybe; updateMemberEnvironmentScope?: Maybe; updateMemberWrappedSecrets?: Maybe; @@ -800,6 +935,20 @@ export type MutationCreateAppArgs = { }; +export type MutationCreateAwsDynamicSecretArgs = { + authenticationId?: InputMaybe; + config: AwsConfigInput; + defaultTtl?: InputMaybe; + description?: InputMaybe; + environmentId: Scalars['ID']['input']; + keyMap: Array>; + maxTtl?: InputMaybe; + name: Scalars['String']['input']; + organisationId: Scalars['ID']['input']; + path?: InputMaybe; +}; + + export type MutationCreateAwsSecretSyncArgs = { credentialId?: InputMaybe; envId?: InputMaybe; @@ -836,6 +985,13 @@ export type MutationCreateCustomRoleArgs = { }; +export type MutationCreateDynamicSecretLeaseArgs = { + name?: InputMaybe; + secretId: Scalars['ID']['input']; + ttl?: InputMaybe; +}; + + export type MutationCreateEnvironmentArgs = { adminKeys?: InputMaybe>>; environmentData: EnvironmentInput; @@ -1067,6 +1223,11 @@ export type MutationDeleteCustomRoleArgs = { }; +export type MutationDeleteDynamicSecretArgs = { + secretId: Scalars['ID']['input']; +}; + + export type MutationDeleteEnvSyncArgs = { syncId?: InputMaybe; }; @@ -1193,12 +1354,23 @@ export type MutationRenameEnvironmentArgs = { }; +export type MutationRenewDynamicSecretLeaseArgs = { + leaseId: Scalars['ID']['input']; + ttl?: InputMaybe; +}; + + export type MutationResumeSubscriptionArgs = { organisationId?: InputMaybe; subscriptionId: Scalars['String']['input']; }; +export type MutationRevokeDynamicSecretLeaseArgs = { + leaseId: Scalars['ID']['input']; +}; + + export type MutationRotateAppKeysArgs = { appToken: Scalars['String']['input']; id: Scalars['ID']['input']; @@ -1240,6 +1412,20 @@ export type MutationUpdateAppNameArgs = { }; +export type MutationUpdateAwsDynamicSecretArgs = { + authenticationId?: InputMaybe; + config: AwsConfigInput; + defaultTtl?: InputMaybe; + description?: InputMaybe; + dynamicSecretId: Scalars['ID']['input']; + keyMap: Array>; + maxTtl?: InputMaybe; + name: Scalars['String']['input']; + organisationId: Scalars['ID']['input']; + path?: InputMaybe; +}; + + export type MutationUpdateCustomRoleArgs = { color?: InputMaybe; description?: InputMaybe; @@ -1475,6 +1661,8 @@ export type Query = { clientIp?: Maybe; cloudflarePagesProjects?: Maybe>>; cloudflareWorkers?: Maybe>>; + dynamicSecretProviders?: Maybe>>; + dynamicSecrets?: Maybe>>; envSyncs?: Maybe>>; environmentKeys?: Maybe>>; environmentTokens?: Maybe>>; @@ -1568,6 +1756,14 @@ export type QueryCloudflareWorkersArgs = { }; +export type QueryDynamicSecretsArgs = { + appId?: InputMaybe; + envId?: InputMaybe; + orgId?: InputMaybe; + secretId?: InputMaybe; +}; + + export type QueryEnvSyncsArgs = { envId?: InputMaybe; }; @@ -1846,6 +2042,16 @@ export type RenderServiceType = { updatedAt?: Maybe; }; +export type RenewLeaseMutation = { + __typename?: 'RenewLeaseMutation'; + lease?: Maybe; +}; + +export type RevokeLeaseMutation = { + __typename?: 'RevokeLeaseMutation'; + lease?: Maybe; +}; + export type RoleType = { __typename?: 'RoleType'; color?: Maybe; @@ -2081,6 +2287,11 @@ export type TriggerSync = { sync?: Maybe; }; +export type UpdateAwsDynamicSecretMutation = { + __typename?: 'UpdateAWSDynamicSecretMutation'; + dynamicSecret?: Maybe; +}; + export type UpdateAccountNetworkAccessPolicies = { __typename?: 'UpdateAccountNetworkAccessPolicies'; ok?: Maybe; @@ -2530,6 +2741,69 @@ export type RenameEnvMutationVariables = Exact<{ export type RenameEnvMutation = { __typename?: 'Mutation', renameEnvironment?: { __typename?: 'RenameEnvironmentMutation', environment?: { __typename?: 'EnvironmentType', id: string, name: string, updatedAt: any } | null } | null }; +export type CreateNewAwsDynamicSecretMutationVariables = Exact<{ + organisationId: Scalars['ID']['input']; + environmentId: Scalars['ID']['input']; + path?: InputMaybe; + name: Scalars['String']['input']; + description?: InputMaybe; + defaultTtl?: InputMaybe; + maxTtl?: InputMaybe; + authenticationId?: InputMaybe; + config: AwsConfigInput; + keyMap: Array> | InputMaybe; +}>; + + +export type CreateNewAwsDynamicSecretMutation = { __typename?: 'Mutation', createAwsDynamicSecret?: { __typename?: 'CreateAWSDynamicSecretMutation', dynamicSecret?: { __typename?: 'DynamicSecretType', id: string, name: string, description: string, provider: ApiDynamicSecretProviderChoices, createdAt?: any | null, updatedAt: any } | null } | null }; + +export type CreateDynamicSecretLeaseMutationVariables = Exact<{ + secretId: Scalars['ID']['input']; + ttl: Scalars['Int']['input']; + name: Scalars['String']['input']; +}>; + + +export type CreateDynamicSecretLeaseMutation = { __typename?: 'Mutation', createDynamicSecretLease?: { __typename?: 'LeaseDynamicSecret', lease?: { __typename?: 'DynamicSecretLeaseType', id: string, name: string, expiresAt?: any | null, credentials?: { __typename?: 'AwsCredentialsType', accessKeyId?: string | null, secretAccessKey?: string | null, username?: string | null } | null } | null } | null }; + +export type DeleteDynamicSecretOpMutationVariables = Exact<{ + secretId: Scalars['ID']['input']; +}>; + + +export type DeleteDynamicSecretOpMutation = { __typename?: 'Mutation', deleteDynamicSecret?: { __typename?: 'DeleteDynamicSecretMutation', ok?: boolean | null } | null }; + +export type RenewDynamicSecretLeaseOpMutationVariables = Exact<{ + leaseId: Scalars['ID']['input']; + ttl: Scalars['Int']['input']; +}>; + + +export type RenewDynamicSecretLeaseOpMutation = { __typename?: 'Mutation', renewDynamicSecretLease?: { __typename?: 'RenewLeaseMutation', lease?: { __typename?: 'DynamicSecretLeaseType', id: string, name: string, expiresAt?: any | null, status: ApiDynamicSecretLeaseStatusChoices } | null } | null }; + +export type RevokeDynamicSecretLeaseOpMutationVariables = Exact<{ + leaseId: Scalars['ID']['input']; +}>; + + +export type RevokeDynamicSecretLeaseOpMutation = { __typename?: 'Mutation', revokeDynamicSecretLease?: { __typename?: 'RevokeLeaseMutation', lease?: { __typename?: 'DynamicSecretLeaseType', id: string, name: string, expiresAt?: any | null, revokedAt?: any | null, status: ApiDynamicSecretLeaseStatusChoices } | null } | null }; + +export type UpdateDynamicSecretMutationVariables = Exact<{ + dynamicSecretId: Scalars['ID']['input']; + organisationId: Scalars['ID']['input']; + path?: InputMaybe; + name: Scalars['String']['input']; + description?: InputMaybe; + defaultTtl?: InputMaybe; + maxTtl?: InputMaybe; + authenticationId?: InputMaybe; + config: AwsConfigInput; + keyMap: Array> | InputMaybe; +}>; + + +export type UpdateDynamicSecretMutation = { __typename?: 'Mutation', updateAwsDynamicSecret?: { __typename?: 'UpdateAWSDynamicSecretMutation', dynamicSecret?: { __typename?: 'DynamicSecretType', id: string, name: string, description: string, provider: ApiDynamicSecretProviderChoices, createdAt?: any | null, updatedAt: any } | null } | null }; + export type CreateSharedSecretMutationVariables = Exact<{ input: LockboxInput; }>; @@ -3023,6 +3297,28 @@ export type VerifyInviteQueryVariables = Exact<{ export type VerifyInviteQuery = { __typename?: 'Query', validateInvite?: { __typename?: 'OrganisationMemberInviteType', id: string, inviteeEmail: string, organisation: { __typename?: 'OrganisationType', id: string, name: string }, invitedBy: { __typename?: 'OrganisationMemberType', fullName?: string | null, email?: string | null }, apps: Array<{ __typename?: 'AppMembershipType', id: string, name: string }> } | null }; +export type GetDynamicSecretsQueryVariables = Exact<{ + orgId: Scalars['ID']['input']; + appId?: InputMaybe; + envId?: InputMaybe; +}>; + + +export type GetDynamicSecretsQuery = { __typename?: 'Query', dynamicSecrets?: Array<{ __typename?: 'DynamicSecretType', id: string, name: string, path: string, description: string, provider: ApiDynamicSecretProviderChoices, defaultTtlSeconds?: number | null, maxTtlSeconds?: number | null, createdAt?: any | null, environment: { __typename?: 'EnvironmentType', id: string, name: string, index: number, app: { __typename?: 'AppMembershipType', id: string, name: string } }, config?: { __typename?: 'AWSConfigType', usernameTemplate: string, iamPath?: string | null } | null, keyMap?: Array<{ __typename?: 'KeyMap', id?: string | null, keyName?: string | null } | null> | null, authentication?: { __typename?: 'ProviderCredentialsType', id: string, name: string } | null } | null> | null }; + +export type GetDynamicSecretProvidersQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetDynamicSecretProvidersQuery = { __typename?: 'Query', dynamicSecretProviders?: Array<{ __typename?: 'DynamicSecretProviderType', id: string, name: string, credentials: any, configMap: any } | null> | null }; + +export type GetDynamicSecretLeasesQueryVariables = Exact<{ + secretId: Scalars['ID']['input']; + orgId: Scalars['ID']['input']; +}>; + + +export type GetDynamicSecretLeasesQuery = { __typename?: 'Query', dynamicSecrets?: Array<{ __typename?: 'DynamicSecretType', id: string, leases: Array<{ __typename?: 'DynamicSecretLeaseType', id: string, name: string, createdAt?: any | null, expiresAt?: any | null, revokedAt?: any | null, status: ApiDynamicSecretLeaseStatusChoices, organisationMember?: { __typename?: 'OrganisationMemberType', id: string, fullName?: string | null, email?: string | null, avatarUrl?: string | null, self?: boolean | null } | null, serviceAccount?: { __typename?: 'ServiceAccountType', id: string, name: string } | null }> } | null> | null }; + export type GetAppEnvironmentsQueryVariables = Exact<{ appId: Scalars['ID']['input']; memberId?: InputMaybe; @@ -3115,7 +3411,7 @@ export type GetSecretsQueryVariables = Exact<{ }>; -export type GetSecretsQuery = { __typename?: 'Query', secrets?: Array<{ __typename?: 'SecretType', id: string, key: string, value: string, path: string, comment: string, createdAt?: any | null, updatedAt: any, tags: Array<{ __typename?: 'SecretTagType', id: string, name: string, color: string }>, override?: { __typename?: 'PersonalSecretType', value?: string | null, isActive: boolean } | null, environment: { __typename?: 'EnvironmentType', id: string, app: { __typename?: 'AppMembershipType', id: string } } } | null> | null, folders?: Array<{ __typename?: 'SecretFolderType', id: string, name: string, path: string, createdAt?: any | null, folderCount?: number | null, secretCount?: number | null } | null> | null, appEnvironments?: Array<{ __typename?: 'EnvironmentType', id: string, name: string, envType: ApiEnvironmentEnvTypeChoices, identityKey: string, app: { __typename?: 'AppMembershipType', name: string } } | null> | null, environmentKeys?: Array<{ __typename?: 'EnvironmentKeyType', id: string, identityKey: string, wrappedSeed: string, wrappedSalt: string } | null> | null, envSyncs?: Array<{ __typename?: 'EnvironmentSyncType', id: string, options: any, isActive: boolean, status: ApiEnvironmentSyncStatusChoices, lastSync?: any | null, createdAt?: any | null, environment: { __typename?: 'EnvironmentType', id: string, name: string, envType: ApiEnvironmentEnvTypeChoices }, serviceInfo?: { __typename?: 'ServiceType', id?: string | null, name?: string | null } | null } | null> | null }; +export type GetSecretsQuery = { __typename?: 'Query', secrets?: Array<{ __typename?: 'SecretType', id: string, key: string, value: string, path: string, comment: string, createdAt?: any | null, updatedAt: any, tags: Array<{ __typename?: 'SecretTagType', id: string, name: string, color: string }>, override?: { __typename?: 'PersonalSecretType', value?: string | null, isActive: boolean } | null, environment: { __typename?: 'EnvironmentType', id: string, app: { __typename?: 'AppMembershipType', id: string } } } | null> | null, folders?: Array<{ __typename?: 'SecretFolderType', id: string, name: string, path: string, createdAt?: any | null, folderCount?: number | null, secretCount?: number | null } | null> | null, appEnvironments?: Array<{ __typename?: 'EnvironmentType', id: string, name: string, envType: ApiEnvironmentEnvTypeChoices, identityKey: string, app: { __typename?: 'AppMembershipType', id: string, name: string, sseEnabled: boolean } } | null> | null, environmentKeys?: Array<{ __typename?: 'EnvironmentKeyType', id: string, identityKey: string, wrappedSeed: string, wrappedSalt: string } | null> | null, envSyncs?: Array<{ __typename?: 'EnvironmentSyncType', id: string, options: any, isActive: boolean, status: ApiEnvironmentSyncStatusChoices, lastSync?: any | null, createdAt?: any | null, environment: { __typename?: 'EnvironmentType', id: string, name: string, envType: ApiEnvironmentEnvTypeChoices }, serviceInfo?: { __typename?: 'ServiceType', id?: string | null, name?: string | null } | null } | null> | null, dynamicSecrets?: Array<{ __typename?: 'DynamicSecretType', id: string, name: string, description: string, provider: ApiDynamicSecretProviderChoices, defaultTtlSeconds?: number | null, maxTtlSeconds?: number | null, createdAt?: any | null, keyMap?: Array<{ __typename?: 'KeyMap', id?: string | null, keyName?: string | null } | null> | null, config?: { __typename?: 'AWSConfigType', usernameTemplate: string, groups?: Array | null, iamPath?: string | null, permissionBoundaryArn?: string | null, policyArns?: Array | null, policyDocument?: any | null } | null, authentication?: { __typename?: 'ProviderCredentialsType', id: string, name: string } | null } | null> | null }; export type GetServiceTokensQueryVariables = Exact<{ appId: Scalars['ID']['input']; @@ -3331,6 +3627,12 @@ export const InitAppEnvironmentsDocument = {"kind":"Document","definitions":[{"k export const LogSecretReadsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"LogSecretReads"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"ids"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"readSecret"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ids"},"value":{"kind":"Variable","name":{"kind":"Name","value":"ids"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const RemovePersonalSecretDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RemovePersonalSecret"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"secretId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"removeOverride"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"secretId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"secretId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const RenameEnvDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RenameEnv"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"environmentId"}},"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":"renameEnvironment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"environmentId"}}},{"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":"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":"updatedAt"}}]}}]}}]}}]} as unknown as DocumentNode; +export const CreateNewAwsDynamicSecretDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewAWSDynamicSecret"},"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":"environmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"path"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"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":"description"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"defaultTtl"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"maxTtl"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"authenticationId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"config"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AWSConfigInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"keyMap"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"KeyMapInput"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createAwsDynamicSecret"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"environmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"description"},"value":{"kind":"Variable","name":{"kind":"Name","value":"description"}}},{"kind":"Argument","name":{"kind":"Name","value":"defaultTtl"},"value":{"kind":"Variable","name":{"kind":"Name","value":"defaultTtl"}}},{"kind":"Argument","name":{"kind":"Name","value":"maxTtl"},"value":{"kind":"Variable","name":{"kind":"Name","value":"maxTtl"}}},{"kind":"Argument","name":{"kind":"Name","value":"authenticationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"authenticationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"config"},"value":{"kind":"Variable","name":{"kind":"Name","value":"config"}}},{"kind":"Argument","name":{"kind":"Name","value":"keyMap"},"value":{"kind":"Variable","name":{"kind":"Name","value":"keyMap"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dynamicSecret"},"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":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]}}]} as unknown as DocumentNode; +export const CreateDynamicSecretLeaseDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateDynamicSecretLease"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"secretId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"ttl"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"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":"createDynamicSecretLease"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"secretId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"secretId"}}},{"kind":"Argument","name":{"kind":"Name","value":"ttl"},"value":{"kind":"Variable","name":{"kind":"Name","value":"ttl"}}},{"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":"lease"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"credentials"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AwsCredentialsType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"accessKeyId"}},{"kind":"Field","name":{"kind":"Name","value":"secretAccessKey"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}}]}}]}}]}}]} as unknown as DocumentNode; +export const DeleteDynamicSecretOpDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteDynamicSecretOP"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"secretId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteDynamicSecret"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"secretId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"secretId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const RenewDynamicSecretLeaseOpDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RenewDynamicSecretLeaseOP"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"leaseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"ttl"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"renewDynamicSecretLease"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"leaseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"leaseId"}}},{"kind":"Argument","name":{"kind":"Name","value":"ttl"},"value":{"kind":"Variable","name":{"kind":"Name","value":"ttl"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lease"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]} as unknown as DocumentNode; +export const RevokeDynamicSecretLeaseOpDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RevokeDynamicSecretLeaseOP"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"leaseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"revokeDynamicSecretLease"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"leaseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"leaseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lease"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}},{"kind":"Field","name":{"kind":"Name","value":"revokedAt"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]} as unknown as DocumentNode; +export const UpdateDynamicSecretDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateDynamicSecret"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dynamicSecretId"}},"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":"path"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"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":"description"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"defaultTtl"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"maxTtl"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"authenticationId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"config"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AWSConfigInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"keyMap"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"KeyMapInput"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateAwsDynamicSecret"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"dynamicSecretId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dynamicSecretId"}}},{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"description"},"value":{"kind":"Variable","name":{"kind":"Name","value":"description"}}},{"kind":"Argument","name":{"kind":"Name","value":"defaultTtl"},"value":{"kind":"Variable","name":{"kind":"Name","value":"defaultTtl"}}},{"kind":"Argument","name":{"kind":"Name","value":"maxTtl"},"value":{"kind":"Variable","name":{"kind":"Name","value":"maxTtl"}}},{"kind":"Argument","name":{"kind":"Name","value":"authenticationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"authenticationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"config"},"value":{"kind":"Variable","name":{"kind":"Name","value":"config"}}},{"kind":"Argument","name":{"kind":"Name","value":"keyMap"},"value":{"kind":"Variable","name":{"kind":"Name","value":"keyMap"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dynamicSecret"},"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":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateSharedSecretDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateSharedSecret"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"LockboxInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createLockbox"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lockbox"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"allowedViews"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}}]}}]}}]}}]} as unknown as DocumentNode; export const SwapEnvOrderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SwapEnvOrder"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"environment1Id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"environment2Id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"swapEnvironmentOrder"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environment1Id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"environment1Id"}}},{"kind":"Argument","name":{"kind":"Name","value":"environment2Id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"environment2Id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const AcceptOrganisationInviteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AcceptOrganisationInvite"},"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"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"inviteId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOrganisationMember"},"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"}}},{"kind":"Argument","name":{"kind":"Name","value":"inviteId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"inviteId"}}}],"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":"email"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]} as unknown as DocumentNode; @@ -3389,6 +3691,9 @@ export const GetOrganisationMembersDocument = {"kind":"Document","definitions":[ export const GetOrganisationPlanDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrganisationPlan"},"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":"organisationPlan"},"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":"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":"seatLimit"}},{"kind":"Field","name":{"kind":"Name","value":"appCount"}}]}}]}}]} as unknown as DocumentNode; export const GetRolesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetRoles"},"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":"roles"},"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":"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":"isDefault"}}]}}]}}]} as unknown as DocumentNode; export const VerifyInviteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"VerifyInvite"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"inviteId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"validateInvite"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"inviteId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"inviteId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"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":"inviteeEmail"}},{"kind":"Field","name":{"kind":"Name","value":"invitedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"email"}}]}},{"kind":"Field","name":{"kind":"Name","value":"apps"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetDynamicSecretsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetDynamicSecrets"},"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":"appId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"envId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dynamicSecrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"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":"index"}},{"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":"description"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"config"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AWSConfigType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"usernameTemplate"}},{"kind":"Field","name":{"kind":"Name","value":"iamPath"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"keyMap"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"keyName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"defaultTtlSeconds"}},{"kind":"Field","name":{"kind":"Name","value":"maxTtlSeconds"}},{"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"}}]}}]}}]} as unknown as DocumentNode; +export const GetDynamicSecretProvidersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetDynamicSecretProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dynamicSecretProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"credentials"}},{"kind":"Field","name":{"kind":"Name","value":"configMap"}}]}}]}}]} as unknown as DocumentNode; +export const GetDynamicSecretLeasesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetDynamicSecretLeases"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"secretId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"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":"dynamicSecrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"secretId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"secretId"}}},{"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":"leases"},"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":"revokedAt"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"organisationMember"},"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":"self"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceAccount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const GetAppEnvironmentsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppEnvironments"},"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":"memberId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"memberType"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"MemberType"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"appEnvironments"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"NullValue"}},{"kind":"Argument","name":{"kind":"Name","value":"memberId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"memberId"}}},{"kind":"Argument","name":{"kind":"Name","value":"memberType"},"value":{"kind":"Variable","name":{"kind":"Name","value":"memberType"}}}],"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":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSeed"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSalt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"secretCount"}},{"kind":"Field","name":{"kind":"Name","value":"folderCount"}},{"kind":"Field","name":{"kind":"Name","value":"index"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"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":"sseEnabled"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}}]},{"kind":"Field","name":{"kind":"Name","value":"serverPublicKey"}}]}}]} as unknown as DocumentNode; export const GetAppSecretsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppSecrets"},"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":"memberId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"memberType"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"MemberType"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"path"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"appEnvironments"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"NullValue"}},{"kind":"Argument","name":{"kind":"Name","value":"memberId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"memberId"}}},{"kind":"Argument","name":{"kind":"Name","value":"memberType"},"value":{"kind":"Variable","name":{"kind":"Name","value":"memberType"}}}],"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":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSeed"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSalt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"secretCount"}},{"kind":"Field","name":{"kind":"Name","value":"folderCount"}},{"kind":"Field","name":{"kind":"Name","value":"index"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"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":"folders"},"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":"secrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"path"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"sseEnabled"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}}]},{"kind":"Field","name":{"kind":"Name","value":"serverPublicKey"}}]}}]} as unknown as DocumentNode; export const GetAppSecretsLogsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppSecretsLogs"},"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"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventTypes"}},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"memberId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"memberType"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"MemberType"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"environmentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"secretLogs"},"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"}}},{"kind":"Argument","name":{"kind":"Name","value":"eventTypes"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventTypes"}}},{"kind":"Argument","name":{"kind":"Name","value":"memberId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"memberId"}}},{"kind":"Argument","name":{"kind":"Name","value":"memberType"},"value":{"kind":"Variable","name":{"kind":"Name","value":"memberType"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"environmentId"}}}],"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":"path"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"ipAddress"}},{"kind":"Field","name":{"kind":"Name","value":"userAgent"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceToken"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceAccount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"deletedAt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceAccountToken"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"deletedAt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"eventType"}},{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"envType"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"secret"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"path"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","name":{"kind":"Name","value":"environmentKeys"},"arguments":[{"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":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSeed"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSalt"}},{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; @@ -3399,7 +3704,7 @@ export const GetOrgSecretKeysDocument = {"kind":"Document","definitions":[{"kind export const GetSecretHistoryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSecretHistory"},"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":"envId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"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":"secrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}},{"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":"id"}},{"kind":"Field","name":{"kind":"Name","value":"history"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"ipAddress"}},{"kind":"Field","name":{"kind":"Name","value":"userAgent"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceToken"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceAccount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"deletedAt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"eventType"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"environmentKeys"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSeed"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSalt"}}]}}]}}]} as unknown as DocumentNode; export const GetEnvSecretsKvDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetEnvSecretsKV"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"envId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"folders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}},{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"StringValue","value":"/","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"secrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}},{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"StringValue","value":"/","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"path"}}]}},{"kind":"Field","name":{"kind":"Name","value":"environmentKeys"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSeed"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSalt"}}]}}]}}]} as unknown as DocumentNode; export const GetSecretTagsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSecretTags"},"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":"secretTags"},"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":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}}]} as unknown as DocumentNode; -export const GetSecretsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSecrets"},"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":"envId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"path"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"secrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}},{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"override"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}}]}},{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"folders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}},{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}}],"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":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"folderCount"}},{"kind":"Field","name":{"kind":"Name","value":"secretCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"appEnvironments"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"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":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"environmentKeys"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSeed"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSalt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"envSyncs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"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":"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":"options"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]} as unknown as DocumentNode; +export const GetSecretsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSecrets"},"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":"envId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"path"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"secrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}},{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"override"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}}]}},{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"folders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}},{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}}],"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":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"folderCount"}},{"kind":"Field","name":{"kind":"Name","value":"secretCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"appEnvironments"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"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":"identityKey"}},{"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":"sseEnabled"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"environmentKeys"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSeed"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSalt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"envSyncs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"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":"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":"options"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dynamicSecrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"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":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"keyMap"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"keyName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"config"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AWSConfigType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"usernameTemplate"}},{"kind":"Field","name":{"kind":"Name","value":"groups"}},{"kind":"Field","name":{"kind":"Name","value":"iamPath"}},{"kind":"Field","name":{"kind":"Name","value":"permissionBoundaryArn"}},{"kind":"Field","name":{"kind":"Name","value":"policyArns"}},{"kind":"Field","name":{"kind":"Name","value":"policyDocument"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"defaultTtlSeconds"}},{"kind":"Field","name":{"kind":"Name","value":"maxTtlSeconds"}},{"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"}}]}}]}}]} as unknown as DocumentNode; export const GetServiceTokensDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetServiceTokens"},"variableDefinitions":[{"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":"serviceTokens"},"arguments":[{"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":"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":"expiresAt"}},{"kind":"Field","name":{"kind":"Name","value":"keys"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetServiceAccountDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetServiceAccountDetail"},"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":"permissions"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"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":"appMemberships"},"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":"sseEnabled"}}]}},{"kind":"Field","name":{"kind":"Name","value":"networkPolicies"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"allowedIps"}},{"kind":"Field","name":{"kind":"Name","value":"isGlobal"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetServiceAccountHandlersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetServiceAccountHandlers"},"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":"serviceAccountHandlers"},"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":"email"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"}}]}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"self"}}]}}]}}]} as unknown as DocumentNode; diff --git a/frontend/apollo/schema.graphql b/frontend/apollo/schema.graphql index e726ab1c0..0ebf2732b 100644 --- a/frontend/apollo/schema.graphql +++ b/frontend/apollo/schema.graphql @@ -53,6 +53,8 @@ type Query { stripeCheckoutDetails(stripeSessionId: String!): StripeCheckoutDetails stripeSubscriptionDetails(organisationId: ID): StripeSubscriptionDetails stripeCustomerPortalUrl(organisationId: ID!): String + dynamicSecretProviders: [DynamicSecretProviderType] + dynamicSecrets(secretId: ID, appId: ID, envId: ID, orgId: ID): [DynamicSecretType] } type OrganisationType { @@ -771,6 +773,107 @@ enum PlanTypeEnum { ENTERPRISE } +type DynamicSecretProviderType { + id: String! + name: String! + credentials: GenericScalar! + configMap: GenericScalar! +} + +""" +The `GenericScalar` scalar type represents a generic +GraphQL scalar value that could be: +String, Boolean, Int, Float, List or Object. +""" +scalar GenericScalar + +type DynamicSecretType { + id: String! + name: String! + description: String! + environment: EnvironmentType! + folder: SecretFolderType + path: String! + authentication: ProviderCredentialsType + + """Which provider this secret is associated with.""" + provider: ApiDynamicSecretProviderChoices! + config: DynamicSecretConfigUnion + keyMap: [KeyMap] + createdAt: DateTime + updatedAt: DateTime! + deletedAt: DateTime + leases: [DynamicSecretLeaseType!]! + defaultTtlSeconds: Int + maxTtlSeconds: Int +} + +enum ApiDynamicSecretProviderChoices { + """AWS""" + AWS +} + +union DynamicSecretConfigUnion = AWSConfigType + +type AWSConfigType { + usernameTemplate: String! + iamPath: String + permissionBoundaryArn: String + groups: [String] + policyArns: [String] + policyDocument: GenericScalar +} + +type KeyMap { + id: String + keyName: String +} + +type DynamicSecretLeaseType { + id: String! + name: String! + description: String! + secret: DynamicSecretType! + organisationMember: OrganisationMemberType + serviceAccount: ServiceAccountType + ttl: Float! + + """Current status of the lease""" + status: ApiDynamicSecretLeaseStatusChoices! + credentials: LeaseCredentialsUnion + createdAt: DateTime + renewedAt: DateTime + expiresAt: DateTime + revokedAt: DateTime + deletedAt: DateTime + cleanupJobId: String! +} + +enum ApiDynamicSecretLeaseStatusChoices { + """Created""" + CREATED + + """Active""" + ACTIVE + + """Renewed""" + RENEWED + + """Revoked""" + REVOKED + + """Expired""" + EXPIRED +} + +union LeaseCredentialsUnion = AwsCredentialsType + +type AwsCredentialsType { + accessKeyId: String + secretAccessKey: String + username: String +} + type Mutation { createOrganisation(id: ID!, identityKey: String!, name: String!, wrappedKeyring: String!, wrappedRecovery: String!): CreateOrganisationMutation bulkInviteOrganisationMembers(invites: [InviteInput]!, orgId: ID!): BulkInviteOrganisationMembersMutation @@ -854,6 +957,12 @@ type Mutation { """Payment Method ID to set as default""" paymentMethodId: String! ): SetDefaultPaymentMethodMutation + createAwsDynamicSecret(authenticationId: ID, config: AWSConfigInput!, defaultTtl: Int, description: String, environmentId: ID!, keyMap: [KeyMapInput]!, maxTtl: Int, name: String!, organisationId: ID!, path: String): CreateAWSDynamicSecretMutation + updateAwsDynamicSecret(authenticationId: ID, config: AWSConfigInput!, defaultTtl: Int, description: String, dynamicSecretId: ID!, keyMap: [KeyMapInput]!, maxTtl: Int, name: String!, organisationId: ID!, path: String): UpdateAWSDynamicSecretMutation + deleteDynamicSecret(secretId: ID!): DeleteDynamicSecretMutation + createDynamicSecretLease(name: String, secretId: ID!, ttl: Int): LeaseDynamicSecret + renewDynamicSecretLease(leaseId: ID!, ttl: Int): RenewLeaseMutation + revokeDynamicSecretLease(leaseId: ID!): RevokeLeaseMutation } type CreateOrganisationMutation { @@ -1254,4 +1363,42 @@ type CreateSetupIntentMutation { type SetDefaultPaymentMethodMutation { ok: Boolean +} + +type CreateAWSDynamicSecretMutation { + dynamicSecret: DynamicSecretType +} + +input AWSConfigInput { + usernameTemplate: String! + iamPath: String = "/" + permissionBoundaryArn: String + groups: [String] + policyArns: [String] + policyDocument: GenericScalar +} + +input KeyMapInput { + id: String! + keyName: String! +} + +type UpdateAWSDynamicSecretMutation { + dynamicSecret: DynamicSecretType +} + +type DeleteDynamicSecretMutation { + ok: Boolean +} + +type LeaseDynamicSecret { + lease: DynamicSecretLeaseType +} + +type RenewLeaseMutation { + lease: DynamicSecretLeaseType +} + +type RevokeLeaseMutation { + lease: DynamicSecretLeaseType } \ No newline at end of file From c9cc5ddf42bdbd6232d0f3404d6d21440bf5d2b0 Mon Sep 17 00:00:00 2001 From: rohan Date: Sat, 30 Aug 2025 14:29:31 +0530 Subject: [PATCH 004/117] feat: add misc frontend utils Signed-off-by: rohan --- frontend/utils/dynamicSecrets.ts | 30 ++++++++++++++++++++++++++++++ frontend/utils/secrets.ts | 26 ++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 frontend/utils/dynamicSecrets.ts diff --git a/frontend/utils/dynamicSecrets.ts b/frontend/utils/dynamicSecrets.ts new file mode 100644 index 000000000..190d9e419 --- /dev/null +++ b/frontend/utils/dynamicSecrets.ts @@ -0,0 +1,30 @@ +export const MINIMUM_LEASE_TTL = 60 // 1 minute + +export const leaseTtlButtons = [ + { + label: '15min', + seconds: '900', + }, + { + label: '1h', + seconds: '3600', + }, + { + label: '3h', + seconds: '10800', + }, + { + label: '6h', + seconds: '21600', + }, + { + label: '12h', + seconds: '43200', + }, + { + label: '24h', + seconds: '86400', + }, + ] + + diff --git a/frontend/utils/secrets.ts b/frontend/utils/secrets.ts index 579ef4ac2..869cea1ba 100644 --- a/frontend/utils/secrets.ts +++ b/frontend/utils/secrets.ts @@ -1,4 +1,4 @@ -import { EnvironmentType, SecretType } from '@/apollo/graphql' +import { DynamicSecretType, EnvironmentType, SecretType } from '@/apollo/graphql' import { AppSecret } from '@/app/[team]/apps/[app]/types' export type SortOption = @@ -142,19 +142,37 @@ export const processEnvFile = ( return newSecrets } -export const duplicateKeysExist = (secrets: SecretType[] | AppSecret[]) => { +export const duplicateKeysExist = ( + secrets: SecretType[] | AppSecret[], + dynamicSecrets: DynamicSecretType[] = [] +): boolean => { const keySet = new Set() + // Check regular secrets for (const secret of secrets) { if (keySet.has(secret.key)) { - return true // Duplicate key found + return true // Duplicate found } keySet.add(secret.key) } - return false // No duplicate keys found + // Check dynamic secrets' keyMap + for (const ds of dynamicSecrets) { + if (!ds.keyMap) continue + + for (const km of ds.keyMap) { + if (!km?.keyName) continue + if (keySet.has(km.keyName)) { + return true // Duplicate found + } + keySet.add(km.keyName) + } + } + + return false // No duplicates } + export const envFilePlaceholder = `# Paste your .env here # Comments before a key-value pair will be parsed From 8daa7e21965f7cd7c371165ba69fe521a38efcc2 Mon Sep 17 00:00:00 2001 From: rohan Date: Sat, 30 Aug 2025 14:29:50 +0530 Subject: [PATCH 005/117] feat: misc improvements to stepper styling Signed-off-by: rohan --- frontend/components/onboarding/Stepper.tsx | 31 ++++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/frontend/components/onboarding/Stepper.tsx b/frontend/components/onboarding/Stepper.tsx index 5b95d0105..b8cb472df 100644 --- a/frontend/components/onboarding/Stepper.tsx +++ b/frontend/components/onboarding/Stepper.tsx @@ -11,9 +11,10 @@ export type Step = { interface StepperProps { steps: Step[] activeStep: number + align?: 'center' | 'left' } -export const Stepper = (props: StepperProps) => { +export const Stepper = ({ steps, activeStep, align = 'center' }: StepperProps) => { const ICON_WRAPPER_BASE = 'rounded-full transition duration-500 ease-in-out h-10 w-10 py-3 border text-center flex justify-center items-center' const LABEL_BASE = @@ -21,18 +22,18 @@ export const Stepper = (props: StepperProps) => { const THREAD_BASE = 'flex-auto border-t transition duration-500 ease-in-out' const stepIsComplete = (step: Step) => { - return step.index < props.activeStep + return step.index < activeStep } const stepIsActive = (step: Step) => { - return step.index === props.activeStep + return step.index === activeStep } return ( -
+
- {props.steps.map((step: Step, index: number) => ( + {steps.map((step: Step, index: number) => ( <>
{ {step.name}
- {index !== props.steps.length - 1 && ( + {index !== steps.length - 1 && (
{ ))}
-
-
- {props.steps[props.activeStep].title} -
-
- {props.steps[props.activeStep].description} +
+
+ {steps[activeStep].title}
+
{steps[activeStep].description}
) From 428217cf08e726a30d6b9f764b510ea73232940f Mon Sep 17 00:00:00 2001 From: rohan Date: Sat, 30 Aug 2025 14:30:19 +0530 Subject: [PATCH 006/117] feat: add support for custom classes to input and label Signed-off-by: rohan --- frontend/components/common/Input.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/frontend/components/common/Input.tsx b/frontend/components/common/Input.tsx index 7a3a01d64..60667247b 100644 --- a/frontend/components/common/Input.tsx +++ b/frontend/components/common/Input.tsx @@ -8,18 +8,22 @@ interface InputProps extends React.InputHTMLAttributes { label?: string placeholder?: string secret?: boolean + labelClassName?: string } // Use forwardRef to allow refs to be passed to the component export const Input = forwardRef((props, ref) => { - const { value, setValue, label, secret } = props + const { value, setValue, label, secret, labelClassName } = props const [showValue, setShowValue] = useState(false) return (
{label && ( -