Skip to content
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

Update allowed tags/attributes from spec in amphtml 2004142326360 #4548

Merged
merged 7 commits into from
Apr 21, 2020

Conversation

westonruter
Copy link
Member

@westonruter westonruter commented Apr 8, 2020

Previously #4390.

  • Run ./bin/amphtml-update.sh (lando ssh -c 'bash ./bin/amphtml-update.sh vendor/amphtml')
  • Examine diff for changelog
  • Update spec generator as needed based on spec format changes.
  • Modify validating sanitizer based on changes to spec, if needed.
  • Add tests for key changes

Changelog

Details

(
    PREV_VERSION=2003031842100;
    THIS_VERSION=2004142326360; 
    git checkout $THIS_VERSION;
    git diff $PREV_VERSION...$THIS_VERSION -w -- $( git ls-files | grep '.protoascii' );
    git checkout - > /dev/null
)
2003031842100...2004142326360
diff --git a/extensions/amp-access/validator-amp-access.protoascii b/extensions/amp-access/validator-amp-access.protoascii
index 2226348dd..043f6202e 100644
--- a/extensions/amp-access/validator-amp-access.protoascii
+++ b/extensions/amp-access/validator-amp-access.protoascii
@@ -32,8 +32,6 @@ tags: {  # amp-access (json)
   unique: true
   mandatory_parent: "HEAD"
   requires_extension: "amp-access"
-  satisfies: "amp-access extension .json script"
-  excludes: "amp-subscriptions extension .json script"
   attrs: {
     name: "id"
     mandatory: true
diff --git a/extensions/amp-autocomplete/validator-amp-autocomplete.protoascii b/extensions/amp-autocomplete/validator-amp-autocomplete.protoascii
index 4d51a7403..0383dc2c0 100644
--- a/extensions/amp-autocomplete/validator-amp-autocomplete.protoascii
+++ b/extensions/amp-autocomplete/validator-amp-autocomplete.protoascii
@@ -24,6 +24,17 @@ tags: {  # amp-autocomplete
   }
   attr_lists: "common-extension-attrs"
 }
+tags: {  # amp-autocomplete
+  html_format: AMP4EMAIL
+  tag_name: "SCRIPT"
+  spec_name: "SCRIPT[custom-element=amp-autocomplete] (AMP4EMAIL)"
+  extension_spec: {
+    name: "amp-autocomplete"
+    # AMP4EMAIL doesn't allow version: "latest".
+    version: "0.1"
+  }
+  attr_lists: "common-extension-attrs"
+}
 tags: {  # <amp-autocomplete>
   html_format: AMP
   tag_name: "AMP-AUTOCOMPLETE"
@@ -81,6 +92,49 @@ tags: {  # <amp-autocomplete>
     supported_layouts: CONTAINER
   }
 }
+# AMP4EMAIL disallows mustache in src attribute, filter attribute.
+tags: {  # <amp-autocomplete>
+  html_format: AMP4EMAIL
+  tag_name: "AMP-AUTOCOMPLETE"
+  spec_name: "AMP-AUTOCOMPLETE (AMP4EMAIL)"
+  requires_extension: "amp-autocomplete"
+  disallowed_ancestor: "AMP-AUTOCOMPLETE"
+  disallowed_ancestor: "AMP-STATE"
+  disallowed_ancestor: "TEMPLATE"
+  attrs: { name: "highlight-user-entry" }
+  attrs: { name: "inline" }
+  attrs: { name: "items" }
+  attrs: { name: "max-entries" }
+  attrs: { name: "min-characters" }
+  attrs: {
+    name: "query"
+    trigger: {
+      also_requires_attr: "src"
+    }
+  }
+  attrs: { name: "submit-on-enter" }
+  attrs: {
+    name: "suggest-first"
+  }
+  attrs: {
+    name: "src"
+    mandatory: true
+    value_url: {
+      protocol: "https"
+      allow_relative: false
+    }
+    blacklisted_value_regex: "__amp_source_origin|"
+        "{{|}}"    # Mustache is disallowed in src.
+  }
+  attrs: {
+    name: "template"
+    value_oneof_set: TEMPLATE_IDS
+  }
+  attr_lists: "extended-amp-global"
+  amp_layout: {
+    supported_layouts: CONTAINER
+  }
+}
 tags: {  # <amp-autocomplete> > <input>
   html_format: AMP
   tag_name: "INPUT"
diff --git a/extensions/amp-list/validator-amp-list.protoascii b/extensions/amp-list/validator-amp-list.protoascii
index 0d36870e2..1d6f6c85d 100644
--- a/extensions/amp-list/validator-amp-list.protoascii
+++ b/extensions/amp-list/validator-amp-list.protoascii
@@ -98,6 +98,7 @@ tags: {  # <amp-list> with mandatory src and/or [src] attr
     mandatory_anyof: "['src','[src]','data-amp-bind-src']"
     value_url: {
       protocol: "https"
+      protocol: "amp-state"
       allow_relative: true  # Will be set to false at a future date.
     }
     blacklisted_value_regex: "__amp_source_origin"
diff --git a/extensions/amp-script/validator-amp-script.protoascii b/extensions/amp-script/validator-amp-script.protoascii
index 9725ae2e2..f78043199 100644
--- a/extensions/amp-script/validator-amp-script.protoascii
+++ b/extensions/amp-script/validator-amp-script.protoascii
@@ -192,6 +192,12 @@ tags: {  # <amp-script>
       also_requires_attr: "script"
     }
   }
+  attrs: {
+    # This attribute should always be invalid. See https://github.com/ampproject/amphtml/pull/27076
+    name: "data-ampdevmode"
+    value: "false"
+    blacklisted_value_regex: "false"
+  }
   attrs: { name: "sandbox" }
   attrs: {
     name: "script"
diff --git a/extensions/amp-story-education/validator-amp-story-education.protoascii b/extensions/amp-story-education/validator-amp-story-education.protoascii
new file mode 100644
index 000000000..810955990
--- /dev/null
+++ b/extensions/amp-story-education/validator-amp-story-education.protoascii
@@ -0,0 +1,15 @@
+#
+# Copyright 2020 The AMP HTML Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS-IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the license.
+#
diff --git a/extensions/amp-story/validator-amp-story.protoascii b/extensions/amp-story/validator-amp-story.protoascii
index 627571eb0..9b1c87daa 100644
--- a/extensions/amp-story/validator-amp-story.protoascii
+++ b/extensions/amp-story/validator-amp-story.protoascii
@@ -151,6 +151,10 @@ tags: {  # <amp-story-grid-layer>
     value: "landscape-half-left"
     value: "landscape-half-right"
   }
+  attrs: {
+    name: "aspect-ratio"
+    value_regex: "\\d+:\\d+"
+  }
   descendant_tag_list: "amp-story-grid-layer-allowed-descendants"
   reference_points: {
     tag_spec_name: "AMP-STORY-GRID-LAYER default"
@@ -380,6 +384,7 @@ tags: {  # amp-story-bookend (json)
     value_casei: "application/json"
     dispatch_key: NAME_VALUE_PARENT_DISPATCH
   }
+  attr_lists: "nonce-attr"
 }
 tags: {  # amp-story-consent (json)
   html_format: AMP
diff --git a/extensions/amp-subscriptions/validator-amp-subscriptions.protoascii b/extensions/amp-subscriptions/validator-amp-subscriptions.protoascii
index 925a7796d..67aafd966 100644
--- a/extensions/amp-subscriptions/validator-amp-subscriptions.protoascii
+++ b/extensions/amp-subscriptions/validator-amp-subscriptions.protoascii
@@ -32,8 +32,6 @@ tags: {  # amp-subscriptions (json)
   unique: true
   mandatory_parent: "HEAD"
   requires_extension: "amp-subscriptions"
-  satisfies: "amp-subscriptions extension .json script"
-  excludes: "amp-access extension .json script"
   attrs: {
     name: "id"
     mandatory: true
diff --git a/validator/validator-css.protoascii b/validator/validator-css.protoascii
new file mode 100644
index 000000000..e4777e882
--- /dev/null
+++ b/validator/validator-css.protoascii
@@ -0,0 +1,573 @@
+#
+# Copyright 2020 The AMP HTML Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS-IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the license.
+#
+
+# Defines how much css is allowed in the entire document. This is the sum of
+# `<style amp-custom>` and `style=` attribute inline CSS. If a CssLengthSpec
+# is not defined for a particular html_format, then no limit is enforced for
+# inline styles but a limit may be enforced on particular style tags. Those
+# would be defined in that tag's CdataSpec.
+css_length_spec: {
+  html_format: AMP
+  max_bytes: 75000
+  max_bytes_per_inline_style: 1000
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#maximum-size"
+}
+
+# This variant of <style amp-custom> is designed to help developers see how
+# close they are to the byte limit, even if the page is passing. By changing
+# the attribute to <style amp-custom-length-check>, this tagspec will be used
+# to match errors. It cannot pass however, as it has a cdata.max_bytes set to
+# -1. As a result, it will always fail and report the length found in the
+# tag's cdata. Deleting this tagspec will never break any valid AMP documents
+# as if it matches, the page will be invalid.
+tags: {  # <style amp-custom-length-check>, ALL FORMATS
+  html_format: AMP
+  html_format: AMP4ADS
+  html_format: AMP4EMAIL
+  html_format: ACTIONS
+  tag_name: "STYLE"
+  spec_name: "style amp-custom-length-check"
+  unique: true
+  mandatory_parent: "HEAD"
+  attrs: {
+    name: "amp-custom-length-check"
+    mandatory: true
+    value: ""
+    dispatch_key: NAME_DISPATCH
+  }
+  attr_lists: "nonce-attr"
+  attrs: {  # Allow the default.
+    name: "type"
+    value_casei: "text/css"
+  }
+  cdata: {
+    # This will always cause the tagspec matching to fail.
+    max_bytes: -1
+  }
+}
+
+tags: {  # <style amp-custom>, [AMP, ACTIONS]
+  html_format: AMP
+  html_format: ACTIONS
+  disabled_by: "transformed"
+  tag_name: "STYLE"
+  spec_name: "style amp-custom"
+  named_id: STYLE_AMP_CUSTOM
+  unique: true
+  mandatory_parent: "HEAD"
+  attr_lists: "nonce-attr"
+  attrs: {
+    name: "amp-custom"
+    mandatory: true
+    value: ""
+    # This is a fine dispatch key, but we would prefer that this tagspec
+    # is used for errors related to <style> tags missing the amp-custom
+    # attribute rather than the boilerplate tagspec which doesn't have an
+    # attribute and thus can't have a dispatch_key.
+    # dispatch_key: NAME_DISPATCH
+  }
+  attrs: {  # Allow the default.
+    name: "type"
+    value_casei: "text/css"
+  }
+  cdata: {
+    max_bytes: 75000
+    max_bytes_spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#maximum-size"
+    css_spec: {
+      at_rule_spec: {
+        name: 'font-face'
+        type: PARSE_AS_DECLARATIONS
+      }
+      at_rule_spec: {
+        name: 'keyframes'
+        type: PARSE_AS_RULES
+      }
+      at_rule_spec: {
+        name: 'media'
+        type: PARSE_AS_RULES
+      }
+      at_rule_spec: {
+        name: 'page'
+        type: PARSE_AS_DECLARATIONS
+      }
+      at_rule_spec: {
+        name: 'supports'
+        type: PARSE_AS_RULES
+      }
+      at_rule_spec: {
+        name: '$DEFAULT'  # matches if none of the above match
+        type: PARSE_AS_ERROR
+      }
+      image_url_spec: {
+        protocol: "https"
+        protocol: "http"
+        protocol: "data"
+        protocol: "absolute"  # Temporary / will go away.
+        allow_empty: true
+      }
+      font_url_spec: {
+        protocol: "https"
+        protocol: "http"
+        protocol: "data"
+        allow_empty: true
+      }
+    }
+    blacklisted_cdata_regex: {
+      regex: "<!--"
+      error_message: "html comments"
+    }
+    # These regex blacklists are temporary hacks to validate essential CSS
+    # rules. They will be replaced later with more principled solutions.
+    blacklisted_cdata_regex: {
+      regex: "(^|\\W)i-amphtml-"
+      error_message: "CSS i-amphtml- name prefix"
+    }
+  }
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#stylesheets"
+}
+
+tags: {  # `<style amp-custom>`, transformed [AMP, ACTIONS]
+  html_format: AMP
+  html_format: ACTIONS
+  enabled_by: "transformed"
+  tag_name: "STYLE"
+  spec_name: "style amp-custom (transformed)"
+  unique: true
+  mandatory_parent: "HEAD"
+  attrs: {
+    name: "amp-custom"
+    mandatory: true
+    value: ""
+    # This is a fine dispatch key, but we would prefer that this tagspec
+    # is used for errors related to <style> tags missing the amp-custom
+    # attribute rather than the boilerplate tagspec which doesn't have an
+    # attribute and thus can't have a dispatch_key.
+    # dispatch_key: NAME_DISPATCH
+  }
+  attrs: {  # Allow the default.
+    name: "type"
+    value_casei: "text/css"
+  }
+  cdata: {
+    max_bytes: 75000
+    # For transformed AMP non-data URLs are not counted against the total byte
+    # limit for <style amp-custom>.
+    url_bytes_included: false
+    max_bytes_spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#maximum-size"
+    css_spec: {
+      at_rule_spec: {
+        name: 'font-face'
+        type: PARSE_AS_DECLARATIONS
+      }
+      at_rule_spec: {
+        name: 'keyframes'
+        type: PARSE_AS_RULES
+      }
+      at_rule_spec: {
+        name: 'media'
+        type: PARSE_AS_RULES
+      }
+      at_rule_spec: {
+        name: 'page'
+        type: PARSE_AS_DECLARATIONS
+      }
+      at_rule_spec: {
+        name: 'supports'
+        type: PARSE_AS_RULES
+      }
+      at_rule_spec: {
+        name: '$DEFAULT'  # matches if none of the above match
+        type: PARSE_AS_ERROR
+      }
+      image_url_spec: {
+        protocol: "https"
+        protocol: "http"
+        protocol: "data"
+        protocol: "absolute"  # Temporary / will go away.
+        allow_empty: true
+      }
+      font_url_spec: {
+        protocol: "https"
+        protocol: "http"
+        protocol: "data"
+        allow_empty: true
+      }
+    }
+    blacklisted_cdata_regex: {
+      regex: "<!--"
+      error_message: "html comments"
+    }
+    # These regex blacklists are temporary hacks to validate essential CSS
+    # rules. They will be replaced later with more principled solutions.
+    blacklisted_cdata_regex: {
+      regex: "(^|\\W)i-amphtml-"
+      error_message: "CSS i-amphtml- name prefix"
+    }
+  }
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#stylesheets"
+}
+
+tags: {  # <style amp-custom>, AMP4ADS
+  html_format: AMP4ADS
+  tag_name: "STYLE"
+  spec_name: "style amp-custom (AMP4ADS)"
+  unique: true
+  mandatory_parent: "HEAD"
+  attr_lists: "nonce-attr"
+  attrs: {
+    name: "amp-custom"
+    mandatory: true
+    value: ""
+    # This is a fine dispatch key, but we would prefer that this tagspec
+    # is used for errors related to <style> tags missing the amp-custom
+    # attribute rather than the boilerplate tagspec which doesn't have an
+    # attribute and thus can't have a dispatch_key.
+    # dispatch_key: NAME_DISPATCH
+  }
+  attrs: {  # Allow the default.
+    name: "type"
+    value_casei: "text/css"
+  }
+  cdata: {
+    max_bytes: 20000  # Smaller than AMP, which is 75,000.
+    max_bytes_spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/a4a_spec#css"
+    css_spec: {
+      at_rule_spec: {
+        name: 'font-face'
+        type: PARSE_AS_DECLARATIONS
+      }
+      at_rule_spec: {
+        name: 'keyframes'
+        type: PARSE_AS_RULES
+      }
+      at_rule_spec: {
+        name: 'media'
+        type: PARSE_AS_RULES
+        media_query_spec: {
+          issues_as_error: false
+          type: 'all'
+          type: 'print'
+          type: 'screen'
+          type: 'speech'
+          feature: 'width'
+          feature: 'height'
+          feature: 'aspect-ratio'
+          feature: 'orientation'
+          feature: 'resolution'
+        }
+      }
+      at_rule_spec: {
+        name: 'supports'
+        type: PARSE_AS_RULES
+      }
+      at_rule_spec: {
+        name: '$DEFAULT'  # matches if none of the above match
+        type: PARSE_AS_ERROR
+      }
+      image_url_spec: {
+        protocol: "https"
+        protocol: "http"
+        protocol: "data"
+        protocol: "absolute"  # Temporary / will go away.
+        allow_empty: true
+      }
+      font_url_spec: {
+        protocol: "https"
+        protocol: "http"
+        protocol: "data"
+        allow_empty: true
+      }
+      validate_amp4ads: true
+    }
+    blacklisted_cdata_regex: {
+      regex: "<!--"
+      error_message: "html comments"
+    }
+    # These regex blacklists are temporary hacks to validate essential CSS
+    # rules. They will be replaced later with more principled solutions.
+    blacklisted_cdata_regex: {
+      regex: "(^|\\W)i-amphtml-"
+      error_message: "CSS i-amphtml- name prefix"
+    }
+  }
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/a4a_spec#css"
+}
+
+tags: {  # <style amp-custom>, AMP4EMAIL
+  html_format: AMP4EMAIL
+  tag_name: "STYLE"
+  spec_name: "style amp-custom (AMP4EMAIL)"
+  unique: true
+  mandatory_parent: "HEAD"
+  attrs: {
+    name: "amp-custom"
+    mandatory: true
+    value: ""
+    # This is a fine dispatch key, but we would prefer that this tagspec
+    # is used for errors related to <style> tags missing the amp-custom
+    # attribute rather than the boilerplate tagspec which doesn't have an
+    # attribute and thus can't have a dispatch_key.
+    # dispatch_key: NAME_DISPATCH
+  }
+  attrs: {  # Allow the default.
+    name: "type"
+    value_casei: "text/css"
+  }
+  # TODO(b/68756045): Whitelist CSS properties allowed in Dynamic Mail.
+  cdata: {
+    max_bytes: 75000
+    max_bytes_spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#maximum-size"
+    css_spec: {
+      at_rule_spec: {
+        name: 'media'
+        type: PARSE_AS_RULES
+        media_query_spec: {
+          issues_as_error: true
+          type: 'all'
+          type: 'screen'
+          feature: 'device-width'
+          feature: 'orientation'
+          feature: 'pointer'
+          feature: 'resolution'
+          feature: 'width'
+        }
+      }
+      at_rule_spec: {
+        name: 'page'
+        type: PARSE_AS_DECLARATIONS
+      }
+      at_rule_spec: {
+        name: '$DEFAULT'  # matches if none of the above match
+        type: PARSE_AS_ERROR
+      }
+      image_url_spec: {
+        protocol: "https"
+      }
+    }
+    blacklisted_cdata_regex: {
+      regex: "<!--"
+      error_message: "html comments"
+    }
+    # These regex blacklists are temporary hacks to validate essential CSS
+    # rules. They will be replaced later with more principled solutions.
+    blacklisted_cdata_regex: {
+      regex: "(^|\\W)i-amphtml-"
+      error_message: "CSS i-amphtml- name prefix"
+    }
+  }
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#stylesheets"
+}
+
+tags: {  # `<style amp-boilerplate>`, [AMP, ACTIONS]
+  html_format: AMP
+  html_format: ACTIONS
+  disabled_by: "transformed"
+  tag_name: "STYLE"
+  spec_name: "head > style[amp-boilerplate]"
+  mandatory: true
+  unique: true
+  mandatory_parent: "HEAD"
+  attr_lists: "nonce-attr"
+  attrs: {
+    name: "amp-boilerplate"
+    mandatory: true
+    value: ""
+    dispatch_key: NAME_VALUE_PARENT_DISPATCH
+  }
+  cdata: {
+    # This regex allows arbitrary whitespace whenever some whitespace
+    # is required in the boilerplate. It was made by replacing ' ' with \\s+.
+    cdata_regex: "\\s*body\\s*{\\s*-webkit-animation:\\s*-amp-start\\s+8s\\s+steps\\(1,\\s*end\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*-moz-animation:\\s*-amp-start\\s+8s\\s+steps\\s*\\(1\\s*,\\s*end\\s*\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*-ms-animation:\\s*-amp-start\\s+8s\\s+steps\\s*\\(1\\s*,\\s*end\\s*\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*animation:\\s*-amp-start\\s+8s\\s+steps\\(1,\\s*end\\)\\s+0s\\s+1\\s+normal\\s+both;?\\s*}\\s*@-webkit-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-moz-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-ms-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-o-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*"
+  }
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amp-boilerplate?format=websites"
+}
+
+tags: {  # `<style amp-boilerplate>`, transformed [AMP, ACTIONS]
+  html_format: AMP
+  html_format: ACTIONS
+  enabled_by: "transformed"
+  tag_name: "STYLE"
+  spec_name: "head > style[amp-boilerplate] (transformed)"
+  unique: true
+  mandatory_parent: "HEAD"
+  attrs: {
+    name: "amp-boilerplate"
+    mandatory: true
+    value: ""
+    dispatch_key: NAME_VALUE_PARENT_DISPATCH
+  }
+  cdata: {
+    # This regex allows arbitrary whitespace whenever some whitespace
+    # is required in the boilerplate. It was made by replacing ' ' with \\s+.
+    cdata_regex: "\\s*body\\s*{\\s*-webkit-animation:\\s*-amp-start\\s+8s\\s+steps\\(1,\\s*end\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*-moz-animation:\\s*-amp-start\\s+8s\\s+steps\\s*\\(1\\s*,\\s*end\\s*\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*-ms-animation:\\s*-amp-start\\s+8s\\s+steps\\s*\\(1\\s*,\\s*end\\s*\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*animation:\\s*-amp-start\\s+8s\\s+steps\\(1,\\s*end\\)\\s+0s\\s+1\\s+normal\\s+both;?\\s*}\\s*@-webkit-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-moz-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-ms-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-o-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*"
+  }
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amp-boilerplate?format=websites"
+}
+
+tags: {  # `<style amp4ads-boilerplate>`, AMP4ADS
+  html_format: AMP4ADS
+  tag_name: "STYLE"
+  spec_name: "head > style[amp4ads-boilerplate]"
+  mandatory: true
+  unique: true
+  mandatory_parent: "HEAD"
+  attr_lists: "nonce-attr"
+  attrs: {
+    name: "amp4ads-boilerplate"
+    mandatory: true
+    value: ""
+    dispatch_key: NAME_VALUE_PARENT_DISPATCH
+  }
+  cdata: {
+    # This regex allows arbitrary whitespace around the body statement, but
+    # not inside it. This is a compromise to keep things simple, but allow
+    # pretty printing tools some latitude.
+    cdata_regex: "\\s*body\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*"
+  }
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/a4a_spec?format=ads#boilerplate"
+}
+
+tags: {  # `<style amp4email-boilerplate>`, AMP4EMAIL
+  html_format: AMP4EMAIL
+  tag_name: "STYLE"
+  spec_name: "head > style[amp4email-boilerplate]"
+  mandatory: true
+  unique: true
+  mandatory_parent: "HEAD"
+  attrs: {
+    name: "amp4email-boilerplate"
+    mandatory: true
+    value: ""
+    dispatch_key: NAME_VALUE_PARENT_DISPATCH
+  }
+  cdata: {
+    # This regex allows arbitrary whitespace whenever some whitespace
+    # is required in the boilerplate. It was made by replacing ' ' with \\s+.
+    cdata_regex: "\\s*body\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*"
+  }
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/amp-email-format?format=email#required-markup"
+}
+
+tags: {  # `<style amp-boilerplate>`, [AMP, ACTIONS]
+  html_format: AMP
+  html_format: ACTIONS
+  disabled_by: "transformed"
+  tag_name: "STYLE"
+  spec_name: "noscript > style[amp-boilerplate]"
+  mandatory: true
+  unique: true
+  mandatory_parent: "NOSCRIPT"
+  mandatory_ancestor: "HEAD"
+  attr_lists: "nonce-attr"
+  attrs: {
+    name: "amp-boilerplate"
+    mandatory: true
+    value: ""
+    dispatch_key: NAME_VALUE_PARENT_DISPATCH
+  }
+  cdata {
+    cdata_regex: "\\s*body\\s*{\\s*-webkit-animation:\\s*none;\\s*-moz-animation:\\s*none;\\s*-ms-animation:\\s*none;\\s*animation:\\s*none;?\\s*}\\s*"
+  }
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amp-boilerplate?format=websites"
+}
+
+tags: {  # `<style amp-boilerplate>`, transformed [AMP, ACTIONS]
+  html_format: AMP
+  html_format: ACTIONS
+  enabled_by: "transformed"
+  tag_name: "STYLE"
+  spec_name: "noscript > style[amp-boilerplate] (transformed)"
+  unique: true
+  mandatory_parent: "NOSCRIPT"
+  mandatory_ancestor: "HEAD"
+  attrs: {
+    name: "amp-boilerplate"
+    mandatory: true
+    value: ""
+    dispatch_key: NAME_VALUE_PARENT_DISPATCH
+  }
+  cdata {
+    cdata_regex: "\\s*body\\s*{\\s*-webkit-animation:\\s*none;\\s*-moz-animation:\\s*none;\\s*-ms-animation:\\s*none;\\s*animation:\\s*none;?\\s*}\\s*"
+  }
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amp-boilerplate?format=websites"
+}
+
+tags: {  # `<style amp-keyframes>`, [AMP, AMP4ADS, ACTIONS]
+  html_format: AMP
+  html_format: AMP4ADS
+  html_format: ACTIONS
+  tag_name: "STYLE"
+  spec_name: "style[amp-keyframes]"
+  unique: true
+  mandatory_parent: "BODY"
+  mandatory_last_child: true
+  attrs: {
+     name: "amp-keyframes"
+     value: ""
+     mandatory: true
+     dispatch_key: NAME_DISPATCH
+  }
+  cdata: {
+    max_bytes: 500000
+    max_bytes_spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#keyframes-stylesheet"
+    css_spec: {
+      at_rule_spec: {
+        name: 'keyframes'
+        type: PARSE_AS_RULES
+      }
+      at_rule_spec: {
+        name: 'media'
+        type: PARSE_AS_RULES
+      }
+      at_rule_spec: {
+        name: 'supports'
+        type: PARSE_AS_RULES
+      }
+      at_rule_spec: {
+        name: '$DEFAULT'  # matches if none of the above match
+        type: PARSE_AS_ERROR
+      }
+      validate_keyframes: true
+      declaration: "animation-timing-function"
+      declaration: "offset-distance"
+      declaration: "opacity"
+      declaration: "transform"
+      declaration: "visibility"
+    }
+  }
+}
+
+tags: {  # '<style amp-runtime>`, transformed AMP
+  html_format: AMP
+  enabled_by: "transformed"
+  tag_name: "STYLE"
+  spec_name: "style[amp-runtime] (transformed)"
+  mandatory: true
+  unique: true
+  mandatory_parent: "HEAD"
+  attrs: {
+    name: "amp-runtime"
+    mandatory: true
+    value: ""
+    dispatch_key: NAME_VALUE_PARENT_DISPATCH
+  }
+  attrs: {
+    name: "i-amphtml-version"
+    mandatory: true
+    value_regex: "^\\d{15}|latest$"
+  }
+  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#stylesheets"
+}
diff --git a/validator/validator-main.protoascii b/validator/validator-main.protoascii
index 1157fb364..ce170315b 100644
--- a/validator/validator-main.protoascii
+++ b/validator/validator-main.protoascii
@@ -19,25 +19,18 @@
 # engine are made, this value must be incremented to prevent old binaries
 # in production from crashing. This id is not relevant to validator.js
 # because thus far, engine (validator.js) and spec file
-# (validator-main.protoascii) are always released together.
+# (validator-main.protoascii, etc) are always released together.
 min_validator_revision_required: 375
 
 # The spec file revision allows the validator engine to distinguish
 # newer versions of the spec file. This is currently a Google internal
 # mechanism, validator.js does not use this facility. However, any
 # change to this file (validator-main.js) requires updating this revision id.
-spec_file_revision: 1012
+spec_file_revision: 1028
 
 styles_spec_url: "https://amp.dev/documentation/guides-and-tutorials/develop/style_and_layout/style_pages"
 script_spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#html-tags"
 
-css_length_spec: {
-  html_format: AMP
-  max_bytes: 75000
-  max_bytes_per_inline_style: 1000
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#maximum-size"
-}
-
 # Validator extensions.
 # =====================
 # In addition to the rules in this file, the Validator honors the rules
@@ -102,6 +95,14 @@ tags: {  # HTML tag for non-transformed AMP.
   tag_name: "HTML"
   mandatory: true
   mandatory_parent: "!DOCTYPE"
+  attrs: {
+    # This attribute should always be invalid. See https://github.com/ampproject/amphtml/pull/27174
+    # To align with HTML spec, custom attributes should be prefixed with `data-`.
+    # Because `data-*` attributes are always valid AMP, the following rules explicitly disallow usage.
+    name: "data-amp-autocomplete-opt-in"
+    value: "false"
+    blacklisted_value_regex: "false"
+  }
   unique: true
   spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#required-markup"
 }
@@ -1032,560 +1033,7 @@ tags: {
   }
 }
 # 4.2.6 The style
-# Text contents of the style tag will be validated seperately.
-tags: {  # Special custom 'author' spreadsheet for AMP
-  html_format: AMP
-  html_format: ACTIONS
-  disabled_by: "transformed"
-  tag_name: "STYLE"
-  spec_name: "style amp-custom"
-  named_id: STYLE_AMP_CUSTOM
-  unique: true
-  mandatory_parent: "HEAD"
-  attr_lists: "nonce-attr"
-  attrs: {
-    name: "amp-custom"
-    mandatory: true
-    value: ""
-    # This is a fine dispatch key, but we would prefer that this tagspec
-    # is used for errors related to <style> tags missing the amp-custom
-    # attribute rather than the boilerplate tagspec which doesn't have an
-    # attribute and thus can't have a dispatch_key.
-    # dispatch_key: NAME_DISPATCH
-  }
-  attrs: {  # This is a default, but it doesn't hurt.
-    name: "type"
-    value_casei: "text/css"
-  }
-  cdata: {
-    max_bytes: 75000
-    max_bytes_spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#maximum-size"
-    css_spec: {
-      at_rule_spec: {
-        name: 'font-face'
-        type: PARSE_AS_DECLARATIONS
-      }
-      at_rule_spec: {
-        name: 'keyframes'
-        type: PARSE_AS_RULES
-      }
-      at_rule_spec: {
-        name: 'media'
-        type: PARSE_AS_RULES
-      }
-      at_rule_spec: {
-        name: 'page'
-        type: PARSE_AS_DECLARATIONS
-      }
-      at_rule_spec: {
-        name: 'supports'
-        type: PARSE_AS_RULES
-      }
-      at_rule_spec: {
-        name: '$DEFAULT'  # matches if none of the above match
-        type: PARSE_AS_ERROR
-      }
-      image_url_spec: {
-        protocol: "https"
-        protocol: "http"
-        protocol: "data"
-        protocol: "absolute"  # Temporary / will go away.
-        allow_empty: true
-      }
-      font_url_spec: {
-        protocol: "https"
-        protocol: "http"
-        protocol: "data"
-        allow_empty: true
-      }
-    }
-    blacklisted_cdata_regex: {
-      regex: "<!--"
-      error_message: "html comments"
-    }
-    # These regex blacklists are temporary hacks to validate essential CSS
-    # rules. They will be replaced later with more principled solutions.
-    blacklisted_cdata_regex: {
-      regex: "(^|\\W)i-amphtml-"
-      error_message: "CSS i-amphtml- name prefix"
-    }
-    blacklisted_cdata_regex: {
-      regex: "!\\s*important"
-      error_message: "CSS !important"
-    }
-  }
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#stylesheets"
-}
-# This variant of <style amp-custom> is designed to help developers see how
-# close they are to the byte limit, even if the page is passing. By changing
-# the attribute to <style amp-custom-length-check>, this tagspec will be used
-# to match errors. It cannot pass however as it has a cdata.max_bytes set to
-# -1. As a result, it will always fail and report the length found in the
-# tag's cdata. This is a small hack, and may be deleted in the future if there
-# are problems maintaining it. Deleting this tagspec will of course never
-# break any valid AMP documents as if it matches, the page will be invalid.
-tags: {
-  html_format: AMP
-  html_format: AMP4ADS
-  html_format: AMP4EMAIL
-  html_format: ACTIONS
-  disabled_by: "transformed"
-  tag_name: "STYLE"
-  spec_name: "style amp-custom-length-check"
-  unique: true
-  mandatory_parent: "HEAD"
-  attrs: {
-    name: "amp-custom-length-check"
-    mandatory: true
-    value: ""
-    dispatch_key: NAME_DISPATCH
-  }
-  attr_lists: "nonce-attr"
-  attrs: {  # This is a default, but it doesn't hurt.
-    name: "type"
-    value_casei: "text/css"
-  }
-  cdata: {
-    # This will always cause the tagspec matching to fail.
-    max_bytes: -1
-  }
-}
-# For transformed AMP non-data URLs are not counted against the total byte
-# limit for <style amp-custom>. This is done by setting url_bytes_included
-# to false for CdataSpec below.
-tags: {  # Special custom 'author' spreadsheet for transformed AMP
-  html_format: AMP
-  html_format: ACTIONS
-  enabled_by: "transformed"
-  tag_name: "STYLE"
-  spec_name: "style amp-custom (transformed)"
-  unique: true
-  mandatory_parent: "HEAD"
-  attrs: {
-    name: "amp-custom"
-    mandatory: true
-    value: ""
-    # This is a fine dispatch key, but we would prefer that this tagspec
-    # is used for errors related to <style> tags missing the amp-custom
-    # attribute rather than the boilerplate tagspec which doesn't have an
-    # attribute and thus can't have a dispatch_key.
-    # dispatch_key: NAME_DISPATCH
-  }
-  attrs: {  # This is a default, but it doesn't hurt.
-    name: "type"
-    value_casei: "text/css"
-  }
-  cdata: {
-    max_bytes: 75000
-    url_bytes_included: false
-    max_bytes_spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#maximum-size"
-    css_spec: {
-      at_rule_spec: {
-        name: 'font-face'
-        type: PARSE_AS_DECLARATIONS
-      }
-      at_rule_spec: {
-        name: 'keyframes'
-        type: PARSE_AS_RULES
-      }
-      at_rule_spec: {
-        name: 'media'
-        type: PARSE_AS_RULES
-      }
-      at_rule_spec: {
-        name: 'page'
-        type: PARSE_AS_DECLARATIONS
-      }
-      at_rule_spec: {
-        name: 'supports'
-        type: PARSE_AS_RULES
-      }
-      at_rule_spec: {
-        name: '$DEFAULT'  # matches if none of the above match
-        type: PARSE_AS_ERROR
-      }
-      image_url_spec: {
-        protocol: "https"
-        protocol: "http"
-        protocol: "data"
-        protocol: "absolute"  # Temporary / will go away.
-        allow_empty: true
-      }
-      font_url_spec: {
-        protocol: "https"
-        protocol: "http"
-        protocol: "data"
-        allow_empty: true
-      }
-    }
-    blacklisted_cdata_regex: {
-      regex: "<!--"
-      error_message: "html comments"
-    }
-    # These regex blacklists are temporary hacks to validate essential CSS
-    # rules. They will be replaced later with more principled solutions.
-    blacklisted_cdata_regex: {
-      regex: "(^|\\W)i-amphtml-"
-      error_message: "CSS i-amphtml- name prefix"
-    }
-    blacklisted_cdata_regex: {
-      regex: "!\\s*important"
-      error_message: "CSS !important"
-    }
-  }
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#stylesheets"
-}
-tags: {  # Special custom 'author' spreadsheet for AMP4ADS
-  html_format: AMP4ADS
-  tag_name: "STYLE"
-  spec_name: "style amp-custom (AMP4ADS)"
-  unique: true
-  mandatory_parent: "HEAD"
-  attr_lists: "nonce-attr"
-  attrs: {
-    name: "amp-custom"
-    mandatory: true
-    value: ""
-    # This is a fine dispatch key, but we would prefer that this tagspec
-    # is used for errors related to <style> tags missing the amp-custom
-    # attribute rather than the boilerplate tagspec which doesn't have an
-    # attribute and thus can't have a dispatch_key.
-    # dispatch_key: NAME_DISPATCH
-  }
-  attrs: {  # This is a default, but it doesn't hurt.
-    name: "type"
-    value_casei: "text/css"
-  }
-  cdata: {
-    max_bytes: 20000  # Smaller than AMP, which is 75,000.
-    max_bytes_spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/a4a_spec#css"
-    css_spec: {
-      at_rule_spec: {
-        name: 'font-face'
-        type: PARSE_AS_DECLARATIONS
-      }
-      at_rule_spec: {
-        name: 'keyframes'
-        type: PARSE_AS_RULES
-      }
-      at_rule_spec: {
-        name: 'media'
-        type: PARSE_AS_RULES
-        media_query_spec: {
-          issues_as_error: false
-          type: 'all'
-          type: 'print'
-          type: 'screen'
-          type: 'speech'
-          feature: 'width'
-          feature: 'height'
-          feature: 'aspect-ratio'
-          feature: 'orientation'
-          feature: 'resolution'
-        }
-      }
-      at_rule_spec: {
-        name: 'supports'
-        type: PARSE_AS_RULES
-      }
-      at_rule_spec: {
-        name: '$DEFAULT'  # matches if none of the above match
-        type: PARSE_AS_ERROR
-      }
-      image_url_spec: {
-        protocol: "https"
-        protocol: "http"
-        protocol: "data"
-        protocol: "absolute"  # Temporary / will go away.
-        allow_empty: true
-      }
-      font_url_spec: {
-        protocol: "https"
-        protocol: "http"
-        protocol: "data"
-        allow_empty: true
-      }
-      validate_amp4ads: true
-    }
-    blacklisted_cdata_regex: {
-      regex: "<!--"
-      error_message: "html comments"
-    }
-    # These regex blacklists are temporary hacks to validate essential CSS
-    # rules. They will be replaced later with more principled solutions.
-    blacklisted_cdata_regex: {
-      regex: "(^|\\W)i-amphtml-"
-      error_message: "CSS i-amphtml- name prefix"
-    }
-    blacklisted_cdata_regex: {
-      regex: "!\\s*important"
-      error_message: "CSS !important"
-    }
-  }
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/a4a_spec#css"
-}
-tags: {  # Special custom 'author' spreadsheet for AMP
-  html_format: AMP4EMAIL
-  tag_name: "STYLE"
-  spec_name: "style amp-custom (AMP4EMAIL)"
-  unique: true
-  mandatory_parent: "HEAD"
-  attrs: {
-    name: "amp-custom"
-    mandatory: true
-    value: ""
-    # This is a fine dispatch key, but we would prefer that this tagspec
-    # is used for errors related to <style> tags missing the amp-custom
-    # attribute rather than the boilerplate tagspec which doesn't have an
-    # attribute and thus can't have a dispatch_key.
-    # dispatch_key: NAME_DISPATCH
-  }
-  attrs: {  # This is a default, but it doesn't hurt.
-    name: "type"
-    value_casei: "text/css"
-  }
-  # TODO(b/68756045): Whitelist CSS properties allowed in Dynamic Mail.
-  cdata: {
-    max_bytes: 75000
-    max_bytes_spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#maximum-size"
-    css_spec: {
-      at_rule_spec: {
-        name: 'media'
-        type: PARSE_AS_RULES
-        media_query_spec: {
-          issues_as_error: true
-          type: 'all'
-          type: 'screen'
-          feature: 'device-width'
-          feature: 'orientation'
-          feature: 'pointer'
-          feature: 'resolution'
-          feature: 'width'
-        }
-      }
-      at_rule_spec: {
-        name: 'page'
-        type: PARSE_AS_DECLARATIONS
-      }
-      at_rule_spec: {
-        name: '$DEFAULT'  # matches if none of the above match
-        type: PARSE_AS_ERROR
-      }
-      image_url_spec: {
-        protocol: "https"
-      }
-    }
-    blacklisted_cdata_regex: {
-      regex: "<!--"
-      error_message: "html comments"
-    }
-    # These regex blacklists are temporary hacks to validate essential CSS
-    # rules. They will be replaced later with more principled solutions.
-    blacklisted_cdata_regex: {
-      regex: "(^|\\W)i-amphtml-"
-      error_message: "CSS i-amphtml- name prefix"
-    }
-    blacklisted_cdata_regex: {
-      regex: "!\\s*important"
-      error_message: "CSS !important"
-    }
-  }
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#stylesheets"
-}
-tags: {
-  html_format: AMP
-  html_format: ACTIONS
-  disabled_by: "transformed"
-  tag_name: "STYLE"
-  spec_name: "head > style[amp-boilerplate]"
-  mandatory: true
-  unique: true
-  mandatory_parent: "HEAD"
-  attr_lists: "nonce-attr"
-  attrs: {
-    name: "amp-boilerplate"
-    mandatory: true
-    value: ""
-    dispatch_key: NAME_VALUE_PARENT_DISPATCH
-  }
-  cdata: {
-    # This regex allows arbitrary whitespace whenever some whitespace
-    # is required in the boilerplate. It was made by replacing ' ' with \\s+.
-    cdata_regex: "\\s*body\\s*{\\s*-webkit-animation:\\s*-amp-start\\s+8s\\s+steps\\(1,\\s*end\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*-moz-animation:\\s*-amp-start\\s+8s\\s+steps\\s*\\(1\\s*,\\s*end\\s*\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*-ms-animation:\\s*-amp-start\\s+8s\\s+steps\\s*\\(1\\s*,\\s*end\\s*\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*animation:\\s*-amp-start\\s+8s\\s+steps\\(1,\\s*end\\)\\s+0s\\s+1\\s+normal\\s+both;?\\s*}\\s*@-webkit-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-moz-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-ms-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-o-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*"
-  }
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amp-boilerplate?format=websites"
-}
-tags: {
-  html_format: AMP
-  html_format: ACTIONS
-  enabled_by: "transformed"
-  tag_name: "STYLE"
-  spec_name: "head > style[amp-boilerplate] (transformed)"
-  unique: true
-  mandatory_parent: "HEAD"
-  attrs: {
-    name: "amp-boilerplate"
-    mandatory: true
-    value: ""
-    dispatch_key: NAME_VALUE_PARENT_DISPATCH
-  }
-  cdata: {
-    # This regex allows arbitrary whitespace whenever some whitespace
-    # is required in the boilerplate. It was made by replacing ' ' with \\s+.
-    cdata_regex: "\\s*body\\s*{\\s*-webkit-animation:\\s*-amp-start\\s+8s\\s+steps\\(1,\\s*end\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*-moz-animation:\\s*-amp-start\\s+8s\\s+steps\\s*\\(1\\s*,\\s*end\\s*\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*-ms-animation:\\s*-amp-start\\s+8s\\s+steps\\s*\\(1\\s*,\\s*end\\s*\\)\\s+0s\\s+1\\s+normal\\s+both;\\s*animation:\\s*-amp-start\\s+8s\\s+steps\\(1,\\s*end\\)\\s+0s\\s+1\\s+normal\\s+both;?\\s*}\\s*@-webkit-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-moz-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-ms-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@-o-keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*@keyframes\\s+-amp-start\\s*{\\s*from\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*to\\s*{\\s*visibility:\\s*visible;?\\s*}\\s*}\\s*"
-  }
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amp-boilerplate?format=websites"
-}
-tags: {
-  html_format: AMP4ADS
-  tag_name: "STYLE"
-  spec_name: "head > style[amp4ads-boilerplate]"
-  mandatory: true
-  unique: true
-  mandatory_parent: "HEAD"
-  attr_lists: "nonce-attr"
-  attrs: {
-    name: "amp4ads-boilerplate"
-    mandatory: true
-    value: ""
-    dispatch_key: NAME_VALUE_PARENT_DISPATCH
-  }
-  cdata: {
-    # This regex allows arbitrary whitespace around the body statement, but
-    # not inside it. This is a compromise to keep things simple, but allow
-    # pretty printing tools some latitude.
-    cdata_regex: "\\s*body\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*"
-  }
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/a4a_spec?format=ads#boilerplate"
-}
-tags: {
-  html_format: AMP4EMAIL
-  tag_name: "STYLE"
-  spec_name: "head > style[amp4email-boilerplate]"
-  mandatory: true
-  unique: true
-  mandatory_parent: "HEAD"
-  attrs: {
-    name: "amp4email-boilerplate"
-    mandatory: true
-    value: ""
-    dispatch_key: NAME_VALUE_PARENT_DISPATCH
-  }
-  cdata: {
-    # This regex allows arbitrary whitespace whenever some whitespace
-    # is required in the boilerplate. It was made by replacing ' ' with \\s+.
-    cdata_regex: "\\s*body\\s*{\\s*visibility:\\s*hidden;?\\s*}\\s*"
-  }
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/amp-email-format?format=email#required-markup"
-}
-tags: {
-  html_format: AMP
-  html_format: ACTIONS
-  disabled_by: "transformed"
-  tag_name: "STYLE"
-  spec_name: "noscript > style[amp-boilerplate]"
-  mandatory: true
-  unique: true
-  mandatory_parent: "NOSCRIPT"
-  mandatory_ancestor: "HEAD"
-  attr_lists: "nonce-attr"
-  attrs: {
-    name: "amp-boilerplate"
-    mandatory: true
-    value: ""
-    dispatch_key: NAME_VALUE_PARENT_DISPATCH
-  }
-  cdata {
-    cdata_regex: "\\s*body\\s*{\\s*-webkit-animation:\\s*none;\\s*-moz-animation:\\s*none;\\s*-ms-animation:\\s*none;\\s*animation:\\s*none;?\\s*}\\s*"
-  }
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amp-boilerplate?format=websites"
-}
-tags: {
-  html_format: AMP
-  html_format: ACTIONS
-  enabled_by: "transformed"
-  tag_name: "STYLE"
-  spec_name: "noscript > style[amp-boilerplate] (transformed)"
-  unique: true
-  mandatory_parent: "NOSCRIPT"
-  mandatory_ancestor: "HEAD"
-  attrs: {
-    name: "amp-boilerplate"
-    mandatory: true
-    value: ""
-    dispatch_key: NAME_VALUE_PARENT_DISPATCH
-  }
-  cdata {
-    cdata_regex: "\\s*body\\s*{\\s*-webkit-animation:\\s*none;\\s*-moz-animation:\\s*none;\\s*-ms-animation:\\s*none;\\s*animation:\\s*none;?\\s*}\\s*"
-  }
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amp-boilerplate?format=websites"
-}
-
-tags: {
-  html_format: AMP
-  html_format: AMP4ADS
-  html_format: ACTIONS
-  tag_name: "STYLE"
-  spec_name: "style[amp-keyframes]"
-  unique: true
-  mandatory_parent: "BODY"
-  mandatory_last_child: true
-  attrs: {
-     name: "amp-keyframes"
-     value: ""
-     mandatory: true
-     dispatch_key: NAME_DISPATCH
-  }
-  cdata: {
-    max_bytes: 500000
-    max_bytes_spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#keyframes-stylesheet"
-    css_spec: {
-      at_rule_spec: {
-        name: 'keyframes'
-        type: PARSE_AS_RULES
-      }
-      at_rule_spec: {
-        name: 'media'
-        type: PARSE_AS_RULES
-      }
-      at_rule_spec: {
-        name: 'supports'
-        type: PARSE_AS_RULES
-      }
-      at_rule_spec: {
-        name: '$DEFAULT'  # matches if none of the above match
-        type: PARSE_AS_ERROR
-      }
-      validate_keyframes: true
-      declaration: "animation-timing-function"
-      declaration: "offset-distance"
-      declaration: "opacity"
-      declaration: "transform"
-      declaration: "visibility"
-    }
-  }
-}
-tags: {
-  html_format: AMP
-  enabled_by: "transformed"
-  tag_name: "STYLE"
-  spec_name: "style[amp-runtime] (transformed)"
-  mandatory: true
-  unique: true
-  mandatory_parent: "HEAD"
-  attrs: {
-    name: "amp-runtime"
-    mandatory: true
-    value: ""
-    dispatch_key: NAME_VALUE_PARENT_DISPATCH
-  }
-  attrs: {
-    name: "i-amphtml-version"
-    mandatory: true
-    value_regex: "^\\d{15}|latest$"
-  }
-  spec_url: "https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#stylesheets"
-}
+# See `validator-css.protoascii`.
 
 # 4.3 Sections
 # 4.3.1 The body element
@@ -1882,6 +1330,7 @@ tags: {
   attrs: {
     name: "href"
     value_url: {
+      # When updating this list, make sure to also update bind-validator.js.
       protocol: "ftp"
       protocol: "geo"
       protocol: "http"
@@ -1899,6 +1348,7 @@ tags: {
       # IOS over-the-air app installation
       # (https://github.com/nifcblm/AHPP-iOS-App/wiki/How-to-distribute-enterprise-iOS-App)
       protocol: "itms-services"
+      protocol: "facetime"
       protocol: "fb-me"
       protocol: "fb-messenger"
       protocol: "feed"
@@ -1989,6 +1439,7 @@ tags: {
       protocol: "http"
       protocol: "https"
       protocol: "mailto"
+      protocol: "tel"
       allow_relative: false
     }
     # Openning doubly curly brackets {{ (these are mustache delimiters) can only
@@ -5425,7 +4876,7 @@ tags: {
   }
   attrs: {
     name: "src"
-    value_regex: "data:image\\/svg\\+xml;charset=utf-8,<svg height=\"\\d+\" width=\"\\d+\" xmlns=\"http:\\/\\/www\\.w3\\.org\\/2000\\/svg\" version=\"1\\.1\"\\/>|data:image\\/svg\\+xml;charset=utf-8,<svg height='100' width='300' xmlns='http:\\/\\/www\\.w3\\.org\\/2000\\/svg' version='1\\.1'\\/>"
+    value_regex: "data:image\\/svg\\+xml;charset=utf-8,<svg height=\"\\d+(\\.\\d+)?\" width=\"\\d+(\\.\\d+)?\" xmlns=\"http:\\/\\/www\\.w3\\.org\\/2000\\/svg\" version=\"1\\.1\"\\/>|data:image\\/svg\\+xml;charset=utf-8,<svg height='\\d+(\\.\\d+)?\' width='\\d+(\\.\\d+)?\' xmlns='http:\\/\\/www\\.w3\\.org\\/2000\\/svg' version='1\\.1'\\/>"
     mandatory: true
   }
 }
@@ -5436,6 +4887,7 @@ tags: {
 # their values.
 attr_lists: {
   name: "$AMP_LAYOUT_ATTRS"
+  attrs: { name: "disable-inline-width" }
   attrs: { name: "height" }
   attrs: { name: "heights" }
   attrs: { name: "layout" }

@westonruter westonruter added this to the v1.5.3 milestone Apr 8, 2020
@googlebot googlebot added the cla: yes Signed the Google CLA label Apr 8, 2020
@@ -4079,6 +4081,7 @@ class AMP_Allowed_Tags_Generated {
'tag_spec' => array(
'amp_layout' => array(
'supported_layouts' => array(
5,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@schlessera Here's where the container layout is being added for amp-list. I'm not sure if it would change #4541, but FYI.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in b5b2978 after updating to updating to v2004142326360.

Comment on lines -16609 to -16610
'error_message' => 'CSS !important',
'regex' => '!\\s*important',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has moved from the blacklisted_cdata_redex in the validator spec to an allowImportant read by the validator JS:

https://github.com/ampproject/amphtml/blob/f2963066145114b26774747455f1f6ea6caec884/validator/engine/validator.js#L2155-L2168

This was introduced in ampproject/amphtml#27412.

The allowImportant property is defined as being false by default for the CssSpec:

https://github.com/ampproject/amphtml/blob/f2963066145114b26774747455f1f6ea6caec884/validator/validator.proto#L263-L266

* Add support for blacklisted_cdata_regex being plural.
* Remove obsolete INVALID_CDATA_CSS_IMPORTANT error code.
* Add new INVALID_CDATA_CSS_I_AMPHTML_NAME error code.

Fixes #4319
@@ -18238,6 +18306,7 @@ class AMP_Allowed_Tags_Generated {
private static $layout_allowed_attrs = array(
'data-amp-bind-height' => array(),
'data-amp-bind-width' => array(),
'disable-inline-width' => array(),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is new. Docs: https://amp.dev/documentation/guides-and-tutorials/learn/amp-html-layout/#disable-inline-width

I wonder, does this mean that the sizes attribute can cease to be removed in favor of setting this boolean attribute?

// Remove sizes attribute since it causes headaches in AMP and because AMP will generate it for us. See <https://github.com/ampproject/amphtml/issues/21371>.
unset( $new_attributes['sizes'] );

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answer is yes! ampproject/amphtml#27083 (comment)

So in a subsequent PR we should eliminate the unset() here and instead add the disable-inline-width attribute. This would be done on the develop branch to give it some time to get tested.

Copy link
Contributor

@pierlon pierlon Apr 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this being tracked in a new issue?

Nevermind I see #4606 has been created.

@westonruter westonruter removed this from the v1.5.3 milestone Apr 16, 2020
@westonruter westonruter changed the title Update allowed tags/attributes from spec in amphtml 2004041903580 Update allowed tags/attributes from spec in amphtml 2004142326360 Apr 18, 2020
…phtml-2004041903580

* 'develop' of github.com:ampproject/amp-wp: (48 commits)
  Bump https-proxy-agent from 2.2.2 to 2.2.4 (#4596)
  Update dependency babel-jest to v25.3.0 (#4550)
  Update dependency core-js to v3.6.5 (#4558)
  For the 'Preview AMP' button, use a title instead of a tooltip (#4601)
  Bump stable tag to 1.5.3
  Fix handling of Mustache templates (#4583)
  Stub request based on test scenario (#4588)
  Return early instead of storing eventual return value in variable
  Improve phpdoc and logic conditions
  Update links in pull request template
  Update contributing.md with link to wiki
  Remove engineering.md now that it is on the wiki
  Remove project-management.md since only applicable to Stories
  Add conditions for comment feed, trackback, robots, and favicon
  Fix typo in global phpdoc
  Update tests after block-library/style.css changes in Gutenberg 7.9 (#4579)
  Remove special conditions for Reader mode; remove need for $exit condition in redirects
  Fix translators comment
  Add comment explaining short-circuit behavior when query var is present
  Update version for _doing_it_wrong() from 1.5.3 to 1.6.0
  ...
Copy link
Contributor

@pierlon pierlon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

@@ -18238,6 +18306,7 @@ class AMP_Allowed_Tags_Generated {
private static $layout_allowed_attrs = array(
'data-amp-bind-height' => array(),
'data-amp-bind-width' => array(),
'disable-inline-width' => array(),
Copy link
Contributor

@pierlon pierlon Apr 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this being tracked in a new issue?

Nevermind I see #4606 has been created.

@westonruter westonruter added this to the v1.6 milestone Jun 2, 2020
westonruter added a commit that referenced this pull request Jul 6, 2020
westonruter added a commit that referenced this pull request Jul 6, 2020
@westonruter westonruter added the Changelogged Whether the issue/PR has been added to release notes. label Jul 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelogged Whether the issue/PR has been added to release notes. cla: yes Signed the Google CLA
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Multiple denylist patterns are not applied to CDATA validation
4 participants