Skip to content

fix: make calculate() robust to omitted optional inputs#32

Open
dmchaledev wants to merge 1 commit into
mainfrom
claude/sleepy-rubin-b0qlb3
Open

fix: make calculate() robust to omitted optional inputs#32
dmchaledev wants to merge 1 commit into
mainfrom
claude/sleepy-rubin-b0qlb3

Conversation

@dmchaledev

Copy link
Copy Markdown
Contributor

Summary

The pure calculate() API — the documented DOM-free entry point — breaks when called with the input shape its own type declarations and README advertise:

  • Throws TypeError: Cannot read properties of undefined (reading 'length') when compliance_needs is omitted, even though index.d.ts marks it compliance_needs? (optional). It's read unconditionally in calcAsmResources() (.length) and calcTiming() (.length).
  • Emits NaN for scan_window_utilization and silently falls through to a bogus 'poor' efficiency rating when scan_window (also typed optional) is omitted — scan_window * 60 is NaN, every comparison is false, so the rating ladder lands on poor.

The README's own Quick Start (calculate({ /* inputs */ })) and the calculate({...}) usage in README.md would crash as written.

Reproduction (before this PR)

import { calculate } from '@hailbytes/vulnerability-calculator';

// Per index.d.ts both fields are optional:
calculate({ target_hosts: 1000, scan_intensity: 'medium',
            scan_frequency: 'weekly', scanning_tools: ['hailbytes_asm'] });
// → TypeError: Cannot read properties of undefined (reading 'length')

calculate({ target_hosts: 1000, scan_intensity: 'medium',
            scan_frequency: 'weekly', scanning_tools: ['openvas'], compliance_needs: [] });
// → timing.scan_window_utilization === NaN, efficiency_rating === 'poor'

Fix

Normalize inputs once at the top of calculateResources() so omitted fields fall back to documented defaults that mirror the web component's form (target_hosts=1000, medium/weekly, 8h window, empty tool/compliance lists). Nullish coalescing (??) is used so explicit 0 / [] are preserved, and the helper also guards against a null/undefined argument and a non-array scanning_tools.

This brings the runtime behaviour in line with the existing index.d.ts contract rather than changing the public type surface.

Changes

  • hailbytes-vuln-calculator.js — add normalizeInputs() and apply it in calculateResources().
  • test/calculate.test.mjs — 5 new tests: omitted compliance_needs, omitted scan_window (finite utilization), minimal-input call, omitted scanning_tools (traditional path), and preservation of explicit 0 / [].
  • README.md — add a Default column to the Input Schema, note that omitted fields fall back to defaults, and fix the Quick Start snippet so it's a runnable example.
  • CHANGELOG.md — record under Unreleased → Fixed.

Verification

npm test70 passing, 0 failing (5 new). The two repro cases above now return finite, well-formed results.

Scope / blast radius

Localized to input handling in the calculation engine. No change to formulas, output shape, or the existing TypeScript types; all prior tests pass unchanged. Distinct from the open formula-accuracy issues (#24, #31).

🤖 Generated with Claude Code


Generated by Claude Code

The pure calculate() API crashed with a TypeError when compliance_needs
was omitted, and produced NaN scan_window_utilization (plus a bogus
'poor' efficiency rating) when scan_window was omitted — even though
index.d.ts marks both fields optional and the README shows
`calculate({ /* inputs */ })`.

Normalize inputs up front so omitted fields fall back to documented
defaults (matching the web component's form), while preserving explicit
0 / [] values via nullish coalescing. Also guards against a null/undefined
argument and a non-array scanning_tools.

- Add 5 tests covering omitted compliance_needs/scan_window, minimal
  input, omitted scanning_tools, and zero/empty-array preservation.
- Document per-field defaults in the README Input Schema and fix the
  Quick Start snippet so it isn't a crashing example.
- Record the fix in CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HPMrQUfv9Q592yhYXKGCGo
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.

2 participants