Skip to content

Add STARTTLS support to testssl-inspector#197

Open
ahmedhxssam wants to merge 4 commits into
GRCEngClub:mainfrom
ahmedhxssam:fix-165-starttls-testssl
Open

Add STARTTLS support to testssl-inspector#197
ahmedhxssam wants to merge 4 commits into
GRCEngClub:mainfrom
ahmedhxssam:fix-165-starttls-testssl

Conversation

@ahmedhxssam

@ahmedhxssam ahmedhxssam commented Jun 15, 2026

Copy link
Copy Markdown

Summary

Adds --starttls=<proto> support to the testssl-inspector scan wrapper so users can scan STARTTLS services such as SMTP, IMAP, POP3, FTP, LDAP, Postgres, and MySQL.

SMTPS on port 465 is implicit TLS, not STARTTLS — it is scanned as a normal TLS endpoint (--target=host:465) without --starttls, so it is intentionally not part of the --starttls allowlist. Passing --starttls=smtps returns a clear hint pointing at the implicit-TLS form.

Changes

  • Parses --starttls=<proto> in scan.js
  • Validates supported STARTTLS protocols
  • Rejects unknown protocols with EXIT.USAGE
  • Defaults target ports when no explicit port is provided
  • Preserves explicit target ports like mail.example.com:587
  • Passes --starttls <proto> through to testssl.sh
  • Updates commands/scan.md and README.md

Verification

Syntax check:

node --check plugins/connectors/testssl-inspector/scripts/scan.js
echo $?

Result:

0

Contract fixture validation:

bash tests/validate-contract-fixtures.sh
echo $?

Result:

All 49 fixture(s) valid.
0

Happy-path STARTTLS argument parsing:

node plugins/connectors/testssl-inspector/scripts/scan.js --target=mail.example.com --starttls=smtp --no-docker --output=json
echo $?

Result:

[testssl-inspector] testssl.sh not on PATH. Install via: brew install testssl (macOS), apt install testssl.sh (Debian/Ubuntu), or git clone https://github.com/testssl/testssl.sh ~/.local/share/testssl.sh && export PATH="$HOME/.local/share/testssl.sh:$PATH". Or rerun with --docker.
3

This confirms --starttls=smtp is no longer rejected as an unknown flag. The command reaches runner/tool resolution, but testssl.sh is not installed locally.

Explicit port preservation smoke test:

node plugins/connectors/testssl-inspector/scripts/scan.js --target=mail.example.com:587 --starttls=smtp --no-docker --output=json
echo $?

Result:

[testssl-inspector] testssl.sh not on PATH. Install via: brew install testssl (macOS), apt install testssl.sh (Debian/Ubuntu), or git clone https://github.com/testssl/testssl.sh ~/.local/share/testssl.sh && export PATH="$HOME/.local/share/testssl.sh:$PATH". Or rerun with --docker.
3

This confirms an explicit-port STARTTLS command is accepted and reaches runner/tool resolution.

Unknown protocol path:

node plugins/connectors/testssl-inspector/scripts/scan.js --target=mail.example.com --starttls=bogus --output=json
echo $?

Result:

[testssl-inspector] unknown STARTTLS protocol: bogus. Supported protocols: smtp, imap, pop3, ftp, ldap, postgres, mysql
2

Closes #165

