Skip to content

feat(linter): add rule noUntrustedLicenses#9474

Merged
ematipico merged 9 commits intomainfrom
feat/no-untrusted-license
Mar 24, 2026
Merged

feat(linter): add rule noUntrustedLicenses#9474
ematipico merged 9 commits intomainfrom
feat/no-untrusted-license

Conversation

@ematipico
Copy link
Copy Markdown
Member

Summary

This is another lint rule I wanted to ship for a long time, and now that we have the infrastructure, here it is!

This lint rule catches dependencies that use untrusted libraries.

The code gen for license is already part of the analyser, and I bet no one knew it was there :D (that's how old this code is, and for how long I wanted it).

I vibe-coded the PR and checked all the code (rewrote it different times).

Test Plan

Added various tests

Docs

Added docs to the rule

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 13, 2026

🦋 Changeset detected

Latest commit: 12f4d84

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@ematipico ematipico requested review from a team March 13, 2026 18:09
@github-actions github-actions Bot added A-Project Area: project A-Linter Area: linter A-Tooling Area: internal tools L-JSON Language: JSON and super languages A-Diagnostic Area: diagnostocis labels Mar 13, 2026
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Mar 13, 2026

Merging this PR will not alter performance

✅ 58 untouched benchmarks
⏩ 159 skipped benchmarks1


Comparing feat/no-untrusted-license (0c24bc9) with main (085d324)

Open in CodSpeed

Footnotes

  1. 159 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 13, 2026

Parser conformance results on

js/262

Test result main count This PR count Difference
Total 53139 53139 0
Passed 51919 51919 0
Failed 1178 1178 0
Panics 42 42 0
Coverage 97.70% 97.70% 0.00%

jsx/babel

Test result main count This PR count Difference
Total 38 38 0
Passed 37 37 0
Failed 1 1 0
Panics 0 0 0
Coverage 97.37% 97.37% 0.00%

markdown/commonmark

Test result main count This PR count Difference
Total 652 652 0
Passed 652 652 0
Failed 0 0 0
Panics 0 0 0
Coverage 100.00% 100.00% 0.00%

symbols/microsoft

Test result main count This PR count Difference
Total 5466 5466 0
Passed 1915 1915 0
Failed 3551 3551 0
Panics 0 0 0
Coverage 35.03% 35.03% 0.00%

ts/babel

Test result main count This PR count Difference
Total 636 636 0
Passed 567 567 0
Failed 69 69 0
Panics 0 0 0
Coverage 89.15% 89.15% 0.00%

ts/microsoft

Test result main count This PR count Difference
Total 18875 18875 0
Passed 13013 13013 0
Failed 5861 5861 0
Panics 1 1 0
Coverage 68.94% 68.94% 0.00%

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 13, 2026

Walkthrough

Adds a new nursery lint rule NoUntrustedLicenses that analyses package.json dependency licenses using SPDX parsing and configurable trust rules. Wires ProjectLayout into the JSON analysis services and query infrastructure so rules can locate dependency manifests in node_modules (including hoisted lookups). Introduces SPDX expression parsing and trust evaluation in biome_package, exposes trust helpers, adds rule options and tests, and updates test harnesses and service wiring to propagate an optional ProjectLayout.

Possibly related PRs

Suggested reviewers

  • dyc3
  • Conaclos
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(linter): add rule noUntrustedLicenses' directly and clearly describes the main change: introducing a new linter rule for detecting untrusted licenses in dependencies.
Description check ✅ Passed The description explains the motivation (catching dependencies with untrusted libraries), mentions the infrastructure reuse, acknowledges iteration and review, and references tests and documentation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/no-untrusted-license

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
crates/biome_project_layout/src/project_layout.rs (1)

74-96: Pin the layout once for the whole walk.

The rustdoc is nicely clear, but the implementation re-pins the concurrent map on every ancestor hop via get_node_manifest_for_package(). Holding one pin here matches the neighbouring lookup helpers and avoids a bit of needless churn.

Suggested tidy-up
     pub fn get_dependency_manifest(
         &self,
         project_dir: &Utf8Path,
         dependency_name: &str,
     ) -> Option<PackageJson> {
-        for ancestor in project_dir.ancestors() {
-            let dep_path = ancestor.join("node_modules").join(dependency_name);
-            if let Some(manifest) = self.get_node_manifest_for_package(&dep_path) {
-                return Some(manifest);
-            }
-        }
-        None
+        let packages = self.0.pin();
+        project_dir.ancestors().find_map(|ancestor| {
+            let dep_path = ancestor.join("node_modules").join(dependency_name);
+            packages
+                .get(dep_path.as_path())
+                .and_then(|data| data.node_package.as_ref())
+                .and_then(|node_package| node_package.manifest.as_ref())
+                .cloned()
+        })
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_project_layout/src/project_layout.rs` around lines 74 - 96, The
loop in get_dependency_manifest re-acquires the concurrent layout pin on every
ancestor by calling get_node_manifest_for_package repeatedly; instead, acquire
the layout pin once before the for ancestor loop (e.g. obtain the pinned guard
from self.layout or whatever pin API the concurrent map exposes), then either
call a variant of get_node_manifest_for_package that takes a reference to that
pinned guard or pass the guard into the loop so each iteration reuses the same
pin; update get_dependency_manifest to hold that single pin for the whole walk
and adjust get_node_manifest_for_package signature if needed to accept the
pinned guard.
crates/biome_json_analyze/tests/spec_tests.rs (1)

163-175: Harden project_layout_for_json_test for real-world node_modules layouts.

The current one-level scan skips scoped packages (node_modules/@scope/pkg), and ok()? in the loop can bail out the whole helper on a single bad entry. A continue-based walk (plus scoped package handling) would make these tests less brittle.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_json_analyze/tests/spec_tests.rs` around lines 163 - 175, The
loop that builds the test ProjectLayout should be hardened: replace the current
for-entry usage that uses ok()? and thus can return early, with a continue-based
walk that skips individual broken entries instead of bailing the whole helper,
and add handling for scoped packages (directories whose name starts with '@') by
iterating their child package directories as well; specifically, update the loop
that reads std::fs::read_dir(node_modules_dir) to (a) on any read_dir, try_from,
or read_to_string error just continue rather than using ok()? to return, (b)
when an entry is a directory whose file_name starts with '@', iterate its
entries and process each child package the same way, and (c) continue to call
project_layout.insert_node_manifest(pkg_dir, manifest) only for successfully
parsed package.json files.
crates/biome_json_analyze/src/lint/nursery/no_untrusted_licenses.rs (1)

337-346: The missing-license diagnostic needs a “what now?” line.

This explains the problem and the risk, but not the next step. A short remediation note would make the warning much more actionable.

✏️ Suggested tweak
             .note(markup! {
-                "Dependencies without a license field may have unknown legal restrictions."
+                "Dependencies without a license field may have unknown legal restrictions. Review the dependency manually, replace it, or contact the maintainer before using it."
             }),
Based on learnings, "Implement the `diagnostic` function to convert signals into RuleDiagnostic instances with informative messages. Always follow the three pillars: explain WHAT the error is, explain WHY it's triggered, and tell the user WHAT to do"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_json_analyze/src/lint/nursery/no_untrusted_licenses.rs` around
lines 337 - 346, The missing-license diagnostic created in the Reason::Missing
arm (using RuleDiagnostic::new with state.range and markup referencing dep and
group) explains the issue and risk but lacks remediation; update this diagnostic
to include a short actionable "what now?" line by chaining a .help or an
additional .note that tells users how to fix it (e.g., add a license field to
the dependency's manifest or contact the package maintainer, or pin to a
known-licensed alternative) so the RuleDiagnostic produced for Reason::Missing
gives WHAT is wrong, WHY it matters, and a clear WHAT TO DO next.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_json_analyze/src/lint/nursery/no_untrusted_licenses.rs`:
- Around line 166-174: DEPENDENCY_GROUPS currently includes "bundleDependencies"
and "bundledDependencies" but the parser only uses as_json_object_value(), so
those array/boolean fields are silently skipped; remove those two entries from
DEPENDENCY_GROUPS to avoid false confidence, or alternatively add handling where
the code calls as_json_object_value() (the function that iterates dependency
groups) to accept array and boolean types: if the value is an array, iterate its
string items as dependency names; if it's a boolean, treat true as "all bundled"
(or explicit policy) and false as none. Update either DEPENDENCY_GROUPS or the
as_json_object_value() usage accordingly (referencing DEPENDENCY_GROUPS and the
as_json_object_value() call to locate the change).

In `@crates/biome_package/src/license/expression.rs`:
- Around line 35-38: The parser currently accepts any identifier after a WITH
token; update the WITH-handling code in this module (the function that parses
primary/license-with expressions—look for methods named parse_with,
parse_exception, or the WITH branch inside parse_expression/parse_primary) to
validate the exception identifier against the official SPDX Exceptions List and
return a parse error if it is not present; you can either (a) import or embed
the SPDX Exceptions set (or use an existing spdx crate lookup) and call
contains(exception_id) before constructing the WITH node, or (b) if you prefer
to block unsupported semantics now, reject any WITH expressions by returning an
explicit error from that parsing branch (ensuring callers treat it as a parse
failure rather than silently dropping the exception).

---

Nitpick comments:
In `@crates/biome_json_analyze/src/lint/nursery/no_untrusted_licenses.rs`:
- Around line 337-346: The missing-license diagnostic created in the
Reason::Missing arm (using RuleDiagnostic::new with state.range and markup
referencing dep and group) explains the issue and risk but lacks remediation;
update this diagnostic to include a short actionable "what now?" line by
chaining a .help or an additional .note that tells users how to fix it (e.g.,
add a license field to the dependency's manifest or contact the package
maintainer, or pin to a known-licensed alternative) so the RuleDiagnostic
produced for Reason::Missing gives WHAT is wrong, WHY it matters, and a clear
WHAT TO DO next.

In `@crates/biome_json_analyze/tests/spec_tests.rs`:
- Around line 163-175: The loop that builds the test ProjectLayout should be
hardened: replace the current for-entry usage that uses ok()? and thus can
return early, with a continue-based walk that skips individual broken entries
instead of bailing the whole helper, and add handling for scoped packages
(directories whose name starts with '@') by iterating their child package
directories as well; specifically, update the loop that reads
std::fs::read_dir(node_modules_dir) to (a) on any read_dir, try_from, or
read_to_string error just continue rather than using ok()? to return, (b) when
an entry is a directory whose file_name starts with '@', iterate its entries and
process each child package the same way, and (c) continue to call
project_layout.insert_node_manifest(pkg_dir, manifest) only for successfully
parsed package.json files.

In `@crates/biome_project_layout/src/project_layout.rs`:
- Around line 74-96: The loop in get_dependency_manifest re-acquires the
concurrent layout pin on every ancestor by calling get_node_manifest_for_package
repeatedly; instead, acquire the layout pin once before the for ancestor loop
(e.g. obtain the pinned guard from self.layout or whatever pin API the
concurrent map exposes), then either call a variant of
get_node_manifest_for_package that takes a reference to that pinned guard or
pass the guard into the loop so each iteration reuses the same pin; update
get_dependency_manifest to hold that single pin for the whole walk and adjust
get_node_manifest_for_package signature if needed to accept the pinned guard.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e19aca81-31f8-4c60-b79a-04df278f67b3

📥 Commits

Reviewing files that changed from the base of the PR and between 1f30838 and 400630c.

⛔ Files ignored due to path filters (12)
  • Cargo.lock is excluded by !**/*.lock and included by **
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/linter_options_check.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/allow_option/package.json.snap is excluded by !**/*.snap and included by **
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/deny_option/package.json.snap is excluded by !**/*.snap and included by **
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/deprecated_license/package.json.snap is excluded by !**/*.snap and included by **
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/fsf_required/package.json.snap is excluded by !**/*.snap and included by **
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/ignore_deprecated/package.json.snap is excluded by !**/*.snap and included by **
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/invalid/package.json.snap is excluded by !**/*.snap and included by **
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/osi_required/package.json.snap is excluded by !**/*.snap and included by **
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/valid/package.json.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (30)
  • crates/biome_json_analyze/Cargo.toml
  • crates/biome_json_analyze/benches/json_analyzer.rs
  • crates/biome_json_analyze/src/lib.rs
  • crates/biome_json_analyze/src/lint/nursery/no_untrusted_licenses.rs
  • crates/biome_json_analyze/src/services/mod.rs
  • crates/biome_json_analyze/src/services/project_layout.rs
  • crates/biome_json_analyze/tests/spec_tests.rs
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/allow_option/package.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/allow_option/package.options.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/deny_option/package.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/deny_option/package.options.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/deprecated_license/package.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/fsf_required/package.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/fsf_required/package.options.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/ignore_deprecated/package.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/ignore_deprecated/package.options.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/invalid/package.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/osi_required/package.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/osi_required/package.options.json
  • crates/biome_json_analyze/tests/specs/nursery/noUntrustedLicenses/valid/package.json
  • crates/biome_package/src/lib.rs
  • crates/biome_package/src/license/expression.rs
  • crates/biome_package/src/license/generated.rs
  • crates/biome_package/src/license/mod.rs
  • crates/biome_project_layout/src/project_layout.rs
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_untrusted_licenses.rs
  • crates/biome_service/src/file_handlers/json.rs
  • xtask/codegen/src/generate_license.rs
  • xtask/rules_check/src/lib.rs
💤 Files with no reviewable changes (2)
  • xtask/codegen/src/generate_license.rs
  • crates/biome_package/src/license/generated.rs

Comment thread crates/biome_json_analyze/src/lint/nursery/no_untrusted_licenses.rs
Comment on lines +35 to +38
///
/// Supports simple identifiers (`MIT`), `OR` (disjunction), `AND` (conjunction),
/// parenthesized sub-expressions, and `WITH` exceptions (the exception is ignored
/// for trust checking — only the base license ID matters).
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In the SPDX license expression grammar, must the identifier after WITHbe a valid SPDX exception identifier, and should an expression likeApache-2.0 WITH NotARealException be considered invalid?

💡 Result:

Yes. In the SPDX license expression ABNF, the token after WITH is a license-exception-id, defined as a short-form license exception identifier from the SPDX Exceptions List (Annex A.2). Therefore, an expression like Apache-2.0 WITH NotARealException is not a valid SPDX license expression under the grammar. If the needed exception is not on the SPDX Exception List, the SPDX spec says you should instead use a single LicenseRef-... to represent the whole license terms (including that exception). [1][2]

Sources:
[1] (spdx.github.io)
[2] (spdx.github.io)

Citations:


Validate WITH exception identifiers against the SPDX Exceptions List.

Per the SPDX spec, the identifier after WITH must be from the official SPDX Exceptions List. Currently, Apache-2.0 WITH NotARealException is silently accepted and treated as just Apache-2.0, which violates the SPDX grammar. Either validate exceptions explicitly or reject WITH expressions until properly modelled.

Also applies to: 252–264

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_package/src/license/expression.rs` around lines 35 - 38, The
parser currently accepts any identifier after a WITH token; update the
WITH-handling code in this module (the function that parses primary/license-with
expressions—look for methods named parse_with, parse_exception, or the WITH
branch inside parse_expression/parse_primary) to validate the exception
identifier against the official SPDX Exceptions List and return a parse error if
it is not present; you can either (a) import or embed the SPDX Exceptions set
(or use an existing spdx crate lookup) and call contains(exception_id) before
constructing the WITH node, or (b) if you prefer to block unsupported semantics
now, reject any WITH expressions by returning an explicit error from that
parsing branch (ensuring callers treat it as a parse failure rather than
silently dropping the exception).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@coderabbiai We'll tackle this in another PR

Comment on lines +8 to +20
/// Additional license identifiers to trust, beyond valid SPDX identifiers.
///
/// Useful for custom or proprietary licenses that are not part of the SPDX
/// standard but are acceptable in your project.
#[serde(skip_serializing_if = "Option::is_none")]
pub allow: Option<Box<[Box<str>]>>,

/// License identifiers to explicitly deny, even if they are valid SPDX identifiers.
///
/// Use this to block specific licenses that your project or organization can't use (e.g.,
/// copyleft licenses in a proprietary project).
#[serde(skip_serializing_if = "Option::is_none")]
pub deny: Option<Box<[Box<str>]>>,
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 think it would be good to give the ability to provide an allowlist. The options currently only allow for a denylist.

Here's how I think it should work:
Basically, it should be possible to configure the rule:

  • with an allowlist that denies things not in the list
  • or a denylist that allows things not in the list
    if both are provided, see if its allowed in the allowlist, and then check the denylist to deny it. As in, the denylist has more authority than the allowlist.

Copy link
Copy Markdown
Member Author

@ematipico ematipico Mar 14, 2026

Choose a reason for hiding this comment

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

Line 13 is the allowlist. If both are provided, deny takes precedence (it's also documented I think)

Comment thread crates/biome_json_analyze/src/lint/nursery/no_untrusted_licenses.rs
Comment thread crates/biome_json_analyze/src/lint/nursery/no_untrusted_licenses.rs Outdated
Comment thread crates/biome_json_analyze/src/lint/nursery/no_untrusted_licenses.rs Outdated
@ematipico ematipico force-pushed the feat/no-untrusted-license branch from 9563015 to 40b1eb2 Compare March 23, 2026 19:21
@ematipico ematipico requested a review from dyc3 March 23, 2026 19:31
@Netail
Copy link
Copy Markdown
Member

Netail commented Mar 23, 2026

No changeset?

@ematipico
Copy link
Copy Markdown
Member Author

@Netail added

@ematipico ematipico force-pushed the feat/no-untrusted-license branch from 0201f1f to 1d3cc84 Compare March 24, 2026 08:31
@ematipico ematipico requested a review from Netail March 24, 2026 08:31
@ematipico ematipico force-pushed the feat/no-untrusted-license branch from 1d3cc84 to 0c24bc9 Compare March 24, 2026 08:32
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/forty-women-move.md:
- Line 12: Fix the typo in the .changeset description for the `requireFsfLibre`
flag: change the word "liceses" to "licenses" in the sentence
"`requireFsfLibre`: whether the liceses need to be approved by the [Free
Software Foundation](https://www.gnu.org/licenses/license-list.html)." so it
reads "whether the licenses need to be approved...".
- Line 11: Fix the typo in the .changeset description: change "neend" to "need"
in the line describing `requireOsiApproved` so the sentence reads
"`requireOsiApproved`: whether the licenses need to be approved by the [Open
Source Initiative](https://opensource.org/)."

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 075eeddb-541e-49da-9071-e9c8b0e3779f

📥 Commits

Reviewing files that changed from the base of the PR and between 400630c and 0c24bc9.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock and included by **
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/linter_options_check.rs is excluded by !**/generated/**, !**/generated/** and included by **
📒 Files selected for processing (1)
  • .changeset/forty-women-move.md

Comment thread .changeset/forty-women-move.md Outdated
Comment thread .changeset/forty-women-move.md Outdated
ematipico and others added 2 commits March 24, 2026 08:55
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@ematipico ematipico merged commit e168494 into main Mar 24, 2026
2 checks passed
@ematipico ematipico deleted the feat/no-untrusted-license branch March 24, 2026 09:23
This was referenced Mar 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Project Area: project A-Tooling Area: internal tools L-JSON Language: JSON and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants