Skip to content

fix(Label_4A_DIS): guard against comma-less DIS payloads (#493) - #520

Open
fuleinist wants to merge 2 commits into
airframesio:masterfrom
fuleinist:fix/493-label-4a-dis-length-guard
Open

fix(Label_4A_DIS): guard against comma-less DIS payloads (#493)#520
fuleinist wants to merge 2 commits into
airframesio:masterfrom
fuleinist:fix/493-label-4a-dis-length-guard

Conversation

@fuleinist

@fuleinist fuleinist commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Problem

Label_4A_DIS.decode splits message.text on , then unconditionally calls fields[1].substring(2). A comma-less DIS payload (truncated header, DIS-only marker) makes fields[1] undefined, throwing TypeError: Cannot read properties of undefined (reading 'substring') and aborting the entire MessageDecoder.decode().

Fix

Early-return with decoded: false when fields.length < 2 or fields[1] is too short for the timestamp parse. This mirrors the defensive pattern used in other label plugins (e.g. Label_4T_ETA, Label_5Z_Slash).

Tests

  • Existing fixture (DIS01,190009,WEN3140,@HOLD CNX) still passes
  • New: "DIS" (no comma) → decoded: false, no throw
  • New: "DIS," (empty field after comma) → decoded: false, no throw
  • Full suite: 483 passed, 8 skipped, 0 failed

Closes #493

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of malformed DIS messages.
    • Invalid or incomplete input now fails safely without throwing errors.
    • Empty or missing fields produce a clear undecoded result with no items.
    • Inputs with missing separators, short identifiers, or absent message content are now rejected consistently.
    • Valid DIS messages continue to decode with their existing timestamps, callsigns, and text formatting.

…amesio#493)

Label_4A_DIS.decode split message.text on ',' then unconditionally
called fields[1].substring(2). A comma-less DIS payload (truncated
header, DIS-only marker) made fields[1] undefined, throwing TypeError
and aborting MessageDecoder.decode().

Fix: early-return with decoded=false when fields.length < 2 or
fields[1] is too short for the substring(2) + '00' timestamp parse.

Adds 2 regression tests for comma-less and empty-field cases.
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 171b40f8-6521-4981-999c-7223ec52e897

📥 Commits

Reviewing files that changed from the base of the PR and between 3477bd7 and 60f8cff.

📒 Files selected for processing (2)
  • lib/plugins/Label_4A_DIS.test.ts
  • lib/plugins/Label_4A_DIS.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/plugins/Label_4A_DIS.ts

Walkthrough

The DIS decoder validates required fields before processing input. Malformed payloads return unsuccessful decode results without throwing. Tests cover comma-less, empty-field, and incomplete payloads.

Changes

DIS payload validation

Layer / File(s) Summary
Validate DIS fields and test invalid results
lib/plugins/Label_4A_DIS.ts, lib/plugins/Label_4A_DIS.test.ts
decode rejects malformed fields before processing valid payload data. Tests verify undecoded results, decode level none, and no items.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

A rabbit checks the DIS line,
Missing fields are declined.
No crash hops through the chain,
Empty payloads leave no stain.
Tests confirm the guard is fine.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the DIS decoder fix for comma-less payloads and matches the primary change.
Linked Issues check ✅ Passed The changes add validation and regression tests for incomplete DIS payloads, preventing throws and invalid decoding as required by issue #493.
Out of Scope Changes check ✅ Passed The changes are limited to DIS decoder validation and related regression tests, with no unrelated code changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/plugins/Label_4A_DIS.test.ts (1)

42-60: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add regression tests for the incomplete payloads in the objective.

These tests cover DIS and DIS,, but they do not cover DIS01 or DIS01,190009. The latter currently passes the decoder guard and can produce a successful result with no callsign. Add both cases and assert decoded is false, decodeLevel is none, and the formatted item list is empty.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/plugins/Label_4A_DIS.test.ts` around lines 42 - 60, Add regression tests
in the existing Label_4A_DIS test suite for payloads `DIS01` and `DIS01,190009`.
For each case, call `plugin.decode(message)` and assert `decoded` is false,
`decodeResult.decoder.decodeLevel` is `none`, and `decodeResult.formatted.items`
is empty, matching the existing incomplete-payload tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/plugins/Label_4A_DIS.ts`:
- Around line 20-26: Update the validation preceding decoded assignment in the
Label_4A_DIS decoder to require at least three fields, a non-empty fields[2]
callsign, and a timestamp in fields[1] with at least six characters; keep
decoded false and return the decode result when any requirement fails. Add
regression tests covering missing callsigns and truncated timestamps.

---

Outside diff comments:
In `@lib/plugins/Label_4A_DIS.test.ts`:
- Around line 42-60: Add regression tests in the existing Label_4A_DIS test
suite for payloads `DIS01` and `DIS01,190009`. For each case, call
`plugin.decode(message)` and assert `decoded` is false,
`decodeResult.decoder.decodeLevel` is `none`, and `decodeResult.formatted.items`
is empty, matching the existing incomplete-payload tests.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a02004c2-a81b-41e0-a445-822c8b7546d7

📥 Commits

Reviewing files that changed from the base of the PR and between 90ad3b2 and 3477bd7.

📒 Files selected for processing (2)
  • lib/plugins/Label_4A_DIS.test.ts
  • lib/plugins/Label_4A_DIS.ts

Comment thread lib/plugins/Label_4A_DIS.ts Outdated
Comment on lines +20 to +26
if (fields.length < 2 || !fields[1] || fields[1].length < 3) {
decodeResult.decoded = false;
this.setDecodeLevel(decodeResult, decodeResult.decoded);
return decodeResult;
}

decodeResult.decoded = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- target file ---'
wc -l lib/plugins/Label_4A_DIS.ts
cat -n lib/plugins/Label_4A_DIS.ts

printf '%s\n' '--- related symbols ---'
rg -n --glob '!node_modules' \
  'convertHHMMSSToTod|Label_4A_DIS|DIS01|callsign|fields\[2\]' \
  . | head -n 240

printf '%s\n' '--- candidate test files ---'
git ls-files | rg -i '(^|/)(test|tests|spec|__tests__)(/|$)|Label_4A_DIS|DIS'

Repository: airframesio/acars-decoder-typescript

Length of output: 13491


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- timestamp utility ---'
cat -n lib/DateTimeUtils.ts
printf '%s\n' '--- timestamp tests ---'
cat -n lib/DateTimeUtils.test.ts

printf '%s\n' '--- formatter callsign ---'
sed -n '1,125p' lib/utils/result_formatter.ts
printf '%s\n' '--- formatter tests ---'
sed -n '1,130p' lib/utils/result_formatter.test.ts

printf '%s\n' '--- plugin base initialization ---'
rg -n -A45 -B10 'initResult|setDecodeLevel' lib/DecoderPlugin.ts lib/DecoderPluginInterface.ts

printf '%s\n' '--- DIS tests ---'
cat -n lib/plugins/Label_4A_DIS.test.ts

Repository: airframesio/acars-decoder-typescript

Length of output: 19553


🏁 Script executed:

#!/bin/bash
set -eu

node - <<'JS'
function convertHHMMSSToTod(time) {
  if (time.length === 4) time += '00';
  const h = Number(time.substring(0, 2));
  const m = Number(time.substring(2, 4));
  const s = Number(time.substring(4, 6));
  return h * 3600 + m * 60 + s;
}

const fields = ['DIS01', '190009', 'WEN3140'];
for (const timestamp of ['190', '1900', '19000', '190009']) {
  const converted = timestamp.substring(2) + '00';
  console.log(JSON.stringify({
    timestamp,
    converted,
    tod: convertHHMMSSToTod(converted),
    acceptedByCurrentGuard: timestamp.length >= 3,
    acceptedByRequiredGuard: timestamp.length >= 6,
  }));
}

for (const text of ['DIS01,190009', 'DIS01,190009,', 'DIS01,190009,WEN3140']) {
  const parts = text.split(',');
  console.log(JSON.stringify({
    text,
    fieldCount: parts.length,
    currentSuccessPath: parts.length >= 2 && !!parts[1] && parts[1].length >= 3,
    completeRecord: parts.length >= 3 && !!parts[1] && !!parts[2] && parts[1].length >= 6,
    callsign: parts[2],
  }));
}
JS

Repository: airframesio/acars-decoder-typescript

Length of output: 926


Require a complete DIS record and a six-character timestamp.

Require fields.length >= 3, a non-empty fields[2], and fields[1].length >= 6 before setting decoded to true. Add regression tests for missing callsigns and truncated timestamp fields.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/plugins/Label_4A_DIS.ts` around lines 20 - 26, Update the validation
preceding decoded assignment in the Label_4A_DIS decoder to require at least
three fields, a non-empty fields[2] callsign, and a timestamp in fields[1] with
at least six characters; keep decoded false and return the decode result when
any requirement fails. Add regression tests covering missing callsigns and
truncated timestamps.

@makrsmark makrsmark left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

approving with non-blocking request

Comment thread lib/plugins/Label_4A_DIS.ts Outdated

decodeResult.decoded = true;
const fields = message.text.split(',');
if (fields.length < 2 || !fields[1] || fields[1].length < 3) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

pretty sure !fields[1] is redundant with fields.length

@fuleinist

Copy link
Copy Markdown
Contributor Author

Addressed the review suggestion in 60f8cff: the guard now requires the callsign field ( ields[2]) and at least three comma-separated fields, so payloads like DIS01,190009 no longer decode successfully without a callsign. Added regression tests for both DIS01 (already guarded, now covered by a test) and DIS01,190009. Full suite: 485 passed / 8 skipped. Thanks for the review!

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.

Bug: Label_4A_DIS dereferences fields[1].substring with no length guard — comma-less DIS payloads throw TypeError and abort MessageDecoder.decode()

2 participants