Summary by CodeRabbit

  • New Features
    • Added STARTTLS scanning for multiple protocols with automatic default-port selection and preservation of explicitly provided target ports.
    • STARTTLS scan outputs now use protocol-specific endpoint identifiers (starttls+<proto>://...) and include STARTTLS-related metadata.
  • Documentation
    • Updated connector and skill docs to clarify default HTTPS targeting, supported --starttls=<proto> options, and that implicit TLS services (e.g., SMTPS on 465) must be scanned as normal TLS endpoints.
    • Refreshed scan command guidance and examples.
  • Tests
    • Added STARTTLS test coverage for protocol allowlisting, port handling (including bracketed IPv6), CLI argument generation, and findings normalization.

@ahmedhxssam
ahmedhxssam requested a review from a team as a code owner June 15, 2026 09:41
@qodo-code-review

qodo-code-review Bot commented Jun 15, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 17 rules

Grey Divider


Action required

1. Docker JSON path mismatch ✓ Resolved 🐞 Bug ☼ Reliability
Description
In Docker mode the JSON output path is generated as a container path (/tmp/scan-out/...), but
runTestssl() later reads that same path on the host filesystem, so --docker scans will fail when
trying to load the JSON results.
Code

plugins/connectors/testssl-inspector/scripts/scan.js[R238-256]

  const out = outDir || CACHE_DIR;
  const jsonPath = path.join(out, `testssl-raw-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.json`);
  const base = [
    '--quiet', '--warnings', 'off', '--color', '0',
    '--jsonfile-pretty', jsonPath,
  ];
  if (mode === 'fast') base.push('--fast');
+  if (starttls) {
+    base.push('--starttls', starttls);
+  }
  base.push(target);
  base.__jsonPath = jsonPath;
  return base;
}

