Bug 1643084 [wpt PR 23954] - [COOP access reporting] Preliminary WPT tests., a=testonly
authorarthursonzogni <arthursonzogni@chromium.org>
Wed, 10 Jun 2020 11:27:32 +0000
changeset 535332 0e8d48cd6e889226979f661c97bdccf05b90d3d6
parent 535331 ce1211465f3b52bd6103a241804045459a9158ad
child 535333 08093a76270156ac164fac2ee6087cde2edd2745
push id37501
push usernbeleuzu@mozilla.com
push dateSat, 13 Jun 2020 03:21:52 +0000
treeherdermozilla-central@80b6f21783a3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1643084, 23954, 922191, 2228884, 775020
milestone79.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1643084 [wpt PR 23954] - [COOP access reporting] Preliminary WPT tests., a=testonly Automatic update from web-platform-tests [COOP access reporting] Preliminary WPT tests. Add some basic WPT tests about the COOP access reporting feature. No web browsers actually implement this. As a result, chrome do not pass them yet. The tests aren't complete yet, they will evolve along the specification and the implementations. Bug: 922191 Change-Id: Ie4675e5fb5ec0f839ca1527c15fafbb456925a0d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2228884 Reviewed-by: Pâris Meuleman <pmeuleman@chromium.org> Commit-Queue: Arthur Sonzogni <arthursonzogni@chromium.org> Cr-Commit-Position: refs/heads/master@{#775020} -- wpt-commits: 093d6292689f36736e7ac0a197d07b995c65c94e wpt-pr: 23954
testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/META.yml
testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/openee-accessed_openee-coop-ro.https.html
testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/openee-accessed_openee-coop.https.html
testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/opener-accessed_openee-coop-ro.https.html
testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/opener-accessed_openee-coop.https.html
testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/resources/dispatcher.js
testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/resources/dispatcher.py
testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/resources/executor.html
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/META.yml
@@ -0,0 +1,6 @@
+suggested_reviewers:
+  - ArthurSonzogni
+  - ParisMeuleman
+  - camillelamy
+  - hemeryar
+  - mikewest
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/openee-accessed_openee-coop-ro.https.html
@@ -0,0 +1,84 @@
+<title>
+  COOP reports are sent when the openee used COOP-RO+COEP and then its opener
+  tries to access it.
+</title>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src="/common/utils.js"></script>
+<script src="./resources/dispatcher.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy/access-reporting";
+const executor_path = directory + "/resources/executor.html?pipe=";
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+const coep_header = '|header(Cross-Origin-Embedder-Policy,require-corp)';
+
+let operation = [
+//[test name           , operation                   ] ,
+  ["Call blur"         , w => w.blur()               ] ,
+  ["Call foo"          , w => w.foo()                ] ,
+  ["Call location"     , w => w.location()           ] ,
+  ["Call opener"       , w => w.opener()             ] ,
+  ["Call postMessage"  , w => w.postMessage()        ] ,
+  ["Call window"       , w => w.window()             ] ,
+  ["Read blur"         , w => w.blur                 ] ,
+  ["Read foo"          , w => w.foo                  ] ,
+  ["Read location"     , w => w.location             ] ,
+  ["Read opener"       , w => w.opener               ] ,
+  ["Read postMessage"  , w => w.postMessage          ] ,
+  ["Read window"       , w => w.window               ] ,
+  ["Write blur"        , w => w.blur = "test"        ] ,
+  ["Write foo"         , w => w.foo = "test"         ] ,
+  ["Write location"    , w => w.location = "test"    ] ,
+  ["Write opener"      , w => w.opener = "test"      ] ,
+  ["Write postMessage" , w => w.postMessage = "test" ] ,
+  ["Write window"      , w => w.window = "test"      ] ,
+];
+
+operation.forEach(([test, op]) => {
+  promise_test(async t => {
+    const report_token = token();
+    const executor_token = token();
+    const callback_token = token();
+
+    const reportTo = reportToHeaders(report_token);
+    const openee_url = cross_origin + executor_path +
+      reportTo.header + reportTo.coopReportOnlySameOrigin + coep_header +
+      `&uuid=${executor_token}`;
+    const openee = window.open(openee_url);
+    t.add_cleanup(() => send(executor_token, "window.close()"))
+
+    // 1. Make sure the new document to be loaded.
+    send(executor_token, `
+      send("${callback_token}", "Ready");
+    `);
+    let reply = await receive(callback_token);
+    assert_equals(reply, "Ready");
+
+    // 2. Skip the first report about the opener breakage.
+    let report_1 = await receive(report_token);
+    assert_not_equals(report_1, "timeout");
+    report_1 = JSON.parse(report_1);
+    assert_equals(report_1.length, 1);
+    assert_equals(report_1[0].type, "coop");
+    assert_equals(report_1[0].body["violation-type"], "navigation-to-document");
+    assert_equals(report_1[0].body["disposition"], "reporting");
+
+    // 3. Try to access the openee. A report is sent, because of COOP-RO+COEP.
+    try {op(openee)} catch(e) {}
+
+    // 4. A COOP access reports must be sent as a result of (3).
+    let report_2 = await receive(report_token);
+    assert_not_equals(report_1, "timeout");
+    report_2 = JSON.parse(report_2);
+    assert_equals(report_2.length, 1);
+    assert_equals(report_2[0].type, "coop");
+    assert_equals(report_2[0].body["violation-type"], "access");
+    assert_equals(report_2[0].body["disposition"], "reporting");
+    assert_equals(report_2[0].body["effective-policy"], "same-origin-plus-coep");
+  }, `${test}`);
+});
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/openee-accessed_openee-coop.https.html
@@ -0,0 +1,84 @@
+<title>
+  COOP reports are sent when the openee used COOP+COEP and then its opener
+  tries to access it.
+</title>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src="/common/utils.js"></script>
+<script src="./resources/dispatcher.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy/access-reporting";
+const executor_path = directory + "/resources/executor.html?pipe=";
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+const coep_header = '|header(Cross-Origin-Embedder-Policy,require-corp)';
+
+let operation = [
+//[test name           , operation                   ] ,
+  ["Call blur"         , w => w.blur()               ] ,
+  ["Call foo"          , w => w.foo()                ] ,
+  ["Call location"     , w => w.location()           ] ,
+  ["Call opener"       , w => w.opener()             ] ,
+  ["Call postMessage"  , w => w.postMessage()        ] ,
+  ["Call window"       , w => w.window()             ] ,
+  ["Read blur"         , w => w.blur                 ] ,
+  ["Read foo"          , w => w.foo                  ] ,
+  ["Read location"     , w => w.location             ] ,
+  ["Read opener"       , w => w.opener               ] ,
+  ["Read postMessage"  , w => w.postMessage          ] ,
+  ["Read window"       , w => w.window               ] ,
+  ["Write blur"        , w => w.blur = "test"        ] ,
+  ["Write foo"         , w => w.foo = "test"         ] ,
+  ["Write location"    , w => w.location = "test"    ] ,
+  ["Write opener"      , w => w.opener = "test"      ] ,
+  ["Write postMessage" , w => w.postMessage = "test" ] ,
+  ["Write window"      , w => w.window = "test"      ] ,
+];
+
+operation.forEach(([test, op]) => {
+  promise_test(async t => {
+    const report_token = token();
+    const executor_token = token();
+    const callback_token = token();
+
+    const reportTo = reportToHeaders(report_token);
+    const openee_url = cross_origin + executor_path +
+      reportTo.header + reportTo.coopSameOrigin + coep_header +
+      `&uuid=${executor_token}`;
+    const openee = window.open(openee_url);
+    t.add_cleanup(() => send(executor_token, "window.close()"))
+
+    // 1. Make sure the new document to be loaded.
+    send(executor_token, `
+      send("${callback_token}", "Ready");
+    `);
+    let reply = await receive(callback_token);
+    assert_equals(reply, "Ready");
+
+    // 2. Skip the first report about the opener breakage.
+    let report_1 = await receive(report_token);
+    assert_not_equals(report_1, "timeout");
+    report_1 = JSON.parse(report_1);
+    assert_equals(report_1.length, 1);
+    assert_equals(report_1[0].type, "coop");
+    assert_equals(report_1[0].body["violation-type"], "navigation-to-document");
+    assert_equals(report_1[0].body["disposition"], "enforce");
+
+    // 3. Try to access the openee. This shouldn't work because of COOP+COEP.
+    try {op(openee)} catch(e) {}
+
+    // 4. A COOP access reports must be sent as a result of (3).
+    let report_2 = await receive(report_token);
+    assert_not_equals(report_2, "timeout");
+    report_2 = JSON.parse(report_2);
+    assert_equals(report_2.length, 1);
+    assert_equals(report_2[0].type, "coop");
+    assert_equals(report_2[0].body["violation-type"], "access");
+    assert_equals(report_2[0].body["disposition"], "enforce");
+    assert_equals(report_2[0].body["effective-policy"], "same-origin-plus-coep");
+  }, `${test}`);
+});
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/opener-accessed_openee-coop-ro.https.html
@@ -0,0 +1,83 @@
+<title>
+  COOP reports are sent when the openee used COOP-RO+COEP and then tries to
+  access its opener.
+</title>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src="/common/utils.js"></script>
+<script src="./resources/dispatcher.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy/access-reporting";
+const executor_path = directory + "/resources/executor.html?pipe=";
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+const coep_header = '|header(Cross-Origin-Embedder-Policy,require-corp)';
+
+let operation = [
+//[test name           , operation                     ]   ,
+  ["Call blur"         , "opener.blur()"               ] ,
+  ["Call foo"          , "opener.foo()"                ] ,
+  ["Call location"     , "opener.location()"           ] ,
+  ["Call opener"       , "opener.opener()"             ] ,
+  ["Call postMessage"  , "opener.postMessage()"        ] ,
+  ["Call window"       , "opener.window()"             ] ,
+  ["Read blur"         , "opener.blur"                 ] ,
+  ["Read foo"          , "opener.foo"                  ] ,
+  ["Read location"     , "opener.location"             ] ,
+  ["Read opener"       , "opener.opener"               ] ,
+  ["Read postMessage"  , "opener.postMessage"          ] ,
+  ["Read window"       , "opener.window"               ] ,
+  ["Write blur"        , "opener.blur = 'test'"        ]  ,
+  ["Write foo"         , "opener.foo = 'test'"         ]  ,
+  ["Write location"    , "opener.location = 'test'"    ]  ,
+  ["Write opener"      , "opener.opener = 'test'"      ]  ,
+  ["Write postMessage" , "opener.postMessage = 'test'" ]  ,
+  ["Write window"      , "opener.window = 'test'"      ]  ,
+];
+
+operation.forEach(([test, op]) => {
+  promise_test(async t => {
+    const report_token = token();
+    const executor_token = token();
+    const callback_token = token();
+
+    const reportTo = reportToHeaders(report_token);
+    const openee_url = cross_origin + executor_path +
+      reportTo.header + reportTo.coopReportOnlySameOrigin + coep_header +
+      `&uuid=${executor_token}`;
+    const openee = window.open(openee_url);
+    t.add_cleanup(() => send(executor_token, "window.close()"))
+
+    // 1. Skip the first report about the opener breakage.
+    let report_1 = await receive(report_token);
+    assert_not_equals(report_1, "timeout");
+    report_1 = JSON.parse(report_1);
+    assert_equals(report_1.length, 1);
+    assert_equals(report_1[0].type, "coop");
+    assert_equals(report_1[0].body["violation-type"], "navigation-to-document");
+    assert_equals(report_1[0].body["disposition"], "reporting");
+
+    // 3. Try to access the opener. A report is sent, because of COOP-RO+COEP.
+    send(executor_token, `
+      try {${op}} catch(e) {}
+      send("${callback_token}", "Done");
+    `);
+    let reply = await receive(callback_token);
+    assert_equals(reply, "Done");
+
+    // 4. A COOP access reports must be sent as a result of (3).
+    let report_2 = await receive(report_token);
+    assert_not_equals(report_2, "timeout");
+    report_2 = JSON.parse(report_2);
+
+    assert_equals(report_2.length, 1);
+    assert_equals(report_2[0].type, "coop");
+    assert_equals(report_2[0].body["violation-type"], "access");
+    assert_equals(report_2[0].body["disposition"], "reporting");
+    assert_equals(report_2[0].body["effective-policy"], "same-origin-plus-coep");
+  }, `${test}`);
+});
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/opener-accessed_openee-coop.https.html
@@ -0,0 +1,83 @@
+<title>
+  COOP reports are sent when the openee used COOP+COEP and then tries to
+  access its opener.
+</title>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src="/common/utils.js"></script>
+<script src="./resources/dispatcher.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy/access-reporting";
+const executor_path = directory + "/resources/executor.html?pipe=";
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+const coep_header = '|header(Cross-Origin-Embedder-Policy,require-corp)';
+
+let operation = [
+//[test name           , operation                     ]   ,
+  ["Call blur"         , "opener.blur()"               ] ,
+  ["Call foo"          , "opener.foo()"                ] ,
+  ["Call location"     , "opener.location()"           ] ,
+  ["Call opener"       , "opener.opener()"             ] ,
+  ["Call postMessage"  , "opener.postMessage()"        ] ,
+  ["Call window"       , "opener.window()"             ] ,
+  ["Read blur"         , "opener.blur"                 ] ,
+  ["Read foo"          , "opener.foo"                  ] ,
+  ["Read location"     , "opener.location"             ] ,
+  ["Read opener"       , "opener.opener"               ] ,
+  ["Read postMessage"  , "opener.postMessage"          ] ,
+  ["Read window"       , "opener.window"               ] ,
+  ["Write blur"        , "opener.blur = 'test'"        ]  ,
+  ["Write foo"         , "opener.foo = 'test'"         ]  ,
+  ["Write location"    , "opener.location = 'test'"    ]  ,
+  ["Write opener"      , "opener.opener = 'test'"      ]  ,
+  ["Write postMessage" , "opener.postMessage = 'test'" ]  ,
+  ["Write window"      , "opener.window = 'test'"      ]  ,
+];
+
+operation.forEach(([test, op]) => {
+  promise_test(async t => {
+    const report_token = token();
+    const executor_token = token();
+    const callback_token = token();
+
+    const reportTo = reportToHeaders(report_token);
+    const openee_url = cross_origin + executor_path +
+      reportTo.header + reportTo.coopSameOrigin + coep_header +
+      `&uuid=${executor_token}`;
+    const openee = window.open(openee_url);
+    t.add_cleanup(() => send(executor_token, "window.close()"));
+
+    // 1. Skip the first report about the opener breakage.
+    let report_1 = await receive(report_token);
+    assert_not_equals(report_1, "timeout");
+    report_1 = JSON.parse(report_1);
+    assert_equals(report_1.length, 1);
+    assert_equals(report_1[0].type, "coop");
+    assert_equals(report_1[0].body["violation-type"], "navigation-to-document");
+    assert_equals(report_1[0].body["disposition"], "enforce");
+
+    // 3. Try to access the opener. A report is sent, because of COOP-RO+COEP.
+    send(executor_token, `
+      try {${op}} catch(e) {}
+      send("${callback_token}", "Done");
+    `);
+    let reply = await receive(callback_token);
+    assert_equals(reply, "Done");
+
+    // 4. A COOP access reports must be sent as a result of (3).
+    let report_2 = await receive(report_token);
+    assert_not_equals(report_2, "timeout");
+    report_2 = JSON.parse(report_2);
+
+    assert_equals(report_2.length, 1);
+    assert_equals(report_2[0].type, "coop");
+    assert_equals(report_2[0].body["violation-type"], "access");
+    assert_equals(report_2[0].body["disposition"], "enforce");
+    assert_equals(report_2[0].body["effective-policy"], "same-origin-plus-coep");
+  }, `${test}`);
+});
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/resources/dispatcher.js
@@ -0,0 +1,55 @@
+// Define an universal message passing API.
+//
+// In particular, this works:
+// - cross-origin and
+// - cross-browsing-context-group.
+//
+// It can also be used to receive reports.
+
+const dispatcher_path =
+    '/html/cross-origin-opener-policy/access-reporting/resources/dispatcher.py';
+const dispatcher_url = new URL(dispatcher_path, location.href).href;
+
+const send = function(uuid, message) {
+  fetch(dispatcher_url + `?uuid=${uuid}`, {
+    method: 'POST',
+    body: message
+  });
+}
+
+const receive = async function(uuid) {
+  const timeout = 3000;
+  const retry_delay = 100;
+  for(let i = 0; i * retry_delay < timeout; ++i) {
+    let response = await fetch(dispatcher_url + `?uuid=${uuid}`);
+    let data = await response.text();
+    if (data != 'not ready')
+      return data;
+    await new Promise(r => step_timeout(r, retry_delay));
+  }
+  return "timeout";
+}
+
+// Build a set of headers to tests the reporting API. This defines a set of
+// matching 'Report-To', 'Cross-Origin-Opener-Policy' and
+// 'Cross-Origin-Opener-Policy-Report-Only' headers.
+const reportToHeaders = function(uuid) {
+  const report_endpoint_url = dispatcher_path + `?uuid=${uuid}`;
+  let reportToJSON = {
+    'group': `${uuid}`,
+    'max_age': 3600,
+    'endpoints': [
+      {'url': report_endpoint_url.toString()},
+    ]
+  };
+  reportToJSON = JSON.stringify(reportToJSON)
+                     .replace(/,/g, '\\,')
+                     .replace(/\(/g, '\\\(')
+                     .replace(/\)/g, '\\\)=');
+
+  return {
+    header: `|header(report-to,${reportToJSON})`,
+    coopSameOrigin: `|header(Cross-Origin-Opener-Policy, same-origin%3Breport-to="${uuid}")`,
+    coopReportOnlySameOrigin: `|header(Cross-Origin-Opener-Policy-Report-Only, same-origin%3Breport-to="${uuid}")`,
+  };
+};
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/resources/dispatcher.py
@@ -0,0 +1,22 @@
+# A server used to store and retrieve arbitrary data.
+# This is used by: ./dispatcher.js
+import json
+
+def main(request, response):
+    response.headers.set('Access-Control-Allow-Origin', '*')
+    response.headers.set('Access-Control-Allow-Methods', 'OPTIONS, GET, POST')
+    response.headers.set('Access-Control-Allow-Headers', 'Content-Type')
+    response.headers.set('Cache-Control', 'no-cache, no-store, must-revalidate');
+    if request.method == 'OPTIONS': # CORS preflight
+        return ''
+
+    uuid = request.GET['uuid']
+
+    if request.method == 'POST':
+        return request.server.stash.put(uuid, request.body)
+    else:
+        body = request.server.stash.take(uuid)
+        if body is None:
+            return 'not ready'
+        else:
+            return body
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/access-reporting/resources/executor.html
@@ -0,0 +1,12 @@
+<script src=/resources/testharness.js></script>
+<script src="./dispatcher.js"></script>
+<script>
+  const params = new URLSearchParams(window.location.search);
+  const uuid = params.get('uuid');
+
+  let executeOrders = async function() {
+    while(true)
+      eval(await receive(uuid));
+  };
+  executeOrders();
+</script>