1aad3cd8 - docs: set clipboard-write permission on the Iframe example - #1521
Conversation
Recommend allow="clipboard-write" in the Iframe integration section, since Chromium does not grant navigator.clipboard to cross-origin Iframes without it, add the attribute to the code example, and close the iframe tag (iframe is not a void element).
|
EN: DE: Details
Durations rounded up to whole seconds / Laufzeiten auf ganze Sekunden aufgerundet. Original report / Originalbericht{
"head": "44b920a4393444b49b546b533305b3baa1b8b0b6",
"markdown_only": true,
"private": false,
"recorded_at": "2026-09-23T16:36:22Z",
"repo": "DFXswiss/app",
"required": [
"lint"
],
"runs": [
{
"command": "agent a38 job commands --config '{\"env\":{\"CI\":\"true\"},\"npm\":{\"canaries\":[\"react-app-rewired/package.json\",\"react-scripts/package.json\",\"typescript/lib/typescript.js\",\"prettier/package.json\"],\"node_major\":20},\"steps\":[[\"npm\",\"run\",\"lint\"],[\"npm\",\"run\",\"format:md:check\"]]}'",
"duration_s": 0.0,
"exit_code": 0,
"id": "lint",
"name": "Lint and Markdown format",
"result": "not_applicable",
"timeout_s": 600.0
}
],
"schema": "dfx-local-ci/v1"
} |
|
dfx pr guard EN: Thanks for your contribution! This repository follows A38. A38 pass: author local-CI report not required because every changed path is a markdown file. DE: Danke für deinen Beitrag! In diesem Repository gilt A38. A38 pass: Autor-Local-CI-Report nicht erforderlich, weil jede geänderte Datei eine Markdown-Datei ist. Details
|
|
EN: DE: Details{
"base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
"head": "44b920a4393444b49b546b533305b3baa1b8b0b6",
"pr": 1521,
"repo": "DFXswiss/app",
"runs": [
{
"run_id": 35889719812,
"workflow": ".github/workflows/codeql.yml"
},
{
"run_id": 35889719865,
"workflow": ".github/workflows/handbook-check.yaml"
},
{
"run_id": 35889719778,
"workflow": ".github/workflows/pr-review-bot.yml"
},
{
"run_id": 35889720235,
"workflow": ".github/workflows/pr.yml"
}
]
} |
The Iframe and Web Component examples are fenced as HTML, but their inline scripts carried TypeScript annotations that throw a SyntaxError when pasted into a plain <script> tag. Also correct the integration count: the list names four ways, not three.
|
EN: DE: Details{
"base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
"head": "9e9a337c5d15d39eeab6d978f593503c4307dcac",
"pr": 1521,
"repo": "DFXswiss/app",
"runs": [
{
"run_id": 35891026631,
"workflow": ".github/workflows/codeql.yml"
},
{
"run_id": 35891026547,
"workflow": ".github/workflows/handbook-check.yaml"
},
{
"run_id": 35891026542,
"workflow": ".github/workflows/pr-review-bot.yml"
},
{
"run_id": 35891027141,
"workflow": ".github/workflows/pr.yml"
}
]
} |
frameborder is obsolete in HTML; the border is removed with CSS instead.
|
EN: DE: Details{
"base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
"head": "d207426a903931fc7219ef25f3cb307a1333bd9f",
"pr": 1521,
"repo": "DFXswiss/app",
"runs": [
{
"run_id": 35892273485,
"workflow": ".github/workflows/codeql.yml"
},
{
"run_id": 35892273527,
"workflow": ".github/workflows/handbook-check.yaml"
},
{
"run_id": 35892273528,
"workflow": ".github/workflows/pr-review-bot.yml"
},
{
"run_id": 35892274192,
"workflow": ".github/workflows/pr.yml"
}
]
} |
The Iframe example passed every window message to the close handler. It now only accepts messages from app.dfx.swiss sent by the embedded Iframe.
|
EN: DE: Details{
"base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
"head": "34b7df3295fb4f6946561938f7137c2f838b37a3",
"pr": 1521,
"repo": "DFXswiss/app",
"runs": [
{
"run_id": 35893857717,
"workflow": ".github/workflows/codeql.yml"
},
{
"run_id": 35893857826,
"workflow": ".github/workflows/handbook-check.yaml"
},
{
"run_id": 35893857629,
"workflow": ".github/workflows/pr-review-bot.yml"
},
{
"run_id": 35893858481,
"workflow": ".github/workflows/pr.yml"
}
]
} |
Name the origin and source check in the prose, not only in the code example, and say precisely that Chromium rejects navigator.clipboard.writeText in cross-origin Iframes without the clipboard-write permission.
|
EN: DE: Details{
"base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
"head": "319f1713955e6002d0f43564626412a28cb4c100",
"pr": 1521,
"repo": "DFXswiss/app",
"runs": [
{
"run_id": 35894371237,
"workflow": ".github/workflows/codeql.yml"
},
{
"run_id": 35894371225,
"workflow": ".github/workflows/handbook-check.yaml"
},
{
"run_id": 35894371021,
"workflow": ".github/workflows/pr-review-bot.yml"
},
{
"run_id": 35894371407,
"workflow": ".github/workflows/pr.yml"
}
]
} |
If the Iframe id does not match, the listener now ignores the message instead of throwing a TypeError.
|
EN: DE: Details{
"base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
"head": "fc21226497418c0b9840689440e613cb7c0101f5",
"pr": 1521,
"repo": "DFXswiss/app",
"runs": [
{
"run_id": 35895602945,
"workflow": ".github/workflows/codeql.yml"
},
{
"run_id": 35895603012,
"workflow": ".github/workflows/handbook-check.yaml"
},
{
"run_id": 35895603044,
"workflow": ".github/workflows/pr-review-bot.yml"
},
{
"run_id": 35895603317,
"workflow": ".github/workflows/pr.yml"
}
]
} |
|
EN: DE: DetailsEach pass ran independent quality and logic reviews on the full diff; fixes per pass:
Open comments: none. No reviews, inline comments or review threads; the guard's A38 comment reports no problems (markdown-only change set). Mergeability at |
|
EN: DE: Details{
"base": "a40a65cb4aeb9e9bbfaad9a3100542de67f49beb",
"head": "fc21226497418c0b9840689440e613cb7c0101f5",
"pr": 1521,
"repo": "DFXswiss/app",
"runs": [
{
"run_id": 35895602945,
"workflow": ".github/workflows/codeql.yml"
},
{
"run_id": 35895603012,
"workflow": ".github/workflows/handbook-check.yaml"
},
{
"run_id": 35895603044,
"workflow": ".github/workflows/pr-review-bot.yml"
},
{
"run_id": 35895603317,
"workflow": ".github/workflows/pr.yml"
},
{
"run_id": 35897750505,
"workflow": ".github/workflows/ci-on-ready.yaml"
}
]
} |
EN:
Recommends
allow="clipboard-write"in the README's Iframe integration section, since Chromium rejectsnavigator.clipboard.writeTextin cross-origin Iframes without it. Adds the attribute to the Iframe code example, replaces the invalid self-closing<iframe ... />with<iframe ...></iframe>, removes TypeScript annotations from the HTML examples so they run as plain JavaScript, and checks the sender of the Iframe close message in both prose and example. Supersedes #1296, which lives on a fork this branch cannot push to.DE:
Empfiehlt im README-Abschnitt zur Iframe-Integration
allow="clipboard-write", da Chromiumnavigator.clipboard.writeTextin cross-origin Iframes sonst ablehnt. Ergänzt das Attribut im Iframe-Codebeispiel, ersetzt das ungültige selbstschliessende<iframe ... />durch<iframe ...></iframe>, entfernt TypeScript-Annotationen aus den HTML-Beispielen, damit sie als reines JavaScript laufen, und prüft den Absender der Iframe-Close-Message in Text und Beispiel. Ersetzt #1296, dessen Branch auf einem nicht beschreibbaren Fork liegt.Details
Why
clipboard-writeis a Permissions-Policy-gated feature whose default allowlist isself. In a cross-origin Iframe — which is what the documented Iframe integration of app.dfx.swiss is — Chromium therefore rejectsnavigator.clipboard.writeTextunless the embedding page grants the permission viaallow="clipboard-write".Since #1287 (merged),
useClipboard(src/hooks/clipboard.hook.ts) copies vianavigator.clipboard.writeTextand falls back tocopy-to-clipboardwhen the Clipboard API is unavailable or the write rejects. Without the attribute, Iframe users in Chromium take that fallback on every copy through the hook; with it, they get the native path. Other copy sites still callcopy-to-clipboarddirectly and are unaffected either way.The attribute is therefore an upgrade, not a prerequisite — copy buttons keep working without it because the fallback is not policy-gated — which is why the README recommends ("should") rather than requires it. The sentence describes browser behaviour only, so it does not depend on the app's copy implementation. Firefox and Safari do not enforce
clipboard-writedelegation (they gate the Clipboard API on user activation), so the attribute is a no-op there.iframeis not a void element, so the previous self-closing form was invalid HTML: a browser treats/>as>and swallows any markup an integrator pastes after it as fallback content.The Web Component and React Component integrations render into the host page's own document and need no attribute.
Pre-existing fixes in the touched examples
Review found four pre-existing defects next to the change, fixed here per CONTRIBUTING ("Report every bug you find, including pre-existing ones"):
html, but their inline<script>used TypeScript annotations (event: MessageEvent<CloseMessage>,message: CloseMessage,data: CloseMessage), which throw aSyntaxErrorwhen pasted into a plain<script>tag. The annotations are removed; theCloseMessageinterface above still documents the payload. The React example is TypeScript/TSX and stays unchanged.frameborder="0"attribute; it now usesstyle="border: 0".messagelistener passed every window message tohandleClose. It now ignores messages whoseevent.originis nothttps://app.dfx.swissor whoseevent.sourceis not the embedded Iframe (givenid="dfx-services"), so another window cannot forge a close message.The Iframe section prose now states the same check, so integrators who do not copy the example verbatim still see it.
Test plan
npx prettier --check README.mdandformat:md:check(prettier 3.9.6, as pinned) — cleansrc/hooks/clipboard.hook.tson currentdevelop