diff --git a/.cirrus.yml b/.cirrus.yml index 4427d8e381..6aa66a5ad4 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -39,7 +39,7 @@ tooling_tests_task: PYTHONPATH: . install_dependencies_script: - cd rspec-tools - - pipenv install + - pipenv install --dev - pipenv run pip install pytest pytest-cov tests_script: - bash ci/fetch_branches.sh diff --git a/ci/asciidoc_validation/validate_environment.py b/ci/asciidoc_validation/validate_environment.py deleted file mode 100644 index 4e451ca3b5..0000000000 --- a/ci/asciidoc_validation/validate_environment.py +++ /dev/null @@ -1,105 +0,0 @@ -# Validate the asciidoc environment directives in the given file(s). -# Errors are printed to the standard output stream. -# -# "ifdef" commands has to start the line without any leading spaces, -# as per asciidoc format. -# -# Only one form is allowed: -# ifdef::env-github,rspecator-view[] -# -# The closing command is: -# endif::env-github,rspecator-view[] -# -# It must be in the same file. -# Only one such environment is allowed per file. - -from pathlib import Path -import sys - - -VALID_IFDEF = "ifdef::env-github,rspecator-view[]" -VALID_ENDIF = "endif::env-github,rspecator-view[]" - - -class Checker: - def __init__(self, file: Path): - assert file.exists() - assert file.is_file() - - self._file = file - self._is_env_open = False - self._has_env = False - self._is_valid = True - - def process(self) -> bool: - content = self._file.read_text(encoding="utf-8") - lines = content.splitlines(keepends=False) - for line_index, line in enumerate(lines): - line_number = line_index + 1 - if line.startswith("ifdef::"): - self._process_open(line_number, line) - if line.startswith("endif::"): - self._process_close(line_number, line) - - if self._is_env_open: - self._on_error(len(lines), "The ifdef command is not closed.") - - return self._is_valid - - def _process_open(self, line_number: int, line: str): - if self._has_env: - self._on_error(line_number, "Only one ifdef command is allowed per file.") - - if self._is_env_open: - self._on_error(line_number, "The previous ifdef command was not closed.") - - self._has_env = True - self._is_env_open = True - - # IDEs should be configured to properly display the description, - # not the other way around. - # "env-vscode" was used in the passed. Instead, user should be able to - # toggle the rspecator view based on their needs. Help these users migrate. - if "vscode" in line: - self._on_error( - line_number, - "Configure VS Code to display rspecator-view by setting the asciidoctor attribute.", - ) - - if line != VALID_IFDEF: - self._on_error( - line_number, - f'Incorrect asciidoc environment. "{VALID_IFDEF}" should be used instead.', - ) - - def _process_close(self, line_number: int, line: str): - if not self._is_env_open: - self._on_error(line_number, "Unexpected endif command.") - - self._is_env_open = False - - if line != VALID_ENDIF: - self._on_error( - line_number, - f'Incorrect endif command. "{VALID_ENDIF}" should be used instead.', - ) - - def _on_error(self, line_number: int, message: str): - print(f"{self._file}:{line_number} {message}") - self._is_valid = False - - -def main(): - files = sys.argv[1:] - if not files: - sys.exit("Missing input files") - - valid = True - for file in files: - if not Checker(Path(file)).process(): - valid = False - if not valid: - sys.exit(1) - -if __name__ == "__main__": - main() diff --git a/ci/validate_asciidoc.sh b/ci/validate_asciidoc.sh index fda29ad643..7f0ea8b691 100755 --- a/ci/validate_asciidoc.sh +++ b/ci/validate_asciidoc.sh @@ -72,30 +72,8 @@ do exit_code=1 fi else - # Make sure include:: clauses are always more than one line away from the previous content - # Detect includes stuck to the line before - find "$dir" -name "*.adoc" -execdir sh -c 'grep -Pzl "\S[ \t]*\ninclude::" $1 | xargs -r -I@ realpath "$PWD/@"' shell {} \; > stuck - # Detect includes stuck to the line after - find "$dir" -name "*.adoc" -execdir sh -c 'grep -Pzl "include::[^\[]+\[\]\n[ \t]*[^\n]" $1 | xargs -r -I@ realpath "$PWD/@"' shell {} \; >> stuck - if [ -s stuck ]; then - echo "ERROR: These adoc files contain an include that is stuck to other content." - echo "This may result in broken tags and other display issues." - echo "Make sure there is an empty line before and after each include:" - cat stuck - exit_code=1 - fi - rm -f stuck - - # Validate modified files' ifdef/endif commands. - find "${dir}" -name '*.adoc' \ - -exec python3 "./ci/asciidoc_validation/validate_environment.py" '{}' '+' \ - >validate_env_commands 2>&1 - if [ -s validate_env_commands ]; then - echo "ERROR: Some ifdef/endif commands are misused." - cat validate_env_commands - exit_code=1 - fi - rm -f validate_env_commands + # Add the full path of all adoc files that were affected for sanitization + find ~+/"${dir}" -name '*.adoc' >> all_asciidocs for language in "${dir}"/*/ do @@ -125,6 +103,18 @@ do fi done +cd rspec-tools +cat ../all_asciidocs | xargs pipenv run rspec-tools check-asciidoc >validate_asciidoc 2>&1 +if [ -s validate_asciidoc ]; then + echo "ERROR: Invalid asciidoc description:" + cat validate_asciidoc + exit_code=1 +fi +rm -f validate_asciidoc ../all_asciidocs +cd .. + + + # Run asciidoctor and fail if a warning is emitted. # Use the tmp_SXYZ_language.adoc files (see note above). ADOC_COUNT=$(find rules -name "tmp*.adoc" | wc -l) diff --git a/rspec-tools/Pipfile b/rspec-tools/Pipfile index 625810f969..d40c75b825 100644 --- a/rspec-tools/Pipfile +++ b/rspec-tools/Pipfile @@ -17,7 +17,8 @@ slackclient = "*" [dev-packages] pytest = ">=6.2.2" mypy = ">=0.800" -rspec-tools = {editable = true, path = "."} +rspec-tools = {file = ".", editable = true} +pytest-snapshot = "*" [requires] python_version = "3.9" diff --git a/rspec-tools/Pipfile.lock b/rspec-tools/Pipfile.lock index f3c4b0b46d..005a404eb3 100644 --- a/rspec-tools/Pipfile.lock +++ b/rspec-tools/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "ea9f240f8315f033a9883d447d2feb9b40fbad6bcbc336f404d47ebb6334e4c7" + "sha256": "5275bfce06cb7aea2422d149640dee6b7052a74e37d82fb02665df43d223005e" }, "pipfile-spec": 6, "requires": { @@ -106,6 +106,7 @@ "sha256:fc37e9aef10a696a5a4474802930079ccfc14d9f9c10b4662169671ff034b7df", "sha256:fdee8405931b0615220e5ddf8cd7edd8592c606a8e4ca2a00704883c396e4479" ], + "markers": "python_version >= '3.6'", "version": "==3.8.6" }, "aiosignal": { @@ -113,6 +114,7 @@ "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17" ], + "markers": "python_version >= '3.7'", "version": "==1.3.1" }, "appdirs": { @@ -127,6 +129,7 @@ "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028" ], + "markers": "python_version >= '3.7'", "version": "==4.0.3" }, "attrs": { @@ -134,6 +137,7 @@ "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04", "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015" ], + "markers": "python_version >= '3.7'", "version": "==23.1.0" }, "beautifulsoup4": { @@ -141,6 +145,7 @@ "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da", "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a" ], + "markers": "python_full_version >= '3.6.0'", "version": "==4.12.2" }, "bs4": { @@ -155,6 +160,7 @@ "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" ], + "markers": "python_version >= '3.6'", "version": "==2023.7.22" }, "cffi": { @@ -212,102 +218,104 @@ "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" ], + "markers": "python_version >= '3.8'", "version": "==1.16.0" }, "charset-normalizer": { "hashes": [ - "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843", - "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786", - "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e", - "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8", - "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4", - "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa", - "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d", - "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82", - "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7", - "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895", - "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d", - "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a", - "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382", - "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678", - "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b", - "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e", - "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741", - "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4", - "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596", - "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9", - "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69", - "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c", - "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77", - "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13", - "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459", - "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e", - "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7", - "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908", - "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a", - "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f", - "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8", - "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482", - "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d", - "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d", - "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545", - "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34", - "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86", - "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6", - "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe", - "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e", - "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc", - "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7", - "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd", - "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c", - "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557", - "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a", - "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89", - "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078", - "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e", - "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4", - "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403", - "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0", - "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89", - "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115", - "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9", - "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05", - "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a", - "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec", - "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56", - "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38", - "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479", - "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c", - "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e", - "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd", - "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186", - "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455", - "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c", - "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65", - "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78", - "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287", - "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df", - "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43", - "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1", - "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7", - "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989", - "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a", - "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63", - "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884", - "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649", - "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810", - "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828", - "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4", - "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2", - "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd", - "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5", - "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe", - "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293", - "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e", - "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e", - "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8" + "sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5", + "sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93", + "sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a", + "sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d", + "sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c", + "sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1", + "sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58", + "sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2", + "sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557", + "sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147", + "sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041", + "sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2", + "sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2", + "sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7", + "sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296", + "sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690", + "sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67", + "sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57", + "sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597", + "sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846", + "sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b", + "sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97", + "sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c", + "sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62", + "sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa", + "sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f", + "sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e", + "sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821", + "sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3", + "sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4", + "sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb", + "sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727", + "sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514", + "sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d", + "sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761", + "sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55", + "sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f", + "sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c", + "sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034", + "sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6", + "sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae", + "sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1", + "sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14", + "sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1", + "sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228", + "sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708", + "sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48", + "sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f", + "sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5", + "sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f", + "sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4", + "sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8", + "sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff", + "sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61", + "sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b", + "sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97", + "sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b", + "sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605", + "sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728", + "sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d", + "sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c", + "sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf", + "sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673", + "sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1", + "sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b", + "sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41", + "sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8", + "sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f", + "sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4", + "sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008", + "sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9", + "sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5", + "sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f", + "sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e", + "sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273", + "sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45", + "sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e", + "sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656", + "sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e", + "sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c", + "sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2", + "sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72", + "sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056", + "sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397", + "sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42", + "sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd", + "sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3", + "sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213", + "sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf", + "sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67" ], - "version": "==3.3.0" + "markers": "python_full_version >= '3.7.0'", + "version": "==3.3.1" }, "click": { "hashes": [ @@ -315,41 +323,43 @@ "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==8.1.7" }, "cryptography": { "hashes": [ - "sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67", - "sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311", - "sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8", - "sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13", - "sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143", - "sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f", - "sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829", - "sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd", - "sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397", - "sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac", - "sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d", - "sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a", - "sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839", - "sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e", - "sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6", - "sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9", - "sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860", - "sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca", - "sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91", - "sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d", - "sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714", - "sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb", - "sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f" + "sha256:0c327cac00f082013c7c9fb6c46b7cc9fa3c288ca702c74773968173bda421bf", + "sha256:0d2a6a598847c46e3e321a7aef8af1436f11c27f1254933746304ff014664d84", + "sha256:227ec057cd32a41c6651701abc0328135e472ed450f47c2766f23267b792a88e", + "sha256:22892cc830d8b2c89ea60148227631bb96a7da0c1b722f2aac8824b1b7c0b6b8", + "sha256:392cb88b597247177172e02da6b7a63deeff1937fa6fec3bbf902ebd75d97ec7", + "sha256:3be3ca726e1572517d2bef99a818378bbcf7d7799d5372a46c79c29eb8d166c1", + "sha256:573eb7128cbca75f9157dcde974781209463ce56b5804983e11a1c462f0f4e88", + "sha256:580afc7b7216deeb87a098ef0674d6ee34ab55993140838b14c9b83312b37b86", + "sha256:5a70187954ba7292c7876734183e810b728b4f3965fbe571421cb2434d279179", + "sha256:73801ac9736741f220e20435f84ecec75ed70eda90f781a148f1bad546963d81", + "sha256:7d208c21e47940369accfc9e85f0de7693d9a5d843c2509b3846b2db170dfd20", + "sha256:8254962e6ba1f4d2090c44daf50a547cd5f0bf446dc658a8e5f8156cae0d8548", + "sha256:88417bff20162f635f24f849ab182b092697922088b477a7abd6664ddd82291d", + "sha256:a48e74dad1fb349f3dc1d449ed88e0017d792997a7ad2ec9587ed17405667e6d", + "sha256:b948e09fe5fb18517d99994184854ebd50b57248736fd4c720ad540560174ec5", + "sha256:c707f7afd813478e2019ae32a7c49cd932dd60ab2d2a93e796f68236b7e1fbf1", + "sha256:d38e6031e113b7421db1de0c1b1f7739564a88f1684c6b89234fbf6c11b75147", + "sha256:d3977f0e276f6f5bf245c403156673db103283266601405376f075c849a0b936", + "sha256:da6a0ff8f1016ccc7477e6339e1d50ce5f59b88905585f77193ebd5068f1e797", + "sha256:e270c04f4d9b5671ebcc792b3ba5d4488bf7c42c3c241a3748e2599776f29696", + "sha256:e886098619d3815e0ad5790c973afeee2c0e6e04b4da90b88e6bd06e2a0b1b72", + "sha256:ec3b055ff8f1dce8e6ef28f626e0972981475173d7973d63f271b29c8a2897da", + "sha256:fba1e91467c65fe64a82c689dc6cf58151158993b13eb7a7f3f4b7f395636723" ], - "version": "==41.0.4" + "version": "==41.0.5" }, "deprecated": { "hashes": [ "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c", "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.2.14" }, "frozenlist": { @@ -416,6 +426,7 @@ "sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1", "sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e" ], + "markers": "python_version >= '3.8'", "version": "==1.4.0" }, "fs": { @@ -428,24 +439,27 @@ }, "gitdb": { "hashes": [ - "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a", - "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7" + "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4", + "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b" ], - "version": "==4.0.10" + "markers": "python_version >= '3.7'", + "version": "==4.0.11" }, "gitpython": { "hashes": [ - "sha256:5f4c4187de49616d710a77e98ddf17b4782060a1788df441846bddefbb89ab33", - "sha256:f9b9ddc0761c125d5780eab2d64be4873fc6817c2899cbcb34b02344bdc7bc54" + "sha256:22b126e9ffb671fdd0c129796343a02bf67bf2994b35449ffc9321aa755e18a4", + "sha256:cf14627d5a8049ffbf49915732e5eddbe8134c3bdb9d476e6182b676fc573f8a" ], "index": "pypi", - "version": "==3.1.37" + "markers": "python_version >= '3.7'", + "version": "==3.1.40" }, "idna": { "hashes": [ "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" ], + "markers": "python_version >= '3.5'", "version": "==3.4" }, "jsonschema": { @@ -454,6 +468,7 @@ "sha256:ec84cc37cfa703ef7cd4928db24f9cb31428a5d0fa77747b8b51a847458e0bbf" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==4.19.1" }, "jsonschema-specifications": { @@ -461,6 +476,7 @@ "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1", "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb" ], + "markers": "python_version >= '3.8'", "version": "==2023.7.1" }, "multidict": { @@ -540,6 +556,7 @@ "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d", "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba" ], + "markers": "python_version >= '3.7'", "version": "==6.0.4" }, "pycparser": { @@ -555,13 +572,18 @@ "sha256:ecf12c2809c44147bce63b047b3d2e9dac8a41b63e90fcb263c703f64936b97c" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==2.1.1" }, "pyjwt": { + "extras": [ + "crypto" + ], "hashes": [ "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" ], + "markers": "python_version >= '3.7'", "version": "==2.8.0" }, "pynacl": { @@ -577,6 +599,7 @@ "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b", "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543" ], + "markers": "python_version >= '3.6'", "version": "==1.5.0" }, "python-dateutil": { @@ -584,6 +607,7 @@ "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.8.2" }, "referencing": { @@ -591,6 +615,7 @@ "sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf", "sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0" ], + "markers": "python_version >= '3.8'", "version": "==0.30.2" }, "requests": { @@ -598,6 +623,7 @@ "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" ], + "markers": "python_version >= '3.7'", "version": "==2.31.0" }, "rpds-py": { @@ -702,17 +728,27 @@ "sha256:f0f17f2ce0f3529177a5fff5525204fad7b43dd437d017dd0317f2746773443d", "sha256:f4e56860a5af16a0fcfa070a0a20c42fbb2012eed1eb5ceeddcc7f8079214281" ], + "markers": "python_version >= '3.8'", "version": "==0.10.6" }, "rspec-tools": { "editable": true, "path": "." }, + "setuptools": { + "hashes": [ + "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87", + "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a" + ], + "markers": "python_version >= '3.8'", + "version": "==68.2.2" + }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, "slackapi": { @@ -728,6 +764,7 @@ "sha256:ab79fefb5412d0595bc01d2f195a787597f2a617b6766562932ab9ffbe5cb173" ], "index": "pypi", + "markers": "python_full_version >= '3.6.0'", "version": "==2.9.4" }, "smmap": { @@ -735,6 +772,7 @@ "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62", "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da" ], + "markers": "python_version >= '3.7'", "version": "==5.0.1" }, "soupsieve": { @@ -742,6 +780,7 @@ "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690", "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7" ], + "markers": "python_version >= '3.8'", "version": "==2.5" }, "typing-extensions": { @@ -749,14 +788,16 @@ "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0", "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef" ], + "markers": "python_version >= '3.8'", "version": "==4.8.0" }, "urllib3": { "hashes": [ - "sha256:7a7c7003b000adf9e7ca2a377c9688bbc54ed41b985789ed576570342a375cd2", - "sha256:b19e1a85d206b56d7df1d5e683df4a7725252a964e3993648dd0fb5a1c157564" + "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84", + "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e" ], - "version": "==2.0.6" + "markers": "python_version >= '3.7'", + "version": "==2.0.7" }, "wrapt": { "hashes": [ @@ -836,6 +877,7 @@ "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559", "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==1.15.0" }, "yarl": { @@ -915,6 +957,7 @@ "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78", "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7" ], + "markers": "python_version >= '3.7'", "version": "==1.9.2" } }, @@ -932,46 +975,49 @@ "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" ], + "markers": "python_version >= '3.7'", "version": "==2.0.0" }, "mypy": { "hashes": [ - "sha256:091f53ff88cb093dcc33c29eee522c087a438df65eb92acd371161c1f4380ff0", - "sha256:1a69db3018b87b3e6e9dd28970f983ea6c933800c9edf8c503c3135b3274d5ad", - "sha256:24f3de8b9e7021cd794ad9dfbf2e9fe3f069ff5e28cb57af6f873ffec1cb0425", - "sha256:31eba8a7a71f0071f55227a8057468b8d2eb5bf578c8502c7f01abaec8141b2f", - "sha256:3c8835a07b8442da900db47ccfda76c92c69c3a575872a5b764332c4bacb5a0a", - "sha256:3df87094028e52766b0a59a3e46481bb98b27986ed6ded6a6cc35ecc75bb9182", - "sha256:49499cf1e464f533fc45be54d20a6351a312f96ae7892d8e9f1708140e27ce41", - "sha256:4c192445899c69f07874dabda7e931b0cc811ea055bf82c1ababf358b9b2a72c", - "sha256:4f3d27537abde1be6d5f2c96c29a454da333a2a271ae7d5bc7110e6d4b7beb3f", - "sha256:7469545380dddce5719e3656b80bdfbb217cfe8dbb1438532d6abc754b828fed", - "sha256:7807a2a61e636af9ca247ba8494031fb060a0a744b9fee7de3a54bed8a753323", - "sha256:856bad61ebc7d21dbc019b719e98303dc6256cec6dcc9ebb0b214b81d6901bd8", - "sha256:89513ddfda06b5c8ebd64f026d20a61ef264e89125dc82633f3c34eeb50e7d60", - "sha256:8e0db37ac4ebb2fee7702767dfc1b773c7365731c22787cb99f507285014fcaf", - "sha256:971104bcb180e4fed0d7bd85504c9036346ab44b7416c75dd93b5c8c6bb7e28f", - "sha256:9e1589ca150a51d9d00bb839bfeca2f7a04f32cd62fad87a847bc0818e15d7dc", - "sha256:9f8464ed410ada641c29f5de3e6716cbdd4f460b31cf755b2af52f2d5ea79ead", - "sha256:ab98b8f6fdf669711f3abe83a745f67f50e3cbaea3998b90e8608d2b459fd566", - "sha256:b19006055dde8a5425baa5f3b57a19fa79df621606540493e5e893500148c72f", - "sha256:c69051274762cccd13498b568ed2430f8d22baa4b179911ad0c1577d336ed849", - "sha256:d2dad072e01764823d4b2f06bc7365bb1d4b6c2f38c4d42fade3c8d45b0b4b67", - "sha256:dccd850a2e3863891871c9e16c54c742dba5470f5120ffed8152956e9e0a5e13", - "sha256:e28d7b221898c401494f3b77db3bac78a03ad0a0fff29a950317d87885c655d2", - "sha256:e4b7a99275a61aa22256bab5839c35fe8a6887781862471df82afb4b445daae6", - "sha256:eb7ff4007865833c470a601498ba30462b7374342580e2346bf7884557e40531", - "sha256:f8598307150b5722854f035d2e70a1ad9cc3c72d392c34fffd8c66d888c90f17", - "sha256:fea451a3125bf0bfe716e5d7ad4b92033c471e4b5b3e154c67525539d14dc15a" + "sha256:19f905bcfd9e167159b3d63ecd8cb5e696151c3e59a1742e79bc3bcb540c42c7", + "sha256:21a1ad938fee7d2d96ca666c77b7c494c3c5bd88dff792220e1afbebb2925b5e", + "sha256:40b1844d2e8b232ed92e50a4bd11c48d2daa351f9deee6c194b83bf03e418b0c", + "sha256:41697773aa0bf53ff917aa077e2cde7aa50254f28750f9b88884acea38a16169", + "sha256:49ae115da099dcc0922a7a895c1eec82c1518109ea5c162ed50e3b3594c71208", + "sha256:4c46b51de523817a0045b150ed11b56f9fff55f12b9edd0f3ed35b15a2809de0", + "sha256:4cbe68ef919c28ea561165206a2dcb68591c50f3bcf777932323bc208d949cf1", + "sha256:4d01c00d09a0be62a4ca3f933e315455bde83f37f892ba4b08ce92f3cf44bcc1", + "sha256:59a0d7d24dfb26729e0a068639a6ce3500e31d6655df8557156c51c1cb874ce7", + "sha256:68351911e85145f582b5aa6cd9ad666c8958bcae897a1bfda8f4940472463c45", + "sha256:7274b0c57737bd3476d2229c6389b2ec9eefeb090bbaf77777e9d6b1b5a9d143", + "sha256:81af8adaa5e3099469e7623436881eff6b3b06db5ef75e6f5b6d4871263547e5", + "sha256:82e469518d3e9a321912955cc702d418773a2fd1e91c651280a1bda10622f02f", + "sha256:8b27958f8c76bed8edaa63da0739d76e4e9ad4ed325c814f9b3851425582a3cd", + "sha256:8c223fa57cb154c7eab5156856c231c3f5eace1e0bed9b32a24696b7ba3c3245", + "sha256:8f57e6b6927a49550da3d122f0cb983d400f843a8a82e65b3b380d3d7259468f", + "sha256:925cd6a3b7b55dfba252b7c4561892311c5358c6b5a601847015a1ad4eb7d332", + "sha256:a43ef1c8ddfdb9575691720b6352761f3f53d85f1b57d7745701041053deff30", + "sha256:a8032e00ce71c3ceb93eeba63963b864bf635a18f6c0c12da6c13c450eedb183", + "sha256:b96ae2c1279d1065413965c607712006205a9ac541895004a1e0d4f281f2ff9f", + "sha256:bb8ccb4724f7d8601938571bf3f24da0da791fe2db7be3d9e79849cb64e0ae85", + "sha256:bbaf4662e498c8c2e352da5f5bca5ab29d378895fa2d980630656178bd607c46", + "sha256:cfd13d47b29ed3bbaafaff7d8b21e90d827631afda134836962011acb5904b71", + "sha256:d4473c22cc296425bbbce7e9429588e76e05bc7342da359d6520b6427bf76660", + "sha256:d8fbb68711905f8912e5af474ca8b78d077447d8f3918997fecbf26943ff3cbb", + "sha256:e5012e5cc2ac628177eaac0e83d622b2dd499e28253d4107a08ecc59ede3fc2c", + "sha256:eb4f18589d196a4cbe5290b435d135dee96567e07c2b2d43b5c4621b6501531a" ], "index": "pypi", - "version": "==1.6.0" + "markers": "python_version >= '3.8'", + "version": "==1.6.1" }, "mypy-extensions": { "hashes": [ "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" ], + "markers": "python_version >= '3.5'", "version": "==1.0.0" }, "packaging": { @@ -979,6 +1025,7 @@ "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" ], + "markers": "python_version >= '3.7'", "version": "==23.2" }, "pluggy": { @@ -986,15 +1033,26 @@ "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" ], + "markers": "python_version >= '3.8'", "version": "==1.3.0" }, "pytest": { "hashes": [ - "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002", - "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069" + "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac", + "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5" ], "index": "pypi", - "version": "==7.4.2" + "markers": "python_version >= '3.7'", + "version": "==7.4.3" + }, + "pytest-snapshot": { + "hashes": [ + "sha256:4b9fe1c21c868fe53a545e4e3184d36bc1c88946e3f5c1d9dd676962a9b3d4ab", + "sha256:c7013c3abc3e860f9feff899f8b4debe3708650d8d8242a61bf2625ff64db7f3" + ], + "index": "pypi", + "markers": "python_version >= '3.5'", + "version": "==0.9.0" }, "rspec-tools": { "editable": true, @@ -1013,6 +1071,7 @@ "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0", "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef" ], + "markers": "python_version >= '3.8'", "version": "==4.8.0" } } diff --git a/rspec-tools/README.adoc b/rspec-tools/README.adoc index 2f701f60a3..ea46a5793b 100644 --- a/rspec-tools/README.adoc +++ b/rspec-tools/README.adoc @@ -27,7 +27,7 @@ Usage .See all commands [source,sh] ---- -$ rspec-tools --help +$ pipenv run rspec-tools --help ---- @@ -44,7 +44,7 @@ $ pipenv install --dev -e . .Run tests [source,sh] ---- -$ pytest +$ pipenv run pytest ---- .Fixtures diff --git a/rspec-tools/rspec_tools/cli.py b/rspec-tools/rspec_tools/cli.py index f57b91edff..0b1e85e44b 100644 --- a/rspec-tools/rspec_tools/cli.py +++ b/rspec-tools/rspec_tools/cli.py @@ -18,6 +18,7 @@ from rspec_tools.validation.description import (validate_subsections, validate_section_levels, validate_section_names, validate_source_language) +from rspec_tools.validation.sanitize_asciidoc import sanitize_asciidoc from rspec_tools.validation.metadata import validate_rule_metadata @@ -87,6 +88,17 @@ def validate_rules_metadata(rules): _fatal_error(f"Validation failed due to {error_counter} errors out of {len(rules)} analyzed rules") +@cli.command() +@click.argument('files', nargs=-1, required=True) +def check_asciidoc(files): + '''Sanitize the AsciiDoc description.''' + error_counter = 0 + for file in files: + error_counter += sanitize_asciidoc(Path(file)) + if error_counter > 0: + _fatal_error(f"Validation of the asciidoc description failed due to {error_counter} errors") + + VALIDATORS = [validate_subsections, validate_section_names, validate_section_levels, diff --git a/rspec-tools/rspec_tools/validation/sanitize_asciidoc.py b/rspec-tools/rspec_tools/validation/sanitize_asciidoc.py new file mode 100644 index 0000000000..9f0e3fd52b --- /dev/null +++ b/rspec-tools/rspec_tools/validation/sanitize_asciidoc.py @@ -0,0 +1,254 @@ +""" Ensure the asciidoc code for a rule description follows best practices + +Checks are: +* "ifdef"/"endif" blocks should be well-formed for RSPEC +* Inline code with backquotes is correctly escaped and balanced +* Include commands are not appended to other code +""" +from pathlib import Path +import re + + +VALID_IFDEF = "ifdef::env-github,rspecator-view[]" +VALID_ENDIF = "endif::env-github,rspecator-view[]" + +VARIABLE_DECL = re.compile(r':\w+: ') + +INCLUDE = re.compile(r'include::') + +FORMATTING_CHARS = ['_', r'\*', r'\#'] +WORD_FORMATTING_CHARS = [r'\~', r'\^'] + +# If the formatting char is repeated twice, it can go anywhere +UNCONSTRAINED_FORMATTING = '|'.join(x + x for x in FORMATTING_CHARS) +# Single formatting char are dangerous at the beginning of a word +FORMATTING_OPENING = '|'.join(r'(\W|^)' + x + r'\w' for x in FORMATTING_CHARS) +# Single formatting char are dangerous at the end of a word +FORMATTING_CLOSING = '|'.join(r'\w' + x + r'(\W|$)' for x in FORMATTING_CHARS) +# Word formatting is broken by spaces so we look for things like `#word#` +WORD_FORMATTING = "|".join(x + r'\S+' + x for x in WORD_FORMATTING_CHARS) + +# We combine all the matchers +NEED_PROTECTION = re.compile('(' + f'{UNCONSTRAINED_FORMATTING}|' + f'{FORMATTING_OPENING}|' + f'{FORMATTING_CLOSING}|' + f'{WORD_FORMATTING}' + ')') + +# There is a regex trick here: +# We want to stop the search if there is a backquote +# We do that by matching backquote OR the closing passthrough +# Then we'll ignore any match of backquote +CLOSE_CONSTRAINED_PASSTHROUGH = re.compile(r'`|((?(``+)|(? 0: + # `+++a++` will display '+a' in case of inbalance, we try to find the biggest closing block + if count == 1: + if not line[pos + count].isspace() and line[pos - 1] == '`': + #constrained '+'. It is a passthrough only if it is directly around text and surrounded by backquotes: `+Some Content+` + close_pattern = CLOSE_CONSTRAINED_PASSTHROUGH + else: + return pos + else: + close_pattern = re.compile('(' + r'\+' * count + ')') + end = close_pattern.search(line, pos + count) + if end and end.group(1): + return end.end() + count -= 1 + return pos + + +def skip_passthrough_macro(line, pos): + '''If this is a passthrough macro, skip to the end''' + if line[pos] == 'p': + pm = PASSTHROUGH_MACRO.match(line, pos) + if pm: + return pm.end() + return pos + + +def skip_passthrough_plus(line, pos): + '''If this is a passthrough +, skip to the end''' + if line[pos] == '+': + count = 1 + while pos + count < len(line) and line[pos + count] == '+': + count += 1 + return close_passthrough(count, pos, line) + return pos + + +def close_inline_block(line: str, pos: int, closing_pattern: re.Pattern[str]): + """Find the end of an inline block started with *pattern*""" + content = "" + while pos < len(line): + pos = skip_passthrough_macro(line, pos) + pos = skip_passthrough_plus(line, pos) + if closing_pattern.match(line, pos): + return pos, content + content += line[pos] + pos += 1 + return -1, content + + +class Sanitizer: + def __init__(self, file: Path): + assert file.exists() + assert file.is_file() + + self._file = file + self._is_env_open = False + self._has_env = False + self._error_count = 0 + self._is_inside_code = False + self._empty_line = True + self._previous_line_was_include = False + + def process(self) -> bool: + content = self._file.read_text(encoding="utf-8") + lines = content.splitlines(keepends=False) + for line_index, line in enumerate(lines): + if self._is_inside_code: + if line == '----': + self._is_inside_code = False + continue + if line == '----': + self._is_inside_code = True + continue + line_number = line_index + 1 + if line.startswith("ifdef::"): + self._process_open_ifdef(line_number, line) + elif line.startswith("endif::"): + self._process_close_ifdef(line_number, line) + elif not line.strip(): + self._empty_line = True + else: + self._process_description(line_number, line) + self._empty_line = False + + if self._is_env_open: + self._on_error(len(lines), "An ifdef command is opened but never closed.") + + return self._error_count + + def _process_open_ifdef(self, line_number: int, line: str): + if self._has_env: + message = "Only one ifdef command is allowed per file." + if self._is_env_open: + message += "\nThe previous ifdef command was not closed." + self._on_error(line_number, message) + + self._has_env = True + self._is_env_open = True + + # IDEs should be configured to properly display the description, + # not the other way around. + # "env-vscode" was used in the passed. Instead, user should be able to + # toggle the rspecator view based on their needs. Help these users migrate. + if "vscode" in line: + self._on_error( + line_number, + "Configure VS Code to display rspecator-view by setting the asciidoctor attribute.", + ) + elif line != VALID_IFDEF: + self._on_error( + line_number, + f'Incorrect asciidoc environment. "{VALID_IFDEF}" should be used instead.', + ) + + def _process_close_ifdef(self, line_number: int, line: str): + if not self._is_env_open: + self._on_error(line_number, "Unexpected endif command.") + + self._is_env_open = False + + if line != VALID_ENDIF: + self._on_error( + line_number, + f'Incorrect endif command. "{VALID_ENDIF}" should be used instead.', + ) + + def _process_description(self, line_number: int, line: str): + if VARIABLE_DECL.match(line): + return + if self._previous_line_was_include and not self._empty_line: + self._on_error(line_number - 1, '''An empty line is missing after the include. +This may result in broken tags and other display issues. +Make sure there are always empty lines before and after each include''') + if INCLUDE.match(line): + self._previous_line_was_include = True + if not self._empty_line: + self._on_error(line_number, '''An empty line is missing before the include. +This may result in broken tags and other display issues. +Make sure there are always empty lines before and after each include''') + return + else: + self._previous_line_was_include = False + pos = 0 + res = BACKQUOTE.search(line, pos) + # We filter out matches for passthrough. See comment near the BACKQUOTE declaration + while res and res.group('backquote'): + pos = self._check_inlined_code(line_number, res.end(), line, res.group('backquote')) + res = BACKQUOTE.search(line, pos) + + def _check_inlined_code(self, line_number: int, pos: int, line: str, opening_pattern: str): + if len(opening_pattern) > 2: + # Part of the backquotes are displayed as backquotes. + self._on_error(line_number, 'Use "++" to isolate the backquotes you want to display from the ones that should be interpreted by AsciiDoc.') + return pos + elif len(opening_pattern) == 2: + closing_pattern = CLOSE_UNCONSTRAINED_BACKQUOTE + else: + closing_pattern = CLOSE_CONSTRAINED_BACKQUOTE + + content_end, content = close_inline_block(line, pos, closing_pattern) + if content_end < 0: + message='Unbalanced code inlining tags.' + if len(opening_pattern) == 1: + message += ''' +If you are trying to write inline code that is glued to text without a space, +you need to use double backquotes: +> Replace all `reference`s. +Will not display correctly. You need to write: +> Replace all ``reference``s. +''' + self._on_error(line_number, message) + return len(line) + pos = content_end + len(opening_pattern) + if NEED_PROTECTION.search(content): + self._on_error (line_number, f''' +Using backquotes does not protect against asciidoc interpretation. Starting or +ending a word with '*', '#', '_' or having two of them consecutively will +trigger unintended behavior with the rest of the text. +Use ``++{content}++`` to avoid that. +If you really want to have formatting inside your code, you can write +``pass:n[{content}]`` +''') + return pos + return pos + + def _on_error(self, line_number: int, message: str): + print(f"{self._file}:{line_number} {message}") + self._error_count += 1 + + +def sanitize_asciidoc(file_path: Path): + """Called by the CLI""" + return Sanitizer(file_path).process() diff --git a/rspec-tools/tests/conftest.py b/rspec-tools/tests/conftest.py index ce8fa0cb7c..034638b0a5 100644 --- a/rspec-tools/tests/conftest.py +++ b/rspec-tools/tests/conftest.py @@ -20,6 +20,17 @@ def mockinvalidrules(): return Path(__file__).parent.joinpath('resources', 'invalid-rules') +@pytest.fixture +def mockinvalidasciidoc(): + '''Provides a path to test asciidoc resources.''' + return Path(__file__).parent.joinpath('resources', 'invalid-asciidoc') + + +@pytest.fixture +def mockasciidoc(): + '''Provides a path to test asciidoc resources.''' + return Path(__file__).parent.joinpath('resources', 'asciidoc') + @pytest.fixture def git_config(): '''Create a mock git configuration.''' diff --git a/rspec-tools/tests/resources/asciidoc/valid.adoc b/rspec-tools/tests/resources/asciidoc/valid.adoc new file mode 100644 index 0000000000..70bdc8ded4 --- /dev/null +++ b/rspec-tools/tests/resources/asciidoc/valid.adoc @@ -0,0 +1,35 @@ +This is a file with `valid inlined code`. +It's using ``unconstrained tag``s. +It has ``++**protected tags**++`` +It escapes `++`++` backquotes +it can use `\` or `+` + +Plays well with beginning and end of lines: +`++`++` + +Mix of passthrough and plusses `+{plus}##+{plus}+` + +:var: ``Variables are not interpreted` + +{var} + +We can use passthrough macros `pass:[__like that__]` + +Or we can use passthrough macros `as a pass:[__part__] of the code`. + +The pass:[can also be outside `__the backquotes__`] + +The pass:[``++Can have __ [escaped brackets\] __ ++``] + +[source,python] +---- +# We don't care about `in the code +---- + +We can have a sole ` surrounded by spaces + +This file does not exist but we only check that the include is well placed: + +include::everything_ok.adoc[] + +For `constrained*format` we don't raise an issue unless `+*it's+ at the beginning or end of a +~word~+`. \ No newline at end of file diff --git a/rspec-tools/tests/resources/invalid-asciidoc/close_unopened_ifdef.adoc b/rspec-tools/tests/resources/invalid-asciidoc/close_unopened_ifdef.adoc new file mode 100644 index 0000000000..3c8a89baed --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/close_unopened_ifdef.adoc @@ -0,0 +1,5 @@ +Some description + +Now we try to close and ifdef that was never opened. + +endif::env-github,rspecator-view[] diff --git a/rspec-tools/tests/resources/invalid-asciidoc/include_stuck_after.adoc b/rspec-tools/tests/resources/invalid-asciidoc/include_stuck_after.adoc new file mode 100644 index 0000000000..03487ad04c --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/include_stuck_after.adoc @@ -0,0 +1,4 @@ +# Header + +include::somefile.adoc[] +* content just after \ No newline at end of file diff --git a/rspec-tools/tests/resources/invalid-asciidoc/include_stuck_before.adoc b/rspec-tools/tests/resources/invalid-asciidoc/include_stuck_before.adoc new file mode 100644 index 0000000000..78f6cba7c4 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/include_stuck_before.adoc @@ -0,0 +1,2 @@ +# Header +include::somefile.adoc[] diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/close_unopened_ifdef.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/close_unopened_ifdef.txt new file mode 100644 index 0000000000..8bcef2b0b6 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/close_unopened_ifdef.txt @@ -0,0 +1 @@ +$PATH/close_unopened_ifdef.adoc:5 Unexpected endif command. diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/include_stuck_after.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/include_stuck_after.txt new file mode 100644 index 0000000000..69927bfa99 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/include_stuck_after.txt @@ -0,0 +1,3 @@ +$PATH/include_stuck_after.adoc:3 An empty line is missing after the include. +This may result in broken tags and other display issues. +Make sure there are always empty lines before and after each include diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/include_stuck_before.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/include_stuck_before.txt new file mode 100644 index 0000000000..77d256f177 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/include_stuck_before.txt @@ -0,0 +1,3 @@ +$PATH/include_stuck_before.adoc:2 An empty line is missing before the include. +This may result in broken tags and other display issues. +Make sure there are always empty lines before and after each include diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/triple_backquotes.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/triple_backquotes.txt new file mode 100644 index 0000000000..ececb05396 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/triple_backquotes.txt @@ -0,0 +1 @@ +$PATH/triple_backquotes.adoc:1 Use "++" to isolate the backquotes you want to display from the ones that should be interpreted by AsciiDoc. diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/two_ifdef.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/two_ifdef.txt new file mode 100644 index 0000000000..09d6eebe4c --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/two_ifdef.txt @@ -0,0 +1 @@ +$PATH/two_ifdef.adoc:9 Only one ifdef command is allowed per file. diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/two_ifdef_unclosed.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/two_ifdef_unclosed.txt new file mode 100644 index 0000000000..3b619851e5 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/two_ifdef_unclosed.txt @@ -0,0 +1,2 @@ +$PATH/two_ifdef_unclosed.adoc:7 Only one ifdef command is allowed per file. +The previous ifdef command was not closed. diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/two_stuck_includes.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/two_stuck_includes.txt new file mode 100644 index 0000000000..10bf28381b --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/two_stuck_includes.txt @@ -0,0 +1,6 @@ +$PATH/two_stuck_includes.adoc:3 An empty line is missing after the include. +This may result in broken tags and other display issues. +Make sure there are always empty lines before and after each include +$PATH/two_stuck_includes.adoc:4 An empty line is missing before the include. +This may result in broken tags and other display issues. +Make sure there are always empty lines before and after each include diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unbalanced_double_backquotes.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unbalanced_double_backquotes.txt new file mode 100644 index 0000000000..5fd2dc18cd --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unbalanced_double_backquotes.txt @@ -0,0 +1 @@ +$PATH/unbalanced_double_backquotes.adoc:2 Unbalanced code inlining tags. diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unbalanced_single_backquotes.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unbalanced_single_backquotes.txt new file mode 100644 index 0000000000..bbed38e60d --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unbalanced_single_backquotes.txt @@ -0,0 +1,7 @@ +$PATH/unbalanced_single_backquotes.adoc:1 Unbalanced code inlining tags. +If you are trying to write inline code that is glued to text without a space, +you need to use double backquotes: +> Replace all `reference`s. +Will not display correctly. You need to write: +> Replace all ``reference``s. + diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unclosed_ifdef.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unclosed_ifdef.txt new file mode 100644 index 0000000000..8d1c344051 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unclosed_ifdef.txt @@ -0,0 +1 @@ +$PATH/unclosed_ifdef.adoc:6 An ifdef command is opened but never closed. diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unprotected_formatting.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unprotected_formatting.txt new file mode 100644 index 0000000000..7c2b1e748d --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unprotected_formatting.txt @@ -0,0 +1,32 @@ +$PATH/unprotected_formatting.adoc:1 +Using backquotes does not protect against asciidoc interpretation. Starting or +ending a word with '*', '#', '_' or having two of them consecutively will +trigger unintended behavior with the rest of the text. +Use ``++*careful++`` to avoid that. +If you really want to have formatting inside your code, you can write +``pass:n[*careful]`` + +$PATH/unprotected_formatting.adoc:3 +Using backquotes does not protect against asciidoc interpretation. Starting or +ending a word with '*', '#', '_' or having two of them consecutively will +trigger unintended behavior with the rest of the text. +Use ``++unpro**tected++`` to avoid that. +If you really want to have formatting inside your code, you can write +``pass:n[unpro**tected]`` + +$PATH/unprotected_formatting.adoc:5 +Using backquotes does not protect against asciidoc interpretation. Starting or +ending a word with '*', '#', '_' or having two of them consecutively will +trigger unintended behavior with the rest of the text. +Use ``++~flags~++`` to avoid that. +If you really want to have formatting inside your code, you can write +``pass:n[~flags~]`` + +$PATH/unprotected_formatting.adoc:7 +Using backquotes does not protect against asciidoc interpretation. Starting or +ending a word with '*', '#', '_' or having two of them consecutively will +trigger unintended behavior with the rest of the text. +Use ``++_problems_++`` to avoid that. +If you really want to have formatting inside your code, you can write +``pass:n[_problems_]`` + diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unprotected_formatting_with_plusses.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unprotected_formatting_with_plusses.txt new file mode 100644 index 0000000000..5a7cd8dd95 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/unprotected_formatting_with_plusses.txt @@ -0,0 +1,8 @@ +$PATH/unprotected_formatting_with_plusses.adoc:1 +Using backquotes does not protect against asciidoc interpretation. Starting or +ending a word with '*', '#', '_' or having two of them consecutively will +trigger unintended behavior with the rest of the text. +Use ``++This is not + ##protected## +++`` to avoid that. +If you really want to have formatting inside your code, you can write +``pass:n[This is not + ##protected## +]`` + diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/vscode_ifdef.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/vscode_ifdef.txt new file mode 100644 index 0000000000..562e819001 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/vscode_ifdef.txt @@ -0,0 +1,2 @@ +$PATH/vscode_ifdef.adoc:3 Configure VS Code to display rspecator-view by setting the asciidoctor attribute. +$PATH/vscode_ifdef.adoc:7 Incorrect endif command. "endif::env-github,rspecator-view[]" should be used instead. diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/wrong_constrained_passthrough.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/wrong_constrained_passthrough.txt new file mode 100644 index 0000000000..9e560820d5 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/wrong_constrained_passthrough.txt @@ -0,0 +1,7 @@ +$PATH/wrong_constrained_passthrough.adoc:1 Unbalanced code inlining tags. +If you are trying to write inline code that is glued to text without a space, +you need to use double backquotes: +> Replace all `reference`s. +Will not display correctly. You need to write: +> Replace all ``reference``s. + diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/wrong_endif.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/wrong_endif.txt new file mode 100644 index 0000000000..f0e18dc6d1 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/wrong_endif.txt @@ -0,0 +1 @@ +$PATH/wrong_endif.adoc:7 Incorrect endif command. "endif::env-github,rspecator-view[]" should be used instead. diff --git a/rspec-tools/tests/resources/invalid-asciidoc/snapshots/wrong_ifdef.txt b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/wrong_ifdef.txt new file mode 100644 index 0000000000..4a6f6f3397 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/snapshots/wrong_ifdef.txt @@ -0,0 +1 @@ +$PATH/wrong_ifdef.adoc:3 Incorrect asciidoc environment. "ifdef::env-github,rspecator-view[]" should be used instead. diff --git a/rspec-tools/tests/resources/invalid-asciidoc/triple_backquotes.adoc b/rspec-tools/tests/resources/invalid-asciidoc/triple_backquotes.adoc new file mode 100644 index 0000000000..ae87c5b5b8 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/triple_backquotes.adoc @@ -0,0 +1,3 @@ +We don't like people using three backquotes to display one in monospace ``` + +Instead they should write `++`++` diff --git a/rspec-tools/tests/resources/invalid-asciidoc/two_ifdef.adoc b/rspec-tools/tests/resources/invalid-asciidoc/two_ifdef.adoc new file mode 100644 index 0000000000..8ff971a5ae --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/two_ifdef.adoc @@ -0,0 +1,13 @@ +Some description + +ifdef::env-github,rspecator-view[] + +A first ifdef block + +endif::env-github,rspecator-view[] + +ifdef::env-github,rspecator-view[] + +This second ifdef should not be there + +endif::env-github,rspecator-view[] diff --git a/rspec-tools/tests/resources/invalid-asciidoc/two_ifdef_unclosed.adoc b/rspec-tools/tests/resources/invalid-asciidoc/two_ifdef_unclosed.adoc new file mode 100644 index 0000000000..8c39593f32 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/two_ifdef_unclosed.adoc @@ -0,0 +1,11 @@ +Some description + +ifdef::env-github,rspecator-view[] + +A first ifdef block + +ifdef::env-github,rspecator-view[] + +This second ifdef should not be there + +endif::env-github,rspecator-view[] diff --git a/rspec-tools/tests/resources/invalid-asciidoc/two_stuck_includes.adoc b/rspec-tools/tests/resources/invalid-asciidoc/two_stuck_includes.adoc new file mode 100644 index 0000000000..66c6b08aaa --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/two_stuck_includes.adoc @@ -0,0 +1,6 @@ +# Header + +include::somefile.adoc[] +include::someotherfile.adoc[] + +* Other content \ No newline at end of file diff --git a/rspec-tools/tests/resources/invalid-asciidoc/unbalanced_double_backquotes.adoc b/rspec-tools/tests/resources/invalid-asciidoc/unbalanced_double_backquotes.adoc new file mode 100644 index 0000000000..28b495f6b1 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/unbalanced_double_backquotes.adoc @@ -0,0 +1,4 @@ +This is a test for double +backquotes``next to text + +We shouldn't raise on this``double backquote usage``. \ No newline at end of file diff --git a/rspec-tools/tests/resources/invalid-asciidoc/unbalanced_single_backquotes.adoc b/rspec-tools/tests/resources/invalid-asciidoc/unbalanced_single_backquotes.adoc new file mode 100644 index 0000000000..6d9855e3b3 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/unbalanced_single_backquotes.adoc @@ -0,0 +1,3 @@ +Some text with `unbalanced`backquotes +Some other text where ` is used correctly. Shouldn't rais +`inlined code with single quotes` \ No newline at end of file diff --git a/rspec-tools/tests/resources/invalid-asciidoc/unclosed_ifdef.adoc b/rspec-tools/tests/resources/invalid-asciidoc/unclosed_ifdef.adoc new file mode 100644 index 0000000000..f3810e1c41 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/unclosed_ifdef.adoc @@ -0,0 +1,6 @@ +Some content followed by an ifdef + +ifdef::env-github,rspecator-view[] + +This ifdef should be valid +But then we don't close the block \ No newline at end of file diff --git a/rspec-tools/tests/resources/invalid-asciidoc/unprotected_formatting.adoc b/rspec-tools/tests/resources/invalid-asciidoc/unprotected_formatting.adoc new file mode 100644 index 0000000000..5ced99316b --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/unprotected_formatting.adoc @@ -0,0 +1,7 @@ +we should be `*careful` + +of `unpro**tected` + +formatting `~flags~` + +They can create `_problems_`. \ No newline at end of file diff --git a/rspec-tools/tests/resources/invalid-asciidoc/unprotected_formatting_with_plusses.adoc b/rspec-tools/tests/resources/invalid-asciidoc/unprotected_formatting_with_plusses.adoc new file mode 100644 index 0000000000..099427bd62 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/unprotected_formatting_with_plusses.adoc @@ -0,0 +1 @@ +Some content and `This is not + ##protected## +` \ No newline at end of file diff --git a/rspec-tools/tests/resources/invalid-asciidoc/vscode_ifdef.adoc b/rspec-tools/tests/resources/invalid-asciidoc/vscode_ifdef.adoc new file mode 100644 index 0000000000..7ab5c14e30 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/vscode_ifdef.adoc @@ -0,0 +1,7 @@ +Some content followed by an ifdef + +ifdef::env-github,rspecator-view,env-vscode[] + +This ifdef is wrong because we add vscode flags in it + +endif::env-github,rspecator-view,env-vscode[] diff --git a/rspec-tools/tests/resources/invalid-asciidoc/wrong_constrained_passthrough.adoc b/rspec-tools/tests/resources/invalid-asciidoc/wrong_constrained_passthrough.adoc new file mode 100644 index 0000000000..ec37134dc5 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/wrong_constrained_passthrough.adoc @@ -0,0 +1 @@ +Constrained pass-through are broken by backquotes: `+`+` \ No newline at end of file diff --git a/rspec-tools/tests/resources/invalid-asciidoc/wrong_endif.adoc b/rspec-tools/tests/resources/invalid-asciidoc/wrong_endif.adoc new file mode 100644 index 0000000000..61e3f62bd1 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/wrong_endif.adoc @@ -0,0 +1,7 @@ +Some content followed by an ifdef + +ifdef::env-github,rspecator-view[] + +This ifdef is wrong because we don't close it with the expected values + +endif::test,rspecator-view[] diff --git a/rspec-tools/tests/resources/invalid-asciidoc/wrong_ifdef.adoc b/rspec-tools/tests/resources/invalid-asciidoc/wrong_ifdef.adoc new file mode 100644 index 0000000000..d2092fa6f9 --- /dev/null +++ b/rspec-tools/tests/resources/invalid-asciidoc/wrong_ifdef.adoc @@ -0,0 +1,7 @@ +Some content followed by an ifdef + +ifdef::mytest,rspecator-view[] + +This ifdef is wrong because we don't open it with the expected values + +endif::env-github,rspecator-view[] diff --git a/rspec-tools/tests/validation/test_asciidoc_sanitization.py b/rspec-tools/tests/validation/test_asciidoc_sanitization.py new file mode 100644 index 0000000000..43512b2df7 --- /dev/null +++ b/rspec-tools/tests/validation/test_asciidoc_sanitization.py @@ -0,0 +1,43 @@ +import re +from pathlib import Path + +import pytest +from rspec_tools.validation.sanitize_asciidoc import sanitize_asciidoc + + +def relative_output(capsys, path: Path): + return capsys.readouterr().out.replace(str(path), '$PATH') + + +@pytest.mark.parametrize('invalid_file,expected_count', [('unbalanced_single_backquotes', 1), + ('unbalanced_double_backquotes', 1), + ('triple_backquotes', 1), + ('unprotected_formatting', 4), + ('unprotected_formatting_with_plusses', 1), + ('wrong_constrained_passthrough', 1), + ('unclosed_ifdef', 1), + ('close_unopened_ifdef', 1), + ('two_ifdef', 1), + ('two_ifdef_unclosed', 1), + ('vscode_ifdef', 2), + ('wrong_ifdef', 1), + ('wrong_endif', 1), + ('include_stuck_before', 1), + ('include_stuck_after', 1), + ('two_stuck_includes', 2) + ]) +def test_need_sanitation(mockinvalidasciidoc: Path, invalid_file, expected_count, capsys, snapshot): + '''Check that we detect needs for sanitation.''' + name_path = Path(invalid_file) + adoc = mockinvalidasciidoc / name_path.with_suffix('.adoc') + expected = mockinvalidasciidoc / 'snapshots' / name_path.with_suffix('.txt') + assert sanitize_asciidoc(adoc) == expected_count + snapshot.snapshot_dir = mockinvalidasciidoc / 'snapshots' + snapshot.assert_match(relative_output(capsys, mockinvalidasciidoc), expected) + + +def test_correctly_sanitized(mockasciidoc: Path): + '''Check that we raise no issue on correctly sanitized asciidoc''' + name_path = Path('valid') + adoc = mockasciidoc / name_path.with_suffix('.adoc') + assert sanitize_asciidoc(adoc) == 0 diff --git a/rules/S112/php/rule.adoc b/rules/S112/php/rule.adoc index 8fe310175c..c8f50a0c09 100644 --- a/rules/S112/php/rule.adoc +++ b/rules/S112/php/rule.adoc @@ -15,7 +15,7 @@ When throwing an exception, it is therefore recommended to throw the most specif To fix this issue, make sure to throw specific exceptions that are relevant to the context in which they arise. It is recommended to either: * Throw a subtype of `Exception` that already exists in the Standard PHP Library. For instance ``++InvalidArgumentException++`` could be raised when an unexpected argument is provided to a function. -* Define a custom exception type that derives from `++Exception++`` or one of its subclasses. +* Define a custom exception type that derives from ``++Exception++`` or one of its subclasses. === Code examples diff --git a/rules/S1128/csharp/rule.adoc b/rules/S1128/csharp/rule.adoc index 816fe9ca06..47539be55c 100644 --- a/rules/S1128/csharp/rule.adoc +++ b/rules/S1128/csharp/rule.adoc @@ -17,8 +17,8 @@ global using System.Net.Sockets; // Compliant by exception Unnecessary `using` directives are ignored in ASP.NET Core projects in the following files: -* `_Imports.razor` -* `_ViewImports.cshtml` +* ``++_Imports.razor++`` +* ``++_ViewImports.cshtml++`` == How to fix it diff --git a/rules/S1143/python/rule.adoc b/rules/S1143/python/rule.adoc index 1de08d1777..6e0f10bbc8 100644 --- a/rules/S1143/python/rule.adoc +++ b/rules/S1143/python/rule.adoc @@ -127,7 +127,7 @@ include::../message.adoc[] (visible only on this page) === on 3 Mar 2020, 17:27:45 Nicolas Harraudeau wrote: -Note: There is no need to create issues for \``++raise++`` statements because: +Note: There is no need to create issues for ``++raise++`` statements because: * there might be a good reason to raise an exception (Ex: cannot release resource) * python will link the new exception and the old exception automatically: diff --git a/rules/S1176/java/rule.adoc b/rules/S1176/java/rule.adoc index 67b6017fb4..94efd9ad79 100644 --- a/rules/S1176/java/rule.adoc +++ b/rules/S1176/java/rule.adoc @@ -37,13 +37,13 @@ For the parameters of the rule, the following rules are applied: * `?` matches a single character * `*` matches zero or more characters -* `**` matches zero or more packages +* ``++**++`` matches zero or more packages Examples: * `java.internal.InternalClass` will match only `InternalClass` class. -* `java.internal.*` will match any member of `java.internal` package. -* `java.internal.**` same as above, but including sub-packages. +* ``++java.internal.*++`` will match any member of `java.internal` package. +* ``++java.internal.**++`` same as above, but including sub-packages. === Code examples diff --git a/rules/S1192/javascript/rule.adoc b/rules/S1192/javascript/rule.adoc index d0991abdc7..7a83dea9cd 100644 --- a/rules/S1192/javascript/rule.adoc +++ b/rules/S1192/javascript/rule.adoc @@ -4,7 +4,7 @@ include::../description.adoc[] === Exceptions -To prevent generating some false-positives, literals having less than 10 characters are excluded as well as literals matching `/^\w*$/`. +To prevent generating some false-positives, literals having less than 10 characters are excluded as well as literals matching ``++/^\w*$/++``. String literals inside import/export statements and JSX attributes are also ignored. The same goes for statement-like string literals, e.g. `'use strict';`. diff --git a/rules/S1232/cfamily/rule.adoc b/rules/S1232/cfamily/rule.adoc index 6846c385b2..d5dd8f2671 100644 --- a/rules/S1232/cfamily/rule.adoc +++ b/rules/S1232/cfamily/rule.adoc @@ -11,7 +11,7 @@ Specifically, deallocation should correspond to allocation as per the table belo |Allocation | Deallocation |`p = new T();` | `delete p;` |`+p = new T[5];+` | `+delete[] p;+` -|`p = malloc(sizeof(int)*5);` | `free(p);` +|``++p = malloc(sizeof(int)*5);++`` | `free(p);` |============================================ === What is the potential impact? @@ -62,7 +62,7 @@ delete[] p; // Noncompliant: expect array cookie If you need allocate memory in a custom `T::operator new(std::size_t)`, -you should use `void* ::operator new(std::size_t)` and not `free()`. +you should use ``++void* ::operator new(std::size_t)++`` and not `free()`. Note that `::operator new` is still not compatible with `free()`: diff --git a/rules/S1301/javascript/rule.adoc b/rules/S1301/javascript/rule.adoc index 665120100b..8fb99fa4bf 100644 --- a/rules/S1301/javascript/rule.adoc +++ b/rules/S1301/javascript/rule.adoc @@ -2,9 +2,9 @@ A ``++switch++`` statement is a control flow statement that allows you to execute different blocks of code based on the value of an expression. It provides a more concise way to handle multiple conditions compared to using multiple ``++if-else++`` statements. -If you only have a single condition to check, using an ``++if++``` statement is simpler and more concise. ``++switch++`` statements are designed for handling multiple cases, so using them for a single condition can be overkill and less readable. +If you only have a single condition to check, using an ``++if++`` statement is simpler and more concise. ``++switch++`` statements are designed for handling multiple cases, so using them for a single condition can be overkill and less readable. -This rule raises an issue when a ``++switch++`` statement has only one ``++case++`` clause and possibly a ``++default`` one. +This rule raises an issue when a ``++switch++`` statement has only one ``++case++`` clause and possibly a ``++default++`` one. [source,javascript,diff-id=1,diff-type=noncompliant] ---- diff --git a/rules/S1596/java/rule.adoc b/rules/S1596/java/rule.adoc index 23312fed55..a2571f4cb1 100644 --- a/rules/S1596/java/rule.adoc +++ b/rules/S1596/java/rule.adoc @@ -1,4 +1,4 @@ -This rule raises an issue when the `Collections.EMPTY_*` fields are used instead of the `Collections.empty*()` methods. +This rule raises an issue when the ``++Collections.EMPTY_*++`` fields are used instead of the ``++Collections.empty*()++`` methods. == Why is this an issue? @@ -23,7 +23,7 @@ Use: - `Collections.emptySet()` instead of `Collections.EMPTY_SET` - `Collections.emptyMap()` instead of `Collections.EMPTY_MAP` -In addition, there are variants of `Collections.empty*()` available also for other collection interfaces, +In addition, there are variants of ``++Collections.empty*()++`` available also for other collection interfaces, such as `Collections.emptyIterator()`, `Collections.emptyNavigableMap()`, `Collections.emptySortedSet()`. === Code examples diff --git a/rules/S1603/php/rule.adoc b/rules/S1603/php/rule.adoc index 7b786cd77f..d45441b81f 100644 --- a/rules/S1603/php/rule.adoc +++ b/rules/S1603/php/rule.adoc @@ -3,8 +3,8 @@ Using a function in PHP with the same name as the nesting class was historically used to declare a class constructor. However, as of PHP 8.0.0, this declaration is discouraged and will provoke an `E_DEPRECATED` error, albeit it functions as a constructor. -Instead, users should explicitly define the constructor by declaring a `\__construct(...)` function. -However, if both styles are present in the same class, PHP will treat the `__construct` function as the class constructor, which can cause unintended behavior. +Instead, users should explicitly define the constructor by declaring a ``++__construct(...)++`` function. +However, if both styles are present in the same class, PHP will treat the ``++__construct++`` function as the class constructor, which can cause unintended behavior. Adhering to this convention improves readability and maintainability by ensuring that the constructor declaration is named uniformly throughout the codebase. diff --git a/rules/S1699/cfamily/rule.adoc b/rules/S1699/cfamily/rule.adoc index c87d4c67c7..bbd0f4b182 100644 --- a/rules/S1699/cfamily/rule.adoc +++ b/rules/S1699/cfamily/rule.adoc @@ -33,7 +33,7 @@ When constructing an object of type C, the following occurs: * The sub-object of type `A` is constructed. * The sub-object of type `B` is constructed. -** The constructor `B::B()` is called, during this call, `*this` is considered as being of type `B`. +** The constructor ``++B::B()++`` is called, during this call, ``++*this++`` is considered as being of type `B`. ** The function `B::f()` is called. ** The function `A::g()` is called. * The object of type `C` is constructed. diff --git a/rules/S1716/python/rule.adoc b/rules/S1716/python/rule.adoc index df099cdc07..e568282450 100644 --- a/rules/S1716/python/rule.adoc +++ b/rules/S1716/python/rule.adoc @@ -30,7 +30,7 @@ for word in words: Python will raise a `SyntaxError` when `break` or `continue` are used outside of `for` or `while` loops. -If the goal is to interrupt the main program flow, `quit()`, `exit()`, `os._exit()` and `sys.exit()` are the preferred way. +If the goal is to interrupt the main program flow, `quit()`, `exit()`, ``++os._exit()++`` and `sys.exit()` are the preferred way. === Code examples diff --git a/rules/S1764/cfamily/rule.adoc b/rules/S1764/cfamily/rule.adoc index 2bdc8c3290..dd993abfa8 100644 --- a/rules/S1764/cfamily/rule.adoc +++ b/rules/S1764/cfamily/rule.adoc @@ -7,7 +7,7 @@ Using the same value on both sides of a binary operator is a code defect. In the The following are ignored: * The expression `1 << 1` -* When an increment or decrement operator is used, ex: ``*p{plus}{plus} == *p{plus}{plus}`` +* When an increment or decrement operator is used, ex: ``+++*p++ == *p+++++`` * Bitwise operators `|, &, ^` * Arithmetic operators `+, *` * Assignment operators `=, +=, *=` diff --git a/rules/S1852/cfamily/rule.adoc b/rules/S1852/cfamily/rule.adoc index bcce7884dc..483027b950 100644 --- a/rules/S1852/cfamily/rule.adoc +++ b/rules/S1852/cfamily/rule.adoc @@ -4,9 +4,9 @@ * It is not part of the standard, which prevents its use in some contexts. * Even if it is supported by virtually all compilers, since its behavior is not defined, it may differ between compilers, especially for some corner cases when determining if two files are identical (for instance, in the presence of symbolic links). -* Its semantic is slightly different from the semantic of an include guard. For instance, if a file is duplicated in two different locations, `#pragma once` will not prevent multiple inclusion of this file. +* Its semantic is slightly different from the semantic of an include guard. For instance, if a file is duplicated in two different locations, ``++#pragma once++`` will not prevent multiple inclusion of this file. -Note: There used to be a build performance improvement when using `#pragma once` instead of an include guard because naive implementations of include guards need to parse the full file to get the `#endif` matching the `#if`. But most modern compilers specifically detect the include guard pattern and use a dedicated optimization that makes it about as fast as `#pragma once`. +Note: There used to be a build performance improvement when using ``++#pragma once++`` instead of an include guard because naive implementations of include guards need to parse the full file to get the ``++#endif++`` matching the ``++#if++``. But most modern compilers specifically detect the include guard pattern and use a dedicated optimization that makes it about as fast as ``++#pragma once++``. === Noncompliant code example diff --git a/rules/S1854/javascript/rule.adoc b/rules/S1854/javascript/rule.adoc index 5629012043..84ec3c123f 100644 --- a/rules/S1854/javascript/rule.adoc +++ b/rules/S1854/javascript/rule.adoc @@ -5,7 +5,7 @@ include::../why.adoc[] The rule ignores * Initializations to `-1`, `0`, `1`, `undefined`, `[]`, `{}`, `true`, `false` and `""`. - * Variables that start with an underscore (e.g. \'`_unused`') are ignored. + * Variables that start with an underscore (e.g. ``++_unused++``) are ignored. * Assignment of `null` is ignored because it is sometimes used to help garbage collection * Increment and decrement expressions are ignored because they are often used idiomatically instead of `x+1` * This rule also ignores variables declared with object destructuring using rest syntax (used to exclude some properties from object) diff --git a/rules/S1860/java/rule.adoc b/rules/S1860/java/rule.adoc index 73fcf02b15..b9cef865d2 100644 --- a/rules/S1860/java/rule.adoc +++ b/rules/S1860/java/rule.adoc @@ -39,7 +39,7 @@ Within the JDK, types which should not be used for synchronization include: * `String` literals * Primitive wrapper classes in `java.lang` (such as `Boolean` with `Boolean.FALSE` and `Boolean.TRUE`) * The class `java.lang.Runtime.Version` -* The `Optional*` classes in `java.util`: `Optional`, `OptionalInt`, `OptionalLong`, and `OptionalDouble` +* The ``++Optional*++`` classes in `java.util`: `Optional`, `OptionalInt`, `OptionalLong`, and `OptionalDouble` * Various classes in the `java.time` API: `Instant`, `LocalDate`, `LocalTime`, `LocalDateTime`, `ZonedDateTime`, `ZoneId`, `OffsetTime`, `OffsetDateTime`, `ZoneOffset`, `Duration`, `Period`, `Year`, `YearMonth`, and `MonthDay` * Various classes in the `java.time.chrono` API: `MinguoDate`, `HijrahDate`, `JapaneseDate`, and `ThaiBuddhistDate` * The interface `java.lang.ProcessHandle` and its implementation classes diff --git a/rules/S1862/javascript/rule.adoc b/rules/S1862/javascript/rule.adoc index 06058a121a..e5844aaf77 100644 --- a/rules/S1862/javascript/rule.adoc +++ b/rules/S1862/javascript/rule.adoc @@ -5,7 +5,7 @@ Both ``++if-else++`` chains and ``++switch++`` statements are used for condition * In an ``++if-else++`` chain, each condition is checked in order, and only the block associated with the first true condition is executed. If no condition is true, the code inside the ``++else++`` block (if present) will be executed. * In a ``++switch++`` statement, the expression is evaluated once, and its value is compared against each case. If a matching case is found, the corresponding block of code is executed. The ``++break++`` statement is used to exit the ``++switch++`` block after a match. If no case matches the expression, the code inside the ``++default++`` block (if present) will be executed. -Having the same condition in both ``++if-else++`` chains and `++switch++`` cases can lead to unreachable code and a potential source of bugs. It defeats the purpose of conditional branching and can make the code harder to read and maintain. +Having the same condition in both ``++if-else++`` chains and ``++switch++`` cases can lead to unreachable code and a potential source of bugs. It defeats the purpose of conditional branching and can make the code harder to read and maintain. [source,javascript,diff-id=1,diff-type=noncompliant] ---- diff --git a/rules/S1905/description.adoc b/rules/S1905/description.adoc index 16b06c0776..080338131a 100644 --- a/rules/S1905/description.adoc +++ b/rules/S1905/description.adoc @@ -1,4 +1,4 @@ -Casting expressions are utilized to convert one data type to another, such as transforming an integer into a string. This is especially crucial in strongly typed languages like `C`, `C++`, `C#`, `Java`, `Python`, and others. +Casting expressions are utilized to convert one data type to another, such as transforming an integer into a string. This is especially crucial in strongly typed languages like C, {cpp}, C#, Java, Python, and others. However, there are instances where casting expressions are not needed. These include situations like: diff --git a/rules/S2003/php/rule.adoc b/rules/S2003/php/rule.adoc index 6355f7b894..a5185ce0a7 100644 --- a/rules/S2003/php/rule.adoc +++ b/rules/S2003/php/rule.adoc @@ -8,11 +8,11 @@ However, the way they perform that task differs, and they should not be used int * ``++include++`` also includes a file, but generates only a warning if an error occurs. Predictably, the difference between ``++require++`` and ``++require_once++`` is the same as the difference between ``++include++`` and ``++include_once++``. -The `_once` versions ensure that the specified file is only included once. +The ``++_once++`` versions ensure that the specified file is only included once. === What is the potential impact? -Including the same file multiple times could have unpredictable results, the `_once` versions are preferred. +Including the same file multiple times could have unpredictable results, the ``++_once++`` versions are preferred. Additionally, as ``++include_once++`` generates only warnings, it should be used only when the file is being included conditionally, i.e. when all possible error conditions have been checked beforehand. == How to fix it diff --git a/rules/S2076/common/fix/sanitize-meta-characters.adoc b/rules/S2076/common/fix/sanitize-meta-characters.adoc index 0c304bc7fb..844961a1cc 100644 --- a/rules/S2076/common/fix/sanitize-meta-characters.adoc +++ b/rules/S2076/common/fix/sanitize-meta-characters.adoc @@ -12,10 +12,11 @@ The library helps you to get rid of common dangerous characters, such as: * `$` * `>` * `<` -* `\`` -* `\\` +* `++`++` +* `++\++` * `!` + If user input is to be included in the arguments of a command, the application must ensure that dangerous options or argument delimiters are neutralized. + Argument delimiters count `'`, `-` and spaces. diff --git a/rules/S2685/javascript/rule.adoc b/rules/S2685/javascript/rule.adoc index 937496f7ac..b04d3cdfdb 100644 --- a/rules/S2685/javascript/rule.adoc +++ b/rules/S2685/javascript/rule.adoc @@ -10,8 +10,7 @@ The ++arguments++ object has two deprecated properties called ``++arguments.call Both ``++arguments.caller++`` and ``++arguments.callee++`` are non-standard, deprecated, and leak stack information, which poses security risks and severely limits the possibility of optimizations. -Accessing ``arguments.callee``, ``Function.prototype.caller`` and ``Function.prototype.arguments -`` in strict mode will throw a ``TypeError``. +Accessing ``arguments.callee``, ``Function.prototype.caller`` and ``Function.prototype.arguments`` in strict mode will throw a ``TypeError``. [source,javascript] ---- diff --git a/rules/S2961/swift/rule.adoc b/rules/S2961/swift/rule.adoc index f2cdca3618..76eeee7727 100644 --- a/rules/S2961/swift/rule.adoc +++ b/rules/S2961/swift/rule.adoc @@ -58,9 +58,9 @@ ifdef::env-github,rspecator-view[] === Message -Remove backticks (`) from "xxx". +Remove backticks ``++`++`` from "xxx". -Remove backticks (`) from "xxx" and rename it. +Remove backticks ``++`++`` from "xxx" and rename it. ''' diff --git a/rules/S3168/csharp/rule.adoc b/rules/S3168/csharp/rule.adoc index c26b0c7816..c7d4478860 100644 --- a/rules/S3168/csharp/rule.adoc +++ b/rules/S3168/csharp/rule.adoc @@ -21,7 +21,7 @@ public async void button1_Click(object sender, EventArgs e) await DoSomethingAsync(); } ---- -* Methods name matching `On[A-Z]\w*` pattern. +* Methods name matching ``++On[A-Z]\w*++`` pattern. + Some frameworks may not use the same `EventHandler` method signature + diff --git a/rules/S3360/php/rule.adoc b/rules/S3360/php/rule.adoc index 4cd0b0a07c..85acd8fe84 100644 --- a/rules/S3360/php/rule.adoc +++ b/rules/S3360/php/rule.adoc @@ -1,10 +1,10 @@ == Why is this an issue? -For better organization and clarity in test suites, test classes should end with `*Test.php`. +For better organization and clarity in test suites, test classes should end with ``++*Test.php++``. This naming convention helps to easily identify and distinguish test classes from other classes in the codebase. It allows for automated test runners or frameworks to locate and execute the tests systematically. -The PHPUnit command-line test runner will look for `*Test.php` files. +The PHPUnit command-line test runner will look for ``++*Test.php++`` files. In that case, test files without this pattern are ignored and not executed without warning. === What is the potential impact? diff --git a/rules/S3415/php/rule.adoc b/rules/S3415/php/rule.adoc index 8b6dc9b844..dc00f8e818 100644 --- a/rules/S3415/php/rule.adoc +++ b/rules/S3415/php/rule.adoc @@ -1,6 +1,6 @@ == Why is this an issue? -The standard PHPUnit assertion methods such as `__assertEquals__`, expect the first argument to be the expected value and the second argument to be the actual value. +The standard PHPUnit assertion methods such as ``++__assertEquals__++``, expect the first argument to be the expected value and the second argument to be the actual value. include::../impact.adoc[] diff --git a/rules/S3477/rule.adoc b/rules/S3477/rule.adoc index 31ffa5c49e..ca01ff6137 100644 --- a/rules/S3477/rule.adoc +++ b/rules/S3477/rule.adoc @@ -1,6 +1,6 @@ == Why is this an issue? -If a ``++RuntimeException++`` is thrown while code is unit tested, it's likely to be thrown again in production. Therefore, test methods should be allowed to \``++throw RuntimeException++``s so you're alerted early to problems in the code. +If a ``++RuntimeException++`` is thrown while code is unit tested, it's likely to be thrown again in production. Therefore, test methods should be allowed to ``++throw RuntimeException++``s so you're alerted early to problems in the code. === Noncompliant code example diff --git a/rules/S3584/cfamily/rule.adoc b/rules/S3584/cfamily/rule.adoc index 3295320928..8eadf8b8a6 100644 --- a/rules/S3584/cfamily/rule.adoc +++ b/rules/S3584/cfamily/rule.adoc @@ -53,7 +53,7 @@ and discourage the further use of the application. === Exceptions -If a function `+return+`s a pointer to the caller or stores it in an external structure, +If a function ``return``s a pointer to the caller or stores it in an external structure, this pointer is said to _escape_ (it is now accessible outside of function, and no longer local to it). This includes storing the pointer in a static or global variable, passing it to a function that can potentially do that, diff --git a/rules/S3590/cfamily/rule.adoc b/rules/S3590/cfamily/rule.adoc index 8abfa10d8c..693d46a0d4 100644 --- a/rules/S3590/cfamily/rule.adoc +++ b/rules/S3590/cfamily/rule.adoc @@ -7,7 +7,7 @@ Attempting to release any other type of memory is _undefined behavior_. The following non-heap memory types may not be released: -* Stack allocated memory - local variables or memory allocated with the `alloca`, `_alloca`, `_malloca` and `__builtin_alloca` functions. +* Stack allocated memory - local variables or memory allocated with the `alloca`, ``++_alloca++``, ``++_malloca++`` and ``++__builtin_alloca++`` functions. * Executable program code - function pointers. * Program data - global and static variables. * Read-only program data - constants and strings. diff --git a/rules/S3715/cfamily/rule.adoc b/rules/S3715/cfamily/rule.adoc index 6251c92066..1211b47fbc 100644 --- a/rules/S3715/cfamily/rule.adoc +++ b/rules/S3715/cfamily/rule.adoc @@ -9,7 +9,7 @@ Proprietary compiler extensions can be handy, but they commit you to always usin * Index range in array initializers * A array initializer without ``++=++`` * A structure member initializer with a colon -* Decimal floating points numbers `_Decimal32`, `_Decimal64`, and `_Decimal128` +* Decimal floating points numbers ``++_Decimal32++``, ``++_Decimal64++``, and ``++_Decimal128++`` * Structures and union without named data members === Noncompliant code example diff --git a/rules/S3786/javascript/rule.adoc b/rules/S3786/javascript/rule.adoc index 38505b1712..60c7563187 100644 --- a/rules/S3786/javascript/rule.adoc +++ b/rules/S3786/javascript/rule.adoc @@ -28,7 +28,7 @@ ifdef::env-github,rspecator-view[] === Message -Replace the quotes (["|']) with back-ticks (`). +Replace the quotes ``++["|']++`` with back-ticks ``++`++``. ''' diff --git a/rules/S3806/cfamily/rule.adoc b/rules/S3806/cfamily/rule.adoc index 97a7fb1158..d1ad3d31bc 100644 --- a/rules/S3806/cfamily/rule.adoc +++ b/rules/S3806/cfamily/rule.adoc @@ -1,13 +1,13 @@ == Why is this an issue? -The way an `#include` directive finds an actual file is implementation-defined, and in practice, it slightly differs in different systems. +The way an ``++#include++`` directive finds an actual file is implementation-defined, and in practice, it slightly differs in different systems. Therefore, a good practice is to identify the files to include in the most straightforward way possible to reduce the risk of inconsistent behaviors. This rule raises an issue when: -* The case of the file in the `#include` directive does not match the case of the file on the disk (the inclusion would not work on a case-sensitive OS), -* The file name in the `#include` directive contains trailing spaces (they would be ignored on Windows but considered on Unix). +* The case of the file in the ``++#include++`` directive does not match the case of the file on the disk (the inclusion would not work on a case-sensitive OS), +* The file name in the ``++#include++`` directive contains trailing spaces (they would be ignored on Windows but considered on Unix). === Noncompliant code example diff --git a/rules/S3812/javascript/rule.adoc b/rules/S3812/javascript/rule.adoc index 6429422626..11a3e455bc 100644 --- a/rules/S3812/javascript/rule.adoc +++ b/rules/S3812/javascript/rule.adoc @@ -2,7 +2,7 @@ Operator precedence determines the order in which different operators are evaluated when an expression contains multiple ones. It helps determine how the expression is parsed and executed. JavaScript follows a specific set of rules to determine operator precedence. -Not being aware of JavaScript's operator precedence rules can lead to unexpected and potentially incorrect results when evaluating expressions. This is common when misapplying the logical negation operator (``++!++``). For instance, consider the difference between ``++!key in dict++`` and ``++!(key in dict)++``. The first looks for a boolean value (``++!key++``) in ``++dict++``, and the other looks for a string and inverts the result. The same applies for ``++!obj instanceof SomeClass++` +Not being aware of JavaScript's operator precedence rules can lead to unexpected and potentially incorrect results when evaluating expressions. This is common when misapplying the logical negation operator (``++!++``). For instance, consider the difference between ``++!key in dict++`` and ``++!(key in dict)++``. The first looks for a boolean value (``++!key++``) in ``++dict++``, and the other looks for a string and inverts the result. The same applies for ``++!obj instanceof SomeClass++``. This rule raises an issue when the left operand of an ``++in++`` or ``++instanceof++`` operator is negated with ``++!++``. diff --git a/rules/S4000/csharp/rule.adoc b/rules/S4000/csharp/rule.adoc index 522579ddd3..8f8453fc7c 100644 --- a/rules/S4000/csharp/rule.adoc +++ b/rules/S4000/csharp/rule.adoc @@ -1,6 +1,6 @@ == Why is this an issue? -Pointer and unmanaged function pointer types such as `IntPtr`, `UIntPtr`, `int*` etc. are used to access unmanaged memory, usually in order to use C or {cpp} libraries. If such a pointer is not secured by making it `private`, `internal` or `readonly`, it can lead to a vulnerability allowing access to arbitrary locations. +Pointer and unmanaged function pointer types such as `IntPtr`, `UIntPtr`, ``++int*++`` etc. are used to access unmanaged memory, usually in order to use C or {cpp} libraries. If such a pointer is not secured by making it `private`, `internal` or `readonly`, it can lead to a vulnerability allowing access to arbitrary locations. === Noncompliant code example diff --git a/rules/S4275/javascript/rule.adoc b/rules/S4275/javascript/rule.adoc index c137b50fc1..b67af18138 100644 --- a/rules/S4275/javascript/rule.adoc +++ b/rules/S4275/javascript/rule.adoc @@ -8,7 +8,7 @@ This rule raises an issue in the following cases: ** does not return any value ** does not access the field with the corresponding name (if it exists). -Underscore prefixes for fields are supported, so `setX()` can assign a value to `_x`. +Underscore prefixes for fields are supported, so `setX()` can assign a value to ``++_x++``. The following type of getters and setters are supported: diff --git a/rules/S4507/xml/rule.adoc b/rules/S4507/xml/rule.adoc index 1a9017a7f5..e39c3c5f88 100644 --- a/rules/S4507/xml/rule.adoc +++ b/rules/S4507/xml/rule.adoc @@ -10,7 +10,7 @@ In all cases, the attack surface of an affected application is increased. In som == Ask Yourself Whether * The development of the app is completed and the development feature is activated. -* The app is distributed to end users with the `development feature activated +* The app is distributed to end users with the development feature activated There is a risk if you answered yes to any of those questions. diff --git a/rules/S4830/python/how-to-fix-it/std.adoc b/rules/S4830/python/how-to-fix-it/std.adoc index 8d8fa9c56d..117fa9e817 100644 --- a/rules/S4830/python/how-to-fix-it/std.adoc +++ b/rules/S4830/python/how-to-fix-it/std.adoc @@ -4,8 +4,8 @@ include::../../common/fix/code-rationale.adoc[] -Certificate validation is not enabled by default when `_create_unverified_context` -is used. It is recommended to use `_create_default_https_context` instead to +Certificate validation is not enabled by default when ``++_create_unverified_context++`` +is used. It is recommended to use ``++_create_default_https_context++`` instead to create a secure context that validates certificates. ==== Noncompliant code example diff --git a/rules/S5283/cfamily/rule.adoc b/rules/S5283/cfamily/rule.adoc index d9acc82706..0c527edd16 100644 --- a/rules/S5283/cfamily/rule.adoc +++ b/rules/S5283/cfamily/rule.adoc @@ -194,7 +194,7 @@ When applicable, it is recommended to replace the VLA with heap-allocated memory In contrast to VLA, heap allocation functions report in a situation when sufficient memory cannot be provided, by returning `NULL` or throwing an exception (in {cpp}). Furthermore, the {cpp} standard library provides containers like `std::vector`, that manage the heap-allocated memory. -Moreover, the C11 language standard and above only optionally supports VLAs (with `__STDC_NO_VLA__`), +Moreover, the C11 language standard and above only optionally supports VLAs (with ``++__STDC_NO_VLA__++``), and the {cpp} standard never supported it, however, they are commonly accepted as extensions. diff --git a/rules/S5484/apex/rule.adoc b/rules/S5484/apex/rule.adoc index 630982c452..ec220da313 100644 --- a/rules/S5484/apex/rule.adoc +++ b/rules/S5484/apex/rule.adoc @@ -3,7 +3,7 @@ https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm[There is a limit] to the number of batch jobs which can be executed at the same time. Executing batch jobs in triggers or in loops is complex as it can easily reach this limit (example: after a bulk update), thus it is recommended to avoid it. Note that checking if the limit is already reached is not enough as nothing prevents the addition of a job between the check and the subsequent call to ``++executeBatch++``. -This rule raises an issue when \``++Databasee.executeBatch()++`` is called in a Trigger or in a loop. +This rule raises an issue when ``++Databasee.executeBatch()++`` is called in a Trigger or in a loop. === Noncompliant code example diff --git a/rules/S5498/apex/rule.adoc b/rules/S5498/apex/rule.adoc index c36d903caa..f509358bae 100644 --- a/rules/S5498/apex/rule.adoc +++ b/rules/S5498/apex/rule.adoc @@ -1,6 +1,6 @@ == Why is this an issue? -Salesforce Governor Limits do not allow more than 10 calls to \``++Messaging.sendEmail++`` in a single transaction. There is a good chance that calling this method in a loop will reach that limit and fail. You can instead send a batch of emails with a single call to \``++Messaging.sendEmail++``. +Salesforce Governor Limits do not allow more than 10 calls to ``++Messaging.sendEmail++`` in a single transaction. There is a good chance that calling this method in a loop will reach that limit and fail. You can instead send a batch of emails with a single call to ``++Messaging.sendEmail++``. This rule raises an issue when a call to ``++Messaging.sendEmail++`` is found in a loop. diff --git a/rules/S5527/python/how-to-fix-it/std.adoc b/rules/S5527/python/how-to-fix-it/std.adoc index 076891c091..2f96de3bca 100644 --- a/rules/S5527/python/how-to-fix-it/std.adoc +++ b/rules/S5527/python/how-to-fix-it/std.adoc @@ -5,7 +5,7 @@ include::../../common/fix/code-rationale.adoc[] Certificate validation is not enabled by default when -`_create_unverified_context` or `_create_stdlib_context` is used. It is +``++_create_unverified_context++`` or ``++_create_stdlib_context++`` is used. It is recommended to use `create_default_context`, without explicitly setting `check_hostname` to `False`. + Doing so creates a secure context that validates both hostnames and diff --git a/rules/S5650/python/rule.adoc b/rules/S5650/python/rule.adoc index 27e7f55337..6fcb72a742 100644 --- a/rules/S5650/python/rule.adoc +++ b/rules/S5650/python/rule.adoc @@ -21,11 +21,12 @@ with MyContextManager(): ---- will output: -``` +[source,text] +---- Entering Executing body Exiting -``` +---- If either the ``++__enter__++`` or the ``++__exit__++`` method is missing, an ``AttributeError`` will be raised instead. diff --git a/rules/S5813/cfamily/rule.adoc b/rules/S5813/cfamily/rule.adoc index daad8386fd..df7804d25e 100644 --- a/rules/S5813/cfamily/rule.adoc +++ b/rules/S5813/cfamily/rule.adoc @@ -1,5 +1,5 @@ -The function `size_t strlen(const char *s)` measures the length of the string `s` (excluding the final null character). + -The function `size_t wcslen(const wchar_t *s)` does the same for wide characters, and should be used with the same guidelines. +The function ``++size_t strlen(const char *s)++`` measures the length of the string `s` (excluding the final null character). + +The function ``++size_t wcslen(const wchar_t *s)++`` does the same for wide characters, and should be used with the same guidelines. Similarly to many other functions in the standard C libraries, `strlen` and `wcslen` assume that their argument is not a null pointer. diff --git a/rules/S5950/cfamily/rule.adoc b/rules/S5950/cfamily/rule.adoc index 32dd4ce42a..a8e0f7b724 100644 --- a/rules/S5950/cfamily/rule.adoc +++ b/rules/S5950/cfamily/rule.adoc @@ -29,7 +29,7 @@ Note: This scenario can only happen before {cpp}17. Since {cpp}17, the standard Using `make_unique()` doesn't impact performance, but `make_shared()` improves it slightly. + Indeed, constructing explicitly a `shared_ptr()` requires two heap allocations: one for the managed object and the other for the control block that stores data about the ref-counts and the `shared_ptr()` deleter. `make_shared()` on the other hand, performs only one heap allocation. -Note: Because `make_shared` performs only one allocation for both the object and the control block, the memory occupied by the object will be deallocated when no `shared_ptr` or `weak_ptr` points to it. If the object is large, a `weak_ptr` is used, and memory is a concern, explicitly calling the constructor of `shared_ptr` may be preferred. This way, the object's memory will be deallocated when there are no more shared owners, independently of any `weak_ptr`s. +Note: Because `make_shared` performs only one allocation for both the object and the control block, the memory occupied by the object will be deallocated when no `shared_ptr` or `weak_ptr` points to it. If the object is large, a `weak_ptr` is used, and memory is a concern, explicitly calling the constructor of `shared_ptr` may be preferred. This way, the object's memory will be deallocated when there are no more shared owners, independently of any ``weak_ptr``s. === Noncompliant code example diff --git a/rules/S6021/cfamily/rule.adoc b/rules/S6021/cfamily/rule.adoc index 3409666f63..988cc40ebb 100644 --- a/rules/S6021/cfamily/rule.adoc +++ b/rules/S6021/cfamily/rule.adoc @@ -47,7 +47,7 @@ void g() { } ---- In this case ``++str++`` will not be converted to a ``++std::string++`` when calling the function ``++find++``, and each element of the bucket that corresponds to the hash of ``++str++`` will be compared using homogeneous ``++operator==++``, -and for each such comparison, a conversion will now happen. The number of compared elements varies depending on the hash distribution from ``++O(1)++` (on average) to ``++O(N)++`` (in the worst case). +and for each such comparison, a conversion will now happen. The number of compared elements varies depending on the hash distribution from ``++O(1)++`` (on average) to ``++O(N)++`` (in the worst case). As consequence, the performance of slow runs (when multiple hash collisions happen due to the data distribution) is made even worse. diff --git a/rules/S6214/cfamily/rule.adoc b/rules/S6214/cfamily/rule.adoc index 51e10b7434..dfa3c655d8 100644 --- a/rules/S6214/cfamily/rule.adoc +++ b/rules/S6214/cfamily/rule.adoc @@ -1,4 +1,4 @@ -Compare integers of mixed signedness safely using `std::cmp_*` functions to avoid any unexpected results. +Compare integers of mixed signedness safely using ``++std::cmp_*++`` functions to avoid any unexpected results. == Why is this an issue? @@ -18,7 +18,7 @@ For example, using container size functions in a comparison can lead to such a p == How to fix it -{cpp}20 introduced a remedy to this common pitfall: a family of `std::cmp_*` functions defined in the `` header. +{cpp}20 introduced a remedy to this common pitfall: a family of ``++std::cmp_*++`` functions defined in the `` header. These functions correctly handle negative numbers and lossy integer conversion. For example, `std::cmp_less(2U, -1)` is `false`. diff --git a/rules/S6225/cfamily/rule.adoc b/rules/S6225/cfamily/rule.adoc index 85ff4b5f85..4cce9e523b 100644 --- a/rules/S6225/cfamily/rule.adoc +++ b/rules/S6225/cfamily/rule.adoc @@ -6,7 +6,7 @@ In {cpp}20 ``++std::to_address++`` was introduced to perform this operation on b * The first option was to take the address of the element pointed by the iterator: ``++&*it++``. However, this operation has undefined behavior if the iterator is not pointing to any element. This may happen for the iterator returned by a call to ``++end()++`` on the container. This may also be the case when we need the address to construct a new object (via placement new) at the location pointed to by the iterator. ``++std::to_address(it)++`` works in such cases. * The second option was to exploit the nature of ``++operator->++`` overloading and call it explicitly on the iterator: ``++it.operator->()++``. This option avoids the pitfalls of the previous one, at the cost of not being portable. It would fail on the implementations that use raw-pointers as iterators for contiguous ranges like ``++std::vector++`` or ``++std::span++``. Moreover, it is confusing, as this functional notation syntax for operators is rarely used. -While both ``++std::to_address++` and above workarounds, can be always used to get the address of the element that the iterator is pointing to (if any), incrementing or decrementing may have undefined behavior. +While both ``++std::to_address++`` and above workarounds, can be always used to get the address of the element that the iterator is pointing to (if any), incrementing or decrementing may have undefined behavior. Performing pointer arithmetic on pointer to elements is safe only in the case of contiguous iterators (e.g. iterators of `std::vector`, `std::array`, `std::span`, `std::string` or `std::string_view`). This rule raises an issue when dereferencing a pointer-like object is immediately followed by taking the address of the result (``++&*x++`` or ``++std::addressof(*x)++``) or when ``++operator->++`` is called through an explicit functional notation (``++x.operator->()++``). diff --git a/rules/S6335/secrets/rule.adoc b/rules/S6335/secrets/rule.adoc index 12f6f20946..633033b15d 100644 --- a/rules/S6335/secrets/rule.adoc +++ b/rules/S6335/secrets/rule.adoc @@ -51,7 +51,7 @@ https://cloud.google.com/iam/docs/keys-create-delete#creating[GCP docs]. ==== Compliant solution Always avoid committing service account key files to public systems. Use any -`*ignore` file possible, such as `.gitignore`, `.dockerignore` and equivalents +``++*ignore++`` file possible, such as `.gitignore`, `.dockerignore` and equivalents for any other system accessing your local codebase. //=== How does this work? diff --git a/rules/S6353/description.adoc b/rules/S6353/description.adoc index f6b4a009ec..7af8d814a7 100644 --- a/rules/S6353/description.adoc +++ b/rules/S6353/description.adoc @@ -12,6 +12,6 @@ For example, to match a two-digit number, one could write `+[0-9]{2,2}+` or `+\d This rule recommends replacing some quantifiers and character classes with more concise equivalents: * `+\d+` for `+[0-9]+` and `+\D+` for `[^0-9]` -* `+\w+` for `+[A-Za-z0-9_]+` and `+\W+` for `[^A-Za-z0-9_]` +* `+\w+` for `+[A-Za-z0-9_]+` and `+\W+` for ``++[^A-Za-z0-9_]++`` * `+.+` for character classes matching everything (e.g. `+[\w\W]+`, `+[\d\D]+`, or `+[\s\S]+` with `+s+` flag) * `+x?+` for `+x{0,1}+`, `+x*+` for `+x{0,}+`, `+x++` for `+x{1,}+`, `+x{N}+` for `+x{N,N}+` \ No newline at end of file diff --git a/rules/S6379/azureresourcemanager/rule.adoc b/rules/S6379/azureresourcemanager/rule.adoc index 9499a768fb..9f05394d3d 100644 --- a/rules/S6379/azureresourcemanager/rule.adoc +++ b/rules/S6379/azureresourcemanager/rule.adoc @@ -162,6 +162,6 @@ include::../message.adoc[] === Highlighting * For ``Microsoft.Batch/batchAccounts/pools``, highlight ``"elevationLevel": "Admin"``. -* For ``Microsoft.ContainerRegistry/registries``, highlight `"adminUserEnabled": true``. +* For ``Microsoft.ContainerRegistry/registries``, highlight ``"adminUserEnabled": true``. endif::env-github,rspecator-view[] diff --git a/rules/S6427/cfamily/rule.adoc b/rules/S6427/cfamily/rule.adoc index d9c0028096..c4be0a3604 100644 --- a/rules/S6427/cfamily/rule.adoc +++ b/rules/S6427/cfamily/rule.adoc @@ -2,7 +2,7 @@ The class `std::optional` either stores a value of type `T` or is empty. -One way to access the value of a non-empty optional is the `operator*`. But using the dereference operator gives the optional appearance of a pointer when it is not: it models an object. Additionally, attempting to call the `operator*` on an empty optional will result in undefined behavior. +One way to access the value of a non-empty optional is the ``++operator*++``. But using the dereference operator gives the optional appearance of a pointer when it is not: it models an object. Additionally, attempting to call the ``++operator*++`` on an empty optional will result in undefined behavior. Another way to access the value of a non-empty optional is the function `value()`. But assigning a value to the optional object through this function will throw an exception (`std::bad_optional_access`) if the optional has no value, and the assignment will not happen. @@ -13,7 +13,7 @@ For the assignment of an optional to happen correctly, whatever its state, it is == How to fix it -The rule raises an issue when the `operator*` or the `value()` function are used to assign a new value to an optional. +The rule raises an issue when the ``++operator*++`` or the `value()` function are used to assign a new value to an optional. === Code examples diff --git a/rules/S6431/kubernetes/rule.adoc b/rules/S6431/kubernetes/rule.adoc index c91ea1678f..ebdb840961 100644 --- a/rules/S6431/kubernetes/rule.adoc +++ b/rules/S6431/kubernetes/rule.adoc @@ -88,7 +88,7 @@ Make sure it is safe to use host operating system namespaces here. === Highlighting -Highlight `host___: true`. +Highlight ``++host___: true++``. endif::env-github,rspecator-view[] diff --git a/rules/S6468/python/rule.adoc b/rules/S6468/python/rule.adoc index 05fbcec606..a9fc4c9ef5 100644 --- a/rules/S6468/python/rule.adoc +++ b/rules/S6468/python/rule.adoc @@ -1,8 +1,8 @@ -Catching `ExceptionGroup` with `except*` will raise a `TypeError`. +Catching `ExceptionGroup` with ``++except*++`` will raise a `TypeError`. == Why is this an issue? -Python 3.11 introduced `except*` and `ExceptionGroup`, making it possible to handle and raise multiple unrelated exceptions simultaneously. +Python 3.11 introduced ``++except*++`` and `ExceptionGroup`, making it possible to handle and raise multiple unrelated exceptions simultaneously. In the example below, we gather multiple exceptions in an `ExceptionGroup`. This `ExceptionGroup` is then caught by a single except block: @@ -18,7 +18,7 @@ except ExceptionGroup as exceptions: pass ---- -To handle differently each type of exceptions present in an `ExceptionGroup`, we have to use the `except*` keyword. +To handle differently each type of exceptions present in an `ExceptionGroup`, we have to use the ``++except*++`` keyword. [source,python] ---- @@ -36,7 +36,7 @@ except* TypeError as t: pass ---- -While it is possible to catch the `ExceptionGroup` and `BaseExceptionGroup` types with `except`, a `TypeError` will be raised when this is done with `except*`. +While it is possible to catch the `ExceptionGroup` and `BaseExceptionGroup` types with `except`, a `TypeError` will be raised when this is done with ``++except*++``. == How to fix it diff --git a/rules/S6534/javascript/rule.adoc b/rules/S6534/javascript/rule.adoc index afc5dd857b..9eca828c42 100644 --- a/rules/S6534/javascript/rule.adoc +++ b/rules/S6534/javascript/rule.adoc @@ -11,7 +11,7 @@ The values are stored using 64 bits in the following form: // When images can be added, add image based on to this one //image::IEEE_754_Double_Floating_Point_Format.svg.png[] -The actual value of the stored number will be `(-1)^sign^ * (1 + significand) * 2 ^exponent^` +The actual value of the stored number will be `pass:n[(-1)^sign^ * (1 + significand) * 2 ^exponent^]` Given this structure, there are limits in both *magnitude* and *precision*. @@ -40,7 +40,7 @@ myBigInt + 1n === myBigInt + 2n; // false For large numbers, JavaScript provides the helper function `Number.isSafeInteger()` to test if a number is between the safe limits. -When you need to store a large number, use `BigInt`. `bigint` and `number` primitives can be compared between them as usual (e.g. `>`, `==`), but pay attention that arithmetic operations (`+` `pass:[*]` `-` `%` `pass:[**]`) between both types raise an error unless they are converted to the same type. Use the `BigInt` and `Number` functions to convert between both types: +When you need to store a large number, use `BigInt`. `bigint` and `number` primitives can be compared between them as usual (e.g. `>`, `==`), but pay attention that arithmetic operations (`+` `pass:[*]` `-` `%` `++**++`) between both types raise an error unless they are converted to the same type. Use the `BigInt` and `Number` functions to convert between both types: [source,javascript] ---- const myNumber = Number(myBigInt); diff --git a/rules/S6547/impact.adoc b/rules/S6547/impact.adoc index 59c0c2f96d..223b4163ab 100644 --- a/rules/S6547/impact.adoc +++ b/rules/S6547/impact.adoc @@ -21,7 +21,7 @@ For example, injecting data into the `HTTP_PROXY` variable could lead to data le ==== Application compromise In the worst case, an attacker manages to inject an important environment -variable such as ` LD _PRELOAD` and execute code by overriding trusted code. +variable such as `LD_PRELOAD` and execute code by overriding trusted code. Depending on the attacker, code execution can be used with different intentions: diff --git a/rules/S6554/python/rule.adoc b/rules/S6554/python/rule.adoc index 95e7a7f1bc..9606fddd6a 100644 --- a/rules/S6554/python/rule.adoc +++ b/rules/S6554/python/rule.adoc @@ -1,12 +1,12 @@ -This rule ensures that Django models have a `__str__` method defined. +This rule ensures that Django models have a ``++__str__++`` method defined. == Why is this an issue? -The `__str__` method in Django models is used to represent the model instance as a string. For example, the return value of this method will be inserted in a template when displaying an object in the Django admin site. Without this method, the model instance will be represented by its object identifier, which is not meaningful to end-users. This can result in confusion and make debugging more difficult. +The ``++__str__++`` method in Django models is used to represent the model instance as a string. For example, the return value of this method will be inserted in a template when displaying an object in the Django admin site. Without this method, the model instance will be represented by its object identifier, which is not meaningful to end-users. This can result in confusion and make debugging more difficult. == How to fix it -To fix this issue, the Django model must define a `__str__` method that returns a string representation of the instance. This string should be meaningful to end-users and provide information about the model instance. +To fix this issue, the Django model must define a ``++__str__++`` method that returns a string representation of the instance. This string should be meaningful to end-users and provide information about the model instance. === Code examples diff --git a/rules/S6559/python/rule.adoc b/rules/S6559/python/rule.adoc index 59bb5496dc..37a42adfab 100644 --- a/rules/S6559/python/rule.adoc +++ b/rules/S6559/python/rule.adoc @@ -1,8 +1,8 @@ -This rule discourages the use of `exclude` or `__all__` with ModelForm in Django and suggests using fields instead. +This rule discourages the use of `exclude` or ``++__all__++`` with ModelForm in Django and suggests using fields instead. == Why is this an issue? -In Django, when creating a `ModelForm`, it is common to use `exclude` to remove fields from the form. It is also possible to set the `fields` value to `__all__` to conveniently indicate that all the model fields should be included in the form. However, this can lead to security issues when new fields are added to the model, as they will automatically be included in the form, which may not be intended. Additionally, `exclude` or `__all__` can make it harder to maintain the codebase by hiding the dependencies between the model and the form. +In Django, when creating a `ModelForm`, it is common to use `exclude` to remove fields from the form. It is also possible to set the `fields` value to ``++__all__++`` to conveniently indicate that all the model fields should be included in the form. However, this can lead to security issues when new fields are added to the model, as they will automatically be included in the form, which may not be intended. Additionally, `exclude` or ``++__all__++`` can make it harder to maintain the codebase by hiding the dependencies between the model and the form. == How to fix it Developers should use the "fields" attribute instead of "exclude" or "all" when creating ModelForms in Django. This ensures that all fields are explicitly listed and makes it clear what fields are included in the form. diff --git a/rules/S6570/docker/rule.adoc b/rules/S6570/docker/rule.adoc index c886609c0e..b97e945c7a 100644 --- a/rules/S6570/docker/rule.adoc +++ b/rules/S6570/docker/rule.adoc @@ -35,7 +35,7 @@ This code will print `"Hello World"`, omitting the leading and trailing whitespa ==== Compliant solution -This example demonstrates pathname expansion using the `echo` command, which will print `"command t*.sh"` as intended: +This example demonstrates pathname expansion using the `echo` command, which will print ``++"command t*.sh"++`` as intended: [source,docker,diff-id=1,diff-type=compliant] ---- RUN test="command t*.sh" && echo "$test" diff --git a/rules/S6610/resources-dotnet.adoc b/rules/S6610/resources-dotnet.adoc index 4900273acf..5c41feafa9 100644 --- a/rules/S6610/resources-dotnet.adoc +++ b/rules/S6610/resources-dotnet.adoc @@ -57,10 +57,11 @@ public void EndsWith_Char() Hardware configuration: -``` +[source,text] +---- BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19045.2846/22H2/2022Update) 11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 physical cores .NET SDK=7.0.203 [Host] : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2 .NET 7.0 : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2 -``` +---- diff --git a/rules/S6654/javascript/rule.adoc b/rules/S6654/javascript/rule.adoc index 28756cb326..1731cb5cdb 100644 --- a/rules/S6654/javascript/rule.adoc +++ b/rules/S6654/javascript/rule.adoc @@ -2,7 +2,7 @@ JavaScript has a prototypical inheritance model. Each object has an internal property that points to another object, called a `prototype`. That prototype object has a prototype of its own, and the whole sequence is called a *prototype chain*. When accessing a property or a method of an object, if it is not found at the top level, the search continues through the object's prototype and then further down the prototype chain. This feature allows for very powerful dynamic inheritance patterns but can also lead to confusion when compared to the classic inheritance. -To simplify the access to the prototype of an object some browsers introduced the `\\__proto__` property, which was later deprecated and removed from the language. The current ECMAScript standard includes `Object.getPrototype` and `Object.setPrototype` static methods that should be used instead of the `\\__proto__` property. +To simplify the access to the prototype of an object some browsers introduced the ``++__proto__++`` property, which was later deprecated and removed from the language. The current ECMAScript standard includes `Object.getPrototype` and `Object.setPrototype` static methods that should be used instead of the ``++__proto__++`` property. [source,javascript,diff-id=1,diff-type=noncompliant] ---- @@ -10,7 +10,7 @@ let prototype = foo.__proto__; // Noncompliant: use Object.getPrototype foo.__proto__ = bar; // Noncompliant: use Object.setPrototype ---- -To fix your code replace `\\__proto__` with calls to `Object.getPrototype` and `Object.setPrototype` static methods. +To fix your code replace ``++__proto__++`` with calls to `Object.getPrototype` and `Object.setPrototype` static methods. [source,javascript,diff-id=1,diff-type=compliant] ---- diff --git a/rules/S6766/javascript/rule.adoc b/rules/S6766/javascript/rule.adoc index c41c659d57..2c2efe2df1 100644 --- a/rules/S6766/javascript/rule.adoc +++ b/rules/S6766/javascript/rule.adoc @@ -14,8 +14,8 @@ If JSX special characters (`>`, `}`) appear unescaped in the element body, this To fix the issue, check the structure of your JSX tag or expression - are the closing brackets correct and in the right place? If the special character is there on purpose - you need to change it to the appropriate HTML entity. -- replace `>` with `\>` -- replace `}` with `\}` +- replace `>` with ``++>++`` +- replace `}` with ``++}++`` [source,javascript,diff-id=1,diff-type=compliant] ---- diff --git a/rules/S899/jvm-description.adoc b/rules/S899/jvm-description.adoc index 66a1a6e477..ffa9442669 100644 --- a/rules/S899/jvm-description.adoc +++ b/rules/S899/jvm-description.adoc @@ -8,7 +8,7 @@ This rule raises an issue when the return values of the following are ignored: * `Iterator.hasNext()` * `Enumeration.hasMoreElements()` * `Lock.tryLock()` -* non-void `Condition.await*` methods +* non-void ``++Condition.await*++`` methods * `CountDownLatch.await(long, TimeUnit)` * `Semaphore.tryAcquire` * `BlockingQueue`: `offer`, `remove` diff --git a/rules/S954/cfamily/rule.adoc b/rules/S954/cfamily/rule.adoc index 7f6d795334..00630ba382 100644 --- a/rules/S954/cfamily/rule.adoc +++ b/rules/S954/cfamily/rule.adoc @@ -2,7 +2,7 @@ To aid code readability, all the ``++#include++`` directives in a particular code file should be grouped together near the top of the file. The only items which may precede an ``++#include++`` in a file are other preprocessor directives or comments. -Additionally, an `#include` may appear within an `extern "C"` block, this can be used for instance to include a C file from a C++ file. +Additionally, an ``++#include++`` may appear within an `extern "C"` block, this can be used for instance to include a C file from a C++ file. === Noncompliant code example diff --git a/rules/S955/cfamily/rule.adoc b/rules/S955/cfamily/rule.adoc index ad3eb3c65f..22deeb3431 100644 --- a/rules/S955/cfamily/rule.adoc +++ b/rules/S955/cfamily/rule.adoc @@ -1,9 +1,9 @@ == Why is this an issue? -The `#include` directive allows you to include header files in your code by enclosing the file names in either double quotes (`"`) or angle brackets (`<` and `>`). However, using: +The ``++#include++`` directive allows you to include header files in your code by enclosing the file names in either double quotes (`"`) or angle brackets (`<` and `>`). However, using: -* `'`, `\` or `/*` characters between the double quotes (for example: `#include "dir\foo.h"`) -* `'`, `\`, `"` or `/*` characters between the angle brackets (for example: `#include <"foo">`) +* `'`, `\` or `/*` characters between the double quotes (for example: ``++#include "dir\foo.h"++``) +* `'`, `\`, `"` or `/*` characters between the angle brackets (for example: ``++#include <"foo">++``) in the header names may or may not be supported, and the behavior will depend on the specific implementation. diff --git a/rules/S956/cfamily/rule.adoc b/rules/S956/cfamily/rule.adoc index 767c2f0816..bce6506914 100644 --- a/rules/S956/cfamily/rule.adoc +++ b/rules/S956/cfamily/rule.adoc @@ -1,10 +1,10 @@ == Why is this an issue? -The `#include` directive is a preprocessor directive that tells the compiler to insert the contents of a file in the source code. +The ``++#include++`` directive is a preprocessor directive that tells the compiler to insert the contents of a file in the source code. -However, the standard only allows the `#include` directive to be followed by angle brackets (``) or double quotes (`"filename.h"`). +However, the standard only allows the ``++#include++`` directive to be followed by angle brackets (``) or double quotes (`"filename.h"`). -If the `#include` directive contains macro names, the result of their expansion must also follow this rule: +If the ``++#include++`` directive contains macro names, the result of their expansion must also follow this rule: [source,cpp] ---- @@ -12,7 +12,7 @@ If the `#include` directive contains macro names, the result of their expansion #include HEADER // Compliant ---- -The behavior is undefined if neither angle brackets nor double quotes follow the `#include` directive. +The behavior is undefined if neither angle brackets nor double quotes follow the ``++#include++`` directive. == Resources