Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: preflight scripts for laboratory #5564

Open
wants to merge 122 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 119 commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
e4b09bd
add query builder for laboratory
dimaMachina Jun 26, 2024
3bdcab2
temp
dimaMachina Jun 26, 2024
a455613
fix
dimaMachina Jun 28, 2024
aa5ecb8
fix
dimaMachina Jun 28, 2024
db6f984
pnpm
dimaMachina Jun 28, 2024
1362231
Merge branch 'main' into add-graphiql-explorer2
dimaMachina Jun 28, 2024
24c1f7f
Merge branch 'main' into add-graphiql-explorer2
dimaMachina Jul 1, 2024
97414e1
use stable version of `@graphiql/plugin-explorer`, update graphiql
dimaMachina Jul 1, 2024
06c2ecc
Merge branch 'main' into explorer3
dimaMachina Aug 19, 2024
5c8b2f0
refactor use-operation-collections-plugin.tsx
dimaMachina Aug 19, 2024
1e1dd05
more
dimaMachina Aug 19, 2024
6c6fc1d
more refactoring
dimaMachina Aug 19, 2024
0b48243
update explorer
dimaMachina Aug 20, 2024
7f0025e
undo rename to have less diff changes
dimaMachina Aug 20, 2024
23fe786
- [ ] remove custom prebuild `rss-generator.ts` script
dimaMachina Aug 20, 2024
fc3966c
fix types
dimaMachina Aug 20, 2024
9276cb7
move `theme.config.tsx` to src
dimaMachina Aug 20, 2024
770a158
more product updates work
dimaMachina Aug 20, 2024
3f17764
prettify
dimaMachina Aug 20, 2024
06d5b96
more
dimaMachina Aug 20, 2024
816f92a
more
dimaMachina Aug 20, 2024
257860c
prettier
dimaMachina Aug 20, 2024
f06fed4
grammarly
dimaMachina Aug 20, 2024
e9ffc80
prettify
dimaMachina Aug 20, 2024
2110c7d
add eslint-disable-next-line
dimaMachina Aug 20, 2024
6fbdd04
update date
dimaMachina Aug 20, 2024
f942172
polish
dimaMachina Aug 20, 2024
0c3a9f9
apply review
dimaMachina Aug 21, 2024
d20f454
replace I with we
dimaMachina Aug 21, 2024
d3a66bc
remove mention of `plugin` in `Operations collections plugin`
dimaMachina Aug 21, 2024
bb00d01
use Laurin's query builder suggestion
dimaMachina Aug 21, 2024
36f8c32
polish graphiql v4 alpha
dimaMachina Aug 21, 2024
dd5b588
polish
dimaMachina Aug 21, 2024
1510a01
mention link to graphiql
dimaMachina Aug 21, 2024
527373b
apply Kamil suggestions
dimaMachina Aug 21, 2024
14e8cf0
Merge branch 'main' into add-graphiql-explorer2
dimaMachina Oct 9, 2024
736b77c
Merge branch 'explorer3' into laboratory-product-update
dimaMachina Oct 9, 2024
aff9468
apply Saihaj review changes and polish after new landing page merge
dimaMachina Oct 9, 2024
2469276
Merge branch 'main' into laboratory-product-update
dimaMachina Oct 11, 2024
a54b13d
remove old look of operations collections
dimaMachina Oct 11, 2024
3f5a2d6
all in one
dimaMachina Oct 11, 2024
28342ba
#2 preflight scripts (db + cypress e2e tests) (#5622)
dimaMachina Oct 11, 2024
7bda2e3
Merge branch 'main' into preflight-script
dimaMachina Oct 11, 2024
2cb4e2d
Merge branch 'main' into preflight-script
kamilkisiela Oct 16, 2024
1a8b261
Merge branch 'main' into preflight-script
dimaMachina Oct 24, 2024
4e4bdde
refactor after merging with main
dimaMachina Oct 24, 2024
ee89ae2
prettier
dimaMachina Oct 24, 2024
cdda687
Merge branch 'main' into preflight-script
dimaMachina Nov 7, 2024
2f36bfc
fixes
dimaMachina Nov 7, 2024
790b24a
more
dimaMachina Nov 7, 2024
ac56106
Update cypress.config.ts [skip ci]
dimaMachina Nov 7, 2024
c9964e5
cleanup global variables
dimaMachina Nov 7, 2024
ed71480
add target_id as unique
dimaMachina Nov 7, 2024
b831de6
move to provider
dimaMachina Nov 7, 2024
629a4ca
more tests
dimaMachina Nov 8, 2024
82cb5bc
more
dimaMachina Nov 8, 2024
5d46167
more
dimaMachina Nov 8, 2024
e2b22cb
Merge branch 'preflight-script' of github.com:kamilkisiela/graphql-hi…
dimaMachina Nov 8, 2024
95cc44b
pnpm i + lint
dimaMachina Nov 8, 2024
b568fcf
fix migrations
dimaMachina Nov 8, 2024
0bc7397
fix typecheck
dimaMachina Nov 8, 2024
6b08723
typecheck
dimaMachina Nov 8, 2024
ffa0380
Update cypress/e2e/preflight-script.cy.ts [skip ci]
dimaMachina Nov 8, 2024
a45e9cc
Merge branch 'main' into preflight-script
dimaMachina Nov 14, 2024
2f865e4
use path.parse(import.meta.url).base [skip ci]
dimaMachina Nov 19, 2024
f02835c
rename targetSlug to targetId and move to lab folder [skip ci]
dimaMachina Nov 19, 2024
ca55d5b
more
dimaMachina Nov 19, 2024
6c735f9
use only 1 resolver updatePreflightScript with ON CONFLICT sql [skip ci]
dimaMachina Nov 19, 2024
ea79bc5
validate source code before inserting [skip ci]
dimaMachina Nov 19, 2024
c0f6488
remove `preflightScriptModule` and merge it with `labModule` [skip ci]
dimaMachina Nov 19, 2024
58739cd
post message to main thread as soon as possible [skip ci]
dimaMachina Nov 19, 2024
0be4397
add timeout 30s to terminate worker process [skip ci]
dimaMachina Nov 19, 2024
ab70d62
this is needed for now for cypress
dimaMachina Nov 19, 2024
5838e82
make all tests pass
dimaMachina Nov 19, 2024
6f5710f
update worker chunk name [skip-ci]
dimaMachina Nov 20, 2024
a60373b
Merge branch 'main' into preflight-script
dimaMachina Nov 20, 2024
e40e9da
apply review [skip-ci]
dimaMachina Nov 20, 2024
85b24a4
add proxy [skip ci]
dimaMachina Nov 20, 2024
58cad81
fixes for proxy [skip ci]
dimaMachina Nov 20, 2024
f5dbd49
refactor
dimaMachina Nov 21, 2024
af6519a
refactor
dimaMachina Nov 21, 2024
3e38bb0
more refactoring
dimaMachina Nov 21, 2024
1676dd0
type result
dimaMachina Nov 21, 2024
6e9b7ab
add start/end running script and line/column number
dimaMachina Nov 21, 2024
ebefade
add ability stop script and clear console output
dimaMachina Nov 21, 2024
dd0db87
call handleStopScript if modal closed and script is run
dimaMachina Nov 21, 2024
7cf4904
grant rights [skip ci]
dimaMachina Nov 21, 2024
4dde658
stop worker [skip ci]
dimaMachina Nov 21, 2024
f992123
all cypress tests pass [skip ci]
dimaMachina Nov 21, 2024
08a25f0
Merge branch 'main' into preflight-script
dimaMachina Nov 22, 2024
db92293
Merge branch 'main' into preflight-script
dimaMachina Dec 3, 2024
e22a428
Merge branch 'main' into preflight-script
dimaMachina Dec 4, 2024
02707a9
simplify code structure for readability (#6022)
n1ru4l Dec 16, 2024
d9113e4
Merge remote-tracking branch 'origin/main' into preflight-script
n1ru4l Dec 16, 2024
71bc1e0
refactor: single input field for mutation field
n1ru4l Dec 16, 2024
83840c2
use seed script for cypress
n1ru4l Dec 17, 2024
7244b44
ffs cypress
n1ru4l Dec 17, 2024
85c8673
feat: lab worker dns per env
n1ru4l Dec 17, 2024
7b4fefe
reuse integration-test environment variables and remove duplicated logic
n1ru4l Dec 17, 2024
cbca6d3
remove unused import
n1ru4l Dec 17, 2024
bee25f2
remove comment
n1ru4l Dec 17, 2024
c61bbdb
Merge remote-tracking branch 'origin/main' into preflight-script
n1ru4l Dec 17, 2024
8cc19ec
we need da codegen for the e2e
n1ru4l Dec 17, 2024
08f94fb
relax environment variable
n1ru4l Dec 18, 2024
9c70421
require preflight script reporting readiness
n1ru4l Dec 18, 2024
417b693
instantiate worker for each script run
n1ru4l Dec 18, 2024
ad56588
ooops
n1ru4l Dec 18, 2024
c7017be
fix import
n1ru4l Dec 18, 2024
a70beb6
try chrome
n1ru4l Dec 18, 2024
da9228e
fix url
n1ru4l Dec 18, 2024
c022299
error handling
n1ru4l Dec 18, 2024
63a7e4f
Merge remote-tracking branch 'origin/main' into preflight-script
n1ru4l Dec 18, 2024
d2ca542
Prepare Vite and Fastify for more than one entry point (#6143)
kamilkisiela Dec 19, 2024
895c545
isolate preflight worker into iframe. (#6146)
n1ru4l Dec 19, 2024
661ee13
Merge remote-tracking branch 'origin/main' into preflight-script
n1ru4l Dec 19, 2024
5b9cbc8
ensure
n1ru4l Dec 19, 2024
51b37b0
lint god
n1ru4l Dec 19, 2024
55ad962
less flaky tests
n1ru4l Dec 19, 2024
1187c2f
cleanup
n1ru4l Dec 19, 2024
fc178c0
any
n1ru4l Dec 19, 2024
46bc881
update dates
n1ru4l Dec 19, 2024
dec32b0
Revert "any"
n1ru4l Dec 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/tests-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: setup environment
uses: ./.github/actions/setup
with:
codegen: false
codegen: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we now use the integration test seed here which uses client preset.

actor: test-e2e
cacheTurbo: false

Expand All @@ -43,7 +43,7 @@ jobs:
timeout-minutes: 10
run: |
docker compose \
--env-file docker/.end2end.env \
--env-file integration-tests/.env \
-f docker/docker-compose.community.yml \
-f docker/docker-compose.end2end.yml \
up -d --wait
Expand All @@ -65,7 +65,7 @@ jobs:
docker --version
docker ps --format json | jq .
docker compose \
--env-file docker/.end2end.env \
--env-file integration-tests/.env \
-f docker/docker-compose.community.yml \
-f docker/docker-compose.end2end.yml \
logs
Expand Down
27 changes: 23 additions & 4 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,38 @@
import * as fs from 'node:fs';
// eslint-disable-next-line import/no-extraneous-dependencies -- cypress SHOULD be a dev dependency
import fs from 'node:fs';
import { defineConfig } from 'cypress';
import { initSeed } from './integration-tests/testkit/seed';

if (!process.env.RUN_AGAINST_LOCAL_SERVICES) {
const dotenv = await import('dotenv');
dotenv.config({ path: import.meta.dirname + '/integration-tests/.env' });
}

const isCI = Boolean(process.env.CI);

export const seed = initSeed();

export default defineConfig({
video: isCI,
screenshotOnRunFailure: isCI,
defaultCommandTimeout: 15_000, // sometimes the app takes longer to load, especially in the CI
retries: 2,
env: {
POSTGRES_URL: 'postgresql://postgres:postgres@localhost:5432/registry',
},
e2e: {
setupNodeEvents(on) {
on('task', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: this is executed on a different thread than the tests, so we cannot simply inject the whole seed object into the tests. For now, we only need these seeds. So it's fine. Later one we might want to investigate into another solution for injecting the seed.

async seedTarget() {
const owner = await seed.createOwner();
const org = await owner.createOrg();
const project = await org.createProject();
const slug = `${org.organization.slug}/${project.project.slug}/${project.target.slug}`;
return {
slug,
refreshToken: owner.ownerRefreshToken,
email: owner.ownerEmail,
};
},
});

on('after:spec', (_, results) => {
if (results && results.video) {
// Do we have failures for any retry attempts?
Expand Down
196 changes: 196 additions & 0 deletions cypress/e2e/preflight-script.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
beforeEach(() => {
cy.clearLocalStorage().then(async () => {
cy.task('seedTarget').then(({ slug, refreshToken }: any) => {
cy.setCookie('sRefreshToken', refreshToken);

cy.visit(`/${slug}/laboratory`);
cy.get('[aria-label*="Preflight Script"]').click();
});
});
});

/** Helper function for setting the text within a monaco editor as typing manually results in flaky tests */
function setMonacoEditorContents(editorCyName: string, text: string) {
// wait for textarea appearing which indicates monaco is loaded
cy.dataCy(editorCyName).find('textarea');
cy.window().then(win => {
// First, check if monaco is available on the main window
const editor = (win as any).monaco.editor
.getEditors()
.find(e => e.getContainerDomNode().parentElement.getAttribute('data-cy') === editorCyName);

// If Monaco instance is found
if (editor) {
editor.setValue(text);
} else {
throw new Error('Monaco editor not found on the window or frames[0]');
}
});
}

function setEditorScript(script: string) {
setMonacoEditorContents('preflight-script-editor', script);
}

describe('Preflight Script', () => {
it('mini script editor is read only', () => {
cy.dataCy('toggle-preflight-script').click();
// Wait loading disappears
cy.dataCy('preflight-script-editor-mini').should('not.contain', 'Loading');
// Click
cy.dataCy('preflight-script-editor-mini').click();
// And type
cy.dataCy('preflight-script-editor-mini').within(() => {
cy.get('textarea').type('🐝', { force: true });
});
cy.dataCy('preflight-script-editor-mini').should(
'have.text',
'Cannot edit in read-only editor',
);
});
});

describe('Preflight Script Modal', () => {
const script = 'console.log("Hello_world")';
const env = '{"foo":123}';

beforeEach(() => {
cy.dataCy('preflight-script-modal-button').click();
setMonacoEditorContents('env-editor', env);
});

it('save script and environment variables when submitting', () => {
setEditorScript(script);
cy.dataCy('preflight-script-modal-submit').click();
cy.dataCy('env-editor-mini').should('have.text', env);
cy.dataCy('toggle-preflight-script').click();
cy.dataCy('preflight-script-editor-mini').should('have.text', script);
cy.reload();
cy.get('[aria-label*="Preflight Script"]').click();
cy.dataCy('env-editor-mini').should('have.text', env);
cy.dataCy('preflight-script-editor-mini').should('have.text', script);
});

it('logs show console/error information', () => {
setEditorScript(script);
cy.dataCy('run-preflight-script').click();
cy.dataCy('console-output').should('contain', 'Log: Hello_world (Line: 1, Column: 1)');

setEditorScript(
`console.info(1)
console.warn(true)
console.error('Fatal')
throw new TypeError('Test')`,
);

cy.dataCy('run-preflight-script').click();
// First log previous log message
cy.dataCy('console-output').should('contain', 'Log: Hello_world (Line: 1, Column: 1)');
// After the new logs
cy.dataCy('console-output').should(
'contain',
[
'Info: 1 (Line: 1, Column: 1)',
'Warn: true (Line: 2, Column: 1)',
'Error: Fatal (Line: 3, Column: 1)',
'TypeError: Test (Line: 4, Column: 7)',
].join(''),
);
});

it('script execution updates environment variables', () => {
setEditorScript(`lab.environment.set('my-test', "TROLOLOL")`);

cy.dataCy('run-preflight-script').click();
cy.dataCy('env-editor').should(
'include.text',
// replace space with  
'{ "foo": 123, "my-test": "TROLOLOL"}'.replaceAll(' ', '\xa0'),
);
});

it('`crypto-js` can be used for generating hashes', () => {
setEditorScript('console.log(lab.CryptoJS.SHA256("🐝"))');
cy.dataCy('run-preflight-script').click();
cy.dataCy('console-output').should('contain', 'Info: Using crypto-js version:');
cy.dataCy('console-output').should(
'contain',
'Log: d5b51e79e4be0c4f4d6b9a14e16ca864de96afe68459e60a794e80393a4809e8',
);
});

it('scripts can not use `eval`', () => {
setEditorScript('eval()');
cy.dataCy('preflight-script-modal-submit').click();
cy.get('body').contains('Usage of dangerous statement like eval() or Function("").');
});

it('invalid code is rejected and can not be saved', () => {
setEditorScript('🐝');
cy.dataCy('preflight-script-modal-submit').click();
cy.get('body').contains("[1:1]: Illegal character '}");
});
});

describe('Execution', () => {
it('header placeholders are substituted with environment variables', () => {
cy.dataCy('toggle-preflight-script').click();
cy.get('[data-name="headers"]').click();
cy.get('.graphiql-editor-tool .graphiql-editor:last-child textarea').type(
'{ "__test": "{{foo}} bar {{nonExist}}" }',
{
force: true,
parseSpecialCharSequences: false,
},
);
cy.dataCy('env-editor-mini').within(() => {
cy.get('textarea').type('{"foo":"injected"}', {
force: true,
parseSpecialCharSequences: false,
});
});
cy.intercept('/api/lab/foo/my-new-project/development', req => {
expect(req.headers.__test).to.equal('injected bar {{nonExist}}');
});
cy.get('body').type('{ctrl}{enter}');
});

it('executed script updates update env editor and substitute headers', () => {
cy.dataCy('toggle-preflight-script').click();
cy.get('[data-name="headers"]').click();
cy.get('.graphiql-editor-tool .graphiql-editor:last-child textarea').type(
'{ "__test": "{{foo}}" }',
{
force: true,
parseSpecialCharSequences: false,
},
);
cy.dataCy('preflight-script-modal-button').click();
setMonacoEditorContents('preflight-script-editor', `lab.environment.set('foo', 92)`);
cy.dataCy('preflight-script-modal-submit').click();
cy.intercept('/api/lab/foo/my-new-project/development', req => {
expect(req.headers.__test).to.equal('92');
});
cy.get('.graphiql-execute-button').click();
});

it('disabled script is not executed', () => {
cy.get('[data-name="headers"]').click();
cy.get('.graphiql-editor-tool .graphiql-editor:last-child textarea').type(
'{ "__test": "{{foo}}" }',
{
force: true,
parseSpecialCharSequences: false,
},
);
cy.dataCy('preflight-script-modal-button').click();
setMonacoEditorContents('preflight-script-editor', `lab.environment.set('foo', 92)`);
setMonacoEditorContents('env-editor', `{"foo":10}`);

cy.dataCy('preflight-script-modal-submit').click();
cy.intercept('/api/lab/foo/my-new-project/development', req => {
expect(req.headers.__test).to.equal('10');
});
cy.get('.graphiql-execute-button').click();
});
});
2 changes: 1 addition & 1 deletion cypress/local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ cd ..
docker buildx bake -f docker/docker.hcl build --load

echo "⬆️ Running all local containers..."
docker compose -f ./docker/docker-compose.community.yml -f ./docker/docker-compose.end2end.yml --env-file ./integration-tests/.env --env-file ./docker/.end2end.env up -d --wait
docker compose -f ./docker/docker-compose.community.yml -f ./docker/docker-compose.end2end.yml --env-file ./integration-tests/.env up -d --wait

echo "✅ E2E tests environment is ready. To run tests now, use:"
echo ""
Expand Down
6 changes: 3 additions & 3 deletions cypress/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
"target": "es2021",
"lib": ["es2021", "dom"],
"types": ["node", "cypress"]
},
"include": ["**/*.ts"]
"include": ["**/*.ts", "../integration-tests/testkit/**/*.ts"]
}
4 changes: 1 addition & 3 deletions deployment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,12 +333,10 @@ deployCloudFlareSecurityTransform({
// Staging
'staging.graphql-hive.com',
'app.staging.graphql-hive.com',
'lab-worker.staging.graphql-hive.com',
'cdn.staging.graphql-hive.com',
// Dev
'dev.graphql-hive.com',
'app.dev.graphql-hive.com',
'lab-worker.dev.graphql-hive.com',
Comment on lines -336 to -341
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no longer needed, we don't need to run on a different domain to isolate the worker.

'cdn.dev.graphql-hive.com',
],
});
Expand All @@ -351,4 +349,4 @@ export const schemaApiServiceId = schema.service.id;
export const webhooksApiServiceId = webhooks.service.id;

export const appId = app.deployment.id;
export const publicIp = proxy!.status.loadBalancer.ingress[0].ip;
export const publicIp = proxy.get()!.status.loadBalancer.ingress[0].ip;
1 change: 1 addition & 0 deletions deployment/services/app.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { randomUUID } from 'crypto';
import * as pulumi from '@pulumi/pulumi';
import { serviceLocalEndpoint } from '../utils/local-endpoint';
import { ServiceDeployment } from '../utils/service-deployment';
Expand Down
3 changes: 0 additions & 3 deletions deployment/services/cloudflare-security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export function deployCloudFlareSecurityTransform(options: {
)} } and not http.host in { ${toExpressionList(options.ignoredHosts)} }`;

// TODO: When Preflight PR is merged, we'll need to change this to build this host in a better way.
const labHost = `lab-worker.${options.environment.rootDns}`;
const monacoCdnDynamicBasePath: `https://${string}/` = `https://cdn.jsdelivr.net/npm/monaco-editor@${monacoEditorVersion}/`;
const monacoCdnStaticBasePath: `https://${string}/` = `https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/`;
const crispHost = 'client.crisp.chat';
Expand All @@ -44,7 +43,6 @@ export function deployCloudFlareSecurityTransform(options: {
crispHost,
stripeHost,
gtmHost,
labHost,
'settings.crisp.chat',
'*.ingest.sentry.io',
'wss://client.relay.crisp.chat',
Expand All @@ -57,7 +55,6 @@ export function deployCloudFlareSecurityTransform(options: {
const contentSecurityPolicy = `
default-src 'self';
frame-src ${stripeHost} https://game.crisp.chat;
worker-src 'self' blob: ${labHost};
style-src 'self' 'unsafe-inline' ${crispHost} fonts.googleapis.com rsms.me ${monacoCdnDynamicBasePath} ${monacoCdnStaticBasePath};
script-src 'self' 'unsafe-eval' 'unsafe-inline' {DYNAMIC_HOST_PLACEHOLDER} ${monacoCdnDynamicBasePath} ${monacoCdnStaticBasePath} ${cspHosts};
connect-src 'self' * {DYNAMIC_HOST_PLACEHOLDER} ${cspHosts};
Expand Down
3 changes: 1 addition & 2 deletions deployment/services/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,5 @@ export function deployProxy({
service: usage.service,
retriable: true,
},
])
.get();
]);
}
Loading
Loading