Skip to content

feat: #140 add trusted_reference_domains to LLM analysis policy - #141

Merged
vineethsai7 merged 8 commits into
cisco-ai-defense:mainfrom
ojacques:feat/trusted-reference-domains
Aug 3, 2026
Merged

vineethsai7 merged 8 commits into
cisco-ai-defense:mainfrom
ojacques:feat/trusted-reference-domains

Conversation

@ojacques

@ojacques ojacques commented Jul 7, 2026 •

Copy link
Copy Markdown
Contributor

Pull Request

Description

Add a policy-driven mechanism to demote LLM findings (transitive trust, supply chain) to LOW when all referenced domains are declared as trusted in the scan policy.

This addresses systematic false positives for organizations hosting skills and documentation on self-managed GitLab/GitHub instances, where the LLM analyzer flags references to internal repos as external threats.

The mechanism mirrors known_installer_domains: findings are demoted to LOW (maintaining visibility) rather than suppressed entirely.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement
  • Code refactoring
  • Test coverage improvement

Related Issues

Fixes #140

Changes Made

  • LLMAnalysisPolicy: new trusted_reference_domains field (set[str])
  • llm_analyzer._convert_to_findings: demotion logic after existing is_internal_file_reading filter
  • Two helpers: _references_only_trusted_domains (URL extraction) and _mentions_only_trusted_domains (plain-text domain detection)
  • default_policy.yaml: empty default list with documentation

Testing

Test Coverage

  • Unit tests added/updated
  • Integration tests added/updated
  • All tests pass locally
  • Test coverage maintained or improved

Manual Testing

Describe manual testing performed:

# Commands run for testing
skill-scanner scan examples/test-skill

Results:

  • Expected: [describe]
  • Actual: [describe]

Checklist

Code Quality

  • Code follows project style guidelines
  • Type hints added where applicable
  • Docstrings added/updated for public APIs
  • No hardcoded credentials or secrets
  • Error handling is comprehensive
  • Logging is appropriate

Documentation

  • README updated (if needed)
  • API documentation updated (if needed)
  • CHANGELOG updated
  • Code comments added for complex logic

Security

  • No new security vulnerabilities introduced
  • Input validation added where needed
  • Follows security best practices from workspace rules
  • No eval/exec on user input without sanitization

Testing

  • Tests pass: uv run pre-commit run --all-files
  • Benchmark passes: uv run python evals/runners/benchmark_runner.py
  • No regressions in existing functionality
  • Edge cases covered

Performance Impact

  • No significant performance regression
  • Performance benchmarks run (if applicable)
  • Resource usage is acceptable

Screenshots (if applicable)

Add screenshots or output examples if relevant.

Additional Notes

Any additional information reviewers should know.

Reviewer Checklist

For reviewers:

  • Code changes are clear and well-documented
  • Tests are comprehensive
  • No security issues introduced
  • Performance is acceptable
  • Documentation is updated

Summary by CodeRabbit

  • New Features

    • Added a configurable list of trusted reference domains for LLM analysis.
    • Findings about transitive trust or supply-chain references that only point to trusted domains may now be downgraded to low severity.
    • Untrusted or unrelated findings retain their existing severity.
  • Documentation

    • Updated the user guide with configuration details and an example policy.
  • Chores

    • Updated the default policy with an empty trusted-domain list.

Add a policy-driven mechanism to demote LLM findings (transitive trust,
supply chain) to LOW when all referenced domains are declared as trusted
in the scan policy.

This addresses systematic false positives for organizations hosting
skills and documentation on self-managed GitLab/GitHub instances, where
the LLM analyzer flags references to internal repos as external threats.

Changes:
- LLMAnalysisPolicy: new trusted_reference_domains field (set[str])
- llm_analyzer._convert_to_findings: demotion logic after existing
  is_internal_file_reading filter
- Two helpers: _references_only_trusted_domains (URL extraction) and
  _mentions_only_trusted_domains (plain-text domain detection)
- default_policy.yaml: empty default list with documentation

The mechanism mirrors known_installer_domains: findings are demoted to
LOW (maintaining visibility) rather than suppressed entirely.
@coderabbitai

coderabbitai Bot commented Jul 7, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@vineethsai7, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 47 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e6a84b12-310a-4ca2-b569-13743223e68c

📥 Commits

Reviewing files that changed from the base of the PR and between 8c22ce4 and 2bda187.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • docs/architecture/analyzers/llm-analyzer.md
  • docs/features/index.md
  • docs/reference/configuration-reference.md
  • docs/reference/dependencies-and-llm-providers.md
  • pyproject.toml
  • scripts/generate_reference_docs.py
  • skill_scanner/core/analyzers/llm_provider_config.py
  • tests/test_llm_analyzer.py
