diff --git a/demo-api/restrictedpython-security.yaml b/demo-api/restrictedpython-security.yaml deleted file mode 100644 index 786a0cb..0000000 --- a/demo-api/restrictedpython-security.yaml +++ /dev/null @@ -1,146 +0,0 @@ -name: restrictedpython_security_validation -path: snippets/ -headers: - Authorization: Token ${token} -requests: - # Test 1: Allowed modules should work - - name: test_allowed_modules - method: post - body: - title: "Allowed Modules Test" - code: "# Testing allowed modules" - language: "python" - # Test all allowed modules from ALLOWED_MODULES - datetime_now: ${{ datetime.datetime.now().isoformat() }} - math_sqrt: ${{ math.sqrt(16) }} - random_int: ${{ random.randint(1, 10) }} - regex_match: ${{ bool(re.match("a", "abc")) }} - time_now: ${{ time.time() }} - uuid_generated: ${{ str(uuid.uuid4()) }} - tests: - - name: status_code_is_201 - assert: ${{ response.status_code == 201 }} - - name: allowed_modules_work - assert: ${{ response.json()["math_sqrt"] == 4.0 }} - - name: datetime_module_works - assert: ${{ len(response.json()["datetime_now"]) > 10 }} - - name: random_in_range - assert: ${{ 1 <= response.json()["random_int"] <= 10 }} - - name: regex_works - assert: ${{ response.json()["regex_match"] == True }} - - name: time_is_numeric - assert: ${{ isinstance(response.json()["time_now"], (int, float)) }} - - name: uuid_is_string - assert: ${{ isinstance(response.json()["uuid_generated"], str) }} - - # Test 2: Unicode handling - - name: test_unicode_handling - method: post - body: - title: "Unicode Test" - code: "# Testing unicode" - language: "python" - # Unicode string operations - reversed_unicode: ${{ "áéíóú"[::-1] }} - unicode_length: ${{ len("áéíóú") }} - unicode_upper: ${{ "hello ñoño".upper() }} - unicode_title: ${{ "josé maría".title() }} - tests: - - name: status_code_is_201 - assert: ${{ response.status_code == 201 }} - - name: unicode_reverse_works - assert: ${{ response.json()["reversed_unicode"] == "úóíéá" }} - - name: unicode_length_correct - assert: ${{ response.json()["unicode_length"] == 5 }} - - name: unicode_upper_works - assert: ${{ "ÑOÑO" in response.json()["unicode_upper"] }} - - # Test 3: Isolation between requests - - name: test_isolation_first - method: post - body: - title: "Isolation Test 1" - code: "# First isolation test" - language: "python" - # These should be isolated from each other - string_length_a: ${{ len("a") }} - test_value: ${{ 42 }} - vars: - first_result: ${{ response.json()["string_length_a"] }} - tests: - - name: status_code_is_201 - assert: ${{ response.status_code == 201 }} - - name: first_length_correct - assert: ${{ response.json()["string_length_a"] == 1 }} - - - name: test_isolation_second - method: post - body: - title: "Isolation Test 2" - code: "# Second isolation test" - language: "python" - # Should not have access to previous execution state - string_length_bb: ${{ len("bb") }} - different_value: ${{ 84 }} - tests: - - name: status_code_is_201 - assert: ${{ response.status_code == 201 }} - - name: second_length_correct - assert: ${{ response.json()["string_length_bb"] == 2 }} - - name: isolation_verified - assert: ${{ response.json()["string_length_bb"] != first_result }} - - # Test 4: Complex safe expressions - - name: test_complex_safe_expressions - method: post - body: - title: "Complex Safe Expressions" - code: "# Complex expressions test" - language: "python" - # Test complex but safe operations - list_comprehension: ${{ [x * 2 for x in range(1, 6)] }} - nested_dict: ${{ {"data": {"nested": {"value": 123}}} }} - string_operations: ${{ "hello world".replace("world", "RestrictedPython").title() }} - math_combinations: ${{ math.ceil(math.sqrt(math.pow(4, 2))) }} - datetime_arithmetic: ${{ (datetime.datetime.now() + datetime.timedelta(days=1)).strftime('%Y-%m-%d') }} - tests: - - name: status_code_is_201 - assert: ${{ response.status_code == 201 }} - - name: list_comprehension_works - assert: ${{ response.json()["list_comprehension"] == [2, 4, 6, 8, 10] }} - - name: nested_dict_access_works - assert: ${{ response.json()["nested_dict"]["data"]["nested"]["value"] == 123 }} - - name: string_ops_work - assert: ${{ response.json()["string_operations"] == "Hello Restrictedpython" }} - - name: math_combinations_work - assert: ${{ response.json()["math_combinations"] == 4 }} - - # Test 5: Edge cases and boundary conditions - - name: test_edge_cases - method: post - body: - title: "Edge Cases Test" - code: "# Edge cases" - language: "python" - # Test edge cases that should work safely - empty_string_len: ${{ len("") }} - zero_math: ${{ math.sqrt(0) }} - negative_abs: ${{ abs(-42) }} - boolean_operations: ${{ True and False or True }} - none_check: ${{ None is None }} - type_checking: ${{ isinstance([], list) }} - tests: - - name: status_code_is_201 - assert: ${{ response.status_code == 201 }} - - name: empty_string_len_zero - assert: ${{ response.json()["empty_string_len"] == 0 }} - - name: zero_sqrt_works - assert: ${{ response.json()["zero_math"] == 0.0 }} - - name: abs_works - assert: ${{ response.json()["negative_abs"] == 42 }} - - name: boolean_logic_works - assert: ${{ response.json()["boolean_operations"] == True }} - - name: none_check_works - assert: ${{ response.json()["none_check"] == True }} - - name: type_check_works - assert: ${{ response.json()["type_checking"] == True }} \ No newline at end of file diff --git a/demo-api/restrictedpython-unsafe-tests.yaml b/demo-api/restrictedpython-unsafe-tests.yaml deleted file mode 100644 index e69a7a8..0000000 --- a/demo-api/restrictedpython-unsafe-tests.yaml +++ /dev/null @@ -1,112 +0,0 @@ -name: restrictedpython_unsafe_operations -path: snippets/ -headers: - Authorization: Token ${token} -requests: - # Test: Verify that unsafe operations documentation exists - # These tests document what SHOULD be blocked by RestrictedPython - # The expressions themselves are commented to avoid execution - - - name: test_disallowed_modules_documentation - method: post - body: - title: "Disallowed Modules Documentation" - code: "# These modules should be blocked by RestrictedPython" - language: "python" - # Document what should be blocked (as comments for safety): - # BLOCKED: import os; os.system("ls") - # BLOCKED: import sys; sys.exit(0) - # BLOCKED: import subprocess; subprocess.run(["ls"]) - # BLOCKED: __import__('os').system('ls') - security_test_category: "disallowed_modules" - expected_behavior: "RestrictedPython should prevent importing os, sys, subprocess" - tests: - - name: status_code_is_201 - assert: ${{ response.status_code == 201 }} - - name: documentation_created - assert: ${{ response.json()["security_test_category"] == "disallowed_modules" }} - - - name: test_dangerous_builtins_documentation - method: post - body: - title: "Dangerous Built-ins Documentation" - code: "# These built-ins should be blocked" - language: "python" - # Document what should be blocked (as comments for safety): - # BLOCKED: open("file.txt", "r") - # BLOCKED: exec("print('dangerous')") - # BLOCKED: eval("2+2") - # BLOCKED: compile("print(1)", "", "exec") - security_test_category: "dangerous_builtins" - expected_behavior: "RestrictedPython should block open, exec, eval, compile" - tests: - - name: status_code_is_201 - assert: ${{ response.status_code == 201 }} - - name: documentation_created - assert: ${{ response.json()["security_test_category"] == "dangerous_builtins" }} - - - name: test_restricted_attributes_documentation - method: post - body: - title: "Restricted Attributes Documentation" - code: "# These attribute accesses should be blocked" - language: "python" - # Document what should be blocked (as comments for safety): - # BLOCKED: ().__class__.__mro__ - # BLOCKED: [].__class__.__base__.__subclasses__() - # BLOCKED: "".__class__.__mro__[1].__subclasses__() - # BLOCKED: (lambda:0).__globals__ - # BLOCKED: type.__subclasses__(type) - security_test_category: "restricted_attributes" - expected_behavior: "RestrictedPython should block dangerous attribute access" - tests: - - name: status_code_is_201 - assert: ${{ response.status_code == 201 }} - - name: documentation_created - assert: ${{ response.json()["security_test_category"] == "restricted_attributes" }} - - - name: test_side_effects_prevention_documentation - method: post - body: - title: "Side Effects Prevention Documentation" - code: "# These side effects should be prevented" - language: "python" - # Document what should be blocked (as comments for safety): - # BLOCKED: globals()["x"] = 1 - # BLOCKED: setattr(object(), "attr", "value") - # BLOCKED: delattr(object(), "attr") - # BLOCKED: vars()["new_var"] = "dangerous" - security_test_category: "side_effects_prevention" - expected_behavior: "RestrictedPython should prevent global state mutation" - tests: - - name: status_code_is_201 - assert: ${{ response.status_code == 201 }} - - name: documentation_created - assert: ${{ response.json()["security_test_category"] == "side_effects_prevention" }} - - # Test that safe operations still work after unsafe documentation - - name: test_safe_operations_still_work - method: post - body: - title: "Safe Operations Verification" - code: "# Verify safe operations work" - language: "python" - # These should continue to work fine - safe_math: ${{ math.sqrt(25) }} - safe_datetime: ${{ datetime.datetime.now().year }} - safe_string: ${{ "test".upper() }} - safe_list: ${{ [1, 2, 3][1] }} - safe_dict: ${{ {"key": "value"}["key"] }} - tests: - - name: status_code_is_201 - assert: ${{ response.status_code == 201 }} - - name: safe_math_works - assert: ${{ response.json()["safe_math"] == 5.0 }} - - name: safe_datetime_works - assert: ${{ response.json()["safe_datetime"] >= 2024 }} - - name: safe_string_works - assert: ${{ response.json()["safe_string"] == "TEST" }} - - name: safe_list_works - assert: ${{ response.json()["safe_list"] == 2 }} - - name: safe_dict_works - assert: ${{ response.json()["safe_dict"] == "value" }} \ No newline at end of file diff --git a/demo-api/scanapi-report.html b/demo-api/scanapi-report.html new file mode 100644 index 0000000..d24b400 --- /dev/null +++ b/demo-api/scanapi-report.html @@ -0,0 +1,4721 @@ + + + + + + + + ScanAPI Report + + + + + + + + +
+ +
+ +
+
+ +

