diff --git a/packages/frontend-2/lib/common/generated/gql/graphql.ts b/packages/frontend-2/lib/common/generated/gql/graphql.ts index 74707d277..7a894a8ea 100644 --- a/packages/frontend-2/lib/common/generated/gql/graphql.ts +++ b/packages/frontend-2/lib/common/generated/gql/graphql.ts @@ -190,6 +190,12 @@ export type AuthStrategy = { url: Scalars['String']; }; +export type AutomateAuthCodePayloadTest = { + action: Scalars['String']; + code: Scalars['String']; + userId: Scalars['String']; +}; + export type AutomateFunction = { __typename?: 'AutomateFunction'; automationCount: Scalars['Int']; @@ -2360,7 +2366,7 @@ export type QueryAutomateFunctionsArgs = { export type QueryAutomateValidateAuthCodeArgs = { - code: Scalars['String']; + payload: AutomateAuthCodePayloadTest; }; diff --git a/packages/server/assets/automate/typedefs/automate.graphql b/packages/server/assets/automate/typedefs/automate.graphql index 7309ffa2c..28273dad2 100644 --- a/packages/server/assets/automate/typedefs/automate.graphql +++ b/packages/server/assets/automate/typedefs/automate.graphql @@ -320,6 +320,12 @@ extend type Project { automation(id: String!): Automation! @hasStreamRole(role: STREAM_OWNER) } +input AutomateAuthCodePayloadTest { + code: String! + userId: String! + action: String! +} + extend type Query { automateFunctions( filter: AutomateFunctionsFilter @@ -334,7 +340,7 @@ extend type Query { """ Part of the automation/function creation handshake mechanism """ - automateValidateAuthCode(code: String!): Boolean! + automateValidateAuthCode(payload: AutomateAuthCodePayloadTest!): Boolean! } extend type Mutation { diff --git a/packages/server/modules/automate/clients/executionEngine.ts b/packages/server/modules/automate/clients/executionEngine.ts index 79d59d9f1..b8be95395 100644 --- a/packages/server/modules/automate/clients/executionEngine.ts +++ b/packages/server/modules/automate/clients/executionEngine.ts @@ -1,27 +1,31 @@ import { automateLogger } from '@/logging/logging' import { ExecutionEngineBadResponseBodyError, - ExecutionEngineErrorResponse, + type ExecutionEngineErrorResponse, ExecutionEngineFailedResponseError, ExecutionEngineNetworkError } from '@/modules/automate/errors/executionEngine' import { AutomateInvalidTriggerError } from '@/modules/automate/errors/management' -import { +import type { FunctionReleaseSchemaType, FunctionSchemaType, FunctionWithVersionsSchemaType } from '@/modules/automate/helpers/executionEngine' import { - AutomationFunctionRunRecord, - BaseTriggerManifest, + type AutomationFunctionRunRecord, + type BaseTriggerManifest, VersionCreationTriggerType, isVersionCreatedTriggerManifest } from '@/modules/automate/helpers/types' +import type { + AuthCodePayload, + AuthCodePayloadWithOrigin +} from '@/modules/automate/services/authCode' import { MisconfiguredEnvironmentError } from '@/modules/shared/errors' import { getServerOrigin, speckleAutomateUrl } from '@/modules/shared/helpers/envHelper' import { - Nullable, - SourceAppName, + type Nullable, + type SourceAppName, isNonNullable, isNullOrUndefined, retry, @@ -129,7 +133,7 @@ const invokeRequest = async (params: { export const createAutomation = async (params: { speckleServerUrl?: string - authCode: string + authCode: AuthCodePayload }) => { const { speckleServerUrl = getServerOrigin(), authCode } = params @@ -141,8 +145,10 @@ export const createAutomation = async (params: { url, method: 'post', body: { - speckleServerOrigin, - speckleServerAuthenticationCode: authCode + speckleServerAuthenticationPayload: { + ...authCode, + origin: speckleServerOrigin + } }, retry: false }) @@ -236,9 +242,7 @@ export enum ExecutionEngineFunctionTemplateId { } export type CreateFunctionBody = { - speckleServerOrigin: string - speckleUserId: string - authenticationCode: string + speckleServerAuthenticationPayload: AuthCodePayloadWithOrigin template: ExecutionEngineFunctionTemplateId functionName: string description: string @@ -276,6 +280,7 @@ export const createFunction = async ({ } export type UpdateFunctionBody = { + //TODO add speckleServerAuthenticationPayload functionName?: string description?: string supportedSourceApps?: SourceAppName[] @@ -423,21 +428,20 @@ export const getUserGithubAuthState = async (params: { export const getUserGithubOrganizations = async (params: { speckleServerUrl?: string - userId: string - authCode: string + authCode: AuthCodePayload }) => { const { speckleServerUrl = getServerOrigin(), - userId: speckleUserId, - authCode: speckleServerAuthenticationCode + authCode: speckleServerAuthenticationPayload } = params const speckleServerOrigin = new URL(speckleServerUrl).origin const url = getApiUrl(`/api/v2/functions/auth/githubapp/organizations`, { query: { - speckleServerOrigin, - speckleUserId, - speckleServerAuthenticationCode + speckleServerAuthenticationPayload: JSON.stringify({ + ...speckleServerAuthenticationPayload, + origin: speckleServerOrigin + }) } }) diff --git a/packages/server/modules/automate/graph/resolvers/automate.ts b/packages/server/modules/automate/graph/resolvers/automate.ts index 5405edf86..38f0eaf38 100644 --- a/packages/server/modules/automate/graph/resolvers/automate.ts +++ b/packages/server/modules/automate/graph/resolvers/automate.ts @@ -36,6 +36,7 @@ import { updateAutomation } from '@/modules/automate/services/automationManagement' import { + AuthCodePayloadAction, createStoredAuthCode, validateStoredAuthCode } from '@/modules/automate/services/authCode' @@ -440,11 +441,8 @@ export = (FF_AUTOMATE_MODULE_ENABLED }, ProjectAutomationMutations: { async create(parent, { input }, ctx) { - const testAutomateAuthCode = process.env['TEST_AUTOMATE_AUTHENTICATION_CODE'] const create = createAutomation({ - createAuthCode: testAutomateAuthCode - ? async () => testAutomateAuthCode - : createStoredAuthCode({ redis: getGenericRedis() }), + createAuthCode: createStoredAuthCode({ redis: getGenericRedis() }), automateCreateAutomation: clientCreateAutomation, storeAutomation, storeAutomationToken @@ -545,11 +543,14 @@ export = (FF_AUTOMATE_MODULE_ENABLED } }, Query: { - async automateValidateAuthCode(_parent, { code }) { + async automateValidateAuthCode(_parent, args) { const validate = validateStoredAuthCode({ redis: getGenericRedis() }) - return await validate(code) + return await validate({ + ...args.payload, + action: args.payload.action as AuthCodePayloadAction + }) }, async automateFunction(_parent, { id }, ctx) { const fn = await ctx.loaders.automationsApi.getFunction.load(id) @@ -615,14 +616,16 @@ export = (FF_AUTOMATE_MODULE_ENABLED return hasAutomateGithubApp }, availableGithubOrgs: async (parent, _args, ctx) => { - const authCode = await createStoredAuthCode({ redis: getGenericRedis() })() const userId = parent.userId + const authCode = await createStoredAuthCode({ redis: getGenericRedis() })({ + userId, + action: AuthCodePayloadAction.GetAvailableGithubOrganizations + }) let orgs: string[] = [] try { orgs = ( await getUserGithubOrganizations({ - userId, authCode }) ).availableGitHubOrganisations diff --git a/packages/server/modules/automate/services/authCode.ts b/packages/server/modules/automate/services/authCode.ts index 94fddf783..8e8fbe5d3 100644 --- a/packages/server/modules/automate/services/authCode.ts +++ b/packages/server/modules/automate/services/authCode.ts @@ -1,25 +1,70 @@ +import { automateLogger } from '@/logging/logging' import { AutomateAuthCodeHandshakeError } from '@/modules/automate/errors/management' import cryptoRandomString from 'crypto-random-string' import Redis from 'ioredis' +import { get, has, isObjectLike } from 'lodash' -export const createStoredAuthCode = (deps: { redis: Redis }) => async () => { - const { redis } = deps - const codeId = cryptoRandomString({ length: 10 }) - const authCode = cryptoRandomString({ length: 20 }) - // prob hashing and salting it would be better, but they expire in 5 mins... - await redis.set(codeId, authCode, 'EX', 60 * 5) - return `${codeId}${authCode}` +export enum AuthCodePayloadAction { + CreateAutomation = 'createAutomation', + CreateFunction = 'createFunction', + BecomeFunctionAuthor = 'becomeFunctionAuthor', + GetAvailableGithubOrganizations = 'getAvailableGithubOrganizations' } -export const validateStoredAuthCode = - (deps: { redis: Redis }) => async (code: string) => { - const { redis } = deps - const codeId = code.slice(0, 10) - const authCode = code.slice(10) - const storedAuthCode = await redis.get(codeId) +export type AuthCodePayload = { + code: string + userId: string + action: AuthCodePayloadAction +} - if (!storedAuthCode || authCode !== storedAuthCode) { - throw new AutomateAuthCodeHandshakeError('Invalid automate auth code') +export type AuthCodePayloadWithOrigin = AuthCodePayload & { origin: string } + +const isPayload = (payload: unknown): payload is AuthCodePayload => + !!( + payload && + isObjectLike(payload) && + has(payload, 'code') && + has(payload, 'userId') && + has(payload, 'action') && + Object.values(AuthCodePayloadAction).includes(get(payload, 'action')) + ) + +export const createStoredAuthCode = + (deps: { redis: Redis }) => async (params: Omit) => { + const { redis } = deps + + const payload: AuthCodePayload = { + ...params, + code: cryptoRandomString({ length: 20 }) + } + + await redis.set(payload.code, JSON.stringify(payload), 'EX', 60 * 5) + return payload + } + +export const validateStoredAuthCode = + (deps: { redis: Redis }) => async (payload: AuthCodePayload) => { + const { redis } = deps + + const potentialPayloadString = await redis.get(payload.code) + const potentialPayload: unknown = potentialPayloadString + ? JSON.parse(potentialPayloadString) + : null + const formattedPayload = isPayload(potentialPayload) ? potentialPayload : null + + if ( + !formattedPayload || + formattedPayload.code !== formattedPayload.code || + formattedPayload.userId !== formattedPayload.userId || + formattedPayload.action !== formattedPayload.action + ) { + throw new AutomateAuthCodeHandshakeError('Invalid automate auth payload') + } + + try { + await redis.del(payload.code) + } catch (e) { + automateLogger.error(e, 'Auth code deletion unexpectedly failed') } return true diff --git a/packages/server/modules/automate/services/automationManagement.ts b/packages/server/modules/automate/services/automationManagement.ts index a2277d3f0..ba177db1c 100644 --- a/packages/server/modules/automate/services/automationManagement.ts +++ b/packages/server/modules/automate/services/automationManagement.ts @@ -19,7 +19,10 @@ import { } from '@/modules/automate/clients/executionEngine' import { validateStreamAccess } from '@/modules/core/services/streams/streamAccessService' import { Automate, Roles, removeNullOrUndefinedKeys } from '@speckle/shared' -import { createStoredAuthCode } from '@/modules/automate/services/authCode' +import { + AuthCodePayloadAction, + createStoredAuthCode +} from '@/modules/automate/services/authCode' import { ProjectAutomationCreateInput, ProjectAutomationRevisionCreateInput, @@ -89,7 +92,10 @@ export const createAutomation = userResourceAccessRules ) - const authCode = await createAuthCode() + const authCode = await createAuthCode({ + userId, + action: AuthCodePayloadAction.CreateAutomation + }) // trigger automation creation on automate const { automationId: executionEngineAutomationId, token } = diff --git a/packages/server/modules/automate/services/functionManagement.ts b/packages/server/modules/automate/services/functionManagement.ts index 5f0e937b8..44004d9ff 100644 --- a/packages/server/modules/automate/services/functionManagement.ts +++ b/packages/server/modules/automate/services/functionManagement.ts @@ -34,7 +34,10 @@ import { } from '@/modules/automate/helpers/executionEngine' import { Request, Response } from 'express' import { UnauthorizedError } from '@/modules/shared/errors' -import { createStoredAuthCode } from '@/modules/automate/services/authCode' +import { + AuthCodePayloadAction, + createStoredAuthCode +} from '@/modules/automate/services/authCode' import { getServerOrigin, speckleAutomateUrl } from '@/modules/shared/helpers/envHelper' import { getFunctionsMarketplaceUrl } from '@/modules/core/helpers/routeHelper' @@ -124,12 +127,16 @@ export const createFunctionFromTemplate = throw new AutomateFunctionCreationError('Speckle user not found') } - const authCode = await createStoredAuthCode() + const authCode = await createStoredAuthCode({ + userId: user.id, + action: AuthCodePayloadAction.CreateFunction + }) const body: CreateFunctionBody = { ...input, - speckleServerOrigin: new URL(getServerOrigin()).origin, - speckleUserId: user.id, - authenticationCode: authCode, + speckleServerAuthenticationPayload: { + ...authCode, + origin: new URL(getServerOrigin()).origin + }, functionName: input.name, template: mapGqlTemplateIdToExecEngineTemplateId(input.template), supportedSourceApps: input.supportedSourceApps as SourceAppName[], @@ -219,17 +226,18 @@ export const startAutomateFunctionCreatorAuth = throw new UnauthorizedError() } - const authCode = await createStoredAuthCode() + const authCode = await createStoredAuthCode({ + userId, + action: AuthCodePayloadAction.BecomeFunctionAuthor + }) const redirectUrl = new URL( '/api/v2/functions/auth/githubapp/authorize', speckleAutomateUrl() ) - redirectUrl.searchParams.set('speckleUserId', userId) redirectUrl.searchParams.set( - 'speckleServerOrigin', - new URL(getServerOrigin()).origin + 'speckleServerAuthenticationPayload', + JSON.stringify({ ...authCode, origin: new URL(getServerOrigin()).origin }) ) - redirectUrl.searchParams.set('speckleServerAuthenticationCode', authCode) return res.redirect(redirectUrl.toString()) } diff --git a/packages/server/modules/automate/tests/automations.spec.ts b/packages/server/modules/automate/tests/automations.spec.ts index 14b60846b..6b5db9bc0 100644 --- a/packages/server/modules/automate/tests/automations.spec.ts +++ b/packages/server/modules/automate/tests/automations.spec.ts @@ -7,7 +7,10 @@ import { updateAutomation as updateDbAutomation } from '@/modules/automate/repositories/automations' import { updateAutomation } from '@/modules/automate/services/automationManagement' -import { createStoredAuthCode } from '@/modules/automate/services/authCode' +import { + AuthCodePayloadAction, + createStoredAuthCode +} from '@/modules/automate/services/authCode' import { getGenericRedis } from '@/modules/core' import { ProjectAutomationRevisionCreateInput } from '@/modules/core/graph/generated/graphql' import { BranchRecord } from '@/modules/core/helpers/types' @@ -482,10 +485,14 @@ const buildAutomationUpdate = () => { it('fails if code is invalid', async () => { const res = await apollo.execute(AutomateValidateAuthCodeDocument, { - code: 'invalid' + payload: { + code: 'invalid', + userId: 'a', + action: 'aty' + } }) - expect(res).to.haveGraphQLErrors('Invalid automate auth code') + expect(res).to.haveGraphQLErrors('Invalid automate auth payload') expect(res.data?.automateValidateAuthCode).to.not.be.ok }) @@ -493,10 +500,13 @@ const buildAutomationUpdate = () => { const storeCode = createStoredAuthCode({ redis: getGenericRedis() }) - const code = await storeCode() + const code = await storeCode({ + userId: me.id, + action: AuthCodePayloadAction.BecomeFunctionAuthor + }) const res = await apollo.execute(AutomateValidateAuthCodeDocument, { - code + payload: code }) expect(res).to.not.haveGraphQLErrors() diff --git a/packages/server/modules/core/graph/generated/graphql.ts b/packages/server/modules/core/graph/generated/graphql.ts index 214a3b3f4..8264f1b39 100644 --- a/packages/server/modules/core/graph/generated/graphql.ts +++ b/packages/server/modules/core/graph/generated/graphql.ts @@ -199,6 +199,12 @@ export type AuthStrategy = { url: Scalars['String']; }; +export type AutomateAuthCodePayloadTest = { + action: Scalars['String']; + code: Scalars['String']; + userId: Scalars['String']; +}; + export type AutomateFunction = { __typename?: 'AutomateFunction'; automationCount: Scalars['Int']; @@ -2374,7 +2380,7 @@ export type QueryAutomateFunctionsArgs = { export type QueryAutomateValidateAuthCodeArgs = { - code: Scalars['String']; + payload: AutomateAuthCodePayloadTest; }; @@ -3604,6 +3610,7 @@ export type ResolversTypes = { AppTokenCreateInput: AppTokenCreateInput; AppUpdateInput: AppUpdateInput; AuthStrategy: ResolverTypeWrapper; + AutomateAuthCodePayloadTest: AutomateAuthCodePayloadTest; AutomateFunction: ResolverTypeWrapper; AutomateFunctionCollection: ResolverTypeWrapper & { items: Array }>; AutomateFunctionRelease: ResolverTypeWrapper; @@ -3830,6 +3837,7 @@ export type ResolversParentTypes = { AppTokenCreateInput: AppTokenCreateInput; AppUpdateInput: AppUpdateInput; AuthStrategy: AuthStrategy; + AutomateAuthCodePayloadTest: AutomateAuthCodePayloadTest; AutomateFunction: AutomateFunctionGraphQLReturn; AutomateFunctionCollection: Omit & { items: Array }; AutomateFunctionRelease: AutomateFunctionReleaseGraphQLReturn; @@ -4889,7 +4897,7 @@ export type QueryResolvers, ParentType, ContextType>; automateFunction?: Resolver>; automateFunctions?: Resolver>; - automateValidateAuthCode?: Resolver>; + automateValidateAuthCode?: Resolver>; comment?: Resolver, ParentType, ContextType, RequireFields>; comments?: Resolver, ParentType, ContextType, RequireFields>; discoverableStreams?: Resolver, ParentType, ContextType, RequireFields>; diff --git a/packages/server/modules/cross-server-sync/graph/generated/graphql.ts b/packages/server/modules/cross-server-sync/graph/generated/graphql.ts index f9f52788e..08611cc27 100644 --- a/packages/server/modules/cross-server-sync/graph/generated/graphql.ts +++ b/packages/server/modules/cross-server-sync/graph/generated/graphql.ts @@ -188,6 +188,12 @@ export type AuthStrategy = { url: Scalars['String']; }; +export type AutomateAuthCodePayloadTest = { + action: Scalars['String']; + code: Scalars['String']; + userId: Scalars['String']; +}; + export type AutomateFunction = { __typename?: 'AutomateFunction'; automationCount: Scalars['Int']; @@ -2363,7 +2369,7 @@ export type QueryAutomateFunctionsArgs = { export type QueryAutomateValidateAuthCodeArgs = { - code: Scalars['String']; + payload: AutomateAuthCodePayloadTest; }; diff --git a/packages/server/test/graphql/automate.ts b/packages/server/test/graphql/automate.ts index f8097bd71..7ff0d65ee 100644 --- a/packages/server/test/graphql/automate.ts +++ b/packages/server/test/graphql/automate.ts @@ -122,7 +122,7 @@ export const getAutomateFunctionsQuery = gql` ` export const automateValidateAuthCodeQuery = gql` - query AutomateValidateAuthCode($code: String!) { - automateValidateAuthCode(code: $code) + query AutomateValidateAuthCode($payload: AutomateAuthCodePayloadTest!) { + automateValidateAuthCode(payload: $payload) } ` diff --git a/packages/server/test/graphql/generated/graphql.ts b/packages/server/test/graphql/generated/graphql.ts index c7747d9ea..82ae6ada9 100644 --- a/packages/server/test/graphql/generated/graphql.ts +++ b/packages/server/test/graphql/generated/graphql.ts @@ -189,6 +189,12 @@ export type AuthStrategy = { url: Scalars['String']; }; +export type AutomateAuthCodePayloadTest = { + action: Scalars['String']; + code: Scalars['String']; + userId: Scalars['String']; +}; + export type AutomateFunction = { __typename?: 'AutomateFunction'; automationCount: Scalars['Int']; @@ -2364,7 +2370,7 @@ export type QueryAutomateFunctionsArgs = { export type QueryAutomateValidateAuthCodeArgs = { - code: Scalars['String']; + payload: AutomateAuthCodePayloadTest; }; @@ -3596,7 +3602,7 @@ export type GetAutomateFunctionsQueryVariables = Exact<{ export type GetAutomateFunctionsQuery = { __typename?: 'Query', automateFunctions: { __typename?: 'AutomateFunctionCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'AutomateFunction', id: string, name: string, isFeatured: boolean, description: string, logo?: string | null, automationCount: number, supportedSourceApps: Array, tags: Array, repo: { __typename?: 'BasicGitRepositoryMetadata', id: string, owner: string, name: string }, releases: { __typename?: 'AutomateFunctionReleaseCollection', totalCount: number, items: Array<{ __typename?: 'AutomateFunctionRelease', id: string, versionTag: string, createdAt: string, inputSchema?: Record | null, commitId: string }> } }> } }; export type AutomateValidateAuthCodeQueryVariables = Exact<{ - code: Scalars['String']; + payload: AutomateAuthCodePayloadTest; }>; @@ -3891,7 +3897,7 @@ export const TokenAppInfoDocument = {"kind":"Document","definitions":[{"kind":"O export const AppTokenCreateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AppTokenCreate"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"token"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AppTokenCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"appTokenCreate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"token"},"value":{"kind":"Variable","name":{"kind":"Name","value":"token"}}}]}]}}]} as unknown as DocumentNode; export const GetProjectAutomationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProjectAutomation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"automationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"automation"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"automationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestAutomation"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestAutomation"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Automation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"runs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"trigger"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"VersionCreatedTrigger"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"version"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"model"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"functionRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"statusMessage"}},{"kind":"Field","name":{"kind":"Name","value":"contextView"}},{"kind":"Field","name":{"kind":"Name","value":"function"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"elapsed"}},{"kind":"Field","name":{"kind":"Name","value":"results"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"currentRevision"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"triggerDefinitions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"VersionCreatedTriggerDefinition"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"model"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"functions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"parameters"}},{"kind":"Field","name":{"kind":"Name","value":"release"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"function"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"versionTag"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"inputSchema"}},{"kind":"Field","name":{"kind":"Name","value":"commitId"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const GetAutomateFunctionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAutomateFunctions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateFunctionsFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"automateFunctions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"cursor"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestAutomateFunction"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestAutomateFunction"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateFunction"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"repo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"owner"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}},{"kind":"Field","name":{"kind":"Name","value":"releases"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"versionTag"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"inputSchema"}},{"kind":"Field","name":{"kind":"Name","value":"commitId"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"automationCount"}},{"kind":"Field","name":{"kind":"Name","value":"supportedSourceApps"}},{"kind":"Field","name":{"kind":"Name","value":"tags"}}]}}]} as unknown as DocumentNode; -export const AutomateValidateAuthCodeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AutomateValidateAuthCode"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"code"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"automateValidateAuthCode"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"code"},"value":{"kind":"Variable","name":{"kind":"Name","value":"code"}}}]}]}}]} as unknown as DocumentNode; +export const AutomateValidateAuthCodeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AutomateValidateAuthCode"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"payload"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateAuthCodePayloadTest"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"automateValidateAuthCode"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"payload"},"value":{"kind":"Variable","name":{"kind":"Name","value":"payload"}}}]}]}}]} as unknown as DocumentNode; export const CreateCommentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateComment"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CommentCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"commentCreate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const CreateReplyDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateReply"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ReplyCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"commentReply"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const GetCommentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetComment"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"streamId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"comment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"streamId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"streamId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentWithReplies"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentWithReplies"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Comment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"rawText"}},{"kind":"Field","name":{"kind":"Name","value":"text"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"doc"}},{"kind":"Field","name":{"kind":"Name","value":"attachments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fileName"}},{"kind":"Field","name":{"kind":"Name","value":"streamId"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"replies"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"10"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"text"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"doc"}},{"kind":"Field","name":{"kind":"Name","value":"attachments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fileName"}},{"kind":"Field","name":{"kind":"Name","value":"streamId"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode;