Replace Elastic APM with Sentry APM (#183)

This commit is contained in:
Jens L 2020-08-20 20:39:21 +02:00 committed by GitHub
parent 0eb94df1f7
commit ff810c689f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 277 additions and 239 deletions

View File

@ -21,7 +21,6 @@ django-rest-framework = "*"
django-storages = "*"
djangorestframework-guardian = "*"
drf-yasg = "*"
elastic-apm = "*"
facebook-sdk = "*"
ldap3 = "*"
lxml = "*"

125
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "b7ba5405c03bf3526eebb29817887744a3e31bca019ad2e566ea23096c6a5cfe"
"sha256": "616f5d355c42881b7ea70d4623bf885cff043d4c58913287960923df49c09909"
},
"pipfile-spec": 6,
"requires": {
@ -21,6 +21,7 @@
"sha256:70cdb10628468ff14e57ec2f751c7aa9e48e7e3651cfd62d431213c0c4e58f21",
"sha256:aa7f313fb887c91f15474c1229907a04dac0b8135822d6603437803424c0aa59"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.6.1"
},
"asgiref": {
@ -28,14 +29,16 @@
"sha256:7e51911ee147dd685c3c8b805c0ad0cb58d360987b56953878f8c06d2d1c6f1a",
"sha256:9fc6fb5d39b8af147ba40765234fa822b39818b12cc80b35ad9b0cef3a476aed"
],
"markers": "python_version >= '3.5'",
"version": "==3.2.10"
},
"attrs": {
"hashes": [
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
"sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a",
"sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff"
],
"version": "==19.3.0"
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==20.1.0"
},
"billiard": {
"hashes": [
@ -258,6 +261,7 @@
"sha256:6dd02d5a4bd2516fb93f80360673bf540c3b6641fec8766b1da2870a5aa00b32",
"sha256:8b1ac62c581dbc5799b03e535854b92fc4053ecfe74bad3f9c05782063d4196b"
],
"markers": "python_version >= '3.5'",
"version": "==3.11.1"
},
"djangorestframework-guardian": {
@ -274,6 +278,7 @@
"sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827",
"sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.15.2"
},
"drf-yasg": {
@ -291,39 +296,6 @@
],
"version": "==1.0.0"
},
"elastic-apm": {
"hashes": [
"sha256:0c766621a4d15ed4ff7dd195499df1af6d7eb8c13790a727bf05773de2952de0",
"sha256:2187a0fd080cac7ed65dabfd64d7693ff187ae9b5ad4a810772387dca6877160",
"sha256:2a0bb663d3f9388db233784356f218807b9cfe1f4d4fa4569f41b567c068b50f",
"sha256:317e2a897b2a81d79bce42688975cfe0ccf6a3dc8025540c47093ea8ac5f1771",
"sha256:3a91d2df89af564dbf0abccb3d370940083205247903fe6d708fa771b16fca38",
"sha256:44fe2ce3ea57f97fce5fb32e747f6a9c9b361f5055608d59747c39ae06d1c526",
"sha256:4ca9f42d4b841ce598819f2f3a4d516c549cd5c02ab43c8283ca406c3b92a2db",
"sha256:56b34b30420aebf9566eeee3ffd633131ce51d1e2a4da6061f143a2b547d1980",
"sha256:5a56d20734771a4f7823ec12492fcd17a15dac761ecf1452d034a9b9b8b83388",
"sha256:6279cc28bd2f2bc2da478cebd5ace711b52549f736d138f950ebe0fa8f706a6f",
"sha256:69bcac2cee8f16a093f57000128caab7d1d3d8ac1474e24ce45190264ffc5ebe",
"sha256:7021b931210140e02540f3e56fdc8be07542eed10de82c9e5464dbe449a4c9aa",
"sha256:70237e1242ae461500ed455f47a5518abdbdc565e47265eddf3ca1dad530a541",
"sha256:7545f27703151ce71d73271a95662735cffb537189c214f778195a6fdab58533",
"sha256:8525ba800fbd955b65af667c43889df2358c22b1ef66ee92a846f5f4bc8d7286",
"sha256:8ba4239862f0b043d191a19e021637a25c3490f677cb8b1dd752bc425bb382e0",
"sha256:8c98625cb825c404954763ca5a6f82e06b833a6e6a9e2035065dc9894b4dc6dc",
"sha256:b02394f4d55af4f39086aee7bacf8652fde703f7226c5a564cdae9f7e2bf3f71",
"sha256:b3b1815765638ce01f9dbd136822d79e887d8d09cd10bc8770d4cc1d530bb853",
"sha256:b7bce10060abd98198d8a96e7f3e2e0e169dbd860c76e2c09e6a8874384eebb7",
"sha256:b8f849202dffe97512843dd366c4104d07d3b319e42916e3e031cff3db7475db",
"sha256:bc677614c198486ca4ef1026bde0c4efd74b936598ff9d64ea109f978a6381bb",
"sha256:d19fe00915c60ceabee42ae8c0aa76c6a48c2ffa67c5ba7f0d0fbb856ac36c09",
"sha256:d5561eb57eaa43c721258797dfab67b13938fdc94b7daec7a6ccb56dc524fe02",
"sha256:dc04aa32c7a3a17c688e3cc4c6293f2176be2482d67efccc651ff1fbb5c00ed6",
"sha256:e0d2c3463061b0e50ca53530bd5317498517d208618d90cf6e9933e93f9c727e",
"sha256:e9a416418cb2f6deb7a18b68bd75dad0552b4fd85d3e72e59ae4add0e8739b1c"
],
"index": "pypi",
"version": "==5.8.1"
},
"facebook-sdk": {
"hashes": [
"sha256:2e987b3e0f466a6f4ee77b935eb023dba1384134f004a2af21f1cfff7fe0806e",
@ -336,6 +308,7 @@
"hashes": [
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.18.2"
},
"idna": {
@ -350,6 +323,7 @@
"sha256:88b101b2668a1d81d6d72d4c2018e53bc6c7fc544c987849da1c7f77545c3bc9",
"sha256:f576e85132d34f5bf7df5183c2c6f94cfb32e528f53065345cf71329ba0b8924"
],
"markers": "python_version >= '3.5'",
"version": "==0.5.0"
},
"itypes": {
@ -364,6 +338,7 @@
"sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0",
"sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.11.2"
},
"jmespath": {
@ -371,6 +346,7 @@
"sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
"sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.0"
},
"jsonschema": {
@ -385,12 +361,16 @@
"sha256:be48cdffb54a2194d93ad6533d73f69408486483d189fe9f5990ee24255b0e0a",
"sha256:ca1b45faac8c0b18493d02a8571792f3c40291cf2bcf1f55afed3d8f3aa7ba74"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.6.11"
},
"ldap3": {
"hashes": [
"sha256:b399c39e80b6459e349b33fbe9787c1bcbf86de05994d41806a05c06f3e7574d",
"sha256:bdaf568cd30fc0006c8bb4f5e6014554afeb0c4bbea1677de9706e278a4057e7",
"sha256:df27407f4991f25bd669b5bb1bc8cb9ddf44a3e713ff6b3afeb3b3c26502f88f",
"sha256:59d1adcd5ead263387039e2a37d7cd772a2006b1cdb3ecfcbaab5192a601c515",
"sha256:df27407f4991f25bd669b5bb1bc8cb9ddf44a3e713ff6b3afeb3b3c26502f88f"
"sha256:7abbb3e5f4522114e0230ec175b60ae968b938d1f8a7d8bce7789f78d871fb9f"
],
"index": "pypi",
"version": "==2.8"
@ -468,6 +448,7 @@
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.1.1"
},
"oauthlib": {
@ -475,6 +456,7 @@
"sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889",
"sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==3.1.0"
},
"packaging": {
@ -530,15 +512,37 @@
},
"pyasn1": {
"hashes": [
"sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
"sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
"sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
"sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
"sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3",
"sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"
"sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2",
"sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
"sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"
],
"version": "==0.4.8"
},
"pyasn1-modules": {
"hashes": [
"sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
"sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
"sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
"sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
"sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
"sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
"sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
"sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199",
"sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
"sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
"sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
"sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"
],
"version": "==0.2.8"
},
@ -547,6 +551,7 @@
"sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.20"
},
"pycryptodome": {
@ -618,6 +623,7 @@
"sha256:ea4d4b58f9bc34e224ef4b4604a6be03d72ef1f8c486391f970205f6733dbc46",
"sha256:f60b3484ce4be04f5da3777c51c5140d3fe21cdd6674f2b6568f41c8130bcdeb"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==3.9.8"
},
"pyjwkest": {
@ -639,6 +645,7 @@
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.4.7"
},
"pyrsistent": {
@ -652,6 +659,7 @@
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.8.1"
},
"pytz": {
@ -709,6 +717,7 @@
"sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2",
"sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==3.5.3"
},
"requests": {
@ -716,12 +725,14 @@
"sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b",
"sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.24.0"
},
"requests-oauthlib": {
"hashes": [
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a",
"sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"
"sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"
],
"index": "pypi",
"version": "==1.3.0"
@ -755,7 +766,7 @@
"sha256:ed5b3698a2bb241b7f5cbbe277eaa7fe48b07a58784fba4f75224fd066d253ad",
"sha256:f9dcc1ae73f36e8059589b601e8e4776b9976effd76c21ad6a855a74318efd6e"
],
"markers": "platform_python_implementation == 'CPython' and python_version < '3.9'",
"markers": "python_version < '3.9' and platform_python_implementation == 'CPython'",
"version": "==0.2.0"
},
"s3transfer": {
@ -794,6 +805,7 @@
"sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
"sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.15.0"
},
"sqlparse": {
@ -801,6 +813,7 @@
"sha256:022fb9c87b524d1f7862b3037e541f68597a730a8843245c349fc93e1643dc4e",
"sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.3.1"
},
"structlog": {
@ -824,6 +837,7 @@
"sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f",
"sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==3.0.1"
},
"urllib3": {
@ -835,7 +849,6 @@
"sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"
],
"index": "pypi",
"markers": null,
"version": "==1.25.10"
},
"vine": {
@ -843,6 +856,7 @@
"sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87",
"sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.3.0"
}
},
@ -859,6 +873,7 @@
"sha256:7e51911ee147dd685c3c8b805c0ad0cb58d360987b56953878f8c06d2d1c6f1a",
"sha256:9fc6fb5d39b8af147ba40765234fa822b39818b12cc80b35ad9b0cef3a476aed"
],
"markers": "python_version >= '3.5'",
"version": "==3.2.10"
},
"astroid": {
@ -866,14 +881,16 @@
"sha256:4c17cea3e592c21b6e222f673868961bad77e1f985cb1694ed077475a89229c1",
"sha256:d8506842a3faf734b81599c8b98dcc423de863adcc1999248480b18bd31a0f38"
],
"markers": "python_version >= '3.5'",
"version": "==2.4.1"
},
"attrs": {
"hashes": [
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
"sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a",
"sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff"
],
"version": "==19.3.0"
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==20.1.0"
},
"autopep8": {
"hashes": [
@ -903,6 +920,7 @@
"sha256:477f0e18a0d58e50bb3dbc9af7fcda464fd0ebfc7a6151d8888602d7153171a0",
"sha256:cd4f3a231305e405ed8944d8ff35bd742d9bc740ad62f483bd0ca21ce7131984"
],
"markers": "python_version >= '3.5'",
"version": "==1.0.0"
},
"bumpversion": {
@ -932,6 +950,7 @@
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==7.1.2"
},
"colorama": {
@ -1018,6 +1037,7 @@
"sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c",
"sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==3.8.3"
},
"flake8-polyfill": {
@ -1032,6 +1052,7 @@
"sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac",
"sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"
],
"markers": "python_version >= '3.4'",
"version": "==4.0.5"
},
"gitpython": {
@ -1039,6 +1060,7 @@
"sha256:2db287d71a284e22e5c2846042d0602465c7434d910406990d5b74df4afb0858",
"sha256:fa3b92da728a457dd75d62bb5f3eb2816d99a7fe6c67398e260637a40e3fafb5"
],
"markers": "python_version >= '3.4'",
"version": "==3.1.7"
},
"idna": {
@ -1053,6 +1075,7 @@
"sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1",
"sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==4.3.21"
},
"lazy-object-proxy": {
@ -1079,6 +1102,7 @@
"sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4",
"sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.4.3"
},
"mccabe": {
@ -1121,6 +1145,7 @@
"sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367",
"sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.6.0"
},
"pydocstyle": {
@ -1128,6 +1153,7 @@
"sha256:da7831660b7355307b32778c4a0dbfb137d89254ef31a2b2978f50fc0b4d7586",
"sha256:f4f5d210610c2d153fae39093d44224c17429e2ad7da12a8b419aba5c2f614b5"
],
"markers": "python_version >= '3.5'",
"version": "==5.0.2"
},
"pyflakes": {
@ -1135,6 +1161,7 @@
"sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92",
"sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.2.0"
},
"pylint": {
@ -1227,6 +1254,7 @@
"sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b",
"sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.24.0"
},
"requirements-detector": {
@ -1254,6 +1282,7 @@
"sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
"sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.15.0"
},
"smmap": {
@ -1261,6 +1290,7 @@
"sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4",
"sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==3.0.4"
},
"snowballstemmer": {
@ -1275,6 +1305,7 @@
"sha256:022fb9c87b524d1f7862b3037e541f68597a730a8843245c349fc93e1643dc4e",
"sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.3.1"
},
"stevedore": {
@ -1282,6 +1313,7 @@
"sha256:38791aa5bed922b0a844513c5f9ed37774b68edc609e5ab8ab8d8fe0ce4315e5",
"sha256:c8f4f0ebbc394e52ddf49de8bcc3cf8ad2b4425ebac494106bbc5e3661ac7633"
],
"markers": "python_version >= '3.6'",
"version": "==3.2.0"
},
"toml": {
@ -1334,7 +1366,6 @@
"sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"
],
"index": "pypi",
"markers": null,
"version": "==1.25.10"
},
"websocket-client": {

View File

@ -61,7 +61,6 @@ postgresql:
user: postgres
log_level: debug
error_reporting: false
```
## Security

View File

@ -18,16 +18,11 @@ config:
# Optionally specify fixed secret_key, otherwise generated automatically
# secret_key: _k*@6h2u2@q-dku57hhgzb7tnx*ba9wodcb^s9g0j59@=y(@_o
# Enable error reporting
error_reporting: false
error_reporting:
enabled: false
# Log level used by web and worker
# Can be either debug, info, warning, error
log_level: warning
# Optionally enable Elastic APM Support
apm:
enabled: false
server_url: ""
secret_token: ""
verify_server_cert: true
# This Helm chart ships with built-in Prometheus ServiceMonitors and Rules.
# This requires the CoreOS Prometheus Operator.

View File

@ -19,10 +19,7 @@ data:
host: "{{ .Release.Name }}-redis-master"
cache_db: 0
message_queue_db: 1
error_reporting: {{ .Values.config.error_reporting }}
error_reporting:
enabled: {{ .Values.config.error_reporting.enabled }}
environment: {{ .Values.config.error_reporting.environment }}
log_level: "{{ .Values.config.log_level }}"
apm:
enabled: {{ .Values.config.apm.enabled }}
server_url: "{{ .Values.config.apm.server_url }}"
secret_token: "{{ .Values.config.apm.secret_token }}"
verify_server_cert: {{ .Values.config.apm.verify_server_cert }}

View File

@ -10,16 +10,12 @@ config:
# Optionally specify fixed secret_key, otherwise generated automatically
# secret_key: _k*@6h2u2@q-dku57hhgzb7tnx*ba9wodcb^s9g0j59@=y(@_o
# Enable error reporting
error_reporting: false
error_reporting:
enabled: false
environment: customer
# Log level used by web and worker
# Can be either debug, info, warning, error
log_level: warning
# Optionally enable Elastic APM Support
apm:
enabled: false
server_url: ""
secret_token: ""
verify_server_cert: true
# This Helm chart ships with built-in Prometheus ServiceMonitors and Rules.
# This requires the CoreOS Prometheus Operator.

View File

@ -1,13 +1,14 @@
"""Flows Planner"""
from dataclasses import dataclass, field
from time import time
from typing import Any, Dict, List, Optional
from django.core.cache import cache
from django.http import HttpRequest
from elasticapm import capture_span
from sentry_sdk import start_span
from sentry_sdk.tracing import Span
from structlog import get_logger
from passbook.audit.models import cleanse_dict
from passbook.core.models import User
from passbook.flows.exceptions import EmptyFlowException, FlowNonApplicableException
from passbook.flows.markers import ReevaluateMarker, StageMarker
@ -90,47 +91,53 @@ class FlowPlanner:
self.allow_empty_flows = False
self.flow = flow
@capture_span(name="FlowPlanner", span_type="flow.planner.plan")
def plan(
self, request: HttpRequest, default_context: Optional[Dict[str, Any]] = None
) -> FlowPlan:
"""Check each of the flows' policies, check policies for each stage with PolicyBinding
and return ordered list"""
LOGGER.debug("f(plan): Starting planning process", flow=self.flow)
# Bit of a workaround here, if there is a pending user set in the default context
# we use that user for our cache key
# to make sure they don't get the generic response
if default_context and PLAN_CONTEXT_PENDING_USER in default_context:
user = default_context[PLAN_CONTEXT_PENDING_USER]
else:
user = request.user
# First off, check the flow's direct policy bindings
# to make sure the user even has access to the flow
engine = PolicyEngine(self.flow, user, request)
if default_context:
engine.request.context = default_context
engine.build()
result = engine.result
if not result.passing:
raise FlowNonApplicableException(result.messages)
# User is passing so far, check if we have a cached plan
cached_plan_key = cache_key(self.flow, user)
cached_plan = cache.get(cached_plan_key, None)
if cached_plan and self.use_cache:
LOGGER.debug(
"f(plan): Taking plan from cache", flow=self.flow, key=cached_plan_key
)
# Reset the context as this isn't factored into caching
cached_plan.context = default_context or {}
return cached_plan
LOGGER.debug("f(plan): building plan", flow=self.flow)
plan = self._build_plan(user, request, default_context)
cache.set(cache_key(self.flow, user), plan)
if not plan.stages and not self.allow_empty_flows:
raise EmptyFlowException()
return plan
with start_span(op="flow.planner.plan") as span:
span: Span
span.set_data("flow", self.flow)
span.set_data("request", request)
LOGGER.debug("f(plan): Starting planning process", flow=self.flow)
# Bit of a workaround here, if there is a pending user set in the default context
# we use that user for our cache key
# to make sure they don't get the generic response
if default_context and PLAN_CONTEXT_PENDING_USER in default_context:
user = default_context[PLAN_CONTEXT_PENDING_USER]
else:
user = request.user
# First off, check the flow's direct policy bindings
# to make sure the user even has access to the flow
engine = PolicyEngine(self.flow, user, request)
if default_context:
span.set_data("default_context", cleanse_dict(default_context))
engine.request.context = default_context
engine.build()
result = engine.result
if not result.passing:
raise FlowNonApplicableException(result.messages)
# User is passing so far, check if we have a cached plan
cached_plan_key = cache_key(self.flow, user)
cached_plan = cache.get(cached_plan_key, None)
if cached_plan and self.use_cache:
LOGGER.debug(
"f(plan): Taking plan from cache",
flow=self.flow,
key=cached_plan_key,
)
# Reset the context as this isn't factored into caching
cached_plan.context = default_context or {}
return cached_plan
LOGGER.debug("f(plan): building plan", flow=self.flow)
plan = self._build_plan(user, request, default_context)
cache.set(cache_key(self.flow, user), plan)
if not plan.stages and not self.allow_empty_flows:
raise EmptyFlowException()
return plan
@capture_span(name="FlowPlanner", span_type="flow.planner.build_plan")
def _build_plan(
self,
user: User,
@ -139,38 +146,40 @@ class FlowPlanner:
) -> FlowPlan:
"""Build flow plan by checking each stage in their respective
order and checking the applied policies"""
start_time = time()
plan = FlowPlan(flow_pk=self.flow.pk.hex)
if default_context:
plan.context = default_context
# Check Flow policies
for stage in (
self.flow.stages.order_by("flowstagebinding__order")
.select_subclasses()
.select_related()
):
binding: FlowStageBinding = stage.flowstagebinding_set.get(
target__pk=self.flow.pk
)
engine = PolicyEngine(binding, user, request)
engine.request.context = plan.context
engine.build()
if engine.passing:
LOGGER.debug("f(plan): Stage passing", stage=stage, flow=self.flow)
plan.stages.append(stage)
marker = StageMarker()
if binding.re_evaluate_policies:
LOGGER.debug(
"f(plan): Stage has re-evaluate marker",
stage=stage,
flow=self.flow,
)
marker = ReevaluateMarker(binding=binding, user=user)
plan.markers.append(marker)
end_time = time()
with start_span(op="flow.planner.build_plan") as span:
span: Span
span.set_data("flow", self.flow)
span.set_data("user", user)
span.set_data("request", request)
plan = FlowPlan(flow_pk=self.flow.pk.hex)
if default_context:
plan.context = default_context
# Check Flow policies
for stage in (
self.flow.stages.order_by("flowstagebinding__order")
.select_subclasses()
.select_related()
):
binding: FlowStageBinding = stage.flowstagebinding_set.get(
target__pk=self.flow.pk
)
engine = PolicyEngine(binding, user, request)
engine.request.context = plan.context
engine.build()
if engine.passing:
LOGGER.debug("f(plan): Stage passing", stage=stage, flow=self.flow)
plan.stages.append(stage)
marker = StageMarker()
if binding.re_evaluate_policies:
LOGGER.debug(
"f(plan): Stage has re-evaluate marker",
stage=stage,
flow=self.flow,
)
marker = ReevaluateMarker(binding=binding, user=user)
plan.markers.append(marker)
LOGGER.debug(
"f(plan): Finished building",
flow=self.flow,
duration_s=end_time - start_time,
"f(plan): Finished building", flow=self.flow, duration_s=span.timestamp,
)
return plan

View File

@ -1,5 +1,5 @@
"""flow planner tests"""
from unittest.mock import MagicMock, PropertyMock, patch
from unittest.mock import MagicMock, Mock, PropertyMock, patch
from django.contrib.sessions.middleware import SessionMiddleware
from django.core.cache import cache
@ -18,7 +18,7 @@ from passbook.policies.types import PolicyResult
from passbook.stages.dummy.models import DummyStage
POLICY_RETURN_FALSE = PropertyMock(return_value=PolicyResult(False))
TIME_NOW_MOCK = MagicMock(return_value=3)
CACHE_MOCK = Mock(wraps=cache)
POLICY_RETURN_TRUE = MagicMock(return_value=PolicyResult(True))
@ -64,7 +64,7 @@ class TestFlowPlanner(TestCase):
planner = FlowPlanner(flow)
planner.plan(request)
@patch("passbook.flows.planner.time", TIME_NOW_MOCK)
@patch("passbook.flows.planner.cache", CACHE_MOCK)
def test_planner_cache(self):
"""Test planner cache"""
flow = Flow.objects.create(
@ -82,12 +82,15 @@ class TestFlowPlanner(TestCase):
planner = FlowPlanner(flow)
planner.plan(request)
self.assertEqual(TIME_NOW_MOCK.call_count, 2) # Start and end
self.assertEqual(
CACHE_MOCK.set.call_count, 1
) # Ensure plan is written to cache
planner = FlowPlanner(flow)
planner.plan(request)
self.assertEqual(
TIME_NOW_MOCK.call_count, 2
) # When taking from cache, time is not measured
CACHE_MOCK.set.call_count, 1
) # Ensure nothing is written to cache
self.assertEqual(CACHE_MOCK.get.call_count, 2) # Get is called twice
def test_planner_default_context(self):
"""Test planner with default_context"""

View File

@ -15,7 +15,9 @@ debug: false
log_level: warning
# Error reporting, sends stacktrace to sentry.beryju.org
error_reporting: false
error_reporting:
enabled: false
environment: customer
passbook:
# Optionally add links to the footer on the login page

View File

@ -4,8 +4,9 @@ from textwrap import indent
from typing import Any, Dict, Iterable, Optional
from django.core.exceptions import ValidationError
from elasticapm import capture_span
from requests import Session
from sentry_sdk import start_span
from sentry_sdk.tracing import Span
from structlog import get_logger
from passbook.core.models import User
@ -71,27 +72,31 @@ class BaseEvaluator:
full_expression += f"\nresult = handler({handler_signature})"
return full_expression
@capture_span(name="BaseEvaluator", span_type="lib.evaluator.evaluate")
def evaluate(self, expression_source: str) -> Any:
"""Parse and evaluate expression. If the syntax is incorrect, a SyntaxError is raised.
If any exception is raised during execution, it is raised.
The result is returned without any type-checking."""
param_keys = self._context.keys()
ast_obj = compile(
self.wrap_expression(expression_source, param_keys), self._filename, "exec",
)
try:
_locals = self._context
# Yes this is an exec, yes it is potentially bad. Since we limit what variables are
# available here, and these policies can only be edited by admins, this is a risk
# we're willing to take.
# pylint: disable=exec-used
exec(ast_obj, self._globals, _locals) # nosec # noqa
result = _locals["result"]
except Exception as exc:
LOGGER.warning("Expression error", exc=exc)
raise
return result
with start_span(op="lib.evaluator.evaluate") as span:
span: Span
span.set_data("expression", expression_source)
param_keys = self._context.keys()
ast_obj = compile(
self.wrap_expression(expression_source, param_keys),
self._filename,
"exec",
)
try:
_locals = self._context
# Yes this is an exec, yes it is potentially bad. Since we limit what variables are
# available here, and these policies can only be edited by admins, this is a risk
# we're willing to take.
# pylint: disable=exec-used
exec(ast_obj, self._globals, _locals) # nosec # noqa
result = _locals["result"]
except Exception as exc:
LOGGER.warning("Expression error", exc=exc)
raise
return result
def validate(self, expression: str) -> bool:
"""Validate expression's syntax, raise ValidationError if Syntax is invalid"""

View File

@ -4,7 +4,6 @@ from botocore.client import ClientError
from django.core.exceptions import DisallowedHost, ValidationError
from django.db import InternalError, OperationalError, ProgrammingError
from django_redis.exceptions import ConnectionInterrupted
from elasticapm.transport.http import TransportException
from redis.exceptions import RedisError
from rest_framework.exceptions import APIException
from structlog import get_logger
@ -34,7 +33,6 @@ def before_send(event, hint):
OSError,
RedisError,
SentryIgnoredException,
TransportException,
)
if "exc_info" in hint:
_, exc_value, _ = hint["exc_info"]

View File

@ -5,7 +5,8 @@ from typing import List, Optional
from django.core.cache import cache
from django.http import HttpRequest
from elasticapm import capture_span
from sentry_sdk import start_span
from sentry_sdk.tracing import Span
from structlog import get_logger
from passbook.core.models import User
@ -70,36 +71,39 @@ class PolicyEngine:
if policy.__class__ == Policy:
raise TypeError(f"Policy '{policy}' is root type")
@capture_span(name="PolicyEngine", span_type="policy.engine.build")
def build(self) -> "PolicyEngine":
"""Build task group"""
for binding in self._iter_bindings():
self._check_policy_type(binding.policy)
key = cache_key(binding, self.request)
cached_policy = cache.get(key, None)
if cached_policy and self.use_cache:
LOGGER.debug(
"P_ENG: Taking result from cache",
policy=binding.policy,
cache_key=key,
"""Build wrapper which monitors performance"""
with start_span(op="policy.engine.build") as span:
span: Span
span.set_data("pbm", self.__pbm)
span.set_data("request", self.request)
for binding in self._iter_bindings():
self._check_policy_type(binding.policy)
key = cache_key(binding, self.request)
cached_policy = cache.get(key, None)
if cached_policy and self.use_cache:
LOGGER.debug(
"P_ENG: Taking result from cache",
policy=binding.policy,
cache_key=key,
)
self.__cached_policies.append(cached_policy)
continue
LOGGER.debug("P_ENG: Evaluating policy", policy=binding.policy)
our_end, task_end = Pipe(False)
task = PolicyProcess(binding, self.request, task_end)
LOGGER.debug("P_ENG: Starting Process", policy=binding.policy)
task.start()
self.__processes.append(
PolicyProcessInfo(process=task, connection=our_end, binding=binding)
)
self.__cached_policies.append(cached_policy)
continue
LOGGER.debug("P_ENG: Evaluating policy", policy=binding.policy)
our_end, task_end = Pipe(False)
task = PolicyProcess(binding, self.request, task_end)
LOGGER.debug("P_ENG: Starting Process", policy=binding.policy)
task.start()
self.__processes.append(
PolicyProcessInfo(process=task, connection=our_end, binding=binding)
)
# If all policies are cached, we have an empty list here.
for proc_info in self.__processes:
proc_info.process.join(proc_info.binding.timeout)
# Only call .recv() if no result is saved, otherwise we just deadlock here
if not proc_info.result:
proc_info.result = proc_info.connection.recv()
return self
# If all policies are cached, we have an empty list here.
for proc_info in self.__processes:
proc_info.process.join(proc_info.binding.timeout)
# Only call .recv() if no result is saved, otherwise we just deadlock here
if not proc_info.result:
proc_info.result = proc_info.connection.recv()
return self
@property
def result(self) -> PolicyResult:

View File

@ -4,7 +4,8 @@ from multiprocessing.connection import Connection
from typing import Optional
from django.core.cache import cache
from elasticapm import capture_span
from sentry_sdk import start_span
from sentry_sdk.tracing import Span
from structlog import get_logger
from passbook.policies.exceptions import PolicyException
@ -45,35 +46,38 @@ class PolicyProcess(Process):
if connection:
self.connection = connection
@capture_span(name="PolicyEngine", span_type="policy.process.execute")
def execute(self) -> PolicyResult:
"""Run actual policy, returns result"""
LOGGER.debug(
"P_ENG(proc): Running policy",
policy=self.binding.policy,
user=self.request.user,
process="PolicyProcess",
)
try:
policy_result = self.binding.policy.passes(self.request)
except PolicyException as exc:
LOGGER.debug("P_ENG(proc): error", exc=exc)
policy_result = PolicyResult(False, str(exc))
# Invert result if policy.negate is set
if self.binding.negate:
policy_result.passing = not policy_result.passing
LOGGER.debug(
"P_ENG(proc): Finished",
policy=self.binding.policy,
result=policy_result,
process="PolicyProcess",
passing=policy_result.passing,
user=self.request.user,
)
key = cache_key(self.binding, self.request)
cache.set(key, policy_result)
LOGGER.debug("P_ENG(proc): Cached policy evaluation", key=key)
return policy_result
with start_span(op="policy.process.execute",) as span:
span: Span
span.set_data("policy", self.binding.policy)
span.set_data("request", self.request)
LOGGER.debug(
"P_ENG(proc): Running policy",
policy=self.binding.policy,
user=self.request.user,
process="PolicyProcess",
)
try:
policy_result = self.binding.policy.passes(self.request)
except PolicyException as exc:
LOGGER.debug("P_ENG(proc): error", exc=exc)
policy_result = PolicyResult(False, str(exc))
# Invert result if policy.negate is set
if self.binding.negate:
policy_result.passing = not policy_result.passing
LOGGER.debug(
"P_ENG(proc): Finished",
policy=self.binding.policy,
result=policy_result,
process="PolicyProcess",
passing=policy_result.passing,
user=self.request.user,
)
key = cache_key(self.binding, self.request)
cache.set(key, policy_result)
LOGGER.debug("P_ENG(proc): Cached policy evaluation", key=key)
return policy_result
def run(self):
"""Task wrapper to run policy checking"""

View File

@ -144,7 +144,11 @@ class OAuthAuthorizationParams:
LOGGER.warning("Missing redirect uri.")
raise RedirectUriError()
if self.redirect_uri not in self.provider.redirect_uris.split():
LOGGER.warning("Invalid redirect uri", redirect_uri=self.redirect_uri, excepted=self.provider.redirect_uris.split())
LOGGER.warning(
"Invalid redirect uri",
redirect_uri=self.redirect_uri,
excepted=self.provider.redirect_uris.split(),
)
raise RedirectUriError()
if not is_open_id and (

View File

@ -110,7 +110,11 @@ class TokenParams:
raise TokenError("invalid_grant")
if self.redirect_uri not in self.provider.redirect_uris.split():
LOGGER.warning("Invalid redirect uri", uri=self.redirect_uri, expected=self.provider.redirect_uris.split())
LOGGER.warning(
"Invalid redirect uri",
uri=self.redirect_uri,
expected=self.provider.redirect_uris.split(),
)
raise TokenError("invalid_client")
try:

View File

@ -269,7 +269,7 @@ if CONFIG.y("postgresql.backup"):
}
# Sentry integration
_ERROR_REPORTING = CONFIG.y_bool("error_reporting", False)
_ERROR_REPORTING = CONFIG.y_bool("error_reporting.enabled", False)
if not DEBUG and _ERROR_REPORTING:
LOGGER.info("Error reporting is enabled.")
sentry_init(
@ -278,21 +278,10 @@ if not DEBUG and _ERROR_REPORTING:
send_default_pii=True,
before_send=before_send,
release="passbook@%s" % __version__,
traces_sample_rate=1.0,
environment=CONFIG.y("error_reporting.environment", "customer"),
)
_APM_ENABLED = CONFIG.y("apm.enabled", False)
if _APM_ENABLED:
INSTALLED_APPS.append("elasticapm.contrib.django")
ELASTIC_APM = {
"CLOUD_PROVIDER": False,
"DEBUG": DEBUG,
"SERVICE_NAME": "passbook",
"SERVICE_VERSION": __version__,
"SECRET_TOKEN": CONFIG.y("apm.secret_token", ""),
"SERVER_URL": CONFIG.y("apm.server_url", "http://localhost:8200"),
"VERIFY_SERVER_CERT": CONFIG.y_bool("apm.verify_server_cert", True),
}
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
@ -372,7 +361,6 @@ _LOGGING_HANDLER_MAP = {
"grpc": LOG_LEVEL,
"docker": "WARNING",
"urllib3": "WARNING",
"elasticapm": "WARNING",
}
for handler_name, level in _LOGGING_HANDLER_MAP.items():
# pyright: reportGeneralTypeIssues=false