Browse Source

security(frontend): pin js-yaml to 5.4.1+

    Raise the js-yaml override from ^5.2.3 to ^5.4.1. Versions up to 5.4.0
    do not count empty mappings towards maxTotalMergeKeys, so a small YAML
    file can keep the CPU busy for a long time. js-yaml is a dev-only
    transitive dependency of eslint and only parses our own ESLint configs.
maziggy 3 days ago
parent
commit
3d2f737de2
5 changed files with 137 additions and 4 deletions
  1. 2 0
      .gitignore
  2. 0 0
      CHANGELOG.md
  3. 131 0
      feature_votes.sh
  4. 3 3
      frontend/package-lock.json
  5. 1 1
      frontend/package.json

+ 2 - 0
.gitignore

@@ -103,3 +103,5 @@ test_pipeline_run_1.3mf
 .coverage
 .coverage.*
 htmlcov/
+
+feature_votes.sh

File diff suppressed because it is too large
+ 0 - 0
CHANGELOG.md


+ 131 - 0
feature_votes.sh

@@ -0,0 +1,131 @@
+#!/bin/bash
+# Rank open enhancement issues by community thumbs-up votes.
+#
+# A vote is a 👍 on the issue itself or on the "gauge community interest"
+# comment. Each person counts once, and the issue author and the maintainer
+# are left out. Read-only: it only queries the GitHub API through gh.
+#
+# Usage: ./feature_votes.sh --help
+
+set -euo pipefail
+
+show_help() {
+    cat <<'EOF'
+Usage: ./feature_votes.sh [options] [limit]
+
+Rank open enhancement issues (without the contrib label) by thumbs-up votes.
+
+Arguments:
+  limit         Show only the top N issues (default: all)
+
+Options:
+  --md          Print a Markdown table with issue links
+  -h, --help    Show this help message
+
+Columns:
+  votes         Different people who voted on the issue or the poll comment,
+                without the issue author and the maintainer (ranked by this)
+  on issue      Thumbs-up on the issue itself
+  on poll       Thumbs-up on the "gauge community interest" comment
+                ("-" when the issue has no such comment)
+
+Examples:
+  ./feature_votes.sh            All issues
+  ./feature_votes.sh 20         Top 20
+  ./feature_votes.sh --md 20    Top 20 as Markdown
+EOF
+}
+
+FORMAT=text
+LIMIT=0
+while [[ $# -gt 0 ]]; do
+    case "$1" in
+        -h|--help) show_help; exit 0 ;;
+        --md) FORMAT=md ;;
+        *[!0-9]*|"")
+            echo "Unknown option: $1" >&2
+            echo "Run ./feature_votes.sh --help for usage." >&2
+            exit 1
+            ;;
+        *) LIMIT="$1" ;;
+    esac
+    shift
+done
+
+command -v gh >/dev/null || { echo "gh (GitHub CLI) is required" >&2; exit 1; }
+gh auth status >/dev/null 2>&1 || { echo "gh is not logged in; run: gh auth login" >&2; exit 1; }
+
+FORMAT="$FORMAT" LIMIT="$LIMIT" python3 - <<'PY'
+import json
+import os
+import subprocess
+
+REPO = "maziggy/bambuddy"
+MAINTAINER = "maziggy"
+SEARCH = f"repo:{REPO} is:issue state:open label:enhancement -label:contrib"
+POLL_MARKER = "I'd like to gauge community interest"
+QUERY = """
+query($q: String!, $after: String) {
+  search(query: $q, type: ISSUE, first: 30, after: $after) {
+    issueCount
+    pageInfo { hasNextPage endCursor }
+    nodes {
+      ... on Issue {
+        number title url author { login }
+        reactions(content: THUMBS_UP, first: 100) { nodes { user { login } } }
+        comments(first: 100) {
+          totalCount
+          nodes { body reactions(content: THUMBS_UP, first: 100) { nodes { user { login } } } }
+        }
+      }
+    }
+  }
+}
+"""
+
+
+def voters(reactions):
+    return {r["user"]["login"] for r in reactions["nodes"] if r["user"]}
+
+
+rows, after, total, truncated = [], None, 0, 0
+while True:
+    args = ["gh", "api", "graphql", "-f", f"query={QUERY}", "-f", f"q={SEARCH}"]
+    if after:
+        args += ["-f", f"after={after}"]
+    page = json.loads(subprocess.check_output(args))["data"]["search"]
+    total = page["issueCount"]
+    for issue in page["nodes"]:
+        body = voters(issue["reactions"])
+        poll, has_poll = set(), False
+        for comment in issue["comments"]["nodes"]:
+            if POLL_MARKER in (comment["body"] or ""):
+                has_poll = True
+                poll |= voters(comment["reactions"])
+        if issue["comments"]["totalCount"] > 100:
+            truncated += 1
+        author = (issue["author"] or {}).get("login")
+        votes = len((body | poll) - {author, MAINTAINER})
+        rows.append((votes, len(body), len(poll) if has_poll else None, issue["number"], issue["title"], issue["url"]))
+    if not page["pageInfo"]["hasNextPage"]:
+        break
+    after = page["pageInfo"]["endCursor"]
+
+rows.sort(key=lambda r: (-r[0], -r[1], r[3]))
+limit = int(os.environ["LIMIT"])
+shown = rows[:limit] if limit > 0 else rows
+
+print(f"{total} open enhancement issues, {sum(r[2] is not None for r in rows)} with a poll comment, "
+      f"{sum(r[0] == 0 for r in rows)} without outside votes")
+if truncated:
+    print(f"Note: {truncated} issues have more than 100 comments; only the first 100 were checked")
+print()
+if os.environ["FORMAT"] == "md":
+    print("| votes | on issue | on poll | issue |\n|---:|---:|---:|---|")
+    for votes, body, poll, number, title, url in shown:
+        print(f"| {votes} | {body} | {'-' if poll is None else poll} | [#{number}]({url}) {title.replace('|', '/')} |")
+else:
+    print(f"{'votes':>5} {'on issue':>8} {'on poll':>7}  issue")
+    for votes, body, poll, number, title, _ in shown:
+        print(f"{votes:>5} {body:>8} {'-' if poll is None else poll:>7}  #{number} {title}")
+PY

+ 3 - 3
frontend/package-lock.json

@@ -5141,9 +5141,9 @@
       "license": "MIT"
     },
     "node_modules/js-yaml": {
-      "version": "5.2.3",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.2.3.tgz",
-      "integrity": "sha512-n+mUVyUX5bVv7G/G2zyIHOhdxfuU1dY2NOFzTQUWiMUbFss8b57NFlgCCaggU78wSw5KVS9cllzeLyzyR+n5nw==",
+      "version": "5.4.2",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.4.2.tgz",
+      "integrity": "sha512-m+aqu+LwO1O6sIopafj8HUVl5aawITwZQe/yHpMCKjaWBaA/d07B/QdMb3529REftiU+RMMHL3Vlsw3hON7vWg==",
       "dev": true,
       "funding": [
         {

+ 1 - 1
frontend/package.json

@@ -61,7 +61,7 @@
   "overrides": {
     "minimatch": "^10.2.1",
     "brace-expansion": "^5.0.9",
-    "js-yaml": "^5.2.3",
+    "js-yaml": "^5.4.1",
     "nanoid": "^3.3.18",
     "react-router": "7.18.2"
   },

Some files were not shown because too many files changed in this diff