Skip to content

fix: handle undefined author in plugins and remove deprecated Projects API#1777

Closed
artik0din wants to merge 4 commits intolowlighter:masterfrom
globodai-group:fix/plugin-bugs
Closed

fix: handle undefined author in plugins and remove deprecated Projects API#1777
artik0din wants to merge 4 commits intolowlighter:masterfrom
globodai-group:fix/plugin-bugs

Conversation

@artik0din
Copy link
Copy Markdown

Summary

This PR fixes three bugs causing plugin crashes:

  • achievements plugin: Remove deprecated GitHub Projects (classic) API usage. GitHub sunset this API in May 2024 (announcement), causing GraphqlResponseError when generating metrics.

  • habits plugin: Add null check for commits without author property. Some PushEvent commits may not have author set, causing TypeError: Cannot destructure property 'author' of 'undefined'.

  • activity plugin: Fix filter that destructures author.email directly. Added null check to prevent TypeError when author is undefined.

Changes

  • source/plugins/achievements/queries/achievements.graphql: Commented out deprecated projects field
  • source/plugins/achievements/list/users.mjs: Disabled "Manager" achievement that relied on Projects API
  • source/plugins/habits/index.mjs: Added .filter(commit => commit && commit.author) before processing
  • source/plugins/activity/index.mjs: Changed destructuring to explicit null check

Test plan

  • Generate metrics with achievements plugin enabled
  • Generate metrics with habits plugin enabled
  • Generate metrics with activity plugin enabled
  • Verify no errors on accounts with commits missing author metadata

🤖 Generated with Claude Code

GitHub deprecated Projects (classic) in May 2024. This removes the
projects field from the GraphQL query and disables the Manager
achievement that depended on it.

See: https://github.blog/changelog/2024-05-23-sunset-notice-projects-classic/
Some commits from PushEvents may not have an author property set.
This adds a null check to prevent TypeError when destructuring.
The filter on line 140 destructured author.email directly, causing
a TypeError when author is undefined. This adds a null check before
accessing the email property.
- Add Dockerfile.web for web server mode
- Add heroku.yml for container deployment
- Add Procfile as fallback
- Support METRICS_TOKEN and PORT environment variables
@diffray-bot
Copy link
Copy Markdown

Changes Summary

This PR fixes three critical plugin bugs that cause crashes: removes deprecated GitHub Projects API usage from achievements plugin, adds null checks for commits missing author metadata in habits and activity plugins, and adds Docker/Heroku deployment configuration with environment variable support.

Type: bugfix

Components Affected: achievements plugin, habits plugin, activity plugin, web deployment/configuration

Files Changed
File Summary Change Impact
...ugins/achievements/queries/achievements.graphql Commented out deprecated GitHub Projects (classic) GraphQL field query that was sunset in May 2024 ✏️ 🔴
...pace/source/plugins/achievements/list/users.mjs Disabled 'Manager' achievement that relied on deprecated Projects API with explanatory comments referencing GitHub sunset notice ✏️ 🔴
/tmp/workspace/source/plugins/habits/index.mjs Added defensive null check filter to prevent TypeError when commits lack author property ✏️ 🔴
/tmp/workspace/source/plugins/activity/index.mjs Changed destructuring assignment to explicit null check before accessing author.email property ✏️ 🔴
/tmp/workspace/source/app/metrics/setup.mjs Added environment variable support for PORT and METRICS_TOKEN configuration with fallback defaults ✏️ 🟡
/tmp/workspace/Dockerfile.web New Docker configuration for containerized deployment with Node.js, Chrome, Deno, Ruby, and Python dependencies 🟡
/tmp/workspace/Procfile Heroku process file specifying npm start command for web dyno 🟢
/tmp/workspace/heroku.yml Heroku stack definition pointing to custom Dockerfile.web for containerized deployment 🟢
Architecture Impact
  • New Patterns: defensive null checks for external API data, environment-based configuration
  • Coupling: Reduced coupling to deprecated GitHub API by removing Projects (classic) dependency from achievements plugin
  • Breaking Changes: Manager achievement removed - users relying on this badge will no longer see it, API behavior change: commits without author metadata now filtered silently instead of causing crash

Risk Areas: Silent filtering of commits without author in habits and activity plugins - may mask data quality issues, Disabled Manager achievement represents lost functionality for users who created projects, Docker image includes multiple language runtimes (Node, Deno, Ruby, Python) increasing attack surface, Environment variable configuration (METRICS_TOKEN) requires secure secret management in Heroku/Docker deployment

