404: Oops, sorry we can't find that page!
-The page you are looking for has either moved, or doesn't exist.
++ 404: Oops, sorry we can't find that page! +
++ The page you are looking for has either moved, or doesn't + exist. +
Get helpdiff --git a/.eslintrc.js b/.eslintrc.js index 2a2c12554..e56c8fecd 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,82 +1,82 @@ -var path = require('path'); +var path = require("path"); module.exports = { extends: [ - 'airbnb', - 'plugin:jest/recommended', - 'plugin:react-hooks/recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:cypress/recommended', - ], - parser: '@typescript-eslint/parser', - plugins: [ - 'jest', - 'react', - '@typescript-eslint', + "airbnb", + "plugin:jest/recommended", + "plugin:react-hooks/recommended", + "plugin:@typescript-eslint/recommended", + "plugin:cypress/recommended", + "plugin:prettier/recommended", ], + parser: "@typescript-eslint/parser", + plugins: ["jest", "react", "@typescript-eslint"], env: { node: true, mocha: true, browser: true, - 'jest/globals': true, + "jest/globals": true, }, globals: { expect: false, describe: false, }, rules: { - camelcase: 'off', - 'consistent-return': 1, - 'arrow-body-style': 0, - 'max-len': 0, - 'no-unused-expressions': 0, - 'no-console': 0, - 'space-before-function-paren': 0, - 'react/prefer-stateless-function': 0, - 'react/no-multi-comp': 0, - 'react/no-unused-prop-types': [1, { customValidators: [], skipShapeProps: true }], - 'react/require-default-props': 0, // TODO set default props and enable this check - 'react/jsx-filename-extension': [1, { extensions: ['.jsx', '.tsx'] }], - 'no-param-reassign': 0, - 'new-cap': 0, - 'import/no-unresolved': [2, { caseSensitive: false }], - 'linebreak-style': 0, - 'import/no-named-as-default': 'off', - 'import/no-named-as-default-member': 'off', - 'import/extensions': 0, - 'import/no-extraneous-dependencies': 0, - 'no-underscore-dangle': 0, - 'jsx-a11y/no-static-element-interactions': 'off', + camelcase: "off", + "consistent-return": 1, + "arrow-body-style": 0, + "max-len": 0, + "no-unused-expressions": 0, + "no-console": 0, + "space-before-function-paren": 0, + "react/prefer-stateless-function": 0, + "react/no-multi-comp": 0, + "react/no-unused-prop-types": [ + 1, + { customValidators: [], skipShapeProps: true }, + ], + "react/require-default-props": 0, // TODO set default props and enable this check + "react/jsx-filename-extension": [1, { extensions: [".jsx", ".tsx"] }], + "no-param-reassign": 0, + "new-cap": 0, + "import/no-unresolved": [2, { caseSensitive: false }], + "linebreak-style": 0, + "import/no-named-as-default": "off", + "import/no-named-as-default-member": "off", + "import/extensions": 0, + "import/no-extraneous-dependencies": 0, + "no-underscore-dangle": 0, + "jsx-a11y/no-static-element-interactions": "off", // note you must disable the base rule as it can report incorrect errors. more info here: // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md - 'no-use-before-define': 'off', - '@typescript-eslint/no-use-before-define': ['error'], + "no-use-before-define": "off", + "@typescript-eslint/no-use-before-define": ["error"], // turn off and override to not run this on js and jsx files. More info here: // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md#configuring-in-a-mixed-jsts-codebase - '@typescript-eslint/explicit-module-boundary-types': 'off', + "@typescript-eslint/explicit-module-boundary-types": "off", // There is a bug with these rules in our version of jsx-a11y plugin (5.1.1) // To upgrade our version of the plugin we would need to make more changes // with eslint-config-airbnb, so we will just turn off for now. - 'jsx-a11y/heading-has-content': 'off', - 'jsx-a11y/anchor-has-content': 'off', + "jsx-a11y/heading-has-content": "off", + "jsx-a11y/anchor-has-content": "off", }, overrides: [ { - files: ['*.ts', '*.tsx'], + files: ["*.ts", "*.tsx"], rules: { // Set to warn for now at the beginning to make migration easier // but want to change this to error when we can. - '@typescript-eslint/explicit-module-boundary-types': ['warn'], + "@typescript-eslint/explicit-module-boundary-types": ["warn"], }, }, ], settings: { - 'import/resolver': { + "import/resolver": { webpack: { - config: path.join(__dirname, 'webpack.config.js'), + config: path.join(__dirname, "webpack.config.js"), }, }, }, diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 95ddb54a3..8b784ac9c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,18 +25,18 @@ jobs: ${{ runner.os }}-modules- # It seems faster not to cache Go dependencies - + - name: Install JS Dependencies run: make deps-js - name: Install Go Dependencies run: make deps-go - # Pre-starting dependencies here means they are ready to go when we need them. + # Pre-starting dependencies here means they are ready to go when we need them. - name: Start Infra Dependencies # Use & to background this run: docker-compose up -d mysql_test redis mailhog saml_idp & - + - name: Build Fleet run: | export PATH=$PATH:~/go/bin @@ -51,7 +51,7 @@ jobs: make e2e-setup yarn cypress run --config video=false - + test-js: strategy: matrix: @@ -106,7 +106,33 @@ jobs: - name: Run JS Linting run: | make lint-js - + + check-prettier: + strategy: + matrix: + os: [ ubuntu-latest ] + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout Code + uses: actions/checkout@v2 + + - name: JS Dependency Cache + uses: actions/cache@v2 + with: + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-modules- + + - name: Install JS Dependencies + run: make deps-js + + - name: Run prettier formatting check + run: | + yarn prettier:check test-go: strategy: @@ -122,15 +148,15 @@ jobs: - name: Checkout Code uses: actions/checkout@v2 - # Pre-starting dependencies here means they are ready to go when we need them. + # Pre-starting dependencies here means they are ready to go when we need them. - name: Start Infra Dependencies # Use & to background this run: docker-compose up -d mysql_test redis & - + # It seems faster not to cache Go dependencies - name: Install Go Dependencies run: make deps-go - + - name: Generate static files run: | export PATH=$PATH:~/go/bin @@ -158,4 +184,3 @@ jobs: - name: Run Go Linting run: | make lint-go - diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..fb328fef1 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,34 @@ +# markdown +*.md + +# output directories +build +vendor +node_modules + +# generated artifacts +assets/bundle*.* +assets/*@*.svg +assets/*@*.png +assets/*@*.eot +assets/*@*.woff +assets/*@*.woff2 +assets/*@*.ttf +frontend/templates/react.tmpl +bindata.go +server/bindata/generated.go +*.cover +*.test +*.log + +# typescript generated test files +tmp/ + +# editors +.vscode +.idea + +# Cypress e2e testing +cypress/screenshots +cypress/videos +cypress/downloads diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/.sass-lint.yml b/.sass-lint.yml deleted file mode 100644 index 9e991d882..000000000 --- a/.sass-lint.yml +++ /dev/null @@ -1,120 +0,0 @@ -# Linter ReadMe: https://github.com/sasstools/sass-lint/tree/master/docs/rules -files: - include: 'frontend/**/*.s+(a|c)ss' - ignore: - - 'frontend/styles/global/_fonts.scss' - - 'frontend/styles/global/_icons.scss' -options: - formatter: stylish - merge-default-rules: false -rules: - bem-depth: - - 1 - - max-depth: 1 - border-zero: - - 1 - - convention: '0' - brace-style: - - 1 - - allow-single-line: false - class-name-format: - - 1 - - convention: ^(?!js-).* - convention-explanation: should not be written in the form js-* - clean-import-paths: - - 1 - - filename-extension: true - leading-underscore: false - empty-line-between-blocks: - - 1 - - ignore-single-line-rulesets: false - extends-before-declarations: 1 - extends-before-mixins: 1 - final-newline: - - 1 - - include: true - force-attribute-nesting: 1 - force-element-nesting: 1 - force-pseudo-nesting: 1 - function-name-format: - - 1 - - convention: '^[\-_a-z]+$' - convention-explanation: 'Variables must contain only lowercase letters, hyphens, and underscores' - hex-length: - - 1 - - style: short - hex-notation: - - 1 - - style: lowercase - id-name-format: - - 1 - - convention: hyphenatedbem - indentation: - - 1 - - size: 2 - leading-zero: - - 0 - mixin-name-format: - - 1 - - convention: '^[\-_a-z]+$' - convention-explanation: 'Variables must contain only lowercase letters, hyphens, and underscores' - mixins-before-declarations: - - 1 - - exclude: ['breakpoint', 'media', 'placeholder'] - nesting-depth: - - 1 - - max-depth: 4 - no-color-keywords: 1 - no-color-literals: 0 - no-css-comments: 1 - no-duplicate-properties: 1 - no-empty-rulesets: 1 - no-extends: 0 - no-ids: 1 - no-important: 1 - no-invalid-hex: 1 - no-mergeable-selectors: 1 - no-misspelled-properties: - - 1 - - extra-properties: [] - no-qualifying-elements: - - 1 - - allow-element-with-attribute: true - allow-element-with-class: false - allow-element-with-id: false - no-trailing-zero: 1 - no-transition-all: 1 - no-url-protocols: 1 - placeholder-name-format: - - 1 - - convention: hyphenatedbem - property-sort-order: 0 - quotes: - - 1 - - style: single - shorthand-values: 1 - single-line-per-selector: 1 - space-after-bang: - - 1 - - include: false - space-after-colon: - - 1 - - include: true - space-after-comma: 1 - space-before-bang: - - 1 - - include: true - space-before-brace: - - 1 - - include: true - space-before-colon: 1 - space-between-parens: - - 1 - - include: false - trailing-semicolon: 1 - url-quotes: 1 - variable-name-format: - - 1 - - convention: '^[\-_a-z]+$' - convention-explanation: 'Variables must contain only lowercase letters, hyphens, and underscores' - zero-unit: 1 diff --git a/cypress/integration/app/hosts.spec.ts b/cypress/integration/app/hosts.spec.ts index 6efa1bc00..438efc984 100644 --- a/cypress/integration/app/hosts.spec.ts +++ b/cypress/integration/app/hosts.spec.ts @@ -1,27 +1,27 @@ +import * as path from "path"; -import * as path from 'path'; - -describe('Hosts page', () => { +describe("Hosts page", () => { beforeEach(() => { cy.setup(); cy.login(); }); - it('Add new host', () => { - cy.visit('/'); + it("Add new host", () => { + cy.visit("/"); - cy.contains('button', /add new host/i) - .click(); + cy.contains("button", /add new host/i).click(); - cy.contains('a', /download/i).first() + cy.contains("a", /download/i) + .first() .click(); cy.get('a[href*="showSecret"]').click(); // Assert enroll secret downloaded matches the one displayed - cy.readFile(path.join(Cypress.config('downloadsFolder'), 'secret.txt'), { timeout: 3000 }) - .then((contents) => { - cy.get('input[disabled]').should('have.value', contents); - }); + cy.readFile(path.join(Cypress.config("downloadsFolder"), "secret.txt"), { + timeout: 3000, + }).then((contents) => { + cy.get("input[disabled]").should("have.value", contents); + }); }); }); diff --git a/cypress/integration/app/labelflow.spec.ts b/cypress/integration/app/labelflow.spec.ts index e7681303a..e685afdb9 100644 --- a/cypress/integration/app/labelflow.spec.ts +++ b/cypress/integration/app/labelflow.spec.ts @@ -1,59 +1,59 @@ -describe('Label flow', () => { +describe("Label flow", () => { beforeEach(() => { cy.setup(); cy.login(); }); - it('Create, edit, and delete a label successfully', () => { - cy.visit('/hosts/manage'); + it("Create, edit, and delete a label successfully", () => { + cy.visit("/hosts/manage"); - cy.findByRole('button', { name: /add new label/i }).click(); + cy.findByRole("button", { name: /add new label/i }).click(); // Using class selector because third party element doesn't work with Cypress Testing Selector Library - cy.get('.ace_content') + cy.get(".ace_content") .click() - .type('{selectall}{backspace}SELECT * FROM users;'); + .type("{selectall}{backspace}SELECT * FROM users;"); - cy.findByLabelText(/name/i).click().type('Show all users'); + cy.findByLabelText(/name/i).click().type("Show all users"); cy.findByLabelText(/description/i) .click() - .type('Select all users across platforms.'); + .type("Select all users across platforms."); // Cannot call cy.select on div disguised as a dropdown cy.findByText(/select one/i).click(); cy.findByText(/all platforms/i).click(); - cy.findByRole('button', { name: /save label/i }).click(); + cy.findByRole("button", { name: /save label/i }).click(); cy.findByText(/show all users/i).click(); - cy.contains('button', /edit/i).click(); + cy.contains("button", /edit/i).click(); // Label SQL not editable to test cy.findByLabelText(/name/i) .click() - .type('{selectall}{backspace}Show all usernames'); + .type("{selectall}{backspace}Show all usernames"); cy.findByLabelText(/description/i) .click() - .type('{selectall}{backspace}Select all usernames on Mac.'); + .type("{selectall}{backspace}Select all usernames on Mac."); cy.findByText(/select one/i).click(); cy.findAllByText(/macos/i).click(); - cy.findByRole('button', { name: /update label/i }).click(); + cy.findByRole("button", { name: /update label/i }).click(); - cy.findByRole('button', { name: /delete/i }).click(); + cy.findByRole("button", { name: /delete/i }).click(); // Can't figure out how attach findByRole onto modal button // Can't use findByText because delete button under modal - cy.get('.manage-hosts__modal-buttons > .button--alert') - .contains('button', /delete/i) + cy.get(".manage-hosts__modal-buttons > .button--alert") + .contains("button", /delete/i) .click(); - cy.findByText(/show all users/i).should('not.exist'); + cy.findByText(/show all users/i).should("not.exist"); }); }); diff --git a/cypress/integration/app/packflow.spec.ts b/cypress/integration/app/packflow.spec.ts index 089faf999..f554af062 100644 --- a/cypress/integration/app/packflow.spec.ts +++ b/cypress/integration/app/packflow.spec.ts @@ -1,25 +1,25 @@ -describe('Pack flow', () => { +describe("Pack flow", () => { beforeEach(() => { cy.setup(); cy.login(); }); - it('Create, edit, and delete a pack successfully', () => { - cy.visit('/packs/manage'); + it("Create, edit, and delete a pack successfully", () => { + cy.visit("/packs/manage"); - cy.findByRole('button', { name: /create new pack/i }).click(); + cy.findByRole("button", { name: /create new pack/i }).click(); cy.findByLabelText(/query pack title/i) .click() - .type('Errors and crashes'); + .type("Errors and crashes"); cy.findByLabelText(/query pack description/i) .click() - .type('See all user errors and window crashes.'); + .type("See all user errors and window crashes."); - cy.findByRole('button', { name: /save query pack/i }).click(); + cy.findByRole("button", { name: /save query pack/i }).click(); - cy.visit('/packs/manage'); + cy.visit("/packs/manage"); cy.findByText(/errors and crashes/i).click(); @@ -27,28 +27,28 @@ describe('Pack flow', () => { cy.findByLabelText(/query pack title/i) .click() - .type('{selectall}{backspace}Server errors'); + .type("{selectall}{backspace}Server errors"); cy.findByLabelText(/query pack description/i) .click() - .type('{selectall}{backspace}See all server errors.'); + .type("{selectall}{backspace}See all server errors."); - cy.findByRole('button', { name: /save/i }).click(); + cy.findByRole("button", { name: /save/i }).click(); - cy.visit('/packs/manage'); + cy.visit("/packs/manage"); - cy.get('#select-pack-1').check({ force: true }); + cy.get("#select-pack-1").check({ force: true }); - cy.findByRole('button', { name: /delete/i }).click(); + cy.findByRole("button", { name: /delete/i }).click(); // Can't figure out how attach findByRole onto modal button // Can't use findByText because delete button under modal - cy.get('.all-packs-page__modal-btn-wrap > .button--alert') - .contains('button', /delete/i) + cy.get(".all-packs-page__modal-btn-wrap > .button--alert") + .contains("button", /delete/i) .click(); - cy.findByText(/successfully deleted/i).should('be.visible'); + cy.findByText(/successfully deleted/i).should("be.visible"); - cy.findByText(/server errors/i).should('not.exist'); + cy.findByText(/server errors/i).should("not.exist"); }); }); diff --git a/cypress/integration/app/queryflow.spec.ts b/cypress/integration/app/queryflow.spec.ts index 041611803..2a4664b20 100644 --- a/cypress/integration/app/queryflow.spec.ts +++ b/cypress/integration/app/queryflow.spec.ts @@ -1,63 +1,66 @@ -describe('Query flow', () => { +describe("Query flow", () => { beforeEach(() => { cy.setup(); cy.login(); }); - it('Create, check, edit, and delete a query successfully', () => { - cy.visit('/queries/manage'); + it("Create, check, edit, and delete a query successfully", () => { + cy.visit("/queries/manage"); - cy.findByRole('button', { name: /create new query/i }).click(); + cy.findByRole("button", { name: /create new query/i }).click(); - cy.findByLabelText(/query title/i).click().type('Query all window crashes'); + cy.findByLabelText(/query title/i) + .click() + .type("Query all window crashes"); // Using class selector because third party element doesn't work with Cypress Testing Selector Library - cy.get('.ace_content') + cy.get(".ace_content") .click() - .type('{selectall}{backspace}SELECT * FROM windows_crashes;'); + .type("{selectall}{backspace}SELECT * FROM windows_crashes;"); - cy.findByLabelText(/description/i).click().type('See all window crashes'); + cy.findByLabelText(/description/i) + .click() + .type("See all window crashes"); - cy.findByRole('button', { name: /save/i }).click(); + cy.findByRole("button", { name: /save/i }).click(); - cy.findByRole('button', { name: /save as new/i }).click(); + cy.findByRole("button", { name: /save as new/i }).click(); // Just refreshes to create new query, needs success alert to user that they created a query - cy.visit('/queries/manage'); + cy.visit("/queries/manage"); cy.findByText(/query all/i).click(); - cy.findByRole('button', { name: /edit or run query/i }).click(); + cy.findByRole("button", { name: /edit or run query/i }).click(); - cy.get('.ace_content') + cy.get(".ace_content") .click() .type( - '{selectall}{backspace}SELECT datetime, username FROM windows_crashes;', + "{selectall}{backspace}SELECT datetime, username FROM windows_crashes;" ); - cy.findByRole('button', { name: /save/i }).click(); + cy.findByRole("button", { name: /save/i }).click(); - cy.findByRole('button', { name: /save changes/i }).click(); + cy.findByRole("button", { name: /save changes/i }).click(); - cy.findByText(/query updated/i).should('be.visible'); + cy.findByText(/query updated/i).should("be.visible"); - cy.visit('/queries/manage'); + cy.visit("/queries/manage"); // This element has no label, text, or role - cy.get('#query-checkbox-1') - .check({ force: true }); + cy.get("#query-checkbox-1").check({ force: true }); - cy.findByRole('button', { name: /delete/i }).click(); + cy.findByRole("button", { name: /delete/i }).click(); // Can't figure out how attach findByRole onto modal button // Can't use findByText because delete button under modal - cy.get('.manage-queries-page__modal-btn-wrap > .button--alert') - .contains('button', /delete/i) + cy.get(".manage-queries-page__modal-btn-wrap > .button--alert") + .contains("button", /delete/i) .click(); - cy.findByText(/successfully deleted/i).should('be.visible'); + cy.findByText(/successfully deleted/i).should("be.visible"); - cy.findByText(/query all/i).should('not.exist'); + cy.findByText(/query all/i).should("not.exist"); }); }); diff --git a/cypress/integration/sessions/sessions.spec.ts b/cypress/integration/sessions/sessions.spec.ts index dda6ff86a..fa17ebc57 100644 --- a/cypress/integration/sessions/sessions.spec.ts +++ b/cypress/integration/sessions/sessions.spec.ts @@ -1,51 +1,43 @@ -describe('Sessions', () => { +describe("Sessions", () => { // Typically we want to use a beforeEach but not much happens in these tests // so sharing some state should be okay and saves a bit of runtime. before(() => { cy.setup(); }); - it('Logs in and out successfully', () => { - cy.visit('/'); + it("Logs in and out successfully", () => { + cy.visit("/"); cy.contains(/forgot password/i); // Log in - cy.get('input').first() - .type('test@fleetdm.com'); - cy.get('input').last() - .type('admin123#'); - cy.get('button') - .click(); + cy.get("input").first().type("test@fleetdm.com"); + cy.get("input").last().type("admin123#"); + cy.get("button").click(); // Verify dashboard - cy.url().should('include', '/hosts/manage'); - cy.contains('All Hosts'); + cy.url().should("include", "/hosts/manage"); + cy.contains("All Hosts"); // Log out - cy.findByAltText(/user avatar/i) - .click(); - cy.contains('button', 'Sign out') - .click(); + cy.findByAltText(/user avatar/i).click(); + cy.contains("button", "Sign out").click(); - cy.url().should('match', /\/login$/); + cy.url().should("match", /\/login$/); }); - it('Fails login with invalid password', () => { - cy.visit('/'); - cy.get('input').first() - .type('test@fleetdm.com'); - cy.get('input').last() - .type('bad_password'); - cy.get('.button') - .click(); + it("Fails login with invalid password", () => { + cy.visit("/"); + cy.get("input").first().type("test@fleetdm.com"); + cy.get("input").last().type("bad_password"); + cy.get(".button").click(); - cy.url().should('match', /\/login$/); - cy.contains('Authentication failed'); + cy.url().should("match", /\/login$/); + cy.contains("Authentication failed"); }); - it('Fails to access authenticated resource', () => { - cy.visit('/hosts/manage'); + it("Fails to access authenticated resource", () => { + cy.visit("/hosts/manage"); - cy.url().should('match', /\/login$/); + cy.url().should("match", /\/login$/); }); }); diff --git a/cypress/integration/sessions/sso.spec.ts b/cypress/integration/sessions/sso.spec.ts index 7251375e5..c295d4ecb 100644 --- a/cypress/integration/sessions/sso.spec.ts +++ b/cypress/integration/sessions/sso.spec.ts @@ -1,65 +1,59 @@ -describe('SSO Sessions', () => { +describe("SSO Sessions", () => { beforeEach(() => { cy.setup(); }); - it('Can login with username/password', () => { + it("Can login with username/password", () => { cy.login(); - cy.setupSSO(enable_idp_login = true); + cy.setupSSO((enable_idp_login = true)); cy.logout(); - cy.visit('/'); + cy.visit("/"); cy.contains(/forgot password/i); // Log in - cy.get('input').first() - .type('test@fleetdm.com'); - cy.get('input').last() - .type('admin123#'); - cy.contains('button', 'Login') - .click(); + cy.get("input").first().type("test@fleetdm.com"); + cy.get("input").last().type("admin123#"); + cy.contains("button", "Login").click(); // Verify dashboard - cy.url().should('include', '/hosts/manage'); - cy.contains('All Hosts'); + cy.url().should("include", "/hosts/manage"); + cy.contains("All Hosts"); // Log out - cy.findByAltText(/user avatar/i) - .click(); - cy.contains('button', 'Sign out') - .click(); + cy.findByAltText(/user avatar/i).click(); + cy.contains("button", "Sign out").click(); - cy.url().should('match', /\/login$/); + cy.url().should("match", /\/login$/); }); - it('Can login via SSO', () => { + it("Can login via SSO", () => { cy.login(); - cy.setupSSO(enable_idp_login = true); + cy.setupSSO((enable_idp_login = true)); cy.logout(); - - cy.visit('/'); + cy.visit("/"); // Log in - cy.contains('button', 'Sign On With SimpleSAML'); + cy.contains("button", "Sign On With SimpleSAML"); cy.loginSSO(); - cy.contains('All hosts'); + cy.contains("All hosts"); }); - it('Fails when IdP login disabled', () => { + it("Fails when IdP login disabled", () => { cy.login(); cy.setupSSO(); cy.logout(); - cy.visit('/'); + cy.visit("/"); - cy.contains('button', 'Sign On With SimpleSAML'); + cy.contains("button", "Sign On With SimpleSAML"); cy.loginSSO(); // Log in should fail - cy.contains('Password'); + cy.contains("Password"); }); }); diff --git a/cypress/integration/setup/setup.spec.ts b/cypress/integration/setup/setup.spec.ts index eb660fe98..f7390a65f 100644 --- a/cypress/integration/setup/setup.spec.ts +++ b/cypress/integration/setup/setup.spec.ts @@ -1,46 +1,41 @@ -describe('Setup', () => { +describe("Setup", () => { // Different than normal beforeEach because we don't run the fleetctl setup. beforeEach(() => { - cy.exec('make e2e-reset-db', { timeout: 5000 }); + cy.exec("make e2e-reset-db", { timeout: 5000 }); }); - it('Completes setup', () => { - cy.visit('/'); - cy.url().should('match', /\/setup$/); + it("Completes setup", () => { + cy.visit("/"); + cy.url().should("match", /\/setup$/); cy.contains(/setup/i); // Page 1 - cy.findByPlaceholderText(/username/i) - .type('test'); + cy.findByPlaceholderText(/username/i).type("test"); - cy.findByPlaceholderText(/^password/i).first() - .type('admin123#'); + cy.findByPlaceholderText(/^password/i) + .first() + .type("admin123#"); - cy.findByPlaceholderText(/confirm password/i).last() - .type('admin123#'); + cy.findByPlaceholderText(/confirm password/i) + .last() + .type("admin123#"); - cy.findByPlaceholderText(/email/i) - .type('test@fleetdm.com'); + cy.findByPlaceholderText(/email/i).type("test@fleetdm.com"); - cy.contains('button:enabled', /next/i) - .click(); + cy.contains("button:enabled", /next/i).click(); // Page 2 - cy.findByPlaceholderText(/organization name/i) - .type('Fleet Test'); + cy.findByPlaceholderText(/organization name/i).type("Fleet Test"); - cy.contains('button:enabled', /next/i) - .click(); + cy.contains("button:enabled", /next/i).click(); // Page 3 - cy.contains('button:enabled', /submit/i) - .click(); + cy.contains("button:enabled", /submit/i).click(); // Page 4 - cy.contains('button:enabled', /finish/i) - .click(); + cy.contains("button:enabled", /finish/i).click(); - cy.url().should('match', /\/hosts\/manage$/i); + cy.url().should("match", /\/hosts\/manage$/i); cy.contains(/all hosts/i); }); }); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 7a646c621..800638d61 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -1,4 +1,4 @@ -import '@testing-library/cypress/add-commands'; +import "@testing-library/cypress/add-commands"; // *********************************************** // This example commands.js shows you how to @@ -26,85 +26,89 @@ import '@testing-library/cypress/add-commands'; // -- This will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) -Cypress.Commands.add('setup', () => { - cy.exec('make e2e-reset-db e2e-setup', { timeout: 20000 }); +Cypress.Commands.add("setup", () => { + cy.exec("make e2e-reset-db e2e-setup", { timeout: 20000 }); }); -Cypress.Commands.add('login', (username, password) => { - username ||= 'test'; - password ||= 'admin123#'; - cy.request('POST', '/api/v1/fleet/login', { username, password }) - .then((resp) => { - window.localStorage.setItem('KOLIDE::auth_token', resp.body.token); - }); +Cypress.Commands.add("login", (username, password) => { + username ||= "test"; + password ||= "admin123#"; + cy.request("POST", "/api/v1/fleet/login", { username, password }).then( + (resp) => { + window.localStorage.setItem("KOLIDE::auth_token", resp.body.token); + } + ); }); -Cypress.Commands.add('logout', () => { +Cypress.Commands.add("logout", () => { cy.request({ - url: '/api/v1/fleet/logout', - method: 'POST', + url: "/api/v1/fleet/logout", + method: "POST", body: {}, auth: { - bearer: window.localStorage.getItem('KOLIDE::auth_token'), + bearer: window.localStorage.getItem("KOLIDE::auth_token"), }, }); }); -Cypress.Commands.add('setupSSO', (enable_idp_login = false) => { +Cypress.Commands.add("setupSSO", (enable_idp_login = false) => { const body = { sso_settings: { enable_sso: true, enable_sso_idp_login: enable_idp_login, - entity_id: 'https://localhost:8080', - idp_name: 'SimpleSAML', - issuer_uri: 'http://localhost:8080/simplesaml/saml2/idp/SSOService.php', - metadata_url: 'http://localhost:9080/simplesaml/saml2/idp/metadata.php', + entity_id: "https://localhost:8080", + idp_name: "SimpleSAML", + issuer_uri: "http://localhost:8080/simplesaml/saml2/idp/SSOService.php", + metadata_url: "http://localhost:9080/simplesaml/saml2/idp/metadata.php", }, }; cy.request({ - url: '/api/v1/fleet/config', - method: 'PATCH', + url: "/api/v1/fleet/config", + method: "PATCH", body, auth: { - bearer: window.localStorage.getItem('KOLIDE::auth_token'), + bearer: window.localStorage.getItem("KOLIDE::auth_token"), }, }); }); -Cypress.Commands.add('loginSSO', () => { +Cypress.Commands.add("loginSSO", () => { // Note these requests set cookies that are required for the SSO flow to // work properly. This is handled automatically by the browser. cy.request({ - method: 'GET', - url: 'http://localhost:9080/simplesaml/saml2/idp/SSOService.php?spentityid=https://localhost:8080', + method: "GET", + url: + "http://localhost:9080/simplesaml/saml2/idp/SSOService.php?spentityid=https://localhost:8080", followRedirect: false, }).then((firstResponse) => { const redirect = firstResponse.headers.location; cy.request({ - method: 'GET', + method: "GET", url: redirect, followRedirect: false, }).then((secondResponse) => { - const el = document.createElement('html'); + const el = document.createElement("html"); el.innerHTML = secondResponse.body; - const authState = el.getElementsByTagName('input').namedItem('AuthState').defaultValue; + const authState = el.getElementsByTagName("input").namedItem("AuthState") + .defaultValue; cy.request({ - method: 'POST', + method: "POST", url: redirect, body: `username=user1&password=user1pass&AuthState=${authState}`, form: true, followRedirect: false, }).then((finalResponse) => { el.innerHTML = finalResponse.body; - const saml = el.getElementsByTagName('input').namedItem('SAMLResponse').defaultValue; + const saml = el.getElementsByTagName("input").namedItem("SAMLResponse") + .defaultValue; // Load the callback URL with the response from the IdP cy.visit({ - url: '/api/v1/fleet/sso/callback', - method: 'POST', + url: "/api/v1/fleet/sso/callback", + method: "POST", body: { SAMLResponse: saml, }, diff --git a/cypress/support/index.js b/cypress/support/index.js index 37a498fb5..d076cec9f 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -14,7 +14,7 @@ // *********************************************************** // Import commands.js using ES2015 syntax: -import './commands'; +import "./commands"; // Alternatively you can use CommonJS syntax: // require('./commands') diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json index 1b532cc84..74b7cb33d 100644 --- a/cypress/tsconfig.json +++ b/cypress/tsconfig.json @@ -4,7 +4,5 @@ "lib": ["es5", "dom"], "types": ["cypress", "@testing-library/cypress", "node"] }, - "include": [ - "**/*.ts" - ] + "include": ["**/*.ts"] } diff --git a/frontend/__mocks__/fileMock.js b/frontend/__mocks__/fileMock.js index 59890f6a2..ea1367c1e 100644 --- a/frontend/__mocks__/fileMock.js +++ b/frontend/__mocks__/fileMock.js @@ -1,3 +1,3 @@ // __mocks__/fileMock.js -module.exports = 'test-file-stub'; +module.exports = "test-file-stub"; diff --git a/frontend/app_constants/APP_SETTINGS.js b/frontend/app_constants/APP_SETTINGS.js index 2cc557cb1..bcf94ab6a 100644 --- a/frontend/app_constants/APP_SETTINGS.js +++ b/frontend/app_constants/APP_SETTINGS.js @@ -1,4 +1,4 @@ export default { - FAKE_PASSWORD: '********', - DEFAULT_SMTP_PORT: '587', + FAKE_PASSWORD: "********", + DEFAULT_SMTP_PORT: "587", }; diff --git a/frontend/app_constants/index.js b/frontend/app_constants/index.js index d789e5275..6bfd5fb5c 100644 --- a/frontend/app_constants/index.js +++ b/frontend/app_constants/index.js @@ -1,6 +1,6 @@ -import APP_SETTINGS from 'app_constants/APP_SETTINGS'; -import HTTP_STATUS from 'app_constants/HTTP_STATUS'; -import PATHS from 'router/paths'; +import APP_SETTINGS from "app_constants/APP_SETTINGS"; +import HTTP_STATUS from "app_constants/HTTP_STATUS"; +import PATHS from "router/paths"; export default { APP_SETTINGS, diff --git a/frontend/components/App/App.jsx b/frontend/components/App/App.jsx index 28bd1173c..07d189dc1 100644 --- a/frontend/components/App/App.jsx +++ b/frontend/components/App/App.jsx @@ -1,13 +1,13 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { noop } from 'lodash'; -import classnames from 'classnames'; +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { noop } from "lodash"; +import classnames from "classnames"; -import { authToken } from 'utilities/local'; -import { fetchCurrentUser } from 'redux/nodes/auth/actions'; -import { getConfig, getEnrollSecret } from 'redux/nodes/app/actions'; -import userInterface from 'interfaces/user'; +import { authToken } from "utilities/local"; +import { fetchCurrentUser } from "redux/nodes/auth/actions"; +import { getConfig, getEnrollSecret } from "redux/nodes/app/actions"; +import userInterface from "interfaces/user"; export class App extends Component { static propTypes = { @@ -20,47 +20,36 @@ export class App extends Component { dispatch: noop, }; - componentWillMount () { + componentWillMount() { const { dispatch, user } = this.props; if (!user && authToken()) { - dispatch(fetchCurrentUser()) - .catch(() => false); + dispatch(fetchCurrentUser()).catch(() => false); } if (user) { - dispatch(getConfig()) - .catch(() => false); - dispatch(getEnrollSecret()) - .catch(() => false); + dispatch(getConfig()).catch(() => false); + dispatch(getEnrollSecret()).catch(() => false); } return false; } - componentWillReceiveProps (nextProps) { + componentWillReceiveProps(nextProps) { const { dispatch, user } = nextProps; if (user && this.props.user !== user) { - dispatch(getConfig()) - .catch(() => false); - dispatch(getEnrollSecret()) - .catch(() => false); + dispatch(getConfig()).catch(() => false); + dispatch(getEnrollSecret()).catch(() => false); } } - render () { + render() { const { children } = this.props; - const wrapperStyles = classnames( - 'wrapper', - ); + const wrapperStyles = classnames("wrapper"); - return ( -
{error || label}
- ); - } + return{error || label}
; + }; renderHint = () => { const { hint } = this.props; @@ -55,9 +53,9 @@ class KolideAce extends Component { } return false; - } + }; - render () { + render() { const { error, fontSize, @@ -78,7 +76,7 @@ class KolideAce extends Component { }); const fixHotkeys = (editor) => { - editor.commands.removeCommands(['gotoline', 'find']); + editor.commands.removeCommands(["gotoline", "find"]); onLoad && onLoad(editor); }; @@ -104,11 +102,13 @@ class KolideAce extends Component { value={value} width="100%" wrapEnabled={wrapEnabled} - commands={[{ - name: 'commandName', - bindKey: { win: 'Ctrl-Enter', mac: 'Ctrl-Enter' }, - exec: handleSubmit, - }]} + commands={[ + { + name: "commandName", + bindKey: { win: "Ctrl-Enter", mac: "Ctrl-Enter" }, + exec: handleSubmit, + }, + ]} /> {renderHint()} diff --git a/frontend/components/KolideAce/_styles.scss b/frontend/components/KolideAce/_styles.scss index 03f019daf..39abb791b 100644 --- a/frontend/components/KolideAce/_styles.scss +++ b/frontend/components/KolideAce/_styles.scss @@ -29,7 +29,7 @@ color: $core-blue; background-color: $ui-light-grey; padding: 2px; - font-family: 'SourceCodePro', $monospace; + font-family: "SourceCodePro", $monospace; } } } diff --git a/frontend/components/KolideAce/index.js b/frontend/components/KolideAce/index.js index ea2dc7bcb..9e9d6cef0 100644 --- a/frontend/components/KolideAce/index.js +++ b/frontend/components/KolideAce/index.js @@ -1 +1 @@ -export { default } from './KolideAce'; +export { default } from "./KolideAce"; diff --git a/frontend/components/KolideAce/mode.js b/frontend/components/KolideAce/mode.js index c9528b566..8b91afda5 100644 --- a/frontend/components/KolideAce/mode.js +++ b/frontend/components/KolideAce/mode.js @@ -1,105 +1,138 @@ /* eslint-disable */ -import { osqueryTableNames } from 'utilities/osquery_tables'; +import { osqueryTableNames } from "utilities/osquery_tables"; -ace.define("ace/mode/kolide_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/sql_highlight_rules"], function(acequire, exports, module) { - "use strict"; +ace.define( + "ace/mode/kolide_highlight_rules", + [ + "require", + "exports", + "module", + "ace/lib/oop", + "ace/mode/sql_highlight_rules", + ], + function (acequire, exports, module) { + "use strict"; - var oop = acequire("../lib/oop"); - var SqlHighlightRules = acequire("./sql_highlight_rules").SqlHighlightRules; + var oop = acequire("../lib/oop"); + var SqlHighlightRules = acequire("./sql_highlight_rules").SqlHighlightRules; - var KolideHighlightRules = function() { - var keywords = ( + var KolideHighlightRules = function () { + var keywords = "select|insert|update|delete|from|where|and|or|group|by|order|limit|offset|having|as|case|" + "when|else|end|type|left|right|join|on|outer|desc|asc|union|create|table|primary|key|if|" + - "foreign|not|references|default|null|inner|cross|natural|database|drop|grant" - ); + "foreign|not|references|default|null|inner|cross|natural|database|drop|grant"; - var builtinConstants = ( - "true|false" - ); + var builtinConstants = "true|false"; - var builtinFunctions = ( + var builtinFunctions = "avg|count|first|last|max|min|sum|ucase|lcase|mid|len|round|rank|now|format|" + - "coalesce|ifnull|isnull|nvl" - ); + "coalesce|ifnull|isnull|nvl"; - var dataTypes = ( + var dataTypes = "int|numeric|decimal|date|varchar|char|bigint|float|double|bit|binary|text|set|timestamp|" + - "money|real|number|integer" - ); + "money|real|number|integer"; - var osqueryTables = osqueryTableNames.join('|'); + var osqueryTables = osqueryTableNames.join("|"); - var keywordMapper = this.createKeywordMapper({ - "osquery-token": osqueryTables, - "support.function": builtinFunctions, - "keyword": keywords, - "constant.language": builtinConstants, - "storage.type": dataTypes, - }, "identifier", true); + var keywordMapper = this.createKeywordMapper( + { + "osquery-token": osqueryTables, + "support.function": builtinFunctions, + keyword: keywords, + "constant.language": builtinConstants, + "storage.type": dataTypes, + }, + "identifier", + true + ); - this.$rules = { - "start" : [{ - token : "comment", - regex : "--.*$" - }, { - token : "comment", - start : "/\\*", - end : "\\*/" - }, { - token : "string", // " string - regex : '".*?"' - }, { - token : "string", // ' string - regex : "'.*?'" - }, { - token : "constant.numeric", // float - regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" - }, { - token : keywordMapper, - regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" - }, { - token : "keyword.operator", - regex : "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=" - }, { - token : "paren.lparen", - regex : "[\\(]" - }, { - token : "paren.rparen", - regex : "[\\)]" - }, { - token : "text", - regex : "\\s+" - }] + this.$rules = { + start: [ + { + token: "comment", + regex: "--.*$", + }, + { + token: "comment", + start: "/\\*", + end: "\\*/", + }, + { + token: "string", // " string + regex: '".*?"', + }, + { + token: "string", // ' string + regex: "'.*?'", + }, + { + token: "constant.numeric", // float + regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b", + }, + { + token: keywordMapper, + regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b", + }, + { + token: "keyword.operator", + regex: + "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=", + }, + { + token: "paren.lparen", + regex: "[\\(]", + }, + { + token: "paren.rparen", + regex: "[\\)]", + }, + { + token: "text", + regex: "\\s+", + }, + ], + }; + + this.normalizeRules(); }; - this.normalizeRules(); - }; + oop.inherits(KolideHighlightRules, SqlHighlightRules); - oop.inherits(KolideHighlightRules, SqlHighlightRules); + exports.KolideHighlightRules = KolideHighlightRules; + } +); - exports.KolideHighlightRules = KolideHighlightRules; -}); +ace.define( + "ace/mode/kolide", + [ + "require", + "exports", + "module", + "ace/lib/oop", + "ace/mode/sql", + "ace/mode/kolide_highlight_rules", + "ace/range", + ], + function (acequire, exports, module) { + "use strict"; -ace.define("ace/mode/kolide",["require","exports","module","ace/lib/oop","ace/mode/sql","ace/mode/kolide_highlight_rules","ace/range"], function(acequire, exports, module) { - "use strict"; + var oop = acequire("../lib/oop"); + var TextMode = acequire("./sql").Mode; + var KolideHighlightRules = acequire("./kolide_highlight_rules") + .KolideHighlightRules; + var Range = acequire("../range").Range; - var oop = acequire("../lib/oop"); - var TextMode = acequire("./sql").Mode; - var KolideHighlightRules = acequire("./kolide_highlight_rules").KolideHighlightRules; - var Range = acequire("../range").Range; + var Mode = function () { + this.HighlightRules = KolideHighlightRules; + }; + oop.inherits(Mode, TextMode); - var Mode = function() { - this.HighlightRules = KolideHighlightRules; - }; - oop.inherits(Mode, TextMode); + (function () { + this.lineCommentStart = "--"; - (function() { + this.$id = "ace/mode/kolide"; + }.call(Mode.prototype)); - this.lineCommentStart = "--"; - - this.$id = "ace/mode/kolide"; - }).call(Mode.prototype); - - exports.Mode = Mode; -}); + exports.Mode = Mode; + } +); diff --git a/frontend/components/KolideAce/theme.css b/frontend/components/KolideAce/theme.css index 9a74d0176..e3b3f9005 100644 --- a/frontend/components/KolideAce/theme.css +++ b/frontend/components/KolideAce/theme.css @@ -1,10 +1,10 @@ .ace_editor.ace-kolide { - font-family: 'SourceCodePro', monospace; + font-family: "SourceCodePro", monospace; font-size: 14px; - background-color: #FAFAFA; + background-color: #fafafa; color: #66696f; border-radius: 4px; - border: solid 1px #DBE3E5; + border: solid 1px #dbe3e5; line-height: 24px; } @@ -21,7 +21,7 @@ } .ace-kolide.ace_autocomplete .ace_content { - padding-left: 0px; + padding-left: 0px; } .ace-kolide .ace_content { @@ -33,7 +33,7 @@ background: #fff; color: #c38dec; z-index: 1; - border-right: solid 1px #E3E3E3; + border-right: solid 1px #e3e3e3; } .ace-kolide .ace_gutter-active-line { @@ -55,12 +55,12 @@ } .ace-kolide .ace_cursor { - color: #aeafad + color: #aeafad; } /* Hide cursor in read-only mode */ .ace-kolide .ace_hidden-cursors { - opacity:0 + opacity: 0; } .ace-kolide .ace_marker-layer .ace_selection { @@ -72,20 +72,20 @@ } .ace-kolide .ace_marker-layer .ace_step { - background: rgb(255, 255, 0) + background: rgb(255, 255, 0); } .ace-kolide .ace_marker-layer .ace_bracket { margin: -1px 0 0 -1px; - border: 1px solid #d1d1d1 + border: 1px solid #d1d1d1; } .ace-kolide .ace_marker-layer .ace_selected-word { - border: 1px solid #d6d6d6 + border: 1px solid #d6d6d6; } .ace-kolide .ace_invisible { - color: #d1d1d1 + color: #d1d1d1; } .ace-kolide .ace_keyword { @@ -93,7 +93,7 @@ font-weight: 600; } -.ace-kolide .ace_osquery-token{ +.ace-kolide .ace_osquery-token { border-radius: 3px; background-color: #ae6ddf; color: #ffffff; @@ -111,11 +111,11 @@ .ace-kolide .ace_storage, .ace-kolide .ace_storage.ace_type, .ace-kolide .ace_support.ace_type { - color: #8959a8 + color: #8959a8; } .ace-kolide .ace_keyword.ace_operator { - color: #3e999f + color: #3e999f; } .ace-kolide .ace_constant.ace_character, @@ -124,43 +124,43 @@ .ace-kolide .ace_keyword.ace_other.ace_unit, .ace-kolide .ace_support.ace_constant, .ace-kolide .ace_variable.ace_parameter { - color: #f5871f + color: #f5871f; } .ace-kolide .ace_constant.ace_other { - color: #666969 + color: #666969; } .ace-kolide .ace_invalid { color: #ffffff; - background-color: #c82829 + background-color: #c82829; } .ace-kolide .ace_invalid.ace_deprecated { color: #ffffff; - background-color: #ae6ddf + background-color: #ae6ddf; } .ace-kolide .ace_fold { background-color: #4271ae; - border-color: #4d4d4c + border-color: #4d4d4c; } .ace-kolide .ace_entity.ace_name.ace_function, .ace-kolide .ace_support.ace_function, .ace-kolide .ace_variable { - color: #4271ae + color: #4271ae; } .ace-kolide .ace_support.ace_class, .ace-kolide .ace_support.ace_type { - color: #c99e00 + color: #c99e00; } .ace-kolide .ace_heading, .ace-kolide .ace_markup.ace_heading, .ace-kolide .ace_string { - color: #4fd061 + color: #4fd061; } .ace-kolide .ace_entity.ace_name.ace_tag, @@ -168,13 +168,14 @@ .ace-kolide .ace_meta.ace_tag, .ace-kolide .ace_string.ace_regexp, .ace-kolide .ace_variable { - color: #c82829 + color: #c82829; } .ace-kolide .ace_comment { - color: #8e908c + color: #8e908c; } .ace-kolide .ace_indent-guide { - background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bdu3f/BwAlfgctduB85QAAAABJRU5ErkJggg==) right repeat-y + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bdu3f/BwAlfgctduB85QAAAABJRU5ErkJggg==) + right repeat-y; } diff --git a/frontend/components/KolideAce/theme.js b/frontend/components/KolideAce/theme.js index 8c991c604..ac219e50f 100644 --- a/frontend/components/KolideAce/theme.js +++ b/frontend/components/KolideAce/theme.js @@ -1,10 +1,13 @@ /* eslint-disable */ -ace.define("ace/theme/kolide",["require","exports","module","ace/lib/dom"], function(acequire, exports, module) { +ace.define( + "ace/theme/kolide", + ["require", "exports", "module", "ace/lib/dom"], + function (acequire, exports, module) { + exports.isDark = false; + exports.cssClass = "ace-kolide"; + exports.cssText = require("./theme.css"); - exports.isDark = false; - exports.cssClass = "ace-kolide"; - exports.cssText = require('./theme.css'); - -var dom = acequire("../lib/dom"); -dom.importCssString(exports.cssText, exports.cssClass); -}); + var dom = acequire("../lib/dom"); + dom.importCssString(exports.cssText, exports.cssClass); + } +); diff --git a/frontend/components/LoginRoutes/LoginRoutes.jsx b/frontend/components/LoginRoutes/LoginRoutes.jsx index a84e2f010..382ddbd61 100644 --- a/frontend/components/LoginRoutes/LoginRoutes.jsx +++ b/frontend/components/LoginRoutes/LoginRoutes.jsx @@ -1,10 +1,10 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; -import { hideBackgroundImage } from 'redux/nodes/app/actions'; -import { ssoSettings } from 'redux/nodes/auth/actions'; -import LoginPage from 'pages/LoginPage'; +import { hideBackgroundImage } from "redux/nodes/app/actions"; +import { ssoSettings } from "redux/nodes/auth/actions"; +import LoginPage from "pages/LoginPage"; export class LoginRoutes extends Component { static propTypes = { @@ -16,22 +16,21 @@ export class LoginRoutes extends Component { token: PropTypes.string, }; - componentWillMount () { + componentWillMount() { const { dispatch } = this.props; - dispatch(ssoSettings()) - .catch(() => false); + dispatch(ssoSettings()).catch(() => false); dispatch(hideBackgroundImage); } - componentWillUnmount () { + componentWillUnmount() { const { dispatch } = this.props; dispatch(hideBackgroundImage); } - render () { + render() { const { children, isResetPassPage, @@ -42,24 +41,27 @@ export class LoginRoutes extends Component { return ({headerText}
); - } + }; - render () { + render() { const { children, className, leadText } = this.props; - const { - isLoading, - isLoaded, - isLeaving, - } = this.state; + const { isLoading, isLoaded, isLeaving } = this.state; const { renderBackButton, renderHeader } = this; - const boxClass = classnames( - baseClass, - className, - { - [`${baseClass}--loading`]: isLoading, - [`${baseClass}--loaded`]: isLoaded, - [`${baseClass}--leaving`]: isLeaving, - }, - ); + const boxClass = classnames(baseClass, className, { + [`${baseClass}--loading`]: isLoading, + [`${baseClass}--loaded`]: isLoaded, + [`${baseClass}--leaving`]: isLeaving, + }); return ({error || label}
- ); - } + return{error || label}
; + }; render() { const { diff --git a/frontend/components/YamlAce/index.js b/frontend/components/YamlAce/index.js index 03ba88370..0af7f7769 100644 --- a/frontend/components/YamlAce/index.js +++ b/frontend/components/YamlAce/index.js @@ -1 +1 @@ -export { default } from './YamlAce'; +export { default } from "./YamlAce"; diff --git a/frontend/components/buttons/Button/Button.tsx b/frontend/components/buttons/Button/Button.tsx index bfd792253..d8327cdcc 100644 --- a/frontend/components/buttons/Button/Button.tsx +++ b/frontend/components/buttons/Button/Button.tsx @@ -1,7 +1,7 @@ -import React from 'react'; -import classnames from 'classnames'; +import React from "react"; +import classnames from "classnames"; -const baseClass = 'button'; +const baseClass = "button"; interface IButtonProps { autofocus?: boolean; @@ -12,7 +12,7 @@ interface IButtonProps { onClick: (evt: React.MouseEventI am migrating an existing osquery installation.
-Take me to the Import Configuration page.
++ I am migrating an existing osquery installation. +
++ Take me to the Import Configuration page. +
/v1
, ' or any other path.']}
- ref={(input) => { this.firstInput = input; }}
+ hint={[
+ "Don’t include ",
+ /v1
,
+ " or any other path.",
+ ]}
+ ref={(input) => {
+ this.firstInput = input;
+ }}
/>
Additional admins can be designated within the Fleet app.
-Verify SSL Certs - Turn this off (not recommended) if you use a self-signed certificate (Default: On)
\Enable STARTTLS - Detects if STARTTLS is enabled in your SMTP server and starts to use it. (Default: On)
\Host Expiry - When enabled, allows automatic cleanup of hosts that have not communicated with Fleet in some number of days. (Default: Off)
\Host Expiry Window - If a host has not communicated with Fleet in the specified number of days, it will be removed.
\Disable Live Queries - When enabled, disables the ability to run live queries (ad hoc queries executed via the UI or fleetctl). (Default: Off)
\ - '} + ' + } />/v1
)}
+ hint={
+
+ Include base path only (eg. no /v1
)
+
+ }
/>
No Authentication - Select this if your SMTP is open.
\Username & Password - Select this if your SMTP server requires authentication with a username and password.
\ - '} + " + } />
Manage secrets with fleetctl
. Active secrets:
@@ -349,13 +409,18 @@ class AppConfigForm extends Component {
YAML
-- Provide an active enroll secret to allow osquery to authenticate with the Fleet server: + Provide an active enroll secret to allow osquery to authenticate + with the Fleet server:
- Provide the TLS certificate used by the Fleet server to enable secure connections from osquery: + Provide the TLS certificate used by the Fleet server to enable + secure connections from osquery:
- { fetchCertificateError - ? {fetchCertificateError} - : Download + {fetchCertificateError ? ( + + {fetchCertificateError} + + ) : ( + + Download - } + )}
- If using the enroll secret and server certificate downloaded above, use the generated flagfile. In some configurations, modifications may need to be made: + If using the enroll secret and server certificate downloaded + above, use the generated flagfile. In some configurations, + modifications may need to be made:
- Run osquery from the directory containing the above files (may require sudo or Run as Administrator privileges): + Run osquery from the directory containing the above files (may + require sudo or Run as Administrator privileges):
osqueryd --flagfile=flagfile.txt --verbose
{pack.description}
+ |
Query name | Description | Author | @@ -116,19 +124,22 @@ class QueriesList extends Component {
---|
interval: the amount of time, in seconds, the query waits before running
-platform: the computer platform where this query will run (other platforms ignored)
-minimum
logging type:
++ interval: the amount of time, in seconds, the + query waits before running +
++ platform: the computer platform where this query + will run (other platforms ignored) +
+
+
+ minimum
+ logging type: +
+ |
Query name | Interval(s) | Platform | -
+ |
Shard | Logging |
---|
{queryText}
Description
-{pack.description || No description available}
++ {pack.description || No description available} +
- Osquery supports grouping of queries (called query packs) - which run on a scheduled basis and log the results to a configurable + Osquery supports grouping of queries (called query packs) which + run on a scheduled basis and log the results to a configurable destination.
- Query Packs are useful for monitoring specific attributes of hosts - over time and can be used for alerting and incident response - investigations. By default, queries added to packs run every hour - (interval = 3600s). + Query Packs are useful for monitoring specific attributes of hosts over + time and can be used for alerting and incident response investigations. + By default, queries added to packs run every hour ( + interval = 3600s).
-- Queries can be run in two modes: -
+Queries can be run in two modes:
- Packs are distributed to specified targets. Targets may be individual hosts or groups of hosts called labels. + Packs are distributed to specified targets. Targets may be{" "} + individual hosts or groups of hosts called labels. +
++ The results of queries run via query packs are stored in log files for + your convenience. We recommend forwarding this logs to a log aggregation + tool or other actionable tool for further analysis. These logs can be + found in the following locations:
-The results of queries run via query packs are stored in log files for your convenience. We recommend forwarding this logs to a log aggregation tool or other actionable tool for further analysis. These logs can be found in the following locations:
- Learn more about log aggregation in the documentation. + Learn more about log aggregation in the{" "} + + documentation + + .
There are no packs associated with this query
; + return ( ++ There are no packs associated with this query +
+ ); } return (Description
-{description || No description available}
++ {description || No description available} +
Packs
{renderPacks()} -{selectedQuery.description || No description available.}
++ {selectedQuery.description || No description available.} +
- Welcome to Fleet -
+Welcome to Fleet
- Before you get started, please take a moment to complete the following information. + Before you get started, please take a moment to complete the + following information.
- Welcome to Fleet -
+Welcome to Fleet
- Before you get started, please take a moment to complete the following information. + Before you get started, please take a moment to complete the + following information.
The page you are looking for has either moved, or doesn't exist.
++ The page you are looking for has either moved, or doesn't + exist. +
Get helpPlease file an issue if you believe this is a bug.
{renderError()} { const { dispatch } = this.props; - return dispatch(forgotPasswordAction(formData)) - .catch(() => false); - }) + return dispatch(forgotPasswordAction(formData)).catch(() => false); + }); clearErrors = () => { const { dispatch } = this.props; return dispatch(clearForgotPasswordErrors); - } + }; renderContent = () => { const { clearErrors, handleSubmit } = this; const { email, errors } = this.props; - const baseClass = 'forgot-password'; + const baseClass = "forgot-password"; if (email) { return ( @@ -60,8 +59,8 @@ export class ForgotPasswordPage extends Component {An email was sent to - {email}. - Click the link on the email to proceed with the password reset process. + {email}. Click the + link on the email to proceed with the password reset process.
Login successful
-Taking you to the Fleet UI...
++ Taking you to the Fleet UI... +
Role
-{roleText}
++ {roleText} +
Password
@@ -356,7 +361,9 @@ export class UserSettingsPage extends Component { > Get API token - {`Fleet ${version.version} • Go ${version.go_version}`} + {`Fleet ${version.version} • Go ${version.go_version}`}