-async function runTestssl(runner, target, mode, log) {
+async function runTestssl(runner, target, mode, starttls, log) {
  const argv = runner.argv(target, mode);
  const jsonPath = argv.__jsonPath;
  log(`scanning ${target}`);
Evidence
The docker runner mounts CACHE_DIR into the container at /tmp/scan-out and calls testsslArgs() with
outDir '/tmp/scan-out', which makes __jsonPath a container-only path. runTestssl() then reads
__jsonPath directly from the host filesystem, where /tmp/scan-out is not the mounted directory, so
the JSON read will fail.

plugins/connectors/testssl-inspector/scripts/scan.js[173-186]
plugins/connectors/testssl-inspector/scripts/scan.js[237-260]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
In `--docker` mode, `testsslArgs()` sets `argv.__jsonPath` to a container path (e.g. `/tmp/scan-out/...json`). After `docker run` completes, `runTestssl()` uses `fs.readFile(jsonPath)` on the host, which should instead read from `${CACHE_DIR}/...json` (the bind-mounted directory).

### Issue Context
Docker binds `${CACHE_DIR}` (host) to `/tmp/scan-out` (container). The JSON file is written inside the container to `/tmp/scan-out/<file>`, which appears on the host at `${CACHE_DIR}/<file>`.

### Fix Focus Areas
- plugins/connectors/testssl-inspector/scripts/scan.js[173-201]
- plugins/connectors/testssl-inspector/scripts/scan.js[237-263]

### Suggested approach
- Generate a filename once (e.g. `const fname = ...`), and set:
 - `containerJsonPath = path.posix.join('/tmp/scan-out', fname)` for the `--jsonfile-pretty` argument.
 - `hostJsonPath = path.join(CACHE_DIR, fname)` for `base.__jsonPath`.
- Alternatively, keep `--jsonfile-pretty` pointing at the container path but translate `argv.__jsonPath` to the host path in the docker runner (e.g., replace the `/tmp/scan-out/` prefix with `${CACHE_DIR}/` before reading).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Node script in connector plugin 📘 Rule violation ⌂ Architecture
Description
The modified plugins/connectors/testssl-inspector/scripts/scan.js is a Node.js entrypoint located
under a non-allowed (non-persona) plugin directory. This violates the requirement that Node.js
scripts only exist under the allowed persona plugins, creating compliance and runtime-governance
risk.
Code

plugins/connectors/testssl-inspector/scripts/scan.js[R35-46]

+const STARTTLS_PORTS = Object.freeze({
+  smtp: 25,
+  imap: 143,
+  pop3: 110,
+  ftp: 21,
+  ldap: 389,
+  postgres: 5432,
+  mysql: 3306,
+  smtps: 465,
+});
+
+const SUPPORTED_STARTTLS = Object.keys(STARTTLS_PORTS).join(', ');
Evidence
PR Compliance ID 396516 restricts Node.js scripts to specific persona plugins only. The PR modifies
plugins/connectors/testssl-inspector/scripts/scan.js (a Node.js script) within a connector plugin
path, which is outside the allowed persona plugin set.

Rule 396516: Restrict Node.js scripts to allowed persona plugins
plugins/connectors/testssl-inspector/scripts/scan.js[35-46]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`plugins/connectors/testssl-inspector/scripts/scan.js` is a Node.js runtime entrypoint, but it lives under `plugins/connectors/...`, which is not one of the allowed persona plugins.

## Issue Context
Compliance policy restricts Node.js scripts to persona plugins named exactly: `grc-engineer`, `grc-auditor`, `grc-internal`, or `grc-tprm`. This PR modifies a Node.js script in a connector plugin, which violates that restriction.

## Fix Focus Areas
- plugins/connectors/testssl-inspector/scripts/scan.js[35-46]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Error target not resolved ✓ Resolved 🐞 Bug ◔ Observability
Description
When STARTTLS default-port expansion is applied, failures still record/log the original target
(without the appended port), so stderr and the JSON errors[] output can disagree with the actual
scan target.
Code

plugins/connectors/testssl-inspector/scripts/scan.js[R89-94]

+      const finalTarget = withDefaultStarttlsPort(target, args.starttls);
+      const raw = await runTestssl(runner, finalTarget, mode, args.starttls, log);
+      const doc = normalizeTargetFindings(raw, finalTarget, runId, runner.version, expansion);
      findings.push(doc);
    } catch (err) {
      errors.push({ target, error: err.message });
Evidence
The scan and normalization run against finalTarget, but on error the code uses target (original
string) in both the logged message and the errors array, so the reported target may omit the
effective port that was actually used.

plugins/connectors/testssl-inspector/scripts/scan.js[87-96]
plugins/connectors/testssl-inspector/scripts/scan.js[230-235]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`finalTarget` (with default STARTTLS port appended) is used for scanning and for normalization, but the `catch` path still logs/persists the original `target`. This makes troubleshooting confusing for STARTTLS scans when the user omitted an explicit port.

### Issue Context
This only affects the error path (when a scan throws). Successful scans already use `finalTarget` for `metadata.target`.

### Fix Focus Areas
- plugins/connectors/testssl-inspector/scripts/scan.js[87-97]
- plugins/connectors/testssl-inspector/scripts/scan.js[230-235]

### Suggested approach
- In the loop, compute `finalTarget` outside the try/catch (or store it in a variable accessible to the catch).
- In the catch block, log and store `finalTarget` as the primary `target` value.
- Optionally include both values, e.g. `{ target: finalTarget, original_target: target, error: ... }`. This preserves user input while accurately reflecting what was attempted.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

STARTTLS support is added to the testssl-inspector connector. scan.js gains --starttls=<proto> parsing, protocol-based default ports, target rewriting, runner wiring, and STARTTLS-aware result normalization. The docs, skill guide, and tests are updated to match.

Changes

STARTTLS Support for testssl-inspector

Layer / File(s) Summary
CLI parsing and runner plumbing
plugins/connectors/testssl-inspector/scripts/scan.js, tests/testssl-inspector-starttls.test.mjs
Adds the supported STARTTLS protocol-to-port map, parses and validates --starttls=<protocol>, initializes args.starttls, rewrites targets without explicit ports, and forwards starttls through resolveRunner, testsslArgs, and runTestssl. The tests cover protocol allowlisting, default-port rewriting, Docker path wiring, and --starttls argument inclusion.
Findings normalization and exports
plugins/connectors/testssl-inspector/scripts/scan.js, tests/testssl-inspector-starttls.test.mjs
Updates target parsing for bracketed IPv6 hosts, emits STARTTLS-specific endpoint URIs, stores starttls in normalized metadata, and exports the STARTTLS helpers plus normalization functions. The tests cover STARTTLS URI/metadata output for hostname and IPv6 targets.
Documentation updates
plugins/connectors/testssl-inspector/commands/scan.md, plugins/connectors/testssl-inspector/README.md, plugins/connectors/testssl-inspector/skills/testssl-inspector-expert/SKILL.md
Documents --starttls=<proto>, protocol default ports, explicit-port handling, STARTTLS URI formatting, example SMTP/IMAP scans, and the updated output-file metadata fields.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 Hop hop, ports align,
SMTP and IMAP join the line.
IPv6 and STARTTLS glow,
URIs and metadata flow.
This bunny twitches ears with glee,
For docs and code now agree.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR adds STARTTLS support, but it rejects smtps as a STARTTLS protocol instead of accepting it with port 465 as requested in #165. Allow --starttls=smtps and map it to port 465, or update the issue scope if implicit-TLS protocols are intentionally unsupported.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the primary change: adding STARTTLS support to testssl-inspector.
Out of Scope Changes check ✅ Passed The changes stay focused on STARTTLS support, related docs, and tests, with no clear unrelated scope creep.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add STARTTLS support to testssl-inspector scan wrapper
✨ Enhancement 📝 Documentation 🕐 10-20 Minutes

Grey Divider

Walkthroughs

Description
• Add --starttls= to enable scanning STARTTLS services via testssl.sh.
• Validate allowed STARTTLS protocols and default ports; preserve explicit target ports.
• Document STARTTLS usage and examples in README and scan command docs.
Diagram
graph TD
  A["scan.js (CLI)"] --> B["parseArgs()"] --> C["STARTTLS ports map"] --> D["withDefaultStarttlsPort()"] --> E["resolveRunner()/testsslArgs()"] --> F["testssl.sh"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Pass through `--starttls` without protocol allowlist/port defaults
  • ➕ Less wrapper logic; automatically supports any future testssl STARTTLS modes
  • ➖ Worse UX: users must always supply correct ports
  • ➖ No early validation; errors shift to testssl output/exit codes
2. Use a host/port parser that handles IPv6 literals explicitly
  • ➕ Avoids false 'port present' detection for IPv6 targets containing ':'
  • ➕ Clearer and more robust target normalization
  • ➖ More code and/or a new dependency
  • ➖ Slightly larger surface area to test

Recommendation: Current approach (explicit allowlist + default-port inference + passthrough to testssl) is a good UX/robustness balance. Consider tightening target parsing for IPv6 (':' detection) if IPv6 targets are in scope, and remove/avoid unused parameters (e.g., runTestssl currently receives starttls but doesn’t use it directly).

Grey Divider

File Changes

Enhancement (1)
scan.js Parse/validate '--starttls', infer ports, and pass through to testssl +46/-10

Parse/validate '--starttls', infer ports, and pass through to testssl

• Adds a STARTTLS protocol allowlist with default ports, parses '--starttls=<proto>' with usage errors for unknown values, and appends a default port when a target has none. Threads the STARTTLS value into runner argument construction so '--starttls <proto>' is forwarded to testssl.sh for both docker and local runners.

plugins/connectors/testssl-inspector/scripts/scan.js


Documentation (2)
README.md Document STARTTLS protocols and default-port behavior +12/-1

Document STARTTLS protocols and default-port behavior

• Replaces the prior HTTPS-only scope note with STARTTLS support documentation. Lists supported protocols with their default ports and explains default-port insertion vs explicit-port preservation.

plugins/connectors/testssl-inspector/README.md


scan.md Add '--starttls' option docs and STARTTLS examples +14/-4

Add '--starttls' option docs and STARTTLS examples

• Documents the new '--starttls=<proto>' flag, including supported protocols and port defaulting rules. Adds example commands for SMTP/IMAP STARTTLS scans and updates scope wording to reflect STARTTLS support.

plugins/connectors/testssl-inspector/commands/scan.md


Grey Divider

Qodo Logo

@greptile-apps

greptile-apps Bot commented Jun 15, 2026

Copy link
Copy Markdown

Greptile Summary

This PR wires --starttls=<proto> into the testssl-inspector scan wrapper, enabling TLS assessment of SMTP, IMAP, POP3, FTP, LDAP, Postgres, and MySQL services. It correctly validates protocols, defaults ports, threads starttls through normalization to emit starttls+<proto>:// URIs, and adds IPv6-bracket-aware port detection — including fixing a previously-reported issue where resource.uri was always https:// for STARTTLS targets.

  • scan.js: Adds STARTTLS_PORTS and IMPLICIT_TLS_PORTS maps, withDefaultStarttlsPort, hasExplicitPort, and endpointUri; threads starttls through resolveRunner, testsslArgs, and normalizeTargetFindings; adds metadata.effective_target and metadata.starttls fields.
  • Tests: New testssl-inspector-starttls.test.mjs covers protocol allowlist, port defaulting, IPv6 handling, CLI arg generation, and URI normalization; all five added tests pass.
  • Docs: README.md, commands/scan.md, and SKILL.md updated consistently with new protocol list, port defaults, and URI format.

Confidence Score: 4/5

Safe to merge for non-docker usage; the --docker flag remains broken for STARTTLS scans (and was broken pre-PR) due to __jsonPath being lost through array spread in the docker argv closure.

The non-docker path is correct end-to-end: protocol validation, port defaulting, testsslArgs construction, normalizeTargetFindings threading, and URI generation all work. The docker runner's argv closure spreads testsslArgs output into a new array, silently dropping the __jsonPath property, so runTestssl receives undefined as the JSON file path and throws on every docker scan. The new docker test passes because it calls testsslArgs() directly rather than exercising the argv closure.

The resolveRunner docker branch in plugins/connectors/testssl-inspector/scripts/scan.js (lines ~196–208) needs __jsonPath re-attached to the constructed argv array after the spread. The corresponding test in tests/testssl-inspector-starttls.test.mjs should exercise runner.argv(target, mode).__jsonPath rather than testsslArgs().__jsonPath to catch this gap.

Important Files Changed

Filename Overview
plugins/connectors/testssl-inspector/scripts/scan.js Core STARTTLS implementation: argument parsing, port defaulting, URI scheme generation, and normalizeTargetFindings threading are all correct and well-tested. However, the docker argv closure spreads testsslArgs output into a new array, silently dropping __jsonPath; docker runs will always fail at fs.readFile(undefined) regardless of the hostOutDir fix added to testsslArgs.
tests/testssl-inspector-starttls.test.mjs Good unit test coverage for protocol allowlist, port defaulting, IPv6 handling, and URI generation. The docker test validates testsslArgs() in isolation and passes, but does not exercise the argv closure in resolveRunner, so the __jsonPath propagation bug in the docker runner is not caught.
plugins/connectors/testssl-inspector/README.md Documentation correctly lists the seven STARTTLS protocols with default ports and clarifies that implicit-TLS services (e.g., SMTPS on 465) should be scanned without --starttls.
plugins/connectors/testssl-inspector/commands/scan.md Command docs updated with --starttls option, default-port behavior, and starttls+:// URI format. Consistent with code and README.
plugins/connectors/testssl-inspector/skills/testssl-inspector-expert/SKILL.md Skill docs updated to document metadata.effective_target, metadata.starttls, and STARTTLS URI format. Matches the implementation.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CLI as CLI (scan.js main)
    participant PA as parseArgs
    participant RR as resolveRunner
    participant TA as testsslArgs
    participant RT as runTestssl
    participant TS as testssl.sh / docker
    participant NF as normalizeTargetFindings

    CLI->>PA: "argv (--target, --starttls=smtp)"
    PA-->>CLI: "args {targets, starttls:"smtp"}"

    CLI->>RR: "{useDocker, configBinary, starttls:"smtp"}"
    RR->>TA: (target, mode, "smtp") — baked into argv closure
    TA-->>RR: base[] with __jsonPath set
    RR-->>CLI: "runner {argv closure, cmd}"

    loop for each target
        CLI->>CLI: withDefaultStarttlsPort(target, "smtp") → finalTarget:25
        CLI->>RT: runner, finalTarget, mode
        RT->>RT: "argv = runner.argv(target, mode)"
        Note over RT: argv.__jsonPath captured here
        RT->>TS: spawn(cmd, argv) — includes --starttls smtp
        TS-->>RT: JSON written to jsonPath
        RT-->>CLI: raw JSON
        CLI->>NF: "raw, finalTarget, starttls="smtp", originalTarget"
        NF-->>CLI: Finding doc (uri: starttls+smtp://host:25/)
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant CLI as CLI (scan.js main)
    participant PA as parseArgs
    participant RR as resolveRunner
    participant TA as testsslArgs
    participant RT as runTestssl
    participant TS as testssl.sh / docker
    participant NF as normalizeTargetFindings

    CLI->>PA: "argv (--target, --starttls=smtp)"
    PA-->>CLI: "args {targets, starttls:"smtp"}"

    CLI->>RR: "{useDocker, configBinary, starttls:"smtp"}"
    RR->>TA: (target, mode, "smtp") — baked into argv closure
    TA-->>RR: base[] with __jsonPath set
    RR-->>CLI: "runner {argv closure, cmd}"

    loop for each target
        CLI->>CLI: withDefaultStarttlsPort(target, "smtp") → finalTarget:25
        CLI->>RT: runner, finalTarget, mode
        RT->>RT: "argv = runner.argv(target, mode)"
        Note over RT: argv.__jsonPath captured here
        RT->>TS: spawn(cmd, argv) — includes --starttls smtp
        TS-->>RT: JSON written to jsonPath
        RT-->>CLI: raw JSON
        CLI->>NF: "raw, finalTarget, starttls="smtp", originalTarget"
        NF-->>CLI: Finding doc (uri: starttls+smtp://host:25/)
    end
Loading

Comments Outside Diff (1)

  1. plugins/connectors/testssl-inspector/scripts/scan.js, line 196-209 (link)

    P1 Docker argv.__jsonPath lost through array spread — docker runs always fail

    The docker argv closure spreads testsslArgs(...) into a new array literal, but __jsonPath is a non-index property on the returned array. JavaScript's spread operator (...) only yields indexed elements, so __jsonPath is silently dropped. Any docker run reaches runTestssl with argv.__jsonPath === undefined, then calls fs.readFile(undefined, 'utf8'), and throws "testssl produced no parseable JSON at undefined".

    The new 'docker testssl args write inside the container but read from host cache' test validates testsslArgs() in isolation (where __jsonPath is correctly set), but never exercises the argv closure in resolveRunner, so this gap is invisible in the test suite. The fix in testsslArgs (adding hostOutDir to map the host path) is the right idea but never reaches runTestssl.

    The simplest fix: capture __jsonPath before spreading and re-attach it to the result inside the closure:

    argv: (target, mode) => {
      const inner = testsslArgs(target, mode, starttls, '/tmp/scan-out', CACHE_DIR);
      const result = [
        'run', '--rm', '--network', 'host',
        '-v', `${CACHE_DIR}:/tmp/scan-out`,
        'drwetter/testssl.sh:latest',
        ...inner,
      ];
      result.__jsonPath = inner.__jsonPath;
      return result;
    },

    Fix in Claude Code Fix in Codex Fix in Cursor

Fix All in Claude Code Fix All in Codex Fix All in Cursor

Reviews (4): Last reviewed commit: "fix(testssl-inspector): drop dead runTes..." | Re-trigger Greptile

Comment thread plugins/connectors/testssl-inspector/scripts/scan.js Outdated
Comment thread plugins/connectors/testssl-inspector/scripts/scan.js
Comment thread plugins/connectors/testssl-inspector/scripts/scan.js

@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

🤖 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 `@plugins/connectors/testssl-inspector/scripts/scan.js`:
- Around line 230-234: The withDefaultStarttlsPort function incorrectly detects
explicit ports by checking if target.includes(':'), which treats IPv6 addresses
as having explicit ports even when they don't (e.g., [2001:db8::1] has colons
but no port). Fix the port detection logic to properly handle IPv6 literals in
square brackets: if the target starts with '[', check whether there's a colon
after the closing bracket ']' to determine if a port is specified; otherwise,
check for the presence of a colon to determine if a port exists. This ensures
the default port is correctly appended only when no explicit port is provided.
🪄 Autofix (Beta)

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 84983c7b-e419-4c9f-94bc-9b7adf3c4081

📥 Commits

Reviewing files that changed from the base of the PR and between 42cdc08 and 5db7073.

📒 Files selected for processing (3)
  • plugins/connectors/testssl-inspector/README.md
  • plugins/connectors/testssl-inspector/commands/scan.md
  • plugins/connectors/testssl-inspector/scripts/scan.js

Comment thread plugins/connectors/testssl-inspector/scripts/scan.js
Co-authored-by: Ethan Troy <ethanolivertroy@users.noreply.github.com>

@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

🤖 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 `@plugins/connectors/testssl-inspector/scripts/scan.js`:
- Around line 88-90: `metadata.target` is being populated with the expanded
`finalTarget` instead of the user-provided input, causing it to diverge from the
original target value. Update the flow in `scan.js` so `runTestssl` still uses
`finalTarget` for execution, but `normalizeTargetFindings` receives the original
`target` separately and stores that in `metadata.target`. Adjust the
`normalizeTargetFindings` signature and call sites accordingly, using the
existing `finalTarget`, `target`, and `normalizeTargetFindings` symbols to keep
host/port handling and metadata consistent.
🪄 Autofix (Beta)

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a6ff5fbe-a0fa-45f7-9163-06e40a84de65

📥 Commits

Reviewing files that changed from the base of the PR and between 5db7073 and 4ee5221.

📒 Files selected for processing (5)
  • plugins/connectors/testssl-inspector/README.md
  • plugins/connectors/testssl-inspector/commands/scan.md
  • plugins/connectors/testssl-inspector/scripts/scan.js
  • plugins/connectors/testssl-inspector/skills/testssl-inspector-expert/SKILL.md
  • tests/testssl-inspector-starttls.test.mjs
✅ Files skipped from review due to trivial changes (1)
  • plugins/connectors/testssl-inspector/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugins/connectors/testssl-inspector/commands/scan.md

Comment thread plugins/connectors/testssl-inspector/scripts/scan.js Outdated
cursoragent and others added 2 commits June 26, 2026 05:02
Co-authored-by: Ethan Troy <ethanolivertroy@users.noreply.github.com>
…TLS errors

- Remove the unused `starttls` parameter from runTestssl(); the flag is
  already baked into the runner's argv closure, so the argument had no
  effect (addresses Greptile review on PR GRCEngClub#197).
- Reject implicit-TLS service names (smtps, imaps, pop3s, ftps, ldaps) with a
  precise hint to scan them as plain TLS on their implicit-TLS port, rather
  than the generic "unknown STARTTLS protocol" message.
- Document metadata.effective_target in the expert SKILL.md so the docs match
  the emitted finding shape.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ahmedhxssam

Copy link
Copy Markdown
Author

Hi @ethanolivertroy, I reviewed the automated feedback and pushed a focused follow-up in commit e201220.

The update removes a dead parameter, clarifies the implicit-TLS handling for SMTPS on port 465, documents metadata.effective_target, and adds targeted tests for default ports, explicit-port preservation, IPv6 handling, runner parity, and invalid protocols.

All checks pass: syntax validation, 6 targeted STARTTLS tests, and all 49 fixture-contract checks. I would appreciate a maintainer review when you have a chance. Thank you!

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@ahmedhxssam

Copy link
Copy Markdown
Author

Hi @ethanolivertroy, just following up on PR #197 since the final update has been ready since June 28. The PR remains mergeable, the targeted tests and all 49 fixture checks pass, and the upstream workflows appear to be awaiting maintainer authorization. When you have a chance, could you approve the workflows and review the PR? Thank you again.

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.

Add STARTTLS protocol support to testssl-inspector

2 participants