Sentry Integration (#221)

* BE sentry setup w/ user scope

* FE sentry integration + user scope

* FE env adjustments

* FE: use NODE_ENV for Sentry

* BE: use FLASK_ENV for Sentry

* BE: remove email, acct & ip from Sentry user scope

* comment .env.example SENTRY* for CI

* fix merge artifact
This commit is contained in:
AMStrix 2018-11-21 23:45:29 -06:00 committed by Daniel Ternyak
parent 968974d8d7
commit 7abeac7bd7
12 changed files with 146 additions and 5 deletions

View File

@ -11,6 +11,7 @@ SENDGRID_API_KEY="optional, but emails won't send without it"
ETHEREUM_ENDPOINT_URI = "http://localhost:8545"
CROWD_FUND_URL = "https://eip-712.herokuapp.com/contract/crowd-fund"
CROWD_FUND_FACTORY_URL = "https://eip-712.herokuapp.com/contract/factory"
# SENTRY_DSN="https://PUBLICKEY@sentry.io/PROJECTID"
# SENTRY_RELEASE="optional, overrides git hash"
UPLOAD_DIRECTORY = "/tmp"
UPLOAD_URL = "http://localhost:5000" # for constructing download url

View File

@ -2,9 +2,12 @@
"""The app module, containing the app factory function."""
from flask import Flask
from flask_cors import CORS
from sentry_sdk.integrations.flask import FlaskIntegration
import sentry_sdk
from grant import commands, proposal, user, comment, milestone, admin, email
from grant.extensions import bcrypt, migrate, db, ma, mail, web3
from grant.settings import SENTRY_RELEASE, ENV
def create_app(config_object="grant.settings"):
@ -15,6 +18,11 @@ def create_app(config_object="grant.settings"):
register_blueprints(app)
register_shellcontext(app)
register_commands(app)
sentry_sdk.init(
environment=ENV,
release=SENTRY_RELEASE,
integrations=[FlaskIntegration()]
)
return app

View File

@ -6,8 +6,11 @@ Most configuration is set via environment variables.
For local development, use a .env file to set
environment variables.
"""
import subprocess
from environs import Env
git_revision_short_hash = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'])
env = Env()
env.read_env()
@ -29,6 +32,8 @@ SENDGRID_API_KEY = env.str("SENDGRID_API_KEY", default="")
SENDGRID_DEFAULT_FROM = "noreply@grant.io"
ETHEREUM_PROVIDER = "http"
ETHEREUM_ENDPOINT_URI = env.str("ETHEREUM_ENDPOINT_URI")
SENTRY_DSN = env.str("SENTRY_DSN", default=None)
SENTRY_RELEASE = env.str("SENTRY_RELEASE", default=git_revision_short_hash)
UPLOAD_DIRECTORY = env.str("UPLOAD_DIRECTORY")
UPLOAD_URL = env.str("UPLOAD_URL")
MAX_CONTENT_LENGTH = 5 * 1024 * 1024 # 5MB (limits file uploads, raises RequestEntityTooLarge)

View File

@ -6,6 +6,7 @@ import requests
from flask import request, g, jsonify
from itsdangerous import SignatureExpired, BadSignature
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
import sentry_sdk
from grant.settings import SECRET_KEY, AUTH_URL
from ..proposal.models import Proposal
@ -69,6 +70,10 @@ def requires_sm(f):
return jsonify(message="No user exists with address: {}".format(auth_address)), 401
g.current_user = user
with sentry_sdk.configure_scope() as scope:
scope.user = {
"id": user.id,
}
return f(*args, **kwargs)
return jsonify(message="Authentication is required to access this resource"), 401

View File

@ -60,3 +60,6 @@ flask-yolo2API==0.2.6
#web3
flask-web3==0.1.1
web3==4.8.1
#sentry
sentry-sdk[flask]==0.5.5

View File

@ -7,5 +7,11 @@ NO_DEV_TS_CHECK=true
# Set the public host url (no trailing slash)
PUBLIC_HOST_URL=https://demo.grant.io
# sentry
SENTRY_DSN="https://PUBLICKEY@sentry.io/PROJECTID"
SENTRY_RELEASE="optional, overrides git hash"
CROWD_FUND_URL = "https://eip-712.herokuapp.com/contract/crowd-fund"
CROWD_FUND_FACTORY_URL = "https://eip-712.herokuapp.com/contract/factory"
CROWD_FUND_FACTORY_URL = "https://eip-712.herokuapp.com/contract/factory"

View File

@ -6,12 +6,19 @@ import { loadComponents } from 'loadable-components';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import { PersistGate } from 'redux-persist/integration/react';
import * as Sentry from '@sentry/browser';
import { I18nextProvider } from 'react-i18next';
import { configureStore } from 'store/configure';
import { massageSerializedState } from 'utils/api';
import Routes from './Routes';
import i18n from './i18n';
Sentry.init({
dsn: process.env.SENTRY_DSN,
release: process.env.SENTRY_RELEASE,
environment: process.env.NODE_ENV,
});
const initialState =
window && massageSerializedState((window as any).__PRELOADED_STATE__);
const { store, persistor } = configureStore(initialState);

View File

@ -1,5 +1,6 @@
import types from './types';
import { Dispatch } from 'redux';
import * as Sentry from '@sentry/browser';
import { sleep } from 'utils/helpers';
import { generateAuthSignatureData } from 'utils/auth';
import { AppState } from 'store/reducers';
@ -37,7 +38,13 @@ export function authUser(address: string, authSignature?: Falsy | AuthSignatureD
signedMessage: authSignature.signedMessage,
rawTypedData: JSON.stringify(authSignature.rawTypedData),
});
// sentry user scope
Sentry.configureScope(scope => {
scope.setUser({
email: res.data.emailAddress,
accountAddress: res.data.ethAddress,
});
});
dispatch({
type: types.AUTH_USER_FULFILLED,
payload: {

View File

@ -1,9 +1,15 @@
const fs = require('fs');
const path = require('path');
const paths = require('./paths');
const childProcess = require('child_process');
delete require.cache[require.resolve('./paths')];
const gitRevisionShortHash = childProcess
.execSync('git rev-parse --short HEAD')
.toString()
.trim();
if (!process.env.NODE_ENV) {
throw new Error(
'The process.env.NODE_ENV environment variable is required but was not specified.',
@ -54,6 +60,10 @@ if (!process.env.BACKEND_URL) {
process.env.BACKEND_URL = 'http://localhost:5000';
}
if (!process.env.SENTRY_RELEASE) {
process.env.SENTRY_RELEASE = gitRevisionShortHash;
}
const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '')
.split(path.delimiter)
@ -67,6 +77,8 @@ module.exports = () => {
NODE_ENV: process.env.NODE_ENV || 'development',
PORT: process.env.PORT || 3000,
PUBLIC_HOST_URL: process.env.PUBLIC_HOST_URL,
SENTRY_DSN: process.env.SENTRY_DSN || null,
SENTRY_RELEASE: process.env.SENTRY_RELEASE,
};
// Stringify all values so we can feed into Webpack DefinePlugin

View File

@ -45,6 +45,8 @@
"@babel/register": "^7.0.0",
"@ledgerhq/hw-app-eth": "4.23.0",
"@ledgerhq/hw-transport-u2f": "4.21.0",
"@sentry/browser": "^4.3.2",
"@sentry/node": "^4.3.2",
"@svgr/webpack": "^2.4.0",
"@types/classnames": "^2.2.6",
"@types/cors": "^2.8.4",

View File

@ -6,6 +6,7 @@ import manifestHelpers from 'express-manifest-helpers';
import * as bodyParser from 'body-parser';
import expressWinston from 'express-winston';
import i18nMiddleware from 'i18next-express-middleware';
import * as Sentry from '@sentry/node';
import '../config/env';
// @ts-ignore
@ -17,8 +18,17 @@ import i18n from './i18n';
process.env.SERVER_SIDE_RENDER = 'true';
const isDev = process.env.NODE_ENV === 'development';
Sentry.init({
dsn: process.env.SENTRY_DSN,
release: process.env.SENTRY_RELEASE,
environment: process.env.NODE_ENV,
});
const app = express();
// sentry
app.use(Sentry.Handlers.requestHandler());
// log requests
app.use(expressWinston.logger({ winstonInstance: log }));
@ -59,6 +69,7 @@ app.use(
app.use(serverRender());
app.use(Sentry.Handlers.errorHandler());
app.use(expressWinston.errorLogger({ winstonInstance: log }));
app.listen(process.env.PORT || 3000, () => {

View File

@ -1612,6 +1612,60 @@
dependencies:
any-observable "^0.3.0"
"@sentry/browser@^4.3.2":
version "4.3.2"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-4.3.2.tgz#430b83583c5c25d33041dd80bf6ed19216086f70"
dependencies:
"@sentry/core" "4.3.2"
"@sentry/types" "4.3.2"
"@sentry/utils" "4.3.2"
"@sentry/core@4.3.2":
version "4.3.2"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-4.3.2.tgz#e8a2850a11316d865ed7d3030ee2c4a1608bb1d8"
dependencies:
"@sentry/hub" "4.3.2"
"@sentry/minimal" "4.3.2"
"@sentry/types" "4.3.2"
"@sentry/utils" "4.3.2"
"@sentry/hub@4.3.2":
version "4.3.2"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-4.3.2.tgz#1ea10038e2080035d2bc09f5f26829cd106a1516"
dependencies:
"@sentry/types" "4.3.2"
"@sentry/utils" "4.3.2"
"@sentry/minimal@4.3.2":
version "4.3.2"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-4.3.2.tgz#c0958e5858b2105a6a0b523787e459a03af603cc"
dependencies:
"@sentry/hub" "4.3.2"
"@sentry/types" "4.3.2"
"@sentry/node@^4.3.2":
version "4.3.2"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-4.3.2.tgz#3c7cd3aff238f3b1eb3252147b963cbdf520aa45"
dependencies:
"@sentry/core" "4.3.2"
"@sentry/hub" "4.3.2"
"@sentry/types" "4.3.2"
"@sentry/utils" "4.3.2"
cookie "0.3.1"
lsmod "1.0.0"
md5 "2.2.1"
stack-trace "0.0.10"
"@sentry/types@4.3.2":
version "4.3.2"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-4.3.2.tgz#28b143979482fcbc9f9e520250482dde015b13fa"
"@sentry/utils@4.3.2":
version "4.3.2"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-4.3.2.tgz#de14046eba972af9d62508f78cd998b0352d634a"
dependencies:
"@sentry/types" "4.3.2"
"@storybook/addons@4.0.0-alpha.22":
version "4.0.0-alpha.22"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-4.0.0-alpha.22.tgz#08d89396fff216c0d5aa305f7ac851b6bc34b6cf"
@ -4105,6 +4159,10 @@ chardet@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
charenc@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
check-error@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
@ -4812,6 +4870,10 @@ cross-spawn@^3.0.0:
lru-cache "^4.0.1"
which "^1.2.9"
crypt@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
cryptiles@3.x.x:
version "3.1.2"
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe"
@ -8082,7 +8144,7 @@ is-boolean-object@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.0.tgz#98f8b28030684219a95f375cfbd88ce3405dff93"
is-buffer@^1.0.2, is-buffer@^1.1.5:
is-buffer@^1.0.2, is-buffer@^1.1.5, is-buffer@~1.1.1:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@ -9658,6 +9720,10 @@ lru-cache@^4.1.1, lru-cache@^4.1.2, lru-cache@^4.1.3:
pseudomap "^1.0.2"
yallist "^2.1.2"
lsmod@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lsmod/-/lsmod-1.0.0.tgz#9a00f76dca36eb23fa05350afe1b585d4299e64b"
make-dir@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.1.0.tgz#19b4369fe48c116f53c2af95ad102c0e39e85d51"
@ -9751,6 +9817,14 @@ md5.js@^1.3.4:
hash-base "^3.0.0"
inherits "^2.0.1"
md5@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
dependencies:
charenc "~0.0.1"
crypt "~0.0.1"
is-buffer "~1.1.1"
mdn-data@~1.1.0:
version "1.1.4"
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01"
@ -14230,7 +14304,7 @@ stable@~0.1.6:
version "0.1.8"
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
stack-trace@0.0.x:
stack-trace@0.0.10, stack-trace@0.0.x:
version "0.0.10"
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"