📝 Walkthrough

Walkthrough

This PR adds trusted_reference_domains to the llm_analysis policy. The analyzer detects trusted domains in URLs and prose, then demotes matching transitive-trust and supply-chain findings to LOW. Tests, defaults, and documentation cover the new behavior.

Changes

Trusted Reference Domains Feature

Layer / File(s) Summary
Policy schema and default configuration
skill_scanner/core/scan_policy.py, skill_scanner/data/default_policy.yaml
Adds trusted_reference_domains to LLMAnalysisPolicy, YAML loading and serialization, and an empty default list.
LLM analyzer severity demotion
skill_scanner/core/analyzers/llm_analyzer.py
Detects trusted domains in URLs and prose. Matching AITech-1.2 and AITech-9.3 findings are demoted to LOW.
Feature validation and policy documentation
tests/test_llm_analyzer.py, docs/user-guide/custom-policy-configuration.md
Tests URL and prose matching, severity demotion, category boundaries, and policy round trips. Documents the setting and adds it to an example policy.
Repository ignore rule
.gitignore
Adds ISSUE_DRAFT.md to ignored files.

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

Sequence Diagram(s)

sequenceDiagram
  participant LLMAnalyzer
  participant ScanPolicy
  participant Finding
  LLMAnalyzer->>ScanPolicy: read trusted_reference_domains
  LLMAnalyzer->>LLMAnalyzer: check URLs and domain mentions
  LLMAnalyzer->>Finding: demote matching finding severity to LOW
