refactors settings and adds security tests

This commit is contained in:
msramalho
2024-10-20 21:30:00 +01:00
parent d2f9f91a5c
commit 84cbf720a9
15 changed files with 203 additions and 47 deletions

View File

@@ -37,7 +37,7 @@ jobs:
working-directory: src working-directory: src
- name: Run tests with coverage - name: Run tests with coverage
run: PYTHONPATH=. pipenv run coverage run -m pytest -v --color=yes tests/ run: PYTHONPATH=. PIPENV_DOTENV_LOCATION=.env.test pipenv run coverage run -m pytest -v --color=yes tests/
working-directory: src working-directory: src
- name: Report coverage - name: Report coverage

View File

@@ -26,6 +26,7 @@ watchdog = "*"
pytest = "*" pytest = "*"
httpx = "*" httpx = "*"
coverage = "*" coverage = "*"
pytest-asyncio = "*"
[requires] [requires]
python_version = "3.10" python_version = "3.10"

65
src/Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "c34b5745f3a6f67222d3f26e6c7f2d13615a3301d0ca4d1f2b0ec58474b1d43a" "sha256": "da25332a2152541157c6873ec43ac771c5491bff7d60bb2714c26c4e6b40577f"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@@ -289,25 +289,26 @@
}, },
"boto3": { "boto3": {
"hashes": [ "hashes": [
"sha256:a5b00f8b82dce62870759f04861747944da834d64a64355970120c475efdafc0", "sha256:18416d07b41e6094101a44f8b881047dcec6b846dad0b9f83b9bbf2f0cd93d07",
"sha256:e1f36f8be453505cebcc3da178ea081b2a06c0e5e1cdee774f1067599b8d9c3e" "sha256:7f8e8a252458d584d8cf7877c372c4f74ec103356eedf43d2dd9e479f47f3639"
], ],
"markers": "python_version >= '3.8'", "markers": "python_version >= '3.8'",
"version": "==1.35.42" "version": "==1.35.44"
}, },
"botocore": { "botocore": {
"hashes": [ "hashes": [
"sha256:05af0bb8b9cea7ce7bc589c332348d338a21b784e9d088a588fd10ec145007ff", "sha256:1fcd97b966ad8a88de4106fe1bd3bbd6d8dadabe99bbd4a6aadcf11cb6c66b39",
"sha256:af348636f73dc24b7e2dc760a34d08c8f2f94366e9b4c78d877307b128abecef" "sha256:55388e80624401d017a9a2b8109afd94814f7e666b53e28fce51375cfa8d9326"
], ],
"markers": "python_version >= '3.8'", "markers": "python_version >= '3.8'",
"version": "==1.35.42" "version": "==1.35.44"
}, },
"brotli": { "brotli": {
"hashes": [ "hashes": [
"sha256:03d20af184290887bdea3f0f78c4f737d126c74dc2f3ccadf07e54ceca3bf208", "sha256:03d20af184290887bdea3f0f78c4f737d126c74dc2f3ccadf07e54ceca3bf208",
"sha256:0541e747cce78e24ea12d69176f6a7ddb690e62c425e01d31cc065e69ce55b48", "sha256:0541e747cce78e24ea12d69176f6a7ddb690e62c425e01d31cc065e69ce55b48",
"sha256:069a121ac97412d1fe506da790b3e69f52254b9df4eb665cd42460c837193354", "sha256:069a121ac97412d1fe506da790b3e69f52254b9df4eb665cd42460c837193354",
"sha256:0737ddb3068957cf1b054899b0883830bb1fec522ec76b1098f9b6e0f02d9419",
"sha256:0b63b949ff929fbc2d6d3ce0e924c9b93c9785d877a21a1b678877ffbbc4423a", "sha256:0b63b949ff929fbc2d6d3ce0e924c9b93c9785d877a21a1b678877ffbbc4423a",
"sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128", "sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128",
"sha256:11d00ed0a83fa22d29bc6b64ef636c4552ebafcef57154b4ddd132f5638fbd1c", "sha256:11d00ed0a83fa22d29bc6b64ef636c4552ebafcef57154b4ddd132f5638fbd1c",
@@ -315,43 +316,67 @@
"sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9", "sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9",
"sha256:1ab4fbee0b2d9098c74f3057b2bc055a8bd92ccf02f65944a241b4349229185a", "sha256:1ab4fbee0b2d9098c74f3057b2bc055a8bd92ccf02f65944a241b4349229185a",
"sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3", "sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3",
"sha256:1b2c248cd517c222d89e74669a4adfa5577e06ab68771a529060cf5a156e9757",
"sha256:1e9a65b5736232e7a7f91ff3d02277f11d339bf34099a56cdab6a8b3410a02b2",
"sha256:224e57f6eac61cc449f498cc5f0e1725ba2071a3d4f48d5d9dffba42db196438", "sha256:224e57f6eac61cc449f498cc5f0e1725ba2071a3d4f48d5d9dffba42db196438",
"sha256:22fc2a8549ffe699bfba2256ab2ed0421a7b8fadff114a3d201794e45a9ff578", "sha256:22fc2a8549ffe699bfba2256ab2ed0421a7b8fadff114a3d201794e45a9ff578",
"sha256:23032ae55523cc7bccb4f6a0bf368cd25ad9bcdcc1990b64a647e7bbcce9cb5b", "sha256:23032ae55523cc7bccb4f6a0bf368cd25ad9bcdcc1990b64a647e7bbcce9cb5b",
"sha256:2333e30a5e00fe0fe55903c8832e08ee9c3b1382aacf4db26664a16528d51b4b", "sha256:2333e30a5e00fe0fe55903c8832e08ee9c3b1382aacf4db26664a16528d51b4b",
"sha256:2954c1c23f81c2eaf0b0717d9380bd348578a94161a65b3a2afc62c86467dd68", "sha256:2954c1c23f81c2eaf0b0717d9380bd348578a94161a65b3a2afc62c86467dd68",
"sha256:2a24c50840d89ded6c9a8fdc7b6ed3692ed4e86f1c4a4a938e1e92def92933e0",
"sha256:2de9d02f5bda03d27ede52e8cfe7b865b066fa49258cbab568720aa5be80a47d", "sha256:2de9d02f5bda03d27ede52e8cfe7b865b066fa49258cbab568720aa5be80a47d",
"sha256:2feb1d960f760a575dbc5ab3b1c00504b24caaf6986e2dc2b01c09c87866a943",
"sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd", "sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd",
"sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409", "sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409",
"sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28",
"sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da", "sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da",
"sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50", "sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50",
"sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f",
"sha256:3d7954194c36e304e1523f55d7042c59dc53ec20dd4e9ea9d151f1b62b4415c0", "sha256:3d7954194c36e304e1523f55d7042c59dc53ec20dd4e9ea9d151f1b62b4415c0",
"sha256:3ee8a80d67a4334482d9712b8e83ca6b1d9bc7e351931252ebef5d8f7335a547",
"sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180", "sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180",
"sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0",
"sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d", "sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d",
"sha256:4410f84b33374409552ac9b6903507cdb31cd30d2501fc5ca13d18f73548444a",
"sha256:494994f807ba0b92092a163a0a283961369a65f6cbe01e8891132b7a320e61eb",
"sha256:4d4a848d1837973bf0f4b5e54e3bec977d99be36a7895c61abb659301b02c112", "sha256:4d4a848d1837973bf0f4b5e54e3bec977d99be36a7895c61abb659301b02c112",
"sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc", "sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc",
"sha256:4f3607b129417e111e30637af1b56f24f7a49e64763253bbc275c75fa887d4b2",
"sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265", "sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265",
"sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327", "sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327",
"sha256:587ca6d3cef6e4e868102672d3bd9dc9698c309ba56d41c2b9c85bbb903cdb95", "sha256:587ca6d3cef6e4e868102672d3bd9dc9698c309ba56d41c2b9c85bbb903cdb95",
"sha256:58d4b711689366d4a03ac7957ab8c28890415e267f9b6589969e74b6e42225ec",
"sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd", "sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd",
"sha256:5dab0844f2cf82be357a0eb11a9087f70c5430b2c241493fc122bb6f2bb0917c",
"sha256:5e55da2c8724191e5b557f8e18943b1b4839b8efc3ef60d65985bcf6f587dd38",
"sha256:5eeb539606f18a0b232d4ba45adccde4125592f3f636a6182b4a8a436548b914", "sha256:5eeb539606f18a0b232d4ba45adccde4125592f3f636a6182b4a8a436548b914",
"sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0", "sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0",
"sha256:5fb2ce4b8045c78ebbc7b8f3c15062e435d47e7393cc57c25115cfd49883747a", "sha256:5fb2ce4b8045c78ebbc7b8f3c15062e435d47e7393cc57c25115cfd49883747a",
"sha256:6172447e1b368dcbc458925e5ddaf9113477b0ed542df258d84fa28fc45ceea7", "sha256:6172447e1b368dcbc458925e5ddaf9113477b0ed542df258d84fa28fc45ceea7",
"sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368",
"sha256:6974f52a02321b36847cd19d1b8e381bf39939c21efd6ee2fc13a28b0d99348c",
"sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0", "sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0",
"sha256:6c6e0c425f22c1c719c42670d561ad682f7bfeeef918edea971a79ac5252437f",
"sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451", "sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451",
"sha256:7905193081db9bfa73b1219140b3d315831cbff0d8941f22da695832f0dd188f", "sha256:7905193081db9bfa73b1219140b3d315831cbff0d8941f22da695832f0dd188f",
"sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8",
"sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e", "sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e",
"sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248", "sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248",
"sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c",
"sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91", "sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91",
"sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724", "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724",
"sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7",
"sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966", "sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966",
"sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9",
"sha256:890b5a14ce214389b2cc36ce82f3093f96f4cc730c1cffdbefff77a7c71f2a97", "sha256:890b5a14ce214389b2cc36ce82f3093f96f4cc730c1cffdbefff77a7c71f2a97",
"sha256:89f4988c7203739d48c6f806f1e87a1d96e0806d44f0fba61dba81392c9e474d", "sha256:89f4988c7203739d48c6f806f1e87a1d96e0806d44f0fba61dba81392c9e474d",
"sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5",
"sha256:8dadd1314583ec0bf2d1379f7008ad627cd6336625d6679cf2f8e67081b83acf", "sha256:8dadd1314583ec0bf2d1379f7008ad627cd6336625d6679cf2f8e67081b83acf",
"sha256:901032ff242d479a0efa956d853d16875d42157f98951c0230f69e69f9c09bac", "sha256:901032ff242d479a0efa956d853d16875d42157f98951c0230f69e69f9c09bac",
"sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b",
"sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951", "sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951",
"sha256:919e32f147ae93a09fe064d77d5ebf4e35502a8df75c29fb05788528e330fe74", "sha256:919e32f147ae93a09fe064d77d5ebf4e35502a8df75c29fb05788528e330fe74",
"sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648",
"sha256:929811df5462e182b13920da56c6e0284af407d1de637d8e536c5cd00a7daf60", "sha256:929811df5462e182b13920da56c6e0284af407d1de637d8e536c5cd00a7daf60",
"sha256:949f3b7c29912693cee0afcf09acd6ebc04c57af949d9bf77d6101ebb61e388c", "sha256:949f3b7c29912693cee0afcf09acd6ebc04c57af949d9bf77d6101ebb61e388c",
"sha256:a090ca607cbb6a34b0391776f0cb48062081f5f60ddcce5d11838e67a01928d1", "sha256:a090ca607cbb6a34b0391776f0cb48062081f5f60ddcce5d11838e67a01928d1",
@@ -362,27 +387,44 @@
"sha256:a599669fd7c47233438a56936988a2478685e74854088ef5293802123b5b2460", "sha256:a599669fd7c47233438a56936988a2478685e74854088ef5293802123b5b2460",
"sha256:a743e5a28af5f70f9c080380a5f908d4d21d40e8f0e0c8901604d15cfa9ba751", "sha256:a743e5a28af5f70f9c080380a5f908d4d21d40e8f0e0c8901604d15cfa9ba751",
"sha256:a77def80806c421b4b0af06f45d65a136e7ac0bdca3c09d9e2ea4e515367c7e9", "sha256:a77def80806c421b4b0af06f45d65a136e7ac0bdca3c09d9e2ea4e515367c7e9",
"sha256:a7e53012d2853a07a4a79c00643832161a910674a893d296c9f1259859a289d2",
"sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0",
"sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1", "sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1",
"sha256:ae15b066e5ad21366600ebec29a7ccbc86812ed267e4b28e860b8ca16a2bc474", "sha256:ae15b066e5ad21366600ebec29a7ccbc86812ed267e4b28e860b8ca16a2bc474",
"sha256:aea440a510e14e818e67bfc4027880e2fb500c2ccb20ab21c7a7c8b5b4703d75",
"sha256:af6fa6817889314555aede9a919612b23739395ce767fe7fcbea9a80bf140fe5",
"sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f",
"sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2", "sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2",
"sha256:c247dd99d39e0338a604f8c2b3bc7061d5c2e9e2ac7ba9cc1be5a69cb6cd832f",
"sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb",
"sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6", "sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6",
"sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9", "sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9",
"sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111",
"sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2", "sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2",
"sha256:cb1dac1770878ade83f2ccdf7d25e494f05c9165f5246b46a621cc849341dc01",
"sha256:cdad5b9014d83ca68c25d2e9444e28e967ef16e80f6b436918c700c117a85467", "sha256:cdad5b9014d83ca68c25d2e9444e28e967ef16e80f6b436918c700c117a85467",
"sha256:cdbc1fc1bc0bff1cef838eafe581b55bfbffaed4ed0318b724d0b71d4d377619", "sha256:cdbc1fc1bc0bff1cef838eafe581b55bfbffaed4ed0318b724d0b71d4d377619",
"sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf", "sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf",
"sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408", "sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408",
"sha256:d143fd47fad1db3d7c27a1b1d66162e855b5d50a89666af46e1679c496e8e579", "sha256:d143fd47fad1db3d7c27a1b1d66162e855b5d50a89666af46e1679c496e8e579",
"sha256:d192f0f30804e55db0d0e0a35d83a9fead0e9a359a9ed0285dbacea60cc10a84", "sha256:d192f0f30804e55db0d0e0a35d83a9fead0e9a359a9ed0285dbacea60cc10a84",
"sha256:d2b35ca2c7f81d173d2fadc2f4f31e88cc5f7a39ae5b6db5513cf3383b0e0ec7",
"sha256:d342778ef319e1026af243ed0a07c97acf3bad33b9f29e7ae6a1f68fd083e90c",
"sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284",
"sha256:d7702622a8b40c49bffb46e1e3ba2e81268d5c04a34f460978c6b5517a34dd52",
"sha256:db85ecf4e609a48f4b29055f1e144231b90edc90af7481aa731ba2d059226b1b", "sha256:db85ecf4e609a48f4b29055f1e144231b90edc90af7481aa731ba2d059226b1b",
"sha256:de6551e370ef19f8de1807d0a9aa2cdfdce2e85ce88b122fe9f6b2b076837e59", "sha256:de6551e370ef19f8de1807d0a9aa2cdfdce2e85ce88b122fe9f6b2b076837e59",
"sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752", "sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752",
"sha256:e4fe605b917c70283db7dfe5ada75e04561479075761a0b3866c081d035b01c1",
"sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80", "sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80",
"sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839",
"sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0", "sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0",
"sha256:e93dfc1a1165e385cc8239fab7c036fb2cd8093728cbd85097b284d7b99249a2", "sha256:e93dfc1a1165e385cc8239fab7c036fb2cd8093728cbd85097b284d7b99249a2",
"sha256:efa8b278894b14d6da122a72fefcebc28445f2d3f880ac59d46c90f4c13be9a3", "sha256:efa8b278894b14d6da122a72fefcebc28445f2d3f880ac59d46c90f4c13be9a3",
"sha256:f0d8a7a6b5983c2496e364b969f0e526647a06b075d034f3297dc66f3b360c64", "sha256:f0d8a7a6b5983c2496e364b969f0e526647a06b075d034f3297dc66f3b360c64",
"sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089",
"sha256:f296c40e23065d0d6650c4aefe7470d2a25fffda489bcc3eb66083f3ac9f6643", "sha256:f296c40e23065d0d6650c4aefe7470d2a25fffda489bcc3eb66083f3ac9f6643",
"sha256:f31859074d57b4639318523d6ffdca586ace54271a73ad23ad021acd807eb14b",
"sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e", "sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e",
"sha256:f733d788519c7e3e71f0855c96618720f5d3d60c3cb829d8bbb722dddce37985", "sha256:f733d788519c7e3e71f0855c96618720f5d3d60c3cb829d8bbb722dddce37985",
"sha256:fce1473f3ccc4187f75b4690cfc922628aed4d3dd013d047f95a9b3919a86596", "sha256:fce1473f3ccc4187f75b4690cfc922628aed4d3dd013d047f95a9b3919a86596",
@@ -3401,6 +3443,15 @@
"markers": "python_version >= '3.8'", "markers": "python_version >= '3.8'",
"version": "==8.2.2" "version": "==8.2.2"
}, },
"pytest-asyncio": {
"hashes": [
"sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b",
"sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
"version": "==0.24.0"
},
"sniffio": { "sniffio": {
"hashes": [ "hashes": [
"sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2",

View File

@@ -8,18 +8,16 @@ from loguru import logger
from db import crud, models from db import crud, models
from db.database import get_db, make_engine from db.database import get_db, make_engine
from shared.settings import Settings from shared.settings import get_settings
from utils.metrics import measure_regular_metrics, redis_subscribe_worker_exceptions from utils.metrics import measure_regular_metrics, redis_subscribe_worker_exceptions
settings = Settings()
@asynccontextmanager @asynccontextmanager
async def lifespan(app: FastAPI): async def lifespan(app: FastAPI):
# see https://fastapi.tiangolo.com/advanced/events/#lifespan # see https://fastapi.tiangolo.com/advanced/events/#lifespan
# STARTUP # STARTUP
engine = make_engine(settings.DATABASE_PATH) engine = make_engine(get_settings().DATABASE_PATH)
models.Base.metadata.create_all(bind=engine) models.Base.metadata.create_all(bind=engine)
alembic.config.main(argv=['--raiseerr', 'upgrade', 'head']) alembic.config.main(argv=['--raiseerr', 'upgrade', 'head'])
# disabling uvicorn logger since we use loguru in logging_middleware # disabling uvicorn logger since we use loguru in logging_middleware
@@ -42,6 +40,6 @@ async def refresh_user_groups():
crud.upsert_user_groups(db) crud.upsert_user_groups(db)
@repeat_every(seconds=settings.REPEAT_COUNT_METRICS_SECONDS) @repeat_every(seconds=get_settings().REPEAT_COUNT_METRICS_SECONDS)
async def repeat_measure_regular_metrics(): async def repeat_measure_regular_metrics():
measure_regular_metrics(settings.DATABASE_PATH, settings.REPEAT_COUNT_METRICS_SECONDS) measure_regular_metrics(get_settings().DATABASE_PATH, get_settings().REPEAT_COUNT_METRICS_SECONDS)

View File

@@ -5,13 +5,13 @@ from loguru import logger
from datetime import datetime, timedelta from datetime import datetime, timedelta
from web.security import ALLOW_ANY_EMAIL from web.security import ALLOW_ANY_EMAIL
from shared.settings import Settings from shared.settings import get_settings
from . import models, schemas from . import models, schemas
import yaml import yaml
DOMAIN_GROUPS = {} DOMAIN_GROUPS = {}
DOMAIN_GROUPS_LOADED = False DOMAIN_GROUPS_LOADED = False
DATABASE_QUERY_LIMIT = Settings().DATABASE_QUERY_LIMIT DATABASE_QUERY_LIMIT = get_settings().DATABASE_QUERY_LIMIT
# --------------- TASK = Archive # --------------- TASK = Archive
@@ -152,7 +152,7 @@ def upsert_user_groups(db: Session):
along with new participation of users in groups along with new participation of users in groups
""" """
logger.debug("Updating user-groups configuration.") logger.debug("Updating user-groups configuration.")
filename = Settings().USER_GROUPS_FILENAME filename = get_settings().USER_GROUPS_FILENAME
# read yaml safely # read yaml safely
try: try:

View File

@@ -1,11 +1,9 @@
from sqlalchemy import Engine, create_engine, event from sqlalchemy import Engine, create_engine, event
from sqlalchemy.orm import sessionmaker, declarative_base from sqlalchemy.orm import sessionmaker
from shared.settings import Settings from shared.settings import get_settings
from contextlib import contextmanager from contextlib import contextmanager
settings = Settings()
def make_engine(database_url: str): def make_engine(database_url: str):
engine = create_engine(database_url, connect_args={"check_same_thread": False}) engine = create_engine(database_url, connect_args={"check_same_thread": False})
@@ -25,7 +23,7 @@ def make_session_local(engine: Engine):
@contextmanager @contextmanager
def get_db(): def get_db():
session = make_session_local(make_engine(settings.DATABASE_PATH))() session = make_session_local(make_engine(get_settings().DATABASE_PATH))()
try: yield session try: yield session
finally: session.close() finally: session.close()

View File

@@ -5,12 +5,12 @@ from sqlalchemy import pool
from alembic import context from alembic import context
from shared.settings import Settings from shared.settings import get_settings
# this is the Alembic Config object, which provides # this is the Alembic Config object, which provides
# access to the values within the .ini file in use. # access to the values within the .ini file in use.
config = context.config config = context.config
config.set_main_option('sqlalchemy.url', Settings().DATABASE_PATH) config.set_main_option('sqlalchemy.url', get_settings().DATABASE_PATH)
# Interpret the config file for Python logging. # Interpret the config file for Python logging.
# This line sets up loggers basically. # This line sets up loggers basically.
if config.config_file_name is not None: if config.config_file_name is not None:

View File

@@ -1,4 +1,5 @@
from functools import lru_cache
from pydantic_settings import BaseSettings from pydantic_settings import BaseSettings
from pydantic import ConfigDict from pydantic import ConfigDict
from typing import Annotated, Set from typing import Annotated, Set
@@ -28,3 +29,7 @@ class Settings(BaseSettings):
ALLOWED_ORIGINS: Annotated[set[str], Len(min_length=1)] ALLOWED_ORIGINS: Annotated[set[str], Len(min_length=1)]
CHROME_APP_IDS: Annotated[set[Annotated[str, Len(min_length=10)]], Len(min_length=1)] CHROME_APP_IDS: Annotated[set[Annotated[str, Len(min_length=10)]], Len(min_length=1)]
BLOCKED_EMAILS: Annotated[Set[str], Len(min_length=0)] = set() BLOCKED_EMAILS: Annotated[Set[str], Len(min_length=0)] = set()
@lru_cache
def get_settings():
return Settings()

View File

@@ -13,7 +13,7 @@ def mock_logger_add():
@pytest.fixture() @pytest.fixture()
def settings(): def get_settings():
return Settings(_env_file=".env.test") return Settings(_env_file=".env.test")
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@@ -23,13 +23,13 @@ def mock_settings():
@pytest.fixture() @pytest.fixture()
def test_db(settings: Settings): def test_db(get_settings: Settings):
from db.database import make_engine from db.database import make_engine
from db import models from db import models
engine = make_engine(settings.DATABASE_PATH) engine = make_engine(get_settings.DATABASE_PATH)
fs = settings.DATABASE_PATH.replace("sqlite:///", "") fs = get_settings.DATABASE_PATH.replace("sqlite:///", "")
if not os.path.exists(fs): if not os.path.exists(fs):
open(fs, 'w').close() open(fs, 'w').close()

View File

@@ -135,7 +135,6 @@ def test_search_archives_by_url(test_data, db_session):
def test_search_archives_by_email(test_data, db_session): def test_search_archives_by_email(test_data, db_session):
from web.security import ALLOW_ANY_EMAIL from web.security import ALLOW_ANY_EMAIL
from db import crud from db import crud
from web.security import ALLOW_ANY_EMAIL
# lower/upper case # lower/upper case
assert len(crud.search_archives_by_email(db_session, "rick@example.com")) == 34 assert len(crud.search_archives_by_email(db_session, "rick@example.com")) == 34
@@ -363,13 +362,13 @@ def test_get_group(test_data, db_session):
def test_upsert_user_groups(db_session): def test_upsert_user_groups(db_session):
from db import crud from db import crud
@patch('db.crud.Settings', new = lambda: bad_setings) @patch('db.crud.get_settings', new = lambda: bad_setings)
def test_missing_yaml(db_session): def test_missing_yaml(db_session):
with pytest.raises(FileNotFoundError): with pytest.raises(FileNotFoundError):
crud.upsert_user_groups(db_session) crud.upsert_user_groups(db_session)
@patch('db.crud.Settings', new = lambda: bad_setings) @patch('db.crud.get_settings', new = lambda: bad_setings)
def test_broken_yaml(db_session): def test_broken_yaml(db_session):
with pytest.raises(yaml.YAMLError): with pytest.raises(yaml.YAMLError):
crud.upsert_user_groups(db_session) crud.upsert_user_groups(db_session)

View File

@@ -1,11 +1,11 @@
import os import os
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from shared.settings import Settings from shared.settings import get_settings
import shutil import shutil
def test_serve_local_archive_logic(settings: Settings): def test_serve_local_archive_logic(get_settings):
# create a test file first # create a test file first
os.makedirs("local_archive_test", exist_ok=True) os.makedirs("local_archive_test", exist_ok=True)
with open("local_archive_test/temp.txt", "w") as f: with open("local_archive_test/temp.txt", "w") as f:
@@ -13,9 +13,9 @@ def test_serve_local_archive_logic(settings: Settings):
try: try:
# modify the settings # modify the settings
settings.SERVE_LOCAL_ARCHIVE = "/app/local_archive_test" get_settings.SERVE_LOCAL_ARCHIVE = "/app/local_archive_test"
from web.main import app_factory from web.main import app_factory
app = app_factory(settings) app = app_factory(get_settings)
# test # test
client = TestClient(app) client = TestClient(app)

View File

@@ -0,0 +1,104 @@
from unittest.mock import patch
from fastapi import HTTPException
from fastapi.security import HTTPAuthorizationCredentials
import pytest
def test_secure_compare():
from web.security import secure_compare
assert secure_compare("test", "test")
assert not secure_compare("test", "test2")
@pytest.mark.asyncio
async def test_get_token_or_user_auth_with_api():
from web.security import get_token_or_user_auth, ALLOW_ANY_EMAIL
mock_api = HTTPAuthorizationCredentials(scheme="lorem", credentials="this_is_the_test_api_token")
assert await get_token_or_user_auth(mock_api) == ALLOW_ANY_EMAIL
@pytest.mark.asyncio
async def test_get_token_or_user_auth_with_user():
from web.security import get_token_or_user_auth
bad_user = HTTPAuthorizationCredentials(scheme="ipsum", credentials="invalid")
with pytest.raises(HTTPException) as e:
await get_token_or_user_auth(bad_user)
assert e.status_code == 401
assert e.detail == "invalid access_token"
@patch("web.security.authenticate_user", return_value=(True, "summer@example.com"))
@pytest.mark.asyncio
async def test_get_user_auth(m1):
from web.security import get_user_auth
bad_user = HTTPAuthorizationCredentials(scheme="ipsum", credentials="valid-and-good")
assert await get_user_auth(bad_user) == "summer@example.com"
@patch("web.security.secure_compare", return_value=False)
@pytest.mark.asyncio
async def test_token_api_key_auth_exception(m1):
from web.security import token_api_key_auth
with pytest.raises(HTTPException) as e:
await token_api_key_auth(HTTPAuthorizationCredentials(scheme="ipsum", credentials="does-not-matter"), auto_error=True)
assert e.status_code == 401
assert e.detail == "Wrong auth credentials"
@pytest.mark.asyncio
async def test_authenticate_user():
from web.security import authenticate_user
assert authenticate_user("test") == (False, "invalid access_token")
assert authenticate_user(123) == (False, "invalid access_token")
with patch("web.security.requests.get") as mock_get:
# bad response from oauth2
mock_get.return_value.status_code = 403
assert authenticate_user("this-will-call-requests") == (False, "invalid token")
assert mock_get.call_count == 1
# 200 but invalid json
mock_get.return_value.status_code = 200
assert authenticate_user("this-will-call-requests") == (False, "token does not belong to valid APP_ID")
assert mock_get.call_count == 2
# 200 but invalid azp and aud
mock_get.return_value.json.return_value = {"email": "summer@example.com", "azp": "not_an_app"}
assert authenticate_user("this-will-call-requests") == (False, "token does not belong to valid APP_ID")
mock_get.return_value.json.return_value = {"email": "summer@example.com", "aud": "not_an_app"}
assert authenticate_user("this-will-call-requests") == (False, "token does not belong to valid APP_ID")
mock_get.return_value.json.return_value = {"email": "summer@example.com", "azp": "not_an_app", "aud": "not_an_app"}
assert authenticate_user("this-will-call-requests") == (False, "token does not belong to valid APP_ID")
# blocked email
mock_get.return_value.json.return_value = {"email": "blocked@example.com", "azp": "test_app_id_1", "aud": "not_an_app"}
assert authenticate_user("this-will-call-requests") == (False, "email 'blocked@example.com' not allowed")
# not verified
mock_get.return_value.json.return_value = {"email": "summer@example.com", "azp": "not_an_app", "aud": "test_app_id_1"}
assert authenticate_user("this-will-call-requests") == (False, "email 'summer@example.com' not verified")
# token expired
mock_get.return_value.json.return_value = {"email": "summer@example.com", "azp": "test_app_id_2", "email_verified": "true"}
assert authenticate_user("this-will-call-requests") == (False, "Token expired")
# 200 and valid azp and aup and verified
mock_get.return_value.json.return_value = {"email": "summer@example.com", "azp": "test_app_id_2", "email_verified": "true", "expires_in": 100}
assert authenticate_user("this-will-call-requests") == (True, "summer@example.com")
assert mock_get.call_count == 9
@pytest.mark.asyncio
async def test_authenticate_user_exception():
from web.security import authenticate_user
with patch("web.security.requests.get") as mock_get:
mock_get.return_value.status_code = 200
mock_get.return_value.json.side_effect = Exception("mocked error")
assert authenticate_user("this-will-call-requests") == (False, "exception occurred")

View File

@@ -19,14 +19,14 @@ from web.security import get_user_auth, token_api_key_auth, get_token_or_user_au
from core.config import VERSION, API_DESCRIPTION from core.config import VERSION, API_DESCRIPTION
from db.database import get_db_dependency from db.database import get_db_dependency
from core.events import lifespan from core.events import lifespan
from shared.settings import Settings from shared.settings import get_settings
from auto_archiver import Metadata from auto_archiver import Metadata
from endpoints import default_router, url_router, sheet_router, task_router, interoperability_router from endpoints import default_router, url_router, sheet_router, task_router, interoperability_router
def app_factory(settings = Settings()): def app_factory(settings = get_settings()):
app = FastAPI( app = FastAPI(
title="Auto-Archiver API", title="Auto-Archiver API",
description=API_DESCRIPTION, description=API_DESCRIPTION,

View File

@@ -1,12 +1,12 @@
from loguru import logger from loguru import logger
import requests, os, secrets import requests, secrets
from fastapi import HTTPException, status, Depends from fastapi import HTTPException, status, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from shared.settings import Settings from shared.settings import get_settings
ALLOW_ANY_EMAIL = "*" ALLOW_ANY_EMAIL = "*"
settings = Settings() settings = get_settings()
bearer_security = HTTPBearer() bearer_security = HTTPBearer()
@@ -39,15 +39,15 @@ token_api_key_auth = api_key_auth(settings.API_BEARER_TOKEN)
async def get_token_or_user_auth(credentials: HTTPAuthorizationCredentials = Depends(bearer_security)): async def get_token_or_user_auth(credentials: HTTPAuthorizationCredentials = Depends(bearer_security)):
# tries to use the static API_KEY and defaults to google JWT auth # tries to use the static API_KEY and defaults to google JWT auth
access_token = credentials.credentials if await token_api_key_auth(credentials, auto_error=False): return ALLOW_ANY_EMAIL
if token_api_key_auth(access_token, auto_error=False): return ALLOW_ANY_EMAIL
return await get_user_auth(credentials) return await get_user_auth(credentials)
async def get_user_auth(credentials: HTTPAuthorizationCredentials = Depends(bearer_security)): async def get_user_auth(credentials: HTTPAuthorizationCredentials = Depends(bearer_security)):
# validates the Bearer token in the case that it requires it # validates the Bearer token in the case that it requires it
valid_user, info = authenticate_user(credentials.credentials) valid_user, info = authenticate_user(credentials.credentials)
if valid_user: return info if valid_user:
return info
logger.debug(f"TOKEN FAILURE: {valid_user=} {info=}") logger.debug(f"TOKEN FAILURE: {valid_user=} {info=}")
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
@@ -73,5 +73,5 @@ def authenticate_user(access_token):
return False, "Token expired" return False, "Token expired"
return True, j.get('email') return True, j.get('email')
except Exception as e: except Exception as e:
logger.warning(f"EXCEPTION occurred: {e}") logger.warning(f"AUTH EXCEPTION occurred: {e}")
return False, f"EXCEPTION occurred" return False, "exception occurred"

View File

@@ -10,12 +10,12 @@ from loguru import logger
from db import crud, schemas, models from db import crud, schemas, models
from db.database import get_db from db.database import get_db
from shared.settings import Settings from shared.settings import get_settings
import json import json
import redis import redis
from sqlalchemy import exc from sqlalchemy import exc
settings = Settings() settings = get_settings()
celery = Celery(__name__) celery = Celery(__name__)
celery.conf.broker_url = settings.CELERY_BROKER_URL celery.conf.broker_url = settings.CELERY_BROKER_URL