Skip to content

RAN-33: Hygiene cluster from RAN-6 review (5 LOW items batched)#70

Merged
aksOps merged 1 commit into
mainfrom
fix/ran-33-hygiene
Apr 25, 2026
Merged

RAN-33: Hygiene cluster from RAN-6 review (5 LOW items batched)#70
aksOps merged 1 commit into
mainfrom
fix/ran-33-hygiene

Conversation

@aksOps

@aksOps aksOps commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes RAN-33. Batches the five LOW-severity follow-ups from the RAN-6 Reviewer audit so reviewers don't pay per-PR overhead on items that are not individually severe.

  • DeterminismAnalyzer breakdown maps (language, node, edge, framework) switched from HashMap to TreeMap across all three pipelines (run, runBatchedIndex, runSmartIndex). AnalysisResult JSON is now byte-stable across runs. New breakdownMapsAreSortedDeterministically test in AnalyzerTest.
  • BrandingVersionCommand banner: stale Code IQcodeiq. BundleCommand javadoc gains a footnote explaining code-iq-*-cli.jar keeps the historical filename because it tracks the Maven artifactId (intentionally unchanged per CLAUDE.md). Other remaining code-iq references in README/BundleCommand are intentional Maven-coordinate strings and stay as-is.
  • CORSCorsConfig defaults promoted to named constants (DEFAULT_ALLOWED_ORIGIN_PATTERNS, API_ALLOWED_METHODS, MCP_ALLOWED_METHODS, ALLOWED_HEADERS) with javadoc explaining the read-only API posture (no PUT/PATCH/DELETE) and the MCP GET/POST requirement. Behaviour unchanged; existing CorsConfigTest passes verbatim.
  • ExecutorService close/lifecycle coverageAnalyzer.BoundedExecutor promoted from private to package-private. New AnalyzerBoundedExecutorTest covers: long-running task is interrupted within the bounded shutdown window, idle close returns promptly, interrupted closer thread still shuts the delegate down and restores the interrupt flag.
  • /api/intelligence/evidence symlink hardening — Added the same two-stage toRealPath guard that protects /api/file (RAN-8). NoSuchFileException is treated as a logical-only graph reference (lexical guard already passed). Tests mirror the GraphController symlink shape and skip gracefully on filesystems without symlink support.

Test plan

  • mvn test -Dnpm.skip=true ... → 3401 tests, 0 failures, 0 errors, 31 skipped (E2E without external repos).
  • Targeted reruns of AnalyzerTest, AnalyzerBoundedExecutorTest, CorsConfigTest, IntelligenceControllerTest, VersionCommandTest all green.
  • CI green on the PR.

Out of scope

  • Splitting any of these items into separate issues — explicitly out of scope per RAN-33.
  • Larger refactors unrelated to the listed hygiene items.
  • Renaming the Maven artifactId / JAR filename — intentionally unchanged per CLAUDE.md.

🤖 Generated with Claude Code

…N-33)

Bundles five low-severity hygiene items so reviewers don't pay per-PR
overhead on items that aren't individually severe.

1. Determinism — Analyzer breakdown-map ordering
   `nodeBreakdown`, `edgeBreakdown`, `frameworkBreakdown`, and
   `languageBreakdown` were `HashMap`s, which made the JSON serialization
   order of `AnalysisResult` non-deterministic across runs. Switched the
   12 declarations across `run`, `runBatchedIndex`, and `runSmartIndex`
   to `TreeMap`. Adds `breakdownMapsAreSortedDeterministically` test
   covering all four breakdowns.

2. Branding hygiene — VersionCommand + BundleCommand
   - VersionCommand banner: stale `Code IQ` → `codeiq` (matches the
     post-rename CLI / package / repo branding).
   - BundleCommand: added a footnote on the bundle-structure javadoc
     explaining that `code-iq-*-cli.jar` keeps the historical filename
     because it tracks the Maven `artifactId` (intentionally unchanged
     per `CLAUDE.md`). Future readers won't trip over it.
   Other remaining `code-iq` strings (the `<artifactId>` snippet in the
   README and the JAR/Maven-URL templates inside BundleCommand) are
   intentional Maven-coordinate references and stay as-is.

3. CORS defaults explicit — CorsConfig
   Promoted defaults to named constants
   (`DEFAULT_ALLOWED_ORIGIN_PATTERNS`, `API_ALLOWED_METHODS`,
   `MCP_ALLOWED_METHODS`, `ALLOWED_HEADERS`) and added a javadoc
   explaining the read-only API posture (no `PUT`/`PATCH`/`DELETE`)
   and the MCP `GET`/`POST` requirement. Behaviour unchanged — existing
   `CorsConfigTest` still passes verbatim. The `@Value` default still
   inlines the constant, and the field initializer keeps direct
   `new CorsConfig()` test usage working.

4. ExecutorService close/lifecycle regression coverage
   Promoted `Analyzer.BoundedExecutor` from `private` to package-private
   so its bounded-shutdown contract can be tested without spinning the
   full pipeline. Added `AnalyzerBoundedExecutorTest` with three cases:
     - long-running task: `close()` returns inside the
       graceful (10s) + force (5s) window and the task is interrupted;
     - idle executor: `close()` returns promptly;
     - interrupted closer thread: delegate is still shut down and the
       caller's interrupt flag is restored.

5. IntelligenceController.evidence — symlink hardening
   The `/api/intelligence/evidence` endpoint had only the lexical
   `normalize` + `startsWith` guard. Aligned it with the two-stage
   `toRealPath` guard that already protects `/api/file` (RAN-8): after
   the lexical check, resolve symlinks via `Path.toRealPath()` and
   re-check containment against the canonical root.
   `NoSuchFileException` is treated as "logical-only graph reference"
   and the lexical guard is sufficient (no symlink to traverse).
   Added `evidenceEndpointRejectsSymlinkEscapingRoot` and
   `evidenceEndpointAllowsInRepoSymlink`, both skip gracefully on
   filesystems without symlink support — same shape as the existing
   GraphController symlink tests.

Verification
- `mvn test -Dnpm.skip=true ...` → 3401 tests run, 0 failures, 0 errors,
  31 skipped (E2E without external repos).
- Targeted reruns of `AnalyzerTest`, `AnalyzerBoundedExecutorTest`,
  `CorsConfigTest`, `IntelligenceControllerTest`, `VersionCommandTest`
  all green.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e7c3ba4c67

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (!resolved.startsWith(root)) {
Path root;
try {
root = Path.of(config.getRootPath()).toRealPath();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid requiring a real filesystem root for file evidence lookup

getEvidence now canonicalizes codeiq.rootPath with Path#toRealPath, which throws when the configured source directory is missing (for example, serving a graph artifact on a host without the original checkout). In that case any request with file=... returns HTTP 500 before reaching assembler.assemble, even though the implementation explicitly supports logical-only graph references (it already ignores NoSuchFileException for the candidate path). This is a behavior regression from the previous lexical guard and breaks valid file-based evidence queries in source-detached deployments.

Useful? React with 👍 / 👎.

@sonarqubecloud

Copy link
Copy Markdown

@aksOps aksOps merged commit d3692cd into main Apr 25, 2026
8 checks passed
@aksOps aksOps deleted the fix/ran-33-hygiene branch April 25, 2026 13:19
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.

1 participant