Repository navigation
EPBDS-16211: a security model and policy, a weekly audit of the bundled packages, and CI that keeps every master run - #205
Merged
Conversation
…ed packages, and CI that keeps every master run Security and CI items of the 2026-10-08 audit: - README: "Security model" says what a meta can do, each claim checked: a Text node renders the HTML of a dangerouslySetInnerHTML it is given, no URL scheme is checked, the built-in fetch action with mapArgs calls the page's fetch with the meta's URL, a data value is text unless a meta binds it to an attribute, and upload checks run in the browser only. SECURITY.md says how to report, and what is in scope. - npm run audit:bundled (scripts/audit-bundled.js) keeps the npm audit findings on the packages dist/sbom.cdx.json lists, at the version bundled. dependencies is empty, so npm audit --omit=dev audits nothing; a full npm audit reports the development tree. On 2026-10-09: 36 findings in the tree, 0 in the 19 bundled packages. .github/workflows/audit-bundled.yml runs it every Monday. - ci.yml cancels a superseded run on pull requests only. On master it cancelled the run before it: four PRs merged within a minute left three master commits with no finished run. - Every action is pinned to the commit its major tag pointed to, with the release in a comment Dependabot updates.
AlexSamBY
added a commit
that referenced
this pull request
Oct 13, 2026
## What Each push to master gets a CI run of its own. A push to master now has a concurrency group named by its commit (`github.sha`). A pull request's group is still its ref, and its newer push still cancels the run before it. ## Why #205 was not enough #205 stopped a push to master from cancelling the run in progress: `cancel-in-progress` is on for pull requests only. But a group still holds at most one running run and one pending run. GitHub cancels the pending one when another is queued, whatever `cancel-in-progress` says. From [GitHub's documentation](https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency): "any existing `pending` job or workflow in the same concurrency group will be canceled". It happened on 2026-10-12, when #214, #215 and #216 merged within two minutes: | commit | its run was created | what happened to it | |---|---|---| | 1b16e4d (#214) | 16:12:35 | ran until 16:18:20, success | | 5cb6bf6 (#215) | 16:13:29 | pending behind it; cancelled at 16:14:02 with no job started | | 1710577 (#216) | 16:14:01 | success | 5cb6bf6 is the case #205 set out to prevent: a master commit with no finished run. ## The change - **`.github/workflows/ci.yml`:** the group is `ci-${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}`. Master's runs no longer share a group, so none waits and none is cancelled; merges in quick succession run in parallel. The comment says why one group for the branch was not enough. - **Why not `queue: max`:** it keeps up to 100 pending runs per group, but GitHub's documentation says it cannot be combined with `cancel-in-progress: true`, which pull requests use. - **The changelog:** its entry said "CI cancels a run only when a newer push to the same pull request supersedes it". It now says that each master commit gets a run of its own. The same fix for release/v0.34's `ci-0.34.yml` is #218. ## Verified - The workflow parses (js-yaml). - For a push, the group comes out as `ci-CI-<sha>`; for a pull request, as `ci-CI-refs/pull/<n>/merge`. `&&` and `||` return one of their operands, the common way to pick a value in a workflow expression. This PR's own run evaluates the expression, so a syntax error would have kept it from starting. - This PR's own run uses the pull-request group, which is unchanged. The push groups show on the next merges in quick succession: each commit should get a finished run. ## Gates All 22 gates and the manifest contract exit 0 on HEAD, on Node 24.14.0. - The suite has 2875 tests. All pass on React 18 and 19. - On React 16.14 and 17, 2871 pass and #207's 4 transition tests are skipped, as before. - In the browser, the demo's 62 tests pass in Chromium on React 18 and 19, and so do the packed tarball's on React 16.14 to 19. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The security and CI items of the 2026-10-08 audit.
What a meta can do, written down
The README gains a Security model section. Each claim in it was checked against the code, and the two strongest also in a test run:
Textnode givendangerouslySetInnerHTML: {__html: '<b id="raw">raw</b>'}puts<b id="raw">in the page: through the published entry, in jsdom, it was found by id. No URL scheme is checked in an attribute a meta sets.fetch. WithmapArgs, the built-infetchaction calls the page'sfetchwith exactly the URL the meta names. With a stand-infetch, the call arrived as["https://example.test/mapped"]. Withargs, the click event goes first.{name: 'path'}.formatsandmaxSizefilter in the browser, anduploadFilereceives the files as chosen.downloadFile. The renderer only saves what that function answers.SECURITY.mdsays how to report a vulnerability and what is in scope: anything a data value can do, the published package and what it bundles, the stylesheet leaving.ui-render, and the build and CI. What a meta may do is out of scope.Before this merges, private vulnerability reporting needs turning on.
SECURITY.mdpoints reporters at it, andgh api repos/eisgroup/ui-render/private-vulnerability-reportinganswers{"enabled":false}. It is under Settings → Code security. The same API shows Dependabot security updates, secret scanning and push protection off too. Those are repository settings, so they are not changed here.The bundled packages, audited every week
npm run audit:bundled(scripts/audit-bundled.js) runsnpm auditand keeps only the findings on the packagesdist/sbom.cdx.jsonlists, at the version the bundle carries. That matters because:dependenciesis empty, sonpm audit --omit=devaudits nothing;npm auditreports the development tree.It fails on a finding at moderate or above.
.github/workflows/audit-bundled.ymlruns it on Mondays and on demand, not on pull requests, so a new advisory cannot turn an unrelated change red.CI
cancel-in-progressapplies to pull requests only. On master each push cancelled the run before it: on 2026-10-09 four PRs merged within a minute, and three of those master commits never finished a run (EPBDS-16211: the published package is driven in a browser on React 16.14, 17 and 19 too #200's 24a0900, EPBDS-16211: validateMeta finds the props a 0.34 host lost, and the meta contract agrees with the renderer on more shapes #201's 0fa9296, EPBDS-16211: unset refuses prototype paths, and a select with no label has an accessible name #202's a506f0b).Every action is pinned to a commit, the one its major tag points to (checked again on 2026-10-12), with the release in a trailing comment:
checkoutv7.0.1,setup-nodev7.1.0,cachev6.1.0,upload-artifactv7.0.2;usesinci.ymland 2 in the new workflow.Dependabot updates the commit and the comment together; GitHub documents this.
Measured
npm run audit:bundledon this branch: "npm audit: 36 finding(s) in the installed tree; 19 package(s) bundled, 0 of them with a finding.", exit 0. The plan's Appendix B now records 36, which it last counted as 35 on 2026-10-06.scripts/__tests__/audit-bundled.contract.test.js, 4 tests, covering:ci.ymlhas 7 jobs, andcancel-in-progressreads${{ github.event_name == 'pull_request' }}.🤖 Generated with Claude Code