This repository was archived by the owner on Oct 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 51
Add custom schema checks #930
Merged
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
4f29979
Add custom check to overview
Meschreiber 66737d1
Add raw custom check doc
Meschreiber 788987f
Vale
Meschreiber b8ab193
Add relevant pointers
Meschreiber dac70e1
Edit
Meschreiber 141a79e
Vale
Meschreiber 0f47999
Schema check edits (#931)
Meschreiber 4bc8fde
Vale
Meschreiber 79da14d
Add relevant pointers
Meschreiber 6edd57d
Fixes
Meschreiber 401e681
Copyedit
Meschreiber e457df0
Copyedit
Meschreiber 1bad8fd
Copyedit
Meschreiber 1027e53
Merge branch 'main' into ms/custom-schema-checks
Meschreiber c132577
Apply suggestions from code review
Meschreiber 97a665f
Review suggestions and other edits
Meschreiber f5f3aa2
Edit
Meschreiber aeda4f0
Remove image for now
Meschreiber 15bec46
Merge branch 'main' into ms/custom-schema-checks
Meschreiber aa70a57
Update check configuration screenshot
Meschreiber eb316f3
Copyedit
Meschreiber c0b7a09
Update HMAC example
Meschreiber 656103f
Add check run screenshot
Meschreiber d387eb4
Add screenshot and copyedits
Meschreiber f3e788e
Vale
Meschreiber 286dd8a
Merge branch 'main' into ms/custom-schema-checks
Meschreiber File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,6 +43,7 @@ Doyensec | |
Dynatrace | ||
Entra | ||
[Ee]nablement | ||
ESLint | ||
(?i)enums? | ||
GCUs? | ||
Gradle | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,289 @@ | ||
--- | ||
title: Run Custom Schema Checks | ||
subtitle: Extend GraphOS schema checks with custom validations | ||
description: Learn how to extend the GraphOS schema checks workflow by configuring custom schema checks that allow your organization to enforce unique validation rules using your own services. | ||
--- | ||
|
||
<EnterpriseFeature linkWithAnchor="https://www.apollographql.com/pricing#delivery-pipeline" /> | ||
|
||
Your organization's validation needs might extend beyond default schema checks. | ||
For example, you might want to enforce schema standards in addition to default [GraphOS linter rules](./linter-rules). | ||
You might require validations that depend on external data, such as ensuring schema changes are only submitted from a specific branch in version control. | ||
_Custom schema checks_ let you supplement default checks by executing custom validations using your own services. | ||
|
||
## How custom checks work | ||
|
||
Once you configure custom checks, GraphOS sends schema change information to an endpoint you specify. | ||
Your endpoint performs validations and reports potential issues back to GraphOS via the [Platform API](/graphos/platform-api/). | ||
GraphOS Studio displays the issues you report along with other check result details. | ||
|
||
<img | ||
className="screenshot" | ||
src="../img/schema-checks/custom-check-results.jpg" | ||
alt="Schema check run showing custom check errors and warnings in GraphOS Studio" | ||
width="700" | ||
/> | ||
|
||
Custom checks run alongside other [check types](./schema-checks#types-of-checks) as part of every schema check run. | ||
Like operations, linter, and other check types, custom checks only run [after a build check has successfully completed](schema-checks#build-checks-1). | ||
|
||
## Prerequisites | ||
|
||
Custom checks require using [Rover CLI](/rover/) version `0.27.0` or later when you [run schema checks](./run-checks). | ||
|
||
## Configuration | ||
|
||
Custom checks require you to set up an HTTPS endpoint that's accessible via the public internet. | ||
You can set secret tokens to ensure that your endpoint only responds to requests sent by GraphOS. | ||
Once you register your endpoint in GraphOS Studio, GraphOS sends it webhook notifications as POST requests. | ||
|
||
You can only register one endpoint for custom checks, but that endpoint can perform as many different schema validations as you want. | ||
You can write and deploy your validation service using any language or framework as long as the endpoint conforms to the expectations listed below. | ||
|
||
### Set up a validation endpoint | ||
|
||
Your validation endpoint should: | ||
|
||
1. Be able to receive and process an HTTP POST request with a payload with [the specified JSON format](#webhook-format). | ||
1. Send a `200` response to the request. | ||
- When GraphOS dispatches a webhook with check information, it has a 30-second timeout to receive a `200` response. | ||
- If the request times out or doesn't receive a `200`, it will retry up to five times, with an exponential backoff delay starting at 5 seconds and going up to 60 seconds. | ||
1. [Submit validation check results](#submitting-a-check-result) to the GraphOS Platform API. | ||
|
||
Outside of these requirements, you can implement any validations you need. | ||
|
||
#### Webhook format | ||
|
||
On every schema run, GraphOS sends your registered endpoint a POST request. | ||
The request has a JSON payload with the following shape: | ||
|
||
```json | ||
{ | ||
// Type of event, indicating a custom schema check in Apollo GraphOS | ||
"eventType": "APOLLO_CUSTOM_CHECK", | ||
// The unique identifier of the event | ||
"eventId": "UUID", | ||
// Version of the payload shape | ||
"version": "1", | ||
"checkStep": { | ||
// The unique identifier of the graph being validated | ||
"graphId": "string", | ||
// The variant of the graph (e.g., "current", "staging") | ||
"graphVariant": "string", | ||
// A unique identifier for the specific custom check task | ||
"taskId": "UUID", | ||
// A unique identifier for the workflow that initiated this check | ||
"workflowId": "UUID", | ||
"gitContext": { | ||
// The branch from which the schema change is being submitted | ||
"branch": "string", | ||
// The commit hash associated with the schema change | ||
"commit": "string", | ||
// The name or email of the person who committed the change | ||
"committer": "string", | ||
// The commit message describing the schema change | ||
"message": "string", | ||
// The URL of the remote Git repository (e.g., GitHub or GitLab) | ||
"remoteUrl": "string" | ||
} | ||
}, | ||
"baseSchema": { | ||
// The hash of the current base schema | ||
"hash": "string", | ||
// A list of subgraphs that make up the base schema (if using Apollo Federation) | ||
"subgraphs": [ | ||
{ | ||
// The hash of the subgraph schema | ||
"hash": "string", | ||
// The name of the subgraph | ||
"name": "string" | ||
} | ||
] | ||
}, | ||
"proposedSchema": { | ||
// The hash of the proposed schema | ||
"hash": "string", | ||
// A list of subgraphs in the proposed schema (if using Apollo Federation) | ||
"subgraphs": [ | ||
{ | ||
// The hash of the subgraph schema | ||
"hash": "string", | ||
// The name of the subgraph | ||
"name": "string" | ||
} | ||
] | ||
} | ||
} | ||
``` | ||
|
||
<Note> | ||
|
||
The `version` attribute is included because payloads may include additional properties in the future. | ||
|
||
</Note> | ||
|
||
Because schemas can be large, the payload provides schema hashes rather than full-text schemas. | ||
Your endpoint can request the full schema contents using the [GraphOS Platform API](/graphos/platform-api/). | ||
Refer to [Platform API docs](https://studio.apollographql.com/public/apollo-platform/home?variant=main) for instructions on making and authenticating requests. | ||
See the examples below for fetching schema contents by hash. | ||
|
||
Using the schema contents and payload information, your endpoint can perform whatever validations you need. | ||
|
||
#### Fetch a single schema | ||
|
||
To fetch a single supergraph or subgraph schema contents by hash, use the following GraphQL query on the Platform API: | ||
|
||
```graphql | ||
query schema($graphId: ID!, $hash: SHA256) { | ||
graph(id: $graphId) { | ||
doc(hash: $hash) { | ||
source | ||
} | ||
} | ||
} | ||
``` | ||
|
||
#### Fetch all schemas | ||
|
||
To request all subgraphs and supergraph schema in one request, use the following GraphQL query on the Platform API: | ||
|
||
```graphql | ||
query schemas($hashes: [SHA256!]!, $graphId: ID!) { | ||
graph(id: $graphId) { | ||
docs(hashes: $hashes) { | ||
hash | ||
source | ||
} | ||
} | ||
} | ||
``` | ||
|
||
#### Submitting a check result | ||
|
||
Once your endpoint has completed its validation, it should submit the results back to the triggering schema check run using the Platform API. | ||
The triggering schema check run waits for a response for ten minutes and doesn't complete until it receives it. | ||
If ten minutes pass without a response, the schema check run is marked as failed. | ||
|
||
The results should include a list of violations, each with the following: | ||
|
||
- `level`: Violation [severity level](./schema-linter/#setting-severity-levels), either `ERROR`, `WARN`, or `IGNORE` | ||
- `rule`: Name of the violation type | ||
- `message`: Error message | ||
|
||
#### Example check results mutation | ||
|
||
You can use the following GraphQL mutation on the Platform API to submit custom check results: | ||
|
||
```graphql | ||
mutation SchemaCheckCallback( | ||
$input: CustomCheckCallbackInput! | ||
$name: String! | ||
$graphId: ID! | ||
) { | ||
graph(id: $graphId) { | ||
variant(name: $name) { | ||
customCheckCallback(input: $input) { | ||
__typename | ||
... on CustomCheckResult { | ||
violations { | ||
level | ||
message | ||
rule | ||
} | ||
} | ||
... on PermissionError { | ||
message | ||
} | ||
... on TaskError { | ||
message | ||
} | ||
... on ValidationError { | ||
message | ||
} | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
### Enable custom checks in Studio | ||
|
||
Once your endpoint is ready, you need to register it in GraphOS Studio. | ||
|
||
1. In [GraphOS Studio](https://studio.apollographql.com?referrer=docs-content), go to your graph's **Checks** page. | ||
2. Select **Configuration** in the upper right to open the checks configuration page. | ||
3. From the checks configuration page, open the **Custom Checks** section. | ||
4. Toggle on the switch next to **Enable Custom Checks**. | ||
5. Click the **Edit** button next to **Registered webhook** and enter the **Endpoint URL**. | ||
6. Optionally, enter a **Secret Token**. | ||
|
||
If you enter a token, each notification HTTP request includes an `x-apollo-signature` header whose value is a [Hash Message Authentication Code (HMAC)](https://en.wikipedia.org/wiki/HMAC) generated using the token, the request body as the message, and the SHA256 hash function. The `x-apollo-signature` header has the format `sha256=<hmac-value>`. | ||
|
||
<ExpansionPanel title="See an example"> | ||
|
||
Given the following inputs: | ||
|
||
**Secret token** (key): `your_secret_token` | ||
|
||
**Request body** (message): | ||
|
||
```json | ||
{ | ||
"eventType": "APOLLO_CUSTOM_CHECK", | ||
"eventId": "123e4567-e89b-12d3-a456-426614174000", | ||
"version": "1", | ||
"checkStep": { | ||
"graphId": "example-graph-id", | ||
"graphVariant": "staging", | ||
"taskId": "9f2a8b8e-e38f-4f4c-a2ad-7e50c2f55544", | ||
"workflowId": "a4b9d5c6-7b3e-40b9-a728-c98ef02e6e29", | ||
"gitContext": { | ||
"branch": "main", | ||
"commit": "f4d3c2a17e9b234bf9b1d1d8d0e5a678e5b1a9f0", | ||
"committer": "john.doe@example.com", | ||
"message": "Updated schema for new feature", | ||
"remoteUrl": "https://github.com/example/repo.git" | ||
} | ||
}, | ||
"baseSchema": { | ||
"hash": "b1f3a79d2a73c8f6b56f5d42dbec4e9a6a7b1f00", | ||
"subgraphs": [ | ||
{ | ||
"hash": "f0a1b7c4d9e7f3a5c2b98e9a6f4d2c1b0e9f4a5b", | ||
"name": "users" | ||
} | ||
] | ||
}, | ||
"proposedSchema": { | ||
"hash": "c1b7a6f3d9e5f2b8c3a7e5b6c1d9e0f1b2a5f6a7", | ||
"subgraphs": [ | ||
{ | ||
"hash": "d9b7a5f2e3c9f8b4a1d2c7b5a3e4f6b2a1c7e5f9", | ||
"name": "orders" | ||
} | ||
] | ||
} | ||
} | ||
``` | ||
|
||
**Hash function**: SHA256 | ||
|
||
The `x-apollo-header` value would be `sha256=7b678bf54081f495866b5cecc5ada7ce85088dda2b46644a7f75ef823b9d5f86`. | ||
</ExpansionPanel> | ||
|
||
Refer to this [guide from Okta](https://www.okta.com/identity-101/hmac/) to learn more about implementation and see additional resources. | ||
|
||
7. You should now see your configured webhook on the checks configuration page. Click **Send test notification** to test your endpoint. | ||
|
||
From now on, whenever you [run schema checks](./run-checks), the check run will include a **Custom Check** task. | ||
|
||
<img | ||
className="screenshot" | ||
src="../img/schema-checks/custom-check-run.jpg" | ||
alt="Custom check run in GraphOS Studio" | ||
width="600" | ||
/> | ||
|
||
## Example validation service implementation | ||
|
||
Refer to the [example implementation](https://github.com/apollosolutions/custom-check-examples) for a custom check validation service that enforces GraphQL ESLint rules. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file modified
BIN
+120 KB
(120%)
src/content/graphos/img/schema-checks/check-configuration-page.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.