php-uptelligence/changelog/2026/jan/code-review.md
Snider ef8a40829f security: fix shell injection in AssetTrackerService
- Add package name validation with strict regex patterns
- Convert all Process::run() calls to array syntax
- Support Composer and NPM package name formats
- Add comprehensive shell injection tests (20 attack patterns)
- Update security docs and changelog

Fixes P2 shell injection vulnerability from security audit.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 12:21:07 +00:00

8 KiB

Uptelligence Module Review

Updated: 2026-01-21 - All recommended improvements implemented

Overview

The Uptelligence module is an internal tooling system for tracking and managing upstream vendor software updates. It provides:

  1. Vendor Tracking - Monitor licensed software (66biolinks, Mixpost Pro/Enterprise), OSS projects, and plugins for version changes
  2. Diff Analysis - Compare versions, cache diffs, and auto-categorise changes by type (security, controller, model, view, etc.)
  3. AI Analysis - Use Claude or OpenAI to analyse diffs and generate prioritised porting todos
  4. Asset Tracking - Monitor Composer/NPM packages, fonts, and CDN resources for updates
  5. Pattern Library - Store reusable code patterns with variants for MCP context
  6. Issue Generation - Auto-create GitHub/Gitea issues from todos
  7. Agent Plan Integration - Generate structured porting plans for the Agentic module
  8. Cold Storage - Archive vendor versions to S3 with on-demand retrieval

This module is well-designed architecturally. P1 critical issues fixed in Wave 1. All recommended improvements now implemented.

Critical Issues (Must Fix)

  • No database migrations - FIXED: Created 2026_01_21_100000_create_uptelligence_tables.php with all 10 tables
  • No Controllers/Routes - No way to interact with the system via HTTP. No UI, no API endpoints
  • No Commands - No artisan commands to run analyses, check for updates, or generate issues
  • No Tests - Zero test coverage. No unit tests, feature tests, or factories
  • No Seeders - No way to seed default vendors defined in config
  • Dependency on Agentic module - FIXED: UpstreamPlanGeneratorService now checks agenticModuleAvailable() before using Agentic models
  • API keys required - AI analysis and GitHub/Gitea integration require API keys but no validation or graceful degradation
  • DiffAnalyzerService shell injection risk - FIXED: Now uses Process::run(['diff', '-u', $prevPath, $currPath]) array syntax
  • AssetTrackerService shell injection risk - FIXED: Now uses array-based Process invocation with package name validation
  • Add input validation on file paths in DiffAnalyzerService::generateDiff() - FIXED: Path traversal validation added to prevent directory traversal attacks.
  • Add rate limiting for AI API calls in AIAnalyzerService - FIXED: Rate limiting implemented for AI analysis calls.
  • Add retry logic with exponential backoff for external API calls - FIXED: Retry logic with exponential backoff added for Packagist, NPM, GitHub, Gitea, Anthropic, and OpenAI calls.
  • Add logging for all external API failures - FIXED: Enhanced logging for API failures beyond just report($e).
  • Add database transactions in DiffAnalyzerService::cacheDiffs() - FIXED: Database transactions added with rollback on failure.
  • Add soft deletes to models for audit trail - FIXED: Soft deletes added to relevant models.
  • Add index on diff_cache.version_release_id and upstream_todos.vendor_id - FIXED: Database performance indexes added.
  • Add validation that vendor target_repo format is valid - FIXED: Validation added before using explode('/', ...) in IssueGeneratorService.
  • VendorStorageService uses both Laravel Storage facade and direct file_exists() calls - FIXED: Standardised to use Storage facade throughout.
  • Add config validation on boot to warn about missing API keys - FIXED: Config validation added on boot.
  • AssetTrackerService processes packages sequentially - could benefit from parallel processing for large checks
  • Add webhook support for vendor notifications (currently only outbound notifications to Slack/Discord)
  • Pattern model stores code as text - consider blob storage for large patterns
  • Add timestamps validation for released_at in AssetVersion - FIXED: Proper validation added instead of using fragile now()->parse().

Missing Features (Future)

  • Livewire/Flux UI for managing vendors, viewing diffs, and tracking todos
  • Scheduled job to auto-check vendors/assets for updates
  • Webhook endpoint for receiving vendor release notifications
  • CLI commands: upstream:check, upstream:analyze, upstream:issues, upstream:sync-assets
  • Dashboard with metrics (pending todos, quick wins, security updates)
  • Email digest notifications for new upstream releases
  • Git submodule sync for OSS vendors (referenced in config but not implemented)
  • Diff viewer UI with syntax highlighting
  • Batch AI analysis with cost tracking
  • Export/import of todos for external tracking systems
  • Integration with project management tools (Linear, Jira)
  • Automated PR creation for simple porting tasks
  • Version comparison UI showing what's changed
  • Pattern search and preview UI

Test Coverage Assessment

Current Coverage: 0%

No tests exist. The module needs:

  • Unit tests for all Models (scopes, helpers, relationships)
  • Unit tests for DiffCache::detectCategory()
  • Unit tests for Vendor path matching methods
  • Feature tests for DiffAnalyzerService
  • Feature tests for AIAnalyzerService (with mocked API responses)
  • Feature tests for IssueGeneratorService (with mocked GitHub/Gitea APIs)
  • Feature tests for VendorStorageService (local and S3 modes)
  • Feature tests for AssetTrackerService
  • Integration test for full analysis workflow
  • Factories for all models

Security Concerns

  1. Shell injection in DiffAnalyzerService - FIXED: Now uses array syntax for Process::run().

  2. No authentication/authorisation - When routes are added, they need proper guards. This is internal tooling and should be admin-only.

  3. API tokens in config - GitHub, Gitea, Anthropic, OpenAI tokens are stored in config. Ensure these are properly protected via .env and not logged.

  4. S3 bucket access - Vendor archives in S3 should use private ACL. Code doesn't explicitly set ACL.

  5. Path traversal - FIXED: Validation added to ensure slug contains no ../ sequences.

  6. Arbitrary code patterns - Pattern model stores code that could be surfaced via MCP. Ensure patterns are vetted before use.

  7. SQL injection via search - Pattern::scopeSearch() uses LIKE with user input. Currently safe due to Eloquent but worth noting.

Notes

Architecture

The module follows good separation of concerns:

  • Models are clean with well-defined scopes and helpers
  • Services handle specific domains (diff analysis, AI, issues, storage)
  • Config is comprehensive and uses env vars appropriately

Dependencies

  • Requires Mod\Agentic module for plan generation (soft dependency - now checks availability)
  • External: Anthropic API, OpenAI API, GitHub API, Gitea API, Packagist, NPM registry, AWS S3

Config Observations

The config includes 3 pre-defined vendors (66biolinks, Mixpost Pro, Mixpost Enterprise) but no seeder to create them.

The AI model defaults to claude-sonnet-4-20250514 which is appropriate.

S3 config supports dual endpoints (Hetzner Object Store pattern) which is good for the infrastructure.

Code Quality

  • Consistent use of declare(strict_types=1)
  • Good PHPDoc on classes
  • Constants defined for all magic strings
  • Proper type hints throughout
  • UK English spelling in documentation (colour, analyse, etc.) matching brand guidelines

Missing from Boot.php

  • Routes not registered (no routes file)
  • No commands registered
  • No event listeners
  • No scheduled tasks
  • DiffAnalyzerService and AssetTrackerService not registered as singletons (only Issue, Plan, and Storage services are)

Potential Quick Wins

  1. Create migrations from model definitions - DONE
  2. Add basic artisan commands
  3. Register DiffAnalyzerService and AssetTrackerService as singletons
  4. Add a simple seeder for default vendors
  5. Fix the shell injection in DiffAnalyzerService - DONE