Skip to content

fix(navlayers): interpolate gradient colors between stops - #250

Open
bacescuandrei wants to merge 1 commit into
mitre-attack:mainfrom
bacescuandrei:fix/gradient-compute-color
Open

bacescuandrei wants to merge 1 commit into
mitre-attack:mainfrom
bacescuandrei:fix/gradient-compute-color

Conversation

@bacescuandrei

Copy link
Copy Markdown

Gradient.compute_color() looks scores up in a precomputed curve. The curve's length depends on how evenly maxValue - minValue divides between the color stops. This causes three problems:

  • With four or more colors and a range such as 0–11, scores near the maximum raise IndexError. This aborts ToExcel.to_xlsx() and ToSvg.to_svg() for the whole layer.
  • Each curve segment repeats its end color, so intermediate scores pick up the next stop early. With red → yellow → green over 0–4, a score of 1 renders as yellow.
  • A single-color gradient raises ZeroDivisionError.

This change interpolates linearly in RGB between evenly spaced stops, approximately as the ATT&CK Navigator does. Navigator uses tinygradient's RGB interpolation, quantised to 100 steps, so small differences remain on steep gradients. It also removes the precomputed curve attribute and _compute_curve. Neither is documented or used elsewhere in the package.

Validation:

  • New tests/test_gradient.py with 13 cases: 9 of them fail on main and all pass with the change.
  • uv run pytest: 310 passed, 4 skipped.
  • ruff check and ruff format --check: clean.
  • Reproduced the export crash end to end with a local ATT&CK v20.0 bundle: a layer with gradient #ff0000, #00ff00, #0000ff, #ffffff over 0–11 and T1003 scored 10. On main, both to_xlsx and to_svg raise IndexError; with the change, both succeed.

Gradient.compute_color() looked scores up in a precomputed curve whose
length depended on how evenly the score range divided between the color
stops. With four or more colors and a range such as 0-11, scores near
the maximum raised IndexError, which aborts Excel and SVG export of the
layer. Each segment of the curve also repeated its end color, so
intermediate scores took the next stop color early (with stops red,
yellow, green over 0-4, a score of 1 was yellow), and a single-color
gradient raised ZeroDivisionError.

Interpolate linearly in RGB between evenly spaced stops instead, as the
ATT&CK Navigator does, and drop the precomputed curve.
@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

No deployments
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