Suggestions
  • Add logging when commits are filtered due to missing author to aid debugging
  • Document the Manager achievement removal in release notes/changelog
  • Consider adding metrics for how many commits are filtered out due to missing author
  • Validate that environment variable configuration works correctly in CI/CD pipeline

Full review in progress... | Powered by diffray


if (!conf.settings.templates)
conf.settings.templates = {default: "classic", enabled: []}
if (!conf.settings.plugins)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 CRITICAL - JSON.parse without try-catch for package.json
Agent: bugs

Category: bug

Description:
JSON.parse() can throw a SyntaxError if package.json contains invalid JSON, but this operation is not wrapped in a try-catch block. The previous try-catch block ended at line 64, leaving this JSON.parse unprotected.

Suggestion:
Wrap the JSON.parse operation in a try-catch block, similar to the pattern used for settings.json in lines 46-64.

Why this matters: Unhandled errors crash the application or hide bugs.

Confidence: 92%
Rule: bug_missing_try_catch
Review ID: 8aeb9742-af0a-4aae-8c5e-a98c17691acc
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

Comment on lines +37 to +38
# Run web server
CMD ["npm", "start"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 HIGH - Missing HEALTHCHECK in Docker container
Agent: bugs

Category: bug

Description:
The Dockerfile does not include a HEALTHCHECK instruction. Without it, Docker orchestrators cannot automatically detect if the application is unhealthy.

Suggestion:
Add a HEALTHCHECK instruction to monitor the application health, e.g., HEALTHCHECK --interval=30s --timeout=5s CMD node -e "require('http').get('http://localhost:3000', (r) => {if (r.statusCode !== 200) throw new Error()})"

Why this matters: Missing healthcheck prevents automatic recovery from application failures.

Confidence: 85%
Rule: docker_missing_healthcheck
Review ID: 8aeb9742-af0a-4aae-8c5e-a98c17691acc
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

FROM node:20-bookworm-slim

# Copy repository
COPY . /metrics
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 HIGH - Docker cache invalidation: COPY all files before dependency install
Agent: microservices

Category: quality

Description:
COPY . /metrics copies all source files before dependency installation, which will invalidate the Docker layer cache on every code change, triggering rebuilding of expensive layers like apt packages and npm dependencies.

Suggestion:
First copy only dependency manifest files (package.json, package-lock.json) before RUN npm ci, then copy the remaining source files after installation.

Why this matters: Any file change invalidates cached npm install layer.

Confidence: 95%
Rule: docker_copy_before_install
Review ID: 8aeb9742-af0a-4aae-8c5e-a98c17691acc
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

Comment on lines +1 to +38
# Base image
FROM node:20-bookworm-slim

# Copy repository
COPY . /metrics
WORKDIR /metrics

# Setup
RUN chmod +x /metrics/source/app/action/index.mjs \
# Install latest chrome dev package, fonts to support major charsets and skip chromium download on puppeteer install
# Based on https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#running-puppeteer-in-docker
&& apt-get update \
&& apt-get install -y wget gnupg ca-certificates libgconf-2-4 \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 libx11-xcb1 libxtst6 lsb-release --no-install-recommends \
# Install deno for miscellaneous scripts
&& apt-get install -y curl unzip \
&& curl -fsSL https://deno.land/x/install/install.sh | DENO_INSTALL=/usr/local sh \
# Install ruby to support github licensed gem
&& apt-get install -y ruby-full git g++ cmake pkg-config libssl-dev \
&& gem install licensed \
# Install python for node-gyp
&& apt-get install -y python3 \
# Clean apt/lists
&& rm -rf /var/lib/apt/lists/* \
# Install node modules and rebuild indexes
&& npm ci \
&& npm run build

# Environment variables
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
ENV PUPPETEER_BROWSER_PATH="google-chrome-stable"
ENV NODE_ENV=production

# Run web server
CMD ["npm", "start"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 HIGH - Container runs as root user
Agent: security

Category: security

Description:
The Dockerfile does not specify a USER instruction. Docker containers without an explicit non-root user will run as root (UID 0), increasing blast radius if the container is compromised.

Suggestion:
Add a USER instruction to run the container as a non-root user. Create a dedicated user with RUN useradd -m -u 1000 appuser && USER appuser

Why this matters: Root in container may have elevated privileges on host depending on configuration.

Confidence: 95%
Rule: docker_running_as_root
Review ID: 8aeb9742-af0a-4aae-8c5e-a98c17691acc
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

Comment on lines +1 to +38
# Base image
FROM node:20-bookworm-slim

# Copy repository
COPY . /metrics
WORKDIR /metrics

# Setup
RUN chmod +x /metrics/source/app/action/index.mjs \
# Install latest chrome dev package, fonts to support major charsets and skip chromium download on puppeteer install
# Based on https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#running-puppeteer-in-docker
&& apt-get update \
&& apt-get install -y wget gnupg ca-certificates libgconf-2-4 \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 libx11-xcb1 libxtst6 lsb-release --no-install-recommends \
# Install deno for miscellaneous scripts
&& apt-get install -y curl unzip \
&& curl -fsSL https://deno.land/x/install/install.sh | DENO_INSTALL=/usr/local sh \
# Install ruby to support github licensed gem
&& apt-get install -y ruby-full git g++ cmake pkg-config libssl-dev \
&& gem install licensed \
# Install python for node-gyp
&& apt-get install -y python3 \
# Clean apt/lists
&& rm -rf /var/lib/apt/lists/* \
# Install node modules and rebuild indexes
&& npm ci \
&& npm run build

# Environment variables
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
ENV PUPPETEER_BROWSER_PATH="google-chrome-stable"
ENV NODE_ENV=production

# Run web server
CMD ["npm", "start"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 HIGH - Single-stage Docker build leaves build tools in production
Agent: security

Category: security

Description:
The Dockerfile uses a single-stage build pattern. Build dependencies (npm, python3, ruby, g++, cmake, git, deno, curl, unzip) are included in the final production image, increasing attack surface and image size.

Suggestion:
Use multi-stage Docker build with 'AS' aliases. Separate build stage from runtime stage. Only copy necessary runtime artifacts from build stage using 'COPY --from=build'.

Why this matters: Security issues can lead to data breaches.

Confidence: 90%
Rule: docker_implement_multi_stage_builds_for_product
Review ID: 8aeb9742-af0a-4aae-8c5e-a98c17691acc
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

Comment on lines +5 to +30
COPY . /metrics
WORKDIR /metrics

# Setup
RUN chmod +x /metrics/source/app/action/index.mjs \
# Install latest chrome dev package, fonts to support major charsets and skip chromium download on puppeteer install
# Based on https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#running-puppeteer-in-docker
&& apt-get update \
&& apt-get install -y wget gnupg ca-certificates libgconf-2-4 \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 libx11-xcb1 libxtst6 lsb-release --no-install-recommends \
# Install deno for miscellaneous scripts
&& apt-get install -y curl unzip \
&& curl -fsSL https://deno.land/x/install/install.sh | DENO_INSTALL=/usr/local sh \
# Install ruby to support github licensed gem
&& apt-get install -y ruby-full git g++ cmake pkg-config libssl-dev \
&& gem install licensed \
# Install python for node-gyp
&& apt-get install -y python3 \
# Clean apt/lists
&& rm -rf /var/lib/apt/lists/* \
# Install node modules and rebuild indexes
&& npm ci \
&& npm run build
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM - Copying entire project directory into production image
Agent: security

Category: security

Description:
Line 5 copies the entire project directory (COPY . /metrics) into the production image. This includes test files, source code, documentation, and git files that are unnecessary at runtime.

Suggestion:
Use .dockerignore to exclude unnecessary files (tests, docs, source, .git, .env files). Consider using multi-stage build where only necessary runtime artifacts are copied.

Why this matters: Smaller images pull faster, have fewer vulnerabilities, and reduce secrets exposure.

Confidence: 80%
Rule: docker_remove_unnecessary_files_from_production
Review ID: 8aeb9742-af0a-4aae-8c5e-a98c17691acc
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

@@ -0,0 +1,38 @@
# Base image
FROM node:20-bookworm-slim
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM - Node.js base image uses floating patch version
Agent: microservices

Category: quality

Description:
Node.js base image uses 'node:20-bookworm-slim' which is a floating tag that resolves to the latest patch version of Node 20. This can lead to non-deterministic builds.

Suggestion:
Use a specific patch version like 'node:20.11.1-bookworm-slim' instead of 'node:20-bookworm-slim' to ensure consistent, reproducible builds.

Why this matters: Improves code reliability.

Confidence: 75%
Rule: docker_pin_specific_patch_versions_for_node_js
Review ID: 8aeb9742-af0a-4aae-8c5e-a98c17691acc
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

@diffray-bot
Copy link
Copy Markdown

Review Summary

Free public review - Want AI code reviews on your PRs? Check out diffray.ai

Validated 16 issues: 12 kept (critical bugs, security issues, Docker best practices), 4 filtered (incorrect analysis, low value, speculative)

Issues Found: 12

💬 See 7 individual line comment(s) for details.

📊 9 unique issue type(s) across 12 location(s)

📋 Full issue list (click to expand)

🔴 CRITICAL - JSON.parse without try-catch for package.json (2 occurrences)

Agent: bugs

Category: bug

Why this matters: Unhandled errors crash the application or hide bugs.

📍 View all locations
File Description Suggestion Confidence
source/app/metrics/setup.mjs:74 JSON.parse() can throw a SyntaxError if package.json contains invalid JSON, but this operation is no... Wrap the JSON.parse operation in a try-catch block, similar to the pattern used for settings.json in... 92%
source/app/metrics/setup.mjs:116 On line 116, fs.promises.readFile() returns a Promise but is not awaited. The Promise object is conv... Await the fs.promises.readFile() call: `const inherit = yaml.load(await fs.promises.readFile(...)).e... 98%

Rule: bug_missing_try_catch


🟠 HIGH - Container runs as root user

Agent: security

Category: security

Why this matters: Root in container may have elevated privileges on host depending on configuration.

File: Dockerfile.web:1-38

Description: The Dockerfile does not specify a USER instruction. Docker containers without an explicit non-root user will run as root (UID 0), increasing blast radius if the container is compromised.

Suggestion: Add a USER instruction to run the container as a non-root user. Create a dedicated user with RUN useradd -m -u 1000 appuser && USER appuser

Confidence: 95%

Rule: docker_running_as_root


🟠 HIGH - Single-stage Docker build leaves build tools in production

Agent: security

Category: security

Why this matters: Security issues can lead to data breaches.

File: Dockerfile.web:1-38

Description: The Dockerfile uses a single-stage build pattern. Build dependencies (npm, python3, ruby, g++, cmake, git, deno, curl, unzip) are included in the final production image, increasing attack surface and image size.

Suggestion: Use multi-stage Docker build with 'AS' aliases. Separate build stage from runtime stage. Only copy necessary runtime artifacts from build stage using 'COPY --from=build'.

Confidence: 90%

Rule: docker_implement_multi_stage_builds_for_product


🟠 HIGH - Docker cache invalidation: COPY all files before dependency install

Agent: microservices

Category: quality

Why this matters: Any file change invalidates cached npm install layer.

File: Dockerfile.web:5

Description: COPY . /metrics copies all source files before dependency installation, which will invalidate the Docker layer cache on every code change, triggering rebuilding of expensive layers like apt packages and npm dependencies.

Suggestion: First copy only dependency manifest files (package.json, package-lock.json) before RUN npm ci, then copy the remaining source files after installation.

Confidence: 95%

Rule: docker_copy_before_install


🟠 HIGH - HTTP request to external service without timeout (2 occurrences)

Agent: security

Category: security

Why this matters: Hanging requests exhaust connections and can cause cascading failures.

📍 View all locations
File Description Suggestion Confidence
source/plugins/achievements/list/users.mjs:312 An axios HTTP GET request to github.com without a timeout can hang indefinitely, causing resource ex... Set an explicit timeout on the axios request: imports.axios.get(url, {timeout: 10000}) 88%
source/plugins/achievements/list/users.mjs:329 An axios HTTP GET request to github.com/stars endpoint without a timeout can hang indefinitely, caus... Set an explicit timeout on the axios request: imports.axios.get(url, {timeout: 10000}) 88%

Rule: sec_external_call_no_timeout


🟠 HIGH - Missing HEALTHCHECK in Docker container

Agent: bugs

Category: bug

Why this matters: Missing healthcheck prevents automatic recovery from application failures.

File: Dockerfile.web:37-38

Description: The Dockerfile does not include a HEALTHCHECK instruction. Without it, Docker orchestrators cannot automatically detect if the application is unhealthy.

Suggestion: Add a HEALTHCHECK instruction to monitor the application health, e.g., HEALTHCHECK --interval=30s --timeout=5s CMD node -e "require('http').get('http://localhost:3000', (r) => {if (r.statusCode !== 200) throw new Error()})"

Confidence: 85%

Rule: docker_missing_healthcheck


🟠 HIGH - Unhandled promise rejection from external HTTP call (2 occurrences)

Agent: security

Category: security

Why this matters: Unhandled rejections can crash Node.js servers and cause downtime.

📍 View all locations
File Description Suggestion Confidence
source/plugins/achievements/list/users.mjs:312 The axios promise at line 312 is not wrapped in a try/catch block. If the HTTP request fails, the pr... Wrap the await call in a try/catch block to handle promise rejections gracefully. 85%
source/plugins/achievements/list/users.mjs:329 The axios promise at line 329 is not wrapped in a try/catch block. If the HTTP request fails, the pr... Wrap the await call in a try/catch block to handle promise rejections gracefully. 85%

Rule: sec_unhandled_promise_rejection


🟡 MEDIUM - Copying entire project directory into production image

Agent: security

Category: security

Why this matters: Smaller images pull faster, have fewer vulnerabilities, and reduce secrets exposure.

File: Dockerfile.web:5-30

Description: Line 5 copies the entire project directory (COPY . /metrics) into the production image. This includes test files, source code, documentation, and git files that are unnecessary at runtime.

Suggestion: Use .dockerignore to exclude unnecessary files (tests, docs, source, .git, .env files). Consider using multi-stage build where only necessary runtime artifacts are copied.

Confidence: 80%

Rule: docker_remove_unnecessary_files_from_production


🟡 MEDIUM - Node.js base image uses floating patch version

Agent: microservices

Category: quality

Why this matters: Improves code reliability.

File: Dockerfile.web:2

Description: Node.js base image uses 'node:20-bookworm-slim' which is a floating tag that resolves to the latest patch version of Node 20. This can lead to non-deterministic builds.

Suggestion: Use a specific patch version like 'node:20.11.1-bookworm-slim' instead of 'node:20-bookworm-slim' to ensure consistent, reproducible builds.

Confidence: 75%

Rule: docker_pin_specific_patch_versions_for_node_js


ℹ️ 5 issue(s) outside PR diff (click to expand)

These issues were found in lines not modified in this PR.

🔴 CRITICAL - Async file operation not awaited, Promise passed to yaml.load()

Agent: bugs

Category: bug

Why this matters: Unhandled errors crash the application or hide bugs.

File: source/app/metrics/setup.mjs:116

Description: On line 116, fs.promises.readFile() returns a Promise but is not awaited. The Promise object is converted to string in template literals and passed to yaml.load(), which will receive '[object Promise]' instead of file contents.

Suggestion: Await the fs.promises.readFile() call: const inherit = yaml.load(await fs.promises.readFile(...)).extends ?? null

Confidence: 98%

Rule: bug_missing_try_catch


🟠 HIGH - HTTP request to external service without timeout (2 occurrences)

Agent: security

Category: security

Why this matters: Hanging requests exhaust connections and can cause cascading failures.

📍 View all locations
File Description Suggestion Confidence
source/plugins/achievements/list/users.mjs:312 An axios HTTP GET request to github.com without a timeout can hang indefinitely, causing resource ex... Set an explicit timeout on the axios request: imports.axios.get(url, {timeout: 10000}) 88%
source/plugins/achievements/list/users.mjs:329 An axios HTTP GET request to github.com/stars endpoint without a timeout can hang indefinitely, caus... Set an explicit timeout on the axios request: imports.axios.get(url, {timeout: 10000}) 88%

Rule: sec_external_call_no_timeout


🟠 HIGH - Unhandled promise rejection from external HTTP call (2 occurrences)

Agent: security

Category: security

Why this matters: Unhandled rejections can crash Node.js servers and cause downtime.

📍 View all locations
File Description Suggestion Confidence
source/plugins/achievements/list/users.mjs:312 The axios promise at line 312 is not wrapped in a try/catch block. If the HTTP request fails, the pr... Wrap the await call in a try/catch block to handle promise rejections gracefully. 85%
source/plugins/achievements/list/users.mjs:329 The axios promise at line 329 is not wrapped in a try/catch block. If the HTTP request fails, the pr... Wrap the await call in a try/catch block to handle promise rejections gracefully. 85%

Rule: sec_unhandled_promise_rejection



Review ID: 8aeb9742-af0a-4aae-8c5e-a98c17691acc
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

@artik0din artik0din closed this Dec 31, 2025
@artik0din artik0din deleted the fix/plugin-bugs branch December 31, 2025 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants