Skip to content

Harden annotation exports and upgrade docs dependencies - #8

Merged
aeiwz merged 1 commit into
mainfrom
codex/refactor-code-quality
Apr 8, 2026
Merged

Harden annotation exports and upgrade docs dependencies#8
aeiwz merged 1 commit into
mainfrom
codex/refactor-code-quality

Conversation

@aeiwz

@aeiwz aeiwz commented Apr 8, 2026

Copy link
Copy Markdown
Owner

This pull request introduces important security and usability improvements to the metbit package, especially around annotation handling, and modernizes the documentation site setup and dependencies. The main changes include sanitizing annotation text to prevent XSS and CSV injection, updating the scaler for better sparse matrix handling, and upgrading the documentation frontend stack.

Security and Annotation Handling Improvements:

  • Added _sanitize_annotation_text to escape HTML in annotation labels and enforce a maximum length, preventing XSS vulnerabilities in annotation rendering (metbit/annotate_peak.py). [1] [2]
  • Added _sanitize_csv_cell to neutralize spreadsheet formula injection when exporting annotations to CSV, blocking potential CSV injection attacks (metbit/annotate_peak.py). [1] [2]
  • Integrated these sanitization routines into annotation addition, import, and export workflows (metbit/annotate_peak.py). [1] [2] [3]
  • Added tests to verify that annotation and CSV cell sanitization work as intended (tests/test_security_annotations.py).

Scaler Usability and Robustness:

  • Refactored the scaler to improve handling of sparse matrices, with a new static method _raise_if_centering_sparse to centralize and clarify error raising for unsupported operations, and improved attribute management and code clarity (metbit/scaler.py). [1] [2] [3] [4] [5]

Documentation Site Modernization:

  • Upgraded Next.js, React, and related dependencies to their latest major versions, and updated the ESLint configuration for improved code quality (docs/package.json, docs/eslint.config.mjs). [1] [2]
  • Switched to using the next/font/google API for loading the Roboto font, removing manual <link> tags and applying the font via className for better performance and maintainability (docs/app/layout.tsx). [1] [2]
  • Improved theme persistence and initialization in the ThemeToggle component by centralizing mode retrieval logic and cleaning up effect usage (docs/app/components/ThemeToggle.tsx). [1] [2]

Version Bump:

  • Bumped the Python package version to 8.7.7 in both metbit/__init__.py and setup.py to reflect these changes. [1] [2]

@aeiwz
aeiwz requested a review from Copilot April 8, 2026 06:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens metbit’s annotation workflows against XSS/CSV injection, refactors the custom scaler’s sparse-matrix handling for clarity, and modernizes the documentation site’s frontend/tooling.

Changes:

  • Add annotation-label HTML escaping + length limiting, and CSV cell sanitization for exports; wire both into add/import/export flows.
  • Refactor Scaler sparse-centering error handling and internal state reset logic.
  • Upgrade docs app dependencies/config (Next/React, ESLint flat config, font loading, theme persistence) and bump package version to 8.7.7.

Reviewed changes

Copilot reviewed 9 out of 40 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
metbit/annotate_peak.py Adds sanitizers and integrates them into annotation add/import/export paths.
tests/test_security_annotations.py Adds tests validating sanitization behavior.
metbit/scaler.py Refactors sparse-centering error raising and attribute reset/fit/transform logic.
metbit/__init__.py Bumps package version string to 8.7.7.
setup.py Bumps package version + tag URL to 8.7.7.
docs/package.json Updates docs dependencies and switches lint script to flat-config ESLint.
docs/eslint.config.mjs Adds ESLint flat configuration for Next.js + TypeScript.
docs/next-env.d.ts Updates Next.js TypeScript reference directives.
docs/app/layout.tsx Migrates Roboto loading to next/font/google and applies font class.
docs/app/components/ThemeToggle.tsx Centralizes theme mode retrieval and simplifies system-theme handling.
tests/__pycache__/* Adds compiled pytest .pyc artifacts (should not be committed).
metbit/__pycache__/* Adds compiled Python .pyc artifacts (should not be committed).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread metbit/annotate_peak.py
Comment on lines +19 to +20
text = text[:max_len].strip()
return html_stdlib.escape(text, quote=True)

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

max_len is applied before html.escape(), but escaping can expand the string (e.g., < -> &lt;), so the returned value can exceed max_len. If the goal is to cap rendered payload size, enforce the limit on the escaped output (or implement a truncation strategy that accounts for entity expansion).

Suggested change
text = text[:max_len].strip()
return html_stdlib.escape(text, quote=True)
escaped_text = html_stdlib.escape(text, quote=True)
return escaped_text[:max_len]

Copilot uses AI. Check for mistakes.
Comment thread metbit/annotate_peak.py
def _sanitize_csv_cell(value: str) -> str:
"""Neutralize spreadsheet formula injection for CSV exports."""
text = str(value or "")
if text and text[0] in ("=", "+", "-", "@", "\t"):

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

CSV formula injection checks typically need to consider leading whitespace/newlines (some spreadsheet apps ignore leading spaces before evaluating formulas). Consider detecting the first non-whitespace character (e.g., via lstrip) and/or including \r/\n in the guard, then prefixing with an apostrophe when needed.

Suggested change
if text and text[0] in ("=", "+", "-", "@", "\t"):
stripped = text.lstrip()
if stripped and stripped[0] in ("=", "+", "-", "@"):

Copilot uses AI. Check for mistakes.
Comment thread tests/test_security_annotations.py

Copilot AI commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

@aeiwz I'm unable to start working on this because of repository rules that prevent me from pushing to the branch:

  • Changes must be made through a pull request due to repository rules
  • Code scanning results must be provided due to repository rules

See the documentation for more details.

@aeiwz
aeiwz merged commit 162871d into main Apr 8, 2026
9 checks passed
@aeiwz

aeiwz commented Apr 8, 2026

Copy link
Copy Markdown
Owner Author

@copilot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants