Skip to content

ACOMMONS-241 Add the approved identifier URL inventory and matcher - #593

Merged
ZiadMarey merged 7 commits into
zm/ACOMMONS-237from
zm/ACOMMONS-241
Nov 12, 2026
Merged

ZiadMarey merged 7 commits into
zm/ACOMMONS-237from
zm/ACOMMONS-241

Conversation

@ZiadMarey

@ZiadMarey ZiadMarey commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Add the 29 approved JS-2698 authority/path patterns and a separate identifier URL matcher. Export the inventory as identifierUrls in cleartext-protocol-exclusions.json, with shared positive and negative regression cases and npm package import verification. Existing isSafeWithoutTls behavior is preserved.

Depends on #592; targets zm/ACOMMONS-237 so the diff contains only the identifier additions.

Validation: clean Maven verification with coverage passed all 1,261 Java tests and the assembled npm package import check. The Commons JAR is 188,114 bytes, below the unchanged 190,000-byte limit.

https://sonarsource.atlassian.net/browse/ACOMMONS-241


Summary by Gitar

  • Domain-wide exclusions:
    • Added neverssl.com and osmand.net to the domain exclusion pattern in CleartextProtocolFilter
  • Regression coverage:
    • Expanded cleartext-protocol-corpus.json with positive and negative identifier cases, including lookalike domains
  • Safe URL assertions:
    • Updated exporter test expectations to include auth0.com OAuth grant-type URLs as safe
  • XMPP exclusions:
    • Added http://jabber.org/features/ to safe identifier URL prefixes

This will update automatically on new commits.

@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

ACOMMONS-241

@ZiadMarey
ZiadMarey added this pull request to stack #594 November 5, 2026 12:20

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why do these additions require context checks when existing namespace and identifier-prefix exclusions don’t? If they are intended to follow the existing exclusion policy, we should integrate the domain/path mapping into the normal filter. If context-sensitive treatment is intentional, please explain the distinction and whether existing exclusions should eventually follow it too.

private static final Pattern CLEARTEXT_AUTHORITY = Pattern.compile(
"^(?:" + String.join("|", CLEARTEXT_SCHEMES) + ")://(?:[^@\\s/?#]++@)?(?<rest>[^\\s/?#]++)", Pattern.CASE_INSENSITIVE);

// JS-2698: exact authorities and case-sensitive path + query + fragment patterns.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think that we need to mention the JIRA ticket in the code here.

"^http://([^\\s/?#\\\\]+)([/?#][^\\s\\\\]*)?$", Pattern.CASE_INSENSITIVE);

