Package: lintian
Version: 2.134.0
Severity: minor
Tags: patch

When a changelog entry body mentions a 4-component Standards-Version
(e.g. "Bump Standards-Version to 4.7.4.1, no changes required."),
lintian incorrectly fires the standards-version-inconsistent hint with
a garbled comparison.  Debian Policy §4.6.1 explicitly permits the
4-component form.

Reproducer
----------

debian/control:

  Standards-Version: 4.7.4.1

debian/changelog entry body:

  * Bump Standards-Version to 4.7.4.1, no changes required.

lintian output (2.134.0):

  W: <source>: standards-version-inconsistent 4.7.4 != 7.4.1

The version "7.4.1" does not appear anywhere in the package or on the
system.  It is an artefact of the regex in
Fields/StandardsVersion.pm extracting the last three-component
substring of "4.7.4.1", which is "7.4.1".

Root cause
----------

File: /usr/share/lintian/lib/Lintian/Check/Fields/StandardsVersion.pm
Lintian version: 2.134.0

Lines 68-71 correctly normalize the control-field version to three
components by taking the first three elements of @compliance_components
and joining them with dots ("4.7.4.1" becomes "4.7.4" in
$compliance_normalized).

Lines 100-102 extract the version string mentioned in the changelog:

  if ($changes
      =~ /(?:standards[ 
-]?version|\bs-v:?\s).*\b(\d+\.\d+\.\d+)\b(?!.*\b\d+\.\d+\.\d+\b)/i
  ) {

The `.*` is greedy and the negative lookahead forces it to settle on
the *last* three-component substring in the line.  In the string
"4.7.4.1" there are two overlapping three-component matches: "4.7.4"
(at position 0) and "7.4.1" (starting between the first and second
dots).  The greedy match picks "7.4.1", so $changelog_standard (line
103) is set to "7.4.1" instead of "4.7.4".

The subsequent comparison on line 107 ("4.7.4" ne "7.4.1") fires the
hint.

Suggested fix
-------------

Make the match non-greedy and optionally capture a fourth component so
the comparison works correctly for both 3- and 4-component versions:

  # Before (line 101):
  =~ /(?:standards[ 
-]?version|\bs-v:?\s).*\b(\d+\.\d+\.\d+)\b(?!.*\b\d+\.\d+\.\d+\b)/i

  # After:
  =~ /(?:standards[ -]?version|\bs-v:?\s).*?\b(\d+\.\d+\.\d+(?:\.\d+)?)\b/i

`.*?` stops at the first version string after the keyword rather than
the last.  The optional `(?:\.\d+)?` captures a fourth component when
present, so $changelog_standard becomes "4.7.4.1"; the existing
normalisation on lines 68-71 already strips the fourth component from
$compliance_normalized, so the ne comparison then correctly handles
both 3 and 4 component mentions in the changelog.

Policy reference
----------------

Debian Policy 5.6.11:

  "Thus only the first three components of the policy version are
  significant in the Standards-Version control field, and so either
  these three components or all four components may be specified."

Workaround
----------

Use the 3-component form ("4.7.4") in both debian/control and in
changelog entry text.  This avoids the false positive and is the form
Policy cites as the primary reference.

Regards,
James

Reply via email to