Skip to content

Commit 0fd4d96

Browse files
authored
feat(deployment): use organization access tokens (#6613)
1 parent edeaadc commit 0fd4d96

File tree

10 files changed

+101
-80
lines changed

10 files changed

+101
-80
lines changed

.changeset/sixty-chicken-swim.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'hive': major
3+
---
4+
5+
Restructure the environment variables used for the Hive Cloud hosting. While this is techincally a breaking change it will not really affect people self-hosting Hive.
6+
7+
**Breaking**: Remove unused environment variable options `HIVE_REPORTING`, `HIVE_REPORTING_ENDPOINT` and `HIVE_USAGE_DATA_RETENTION_PURGE_INTERVAL_MINUTES` from the `server` service.
8+
9+
These environment variables are obsolete since the Hive GraphQL schema is reported via the Hive CLI instead.
10+
11+
**Breaking**: Replace the environment variable option `HIVE` with `HIVE_USAGE`, rename environment variable option `HIVE_API_TOKEN` to `HIVE_USAGE_ACCESS_TOKEN` for the `server` service. Require providing the `HIVE_USAGE_ACCESS_TOKEN` environment variable if `HIVE_USAGE` is set to `1`.

deployment/index.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { optimizeAzureCluster } from './utils/azure-helpers';
3333
import { isDefined } from './utils/helpers';
3434
import { publishAppDeployment } from './utils/publish-app-deployment';
3535
import { publishGraphQLSchema } from './utils/publish-graphql-schema';
36+
import { ServiceSecret } from './utils/secrets';
3637

3738
// eslint-disable-next-line no-process-env
3839
const imagesTag = process.env.DOCKER_IMAGE_TAG as string;
@@ -229,14 +230,17 @@ const graphql = deployGraphQL({
229230
observability,
230231
});
231232

232-
const apiConfig = new pulumi.Config('api');
233-
const apiEnv = apiConfig.requireObject<Record<string, string>>('env');
233+
const hiveConfig = new pulumi.Config('hive');
234+
const hiveConfigSecret = new ServiceSecret('hive-config-secret', {
235+
usageAccessToken: hiveConfig.requireSecret('cliAccessToken'),
236+
});
234237

235238
const publishGraphQLSchemaCommand = publishGraphQLSchema({
236239
graphql,
237240
registry: {
238241
endpoint: `https://${environment.appDns}/registry`,
239-
accessToken: apiEnv.HIVE_API_TOKEN,
242+
accessToken: hiveConfigSecret.raw.usageAccessToken,
243+
target: hiveConfig.require('target'),
240244
},
241245
version: {
242246
commit: imagesTag,
@@ -251,7 +255,8 @@ if (hiveAppPersistedDocumentsAbsolutePath) {
251255
appName: 'hive-app',
252256
registry: {
253257
endpoint: `https://${environment.appDns}/registry`,
254-
accessToken: apiEnv.HIVE_API_TOKEN,
258+
accessToken: hiveConfigSecret.raw.usageAccessToken,
259+
target: hiveConfig.require('target'),
255260
},
256261
version: {
257262
commit: imagesTag,

deployment/services/graphql.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ export function deployGraphQL({
8282
const apiConfig = new pulumi.Config('api');
8383
const apiEnv = apiConfig.requireObject<Record<string, string>>('env');
8484

85+
const hiveConfig = new pulumi.Config('hive');
86+
8587
const oauthConfig = new pulumi.Config('oauth');
8688
const githubOAuthSecret = new AppOAuthSecret('oauth-github', {
8789
clientId: oauthConfig.requireSecret('githubClient'),
@@ -95,6 +97,9 @@ export function deployGraphQL({
9597
const persistedDocumentsSecret = new ServiceSecret('persisted-documents', {
9698
cdnAccessKeyId: apiConfig.requireSecret('hivePersistedDocumentsCdnAccessKeyId'),
9799
});
100+
const hiveUsageSecret = new ServiceSecret('hive-usage', {
101+
usageAccessToken: hiveConfig.requireSecret('usageAccessToken'),
102+
});
98103

99104
return (
100105
new ServiceDeployment(
@@ -124,15 +129,13 @@ export function deployGraphQL({
124129
WEBHOOKS_ENDPOINT: serviceLocalEndpoint(webhooks.service),
125130
SCHEMA_ENDPOINT: serviceLocalEndpoint(schema.service),
126131
SCHEMA_POLICY_ENDPOINT: serviceLocalEndpoint(schemaPolicy.service),
127-
HIVE_USAGE_ENDPOINT: serviceLocalEndpoint(usage.service),
128132
EMAILS_ENDPOINT: serviceLocalEndpoint(emails.service),
129133
WEB_APP_URL: `https://${environment.appDns}`,
130134
GRAPHQL_PUBLIC_ORIGIN: `https://${environment.appDns}`,
131135
CDN_CF: '1',
132-
HIVE: '1',
133-
HIVE_REPORTING: '1',
134136
HIVE_USAGE: '1',
135-
HIVE_REPORTING_ENDPOINT: 'http://0.0.0.0:4000/graphql',
137+
HIVE_USAGE_TARGET: hiveConfig.require('target'),
138+
HIVE_USAGE_ENDPOINT: serviceLocalEndpoint(usage.service),
136139
HIVE_PERSISTED_DOCUMENTS: '1',
137140
ZENDESK_SUPPORT: zendesk.enabled ? '1' : '0',
138141
INTEGRATION_GITHUB: '1',
@@ -206,6 +209,8 @@ export function deployGraphQL({
206209
.withSecret('AUTH_GITHUB_CLIENT_SECRET', githubOAuthSecret, 'clientSecret')
207210
.withSecret('AUTH_GOOGLE_CLIENT_ID', googleOAuthSecret, 'clientId')
208211
.withSecret('AUTH_GOOGLE_CLIENT_SECRET', googleOAuthSecret, 'clientSecret')
212+
// Hive Usage Reporting
213+
.withSecret('HIVE_USAGE_ACCESS_TOKEN', hiveUsageSecret, 'usageAccessToken')
209214
// Persisted Documents
210215
.withSecret(
211216
'HIVE_PERSISTED_DOCUMENTS_CDN_ACCESS_KEY_ID',

deployment/utils/publish-app-deployment.ts

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import { local } from '@pulumi/command';
22
import { Secret } from '@pulumi/kubernetes/core/v1';
33
import { Resource } from '@pulumi/pulumi';
4+
import * as pulumi from '@pulumi/pulumi';
45
import { ClickhouseConnectionSecret } from '../services/clickhouse';
56
import { ServiceDeployment } from './service-deployment';
67

7-
const dockerImage = 'ghcr.io/graphql-hive/cli:0.44.4';
8+
const dockerImage = 'ghcr.io/graphql-hive/cli:0.49.0';
89

910
/** Publish API GraphQL schema to Hive schema registry. */
1011
export function publishAppDeployment(args: {
1112
appName: string;
12-
registry: { accessToken: string; endpoint: string };
13+
registry: { accessToken: pulumi.Output<string>; endpoint: string; target: string };
1314
version: {
1415
commit: string;
1516
};
@@ -49,13 +50,15 @@ export function publishAppDeployment(args: {
4950
const createCommand = new local.Command(
5051
`create-app-deployment-${args.appName}`,
5152
{
52-
create:
53-
`docker run --name "create-app-deployment-${args.appName}"` +
54-
` --rm -v ${args.persistedDocumentsPath}:/usr/src/app/persisted-documents.json` +
55-
` ${dockerImage}` +
56-
` app:create` +
57-
` --registry.endpoint ${args.registry.endpoint} --registry.accessToken ${args.registry.accessToken}` +
58-
` --name ${args.appName} --version ${args.version.commit} ./persisted-documents.json`,
53+
create: args.registry.accessToken.apply(
54+
accessToken =>
55+
`docker run --name "create-app-deployment-${args.appName}"` +
56+
` --rm -v ${args.persistedDocumentsPath}:/usr/src/app/persisted-documents.json` +
57+
` ${dockerImage}` +
58+
` app:create` +
59+
` --registry.endpoint ${args.registry.endpoint} --registry.accessToken ${accessToken} --target ${args.registry.target}` +
60+
` --name ${args.appName} --version ${args.version.commit} ./persisted-documents.json`,
61+
),
5962
},
6063
{
6164
dependsOn: [wakeupCommandJob, ...(args.dependsOn || [])].filter(v => v !== null),
@@ -66,12 +69,14 @@ export function publishAppDeployment(args: {
6669
return new local.Command(
6770
`publish-app-deployment-${args.appName}`,
6871
{
69-
create:
70-
`docker run --rm --name "publish-app-deployment-${args.appName}"` +
71-
` ${dockerImage}` +
72-
` app:publish` +
73-
` --registry.endpoint ${args.registry.endpoint} --registry.accessToken ${args.registry.accessToken}` +
74-
` --name ${args.appName} --version ${args.version.commit}`,
72+
create: args.registry.accessToken.apply(
73+
accessToken =>
74+
`docker run --rm --name "publish-app-deployment-${args.appName}"` +
75+
` ${dockerImage}` +
76+
` app:publish` +
77+
` --registry.endpoint ${args.registry.endpoint} --registry.accessToken ${accessToken} --target ${args.registry.target}` +
78+
` --name ${args.appName} --version ${args.version.commit}`,
79+
),
7580
},
7681
{
7782
dependsOn: createCommand,

deployment/utils/publish-graphql-schema.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
11
import { local } from '@pulumi/command';
2+
import * as pulumi from '@pulumi/pulumi';
23
import type { GraphQL } from '../services/graphql';
34

4-
const dockerImage = 'ghcr.io/graphql-hive/cli:0.44.4';
5+
const dockerImage = 'ghcr.io/graphql-hive/cli:0.49.0';
56

67
/** Publish API GraphQL schema to Hive schema registry. */
78
export function publishGraphQLSchema(args: {
89
graphql: GraphQL;
9-
registry: { accessToken: string; endpoint: string };
10+
registry: { accessToken: pulumi.Output<string>; endpoint: string; target: string };
1011
version: {
1112
commit: string;
1213
};
1314
schemaPath: string;
1415
}) {
15-
const command =
16+
const command = (accessToken: string) =>
1617
`schema:publish` +
17-
` --registry.endpoint ${args.registry.endpoint} --registry.accessToken ${args.registry.accessToken}` +
18+
` --registry.endpoint ${args.registry.endpoint} --registry.accessToken ${accessToken} --target ${args.registry.target}` +
1819
` --commit ${args.version.commit} --author "Hive CD" ./schema.graphqls`;
1920

2021
return new local.Command(
2122
'publish-graphql-schema',
2223
{
23-
create:
24-
`docker run --name "publish-graphql-schema" -v ${args.schemaPath}:/usr/src/app/schema.graphqls ${dockerImage} ` +
25-
command,
24+
create: args.registry.accessToken.apply(
25+
accessToken =>
26+
`docker run --name "publish-graphql-schema" -v ${args.schemaPath}:/usr/src/app/schema.graphqls ${dockerImage} ` +
27+
command(accessToken),
28+
),
2629
},
2730
{
2831
dependsOn: [args.graphql.deployment, args.graphql.service],

deployment/utils/service-deployment.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export class ServiceDeployment {
6262
};
6363
};
6464
availabilityOnEveryNode?: boolean;
65-
command?: string[];
65+
command?: pulumi.Input<pulumi.Input<string>[]>;
6666
},
6767
protected dependencies?: Array<pulumi.Resource | undefined | null>,
6868
protected parent?: pulumi.Resource | null,

packages/services/server/README.md

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ The GraphQL API for GraphQL Hive.
2929
| `CLICKHOUSE_REQUEST_TIMEOUT` | No | Force a request timeout value for ClickHouse operations (in ms) | `30000` |
3030
| `REDIS_HOST` | **Yes** | The host of your redis instance. | `"127.0.0.1"` |
3131
| `REDIS_PORT` | **Yes** | The port of your redis instance. | `6379` |
32-
| `REDIS_PASSWORD` | **Yes** | The password of your redis instance. | `"apollorocks"` |
32+
| `REDIS_PASSWORD` | **Yes** | The password of your redis instance. | `"password"` |
3333
| `REDIS_TLS_ENABLED` | **No** | Enable TLS for redis connection (rediss://). | `"0"` |
3434
| `S3_ENDPOINT` | **Yes** | The S3 endpoint. | `http://localhost:9000` |
3535
| `S3_ACCESS_KEY_ID` | **Yes** | The S3 access key id. | `minioadmin` |
@@ -89,14 +89,12 @@ The GraphQL API for GraphQL Hive.
8989
If you are self-hosting GraphQL Hive, you can ignore this section. It is only required for the Cloud
9090
version.
9191

92-
| Name | Required | Description | Example Value |
93-
| ------------------------- | ----------------------------- | -------------------------------------- | ------------------------------- |
94-
| `COMMERCE_ENDPOINT` | **Yes** | The endpoint of the commerce service. | `http://127.0.0.1:4012` |
95-
| `CDN_CF` | No | Whether the CDN is enabled. | `1` (enabled) or `0` (disabled) |
96-
| `CDN_CF_BASE_URL` | No (**Yes** if `CDN` is `1`) | The base URL of the cdn. | `https://cdn.graphql-hive.com` |
97-
| `HIVE` | No | The internal endpoint key. | `iliketurtles` |
98-
| `HIVE_API_TOKEN` | No (**Yes** if `HIVE` is set) | The internal endpoint key. | `iliketurtles` |
99-
| `HIVE_USAGE` | No | The internal endpoint key. | `1` (enabled) or `0` (disabled) |
100-
| `HIVE_USAGE_ENDPOINT` | No | The endpoint used for usage reporting. | `http://127.0.0.1:4001` |
101-
| `HIVE_REPORTING` | No | The internal endpoint key. | `iliketurtles` |
102-
| `HIVE_REPORTING_ENDPOINT` | No | The internal endpoint key. | `http://127.0.0.1:4000/graphql` |
92+
| Name | Required | Description | Example Value |
93+
| ------------------------- | ------------------------------------ | -------------------------------------------------------------- | --------------------------------------------------- |
94+
| `COMMERCE_ENDPOINT` | **Yes** | The endpoint of the commerce service. | `http://127.0.0.1:4012` |
95+
| `CDN_CF` | No | Whether the CDN is enabled. | `1` (enabled) or `0` (disabled) |
96+
| `CDN_CF_BASE_URL` | No (**Yes** if `CDN` is `1`) | The base URL of the cdn. | `https://cdn.graphql-hive.com` |
97+
| `HIVE_USAGE` | No | Whether usage reporting for the GraphQL API to Hive is enabled | `1` (enabled) or `0` (disabled) |
98+
| `HIVE_USAGE_TARGET` | No (**Yes** if `HIVE` is set to `1`) | The target to which the usage data should be reported | `the-guild/graphql-hive/development` |
99+
| `HIVE_USAGE_ACCESS_TOKEN` | No (**Yes** if `HIVE` is set to `1`) | The internal endpoint key. | `iliketurtles` |
100+
| `HIVE_USAGE_ENDPOINT` | No | The endpoint used for usage reporting. | `http://app.graphql-hive.com/usage` (default value) |

packages/services/server/src/environment.ts

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,12 @@ const CdnApiModel = zod.union([
132132
]);
133133

134134
const HiveModel = zod.union([
135-
zod.object({ HIVE: emptyString(zod.literal('0').optional()) }),
135+
zod.object({ HIVE_USAGE: emptyString(zod.literal('0').optional()) }),
136136
zod.object({
137-
HIVE: zod.literal('1'),
138-
HIVE_API_TOKEN: zod.string(),
139-
HIVE_USAGE: zod.union([zod.literal('0'), zod.literal('1')]).optional(),
137+
HIVE_USAGE: zod.literal('1'),
140138
HIVE_USAGE_ENDPOINT: zod.string().url().optional(),
141-
HIVE_USAGE_DATA_RETENTION_PURGE_INTERVAL_MINUTES: emptyString(NumberFromString.optional()),
142-
HIVE_REPORTING: zod.union([zod.literal('0'), zod.literal('1')]).optional(),
143-
HIVE_REPORTING_ENDPOINT: zod.string().url().optional(),
139+
HIVE_USAGE_TARGET: zod.string(),
140+
HIVE_USAGE_ACCESS_TOKEN: zod.string(),
144141
}),
145142
]);
146143

@@ -330,18 +327,12 @@ const zendeskSupport = extractConfig(configs.zendeskSupport);
330327
const tracing = extractConfig(configs.tracing);
331328
const hivePersistedDocuments = extractConfig(configs.hivePersistedDocuments);
332329

333-
const hiveConfig =
334-
hive.HIVE === '1'
330+
const hiveUsageConfig =
331+
hive.HIVE_USAGE === '1'
335332
? {
336-
token: hive.HIVE_API_TOKEN,
337-
reporting:
338-
hive.HIVE_REPORTING === '1' ? { endpoint: hive.HIVE_REPORTING_ENDPOINT ?? null } : null,
339-
usage:
340-
hive.HIVE_USAGE === '1'
341-
? {
342-
endpoint: hive.HIVE_USAGE_ENDPOINT ?? null,
343-
}
344-
: null,
333+
target: hive.HIVE_USAGE_TARGET,
334+
token: hive.HIVE_USAGE_ACCESS_TOKEN,
335+
endpoint: hive.HIVE_USAGE_ENDPOINT ?? null,
345336
}
346337
: null;
347338

@@ -353,7 +344,7 @@ const hivePersistedDocumentsConfig =
353344
}
354345
: null;
355346

356-
export type HiveConfig = typeof hiveConfig;
347+
export type HiveUsageConfig = typeof hiveUsageConfig;
357348
export type HivePersistedDocumentsConfig = typeof hivePersistedDocumentsConfig;
358349

359350
export const env = {
@@ -511,7 +502,7 @@ export const env = {
511502
port: prometheus.PROMETHEUS_METRICS_PORT ?? 10_254,
512503
}
513504
: null,
514-
hive: hiveConfig,
505+
hive: hiveUsageConfig,
515506
hivePersistedDocuments: hivePersistedDocumentsConfig,
516507
graphql: {
517508
origin: base.GRAPHQL_PUBLIC_ORIGIN,

packages/services/server/src/graphql-handler.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { cleanRequestId, type TracingInstance } from '@hive/service-common';
2929
import { runWithAsyncContext } from '@sentry/node';
3030
import { AuthN, Session } from '../../api/src/modules/auth/lib/authz';
3131
import { asyncStorage } from './async-storage';
32-
import type { HiveConfig, HivePersistedDocumentsConfig } from './environment';
32+
import type { HivePersistedDocumentsConfig, HiveUsageConfig } from './environment';
3333
import { useArmor } from './use-armor';
3434
import { extractUserId, useSentryUser } from './use-sentry-user';
3535

@@ -49,7 +49,7 @@ export interface GraphQLHandlerOptions {
4949
apiKey: string;
5050
};
5151
isProduction: boolean;
52-
hiveConfig: HiveConfig;
52+
hiveUsageConfig: HiveUsageConfig;
5353
hivePersistedDocumentsConfig: HivePersistedDocumentsConfig;
5454
release: string;
5555
logger: FastifyBaseLogger;
@@ -167,22 +167,25 @@ export const graphqlHandler = (options: GraphQLHandlerOptions): RouteHandlerMeth
167167
})),
168168
useHive({
169169
debug: true,
170-
enabled: !!options.hiveConfig,
171-
token: options.hiveConfig?.token ?? '',
172-
usage: {
173-
endpoint: options.hiveConfig?.usage?.endpoint ?? undefined,
174-
clientInfo(ctx: { req: FastifyRequest; reply: FastifyReply }) {
175-
const name = ctx.req.headers['graphql-client-name'] as string;
176-
const version = (ctx.req.headers['graphql-client-version'] as string) ?? 'missing';
170+
enabled: !!options.hiveUsageConfig,
171+
token: options.hiveUsageConfig?.token ?? '',
172+
usage: options.hiveUsageConfig
173+
? {
174+
target: options.hiveUsageConfig.target,
175+
endpoint: options.hiveUsageConfig.endpoint ?? undefined,
176+
clientInfo(ctx: { req: FastifyRequest; reply: FastifyReply }) {
177+
const name = ctx.req.headers['graphql-client-name'] as string;
178+
const version = (ctx.req.headers['graphql-client-version'] as string) ?? 'missing';
177179

178-
if (name) {
179-
return { name, version };
180-
}
180+
if (name) {
181+
return { name, version };
182+
}
181183

182-
return null;
183-
},
184-
exclude: ['readiness'],
185-
},
184+
return null;
185+
},
186+
exclude: ['readiness'],
187+
}
188+
: false,
186189
experimental__persistedDocuments: options.hivePersistedDocumentsConfig
187190
? {
188191
cdn: {

packages/services/server/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ export async function main() {
445445
},
446446
isProduction: env.environment !== 'development',
447447
release: env.release,
448-
hiveConfig: env.hive,
448+
hiveUsageConfig: env.hive,
449449
hivePersistedDocumentsConfig: env.hivePersistedDocuments,
450450
tracing,
451451
logger: logger as any,

0 commit comments

Comments
 (0)