paperclip/patches/@chat-adapter__github@4.39....

100 lines
3.6 KiB
Diff

diff --git a/dist/index.js b/dist/index.js
index 32d5ca33adadd3928983ae76d78949190320cdab..056ab06ceb047e4bb08c2b0dacfd8b2a41540ec1 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -8,7 +8,7 @@ import {
} from "@chat-adapter/shared";
import { createAppAuth } from "@octokit/auth-app";
import { Octokit } from "@octokit/rest";
-import { ConsoleLogger, convertEmojiPlaceholders, Message } from "chat";
+import { ConsoleLogger, convertEmojiPlaceholders, Message, toPlainText } from "chat";
// src/cards.ts
import { renderGfmTable } from "@chat-adapter/shared";
@@ -144,6 +144,55 @@ var GitHubFormatConverter = class extends BaseFormatConverter {
}
};
+// GitHub comments commonly represent uploaded files as Markdown images. The
+// shared plain-text converter preserves their label but drops the destination,
+// which makes the uploaded artifact impossible to recover downstream. Append
+// a bounded set of safe HTTPS destinations without treating them as fetchable
+// attachments or retaining credential-bearing URLs.
+function safeGitHubMarkdownUrl(value) {
+ if (typeof value !== "string" || value.length === 0 || value.length > 2048) {
+ return null;
+ }
+ let parsed;
+ try {
+ parsed = new URL(value);
+ } catch {
+ return null;
+ }
+ if (parsed.protocol !== "https:" || parsed.username || parsed.password) {
+ return null;
+ }
+ return parsed.href;
+}
+function normalizedGitHubCommentText(formatted) {
+ const plainText = toPlainText(formatted);
+ const urls = [];
+ const seen = /* @__PURE__ */ new Set();
+ const stack = [formatted];
+ let visited = 0;
+ while (stack.length > 0 && urls.length < 32 && visited < 1e4) {
+ const node = stack.pop();
+ visited += 1;
+ if (node && typeof node === "object") {
+ if (node.type === "link" || node.type === "image" || node.type === "definition") {
+ const url = safeGitHubMarkdownUrl(node.url);
+ if (url && !seen.has(url)) {
+ seen.add(url);
+ urls.push(url);
+ }
+ }
+ if (Array.isArray(node.children)) {
+ for (let index = node.children.length - 1; index >= 0; index -= 1) {
+ stack.push(node.children[index]);
+ }
+ }
+ }
+ }
+ const missingUrls = urls.filter((url) => !plainText.includes(url));
+ if (missingUrls.length === 0) return plainText;
+ return [plainText, ...missingUrls].filter(Boolean).join("\n");
+}
+
// src/index.ts
var REVIEW_COMMENT_THREAD_PATTERN = /^([^/]+)\/([^:]+):(\d+):rc:(\d+)$/;
var ISSUE_THREAD_PATTERN = /^([^/]+)\/([^:]+):issue:(\d+)$/;
@@ -677,11 +726,12 @@ var GitHubAdapter = class {
*/
parseIssueComment(comment, repository, prNumber, threadId, threadType = "pr") {
const author = this.parseAuthor(comment.user);
+ const formatted = this.formatConverter.toAst(comment.body);
return new Message({
id: comment.id.toString(),
threadId,
- text: this.formatConverter.extractPlainText(comment.body),
- formatted: this.formatConverter.toAst(comment.body),
+ text: normalizedGitHubCommentText(formatted),
+ formatted,
raw: {
type: "issue_comment",
comment,
@@ -709,11 +759,12 @@ var GitHubAdapter = class {
*/
parseReviewComment(comment, repository, prNumber, threadId) {
const author = this.parseAuthor(comment.user);
+ const formatted = this.formatConverter.toAst(comment.body);
return new Message({
id: comment.id.toString(),
threadId,
- text: this.formatConverter.extractPlainText(comment.body),
- formatted: this.formatConverter.toAst(comment.body),
+ text: normalizedGitHubCommentText(formatted),
+ formatted,
raw: {
type: "review_comment",
comment,