-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: preflight scripts for laboratory (#5564)
Co-authored-by: Kamil Kisiela <[email protected]> Co-authored-by: Saihajpreet Singh <[email protected]> Co-authored-by: Laurin Quast <[email protected]> Co-authored-by: Dotan Simha <[email protected]>
- Loading branch information
1 parent
38c14e2
commit e0eb3bd
Showing
60 changed files
with
2,883 additions
and
346 deletions.
There are no files selected for viewing
This file contains 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,8 @@ | ||
--- | ||
'hive': minor | ||
--- | ||
|
||
Add preflight scripts for laboratory. | ||
|
||
It is now possible to add a preflight script within the laboratory that executes before sending a GraphQL request. | ||
[Learn more.](https://the-guild.dev/graphql/hive/product-updates/2024-12-27-preflight-script) |
This file contains 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 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 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,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(); | ||
}); | ||
}); |
This file contains 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 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 |
---|---|---|
@@ -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"] | ||
} |
This file contains 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 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 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 |
---|---|---|
|
@@ -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/[email protected]/`; | ||
const crispHost = 'client.crisp.chat'; | ||
|
@@ -44,7 +43,6 @@ export function deployCloudFlareSecurityTransform(options: { | |
crispHost, | ||
stripeHost, | ||
gtmHost, | ||
labHost, | ||
'settings.crisp.chat', | ||
'*.ingest.sentry.io', | ||
'wss://client.relay.crisp.chat', | ||
|
@@ -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}; | ||
|
This file contains 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 |
---|---|---|
|
@@ -100,6 +100,5 @@ export function deployProxy({ | |
service: usage.service, | ||
retriable: true, | ||
}, | ||
]) | ||
.get(); | ||
]); | ||
} |
Oops, something went wrong.