-
Notifications
You must be signed in to change notification settings - Fork 384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Experimental: Add sandboxing levels #6546
Conversation
(Marking as ready for review to trigger builds.) |
Codecov Report
@@ Coverage Diff @@
## develop #6546 +/- ##
=============================================
+ Coverage 76.63% 77.13% +0.50%
- Complexity 6318 6420 +102
=============================================
Files 248 250 +2
Lines 19812 20121 +309
=============================================
+ Hits 15182 15521 +339
+ Misses 4630 4600 -30
Flags with carried forward coverage won't be shown. Click here to find out more.
|
Plugin builds for faaf295 are ready 🛎️!
|
Rebasing onto |
f0c1ec0
to
e3bf4e3
Compare
3e52e64
to
d2dbc7c
Compare
d2dbc7c
to
632760c
Compare
…r doc, tag, and attrs
…ds in img sanitizer
Finally the coverage is ✅ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few comments to address, but functionality wise this looks ready and can be merged ✅.
* @param int|null $effective_sandboxing_level Effective sandboxing level. | ||
*/ | ||
public function finalize_document( Document $dom, $effective_sandboxing_level ) { | ||
$actual_sandboxing_level = AMP_Options_Manager::get_option( self::OPTION_LEVEL ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe bail if not in Standard mode? Or rather amp_is_canonical()
should be added as a condition to Sandboxing::is_needed()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's a good call. I'll add that to the future todos.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in #6715.
* | ||
* @var int[] | ||
*/ | ||
const LEVELS = [ 1, 2, 3 ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on each sandbox level being it's own constant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Problem: that would eliminate the the relevance of the comment on this line:
Line 155 in faaf295
if ( $sandboxing_level < 3 ) { // <3 === ❤️ |
Joking aside, that makes sense. I'll add it to the future todos.
Co-authored-by: Pierre Gordon <[email protected]>
…oxing-levels * 'develop' of github.com:ampproject/amp-wp: (41 commits) Bump eslint-plugin-jsdoc from 36.1.0 to 36.1.1 Bump lint-staged from 11.1.2 to 11.2.3 Use assertContains for array Use DependencyInjectedTestCase Add test assertions Update comments Update unit test cases Remove unwanted style, Fix notice style in mobile Revert some changes and update unit test case Bump @babel/core from 7.15.5 to 7.15.8 Fix grammar in comment Bump css-minimizer-webpack-plugin from 3.0.2 to 3.1.1 Apply suggestions from code review Remove changes from .github Bump postcss from 8.3.8 to 8.3.9 Remove template change notice from other pages Remove template change notice from other pages Add unit test case Add data removal notice to plugin description Update unit test case ...
JS unit tests are failing with:
Is it down? They say all systems operational. |
Seems to be an issue with the uploader Codecov uses, but they now pass after restarting the jobs for some reason. |
Aaand I don't know why it's not auto-merging, maybe GitHub is busy... |
I think it's because one of the reviewers hasn't approved, but I'm merging 😄 |
Summary
Fixes #6443.
This PR introduces a new Sandboxing Level section which is available in the Standard template mode drawer:
Given the example of Ninja Forms, which is a forms plugin that requires scripts to render a form, compare the following two sandboxing levels:
Notice how where previously the form would have failed to render entirely on an validAMP page, whereas now with the Loose Sandboxing level the custom scripts required by Ninja Forms are kept by default, allowing the form to work normally:
ninja-forms-functional.mov
Loose Sandboxing
When there are custom scripts on the page in the loose sandboxing level:
link
elements,style
elements, andstyle
attributes as-is (including!important
qualifiers). Since tree-shaking cannot be safely performed, it is likely preferable to not have a massive inlinestyle
of all concatenated CSS.CSS tree shaking is disabled and inlinestyle
attributes and!important
qualifiers are not transformed.video
is used (with dimensions added).img
is used (with dimensions added).audio
is used.iframe
is used.amp-form
(including comments form).comment-reply
script is used for comment threading instead of the amp-bind implementation.noscript
elements are not unwrapped.As seen in the Ninja Forms example above, this allows non-AMP scripting to work on a page that still uses the AMP plugin's sanitizers and also goes through the AMP Optimizer.
👉 The fundamental goals of the loose sandboxing level is that it will allow us to:
Moderate Sandboxing
When a page doesn't have custom scripts on it (or rather the custom scripts have been marked as being PX-verified, see below), then a more restrictive set of sanitization constraints are applied on the page:
style
attributes and!important
qualifiers are not transformed.comment-reply
script is used for comment threading instead of the amp-bind implementation (which is not feature-complete and thecomment-reply
script does not negatively impact PX).noscript
elements are unwrapped.The intention here is that the PX characteristics for moderate sandboxing should be more or less the same as for strict sandboxing. The main difference in terms of PX is that the moderate sandboxing level is not eligible for AMP Cache. This level allows for external POST forms to not break on AMP pages, as is a big pain point currently on valid AMP pages (ampproject/amphtml#27638), so much so that we have a documentation page all about it. For example, the Revue Newsletter Signup block in Jetpack shows an error message when on a valid AMP page (strict sandboxing), whereas in moderate sandboxing the form submission opens a new window as expected:
Strict Sandboxing
The strict sandboxing level is the same as the current behavior today, where the AMP plugin removes any AMP-invalid markup by default to generate a valid AMP page.
Dynamic Sandboxing Levels
Even when a user selects the loose sandboxing level, if it turns out that on a given page there are no custom scripts and no POST forms except for the comments form, the page will automatically be upgraded to be valid AMP since there is nothing blocking it from doing so. In the same way, if on another page there are no custom scripts and yet there is an external POST form for newsletter signups, the page will be served at the moderate sandboxing level. In this way, even when the user has selected the loose sandboxing level, the majority of pages on a site could still be valid AMP. For example, all single blog posts could be valid AMP, while the shopping cart page may be at the loose level and the newsletter sign up page may be at the moderate level.
In this way, the chosen sandboxing level can be thought of as the default minimum sandboxing level of PX conformance. The actual sandboxing level applied is the effective level.
The dynamic levels work both ways as well. As noted above, If you are in the moderate sandboxing level, any invalid AMP markup is removed by default and validation errors will be raised. If you mark any of those validation errors as kept, then the page's level will go down from moderate to loose.
The effective level is currently displayed with the AMP admin bar menu item with the 1️⃣, 2️⃣, or 3️⃣ emoji.
New attributes to demarcate non-AMP markup
One thing that has become clear is that the
data-ampdevmode
attribute is highly overloaded. It can mean three things:html
element).This overloading causes some ambiguity for what is intended. For example, currently the form sanitizer skips processing a form that has the dev mode attribute. When the new script sanitizer runs first and an
onsubmit
attribute is kept, this currently results indata-ampdevmode
attribute added. When the form sanitizer then runs later, it skips processing of the form altogether even though the only intention was to exempt theonsubmit
attribute from validation. The result is some validation errors not being raised when they should be, and thus some unexpected behaviors occur.The ambiguity of dev mode also extends to what the intention is for why a given bit of markup is being kept on the page. Is it being kept just for "dev mode" in that the user is a developer or admin user who is administering the page? Or is dev mode being used as a hack to prevent the AMP plugin from stripping out the markup from the page? On another level, is the invalid AMP markup being exempted with dev mode because AMP forbids it due to it negatively impacting the page, or is it being exempted because it actually doesn't hurt PX but it just isn't allowed in the AMP format (yet)?
For these reasons, this PR introduces 2 sets of attributes:
data-amp-unvalidated-tag
: Prevents a tag as a whole from being removed.data-amp-unvalidated-attrs
: Prevents specific attributes from being removed. The value is a token list of attribute names.data-px-verified-tag
: Prevents a tag as a whole from being removed.data-px-verified-attrs
: Prevents specific attributes from being removed. The value is a token list of attribute names.The latter set of attributes are particularly useful on custom scripts which are interacting with the APIs for Bento components.
These attributes will suppress validation errors from being reported in the validation screens. And when invalid markup causing a validation error is marked as “kept”, either the
data-amp-unvalidated-tag
ordata-amp-unvalidated-attrs
attribute will be added during post-processing. For example, if there was anonload
attribute on thebody
and you indicate you want the markup kept, the resulting page would contain:Sanitizer ordering
Prior to this PR, the only requirement was for the following sanitizers to run at the end:
AMP_Layout_Sanitizer
AMP_Style_Sanitizer
AMP_Meta_Sanitizer
AMP_Tag_And_Attribute_Sanitizer
When a user filtered
amp_content_sanitizers
to add additional sanitizers, they could appear in any order among the previous sanitizers. This could have resulted in problems, specifically for theAMP_Script_Sanitizer
. In particular, sanitizers likeAMP_Embed_Sanitizer
andAMP_O2_Player_Sanitizer
are removingscript
elements from the page (e.g. Twitter'swidgets.js
). IfAMP_Script_Sanitizer
were to run first, then it would find these custom scripts too early and could result in a page being downgraded to L1, even though theAMP_Embed_Sanitizer
would be converting the tweets toamp-twitter
already. Therefore, this PR ensures that all of the plugin's sanitizers run in the order they are defined prior to filtering with the exception of the the embed sanitizers (AMP_Embed_Sanitizer
,AMP_O2_Player_Sanitizer
,AMP_Playbuzz_Sanitizer
) and any other user-supplied sanitizers which will get run before all the others. This will ensure consistency in the sanitized output of the page as well when plugins are filteringamp_content_sanitizers
(either by appending or prepending sanitizers to the array).The sanitizer ordering is particularly important now because when a sanitizer encounters markup that impacts the sandboxing level, it may need to change the arguments of sanitizers which haven't run yet.
The final sanitizers now are forced to run in the following order:
AMP_Core_Theme_Sanitizer
AMP_Script_Sanitizer
AMP_Form_Sanitizer
AMP_Comments_Sanitizer
AMP_Srcset_Sanitizer
AMP_Img_Sanitizer
AMP_Video_Sanitizer
AMP_Audio_Sanitizer
AMP_Object_Sanitizer
AMP_Iframe_Sanitizer
AMP_Gallery_Block_Sanitizer
AMP_Block_Sanitizer
AMP_Accessibility_Sanitizer
AMP_Layout_Sanitizer
AMP_Style_Sanitizer
AMP_Meta_Sanitizer
AMP_Tag_And_Attribute_Sanitizer
Dynamic Bento Experiment Opt-in
Previously with #6353, when
amp_bento_enabled
was filtered on, the JS code to enable thebento
AMP experiment was always added. This is no longer the case. The experimentscript
will only be added to the page if there's actually a Bento component on it. When a Bento version is available for a used component on the page, the Bento version will be used when eitheramp_bento_enabled
is filtered to betrue
or the page is being served in the loose or moderate sandboxing levels.Revamped Comments Handling
The comments sanitizer has been completely rewritten in how it implements amp-bind comment threading. The code was quite old and it turned out there was a lot that wasn't needed anymore. In particular, a lot of code seemed to be a workaround for the
clear
action not working as expected on forms, however now it is working as expect. More to the point of sandboxing levels, this PR discontinues splitting up the responsibilities for making comments AMP-compatible between theAMP_Theme_Support
class (during template rendering) and theAMP_Comments_Sanitizer
(during post-processing). Now everything is done during post-process in in theAMP_Comments_Sanitizer
and this allows it to dynamically switch between WP-nativecomment-reply
and the amp-bind implementation based on what sandboxing level the page is at (which can only be determined at post-processing time).Moving the logi to the post-processing phase also allowed for a full fix of #2489, going beyond the short-term fix introduced in #4388.
Upon clicking a link to reply to a comment by “admin”:
Commits first added in sub-PR #6546.
Also fixes #6231.
Fixes #4624.
Testing
Since it is experimental, you have to opt-in via the following plugin code (or use example plugin):
Choose the loose sandboxing level. The chosen sandboxing level is indicated in the
meta
generator tag, followed by the effective sandboxing level for the given page (here chosen is 1 and effective is 3):I've put together three example posts that demonstrate the sandboxing levels. For each post, obtain the post content from the Gist linked to in the heading, and add a comment to each of the posts. When in the loose sandboxing level, each page should result in the aforementioned dynamic sandboxing levels where a page that has nothing blocking it from being valid AMP will automatically upgrade to strict even though the loose sandboxing level is selected.
This PR adds a UI which exposes the functionality that has been added in:
img
opt-in to prevent conversion toamp-img
/amp-anim
#6518POST
forms from being converted toamp-form
(withaction-xhr
) #6527transform_important_qualifiers
arg toAMP_Style_Sanitizer
#6589Key Todos
allow_excessive_css
arg the Style sanitizer which is automatically set when in lower sandboxing modes? We should not rely on standard mode as being the suppressor of excessive css errors.data-px-verified
.)data-px-verified
.)Future Todos
data-amp-unvalidated-*
considerdata-px-unverified-*
ordata-px-exempted-*
.Checklist