Loading
🚥 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 addition of trusted_reference_domains to the LLM analysis policy.
Linked Issues check ✅ Passed The changes implement the policy field, trusted-domain detection, LOW severity demotion, serialization, documentation, and tests required by issue [#140].
Out of Scope Changes check ✅ Passed All code, policy, documentation, and test changes support the trusted reference domain feature; the .gitignore update is non-code and incidental.
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

🧹 Nitpick comments (1)
skill_scanner/core/analyzers/llm_analyzer.py (1)

750-779: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Trailing punctuation after a bare domain URL breaks trust matching.

_URL_PATTERN doesn't exclude trailing punctuation (., ,, etc.), so a domain immediately followed by punctuation (no path) won't match a trusted entry, since the captured string retains the punctuation. This fails safe (no demotion) rather than being exploitable, but it's an untested edge case worth hardening.

♻️ Optional hardening
-        for domain in urls:
-            # Strip port if present (e.g. "gitlab.example.com:8443")
-            domain_no_port = domain.split(":")[0].lower()
+        for domain in urls:
+            # Strip port and trailing punctuation (e.g. "gitlab.example.com:8443," or "gitlab.example.com.")
+            domain_no_port = domain.split(":")[0].rstrip(".,;)\"'").lower()
🤖 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 `@skill_scanner/core/analyzers/llm_analyzer.py` around lines 750 - 779, The
trust-check in _references_only_trusted_domains is overly strict for bare URLs
because _URL_PATTERN can capture trailing punctuation, causing trusted domains
to miss exact matching. Update the URL handling in
_references_only_trusted_domains so each extracted domain is normalized to
remove trailing punctuation before the existing port-stripping and
trusted_reference_domains comparison, keeping the current behavior for untrusted
or missing URLs.
🤖 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 `@skill_scanner/core/analyzers/llm_analyzer.py`:
- Around line 606-621: Severity demotion is currently driven by free-text
matches in the LLM `description`, which is too loose and brittle. Update the
demotion logic in `llm_analyzer.py` to key off the parsed
`aitech_code`/`category` for the intended AITech-1.2 and supply-chain codes,
matching the same scoped pattern used by `is_internal_file_reading`, and remove
the dead `not is_internal_file_reading` check since that branch already
continues earlier. Keep the trusted-domain checks in place, but only apply the
LOW severity demotion when the finding’s classified code indicates the relevant
AITech category.

---

Nitpick comments:
In `@skill_scanner/core/analyzers/llm_analyzer.py`:
- Around line 750-779: The trust-check in _references_only_trusted_domains is
overly strict for bare URLs because _URL_PATTERN can capture trailing
punctuation, causing trusted domains to miss exact matching. Update the URL
handling in _references_only_trusted_domains so each extracted domain is
normalized to remove trailing punctuation before the existing port-stripping and
trusted_reference_domains comparison, keeping the current behavior for untrusted
or missing URLs.
🪄 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

Run ID: 028ebb9f-fb5c-4ba4-8af2-8afccbaae096

📥 Commits

Reviewing files that changed from the base of the PR and between 41fec4a and 35a32e1.

📒 Files selected for processing (6)
  • .gitignore
  • docs/user-guide/custom-policy-configuration.md
  • skill_scanner/core/analyzers/llm_analyzer.py
  • skill_scanner/core/scan_policy.py
  • skill_scanner/data/default_policy.yaml
  • tests/test_llm_analyzer.py

Comment thread skill_scanner/core/analyzers/llm_analyzer.py
gyrospectre and others added 7 commits July 24, 2026 08:47
ProviderConfig.validate() required a truthy credential for every provider
except Bedrock and Ollama, and the only credential source it checked for
Vertex was GOOGLE_APPLICATION_CREDENTIALS. This blocked ambient auth via
a GCE/Cloud Run attached service account or Workload Identity, even though
LiteLLM/google-auth already fall back to it automatically when no explicit
credential is passed -- the same pattern already supported for Bedrock's
IAM role. Excludes is_vertex from the check, mirroring the Bedrock/Ollama
precedent, and documents the fallback.
- _resolve_api_key() now returns None for Vertex instead of the
  GOOGLE_APPLICATION_CREDENTIALS path, since vertex_ai/gemini-* models
  set both is_vertex and is_gemini, which was causing the file path to
  be written into GEMINI_API_KEY.
- Regenerated configuration-reference.md via generate_reference_docs.py
  instead of hand-editing, and updated the underlying descriptions so
  the doc doesn't drift on next regeneration.

Addresses CodeRabbit review feedbak on cisco-ai-defense#144.

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

Caution

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

⚠️ Outside diff range comments (1)
tests/test_llm_analyzer.py (1)

921-928: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Require all referenced domains to pass the trust check.

The mixed URL test checks _references_only_trusted_domains in isolation. It does not test _convert_to_findings. The analyzer combines that result with _mentions_only_trusted_domains.

_mentions_only_trusted_domains returns true when any trusted-domain substring appears. A finding that contains both gitlab.example.com and evil.com can therefore be demoted to LOW. The same substring check can trust a look-alike such as evilgitlab.example.com.

Add end-to-end mixed URL, mixed prose, and look-alike-domain cases for both AITech-1.2 and AITech-9.3. Parse domain boundaries and require every referenced domain to be trusted before demotion.

This conflicts with the PR objective that demotion applies only when all referenced domains are trusted.

Suggested regression cases
+    def test_mentions_rejects_mixed_and_lookalike_domains(self):
+        analyzer = self._make_analyzer_with_trusted_domains(["gitlab.example.com"])
+        assert not analyzer._mentions_only_trusted_domains(
+            "gitlab.example.com/repo and evil.com/repo"
+        )
+        assert not analyzer._mentions_only_trusted_domains(
+            "evilgitlab.example.com/repo"
+        )

Also applies to: 957-973, 995-1013, 1111-1140

🤖 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 `@tests/test_llm_analyzer.py` around lines 921 - 928, Update the analyzer’s
end-to-end demotion logic in _convert_to_findings and the trust helpers
_references_only_trusted_domains/_mentions_only_trusted_domains so every
referenced domain must be explicitly trusted, using domain-boundary parsing
rather than substring matching. Add coverage for mixed URLs, mixed prose, and
look-alike domains for both AITech-1.2 and AITech-9.3, while preserving demotion
only when all references pass the trust check.
🤖 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.

Outside diff comments:
In `@tests/test_llm_analyzer.py`:
- Around line 921-928: Update the analyzer’s end-to-end demotion logic in
_convert_to_findings and the trust helpers
_references_only_trusted_domains/_mentions_only_trusted_domains so every
referenced domain must be explicitly trusted, using domain-boundary parsing
rather than substring matching. Add coverage for mixed URLs, mixed prose, and
look-alike domains for both AITech-1.2 and AITech-9.3, while preserving demotion
only when all references pass the trust check.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 443a9e02-ebb1-404e-9f66-7bbfa6fbb107

📥 Commits

Reviewing files that changed from the base of the PR and between 35a32e1 and 8c22ce4.

📒 Files selected for processing (2)
  • skill_scanner/core/analyzers/llm_analyzer.py
  • tests/test_llm_analyzer.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • skill_scanner/core/analyzers/llm_analyzer.py

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 21.42857% with 22 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
skill_scanner/core/analyzers/llm_analyzer.py 16.00% 21 Missing ⚠️
...kill_scanner/core/analyzers/llm_provider_config.py 50.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@vineethsai7
vineethsai7 merged commit d5aa0fb into cisco-ai-defense:main Aug 3, 2026
8 checks passed
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.

[FEATURE] Policy-driven trusted reference domains to demote LLM false positives on internal infrastructure

4 participants