diff --git a/pipeline/fiftyone_pipeline_cloudrequestengine/src/fiftyone_pipeline_cloudrequestengine/constants.py b/pipeline/fiftyone_pipeline_cloudrequestengine/src/fiftyone_pipeline_cloudrequestengine/constants.py index 8014286d..239e8dad 100644 --- a/pipeline/fiftyone_pipeline_cloudrequestengine/src/fiftyone_pipeline_cloudrequestengine/constants.py +++ b/pipeline/fiftyone_pipeline_cloudrequestengine/src/fiftyone_pipeline_cloudrequestengine/constants.py @@ -71,13 +71,16 @@ class Constants: LICENSE_PARAMETER = "license" VALUES_PARAMETER = "values" - # The cloud service advertises these three among its accepted evidence - # keys, so evidence such as "query.license" would otherwise go into the - # request body beside the engine's own credentials, with no way to say + # The service reads its credentials and the list of requested properties + # from these names, and also reads "licence" as another spelling of + # "license", so evidence such as "query.license" would otherwise go into + # the request body beside the engine's own values, with no way to say # which one the service applied. Evidence whose key strips to one of - # them is left out of every request. + # them, in any letter case, is left out of every request. + LICENCE_SPELLING = "licence" RESERVED_EVIDENCE_SUFFIXES = ( - RESOURCE_PARAMETER, LICENSE_PARAMETER, VALUES_PARAMETER) + RESOURCE_PARAMETER, LICENSE_PARAMETER, LICENCE_SPELLING, + VALUES_PARAMETER) # The path, below the base URL, of the data endpoint that takes no # resource key in its route, used when the engine authenticates on a diff --git a/pipeline/fiftyone_pipeline_cloudrequestengine/tests/test_reserved_evidence.py b/pipeline/fiftyone_pipeline_cloudrequestengine/tests/test_reserved_evidence.py new file mode 100644 index 00000000..ded452a0 --- /dev/null +++ b/pipeline/fiftyone_pipeline_cloudrequestengine/tests/test_reserved_evidence.py @@ -0,0 +1,49 @@ + +""" +Evidence whose key strips to values, resource, license or licence, in any +letter case, is left out of the request, as the Cloud Request Engine +specification says. +""" + +import warnings + +from fiftyone_pipeline_cloudrequestengine.cloudrequestengine import \ + CloudRequestEngine +from fiftyone_pipeline_core.pipelinebuilder import PipelineBuilder + +from .classes.cloudrequestengine_testbase import CloudRequestEngineTestsBase + + +class TestReservedEvidence(CloudRequestEngineTestsBase): + + def content_for(self, evidence): + engine = CloudRequestEngine({ + "resource_key": "resource_key", "http_client": self.mock_http()}) + pipeline = PipelineBuilder({ + "add_javascript_builder": False, + "use_setheader_properties": False}).add(engine).build() + self.addCleanup(pipeline.close) + data = pipeline.create_flowdata() + for key, value in evidence.items(): + data.evidence.add(key, value) + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter("always") + content = engine.get_content(data) + return content, caught + + def test_each_reserved_name_is_left_out_in_any_letter_case(self): + for name in ("values", "Values", "resource", "RESOURCE", "license", + "License", "licence", "Licence", "LICENCE"): + for prefix in ("query.", "header.", "cookie."): + content, caught = self.content_for( + {prefix + name: "secret", "header.user-agent": "iPhone"}) + self.assertEqual( + {"user-agent": "iPhone"}, content, prefix + name) + self.assertEqual(1, len(caught), prefix + name) + self.assertNotIn("secret", str(caught[0].message)) + + def test_other_evidence_is_kept(self): + content, caught = self.content_for( + {"query.sequence": 1, "header.user-agent": "iPhone"}) + self.assertEqual({"sequence": 1, "user-agent": "iPhone"}, content) + self.assertEqual([], caught)