Macros nested inside other macros are corrupted if original macro is disabled or not installed

XMLWordPrintable

    • Type: Bug
    • Resolution: Fixed
    • Priority: High
    • 6.14.0
    • Affects Version/s: 6.7.2
    • Component/s: Macros - Other Macros
    • None
    • 1
    • Severity 2 - Major
    • 0

      Confluence will corrupt nested macros inside a unknown macro, leading to data loss in the page storage. The bug lies in the XhtmlContent's implementation and what the class does when a macro definition does not exists or it's not available.

      When the xhtmlContent.handleMacroDefinitions method is called with a block of xhtml content which contains a reference to a macro module that has been disabled it will return invalid data - such that it ignores the macros that the disabled macro contains and will conflate the parameters of those macros into the disable MacroDefinition.

      xhtmlContent.handleMacroDefinitions will generates invalid data leading to data loss.

      In the page we will see this image:

      And if we edit the page, nothing will appear inside the macro:

      The storage format shows that the data exist in the page and the following error appears in the logs:

      handleMacroExecutionException Exception executing macro: jira-form-wrapper, with message: Unable to locate projectKey input, use the blueprint to generate a new form and copy/paste the macro back in to the form.
      

      Replicating the issue

      <ac:structured-macro ac:name="unknown-macro" ac:schema-version="1" ac:macro-id="dcbc25a6-6b81-40bf-9ef8-7a687af59538">
       <ac:rich-text-body>
       <ac:structured-macro ac:name="simple-macro" ac:schema-version="1" ac:macro-id="dcbc25a6-6b81-40bf-9ef8-7a687af59538">
       <ac:parameter ac:name="simple-macro-param">aaa</ac:parameter>
       <ac:parameter ac:name="atlassian-macro-output-type">INLINE</ac:parameter>
       <ac:rich-text-body>
       <p class="auto-cursor-target"><br/></p>
       <ac:structured-macro ac:name="info" ac:schema-version="1" ac:macro-id="3caf2e75-1b55-48cf-9810-fa3884dd8f94">
       <ac:parameter ac:name="info-macro-param">bbb</ac:parameter>
       <ac:parameter ac:name="icon">false</ac:parameter>
       <ac:parameter ac:name="title">title</ac:parameter>
       <ac:rich-text-body>
       <p>this is some content</p></ac:rich-text-body>
       </ac:structured-macro>
       <p class="auto-cursor-target"><br/></p>
       </ac:rich-text-body>
       </ac:structured-macro>
       </ac:rich-text-body>
      </ac:structured-macro>
      

      The "info" above is the standard info macro and simple macro was a test macro created to just return the body.

      When this situation arises, a call to xhtmlContent.handleMacroDefinitions will result in the first MacroDefinition passed to the MacroDefinitionHandler.handle method being corrupted - the MacroDefinition will have no body, and all of the parameters of the child macros will be conflated into the corrupt definition.

      On the event, this bug caused the F4C (Forms for Confluence) migrator to attempt to migrate the content based on invalid data, and thus corrupted the pages.

      In the test, if we used the following storage format:

      <ac:structured-macro ac:name="simple-macro" ac:schema-version="1" ac:macro-id="dcbc25a6-6b81-40bf-9ef8-7a687af59538">
          <ac:parameter ac:name="simplemacroarg">arg</ac:parameter>
          <ac:rich-text-body>
              <p class="auto-cursor-target"><br/></p>
              <ac:structured-macro ac:name="other-macro" ac:schema-version="1" ac:macro-id="3caf2e75-1b55-48cf-9810-fa3884dd8f94">
                  <ac:parameter ac:name="othermacroarg">arg</ac:parameter>
                  <ac:rich-text-body>
                      <ac:structured-macro ac:name="warn" ac:schema-version="1" ac:macro-id="3caf2e75-1b55-48cf-9810-fa3884dd8f94">
                          <ac:parameter ac:name="icon">false</ac:parameter>
                          <ac:parameter ac:name="title">title</ac:parameter>
                          <ac:rich-text-body>
                              <p>this is some content</p></ac:rich-text-body>
                      </ac:structured-macro>
                  </ac:rich-text-body>
              </ac:structured-macro>
              <p class="auto-cursor-target"><br/></p>
              <ac:structured-macro ac:name="info" ac:schema-version="1" ac:macro-id="3caf2e75-1b55-48cf-9810-fa3884dd8f94">
                  <ac:parameter ac:name="icon">false</ac:parameter>
                  <ac:parameter ac:name="title">title</ac:parameter>
                  <ac:rich-text-body>
                      <p>this is some content</p></ac:rich-text-body>
              </ac:structured-macro>
              <p class="auto-cursor-target"><br/></p>
          </ac:rich-text-body>
      </ac:structured-macro>
      

      With both "Simple-macro" and "other-macro" enabled, we get these results from the test plugin (which iterates across the macro definitions found by XhtmlContent and outputs the parameters and values)

      [INFO] [talledLocalContainer] ----------------------------------
      [INFO] [talledLocalContainer] All macros enabled
      [INFO] [talledLocalContainer]
      [INFO] [talledLocalContainer] warn
      [INFO] [talledLocalContainer]     icon = false
      [INFO] [talledLocalContainer]     title = title
      [INFO] [talledLocalContainer]
      [INFO] [talledLocalContainer] other-macro
      [INFO] [talledLocalContainer]     othermacroarg = arg
      [INFO] [talledLocalContainer]
      [INFO] [talledLocalContainer] info
      [INFO] [talledLocalContainer]     icon = false
      [INFO] [talledLocalContainer]     title = title
      [INFO] [talledLocalContainer]
      [INFO] [talledLocalContainer] simple-macro
      [INFO] [talledLocalContainer]     simplemacroarg = arg
      [INFO] [talledLocalContainer]
      

      However, if the "other-macro" have it's module disabled, we see that the "warn" macro content disappears and the arguments are conflated ito the "other-macro" definition.

      [INFO] [talledLocalContainer] ----------------------------------
      [INFO] [talledLocalContainer] With other-macro disabled
      [INFO] [talledLocalContainer]
      [INFO] [talledLocalContainer] other-macro
      [INFO] [talledLocalContainer]     icon = false
      [INFO] [talledLocalContainer]     othermacroarg = arg
      [INFO] [talledLocalContainer]     title = title
      [INFO] [talledLocalContainer]
      [INFO] [talledLocalContainer] info
      [INFO] [talledLocalContainer]     icon = false
      [INFO] [talledLocalContainer]     title = title
      [INFO] [talledLocalContainer]
      [INFO] [talledLocalContainer] simple-macro
      [INFO] [talledLocalContainer]     simplemacroarg = arg
      [INFO] [talledLocalContainer]
      

      This will cause data loss on all pages that uses the disabled macro and a separate macro migration tries to use the XhtmlContent to convert markup to MacroDefinition objects so that they can be adjusted and then reformatted out to migrate the content to the new format.

      Workaround

      Reverting to the page last version fixes the problem, however not all pages have a previous version so it might require a manual intervention to restore an old backup into a staging instance and manually restore lost page contents to production.

        1. image2.png
          image2.png
          10 kB
        2. image1.png
          image1.png
          19 kB
        3. xhtml-weirdness.tar
          34 kB

            Assignee:
            Quan Pham
            Reporter:
            Rodrigo Girardi Adami
            Votes:
            4 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated:
              Resolved: