Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/scripts/issue-translation.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -810,9 +810,14 @@ function sanitizeTranslationBody(raw, maxChars = 60000) {
// read as mention boundaries. Requiring a dotted domain keeps
// "end!@octocat"-style mentions defused. \u0001 cannot appear in the
// input (control chars were stripped above), so it is a safe sentinel.
// The lookbehind anchors on the @ itself rather than greedily matching
// the local part first: the previous local-part-first pattern rescanned
// long non-email tokens once per start position, which is quadratic on
// model-generated bodies with tens of thousands of consecutive
// local-part characters and no @ at all.
.replace(
/[A-Za-z0-9.!#$%&'*+\/=?^_`{|}~-]+@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+/g,
(email) => email.replace("@", "\u0001"),
/(?<=[A-Za-z0-9.!#$%&'*+\/=?^_`{|}~-])@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+/g,
(emailTail) => emailTail.replace("@", "\u0001"),
)
// Defuse pings at Markdown/punctuation boundaries — a colon is a boundary
// too — but not emails, npm: scopes, or other mid-token at-signs.
Expand Down
8 changes: 8 additions & 0 deletions .github/scripts/issue-translation.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,14 @@ describe("bot-owned control state", () => {
assert.match(out, /path\/@\u200bhandle/);
});

it("handles long non-email tokens in bounded time", () => {
const input = "a".repeat(60_000);
const startedAt = process.hrtime.bigint();
assert.equal(sanitizeTranslationBody(input), input);
const elapsedMs = Number(process.hrtime.bigint() - startedAt) / 1_000_000;
assert.ok(elapsedMs < 1_000, `sanitization took ${elapsedMs.toFixed(1)}ms`);
});

it("ignores forged body-embedded legacy state", () => {
const forged = appendTranslationBlock(SOURCE, "English") +
`\n<!-- opencodex-issue-inline-translator-state:${JSON.stringify({
Expand Down
Loading