Skip to content

Commit

Permalink
[Console] Only copy as curl should be allowed for kbn requests (#20…
Browse files Browse the repository at this point in the history
  • Loading branch information
sabarasaba authored Dec 3, 2024
1 parent 14bdd8d commit 27e828c
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ import type { EditorRequest } from '../../types';

import { useServicesContext } from '../../../../contexts';
import { StorageKeys } from '../../../../../services';
import { DEFAULT_LANGUAGE, AVAILABLE_LANGUAGES } from '../../../../../../common/constants';
import {
DEFAULT_LANGUAGE,
AVAILABLE_LANGUAGES,
KIBANA_API_PREFIX,
} from '../../../../../../common/constants';

interface Props {
getRequests: () => Promise<EditorRequest[]>;
Expand Down Expand Up @@ -90,9 +94,24 @@ export const ContextMenu = ({
// Get all the selected requests
const requests = await getRequests();

// If we have any kbn requests, we should not allow the user to copy as
// anything other than curl
const hasKbnRequests = requests.some((req) => req.url.startsWith(KIBANA_API_PREFIX));

if (hasKbnRequests && withLanguage !== 'curl') {
notifications.toasts.addDanger({
title: i18n.translate('console.consoleMenu.copyAsMixedRequestsMessage', {
defaultMessage: 'Kibana requests can only be copied as curl',
}),
});

return;
}

const { data: requestsAsCode, error: requestError } = await convertRequestToLanguage({
language: withLanguage,
esHost: esHostService.getHost(),
kibanaHost: window.location.origin,
requests,
});

Expand Down
4 changes: 3 additions & 1 deletion src/plugins/console/public/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ export async function convertRequestToLanguage({
requests,
language,
esHost,
kibanaHost,
}: {
language: string;
esHost: string;
kibanaHost: string;
requests: EditorRequest[];
}) {
return sendRequest({
path: `/api/console/convert_request_to_language`,
method: 'post',
query: { language, esHost },
query: { language, esHost, kibanaHost },
body: requests,
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const routeValidationConfig = {
query: schema.object({
language: schema.string(),
esHost: schema.string(),
kibanaHost: schema.string(),
}),
body: schema.maybe(
schema.arrayOf(
Expand All @@ -39,7 +40,7 @@ export const registerConvertRequestRoute = ({
}: RouteDependencies) => {
const handler: RequestHandler<unknown, Query, Body> = async (ctx, req, response) => {
const { body, query } = req;
const { language, esHost } = query;
const { language, esHost, kibanaHost } = query;

try {
// Iterate over each request and build all the requests into a single string
Expand All @@ -60,6 +61,9 @@ export const registerConvertRequestRoute = ({
printResponse: true,
complete: true,
elasticsearchUrl: esHost,
otherUrls: {
kbn: kibanaHost,
},
});

return response.ok({
Expand Down
49 changes: 49 additions & 0 deletions test/functional/apps/console/_context_menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,55 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
}
});

it('doesnt allow to copy kbn requests as anything other than curl', async () => {
const canReadClipboard = await browser.checkBrowserPermission('clipboard-read');

await PageObjects.console.clearEditorText();
await PageObjects.console.enterText('GET _search\n');

// Add a kbn request
// pressEnter
await PageObjects.console.enterText('GET kbn:/api/spaces/space');
// Make sure to select the es and kbn request
await PageObjects.console.selectAllRequests();

await PageObjects.console.clickContextMenu();
await PageObjects.console.clickCopyAsButton();

let resultToast = await toasts.getElementByIndex(1);
let toastText = await resultToast.getVisibleText();

expect(toastText).to.be('Requests copied to clipboard as curl');

// Check if the clipboard has the curl request
if (canReadClipboard) {
const clipboardText = await browser.getClipboardValue();
expect(clipboardText).to.contain('curl -X GET');
}

// Wait until async operation is done
await PageObjects.common.sleep(1000);

// Focus editor once again
await PageObjects.console.focusInputEditor();

// Try to copy as javascript
await PageObjects.console.clickContextMenu();
await PageObjects.console.changeLanguageAndCopy('javascript');

resultToast = await toasts.getElementByIndex(2);
toastText = await resultToast.getVisibleText();

expect(toastText).to.be('Kibana requests can only be copied as curl');

// Since we tried to copy as javascript, the clipboard should still have
// the curl request
if (canReadClipboard) {
const clipboardText = await browser.getClipboardValue();
expect(clipboardText).to.contain('curl -X GET');
}
});

it.skip('allows to change default language', async () => {
await PageObjects.console.clickContextMenu();

Expand Down
7 changes: 7 additions & 0 deletions test/functional/page_objects/console_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ export class ConsolePageObject extends FtrService {
await textArea.clearValueWithKeyboard();
}

public async focusInputEditor() {
const outputEditor = await this.testSubjects.find('consoleMonacoEditor');
// Simply clicking on the editor doesn't focus it, so we need to click
// on the margin view overlays
await (await outputEditor.findByClassName('margin-view-overlays')).click();
}

public async focusOutputEditor() {
const outputEditor = await this.testSubjects.find('consoleMonacoOutput');
// Simply clicking on the output editor doesn't focus it, so we need to click
Expand Down

0 comments on commit 27e828c

Please sign in to comment.