From f63dcefd2feeb098c545abc631846ffb595961da Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 28 Aug 2026 23:47:34 +0000 Subject: [PATCH 1/2] Close the family-nav host check at the slash `startsWith(BASE)` is a prefix test on a URL, and a host name may continue where the prefix stops: `https://abap2ui5.github.io.example.com/samples/` starts with `https://abap2ui5.github.io` and was therefore collected as one of "our" links and compared, in order, against the wanted list. The check that exists to say which three pages the bar links to would have counted a link to somebody else as one of them. With the trailing slash the host is closed and the prefix can only match this origin. Every real link already carries it, so nothing about the current pages changes - this is the case the check could not have caught. The body is shared with abap2UI5/.github/shared/check-family-nav.mjs and the two sibling repositories; it is changed in all four or in none. --- scripts/check-family-nav.mjs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/check-family-nav.mjs b/scripts/check-family-nav.mjs index 83a2eba..716f7c8 100644 --- a/scripts/check-family-nav.mjs +++ b/scripts/check-family-nav.mjs @@ -53,6 +53,14 @@ const PAGES = [ const TOOLS = [`${BASE}/playground/`, `${BASE}/docs/`]; +/* Our own origin, with the trailing slash, for the "is this one of ours?" + * filter below. The slash is not cosmetic: a host name may continue where a + * prefix stops, so `startsWith(BASE)` also accepts + * `https://abap2ui5.github.io.example.com/samples/` - a link to somebody + * else entirely, counted as one of the three and compared against the wanted + * list as if it were. With the slash the host is closed. */ +const OURS = `${BASE}/`; + /* The catalogue moved to the root of its Pages site when the in-browser demo * was dropped, so this address is a 404 and stayed in one footer for a while. * Nothing may link to it again. */ @@ -101,7 +109,7 @@ if (!three) fail(`${PAGE_HTML}: no three-pages:start / three-pages:end block`); if (nav) { const want = [...PAGES.map((p) => p.url), ...TOOLS]; - const got = hrefs(nav).filter((h) => h.startsWith(BASE)); + const got = hrefs(nav).filter((h) => h.startsWith(OURS)); if (got.join(' ') !== want.join(' ')) { fail(`the bar links to\n ${got.join('\n ')}\n but must link, in this order, to\n ${want.join('\n ')}`); } @@ -122,7 +130,7 @@ if (nav) { if (three) { const want = PAGES.map((p) => p.url); - const got = hrefs(three).filter((h) => h.startsWith(BASE)); + const got = hrefs(three).filter((h) => h.startsWith(OURS)); if (got.join(' ') !== want.join(' ')) { fail(`the three-pages strip links to\n ${got.join('\n ')}\n but must link, in this order, to\n ${want.join('\n ')}`); } From 1126fa38a704398e027afab9f8cc2425af4713fd Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 28 Aug 2026 23:49:55 +0000 Subject: [PATCH 2/2] Identify the framework dependency by its url value, not by a substring `A2UI5_URL_RE` was `/github\.com\/abap2UI5\/abap2UI5/`, tested against a whole `{...}` slice of a "dependencies" array. It matched anywhere in the slice and it stopped at the repository name without closing it, so `https://github.com/abap2UI5/abap2UI5-local` - a different repository in the same organisation, and a plausible thing for an abaplint config to depend on - was read as the framework and had its "branch" key checked, allowlisted and reported as if it were. Anchoring at the `"url"` key and closing at the quote leaves only the framework. Output is byte-identical on every config in this repository today (same entry counts, same release, same allowlisted pins); the difference is the entry that does not exist yet. CodeQL reports the old form as js/regex/missing-regexp-anchor, high severity. The file is byte-identical with abap2UI5/.github/shared/check-framework-pin.mjs and the sibling copy, and is synced from there - changed in all three or in none. --- scripts/check-framework-pin.mjs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/check-framework-pin.mjs b/scripts/check-framework-pin.mjs index b9731d5..c038faa 100644 --- a/scripts/check-framework-pin.mjs +++ b/scripts/check-framework-pin.mjs @@ -61,7 +61,16 @@ const ALLOWED_BRANCHES = new Map([ ['.github/abaplint/abap_702.jsonc', '702'], ]); -const A2UI5_URL_RE = /github\.com\/abap2UI5\/abap2UI5/i; +/* The framework dependency, identified by its url VALUE rather than by a + * substring of the entry. + * + * `/github\.com\/abap2UI5\/abap2UI5/` matched anywhere in the object slice and + * stopped at the repository name without closing it, so + * `https://github.com/abap2UI5/abap2UI5-local` - a different repository in + * the same organisation, and a plausible thing for a config to depend on - + * was read as the framework and had its "branch" key checked as if it were. + * Anchoring at the key and closing at the quote leaves only the framework. */ +const A2UI5_URL_RE = /"url"\s*:\s*"https:\/\/github\.com\/abap2UI5\/abap2UI5(?:\.git)?\/?"/i; const RELEASE_RE = /^\d+\.\d+\.\d+$/; let errors = 0;