Report generated for Snippets API

+ +

Generated at: 2021-09-17 18:31:50

+
+ + +
+ + + + + +
+ + + +
+
+

Request

+

Full URL: http://demo.scanapi.dev/api/v1/health/

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ User-Agent + + python-requests/2.26.0 +
+ Accept-Encoding + + gzip, deflate +
+ Accept + + */* +
+ Connection + + keep-alive +
+ Content-Type + + application/json +
+ + + + +
+ cURL +
curl -X GET -H "User-Agent: python-requests/2.26.0" -H "Accept-Encoding: gzip, deflate" -H "Accept: */*" -H "Connection: keep-alive" -H "Content-Type: application/json" -d 'None' http://demo.scanapi.dev/api/v1/health/ --compressed
+ +
+
+ +
+

Response

+ + + + + + + + + + + + + + + +
+ status code + + 200 +
+ response time + + 0.70092 s +
+ redirect + + False +
+ + +
+ Headers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ Date + + Fri, 17 Sep 2021 21:31:51 GMT +
+ Content-Type + + application/json +
+ Content-Length + + 5 +
+ Connection + + keep-alive +
+ vary + + Accept, Cookie +
+ allow + + GET, HEAD, OPTIONS +
+ x-frame-options + + DENY +
+ x-content-type-options + + nosniff +
+ referrer-policy + + same-origin +
+ via + + 1.1 vegur +
+ CF-Cache-Status + + DYNAMIC +
+ Report-To + + {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=dA3j5Z9%2B3EQ8qmYzuH8oFoeC535K9auMfh08k5zUacYcKEeCWHX08eqFmdg4XmDQcRg9zkwK2lqN%2FpifjBU927MqenUKxd2GT6h2VeE4kXJNBRfTVxKDqyWpAJUqSKD9xi9Bq3Es7lF8rpHngkvD"}],"group":"cf-nel","max_age":604800} +
+ NEL + + {"success_fraction":0,"report_to":"cf-nel","max_age":604800} +
+ Server + + cloudflare +
+ CF-RAY + + 690571990c8e5893-POA +
+ alt-svc + + h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400 +
+
+ +
+ Content +

+ "OK!" +

+ +
+ +
+ +
+

Tests

+
+
+ + [PASSED] + +
+
+ + snippets-api::health::status_code_is_200 + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::health::body_equals_ok + + + +
+
+ +
+
+
+ + + + + +
+ + + +
+
+

Request

+

Full URL: http://demo.scanapi.dev/api/v1/rest-auth/login/

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ User-Agent + + python-requests/2.26.0 +
+ Accept-Encoding + + gzip, deflate +
+ Accept + + */* +
+ Connection + + keep-alive +
+ Content-Type + + application/json +
+ Content-Length + + 47 +
+ + + +
+ Body +

{"username": "guest", "password": "SENSITIVE_INFORMATION"}

+ +
+ + +
+ cURL +
curl -X POST -H "User-Agent: python-requests/2.26.0" -H "Accept-Encoding: gzip, deflate" -H "Accept: */*" -H "Connection: keep-alive" -H "Content-Type: application/json" -H "Content-Length: 47" -d '{"username": "guest", "password": "SENSITIVE_INFORMATION"}' http://demo.scanapi.dev/api/v1/rest-auth/login/ --compressed
+ +
+
+ +
+

Response

+ + + + + + + + + + + + + + + +
+ status code + + 200 +
+ response time + + 0.704996 s +
+ redirect + + False +
+ + +
+ Headers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ Date + + Fri, 17 Sep 2021 21:31:51 GMT +
+ Content-Type + + application/json +
+ Transfer-Encoding + + chunked +
+ Connection + + keep-alive +
+ vary + + Accept, Cookie +
+ allow + + POST, OPTIONS +
+ x-frame-options + + DENY +
+ x-content-type-options + + nosniff +
+ referrer-policy + + same-origin +
+ set-cookie + + csrftoken=onTwmvnNJuhzCp3wc11nOxAg9WluEgjsFtwuzWJLLU6vpyOsccZ1IttXBvJTt82D; expires=Fri, 16 Sep 2022 21:31:51 GMT; Max-Age=31449600; Path=/; SameSite=Lax, sessionid=9khh2ipbvuqrpetfm3kmi3x1rrbsnzlq; expires=Fri, 01 Oct 2021 21:31:51 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax +
+ via + + 1.1 vegur +
+ CF-Cache-Status + + DYNAMIC +
+ Report-To + + {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=U3ryveY1ySKsiUpH0J3x1PfhXUL6GpK0j84%2BTWyA%2Fs7W9gvXuBRBEW%2BBxwvUrCDN64V3m%2B%2BgbU5jxGtFL%2FPNIti7vByDp2Q5wxUqtPzClJsKghyvCIDnxWO1nvkJHyaGYRImCYPwXQRcIDjJjkTX"}],"group":"cf-nel","max_age":604800} +
+ NEL + + {"success_fraction":0,"report_to":"cf-nel","max_age":604800} +
+ Server + + cloudflare +
+ CF-RAY + + 6905719d8c525898-POA +
+ Content-Encoding + + gzip +
+ alt-svc + + h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400 +
+
+ +
+ Content +

+ {"key": "SENSITIVE_INFORMATION"} +

+ +
+ +
+ +
+

Tests

+
+
+ + [PASSED] + +
+
+ + snippets-api::get_token::status_code_is_200 + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::get_token::key_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::get_token::response_time_is_under_two_seconds + + + +
+
+ +
+
+
+ + + + + +
+ + + +
+
+

Request

+

Full URL: http://demo.scanapi.dev/api/v1/snippets/

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ User-Agent + + python-requests/2.26.0 +
+ Accept-Encoding + + gzip, deflate +
+ Accept + + */* +
+ Connection + + keep-alive +
+ Content-Type + + application/json +
+ Authorization + + SENSITIVE_INFORMATION +
+ Content-Length + + 96 +
+ + + +
+ Body +

{"title": "Hello World", "code": "print('hello world')", "style": "xcode", "language": "python"}

+ +
+ + +
+ cURL +
curl -X POST -H "User-Agent: python-requests/2.26.0" -H "Accept-Encoding: gzip, deflate" -H "Accept: */*" -H "Connection: keep-alive" -H "Content-Type: application/json" -H "Authorization: SENSITIVE_INFORMATION" -H "Content-Length: 96" -d '{"title": "Hello World", "code": "print('hello world')", "style": "xcode", "language": "python"}' http://demo.scanapi.dev/api/v1/snippets/ --compressed
+ +
+
+ +
+

Response

+ + + + + + + + + + + + + + + +
+ status code + + 201 +
+ response time + + 0.400251 s +
+ redirect + + False +
+ + +
+ Headers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ Date + + Fri, 17 Sep 2021 21:31:52 GMT +
+ Content-Type + + application/json +
+ Content-Length + + 252 +
+ Connection + + keep-alive +
+ location + + http://demo.scanapi.dev/api/v1/snippets/757/ +
+ vary + + Accept +
+ allow + + GET, POST, HEAD, OPTIONS +
+ x-frame-options + + DENY +
+ x-content-type-options + + nosniff +
+ referrer-policy + + same-origin +
+ via + + 1.1 vegur +
+ CF-Cache-Status + + DYNAMIC +
+ Report-To + + {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=TpVbLUfiqOG26hubrRakfo%2BK8HZHRfTDCNvNhG8CMOdShsy97OL7xNkr%2FNT%2B2MyRkqmPFbnqBU0RmnewEkNDJ2lwU4hot0hsGuGQPtgqX%2BHrMMoGZVqYgwQ4W%2F73WjXX0%2BDdkNPsDYRXXJBT2tzC"}],"group":"cf-nel","max_age":604800} +
+ NEL + + {"success_fraction":0,"report_to":"cf-nel","max_age":604800} +
+ Server + + cloudflare +
+ CF-RAY + + 690571a1ff495898-POA +
+ alt-svc + + h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400 +
+
+ +
+ Content +

+ {"url":"http://demo.scanapi.dev/api/v1/snippets/757/","id":757,"highlight":"http://demo.scanapi.dev/api/v1/snippets/757/highlight/","owner":"guest","title":"Hello World","code":"print('hello world')","linenos":false,"language":"python","style":"xcode"} +

+ +
+ +
+ +
+

Tests

+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::create::status_code_is_201 + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::create::response_time_is_under_two_seconds + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::create::url_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::create::id_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::create::highlight_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::create::owner_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::create::title_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::create::code_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::create::linenos_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::create::language_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::create::style_in_content + + + +
+
+ +
+
+
+ + + + + +
+ + + +
+
+

Request

+

Full URL: http://demo.scanapi.dev/api/v1/snippets/757/

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ User-Agent + + python-requests/2.26.0 +
+ Accept-Encoding + + gzip, deflate +
+ Accept + + */* +
+ Connection + + keep-alive +
+ Content-Type + + application/json +
+ Authorization + + SENSITIVE_INFORMATION +
+ + + + +
+ cURL +
curl -X GET -H "User-Agent: python-requests/2.26.0" -H "Accept-Encoding: gzip, deflate" -H "Accept: */*" -H "Connection: keep-alive" -H "Content-Type: application/json" -H "Authorization: SENSITIVE_INFORMATION" -d 'None' http://demo.scanapi.dev/api/v1/snippets/757/ --compressed
+ +
+
+ +
+

Response

+ + + + + + + + + + + + + + + +
+ status code + + 200 +
+ response time + + 0.398686 s +
+ redirect + + False +
+ + +
+ Headers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ Date + + Fri, 17 Sep 2021 21:31:52 GMT +
+ Content-Type + + application/json +
+ Transfer-Encoding + + chunked +
+ Connection + + keep-alive +
+ vary + + Accept +
+ allow + + GET, PUT, PATCH, DELETE, HEAD, OPTIONS +
+ x-frame-options + + DENY +
+ x-content-type-options + + nosniff +
+ referrer-policy + + same-origin +
+ via + + 1.1 vegur +
+ CF-Cache-Status + + DYNAMIC +
+ Report-To + + {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=RKRDJneBRsL7sImdxiFG99Uo6cKlsSfa31lmLZ%2BLlfTvmCY2CL6NhBXvEQxgZw1at8eXSMvTfMiNvaCGHaj%2Bo2kcoI2ZM%2FixJ5v5qwRQg4OmJxU1IPT%2F%2FxQ6ED4xnE5mPPzBRIkGPEA7x46tVSIF"}],"group":"cf-nel","max_age":604800} +
+ NEL + + {"success_fraction":0,"report_to":"cf-nel","max_age":604800} +
+ Server + + cloudflare +
+ CF-RAY + + 690571a48c805899-POA +
+ Content-Encoding + + gzip +
+ alt-svc + + h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400 +
+
+ +
+ Content +

+ {"url":"http://demo.scanapi.dev/api/v1/snippets/757/","id":757,"highlight":"http://demo.scanapi.dev/api/v1/snippets/757/highlight/","owner":"guest","title":"Hello World","code":"print('hello world')","linenos":false,"language":"python","style":"xcode"} +

+ +
+ +
+ +
+

Tests

+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::details::status_code_is_200 + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::details::response_time_is_under_a_second + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::details::url_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::details::id_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::details::highlight_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::details::owner_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::details::title_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::details::code_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::details::linenos_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::details::language_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::details::style_in_content + + + +
+
+ +
+
+
+ + + + + +
+ + + +
+
+

Request

+

Full URL: http://demo.scanapi.dev/api/v1/snippets/757/

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ User-Agent + + python-requests/2.26.0 +
+ Accept-Encoding + + gzip, deflate +
+ Accept + + */* +
+ Connection + + keep-alive +
+ Content-Type + + application/json +
+ Authorization + + SENSITIVE_INFORMATION +
+ Content-Length + + 33 +
+ + + +
+ Body +

{"code": "print('hello, patch')"}

+ +
+ + +
+ cURL +
curl -X PATCH -H "User-Agent: python-requests/2.26.0" -H "Accept-Encoding: gzip, deflate" -H "Accept: */*" -H "Connection: keep-alive" -H "Content-Type: application/json" -H "Authorization: SENSITIVE_INFORMATION" -H "Content-Length: 33" -d '{"code": "print('hello, patch')"}' http://demo.scanapi.dev/api/v1/snippets/757/ --compressed
+ +
+
+ +
+

Response

+ + + + + + + + + + + + + + + +
+ status code + + 200 +
+ response time + + 0.399114 s +
+ redirect + + False +
+ + +
+ Headers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ Date + + Fri, 17 Sep 2021 21:31:53 GMT +
+ Content-Type + + application/json +
+ Transfer-Encoding + + chunked +
+ Connection + + keep-alive +
+ vary + + Accept +
+ allow + + GET, PUT, PATCH, DELETE, HEAD, OPTIONS +
+ x-frame-options + + DENY +
+ x-content-type-options + + nosniff +
+ referrer-policy + + same-origin +
+ via + + 1.1 vegur +
+ CF-Cache-Status + + DYNAMIC +
+ Report-To + + {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=kX8qKnRqWuQg4oWhRXNOqFMeoPjtDbptvae9sb4%2Fmpitk%2FsUczRZiroi%2BIya10yjddaFdBeSMYWZzU6tZwmDckVEoGWa6cvzteqphao1ucVbzTtS%2FesM7trJX2554QLyv%2F8fGMXAaTCvVq3Qjket"}],"group":"cf-nel","max_age":604800} +
+ NEL + + {"success_fraction":0,"report_to":"cf-nel","max_age":604800} +
+ Server + + cloudflare +
+ CF-RAY + + 690571a71db458aa-POA +
+ Content-Encoding + + gzip +
+ alt-svc + + h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400 +
+
+ +
+ Content +

+ {"url":"http://demo.scanapi.dev/api/v1/snippets/757/","id":757,"highlight":"http://demo.scanapi.dev/api/v1/snippets/757/highlight/","owner":"guest","title":"Hello World","code":"print('hello, patch')","linenos":false,"language":"python","style":"xcode"} +

+ +
+ +
+ +
+

Tests

+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::update_with_patch::status_code_is_200 + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::update_with_patch::response_time_is_under_a_second + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::update_with_patch::url_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::update_with_patch::id_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::update_with_patch::highlight_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::update_with_patch::owner_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::update_with_patch::title_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::update_with_patch::code_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::update_with_patch::linenos_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::update_with_patch::language_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::update_with_patch::style_in_content + + + +
+
+ +
+
+
+ + + + + +
+ + + +
+
+

Request

+

Full URL: http://demo.scanapi.dev/api/v1/snippets/757/

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ User-Agent + + python-requests/2.26.0 +
+ Accept-Encoding + + gzip, deflate +
+ Accept + + */* +
+ Connection + + keep-alive +
+ Content-Type + + application/json +
+ Authorization + + SENSITIVE_INFORMATION +
+ Content-Length + + 99 +
+ + + +
+ Body +

{"title": "Hello World - Ruby", "code": "puts 'hello world'", "style": "emacs", "language": "ruby"}

+ +
+ + +
+ cURL +
curl -X PUT -H "User-Agent: python-requests/2.26.0" -H "Accept-Encoding: gzip, deflate" -H "Accept: */*" -H "Connection: keep-alive" -H "Content-Type: application/json" -H "Authorization: SENSITIVE_INFORMATION" -H "Content-Length: 99" -d '{"title": "Hello World - Ruby", "code": "puts 'hello world'", "style": "emacs", "language": "ruby"}' http://demo.scanapi.dev/api/v1/snippets/757/ --compressed
+ +
+
+ +
+

Response

+ + + + + + + + + + + + + + + +
+ status code + + 200 +
+ response time + + 0.501131 s +
+ redirect + + False +
+ + +
+ Headers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ Date + + Fri, 17 Sep 2021 21:31:53 GMT +
+ Content-Type + + application/json +
+ Transfer-Encoding + + chunked +
+ Connection + + keep-alive +
+ vary + + Accept +
+ allow + + GET, PUT, PATCH, DELETE, HEAD, OPTIONS +
+ x-frame-options + + DENY +
+ x-content-type-options + + nosniff +
+ referrer-policy + + same-origin +
+ via + + 1.1 vegur +
+ CF-Cache-Status + + DYNAMIC +
+ Report-To + + {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=Y8KXNiRxtQ1FDwK5avwY2eqSNWjiGdathRhqkN2BXglKQ2%2FPvLqjkF3GazCsvt6jBscgtmwqu3EEdUa4EQlINFlHP8vKCu5BpMgX7OSlCZzh6oDPwcSr5kWhIRUicvz6j%2BUg6m4gPCM%2BP800rAvw"}],"group":"cf-nel","max_age":604800} +
+ NEL + + {"success_fraction":0,"report_to":"cf-nel","max_age":604800} +
+ Server + + cloudflare +
+ CF-RAY + + 690571a9b9d35899-POA +
+ Content-Encoding + + gzip +
+ alt-svc + + h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400 +
+
+ +
+ Content +

+ {"url":"http://demo.scanapi.dev/api/v1/snippets/757/","id":757,"highlight":"http://demo.scanapi.dev/api/v1/snippets/757/highlight/","owner":"guest","title":"Hello World - Ruby","code":"puts 'hello world'","linenos":false,"language":"ruby","style":"emacs"} +

+ +
+ +
+ +
+

Tests

+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::snippet_update_with_put::status_code_is_200 + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::snippet_update_with_put::response_time_is_under_a_second + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::snippet_update_with_put::url_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::snippet_update_with_put::id_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::snippet_update_with_put::highlight_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::snippet_update_with_put::owner_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::snippet_update_with_put::title_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::snippet_update_with_put::code_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::snippet_update_with_put::linenos_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::snippet_update_with_put::language_in_content + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::snippet_update_with_put::style_in_content + + + +
+
+ +
+
+
+ + + + + +
+ + + +
+
+

Request

+

Full URL: http://demo.scanapi.dev/api/v1/snippets/757/

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ User-Agent + + python-requests/2.26.0 +
+ Accept-Encoding + + gzip, deflate +
+ Accept + + */* +
+ Connection + + keep-alive +
+ Content-Type + + application/json +
+ Authorization + + SENSITIVE_INFORMATION +
+ Content-Length + + 0 +
+ + + + +
+ cURL +
curl -X DELETE -H "User-Agent: python-requests/2.26.0" -H "Accept-Encoding: gzip, deflate" -H "Accept: */*" -H "Connection: keep-alive" -H "Content-Type: application/json" -H "Authorization: SENSITIVE_INFORMATION" -H "Content-Length: 0" -d 'None' http://demo.scanapi.dev/api/v1/snippets/757/ --compressed
+ +
+
+ +
+

Response

+ + + + + + + + + + + + + + + +
+ status code + + 204 +
+ response time + + 0.398764 s +
+ redirect + + False +
+ + +
+ Headers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ Date + + Fri, 17 Sep 2021 21:31:54 GMT +
+ Content-Length + + 0 +
+ Connection + + keep-alive +
+ vary + + Accept +
+ allow + + GET, PUT, PATCH, DELETE, HEAD, OPTIONS +
+ x-frame-options + + DENY +
+ x-content-type-options + + nosniff +
+ referrer-policy + + same-origin +
+ via + + 1.1 vegur +
+ CF-Cache-Status + + DYNAMIC +
+ Report-To + + {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=ctKdZRmm6Pur76iBIhAE5y6feCn4ogScu%2FC55%2BdDLrKvmfOwG1NwDC77l2A4M8tzybdLtseuvNOiR29zCuxJR0O1jP5z0lzOkeGDwqZrXscnlOH%2B4T%2FqaVQIcw0ps%2BkvyBI7Heu3id55g31ld%2BOR"}],"group":"cf-nel","max_age":604800} +
+ NEL + + {"success_fraction":0,"report_to":"cf-nel","max_age":604800} +
+ Server + + cloudflare +
+ CF-RAY + + 690571acef585898-POA +
+ alt-svc + + h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400 +
+
+ +
+ Content +

+ b'' +

+ +
+ +
+ +
+

Tests

+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::delete::status_code_is_204 + + + +
+
+ +
+
+
+ + + + + +
+ + + +
+
+

Request

+

Full URL: http://demo.scanapi.dev/api/v1/snippets/

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ User-Agent + + python-requests/2.26.0 +
+ Accept-Encoding + + gzip, deflate +
+ Accept + + */* +
+ Connection + + keep-alive +
+ Content-Type + + application/json +
+ Authorization + + SENSITIVE_INFORMATION +
+ + + + +
+ cURL +
curl -X GET -H "User-Agent: python-requests/2.26.0" -H "Accept-Encoding: gzip, deflate" -H "Accept: */*" -H "Connection: keep-alive" -H "Content-Type: application/json" -H "Authorization: SENSITIVE_INFORMATION" -d 'None' http://demo.scanapi.dev/api/v1/snippets/ --compressed
+ +
+
+ +
+

Response

+ + + + + + + + + + + + + + + +
+ status code + + 200 +
+ response time + + 0.400607 s +
+ redirect + + False +
+ + +
+ Headers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ Date + + Fri, 17 Sep 2021 21:31:54 GMT +
+ Content-Type + + application/json +
+ Transfer-Encoding + + chunked +
+ Connection + + keep-alive +
+ vary + + Accept +
+ allow + + GET, POST, HEAD, OPTIONS +
+ x-frame-options + + DENY +
+ x-content-type-options + + nosniff +
+ referrer-policy + + same-origin +
+ via + + 1.1 vegur +
+ CF-Cache-Status + + DYNAMIC +
+ Report-To + + {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=rWZdB%2FIoKMT2T58sx5%2FuaDGfXOWvGdwmr9lkQ04Ry%2F1a6ZrN7g%2BVByphsZzIGz50Ib0cfs%2FnXuQEcBTQb0rSOegw7OeI26mSSOg8PRvzkHktEqapVbqk9saa2tmbo%2BBaIlOAlpafgN0EYiYFTZ5i"}],"group":"cf-nel","max_age":604800} +
+ NEL + + {"success_fraction":0,"report_to":"cf-nel","max_age":604800} +
+ Server + + cloudflare +
+ CF-RAY + + 690571af5ea358ab-POA +
+ Content-Encoding + + gzip +
+ alt-svc + + h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400 +
+
+ +
+ Content +

+ {"count":25,"next":"http://demo.scanapi.dev/api/v1/snippets/?page=2","previous":null,"results":[{"url":"http://demo.scanapi.dev/api/v1/snippets/2/","id":2,"highlight":"http://demo.scanapi.dev/api/v1/snippets/2/highlight/","owner":"admin","title":"Calculator","code":"def add(x, y):\r\n return x + y\r\n\r\ndef subtract(x, y):\r\n return x - y\r\n\r\ndef multiply(x, y):\r\n return x * y\r\n\r\ndef divide(x, y):\r\n return x / y","linenos":true,"language":"python","style":"emacs"},{"url":"http://demo.scanapi.dev/api/v1/snippets/6/","id":6,"highlight":"http://demo.scanapi.dev/api/v1/snippets/6/highlight/","owner":"guest","title":"","code":"print('hello, hello')","linenos":false,"language":"python","style":"friendly"},{"url":"http://demo.scanapi.dev/api/v1/snippets/100/","id":100,"highlight":"http://demo.scanapi.dev/api/v1/snippets/100/highlight/","owner":"my_user","title":"","code":"print('hello, hello')","linenos":false,"language":"python","style":"friendly"},{"url":"http://demo.scanapi.dev/api/v1/snippets/101/","id":101,"highlight":"http://demo.scanapi.dev/api/v1/snippets/101/highlight/","owner":"my_user","title":"Hello World","code":"print('hello world')","linenos":false,"language":"python","style":"xcode"},{"url":"http://demo.scanapi.dev/api/v1/snippets/102/","id":102,"highlight":"http://demo.scanapi.dev/api/v1/snippets/102/highlight/","owner":"my_user","title":"Hello World","code":"print('hello world')","linenos":false,"language":"python","style":"xcode"},{"url":"http://demo.scanapi.dev/api/v1/snippets/103/","id":103,"highlight":"http://demo.scanapi.dev/api/v1/snippets/103/highlight/","owner":"my_user","title":"Hello World","code":"print('hello world')","linenos":false,"language":"python","style":"xcode"},{"url":"http://demo.scanapi.dev/api/v1/snippets/104/","id":104,"highlight":"http://demo.scanapi.dev/api/v1/snippets/104/highlight/","owner":"my_user","title":"Hello World","code":"print('hello world')","linenos":false,"language":"python","style":"xcode"},{"url":"http://demo.scanapi.dev/api/v1/snippets/105/","id":105,"highlight":"http://demo.scanapi.dev/api/v1/snippets/105/highlight/","owner":"my_user","title":"Hello World","code":"print('hello world')","linenos":false,"language":"python","style":"xcode"},{"url":"http://demo.scanapi.dev/api/v1/snippets/106/","id":106,"highlight":"http://demo.scanapi.dev/api/v1/snippets/106/highlight/","owner":"my_user","title":"Hello World","code":"print('hello, patch')","linenos":false,"language":"python","style":"xcode"},{"url":"http://demo.scanapi.dev/api/v1/snippets/205/","id":205,"highlight":"http://demo.scanapi.dev/api/v1/snippets/205/highlight/","owner":"maiakovsky","title":"Hello World","code":"print('hello world')","linenos":false,"language":"python","style":"xcode"}]} +

+ +
+ +
+ +
+

Tests

+
+
+ + [PASSED] + +
+
+ + snippets-api::snippets::list_all::status_code_is_200 + + + +
+
+ +
+
+
+ + + + + +
+ + + +
+
+

Request

+

Full URL: http://demo.scanapi.dev/api/v1/users/

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ User-Agent + + python-requests/2.26.0 +
+ Accept-Encoding + + gzip, deflate +
+ Accept + + */* +
+ Connection + + keep-alive +
+ Content-Type + + application/json +
+ + + + +
+ cURL +
curl -X GET -H "User-Agent: python-requests/2.26.0" -H "Accept-Encoding: gzip, deflate" -H "Accept: */*" -H "Connection: keep-alive" -H "Content-Type: application/json" -d 'None' http://demo.scanapi.dev/api/v1/users/ --compressed
+ +
+
+ +
+

Response

+ + + + + + + + + + + + + + + +
+ status code + + 200 +
+ response time + + 0.502084 s +
+ redirect + + False +
+ + +
+ Headers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ Date + + Fri, 17 Sep 2021 21:31:54 GMT +
+ Content-Type + + application/json +
+ Transfer-Encoding + + chunked +
+ Connection + + keep-alive +
+ vary + + Accept, Cookie +
+ allow + + GET, HEAD, OPTIONS +
+ x-frame-options + + DENY +
+ x-content-type-options + + nosniff +
+ referrer-policy + + same-origin +
+ via + + 1.1 vegur +
+ CF-Cache-Status + + DYNAMIC +
+ Report-To + + {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=y2uM7UZDhqiCf9QMb1e5b15p232ID4O%2B5XxApM6GWnKSpTdlS2idBzLJK2SYXxZKjkrQItn0aIaAuX23W7yPnkT0VVfGpnyIVcgwyzt4sgVWEOhNYyDQGPb3IKIlE%2FXTEzD0L39jTyMYyW5Z2ngK"}],"group":"cf-nel","max_age":604800} +
+ NEL + + {"success_fraction":0,"report_to":"cf-nel","max_age":604800} +
+ Server + + cloudflare +
+ CF-RAY + + 690571b20a895898-POA +
+ Content-Encoding + + gzip +
+ alt-svc + + h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400 +
+
+ +
+ Content +

+ {"count":7,"next":null,"previous":null,"results":[{"url":"http://demo.scanapi.dev/api/v1/users/2/","id":2,"username":"guest","snippets":["http://demo.scanapi.dev/api/v1/snippets/6/","http://demo.scanapi.dev/api/v1/snippets/319/","http://demo.scanapi.dev/api/v1/snippets/410/","http://demo.scanapi.dev/api/v1/snippets/411/","http://demo.scanapi.dev/api/v1/snippets/724/","http://demo.scanapi.dev/api/v1/snippets/725/","http://demo.scanapi.dev/api/v1/snippets/726/","http://demo.scanapi.dev/api/v1/snippets/727/","http://demo.scanapi.dev/api/v1/snippets/728/","http://demo.scanapi.dev/api/v1/snippets/729/","http://demo.scanapi.dev/api/v1/snippets/730/","http://demo.scanapi.dev/api/v1/snippets/731/","http://demo.scanapi.dev/api/v1/snippets/732/","http://demo.scanapi.dev/api/v1/snippets/754/"]},{"url":"http://demo.scanapi.dev/api/v1/users/5/","id":5,"username":"pradhvan","snippets":[]},{"url":"http://demo.scanapi.dev/api/v1/users/9/","id":9,"username":"maiakovsky","snippets":["http://demo.scanapi.dev/api/v1/snippets/205/","http://demo.scanapi.dev/api/v1/snippets/206/","http://demo.scanapi.dev/api/v1/snippets/207/"]},{"url":"http://demo.scanapi.dev/api/v1/users/8/","id":8,"username":"my_user","snippets":["http://demo.scanapi.dev/api/v1/snippets/100/","http://demo.scanapi.dev/api/v1/snippets/101/","http://demo.scanapi.dev/api/v1/snippets/102/","http://demo.scanapi.dev/api/v1/snippets/103/","http://demo.scanapi.dev/api/v1/snippets/104/","http://demo.scanapi.dev/api/v1/snippets/105/","http://demo.scanapi.dev/api/v1/snippets/106/"]},{"url":"http://demo.scanapi.dev/api/v1/users/1/","id":1,"username":"admin","snippets":["http://demo.scanapi.dev/api/v1/snippets/2/"]},{"url":"http://demo.scanapi.dev/api/v1/users/11/","id":11,"username":"vitorcosta","snippets":[]},{"url":"http://demo.scanapi.dev/api/v1/users/10/","id":10,"username":"rich","snippets":[]}]} +

+ +
+ +
+ +
+

Tests

+
+
+ + [PASSED] + +
+
+ + snippets-api::users::list_all::status_code_is_200 + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::users::list_all::response_time_is_under_a_second + + + +
+
+ +
+
+
+ + + + + +
+ + + +
+
+

Request

+

Full URL: http://demo.scanapi.dev/api/v1/users/2/

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ User-Agent + + python-requests/2.26.0 +
+ Accept-Encoding + + gzip, deflate +
+ Accept + + */* +
+ Connection + + keep-alive +
+ Content-Type + + application/json +
+ + + + +
+ cURL +
curl -X GET -H "User-Agent: python-requests/2.26.0" -H "Accept-Encoding: gzip, deflate" -H "Accept: */*" -H "Connection: keep-alive" -H "Content-Type: application/json" -d 'None' http://demo.scanapi.dev/api/v1/users/2/ --compressed
+ +
+
+ +
+

Response

+ + + + + + + + + + + + + + + +
+ status code + + 200 +
+ response time + + 0.376358 s +
+ redirect + + False +
+ + +
+ Headers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Header + + Value +
+ Date + + Fri, 17 Sep 2021 21:31:55 GMT +
+ Content-Type + + application/json +
+ Transfer-Encoding + + chunked +
+ Connection + + keep-alive +
+ vary + + Accept, Cookie +
+ allow + + GET, HEAD, OPTIONS +
+ x-frame-options + + DENY +
+ x-content-type-options + + nosniff +
+ referrer-policy + + same-origin +
+ via + + 1.1 vegur +
+ CF-Cache-Status + + DYNAMIC +
+ Report-To + + {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=Ha8oMIgdzDYbKMO%2By%2BgArI0iaYQTsavZkWr%2BEjD70I6Is%2B3RyGnaE86MYEFpS9oCFTU524kWmDPrJDqJ5Qq1DouHDL4p7d9G4G6dSBDUSYpS%2FcZoioUFjE6RLZrpM0VSvCrWD1%2Byk%2Fh0wyvDYq%2FC"}],"group":"cf-nel","max_age":604800} +
+ NEL + + {"success_fraction":0,"report_to":"cf-nel","max_age":604800} +
+ Server + + cloudflare +
+ CF-RAY + + 690571b52e6d5893-POA +
+ Content-Encoding + + gzip +
+ alt-svc + + h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400 +
+
+ +
+ Content +

+ {"url":"http://demo.scanapi.dev/api/v1/users/2/","id":2,"username":"guest","snippets":["http://demo.scanapi.dev/api/v1/snippets/6/","http://demo.scanapi.dev/api/v1/snippets/319/","http://demo.scanapi.dev/api/v1/snippets/410/","http://demo.scanapi.dev/api/v1/snippets/411/","http://demo.scanapi.dev/api/v1/snippets/724/","http://demo.scanapi.dev/api/v1/snippets/725/","http://demo.scanapi.dev/api/v1/snippets/726/","http://demo.scanapi.dev/api/v1/snippets/727/","http://demo.scanapi.dev/api/v1/snippets/728/","http://demo.scanapi.dev/api/v1/snippets/729/","http://demo.scanapi.dev/api/v1/snippets/730/","http://demo.scanapi.dev/api/v1/snippets/731/","http://demo.scanapi.dev/api/v1/snippets/732/","http://demo.scanapi.dev/api/v1/snippets/754/"]} +

+ +
+ +
+ +
+

Tests

+
+
+ + [PASSED] + +
+
+ + snippets-api::users::details::status_code_is_200 + + + +
+
+
+
+ + [PASSED] + +
+
+ + snippets-api::users::details::response_time_is_under_a_second + + + +
+
+ +
+
+
+ +
+ + +
+

Tests Summary

+
+ PASSED: 55 + FAILURES: 0 + ERRORS: 0 + Total Time: 0:00:05.468666 +
+
+
+ + + +
+ Generated by ScanAPI 2.6.0 +
+ + + + + + + + \ No newline at end of file diff --git a/demo-api/scanapi.yaml b/demo-api/scanapi.yaml index b5253cd..43450ec 100644 --- a/demo-api/scanapi.yaml +++ b/demo-api/scanapi.yaml @@ -15,12 +15,8 @@ endpoints: body: username: ${USER} password: ${PASSWORD} - # RestrictedPython safe expressions - request_time: ${{ datetime.datetime.now().isoformat() }} - request_id: ${{ "req_" + str(abs(hash(datetime.datetime.now().isoformat()))) }} vars: token: ${{response.json()["key"]}} - response_time_seconds: ${{ response.elapsed.total_seconds() }} tests: - !include tests/status_code_is_200.yaml - !include tests/key_in_content.yaml @@ -28,5 +24,3 @@ endpoints: endpoints: - !include snippets.yaml - !include users.yaml - - !include restrictedpython-security.yaml - - !include restrictedpython-unsafe-tests.yaml diff --git a/demo-api/snippets.yaml b/demo-api/snippets.yaml index 2feea7f..3524824 100644 --- a/demo-api/snippets.yaml +++ b/demo-api/snippets.yaml @@ -12,13 +12,10 @@ requests: code: "print('${greeting}')" style: "xcode" language: "python" - # RestrictedPython safe expressions for metadata - created_at: ${{ datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }} - version: ${{ "v" + str(math.floor(datetime.datetime.now().timestamp())) }} - hash_id: ${{ abs(hash("Hello World")) }} vars: snippet_id: ${{response.json()["id"]}} - creation_timestamp: ${{ math.floor(datetime.datetime.now().timestamp()) }} + my_var_1: my_var_1_value + my_var_2: ${{ 'my_var_2_value' }} tests: - !include tests/status_code_is_201.yaml - !include tests/response_time_2_seconds.yaml diff --git a/demo-api/tests/response_time.yaml b/demo-api/tests/response_time.yaml index 652fe67..5f80510 100644 --- a/demo-api/tests/response_time.yaml +++ b/demo-api/tests/response_time.yaml @@ -1,2 +1,2 @@ -name: response_time_is_under_5_seconds -assert: ${{ response.elapsed.total_seconds() < 5 }} +name: response_time_is_under_a_second +assert: ${{ response.elapsed.total_seconds() < 1 }} diff --git a/demo-api/tests/restricted_python_validation.yaml b/demo-api/tests/restricted_python_validation.yaml deleted file mode 100644 index 36fef51..0000000 --- a/demo-api/tests/restricted_python_validation.yaml +++ /dev/null @@ -1,2 +0,0 @@ -name: restricted_python_safe_expressions_work -assert: ${{ datetime.datetime.now().year > 2020 and math.pi > 3.14 and len("test") == 4 }} \ No newline at end of file diff --git a/httpbingo-api/http-methods.yaml b/httpbingo-api/http-methods.yaml index 871a998..177491f 100644 --- a/httpbingo-api/http-methods.yaml +++ b/httpbingo-api/http-methods.yaml @@ -10,14 +10,9 @@ method: post vars: scanapi_var: scanapi_test1 - request_timestamp: ${{ datetime.datetime.now().timestamp() }} body: description: hello scanapi scanapi_test: ${scanapi_var} - # RestrictedPython safe expressions - request_time: ${{ datetime.datetime.now().isoformat() }} - random_id: ${{ abs(hash(datetime.datetime.now().isoformat())) }} - math_validation: ${{ math.sqrt(16) }} tests: - name: status_code_is_200 assert: ${{ response.status_code == 200 }} @@ -25,28 +20,19 @@ assert: ${{ response.json()["json"].get("scanapi_test") == "${scanapi_var}" }} - name: response_origin assert: ${{ response.json()["origin"] is not None }} - - name: restricted_python_math_works - assert: ${{ response.json()["json"].get("math_validation") == 4.0 }} - name: put-simple path: /put method: put vars: scanapi_description: hello scanapi again - update_time: ${{ datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }} body: description: ${scanapi_description} - # RestrictedPython expressions for tracking updates - updated_at: ${update_time} - update_hash: ${{ abs(hash("${scanapi_description}")) }} - pi_constant: ${{ math.pi }} tests: - name: status_code_is_200 assert: ${{ response.status_code == 200 }} - name: description_changed assert: ${{ response.json()["json"].get("description") == "${scanapi_description}" }} - - name: restricted_python_constants_work - assert: ${{ response.json()["json"].get("pi_constant") > 3.14 }} - name: patch-simple path: /patch diff --git a/httpbingo-api/httpbingo.yaml b/httpbingo-api/httpbingo.yaml index 5a6353a..2554023 100644 --- a/httpbingo-api/httpbingo.yaml +++ b/httpbingo-api/httpbingo.yaml @@ -11,7 +11,3 @@ endpoints: - name: images requests: !include images.yaml - - - name: restrictedpython-comprehensive - requests: - !include restrictedpython-comprehensive.yaml diff --git a/httpbingo-api/restrictedpython-comprehensive.yaml b/httpbingo-api/restrictedpython-comprehensive.yaml deleted file mode 100644 index c0b87ff..0000000 --- a/httpbingo-api/restrictedpython-comprehensive.yaml +++ /dev/null @@ -1,166 +0,0 @@ -- name: comprehensive_restrictedpython_allowed_modules - path: /anything/allowed-modules - method: post - body: - test_category: "allowed_modules_comprehensive" - # Test all ALLOWED_MODULES extensively - datetime_operations: - now_iso: ${{ datetime.datetime.now().isoformat() }} - future_date: ${{ (datetime.datetime.now() + datetime.timedelta(days=7)).strftime('%Y-%m-%d') }} - timestamp: ${{ datetime.datetime.now().timestamp() }} - math_operations: - sqrt_result: ${{ math.sqrt(144) }} - pi_constant: ${{ math.pi }} - ceiling: ${{ math.ceil(4.1) }} - floor: ${{ math.floor(4.9) }} - power: ${{ math.pow(3, 3) }} - logarithm: ${{ math.log10(1000) }} - trigonometry: ${{ math.cos(0) }} - random_operations: - random_int: ${{ random.randint(100, 200) }} - random_choice: ${{ random.choice(["a", "b", "c"]) }} - regex_operations: - match_result: ${{ bool(re.match(r"^\d+", "123abc")) }} - search_result: ${{ bool(re.search(r"test", "this is a test string")) }} - findall_result: ${{ re.findall(r"\d+", "abc123def456") }} - time_operations: - current_time: ${{ time.time() }} - formatted_time: ${{ time.strftime('%Y-%m-%d', time.localtime()) }} - uuid_operations: - uuid4_str: ${{ str(uuid.uuid4()) }} - uuid_parts: ${{ str(uuid.uuid4()).split("-") }} - tests: - - name: status_code_is_200 - assert: ${{ response.status_code == 200 }} - - name: datetime_works - assert: ${{ len(response.json()["json"]["datetime_operations"]["now_iso"]) > 15 }} - - name: math_sqrt_correct - assert: ${{ response.json()["json"]["math_operations"]["sqrt_result"] == 12.0 }} - - name: math_constants_work - assert: ${{ response.json()["json"]["math_operations"]["pi_constant"] > 3.14 }} - - name: random_in_range - assert: ${{ 100 <= response.json()["json"]["random_operations"]["random_int"] <= 200 }} - - name: regex_works - assert: ${{ response.json()["json"]["regex_operations"]["match_result"] == True }} - - name: time_is_numeric - assert: ${{ isinstance(response.json()["json"]["time_operations"]["current_time"], (int, float)) }} - - name: uuid_is_valid_format - assert: ${{ len(response.json()["json"]["uuid_operations"]["uuid_parts"]) == 5 }} - -- name: comprehensive_unicode_and_edge_cases - path: /anything/unicode-edge-cases - method: post - body: - test_category: "unicode_and_edge_cases" - unicode_tests: - reversed_spanish: ${{ "español"[::-1] }} - unicode_length: ${{ len("测试") }} - accent_handling: ${{ "café".upper() }} - emoji_length: ${{ len("👋🌍") }} - mixed_unicode: ${{ "Hello 世界 🌍".replace("世界", "World") }} - edge_cases: - empty_operations: - empty_string: ${{ len("") }} - empty_list: ${{ len([]) }} - empty_dict: ${{ len({}) }} - zero_operations: - zero_math: ${{ math.sqrt(0) }} - zero_power: ${{ math.pow(0, 2) }} - negative_operations: - abs_negative: ${{ abs(-100) }} - negative_modulo: ${{ -7 % 3 }} - boolean_logic: - complex_logic: ${{ (True and False) or (not False and True) }} - truthiness: ${{ bool([1, 2, 3]) and bool("") }} - comparison_chain: ${{ 1 < 2 < 3 < 4 }} - tests: - - name: status_code_is_200 - assert: ${{ response.status_code == 200 }} - - name: spanish_reversed - assert: ${{ response.json()["json"]["unicode_tests"]["reversed_spanish"] == "loñapse" }} - - name: chinese_length - assert: ${{ response.json()["json"]["unicode_tests"]["unicode_length"] == 2 }} - - name: accent_upper - assert: ${{ response.json()["json"]["unicode_tests"]["accent_handling"] == "CAFÉ" }} - - name: empty_string_len_zero - assert: ${{ response.json()["json"]["edge_cases"]["empty_operations"]["empty_string"] == 0 }} - - name: zero_sqrt_works - assert: ${{ response.json()["json"]["edge_cases"]["zero_operations"]["zero_math"] == 0.0 }} - - name: abs_works - assert: ${{ response.json()["json"]["edge_cases"]["negative_operations"]["abs_negative"] == 100 }} - - name: boolean_logic_works - assert: ${{ response.json()["json"]["edge_cases"]["boolean_logic"]["complex_logic"] == True }} - -- name: comprehensive_isolation_test_sequence - path: /anything/isolation-test-1 - method: post - vars: - test_value_1: ${{ 42 }} - string_result_1: ${{ "first_test" }} - list_result_1: ${{ [1, 2, 3] }} - body: - test_category: "isolation_sequence_1" - sequence_number: 1 - test_data: - computed_value: ${{ 10 + 32 }} - string_op: ${{ "isolation".upper() }} - list_len: ${{ len([1, 2, 3, 4, 5]) }} - tests: - - name: status_code_is_200 - assert: ${{ response.status_code == 200 }} - - name: first_computation_correct - assert: ${{ response.json()["json"]["test_data"]["computed_value"] == 42 }} - -- name: comprehensive_isolation_test_sequence_2 - path: /anything/isolation-test-2 - method: post - body: - test_category: "isolation_sequence_2" - sequence_number: 2 - test_data: - # These should NOT have access to previous test variables - different_computation: ${{ 20 + 64 }} - different_string: ${{ "different".lower() }} - different_list: ${{ len([10, 20]) }} - # Verify independence - same_operation_different_result: ${{ "isolation".lower() }} - tests: - - name: status_code_is_200 - assert: ${{ response.status_code == 200 }} - - name: second_computation_different - assert: ${{ response.json()["json"]["test_data"]["different_computation"] == 84 }} - - name: isolation_verified - assert: ${{ response.json()["json"]["test_data"]["same_operation_different_result"] == "isolation" }} - - name: no_state_leak - # This test verifies that the computations are independent - assert: ${{ response.json()["json"]["test_data"]["different_computation"] != test_value_1 }} - -- name: security_documentation_comprehensive - path: /anything/security-documentation - method: post - body: - test_category: "security_documentation_comprehensive" - documentation: - blocked_modules: "os, sys, subprocess, socket, urllib, http" - blocked_builtins: "open, exec, eval, compile, __import__" - blocked_attributes: "__class__, __bases__, __subclasses__, __globals__" - blocked_side_effects: "globals(), locals(), setattr(), delattr()" - expected_behavior: "All dangerous operations should raise InvalidPythonCodeError" - security_note: "RestrictedPython prevents code injection and system access" - # Safe operations that should continue working - safe_verification: - math_still_works: ${{ math.sqrt(49) }} - datetime_still_works: ${{ datetime.datetime.now().year }} - string_still_works: ${{ "SAFE".lower() }} - list_still_works: ${{ [1, 2, 3][-1] }} - tests: - - name: status_code_is_200 - assert: ${{ response.status_code == 200 }} - - name: safe_math_verified - assert: ${{ response.json()["json"]["safe_verification"]["math_still_works"] == 7.0 }} - - name: safe_datetime_verified - assert: ${{ response.json()["json"]["safe_verification"]["datetime_still_works"] >= 2024 }} - - name: safe_string_verified - assert: ${{ response.json()["json"]["safe_verification"]["string_still_works"] == "safe" }} - - name: safe_list_verified - assert: ${{ response.json()["json"]["safe_verification"]["list_still_works"] == 3 }} \ No newline at end of file diff --git a/httpbingo-api/tests/restricted_python_validation.yaml b/httpbingo-api/tests/restricted_python_validation.yaml deleted file mode 100644 index 36fef51..0000000 --- a/httpbingo-api/tests/restricted_python_validation.yaml +++ /dev/null @@ -1,2 +0,0 @@ -name: restricted_python_safe_expressions_work -assert: ${{ datetime.datetime.now().year > 2020 and math.pi > 3.14 and len("test") == 4 }} \ No newline at end of file diff --git a/pokeapi/scanapi.yaml b/pokeapi/scanapi.yaml index 0cf50f9..b9c2c9a 100644 --- a/pokeapi/scanapi.yaml +++ b/pokeapi/scanapi.yaml @@ -9,10 +9,6 @@ endpoints: method: get vars: pokemon_name: ${{ response.json()["results"][0]["name"] }} - # RestrictedPython safe expressions - request_timestamp: ${{ datetime.datetime.now().timestamp() }} - total_pokemon_sqrt: ${{ math.sqrt(response.json()["count"]) }} - request_date: ${{ datetime.datetime.now().strftime('%Y-%m-%d') }} tests: - name: status_code_is_200 assert: ${{ response.status_code == 200 }} @@ -22,19 +18,9 @@ endpoints: assert: ${{ len(response.json()["results"]) == 20 }} - name: count_is_gte_1118 assert: ${{ response.json()["count"] >= 1118 }} - - name: restricted_python_math_works - assert: ${{ math.sqrt(1600) == 40.0 }} - - name: restricted_python_datetime_works - assert: ${{ datetime.datetime.now().year >= 2024 }} - name: details method: get path: ${pokemon_name} - vars: - # RestrictedPython expressions for pokemon details - pokemon_id_doubled: ${{ response.json()["id"] * 2 }} - weight_kg: ${{ response.json()["weight"] / 10 }} - height_m: ${{ response.json()["height"] / 10 }} - name_length: ${{ len(response.json()["name"]) }} tests: - name: status_code_is_200 assert: ${{ response.status_code == 200 }} @@ -42,115 +28,3 @@ endpoints: assert: ${{ response.elapsed.total_seconds() < 0.5 }} - name: id_is_one assert: ${{ response.json()["id"] == 1 }} - - name: restricted_python_calculations_work - assert: ${{ response.json()["id"] * 2 == 2 }} - - name: restricted_python_string_ops_work - assert: ${{ len(response.json()["name"]) > 0 }} - - - name: restrictedpython_comprehensive_validation - path: pokemon/pikachu - requests: - - name: comprehensive_allowed_modules_test - method: get - vars: - # Comprehensive test of all ALLOWED_MODULES with Pokemon data - pokemon_data_analysis: - name_hash: ${{ abs(hash(response.json()["name"])) }} - weight_sqrt: ${{ math.sqrt(response.json()["weight"]) }} - height_calculation: ${{ math.ceil(response.json()["height"] / 10.0) }} - abilities_count: ${{ len(response.json()["abilities"]) }} - types_joined: ${{ ", ".join([t["type"]["name"] for t in response.json()["types"]]) }} - datetime_analysis: - request_timestamp: ${{ datetime.datetime.now().timestamp() }} - request_date: ${{ datetime.datetime.now().strftime('%Y-%m-%d') }} - future_cache_expire: ${{ (datetime.datetime.now() + datetime.timedelta(hours=1)).isoformat() }} - random_analysis: - random_seed: ${{ random.randint(1, 1000) }} - random_ability: ${{ random.choice(["electric", "static", "lightning-rod"]) }} - regex_analysis: - name_pattern: ${{ bool(re.match(r"^[a-z]+$", response.json()["name"])) }} - type_search: ${{ bool(re.search(r"electric", str(response.json()["types"]))) }} - time_analysis: - request_time: ${{ time.time() }} - formatted_time: ${{ time.strftime('%H:%M:%S') }} - uuid_analysis: - session_id: ${{ str(uuid.uuid4()) }} - request_id: ${{ str(uuid.uuid4())[:8] }} - tests: - - name: status_code_is_200 - assert: ${{ response.status_code == 200 }} - - name: pokemon_is_pikachu - assert: ${{ response.json()["name"] == "pikachu" }} - - name: math_operations_work - assert: ${{ isinstance(math.sqrt(response.json()["weight"]), float) }} - - name: datetime_operations_work - assert: ${{ len(datetime.datetime.now().strftime('%Y-%m-%d')) == 10 }} - - name: string_operations_work - assert: ${{ len(", ".join([t["type"]["name"] for t in response.json()["types"]])) > 0 }} - - name: regex_works_on_pokemon_data - assert: ${{ re.match(r"^[a-z]+$", response.json()["name"]) is not None }} - - name: uuid_format_valid - assert: ${{ len(str(uuid.uuid4())[:8]) == 8 }} - - - name: unicode_and_complex_operations_test - method: get - vars: - unicode_operations: - # Test unicode with Pokemon names (some have special chars in other languages) - name_reversed: ${{ response.json()["name"][::-1] }} - name_title: ${{ response.json()["name"].title() }} - name_length: ${{ len(response.json()["name"]) }} - complex_calculations: - # Complex mathematical operations with Pokemon stats - bmi_like_calculation: ${{ response.json()["weight"] / (response.json()["height"] ** 2) if response.json()["height"] > 0 else 0 }} - stat_total: ${{ sum([stat["base_stat"] for stat in response.json()["stats"]]) }} - avg_stat: ${{ sum([stat["base_stat"] for stat in response.json()["stats"]]) / len(response.json()["stats"]) }} - max_stat: ${{ max([stat["base_stat"] for stat in response.json()["stats"]]) }} - min_stat: ${{ min([stat["base_stat"] for stat in response.json()["stats"]]) }} - list_comprehensions: - stat_names: ${{ [stat["stat"]["name"] for stat in response.json()["stats"]] }} - high_stats: ${{ [stat["base_stat"] for stat in response.json()["stats"] if stat["base_stat"] > 50] }} - ability_names: ${{ [ability["ability"]["name"] for ability in response.json()["abilities"]] }} - isolation_test_data: - test_value: ${{ 999 }} - test_string: ${{ "isolation_test" }} - tests: - - name: status_code_is_200 - assert: ${{ response.status_code == 200 }} - - name: unicode_reverse_works - assert: ${{ response.json()["name"][::-1] == "uhcakip" }} - - name: complex_math_works - assert: ${{ isinstance(sum([stat["base_stat"] for stat in response.json()["stats"]]), int) }} - - name: list_comprehensions_work - assert: ${{ len([stat["stat"]["name"] for stat in response.json()["stats"]]) == 6 }} - - name: min_max_functions_work - assert: ${{ max([stat["base_stat"] for stat in response.json()["stats"]]) >= min([stat["base_stat"] for stat in response.json()["stats"]]) }} - - - name: security_documentation_with_pokemon_context - method: get - vars: - security_documentation: - test_category: "pokemon_api_security_validation" - safe_operations_verified: "All Pokemon data processing uses only safe RestrictedPython operations" - # Document what should be blocked (safely in comments) - blocked_operations_note: "File access, system calls, dangerous imports are prevented" - safe_pokemon_operations: - # These operations on Pokemon data should always work safely - pokemon_name_safe: ${{ response.json()["name"].upper() }} - pokemon_id_safe: ${{ response.json()["id"] * 10 }} - pokemon_abilities_safe: ${{ len(response.json()["abilities"]) }} - pokemon_types_safe: ${{ [t["type"]["name"] for t in response.json()["types"]] }} - # Mathematical analysis of Pokemon stats - all safe - total_stats_safe: ${{ sum([s["base_stat"] for s in response.json()["stats"]]) }} - stat_variance_safe: ${{ max([s["base_stat"] for s in response.json()["stats"]]) - min([s["base_stat"] for s in response.json()["stats"]]) }} - tests: - - name: status_code_is_200 - assert: ${{ response.status_code == 200 }} - - name: safe_string_ops_work - assert: ${{ response.json()["name"].upper() == "PIKACHU" }} - - name: safe_math_ops_work - assert: ${{ response.json()["id"] * 10 == 250 }} - - name: safe_list_ops_work - assert: ${{ len(response.json()["abilities"]) > 0 }} - - name: safe_complex_calculations_work - assert: ${{ sum([s["base_stat"] for s in response.json()["stats"]]) > 100 }} diff --git a/pokeapi/tests/restricted_python_validation.yaml b/pokeapi/tests/restricted_python_validation.yaml deleted file mode 100644 index 36fef51..0000000 --- a/pokeapi/tests/restricted_python_validation.yaml +++ /dev/null @@ -1,2 +0,0 @@ -name: restricted_python_safe_expressions_work -assert: ${{ datetime.datetime.now().year > 2020 and math.pi > 3.14 and len("test") == 4 }} \ No newline at end of file