diff --git a/backend/api/tasks/syncing.py b/backend/api/tasks/syncing.py index f23addd22..3b42bbb00 100644 --- a/backend/api/tasks/syncing.py +++ b/backend/api/tasks/syncing.py @@ -257,6 +257,7 @@ def perform_github_actions_sync(environment_sync): access_token, api_host = get_gh_actions_credentials(environment_sync) repo_name = environment_sync.options.get("repo_name") repo_owner = environment_sync.options.get("owner") + environment_name = environment_sync.options.get("environment_name") handle_sync_event( environment_sync, @@ -265,6 +266,7 @@ def perform_github_actions_sync(environment_sync): repo_name, repo_owner, api_host, + environment_name, ) diff --git a/backend/api/utils/syncing/github/actions.py b/backend/api/utils/syncing/github/actions.py index a35ea4f80..fafc33659 100644 --- a/backend/api/utils/syncing/github/actions.py +++ b/backend/api/utils/syncing/github/actions.py @@ -100,6 +100,50 @@ def get_gh_actions_credentials(environment_sync): return access_token, api_host +def list_environments(credential_id, owner, repo_name): + """Return a list of GitHub Actions environment names for a repo. + + This requires at least the `repo` scope on the OAuth token. + """ + ProviderCredentials = apps.get_model("api", "ProviderCredentials") + + pk, sk = get_server_keypair() + credential = ProviderCredentials.objects.get(id=credential_id) + + access_token = decrypt_asymmetric( + credential.credentials["access_token"], sk.hex(), pk.hex() + ) + + api_host = GITHUB_CLOUD_API_URL + if "host" in credential.credentials: + api_host = decrypt_asymmetric( + credential.credentials["api_url"], sk.hex(), pk.hex() + ) + + api_host = normalize_api_host(api_host) + + headers = {"Authorization": f"Bearer {access_token}", "Accept": "application/vnd.github+json"} + + environments = [] + page = 1 + while True: + url = f"{api_host}/repos/{owner}/{repo_name}/environments?per_page=100&page={page}" + response = requests.get(url, headers=headers) + if response.status_code != 200: + raise Exception( + f"Error fetching environments: {response.status_code} {response.text}" + ) + + payload = response.json() + items = payload.get("environments", []) + if not items: + break + environments.extend([env.get("name") for env in items if env.get("name")]) + page += 1 + + return environments + + def encrypt_secret(public_key: str, secret_value: str) -> str: pk = nacl.public.PublicKey(public_key, nacl.encoding.Base64Encoder()) box = nacl.public.SealedBox(pk) @@ -136,8 +180,29 @@ def get_all_secrets(repo, owner, headers, api_host=GITHUB_CLOUD_API_URL): return all_secrets +def get_all_env_secrets(repo, owner, environment_name, headers, api_host=GITHUB_CLOUD_API_URL): + api_host = normalize_api_host(api_host) + all_secrets = [] + page = 1 + while True: + response = requests.get( + f"{api_host}/repos/{owner}/{repo}/environments/{environment_name}/secrets?page={page}", + headers=headers, + ) + if response.status_code != 200 or not response.json().get("secrets"): + break + all_secrets.extend(response.json()["secrets"]) + page += 1 + return all_secrets + + def sync_github_secrets( - secrets, access_token, repo, owner, api_host=GITHUB_CLOUD_API_URL + secrets, + access_token, + repo, + owner, + api_host=GITHUB_CLOUD_API_URL, + environment_name=None, ): api_host = normalize_api_host(api_host) @@ -150,10 +215,14 @@ def sync_github_secrets( "Accept": "application/vnd.github+json", } - public_key_response = requests.get( - f"{api_host}/repos/{owner}/{repo}/actions/secrets/public-key", - headers=headers, - ) + if environment_name: + public_key_url = ( + f"{api_host}/repos/{owner}/{repo}/environments/{environment_name}/secrets/public-key" + ) + else: + public_key_url = f"{api_host}/repos/{owner}/{repo}/actions/secrets/public-key" + + public_key_response = requests.get(public_key_url, headers=headers) if public_key_response.status_code != 200: return False, { "response_code": public_key_response.status_code, @@ -165,7 +234,12 @@ def sync_github_secrets( public_key_value = public_key["key"] local_secrets = {k: v for k, v, _ in secrets} - existing_secrets = get_all_secrets(repo, owner, headers, api_host) + if environment_name: + existing_secrets = get_all_env_secrets( + repo, owner, environment_name, headers, api_host + ) + else: + existing_secrets = get_all_secrets(repo, owner, headers, api_host) existing_secret_names = {secret["name"] for secret in existing_secrets} for key, value in local_secrets.items(): @@ -174,7 +248,12 @@ def sync_github_secrets( continue # Skip oversized secret secret_data = {"encrypted_value": encrypted_value, "key_id": key_id} - secret_url = f"{api_host}/repos/{owner}/{repo}/actions/secrets/{key}" + if environment_name: + secret_url = ( + f"{api_host}/repos/{owner}/{repo}/environments/{environment_name}/secrets/{key}" + ) + else: + secret_url = f"{api_host}/repos/{owner}/{repo}/actions/secrets/{key}" response = requests.put(secret_url, headers=headers, json=secret_data) if response.status_code not in [201, 204]: @@ -185,9 +264,14 @@ def sync_github_secrets( for secret_name in existing_secret_names: if secret_name not in local_secrets: - delete_url = ( - f"{api_host}/repos/{owner}/{repo}/actions/secrets/{secret_name}" - ) + if environment_name: + delete_url = ( + f"{api_host}/repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}" + ) + else: + delete_url = ( + f"{api_host}/repos/{owner}/{repo}/actions/secrets/{secret_name}" + ) delete_response = requests.delete(delete_url, headers=headers) if delete_response.status_code != 204: return False, { diff --git a/backend/backend/graphene/mutations/syncing.py b/backend/backend/graphene/mutations/syncing.py index f032cde79..b1970b06a 100644 --- a/backend/backend/graphene/mutations/syncing.py +++ b/backend/backend/graphene/mutations/syncing.py @@ -266,11 +266,14 @@ class Arguments: credential_id = graphene.ID() repo_name = graphene.String() owner = graphene.String() + environment_name = graphene.String(required=False) sync = graphene.Field(EnvironmentSyncType) @classmethod - def mutate(cls, root, info, env_id, path, credential_id, repo_name, owner): + def mutate( + cls, root, info, env_id, path, credential_id, repo_name, owner, environment_name=None + ): service_id = "github_actions" service_config = ServiceConfig.get_service_config(service_id) @@ -283,6 +286,8 @@ def mutate(cls, root, info, env_id, path, credential_id, repo_name, owner): raise GraphQLError("You don't have access to this app") sync_options = {"repo_name": repo_name, "owner": owner} + if environment_name: + sync_options["environment_name"] = environment_name existing_syncs = EnvironmentSync.objects.filter( environment__app_id=env.app.id, service=service_id, deleted_at=None diff --git a/backend/backend/graphene/queries/syncing.py b/backend/backend/graphene/queries/syncing.py index 164228872..ba427a5e0 100644 --- a/backend/backend/graphene/queries/syncing.py +++ b/backend/backend/graphene/queries/syncing.py @@ -20,7 +20,7 @@ ) from api.services import Providers, ServiceConfig from api.utils.syncing.aws.secrets_manager import list_aws_secrets -from api.utils.syncing.github.actions import list_repos +from api.utils.syncing.github.actions import list_repos, list_environments from api.utils.syncing.vault.main import test_vault_creds from api.utils.syncing.nomad.main import test_nomad_creds from api.utils.syncing.gitlab.main import list_gitlab_groups, list_gitlab_projects @@ -191,6 +191,14 @@ def resolve_gh_repos(root, info, credential_id): raise GraphQLError(ex) +def resolve_github_environments(root, info, credential_id, owner, repo_name): + try: + envs = list_environments(credential_id, owner, repo_name) + return envs + except Exception as ex: + raise GraphQLError(ex) + + def resolve_test_vault_creds(root, info, credential_id): try: valid = test_vault_creds(credential_id) diff --git a/backend/backend/schema.py b/backend/backend/schema.py index e5d0c8457..47e334221 100644 --- a/backend/backend/schema.py +++ b/backend/backend/schema.py @@ -70,6 +70,7 @@ from .graphene.queries.syncing import ( resolve_aws_secret_manager_secrets, resolve_gh_repos, + resolve_github_environments, resolve_gitlab_projects, resolve_gitlab_groups, resolve_server_public_key, @@ -384,6 +385,9 @@ class Query(graphene.ObjectType): GitHubRepoType, credential_id=graphene.ID(), ) + github_environments = graphene.List( + graphene.String, credential_id=graphene.ID(), owner=graphene.String(), repo_name=graphene.String() + ) gitlab_projects = graphene.List(GitLabProjectType, credential_id=graphene.ID()) gitlab_groups = graphene.List(GitLabGroupType, credential_id=graphene.ID()) @@ -458,6 +462,7 @@ class Query(graphene.ObjectType): resolve_aws_secrets = resolve_aws_secret_manager_secrets resolve_github_repos = resolve_gh_repos + resolve_github_environments = resolve_github_environments resolve_gitlab_projects = resolve_gitlab_projects resolve_gitlab_groups = resolve_gitlab_groups diff --git a/frontend/apollo/gql.ts b/frontend/apollo/gql.ts index abb28ea82..2e2ef231f 100644 --- a/frontend/apollo/gql.ts +++ b/frontend/apollo/gql.ts @@ -84,7 +84,7 @@ const documents = { "mutation CreateNewCfWorkersSync($envId: ID!, $path: String!, $workerName: String!, $credentialId: ID!) {\n createCloudflareWorkersSync(\n envId: $envId\n path: $path\n workerName: $workerName\n credentialId: $credentialId\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}": types.CreateNewCfWorkersSyncDocument, "mutation DeleteProviderCreds($credentialId: ID!) {\n deleteProviderCredentials(credentialId: $credentialId) {\n ok\n }\n}": types.DeleteProviderCredsDocument, "mutation DeleteSync($syncId: ID!) {\n deleteEnvSync(syncId: $syncId) {\n ok\n }\n}": types.DeleteSyncDocument, - "mutation CreateNewGhActionsSync($envId: ID!, $path: String!, $repoName: String!, $owner: String!, $credentialId: ID!) {\n createGhActionsSync(\n envId: $envId\n path: $path\n repoName: $repoName\n owner: $owner\n credentialId: $credentialId\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}": types.CreateNewGhActionsSyncDocument, + "mutation CreateNewGhActionsSync($envId: ID!, $path: String!, $repoName: String!, $owner: String!, $credentialId: ID!, $environmentName: String) {\n createGhActionsSync(\n envId: $envId\n path: $path\n repoName: $repoName\n owner: $owner\n credentialId: $credentialId\n environmentName: $environmentName\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}": types.CreateNewGhActionsSyncDocument, "mutation CreateNewGitlabCiSync($envId: ID!, $path: String!, $credentialId: ID!, $resourcePath: String!, $resourceId: String!, $isGroup: Boolean!, $isMasked: Boolean!, $isProtected: Boolean!) {\n createGitlabCiSync(\n envId: $envId\n path: $path\n credentialId: $credentialId\n resourcePath: $resourcePath\n resourceId: $resourceId\n isGroup: $isGroup\n masked: $isMasked\n protected: $isProtected\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}": types.CreateNewGitlabCiSyncDocument, "mutation InitAppSyncing($appId: ID!, $envKeys: [EnvironmentKeyInput]) {\n initEnvSync(appId: $appId, envKeys: $envKeys) {\n app {\n id\n sseEnabled\n }\n }\n}": types.InitAppSyncingDocument, "mutation CreateNewNomadSync($envId: ID!, $path: String!, $nomadPath: String!, $nomadNamespace: String!, $credentialId: ID!) {\n createNomadSync(\n envId: $envId\n path: $path\n nomadPath: $nomadPath\n nomadNamespace: $nomadNamespace\n credentialId: $credentialId\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}": types.CreateNewNomadSyncDocument, @@ -155,6 +155,7 @@ const documents = { "query GetSavedCredentials($orgId: ID!) {\n savedCredentials(orgId: $orgId) {\n id\n name\n credentials\n createdAt\n provider {\n id\n name\n expectedCredentials\n optionalCredentials\n }\n syncCount\n }\n}": types.GetSavedCredentialsDocument, "query GetServerKey {\n serverPublicKey\n}": types.GetServerKeyDocument, "query GetServiceList {\n services {\n id\n name\n provider {\n id\n }\n }\n}": types.GetServiceListDocument, + "query GetGithubEnvironments($credentialId: ID!, $owner: String!, $repoName: String!) {\n githubEnvironments(\n credentialId: $credentialId\n owner: $owner\n repoName: $repoName\n )\n}": types.GetGithubEnvironmentsDocument, "query GetGithubRepos($credentialId: ID!) {\n githubRepos(credentialId: $credentialId) {\n name\n owner\n type\n }\n}": types.GetGithubReposDocument, "query GetGitLabResources($credentialId: ID!) {\n gitlabProjects(credentialId: $credentialId) {\n id\n name\n namespace {\n name\n fullPath\n }\n pathWithNamespace\n webUrl\n }\n gitlabGroups(credentialId: $credentialId) {\n id\n fullName\n fullPath\n webUrl\n }\n}": types.GetGitLabResourcesDocument, "query TestNomadAuth($credentialId: ID!) {\n testNomadCreds(credentialId: $credentialId)\n}": types.TestNomadAuthDocument, @@ -467,7 +468,7 @@ export function graphql(source: "mutation DeleteSync($syncId: ID!) {\n deleteEn /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "mutation CreateNewGhActionsSync($envId: ID!, $path: String!, $repoName: String!, $owner: String!, $credentialId: ID!) {\n createGhActionsSync(\n envId: $envId\n path: $path\n repoName: $repoName\n owner: $owner\n credentialId: $credentialId\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}"): (typeof documents)["mutation CreateNewGhActionsSync($envId: ID!, $path: String!, $repoName: String!, $owner: String!, $credentialId: ID!) {\n createGhActionsSync(\n envId: $envId\n path: $path\n repoName: $repoName\n owner: $owner\n credentialId: $credentialId\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}"]; +export function graphql(source: "mutation CreateNewGhActionsSync($envId: ID!, $path: String!, $repoName: String!, $owner: String!, $credentialId: ID!, $environmentName: String) {\n createGhActionsSync(\n envId: $envId\n path: $path\n repoName: $repoName\n owner: $owner\n credentialId: $credentialId\n environmentName: $environmentName\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}"): (typeof documents)["mutation CreateNewGhActionsSync($envId: ID!, $path: String!, $repoName: String!, $owner: String!, $credentialId: ID!, $environmentName: String) {\n createGhActionsSync(\n envId: $envId\n path: $path\n repoName: $repoName\n owner: $owner\n credentialId: $credentialId\n environmentName: $environmentName\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -748,6 +749,10 @@ export function graphql(source: "query GetServerKey {\n serverPublicKey\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 GetServiceList {\n services {\n id\n name\n provider {\n id\n }\n }\n}"): (typeof documents)["query GetServiceList {\n services {\n id\n name\n provider {\n id\n }\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "query GetGithubEnvironments($credentialId: ID!, $owner: String!, $repoName: String!) {\n githubEnvironments(\n credentialId: $credentialId\n owner: $owner\n repoName: $repoName\n )\n}"): (typeof documents)["query GetGithubEnvironments($credentialId: ID!, $owner: String!, $repoName: String!) {\n githubEnvironments(\n credentialId: $credentialId\n owner: $owner\n repoName: $repoName\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 48d2a2d45..f6de5ce83 100644 --- a/frontend/apollo/graphql.ts +++ b/frontend/apollo/graphql.ts @@ -1106,6 +1106,7 @@ export type MutationCreateEnvironmentTokenArgs = { export type MutationCreateGhActionsSyncArgs = { credentialId?: InputMaybe; envId?: InputMaybe; + environmentName?: InputMaybe; owner?: InputMaybe; path?: InputMaybe; repoName?: InputMaybe; @@ -1791,6 +1792,7 @@ export type Query = { environmentKeys?: Maybe>>; environmentTokens?: Maybe>>; folders?: Maybe>>; + githubEnvironments?: Maybe>>; githubRepos?: Maybe>>; gitlabGroups?: Maybe>>; gitlabProjects?: Maybe>>; @@ -1914,6 +1916,13 @@ export type QueryFoldersArgs = { }; +export type QueryGithubEnvironmentsArgs = { + credentialId?: InputMaybe; + owner?: InputMaybe; + repoName?: InputMaybe; +}; + + export type QueryGithubReposArgs = { credentialId?: InputMaybe; }; @@ -3181,6 +3190,7 @@ export type CreateNewGhActionsSyncMutationVariables = Exact<{ repoName: Scalars['String']['input']; owner: Scalars['String']['input']; credentialId: Scalars['ID']['input']; + environmentName?: InputMaybe; }>; @@ -3734,6 +3744,15 @@ export type GetServiceListQueryVariables = Exact<{ [key: string]: never; }>; export type GetServiceListQuery = { __typename?: 'Query', services?: Array<{ __typename?: 'ServiceType', id?: string | null, name?: string | null, provider?: { __typename?: 'ProviderType', id: string } | null } | null> | null }; +export type GetGithubEnvironmentsQueryVariables = Exact<{ + credentialId: Scalars['ID']['input']; + owner: Scalars['String']['input']; + repoName: Scalars['String']['input']; +}>; + + +export type GetGithubEnvironmentsQuery = { __typename?: 'Query', githubEnvironments?: Array | null }; + export type GetGithubReposQueryVariables = Exact<{ credentialId: Scalars['ID']['input']; }>; @@ -3870,7 +3889,7 @@ export const CreateNewCfPagesSyncDocument = {"kind":"Document","definitions":[{" export const CreateNewCfWorkersSyncDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewCfWorkersSync"},"variableDefinitions":[{"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":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workerName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createCloudflareWorkersSync"},"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"}}},{"kind":"Argument","name":{"kind":"Name","value":"workerName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workerName"}}},{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sync"},"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":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode; export const DeleteProviderCredsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteProviderCreds"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteProviderCredentials"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeleteSyncDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteSync"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"syncId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteEnvSync"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"syncId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"syncId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const CreateNewGhActionsSyncDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewGhActionsSync"},"variableDefinitions":[{"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":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"repoName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"owner"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createGhActionsSync"},"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"}}},{"kind":"Argument","name":{"kind":"Name","value":"repoName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"repoName"}}},{"kind":"Argument","name":{"kind":"Name","value":"owner"},"value":{"kind":"Variable","name":{"kind":"Name","value":"owner"}}},{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sync"},"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":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode; +export const CreateNewGhActionsSyncDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewGhActionsSync"},"variableDefinitions":[{"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":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"repoName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"owner"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"environmentName"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createGhActionsSync"},"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"}}},{"kind":"Argument","name":{"kind":"Name","value":"repoName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"repoName"}}},{"kind":"Argument","name":{"kind":"Name","value":"owner"},"value":{"kind":"Variable","name":{"kind":"Name","value":"owner"}}},{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"environmentName"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sync"},"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":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateNewGitlabCiSyncDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewGitlabCiSync"},"variableDefinitions":[{"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":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"resourcePath"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"resourceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isGroup"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isMasked"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isProtected"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createGitlabCiSync"},"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"}}},{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}},{"kind":"Argument","name":{"kind":"Name","value":"resourcePath"},"value":{"kind":"Variable","name":{"kind":"Name","value":"resourcePath"}}},{"kind":"Argument","name":{"kind":"Name","value":"resourceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"resourceId"}}},{"kind":"Argument","name":{"kind":"Name","value":"isGroup"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isGroup"}}},{"kind":"Argument","name":{"kind":"Name","value":"masked"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isMasked"}}},{"kind":"Argument","name":{"kind":"Name","value":"protected"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isProtected"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sync"},"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":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode; export const InitAppSyncingDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"InitAppSyncing"},"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":"envKeys"}},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EnvironmentKeyInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"initEnvSync"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"envKeys"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envKeys"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"sseEnabled"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateNewNomadSyncDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewNomadSync"},"variableDefinitions":[{"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":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"nomadPath"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"nomadNamespace"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createNomadSync"},"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"}}},{"kind":"Argument","name":{"kind":"Name","value":"nomadPath"},"value":{"kind":"Variable","name":{"kind":"Name","value":"nomadPath"}}},{"kind":"Argument","name":{"kind":"Name","value":"nomadNamespace"},"value":{"kind":"Variable","name":{"kind":"Name","value":"nomadNamespace"}}},{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sync"},"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":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode; @@ -3941,6 +3960,7 @@ export const GetProviderListDocument = {"kind":"Document","definitions":[{"kind" export const GetSavedCredentialsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSavedCredentials"},"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":"savedCredentials"},"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":"credentials"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"provider"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"expectedCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"optionalCredentials"}}]}},{"kind":"Field","name":{"kind":"Name","value":"syncCount"}}]}}]}}]} as unknown as DocumentNode; export const GetServerKeyDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetServerKey"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverPublicKey"}}]}}]} as unknown as DocumentNode; export const GetServiceListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetServiceList"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"services"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"provider"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetGithubEnvironmentsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetGithubEnvironments"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"owner"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"repoName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"githubEnvironments"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}},{"kind":"Argument","name":{"kind":"Name","value":"owner"},"value":{"kind":"Variable","name":{"kind":"Name","value":"owner"}}},{"kind":"Argument","name":{"kind":"Name","value":"repoName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"repoName"}}}]}]}}]} as unknown as DocumentNode; export const GetGithubReposDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetGithubRepos"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"githubRepos"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"owner"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]}}]} as unknown as DocumentNode; export const GetGitLabResourcesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetGitLabResources"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"gitlabProjects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"namespace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"fullPath"}}]}},{"kind":"Field","name":{"kind":"Name","value":"pathWithNamespace"}},{"kind":"Field","name":{"kind":"Name","value":"webUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"gitlabGroups"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"fullPath"}},{"kind":"Field","name":{"kind":"Name","value":"webUrl"}}]}}]}}]} as unknown as DocumentNode; export const TestNomadAuthDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TestNomadAuth"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"testNomadCreds"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}]}]}}]} as unknown as DocumentNode; diff --git a/frontend/apollo/schema.graphql b/frontend/apollo/schema.graphql index 6154c9b23..e87d120d1 100644 --- a/frontend/apollo/schema.graphql +++ b/frontend/apollo/schema.graphql @@ -42,6 +42,7 @@ type Query { cloudflareWorkers(credentialId: ID): [CloudflareWorkerType] awsSecrets(credentialId: ID): [AWSSecretType] githubRepos(credentialId: ID): [GitHubRepoType] + githubEnvironments(credentialId: ID, owner: String, repoName: String): [String] gitlabProjects(credentialId: ID): [GitLabProjectType] gitlabGroups(credentialId: ID): [GitLabGroupType] railwayProjects(credentialId: ID): [RailwayProjectType] @@ -991,7 +992,7 @@ type Mutation { createCloudflarePagesSync(credentialId: ID, deploymentId: ID, envId: ID, path: String, projectEnv: String, projectName: String): CreateCloudflarePagesSync createCloudflareWorkersSync(credentialId: ID, envId: ID, path: String, workerName: String): CreateCloudflareWorkersSync createAwsSecretSync(credentialId: ID, envId: ID, kmsId: String, path: String, secretName: String): CreateAWSSecretsManagerSync - createGhActionsSync(credentialId: ID, envId: ID, owner: String, path: String, repoName: String): CreateGitHubActionsSync + createGhActionsSync(credentialId: ID, envId: ID, environmentName: String, owner: String, path: String, repoName: String): CreateGitHubActionsSync createVaultSync(credentialId: ID, engine: String, envId: ID, path: String, vaultPath: String): CreateVaultSync createNomadSync(credentialId: ID, envId: ID, nomadNamespace: String, nomadPath: String, path: String): CreateNomadSync createGitlabCiSync(credentialId: ID, envId: ID, isGroup: Boolean, masked: Boolean, path: String, protected: Boolean, resourceId: String, resourcePath: String): CreateGitLabCISync diff --git a/frontend/components/syncing/CreateSyncDialog.tsx b/frontend/components/syncing/CreateSyncDialog.tsx index 1f6aca927..87e8d74ea 100644 --- a/frontend/components/syncing/CreateSyncDialog.tsx +++ b/frontend/components/syncing/CreateSyncDialog.tsx @@ -116,7 +116,7 @@ export const CreateSyncDialog = (props: { {userCanReadEnvs && userCanCreateIntegrations ? ( -
{isOpen && renderSyncPanel(props.service)}
+
{isOpen && renderSyncPanel(props.service)}
) : ( vo const { appId, closeModal } = props - const { data: appEnvsData } = useQuery(GetAppEnvironments, { - variables: { - appId, - }, - }) - const { data: credentialsData } = useQuery(GetSavedCredentials, { - variables: { orgId: organisation!.id }, - }) - - const [getGhRepos, { loading }] = useLazyQuery(GetGithubRepos) - const [createGhActionsSync, { data: syncData, loading: creating }] = useMutation(CreateNewGhActionsSync) const [credential, setCredential] = useState(null) - const [repos, setRepos] = useState([]) - const [selectedRepo, setSelectedRepo] = useState(undefined) + const [selectedEnvironment, setSelectedEnvironment] = useState(undefined) const [query, setQuery] = useState('') + const [envQuery, setEnvQuery] = useState('') + const [repos, setRepos] = useState([]) const [phaseEnv, setPhaseEnv] = useState(null) const [path, setPath] = useState('/') const [credentialsValid, setCredentialsValid] = useState(false) + const { data: appEnvsData } = useQuery(GetAppEnvironments, { + variables: { + appId, + }, + }) + const { data: credentialsData } = useQuery(GetSavedCredentials, { + variables: { orgId: organisation!.id }, + }) + + const [getGhRepos] = useLazyQuery(GetGithubRepos) + + const { data: environmentsData } = useQuery(GetGithubEnvironments, { + variables: { + credentialId: credential?.id, + owner: selectedRepo?.owner, + repoName: selectedRepo?.name, + }, + skip: !credential || !selectedRepo, // Only fetch when we have both credential and selected repo + }) + + const environments = environmentsData?.githubEnvironments || [] + useEffect(() => { if (credentialsData && credentialsData.savedCredentials.length > 0) { setCredential(credentialsData.savedCredentials[0]) @@ -95,6 +108,7 @@ export const CreateGhActionsSync = (props: { appId: string; closeModal: () => vo repoName: selectedRepo.name, owner: selectedRepo.owner, credentialId: credential.id, + environmentName: selectedEnvironment || null, }, refetchQueries: [{ query: GetAppSyncStatus, variables: { appId } }], }) @@ -116,7 +130,7 @@ export const CreateGhActionsSync = (props: { appId: string; closeModal: () => vo }) return ( -
+
@@ -192,7 +206,7 @@ export const CreateGhActionsSync = (props: { appId: string; closeModal: () => vo
@@ -274,6 +288,110 @@ export const CreateGhActionsSync = (props: { appId: string; closeModal: () => vo )}
+
+ + {({ open }) => ( + <> +
+ + + +
+ setEnvQuery(e.target.value)} + displayValue={(env?: string) => (env ? env : envQuery)} + aria-disabled={!selectedRepo} + placeholder={ + !selectedRepo + ? 'Select a repository' + : environments.length === 0 + ? 'No environments found' + : 'Select an environment' + } + /> +
+ + + +
+
+
+ {selectedRepo && ( + + +
+ + {({ active, selected }) => ( +
+
+ No environment (repo-level) +
+ {selected && ( + + )} +
+ )} +
+ {environments + .filter((env: string) => + envQuery + ? env.toLowerCase().includes(envQuery.toLowerCase()) + : true + ) + .map((env: string) => ( + + {({ active, selected }) => ( +
+
+ {env} +
+ {selected && ( + + )} +
+ )} +
+ ))} +
+
+
+ )} + + )} +
+
)} @@ -285,7 +403,7 @@ export const CreateGhActionsSync = (props: { appId: string; closeModal: () => vo )}
-
diff --git a/frontend/components/syncing/ServiceInfo.tsx b/frontend/components/syncing/ServiceInfo.tsx index b3f115988..1afe11a62 100644 --- a/frontend/components/syncing/ServiceInfo.tsx +++ b/frontend/components/syncing/ServiceInfo.tsx @@ -20,12 +20,15 @@ export const ServiceInfo = (props: { sync: EnvironmentSyncType }) => { return
{secretName}
} else if (sync.serviceInfo?.id?.includes('github')) { - const repoName = JSON.parse(sync.options)['repo_name'] - const owner = JSON.parse(sync.options)['owner'] + const ghSyncMeta = JSON.parse(sync.options) + const repoName = ghSyncMeta['repo_name'] + const owner = ghSyncMeta['owner'] + const ghEnv = ghSyncMeta['environment_name'] return (
{owner}/{repoName} + {ghEnv && ({ghEnv})}
) } else if (sync.serviceInfo?.id?.includes('hashicorp_vault')) { diff --git a/frontend/graphql/mutations/syncing/github/CreateGhActionsSync.gql b/frontend/graphql/mutations/syncing/github/CreateGhActionsSync.gql index f48e5e85b..ba487e5b3 100644 --- a/frontend/graphql/mutations/syncing/github/CreateGhActionsSync.gql +++ b/frontend/graphql/mutations/syncing/github/CreateGhActionsSync.gql @@ -1,5 +1,5 @@ -mutation CreateNewGhActionsSync($envId: ID!, $path: String!, $repoName: String!, $owner: String!, $credentialId: ID!) { - createGhActionsSync(envId: $envId, path: $path, repoName: $repoName, owner: $owner, credentialId: $credentialId) { +mutation CreateNewGhActionsSync($envId: ID!, $path: String!, $repoName: String!, $owner: String!, $credentialId: ID!, $environmentName: String) { + createGhActionsSync(envId: $envId, path: $path, repoName: $repoName, owner: $owner, credentialId: $credentialId, environmentName: $environmentName) { sync { id environment { diff --git a/frontend/graphql/queries/syncing/github/getEnvironments.gql b/frontend/graphql/queries/syncing/github/getEnvironments.gql new file mode 100644 index 000000000..7a95b7727 --- /dev/null +++ b/frontend/graphql/queries/syncing/github/getEnvironments.gql @@ -0,0 +1,3 @@ +query GetGithubEnvironments($credentialId: ID!, $owner: String!, $repoName: String!) { + githubEnvironments(credentialId: $credentialId, owner: $owner, repoName: $repoName) +}