diff --git a/Pipfile b/Pipfile index b1f167c..5cb50e4 100644 --- a/Pipfile +++ b/Pipfile @@ -27,10 +27,11 @@ test = "bash ./scripts/test.sh" allow_prereleases = true [packages] -aiohttp = "*" apscheduler = "*" pygithub = "*" -aiohttp-basicauth = "*" todoist-python = "*" sentry-sdk = "*" python-dateutil = "*" +starlette = "*" +uvicorn = "*" +starlette-auth-toolkit = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 93ffd12..cbe13c5 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "03e80110ad057d53144378ffb7408e120d5196509d80bc31a6092910dd4bd625" + "sha256": "57eb2cb3c7115a01ad13d8eb1a030f29ee76e1985c36ff5511817dbf47b48696" }, "pipfile-spec": 6, "requires": { @@ -16,42 +16,6 @@ ] }, "default": { - "aiohttp": { - "hashes": [ - "sha256:02396865118790ebb0bd14d6935e9e4fa80d87683240618894e585048a8b83ec", - "sha256:0f448b5d5cd45e642b9fcf4798e48cca4149ae479022f59bd67a47caed44657e", - "sha256:1af72f53ccead6d161296e576aa2b5d0c6c7403a389601dd7aa7a7a30a9f41c3", - "sha256:32eeef64a5bcf6dc652f19e020b16f36ec66d291957f62ffad18ecfc58695966", - "sha256:36c4e234a85a81e325d8b1d7fdeb696a3d51bb8eb09a8c8e69c7532b421e8a29", - "sha256:371a5f1bb604fc262ba32893931f5aad3bb3e797dbebcf2b5b2c36f97603e4c7", - "sha256:3f5a30f67e4152d4075063ae9f2286313af2e39b950869edba76232569e08793", - "sha256:48c65d65d0de79f1a4391bc29c8c8ec7655671a03ad7902d5e66fd735531893e", - "sha256:4ede22808195126d55879f1a14aaa3d1004f188c341f92ec3b9ca5ea13e695b9", - "sha256:53228028648b40f59fc941c0cd67b7899bce52f35eb66aeb9e33b75bac0aac0a", - "sha256:67cb8e71c043686f806cfdb4189774c57ef929d32890024c3775d72b54381797", - "sha256:6b1e99dc838c28f14e45bffef6fb77bf5b54bd2bfb1a475c776da5ba8a9fec2d", - "sha256:6c30eca95e7d60fbf13e6ebcaf62b7c0f3f93ec5de8862919aa5ede3720b1c86", - "sha256:6f2c905ab82aa0ee8a06210d5a6c1359c79f3f2088cc1b53c8758cae1dbc0d55", - "sha256:746b73eff86a1618025093b9c86ff4d642cff71a7ac7244f7fd8a186967cee22", - "sha256:9ebf518c7bc08e65b5396f80e8155c7bb1380b921b84b510570e62196c9fca56", - "sha256:9efc80ced0936f3fb2774e1bc981006324c74d1e58fc7f7164ecd98ede727c7d", - "sha256:abc43651f2c6d70b812cb874fc8caa00eb69fac11930cd2640d32a11ee7beef0", - "sha256:b4c6e1f5a591511537d4ccd4c807f6c8bb8d1b8a5043395950ba339086380904", - "sha256:bee80820a8ef5f6bddd58d762fc9f981ef1041a464d382d7d9a992bb94cd23c6", - "sha256:f0c304dcc1494dbc3fc492ebc2e61d0db323be9756a1bb14f407097d8adf82ec", - "sha256:fb9c2f27d2db6d709a02421733bb6ad22e16104beb2cf403e1120c24f3cc8668" - ], - "index": "pypi", - "version": "==4.0.0a0" - }, - "aiohttp-basicauth": { - "hashes": [ - "sha256:02bc53659ed90fcd97fe541e0aa61c1d415ec7304d4757aedb58aa70ca6df358", - "sha256:3f5f05b064c4601bbf24cac42cd55def779aa266cfbd1fe1630ea4a058779003" - ], - "index": "pypi", - "version": "==0.1.3" - }, "apscheduler": { "hashes": [ "sha256:529afb7909e08416132891188cbfea5351eb35e4a684b67e983d819e8d01a6b0", @@ -60,20 +24,6 @@ "index": "pypi", "version": "==3.6.1" }, - "async-timeout": { - "hashes": [ - "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", - "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" - ], - "version": "==3.0.1" - }, - "attrs": { - "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" - ], - "version": "==19.1.0" - }, "certifi": { "hashes": [ "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", @@ -88,6 +38,13 @@ ], "version": "==3.0.4" }, + "click": { + "hashes": [ + "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", + "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + ], + "version": "==7.0" + }, "deprecated": { "hashes": [ "sha256:a515c4cf75061552e0284d123c3066fbbe398952c87333a92b8fc3dd8e4f9cc1", @@ -95,6 +52,20 @@ ], "version": "==1.2.6" }, + "h11": { + "hashes": [ + "sha256:acca6a44cb52a32ab442b1779adf0875c443c689e9e028f8d831a3769f9c5208", + "sha256:f2b1ca39bfed357d1f19ac732913d5f9faa54a5062eca7d2ec3a916cfb7ae4c7" + ], + "version": "==0.8.1" + }, + "httptools": { + "hashes": [ + "sha256:e00cbd7ba01ff748e494248183abc6e153f49181169d8a3d41bb49132ca01dfc" + ], + "markers": "sys_platform != 'win32' and sys_platform != 'cygwin' and platform_python_implementation != 'pypy'", + "version": "==0.0.13" + }, "idna": { "hashes": [ "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", @@ -102,40 +73,6 @@ ], "version": "==2.8" }, - "multidict": { - "hashes": [ - "sha256:024b8129695a952ebd93373e45b5d341dbb87c17ce49637b34000093f243dd4f", - "sha256:041e9442b11409be5e4fc8b6a97e4bcead758ab1e11768d1e69160bdde18acc3", - "sha256:045b4dd0e5f6121e6f314d81759abd2c257db4634260abcfe0d3f7083c4908ef", - "sha256:047c0a04e382ef8bd74b0de01407e8d8632d7d1b4db6f2561106af812a68741b", - "sha256:068167c2d7bbeebd359665ac4fff756be5ffac9cda02375b5c5a7c4777038e73", - "sha256:148ff60e0fffa2f5fad2eb25aae7bef23d8f3b8bdaf947a65cdbe84a978092bc", - "sha256:1d1c77013a259971a72ddaa83b9f42c80a93ff12df6a4723be99d858fa30bee3", - "sha256:1d48bc124a6b7a55006d97917f695effa9725d05abe8ee78fd60d6588b8344cd", - "sha256:31dfa2fc323097f8ad7acd41aa38d7c614dd1960ac6681745b6da124093dc351", - "sha256:34f82db7f80c49f38b032c5abb605c458bac997a6c3142e0d6c130be6fb2b941", - "sha256:3d5dd8e5998fb4ace04789d1d008e2bb532de501218519d70bb672c4c5a2fc5d", - "sha256:4a6ae52bd3ee41ee0f3acf4c60ceb3f44e0e3bc52ab7da1c2b2aa6703363a3d1", - "sha256:4b02a3b2a2f01d0490dd39321c74273fed0568568ea0e7ea23e02bd1fb10a10b", - "sha256:4b843f8e1dd6a3195679d9838eb4670222e8b8d01bc36c9894d6c3538316fa0a", - "sha256:5de53a28f40ef3c4fd57aeab6b590c2c663de87a5af76136ced519923d3efbb3", - "sha256:61b2b33ede821b94fa99ce0b09c9ece049c7067a33b279f343adfe35108a4ea7", - "sha256:6a3a9b0f45fd75dc05d8e93dc21b18fc1670135ec9544d1ad4acbcf6b86781d0", - "sha256:76ad8e4c69dadbb31bad17c16baee61c0d1a4a73bed2590b741b2e1a46d3edd0", - "sha256:7ba19b777dc00194d1b473180d4ca89a054dd18de27d0ee2e42a103ec9b7d014", - "sha256:7c1b7eab7a49aa96f3db1f716f0113a8a2e93c7375dd3d5d21c4941f1405c9c5", - "sha256:7fc0eee3046041387cbace9314926aa48b681202f8897f8bff3809967a049036", - "sha256:8ccd1c5fff1aa1427100ce188557fc31f1e0a383ad8ec42c559aabd4ff08802d", - "sha256:8e08dd76de80539d613654915a2f5196dbccc67448df291e69a88712ea21e24a", - "sha256:c18498c50c59263841862ea0501da9f2b3659c00db54abfbf823a80787fde8ce", - "sha256:c49db89d602c24928e68c0d510f4fcf8989d77defd01c973d6cbe27e684833b1", - "sha256:ce20044d0317649ddbb4e54dab3c1bcc7483c78c27d3f58ab3d0c7e6bc60d26a", - "sha256:d1071414dd06ca2eafa90c85a079169bfeb0e5f57fd0b45d44c092546fcd6fd9", - "sha256:d3be11ac43ab1a3e979dac80843b42226d5d3cccd3986f2e03152720a4297cd7", - "sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b" - ], - "version": "==4.5.2" - }, "pygithub": { "hashes": [ "sha256:db415a5aeb5ab1e4a3263b1a091b4f9ffbd85a12a06a0303d5bf083ce7c1b2c8" @@ -174,11 +111,11 @@ }, "sentry-sdk": { "hashes": [ - "sha256:79e8352b5097aa06014871c6daad0933f59d1fcccc586339464ea86e4877b2ab", - "sha256:aeaaf6ae7cc4030d390e5c95797ac1a2a79ac2c8b687709293975ee808c68784" + "sha256:528f936118679e9a52dacb96bfefe20acb5d63e0797856c64a582cc3c2bc1f9e", + "sha256:b4edcb1296fee107439345d0f8b23432b8732b7e28407f928367d0a4a36301a9" ], "index": "pypi", - "version": "==0.11.1" + "version": "==0.11.2" }, "six": { "hashes": [ @@ -187,6 +124,21 @@ ], "version": "==1.12.0" }, + "starlette": { + "hashes": [ + "sha256:f600bf9d0beeeeebcb143e6d0c4f8858c2b05067d5a4feb446ba7400ba5e5dc5" + ], + "index": "pypi", + "version": "==0.12.8" + }, + "starlette-auth-toolkit": { + "hashes": [ + "sha256:5b3b651bf05d3f0332846fac52b7266b06f05d9264c7a9d065ca51dccf765a7a", + "sha256:9fd041aff89fffe67feb8cd94e10e2a8bbf609aeb6a736a74fce79320254e1f1" + ], + "index": "pypi", + "version": "==0.5.0" + }, "todoist-python": { "hashes": [ "sha256:69df6f2c659ca341ceb6ff137bf87ba32df8a3b07686d01eeae4c5daa6a26646" @@ -208,27 +160,60 @@ ], "version": "==1.25.3" }, + "uvicorn": { + "hashes": [ + "sha256:8aa44f9d9c3082ef693950387ea25d376e32944df6d4071dbd8edc3c25a40c74" + ], + "index": "pypi", + "version": "==0.8.6" + }, + "uvloop": { + "hashes": [ + "sha256:0fcd894f6fc3226a962ee7ad895c4f52e3f5c3c55098e21efb17c071849a0573", + "sha256:2f31de1742c059c96cb76b91c5275b22b22b965c886ee1fced093fa27dde9e64", + "sha256:459e4649fcd5ff719523de33964aa284898e55df62761e7773d088823ccbd3e0", + "sha256:67867aafd6e0bc2c30a079603a85d83b94f23c5593b3cc08ec7e58ac18bf48e5", + "sha256:8c200457e6847f28d8bb91c5e5039d301716f5f2fce25646f5fb3fd65eda4a26", + "sha256:958906b9ca39eb158414fbb7d6b8ef1b7aee4db5c8e8e5d00fcbb69a1ce9dca7", + "sha256:ac1dca3d8f3ef52806059e81042ee397ac939e5a86c8a3cea55d6b087db66115", + "sha256:b284c22d8938866318e3b9d178142b8be316c52d16fcfe1560685a686718a021", + "sha256:c48692bf4587ce281d641087658eca275a5ad3b63c78297bbded96570ae9ce8f", + "sha256:fefc3b2b947c99737c348887db2c32e539160dcbeb7af9aa6b53db7a283538fe" + ], + "markers": "sys_platform != 'win32' and sys_platform != 'cygwin' and platform_python_implementation != 'pypy'", + "version": "==0.12.2" + }, + "websockets": { + "hashes": [ + "sha256:04b42a1b57096ffa5627d6a78ea1ff7fad3bc2c0331ffc17bc32a4024da7fea0", + "sha256:08e3c3e0535befa4f0c4443824496c03ecc25062debbcf895874f8a0b4c97c9f", + "sha256:10d89d4326045bf5e15e83e9867c85d686b612822e4d8f149cf4840aab5f46e0", + "sha256:232fac8a1978fc1dead4b1c2fa27c7756750fb393eb4ac52f6bc87ba7242b2fa", + "sha256:4bf4c8097440eff22bc78ec76fe2a865a6e658b6977a504679aaf08f02c121da", + "sha256:51642ea3a00772d1e48fb0c492f0d3ae3b6474f34d20eca005a83f8c9c06c561", + "sha256:55d86102282a636e195dad68aaaf85b81d0bef449d7e2ef2ff79ac450bb25d53", + "sha256:564d2675682bd497b59907d2205031acbf7d3fadf8c763b689b9ede20300b215", + "sha256:5d13bf5197a92149dc0badcc2b699267ff65a867029f465accfca8abab95f412", + "sha256:5eda665f6789edb9b57b57a159b9c55482cbe5b046d7db458948370554b16439", + "sha256:5edb2524d4032be4564c65dc4f9d01e79fe8fad5f966e5b552f4e5164fef0885", + "sha256:79691794288bc51e2a3b8de2bc0272ca8355d0b8503077ea57c0716e840ebaef", + "sha256:7fcc8681e9981b9b511cdee7c580d5b005f3bb86b65bde2188e04a29f1d63317", + "sha256:8e447e05ec88b1b408a4c9cde85aa6f4b04f06aa874b9f0b8e8319faf51b1fee", + "sha256:90ea6b3e7787620bb295a4ae050d2811c807d65b1486749414f78cfd6fb61489", + "sha256:9e13239952694b8b831088431d15f771beace10edfcf9ef230cefea14f18508f", + "sha256:d40f081187f7b54d7a99d8a5c782eaa4edc335a057aa54c85059272ed826dc09", + "sha256:e1df1a58ed2468c7b7ce9a2f9752a32ad08eac2bcd56318625c3647c2cd2da6f", + "sha256:e98d0cec437097f09c7834a11c69d79fe6241729b23f656cfc227e93294fc242", + "sha256:f8d59627702d2ff27cb495ca1abdea8bd8d581de425c56e93bff6517134e0a9b", + "sha256:fc30cdf2e949a2225b012a7911d1d031df3d23e99b7eda7dfc982dc4a860dae9" + ], + "version": "==7.0" + }, "wrapt": { "hashes": [ "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" ], "version": "==1.11.2" - }, - "yarl": { - "hashes": [ - "sha256:024ecdc12bc02b321bc66b41327f930d1c2c543fa9a561b39861da9388ba7aa9", - "sha256:2f3010703295fbe1aec51023740871e64bb9664c789cba5a6bdf404e93f7568f", - "sha256:3890ab952d508523ef4881457c4099056546593fa05e93da84c7250516e632eb", - "sha256:3e2724eb9af5dc41648e5bb304fcf4891adc33258c6e14e2a7414ea32541e320", - "sha256:5badb97dd0abf26623a9982cd448ff12cb39b8e4c94032ccdedf22ce01a64842", - "sha256:73f447d11b530d860ca1e6b582f947688286ad16ca42256413083d13f260b7a0", - "sha256:7ab825726f2940c16d92aaec7d204cfc34ac26c0040da727cf8ba87255a33829", - "sha256:b25de84a8c20540531526dfbb0e2d2b648c13fd5dd126728c496d7c3fea33310", - "sha256:c6e341f5a6562af74ba55205dbd56d248daf1b5748ec48a0200ba227bb9e33f4", - "sha256:c9bb7c249c4432cd47e75af3864bc02d26c9594f49c82e2a28624417f0ae63b8", - "sha256:e060906c0c585565c718d1c3841747b61c5439af2211e185f6739a9412dfbde1" - ], - "version": "==1.3.0" } }, "develop": { @@ -354,11 +339,11 @@ }, "ipython": { "hashes": [ - "sha256:1d3a1692921e932751bc1a1f7bb96dc38671eeefdc66ed33ee4cbc57e92a410e", - "sha256:537cd0176ff6abd06ef3e23f2d0c4c2c8a4d9277b7451544c6cbf56d1c79a83d" + "sha256:c4ab005921641e40a68e405e286e7a1fcc464497e14d81b6914b4fd95e5dee9b", + "sha256:dd76831f065f17bddd7eaa5c781f5ea32de5ef217592cf019e34043b56895aa1" ], "index": "pypi", - "version": "==7.7.0" + "version": "==7.8.0" }, "ipython-genutils": { "hashes": [ diff --git a/actioner/main.py b/actioner/main.py index 694b54b..da7c83d 100644 --- a/actioner/main.py +++ b/actioner/main.py @@ -2,12 +2,11 @@ import logging from multiprocessing import Process import sentry_sdk -from aiohttp.web import run_app as run_web_app from sentry_sdk.integrations.aiohttp import AioHttpIntegration from actioner.scheduler import create_scheduler from actioner.settings import LOGGING_LEVEL, SENTRY_DSN -from actioner.web import get_server +from actioner.web import get_server, run_server def main(): @@ -19,7 +18,7 @@ def main(): scheduler = create_scheduler() # HACK: APScheduler doesn't like running in an external event loop. https://github.com/agronholm/apscheduler/issues/360 - Process(target=run_web_app, args=(server,)).start() + Process(target=run_server, args=(server,)).start() Process(target=scheduler.start).start() diff --git a/actioner/web/__init__.py b/actioner/web/__init__.py index d155252..db68d02 100644 --- a/actioner/web/__init__.py +++ b/actioner/web/__init__.py @@ -1,15 +1,39 @@ -from aiohttp import web -from aiohttp_basicauth import BasicAuthMiddleware +import os + +import uvicorn +from starlette.applications import Starlette +from starlette.authentication import SimpleUser, requires # or a custom user model +from starlette.middleware.authentication import AuthenticationMiddleware +from starlette.responses import PlainTextResponse +from starlette.routing import Route, Router +from starlette_auth_toolkit.base.backends import BaseBasicAuth from actioner.settings import BASIC_AUTH from .healthcheck import healthcheck +class BasicAuth(BaseBasicAuth): + async def verify(self, username: str, password: str): + print(username, password) + if [username, password] != BASIC_AUTH: + return None + return SimpleUser(username) + + def get_server(): - auth = BasicAuthMiddleware( - username=BASIC_AUTH[0], password=BASIC_AUTH[1], force=False + requires_authentication = requires("authenticated") + app = Starlette( + routes=[ + Route( + "/healthcheck/", requires_authentication(healthcheck), methods=["GET"] + ) + ] ) - app = web.Application() - app.router.add_get("/healthcheck", auth.required(healthcheck)) + app.add_middleware(AuthenticationMiddleware, backend=BasicAuth()) + return app + + +def run_server(server): + uvicorn.run(server, host="0.0.0.0", port=os.environ.get("PORT", 8000)) diff --git a/actioner/web/healthcheck.py b/actioner/web/healthcheck.py index a09d0e9..3508e9c 100644 --- a/actioner/web/healthcheck.py +++ b/actioner/web/healthcheck.py @@ -1,4 +1,4 @@ -from aiohttp import web +from starlette.responses import JSONResponse from actioner.clients import get_todoist_client, github @@ -6,6 +6,6 @@ from actioner.clients import get_todoist_client, github async def healthcheck(request): todoist = get_todoist_client() todoist.user.sync() - return web.json_response( + return JSONResponse( {"github": github.get_user().login, "todoist": todoist.user.get_id()} )