/**
* Recognizes the namespace, schema, vocabulary and protocol identifier inventory shared with SonarJS.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think that it makes sense to mention SonarJS here.
Our configuration in analyzer-commons should be as much analyzer agnostic as possible.

The implementation looks okay to me so you probably only have to adjust the comment.

@ZiadMarey

Copy link
Copy Markdown
Contributor Author

@daniel-teuchert-sonarsource The distinction is intentional: JS-2698, which is why we’re adding these URLs, states to preserve the existing exclusions while still reporting actual HTTP requests to the newly added identifier URLs. This PR keeps the new URL matching separate from isSafeWithoutTls() so the JS can apply context-sensitive checks before suppressing an issue.

You’re right that the same concern applies to existing namespace and identifier-prefix exclusions. To preserve their current treatment for compitability, rather than because those URLs can never be request destinations.

Let me know if you have any questions 😄.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM!

One caveat about completeness: the requested additions are complete, but the resulting list does not preserve every current SonarJS exclusion. The existing SonarJS inventory also contains:

cyclonedx.org — whole host
adlnet.gov — whole host
etherx.jabber.org — whole host
snomed.info — whole host (Only /sct is excluded by this PR)

Please double check if this is intended and if not, add these entries as well.

@ZiadMarey

Copy link
Copy Markdown
Contributor Author

@daniel-teuchert-sonarsource Thank you for pointing that out. I have already discussed with @pierre-loup-tristant-sonarsource he confirmed that we should keep Analyzer Commons’ existing behavior for these four hosts. 👍

@gitar-bot

gitar-bot Bot commented Nov 12, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 🟡 Medium risk 4 closed / 4 findings

Expanding cleartext-protocol exclusions to entire neverssl.com and osmand.net domains could hide genuine insecure HTTP usage from security analysis.

Adds the 29 approved JS-2698 identifier URL authority/path patterns and a separate matcher, exported as identifierUrls in cleartext-protocol-exclusions.json with shared regression cases and npm import verification. Resolved the npm test shape assertions, the missing identifier-urls.json import, the commit ordering issue with the matcher API, and whitespace handling in the SonarJS helper. No open issues remain.

✅ 4 closed
✅ Quality: npm import test drops existing shape assertions instead of extending them

📄 sonar-analyzer-commons-configurations/src/test/js/npm-package.test.mjs:45-48
The consumer script used to check the documented shape of the package: the exclusion keys (cleartextProtocols, hostPatterns, safeUrlPrefixes), that http:// and the jabber prefix are present, the corpus keys, and that the corpus is non-empty. This PR deletes all of those checks and adds only two identifierUrls assertions. What remains is a deepEqual against the Java-generated files, and that passes even when both sides are equally wrong. For example, if cleartext-protocol-corpus.json were exported empty or without the new identifierUrls/nonIdentifierUrls groups, the check would still pass, even though the README tells consumers to run those cases. Restore the earlier assertions and add the new key lists, so the test actually verifies the documented package shape.

✅ Cross-PR: SonarJS imports identifier-urls.json, which this package never ships

📄 sonar-analyzer-commons-configurations/src/main/java/org/sonarsource/analyzer/commons/appsec/export/CleartextProtocolFilterExporter.java:60-62 📄 sonar-analyzer-commons-configurations/src/main/packaging/npm/README.md:24 📄 sonar-analyzer-commons-configurations/src/main/packaging/npm/README.md:33-35
Breaks when SonarJS#8325 resolves @sonarsource/analyzer-commons-configurations to a package built from this PR and loads the S5332 identifier helper.

How

  1. This PR puts the 29-entry inventory under the identifierUrls key of cleartext-protocol-exclusions.json (CleartextProtocolFilterExporter.java:60-62).
  2. The npm assembly and package.json files list ship only cleartext-protocol-exclusions.json and cleartext-protocol-corpus.json. Neither ships an identifier-urls.json.
  3. SonarJS imports @sonarsource/analyzer-commons-configurations/identifier-urls.json (identifier-urls.ts:19, identifier-urls.test.ts:3), so module resolution fails.
  4. SonarJS's test also asserts the inventory is {} (identifier-urls.test.ts:26), but this PR populates 29 entries.

Fix

  • This PR: Nothing needed if identifierUrls inside cleartext-protocol-exclusions.json is the intended contract, which the README documents. Otherwise, also ship a standalone identifier-urls.json.
  • SonarJS/SonarJS#8325: Import cleartext-protocol-exclusions.json and read .identifierUrls, then replace the empty-inventory test with the shared identifierUrls/nonIdentifierUrls corpus cases.

Compared 1e0100a with SonarJS/SonarJS#8325 at 4281d21

✅ Quality: First commit references matcher API that only exists in the next commit

📄 commons/src/main/java/org/sonarsource/analyzer/commons/appsec/CleartextProtocolFilter.java:228-242 📄 sonar-analyzer-commons-configurations/src/test/java/org/sonarsource/analyzer/commons/appsec/export/CleartextProtocolCorpusExporterTest.java:53-67
Commit dc0e289 ("Add the approved identifier URL inventory and matcher") adds CleartextProtocolCorpusExporterTest, which calls CleartextProtocolFilter.isKnownIdentifier and exportIdentifierUrls. Neither method exists at that commit. IDENTIFIER_URLS, isKnownIdentifier and exportIdentifierUrls only appear in 73aa693, the commit described as the npm export. So dc0e289 doesn't compile on its own, which breaks git bisect. If the PR is rebase-merged, the target branch history also ends up with a commit that doesn't build. The commit contents look swapped relative to their messages. Move the CleartextProtocolFilter matcher and inventory changes into dc0e289, or squash the two commits.

✅ Cross-PR: SonarJS helper rejects whitespace-wrapped identifiers that Java accepts

📄 sonar-analyzer-commons-configurations/src/main/packaging/npm/README.md:79-80 📄 commons/src/test/resources/org/sonarsource/analyzer/commons/appsec/cleartext-protocol-corpus.json:38 📄 commons/src/test/resources/org/sonarsource/analyzer/commons/appsec/cleartext-protocol-corpus.json:45
Breaks when SonarJS#8325 consumes this PR's inventory and runs the shared corpus (or receives a URL literal with surrounding whitespace) through isKnownIdentifierUrl.

How

  1. This PR's README requires stripping surrounding whitespace before matching, as Java's String.strip() does (sonar-analyzer-commons-configurations/src/main/packaging/npm/README.md:79). Java does this in CleartextProtocolFilter.isKnownIdentifier via url.strip() (CleartextProtocolFilter.java:272).
  2. The shared corpus has whitespace-wrapped positives, such as " http://auth0.com/oauth/grant-type/password-realm " and " http://www.topografix.com/GPX " (cleartext-protocol-corpus.json:38,45).
  3. The SonarJS helper runs the anchored regex /^http:\/\/([^\s/?#\]+)([/?#][^\s\]*)?$/i directly on value and never trims it (packages/analysis/src/jsts/rules/S5332/identifier-urls.ts:31-34).
  4. Those inputs return false in SonarJS but true in Java, so the parity check the README asks consumers to run fails on them.

Fix

  • This PR: nothing needed.
  • SonarJS/SonarJS#8325: apply the regex to the stripped value (use value.trim(), or a trim matching Java strip()), then run the shared identifierUrls/nonIdentifierUrls corpus in the helper tests.

Compared 73aa693 with SonarSource/SonarJS#8325 at 4281d21

Verification Rules 2/2 met Repos 9 inspected · PRs 2 inspected

Functional validation No results

Rules 2 passed 2 not applicable

✅ Internal artifact registries
✅ Repository license compliance

Broader impact Repos 9 inspected PRs 2 inspected
Cross-repo 9 repositories inspected 0 open impacts

SonarSource/sonar-xml Inspected
SonarSource/sonar-php Inspected
SonarSource/sonar-flex Inspected
SonarSource/sonar-dotnet Inspected
SonarSource/sonar-java-symbolic-execution Inspected

4 more repositories

Cross-PR 2 PRs inspected 0 open impacts

PR 592: ACOMMONS-237 Export the S5332 identifier URL inventory through the shared npm package Inspected
PR 8325: JS-2774 Consume the shared identifier inventory. Inspected

Auto-approval Not enabled

Set up

For more verification details, comment gitar display:verbose.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqube-next

Copy link
Copy Markdown

@ZiadMarey
ZiadMarey merged commit ccc7f0d into master Nov 12, 2026
11 checks passed
@ZiadMarey
ZiadMarey deleted the zm/ACOMMONS-241 branch November 12, 2026 14:26
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