Repository: dart-lang/pub-dev (dart)

Issue:
"Issue with pana Tool Using Outdated Flutter SDK on pub.dev"
I recently uploaded the `antinna_ui_kit` package to [pub.dev](https://pub.dev/packages/antinna_ui_kit), which requires the Dart SDK version `>=3.4.4 <4.0.0`. However, during the analysis, it seems that `pana` is currently using Flutter version 3.22.2, Even though flutter new Stable version is there.
```text
## Running analysis for "antinna_ui_kit" version "1.0.0"
STARTED: 2024-07-24T15:35:47.305052Z

### Starting pana
2024-07-24 15:36:02.615396 INFO: Running `/home/worker/dart/stable/bin/dart --version`...
2024-07-24 15:36:02.662876 INFO: Running `/home/worker/flutter/stable/bin/flutter --no-version-check --version --machine`...
2024-07-24 15:36:02.850325 INFO: Downloading package antinna_ui_kit 1.0.0 from https://pub.dev/api/archives/antinna_ui_kit-1.0.0.tar.gz
2024-07-24 15:36:03.054172 INFO: Running `/home/worker/flutter/stable/bin/flutter --no-version-check pub pub get --no-example`...
2024-07-24 15:36:04.328979 INFO: Running `/home/worker/flutter/stable/bin/flutter --no-version-check pub pub get --no-example`...
2024-07-24 15:36:07.455499 INFO: Running `webpinfo /tmp/pana_JXCNMJ/screenshots/antinna_copyrights.webp`...
2024-07-24 15:36:07.478643 INFO: Running `webpinfo /tmp/JWGTRH/gen/antinna_copyrights.webp`...
2024-07-24 15:36:07.498990 INFO: Running `cwebp -resize 0 100 /tmp/JWGTRH/gen/antinna_copyrights.webp -o /tmp/JWGTRH/gen/100x100/antinna_copyrights.webp`...
2024-07-24 15:36:07.525239 INFO: Running `cwebp -resize 0 190 /tmp/JWGTRH/gen/antinna_copyrights.webp -o /tmp/JWGTRH/gen/190x190/antinna_copyrights.webp`...
2024-07-24 15:36:07.555368 INFO: Running `dwebp /tmp/JWGTRH/gen/100x100/antinna_copyrights.webp -o /tmp/JWGTRH/gen/100x100/antinna_copyrights.png`...
2024-07-24 15:36:07.579246 INFO: Running `dwebp /tmp/JWGTRH/gen/190x190/antinna_copyrights.webp -o /tmp/JWGTRH/gen/190x190/antinna_copyrights.png`...
2024-07-24 15:36:08.708029 INFO: Running `git init`...
2024-07-24 15:36:08.732081 INFO: Running `git remote add origin https://github.com/antinna/antinna_ui_kit`...
2024-07-24 15:36:08.754786 INFO: Running `git remote show origin`...
2024-07-24 15:36:09.017817 INFO: Running `git fetch --depth 1 --no-recurse-submodules origin main`...
2024-07-24 15:36:09.598520 INFO: Running `git ls-tree -r --name-only --full-tree origin/main`...
2024-07-24 15:36:09.627163 INFO: Running `git show origin/main:example_projects/pubspec.yaml`...
2024-07-24 15:36:09.658720 INFO: Running `git show origin/main:pubspec.yaml`...
2024-07-24 15:36:10.537557 INFO: Analyzing pub downgrade...
2024-07-24 15:36:10.543714 INFO: Running `/home/worker/flutter/stable/bin/flutter --no-version-check packages pub downgrade --no-example`...
2024-07-24 15:36:11.839963 INFO: [pub-downgrade-error]
2024-07-24 15:36:11.840285 INFO: Resolving dependencies...
2024-07-24 15:36:11.840285 INFO: The current Dart SDK version is 3.4.3.
2024-07-24 15:36:11.840285 INFO: 
2024-07-24 15:36:11.840285 INFO: Because antinna_ui_kit requires SDK version >=3.4.4 <4.0.0, version solving failed.
2024-07-24 15:36:11.840285 INFO: 
2024-07-24 15:36:11.840285 INFO: 
2024-07-24 15:36:11.840285 INFO: You can try the following suggestion to make the pubspec resolve:
2024-07-24 15:36:11.840285 INFO: * Try using the Flutter SDK version: 3.22.3.
2024-07-24 15:36:11.848567 INFO: Running `/home/worker/flutter/stable/bin/flutter --no-version-check packages pub upgrade --no-example`...
2024-07-24 15:36:13.212554 INFO: Writing summary.json
2024-07-24 15:36:13.218063 INFO: Running dartdoc post-processing
2024-07-24 15:36:13.222252 INFO: Creating .tar.gz archive
2024-07-24 15:36:13.236450 INFO: Finished post-processing
2024-07-24 15:36:13.242229 INFO: Finished .tar.gz archive
### Execution of pana exited 0
STOPPED: 2024-07-24T15:36:13.325508Z
```
![Screenshot 2024-07-24 211354](https://github.com/user-attachments/assets/9265a5a3-709b-47ca-9c6a-80bc93b111db)

###  Suggested Solution:
Please upgrade the Flutter SDK used in the `pub.dev` for pana tool. As new Stable release is there
[Flutter release archive](https://docs.flutter.dev/release/archive)

Pull request description:
Fixes #7888.

Patch:
diff --git a/pkg/_pub_shared/build.yaml b/pkg/_pub_shared/build.yaml
index 21c294f6da..8069b0a4d0 100644
--- a/pkg/_pub_shared/build.yaml
+++ b/pkg/_pub_shared/build.yaml
@@ -14,3 +14,4 @@ targets:
       - 'lib/data/publisher_api.dart'
       - 'lib/data/task_api.dart'
       - 'lib/data/task_payload.dart'
+      - 'lib/utils/flutter_archive.dart'
diff --git a/pkg/_pub_shared/lib/utils/flutter_archive.dart b/pkg/_pub_shared/lib/utils/flutter_archive.dart
index 08767b7740..0a7b9b1d3e 100644
--- a/pkg/_pub_shared/lib/utils/flutter_archive.dart
+++ b/pkg/_pub_shared/lib/utils/flutter_archive.dart
@@ -96,6 +96,8 @@ class FlutterRelease {
   final DateTime? releaseDate;
   final String? archive;
   final String? sha256;
+  @JsonKey(name: 'dart_sdk_version')
+  final String? dartSdkVersion;
 
   FlutterRelease({
     this.hash,
@@ -104,6 +106,7 @@ class FlutterRelease {
     this.releaseDate,
     this.archive,
     this.sha256,
+    this.dartSdkVersion,
   });
 
   factory FlutterRelease.fromJson(Map<String, dynamic> json) =>
@@ -115,4 +118,22 @@ class FlutterRelease {
       version!.startsWith('v') ? version!.substring(1) : version!;
 
   late final semanticVersion = Version.parse(cleanVersion);
+
+  /// The Dart SDK version string may be `3.4.3` for stable versions or
+  /// `3.5.0 (build 3.5.0-180.3.beta)` for prerelease versions.
+  /// For simplicity we only parse the first part of the version string.
+  late final _extractedDartSdkVersion = dartSdkVersion?.split(' ').first;
+
+  /// The parsed Dart SDK version or `null` if we were not able to
+  /// parse the value.
+  late final semanticDartSdkVersion = () {
+    if (_extractedDartSdkVersion == null) {
+      return null;
+    }
+    try {
+      return Version.parse(_extractedDartSdkVersion!);
+    } catch (_) {
+      return null;
+    }
+  }();
 }
diff --git a/pkg/_pub_shared/lib/utils/flutter_archive.g.dart b/pkg/_pub_shared/lib/utils/flutter_archive.g.dart
index 06ed759a9a..346583c784 100644
--- a/pkg/_pub_shared/lib/utils/flutter_archive.g.dart
+++ b/pkg/_pub_shared/lib/utils/flutter_archive.g.dart
@@ -67,6 +67,7 @@ FlutterRelease _$FlutterReleaseFromJson(Map<String, dynamic> json) =>
           : DateTime.parse(json['release_date'] as String),
       archive: json['archive'] as String?,
       sha256: json['sha256'] as String?,
+      dartSdkVersion: json['dart_sdk_version'] as String?,
     );
 
 Map<String, dynamic> _$FlutterReleaseToJson(FlutterRelease instance) {
@@ -84,5 +85,6 @@ Map<String, dynamic> _$FlutterReleaseToJson(FlutterRelease instance) {
   writeNotNull('release_date', instance.releaseDate?.toIso8601String());
   writeNotNull('archive', instance.archive);
   writeNotNull('sha256', instance.sha256);
+  writeNotNull('dart_sdk_version', instance.dartSdkVersion);
   return val;
 }
diff --git a/pkg/pub_worker/lib/src/bin/pana_wrapper.dart b/pkg/pub_worker/lib/src/bin/pana_wrapper.dart
index 4a1a63fc6d..02927d9e18 100644
--- a/pkg/pub_worker/lib/src/bin/pana_wrapper.dart
+++ b/pkg/pub_worker/lib/src/bin/pana_wrapper.dart
@@ -210,26 +210,42 @@ Future<({String configKind, String? dartSdkPath, String? flutterSdkPath})>
   bool matchesSdks({
     required Version? dart,
     required Version? flutter,
+    required Version? flutterDartSdk,
     bool allowsMissingVersion = false,
   }) {
     if (!allowsMissingVersion && (dart == null || flutter == null)) {
       return false;
     }
 
-    return sdkMatchesConstraint(
-          sdkVersion: dart,
-          constraint: pubspec.dartSdkConstraint,
-        ) &&
-        sdkMatchesConstraint(
-          sdkVersion: flutter,
-          constraint: pubspec.flutterSdkConstraint,
-        );
+    // Dart SDK
+    if (!sdkMatchesConstraint(
+        sdkVersion: dart, constraint: pubspec.dartSdkConstraint)) {
+      return false;
+    }
+
+    // Flutter SDK
+    if (!sdkMatchesConstraint(
+        sdkVersion: flutter, constraint: pubspec.flutterSdkConstraint)) {
+      return false;
+    }
+
+    // Dart SDK inside the Flutter SDK
+    if (flutterDartSdk != null &&
+        !sdkMatchesConstraint(
+            sdkVersion: flutterDartSdk,
+            constraint: pubspec.dartSdkConstraint)) {
+      return false;
+    }
+
+    // Otherwise accepting the analysis SDK bundle.
+    return true;
   }
 
   // try to use the latest SDKs in the docker image
   final matchesInstalledSdks = matchesSdks(
     dart: installedDartSdk?.version,
     flutter: installedFlutterSdk?.version,
+    flutterDartSdk: installedFlutterSdk?.embeddedDartSdkVersion,
     allowsMissingVersion: true,
   );
   if (matchesInstalledSdks) {
@@ -249,6 +265,7 @@ Future<({String configKind, String? dartSdkPath, String? flutterSdkPath})>
         matchesSdks(
           dart: bundle.semanticDartVersion,
           flutter: bundle.semanticFlutterVersion,
+          flutterDartSdk: bundle.semanticFlutterDartSdkVersion,
         );
     if (matchesBundle) {
       final dartSdkPath = await _installSdk(
@@ -330,12 +347,14 @@ class _SdkBundle {
   final String configKind;
   final String dart;
   final String flutter;
+  final Version? semanticFlutterDartSdkVersion;
 
   _SdkBundle({
     required this.channel,
     required this.configKind,
     required this.dart,
     required this.flutter,
+    required this.semanticFlutterDartSdkVersion,
   });
 
   late final semanticDartVersion = Version.parse(dart);
@@ -362,6 +381,8 @@ Future<List<_SdkBundle>> _detectSdkBundles() async {
         configKind: 'latest-stable',
         dart: latestStableDartSdkVersion,
         flutter: latestStableFlutterSdkVersion,
+        semanticFlutterDartSdkVersion:
+            flutterArchive?.latestStable?.semanticDartSdkVersion,
       ),
     if (latestBetaDartSdkVersion != null && latestBetaFlutterSdkVersion != null)
       _SdkBundle(
@@ -369,12 +390,15 @@ Future<List<_SdkBundle>> _detectSdkBundles() async {
         configKind: 'latest-beta',
         dart: latestBetaDartSdkVersion,
         flutter: latestBetaFlutterSdkVersion,
+        semanticFlutterDartSdkVersion:
+            flutterArchive?.latestBeta?.semanticDartSdkVersion,
       ),
     _SdkBundle(
       channel: 'master',
       configKind: 'master',
       dart: 'master',
       flutter: 'master',
+      semanticFlutterDartSdkVersion: null,
     ),
   ];
 }
diff --git a/pkg/pub_worker/lib/src/sdks.dart b/pkg/pub_worker/lib/src/sdks.dart
index 927da0b55a..44e63cc611 100644
--- a/pkg/pub_worker/lib/src/sdks.dart
+++ b/pkg/pub_worker/lib/src/sdks.dart
@@ -11,10 +11,11 @@ import 'package:pub_semver/pub_semver.dart' show Version;
 
 @sealed
 class InstalledSdk {
+  final String kind;
   final String path;
   final Version version;
-  final String kind;
-  InstalledSdk(this.kind, this.path, this.version);
+  final Version? embeddedDartSdkVersion;
+  InstalledSdk(this.kind, this.path, this.version, this.embeddedDartSdkVersion);
 
   @override
   String toString() => 'InstalledSdk($kind, $version, $path)';
@@ -70,6 +71,17 @@ class InstalledSdk {
     required String path,
   }) async {
     final v = await File(p.join(path, 'version')).readAsString();
-    return InstalledSdk(kind, path, Version.parse(v.trim()));
+    Version? embeddedDartSdkVersion;
+    if (kind == 'flutter') {
+      final embeddedFile =
+          File(p.join(path, 'bin', 'cache', 'dart-sdk', 'version'));
+      if (await embeddedFile.exists()) {
+        final embeddedValue = await embeddedFile.readAsString();
+        embeddedDartSdkVersion =
+            Version.parse(embeddedValue.split(' ').first.trim());
+      }
+    }
+    return InstalledSdk(
+        kind, path, Version.parse(v.trim()), embeddedDartSdkVersion);
   }
 }


Test patch:
diff --git a/pkg/_pub_shared/test/utils/flutter_archive_test.dart b/pkg/_pub_shared/test/utils/flutter_archive_test.dart
index b4cd2dd508..b2122b872e 100644
--- a/pkg/_pub_shared/test/utils/flutter_archive_test.dart
+++ b/pkg/_pub_shared/test/utils/flutter_archive_test.dart
@@ -19,5 +19,7 @@ void main() {
       DateTime.now().difference(archive.latestBeta!.releaseDate!).inDays,
       lessThan(45),
     );
+    expect(archive.latestStable?.semanticDartSdkVersion, isNotNull);
+    expect(archive.latestBeta?.semanticDartSdkVersion, isNotNull);
   });
 }