From d7aed50d50969d859b331acbe35a992d75c89901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 27 Aug 2026 08:15:08 +0200 Subject: [PATCH 01/13] Add Linux RPM packaging to official pipeline Build framework-dependent x86_64 and aarch64 RPMs that require the .NET 10 runtime, validate their payload and Cloud Shell size limit, and document installation. --- .pipelines/CosmosDB-Shell-Official.yml | 102 +++++++++++++++++++++++++ CHANGELOG.md | 4 + README.md | 16 ++++ packaging/rpm/cosmosdbshell.spec | 37 +++++++++ 4 files changed, 159 insertions(+) create mode 100644 packaging/rpm/cosmosdbshell.spec diff --git a/.pipelines/CosmosDB-Shell-Official.yml b/.pipelines/CosmosDB-Shell-Official.yml index 3432ffc3..174c64aa 100644 --- a/.pipelines/CosmosDB-Shell-Official.yml +++ b/.pipelines/CosmosDB-Shell-Official.yml @@ -31,6 +31,7 @@ variables: BuildConfiguration: Release WindowsContainerImage: "onebranch.azurecr.io/windows/ltsc2022/vse2022:latest" # Docker image which is used to build the project https://aka.ms/obpipelines/containers + LinuxContainerImage: "onebranch.azurecr.io/linux/ubuntu-2204:latest" resources: repositories: @@ -822,6 +823,107 @@ extends: publishVstsFeed: "CosmosDB/CosmosDBShell" allowPackageConflicts: true + - job: rpm + displayName: Build RPM packages + pool: + type: linux + variables: + ob_outputDirectory: "$(Build.SourcesDirectory)/out" + ob_artifactBaseName: cosmos_shell_rpm + ob_git_fetchDepth: -1 + steps: + - task: UseDotNet@2 + inputs: + packageType: "sdk" + useGlobalJson: true + performMultiLevelLookup: true + + - script: | + set -euo pipefail + dotnet tool restore --configfile "$(Build.SourcesDirectory)/.pipelines/nuget.config" + package_version="$(dotnet tool run nbgv get-version -v NuGetPackageVersion)" + if [[ ! "$package_version" =~ ^([0-9]+\.[0-9]+\.[0-9]+)(-(.+))?$ ]]; then + echo "Unsupported RPM package version: $package_version" >&2 + exit 1 + fi + + echo "##vso[task.setvariable variable=CosmosDBShell_RpmVersion]${BASH_REMATCH[1]}" + if [[ -n "${BASH_REMATCH[3]:-}" ]]; then + rpm_release="0.${BASH_REMATCH[3]//[^[:alnum:].]/.}" + else + rpm_release="1" + fi + echo "##vso[task.setvariable variable=CosmosDBShell_RpmRelease]$rpm_release" + displayName: Compute RPM version + + - script: | + set -euo pipefail + if ! command -v rpmbuild >/dev/null 2>&1; then + sudo apt-get update + sudo apt-get install -y rpm + fi + + rpm_root="$(Build.SourcesDirectory)/.rpmbuild" + output_dir="$(Build.SourcesDirectory)/out/rpm" + mkdir -p "$rpm_root"/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} "$output_dir" + cp "$(Build.SourcesDirectory)/packaging/rpm/cosmosdbshell.spec" "$rpm_root/SPECS/" + cp "$(Build.SourcesDirectory)/LICENSE.md" "$(Build.SourcesDirectory)/NOTICE.html" "$rpm_root/SOURCES/" + + for entry in "linux-x64:x86_64" "linux-arm64:aarch64"; do + rid="${entry%%:*}" + rpm_arch="${entry##*:}" + publish_dir="$(Build.SourcesDirectory)/.rpm-publish/$rid" + + dotnet publish "$(Build.SourcesDirectory)/CosmosDBShell/CosmosDBShell.csproj" \ + --configuration "$(BuildConfiguration)" \ + --runtime "$rid" \ + --self-contained false \ + -p:PublishSingleFile=true \ + -p:EnableCompressionInSingleFile=false \ + -p:IncludeAllContentForSelfExtract=true \ + -p:PackAsTool=false \ + --output "$publish_dir" \ + --configfile "$(Build.SourcesDirectory)/.pipelines/nuget.config" + + mapfile -t payload < <(find "$publish_dir" -maxdepth 1 -type f -printf '%f\n') + if [[ ${#payload[@]} -ne 1 || "${payload[0]}" != "CosmosDBShell" ]]; then + echo "Expected exactly one CosmosDBShell file in $publish_dir; found: ${payload[*]:-none}" >&2 + exit 1 + fi + + cp "$publish_dir/CosmosDBShell" "$rpm_root/SOURCES/CosmosDBShell" + rpmbuild -bb "$rpm_root/SPECS/cosmosdbshell.spec" \ + --target "$rpm_arch" \ + --define "_topdir $rpm_root" \ + --define "package_version $(CosmosDBShell_RpmVersion)" \ + --define "package_release $(CosmosDBShell_RpmRelease)" + done + + find "$rpm_root/RPMS" -type f -name '*.rpm' -exec cp {} "$output_dir/" \; + displayName: Build framework-dependent RPMs + + - script: | + set -euo pipefail + output_dir="$(Build.SourcesDirectory)/out/rpm" + mapfile -t packages < <(find "$output_dir" -maxdepth 1 -type f -name '*.rpm' | sort) + if [[ ${#packages[@]} -ne 2 ]]; then + echo "Expected two RPM packages; found ${#packages[@]}." >&2 + exit 1 + fi + + for package in "${packages[@]}"; do + size="$(stat -c %s "$package")" + if (( size > 25000000 )); then + echo "$(basename "$package") is $size bytes and exceeds the 25 MB Cloud Shell limit." >&2 + exit 1 + fi + rpm -qpR "$package" | grep -Fx 'dotnet-runtime-10.0 >= 10.0' + rpm -qlp "$package" | grep -Fx '/usr/bin/cosmosdbshell' + rpm -qlp "$package" | grep -Fx '/usr/libexec/cosmosdbshell/CosmosDBShell' + echo "Validated $(basename "$package") [$size bytes]" + done + displayName: Validate RPM packages + - job: CodeQLAnalyze displayName: CodeQL (C#) pool: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c95e294..ba02fc3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Build & pipeline + +- The official pipeline now produces compressed `x86_64` and `aarch64` RPM packages from the framework-dependent Linux builds. The packages require the .NET 10 runtime and are validated against the Azure Cloud Shell 25 MB package-size limit. + ## 1.1.209-preview — 2026-08-26 ### New features diff --git a/README.md b/README.md index 21011f6d..c6da8cf4 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,22 @@ Run the tests: dotnet test CosmosDBShell.sln ``` +## Install from RPM Artifacts + +The official pipeline produces framework-dependent RPMs for Azure Linux and +other RPM-based distributions: + +- `cosmosdbshell--.x86_64.rpm` +- `cosmosdbshell--.aarch64.rpm` + +The RPM requires the .NET 10 runtime package (`dotnet-runtime-10.0`), but does +not require the .NET SDK. Install the package that matches the host architecture: + +```bash +sudo dnf install ./cosmosdbshell--..rpm +cosmosdbshell +``` + ## Architecture | Folder | Purpose | diff --git a/packaging/rpm/cosmosdbshell.spec b/packaging/rpm/cosmosdbshell.spec new file mode 100644 index 00000000..e748e12d --- /dev/null +++ b/packaging/rpm/cosmosdbshell.spec @@ -0,0 +1,37 @@ +Name: cosmosdbshell +Version: %{package_version} +Release: %{package_release}%{?dist} +Summary: Interactive shell for Azure Cosmos DB +License: MIT +URL: https://github.com/Azure/CosmosDBShell +Source0: CosmosDBShell +Source1: LICENSE.md +Source2: NOTICE.html +Requires: dotnet-runtime-10.0 >= 10.0 +%define _binary_payload w19.zstdio + +%description +Azure Cosmos DB Shell is a command-line tool for interactive navigation, +queries, scripting, and MCP server workflows with Azure Cosmos DB. + +%prep + +%build + +%install +install -D -m 0755 %{SOURCE0} %{buildroot}%{_libexecdir}/cosmosdbshell/CosmosDBShell +install -D -m 0644 %{SOURCE1} %{buildroot}%{_licensedir}/%{name}/LICENSE.md +install -D -m 0644 %{SOURCE2} %{buildroot}%{_licensedir}/%{name}/NOTICE.html +mkdir -p %{buildroot}%{_bindir} +ln -s %{_libexecdir}/cosmosdbshell/CosmosDBShell %{buildroot}%{_bindir}/cosmosdbshell + +%files +%{_bindir}/cosmosdbshell +%dir %{_libexecdir}/cosmosdbshell +%{_libexecdir}/cosmosdbshell/CosmosDBShell +%license %{_licensedir}/%{name}/LICENSE.md +%license %{_licensedir}/%{name}/NOTICE.html + +%changelog +* Thu Aug 27 2026 Microsoft Corporation - %{package_version}-%{package_release} +- Build from the framework-dependent .NET 10 publish output. \ No newline at end of file From faac8db6de28fcbdb1225a2a9f63d535360501d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 27 Aug 2026 09:01:38 +0200 Subject: [PATCH 02/13] Build RPMs in an Azure Linux container instead of Ubuntu The build containers cannot reach the public Ubuntu archives, so installing the RPM tooling with apt-get failed. Azure Linux is RPM-native and resolves packages from packages.microsoft.com, which is reachable. Also disable RPM debuginfo extraction and binary stripping, which would corrupt the appended .NET single-file bundle. --- .pipelines/CosmosDB-Shell-Official.yml | 8 +++++--- packaging/rpm/cosmosdbshell.spec | 9 ++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.pipelines/CosmosDB-Shell-Official.yml b/.pipelines/CosmosDB-Shell-Official.yml index 174c64aa..6050964d 100644 --- a/.pipelines/CosmosDB-Shell-Official.yml +++ b/.pipelines/CosmosDB-Shell-Official.yml @@ -31,7 +31,10 @@ variables: BuildConfiguration: Release WindowsContainerImage: "onebranch.azurecr.io/windows/ltsc2022/vse2022:latest" # Docker image which is used to build the project https://aka.ms/obpipelines/containers - LinuxContainerImage: "onebranch.azurecr.io/linux/ubuntu-2204:latest" + # Azure Linux is RPM-native and resolves packages from packages.microsoft.com. + # The build containers cannot reach the public Ubuntu archives, so an + # Ubuntu image cannot install the RPM tooling the rpm job needs. + LinuxContainerImage: "mcr.microsoft.com/onebranch/azurelinux/build:3.0" resources: repositories: @@ -859,8 +862,7 @@ extends: - script: | set -euo pipefail if ! command -v rpmbuild >/dev/null 2>&1; then - sudo apt-get update - sudo apt-get install -y rpm + tdnf install -y rpm-build fi rpm_root="$(Build.SourcesDirectory)/.rpmbuild" diff --git a/packaging/rpm/cosmosdbshell.spec b/packaging/rpm/cosmosdbshell.spec index e748e12d..6773714a 100644 --- a/packaging/rpm/cosmosdbshell.spec +++ b/packaging/rpm/cosmosdbshell.spec @@ -8,7 +8,14 @@ Source0: CosmosDBShell Source1: LICENSE.md Source2: NOTICE.html Requires: dotnet-runtime-10.0 >= 10.0 -%define _binary_payload w19.zstdio + +%global _binary_payload w19.zstdio +%{!?_licensedir: %global _licensedir %{_datadir}/licenses} + +# The payload is a prebuilt .NET single-file binary whose bundle is appended to +# the ELF image; stripping or extracting debuginfo from it corrupts the bundle. +%global debug_package %{nil} +%global __os_install_post %{nil} %description Azure Cosmos DB Shell is a command-line tool for interactive navigation, From a9dd7897daf3525a801b412cf6a4eb7b15a8f694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 27 Aug 2026 09:30:01 +0200 Subject: [PATCH 03/13] Shrink the RPM payload and drop the single-file bundle Ship the ordinary framework-dependent publish output instead of a single-file bundle, so the package relies on the preinstalled .NET 10 runtime and does not extract itself at startup. Drop libmsalruntime.so, which ships only for linux-x64 and accounted for the entire size difference against linux-arm64. --- .pipelines/CosmosDB-Shell-Official.yml | 28 +++++++++++++++++--------- packaging/rpm/cosmosdbshell.spec | 15 ++++++++------ 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/.pipelines/CosmosDB-Shell-Official.yml b/.pipelines/CosmosDB-Shell-Official.yml index 6050964d..ba31d7f3 100644 --- a/.pipelines/CosmosDB-Shell-Official.yml +++ b/.pipelines/CosmosDB-Shell-Official.yml @@ -876,24 +876,29 @@ extends: rpm_arch="${entry##*:}" publish_dir="$(Build.SourcesDirectory)/.rpm-publish/$rid" + rm -rf "$publish_dir" dotnet publish "$(Build.SourcesDirectory)/CosmosDBShell/CosmosDBShell.csproj" \ --configuration "$(BuildConfiguration)" \ --runtime "$rid" \ --self-contained false \ - -p:PublishSingleFile=true \ - -p:EnableCompressionInSingleFile=false \ - -p:IncludeAllContentForSelfExtract=true \ + -p:PublishSingleFile=false \ -p:PackAsTool=false \ --output "$publish_dir" \ --configfile "$(Build.SourcesDirectory)/.pipelines/nuget.config" - mapfile -t payload < <(find "$publish_dir" -maxdepth 1 -type f -printf '%f\n') - if [[ ${#payload[@]} -ne 1 || "${payload[0]}" != "CosmosDBShell" ]]; then - echo "Expected exactly one CosmosDBShell file in $publish_dir; found: ${payload[*]:-none}" >&2 - exit 1 - fi + # Ships for linux-x64 only and doubles the package size. The VS Code + # broker credential falls back when it is absent, as it already does + # on linux-arm64, where this library does not exist at all. + rm -f "$publish_dir/libmsalruntime.so" + + for required in CosmosDBShell CosmosDBShell.dll; do + if [[ ! -f "$publish_dir/$required" ]]; then + echo "Expected $required in $publish_dir." >&2 + exit 1 + fi + done - cp "$publish_dir/CosmosDBShell" "$rpm_root/SOURCES/CosmosDBShell" + tar -czf "$rpm_root/SOURCES/cosmosdbshell-payload.tar.gz" -C "$publish_dir" . rpmbuild -bb "$rpm_root/SPECS/cosmosdbshell.spec" \ --target "$rpm_arch" \ --define "_topdir $rpm_root" \ @@ -922,6 +927,11 @@ extends: rpm -qpR "$package" | grep -Fx 'dotnet-runtime-10.0 >= 10.0' rpm -qlp "$package" | grep -Fx '/usr/bin/cosmosdbshell' rpm -qlp "$package" | grep -Fx '/usr/libexec/cosmosdbshell/CosmosDBShell' + rpm -qlp "$package" | grep -Fx '/usr/libexec/cosmosdbshell/CosmosDBShell.dll' + if rpm -qlp "$package" | grep -q 'libmsalruntime\.so'; then + echo "$(basename "$package") still carries libmsalruntime.so." >&2 + exit 1 + fi echo "Validated $(basename "$package") [$size bytes]" done displayName: Validate RPM packages diff --git a/packaging/rpm/cosmosdbshell.spec b/packaging/rpm/cosmosdbshell.spec index 6773714a..6f967763 100644 --- a/packaging/rpm/cosmosdbshell.spec +++ b/packaging/rpm/cosmosdbshell.spec @@ -4,16 +4,18 @@ Release: %{package_release}%{?dist} Summary: Interactive shell for Azure Cosmos DB License: MIT URL: https://github.com/Azure/CosmosDBShell -Source0: CosmosDBShell +Source0: cosmosdbshell-payload.tar.gz Source1: LICENSE.md Source2: NOTICE.html Requires: dotnet-runtime-10.0 >= 10.0 +# The payload is prebuilt and only needs the .NET runtime, so skip the ELF scan +# that would otherwise derive dependencies from the build host. +AutoReqProv: no %global _binary_payload w19.zstdio %{!?_licensedir: %global _licensedir %{_datadir}/licenses} -# The payload is a prebuilt .NET single-file binary whose bundle is appended to -# the ELF image; stripping or extracting debuginfo from it corrupts the bundle. +# Prebuilt binaries are shipped as published; stripping them breaks the .NET host. %global debug_package %{nil} %global __os_install_post %{nil} @@ -26,7 +28,9 @@ queries, scripting, and MCP server workflows with Azure Cosmos DB. %build %install -install -D -m 0755 %{SOURCE0} %{buildroot}%{_libexecdir}/cosmosdbshell/CosmosDBShell +mkdir -p %{buildroot}%{_libexecdir}/cosmosdbshell +tar -xzf %{SOURCE0} -C %{buildroot}%{_libexecdir}/cosmosdbshell +chmod 0755 %{buildroot}%{_libexecdir}/cosmosdbshell/CosmosDBShell install -D -m 0644 %{SOURCE1} %{buildroot}%{_licensedir}/%{name}/LICENSE.md install -D -m 0644 %{SOURCE2} %{buildroot}%{_licensedir}/%{name}/NOTICE.html mkdir -p %{buildroot}%{_bindir} @@ -34,8 +38,7 @@ ln -s %{_libexecdir}/cosmosdbshell/CosmosDBShell %{buildroot}%{_bindir}/cosmosdb %files %{_bindir}/cosmosdbshell -%dir %{_libexecdir}/cosmosdbshell -%{_libexecdir}/cosmosdbshell/CosmosDBShell +%{_libexecdir}/cosmosdbshell %license %{_licensedir}/%{name}/LICENSE.md %license %{_licensedir}/%{name}/NOTICE.html From a00ce6c21603673a1949d323af10cafb6e9cb0ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 27 Aug 2026 10:42:04 +0200 Subject: [PATCH 04/13] Address RPM packaging review feedback --- .pipelines/CosmosDB-Shell-Official.yml | 1 + README.md | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.pipelines/CosmosDB-Shell-Official.yml b/.pipelines/CosmosDB-Shell-Official.yml index ba31d7f3..75d4d4ae 100644 --- a/.pipelines/CosmosDB-Shell-Official.yml +++ b/.pipelines/CosmosDB-Shell-Official.yml @@ -845,6 +845,7 @@ extends: set -euo pipefail dotnet tool restore --configfile "$(Build.SourcesDirectory)/.pipelines/nuget.config" package_version="$(dotnet tool run nbgv get-version -v NuGetPackageVersion)" + package_version="${package_version%%+*}" if [[ ! "$package_version" =~ ^([0-9]+\.[0-9]+\.[0-9]+)(-(.+))?$ ]]; then echo "Unsupported RPM package version: $package_version" >&2 exit 1 diff --git a/README.md b/README.md index c6da8cf4..5707d758 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,15 @@ other RPM-based distributions: - `cosmosdbshell--.aarch64.rpm` The RPM requires the .NET 10 runtime package (`dotnet-runtime-10.0`), but does -not require the .NET SDK. Install the package that matches the host architecture: +not require the .NET SDK. On Azure Linux, install the package that matches the +host architecture with `tdnf`: + +```bash +sudo tdnf install ./cosmosdbshell--..rpm +cosmosdbshell +``` + +On other RPM-based distributions, use `dnf`: ```bash sudo dnf install ./cosmosdbshell--..rpm From b277fbca63111fb52316fa351e9886e615dcc3fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 27 Aug 2026 10:52:42 +0200 Subject: [PATCH 05/13] Validate RPM tooling environment --- .pipelines/CosmosDB-Shell-Official.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.pipelines/CosmosDB-Shell-Official.yml b/.pipelines/CosmosDB-Shell-Official.yml index 75d4d4ae..63c1813f 100644 --- a/.pipelines/CosmosDB-Shell-Official.yml +++ b/.pipelines/CosmosDB-Shell-Official.yml @@ -863,6 +863,10 @@ extends: - script: | set -euo pipefail if ! command -v rpmbuild >/dev/null 2>&1; then + if ! command -v tdnf >/dev/null 2>&1; then + echo "rpmbuild is unavailable and tdnf is not installed; run this job in the configured Azure Linux container." >&2 + exit 1 + fi tdnf install -y rpm-build fi From 3c72b0f80508fe3f55ed1851312acbce9b605652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 27 Aug 2026 12:02:56 +0200 Subject: [PATCH 06/13] Warn when RPM lacks broker authentication --- .pipelines/CosmosDB-Shell-Official.yml | 1 + .../CommandTests/ConnectCommandTests.cs | 10 ++++ .../ShellInterpreter.cs | 51 +++++++++++++------ CosmosDBShell/lang/en.ftl | 1 + Directory.Build.props | 3 ++ README.md | 5 ++ 6 files changed, 55 insertions(+), 16 deletions(-) diff --git a/.pipelines/CosmosDB-Shell-Official.yml b/.pipelines/CosmosDB-Shell-Official.yml index 63c1813f..2658090e 100644 --- a/.pipelines/CosmosDB-Shell-Official.yml +++ b/.pipelines/CosmosDB-Shell-Official.yml @@ -888,6 +888,7 @@ extends: --self-contained false \ -p:PublishSingleFile=false \ -p:PackAsTool=false \ + -p:CosmosDBShellExcludeMsalRuntime=true \ --output "$publish_dir" \ --configfile "$(Build.SourcesDirectory)/.pipelines/nuget.config" diff --git a/CosmosDBShell.Tests/CommandTests/ConnectCommandTests.cs b/CosmosDBShell.Tests/CommandTests/ConnectCommandTests.cs index 137147aa..27fefbd8 100644 --- a/CosmosDBShell.Tests/CommandTests/ConnectCommandTests.cs +++ b/CosmosDBShell.Tests/CommandTests/ConnectCommandTests.cs @@ -15,6 +15,16 @@ namespace CosmosShell.Tests.CommandTests; [Collection(CosmosShell.Tests.Shell.ThemeStateTestCollection.Name)] public class ConnectCommandTests { + [Fact] + public void VSCodeCredential_SupportMatchesBuildCapability() + { +#if COSMOSDBSHELL_NO_MSAL_RUNTIME + Assert.False(ShellInterpreter.IsVSCodeCredentialSupported); +#else + Assert.True(ShellInterpreter.IsVSCodeCredentialSupported); +#endif + } + [Fact] public async Task ConnectAsync_CanceledToken_CancelsConnectionAttempt() { diff --git a/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs b/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs index 4826518f..3640001a 100644 --- a/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs +++ b/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs @@ -110,6 +110,18 @@ internal ShellInterpreter(string? configPath = null) /// public bool Echo { get; set; } = true; + internal static bool IsVSCodeCredentialSupported + { + get + { +#if COSMOSDBSHELL_NO_MSAL_RUNTIME + return false; +#else + return true; +#endif + } + } + internal static CancellationTokenSource TokenSource { get @@ -970,27 +982,34 @@ internal async Task ConnectAsync(string connectionString, string? loginHint = nu // Step 2: VisualStudioCodeCredential (when launched from VS Code extension) if (client == null && credentialMethod == CredentialMethod.VSCode) { - WriteLine(MessageService.GetString("shell-connect-vscode-credential-auth")); - - var vscOptions = new VisualStudioCodeCredentialOptions(); - if (!string.IsNullOrWhiteSpace(tenantId)) + if (!IsVSCodeCredentialSupported) { - vscOptions.TenantId = tenantId; + WriteLine(MessageService.GetString("shell-connect-vscode-credential-msal-runtime-missing")); } - - if (authorityHostUri != null) + else { - vscOptions.AuthorityHost = authorityHostUri; - } + WriteLine(MessageService.GetString("shell-connect-vscode-credential-auth")); - var vscCredential = new VisualStudioCodeCredential(vscOptions); - if (await this.TryConnectWithTokenCredentialAsync(tokenEndpoint, vscCredential, options, subscriptionId, resourceGroupName, authorityHostUri, allowCredentialFallback: true, token)) - { - return; - } + var vscOptions = new VisualStudioCodeCredentialOptions(); + if (!string.IsNullOrWhiteSpace(tenantId)) + { + vscOptions.TenantId = tenantId; + } - // VS Code credential unavailable or expired; continue the credential chain. - WriteLine(MessageService.GetString("shell-connect-vscode-credential-fallback")); + if (authorityHostUri != null) + { + vscOptions.AuthorityHost = authorityHostUri; + } + + var vscCredential = new VisualStudioCodeCredential(vscOptions); + if (await this.TryConnectWithTokenCredentialAsync(tokenEndpoint, vscCredential, options, subscriptionId, resourceGroupName, authorityHostUri, allowCredentialFallback: true, token)) + { + return; + } + + // VS Code credential unavailable or expired; continue the credential chain. + WriteLine(MessageService.GetString("shell-connect-vscode-credential-fallback")); + } } // Step 3: Static token from COSMOSDB_SHELL_TOKEN environment variable diff --git a/CosmosDBShell/lang/en.ftl b/CosmosDBShell/lang/en.ftl index d0a5ae95..02ebb4cf 100644 --- a/CosmosDBShell/lang/en.ftl +++ b/CosmosDBShell/lang/en.ftl @@ -17,6 +17,7 @@ shell-connect-static-token-auth = Connecting with externally provided access tok shell-connect-static-token-expiry = Expires in { $timespan } (expiration: { $expiration }). shell-connect-vscode-credential-auth = Connecting with Visual Studio Code credential... shell-connect-vscode-credential-fallback = Visual Studio Code credential unavailable, falling back... +shell-connect-vscode-credential-msal-runtime-missing = WARNING: Visual Studio Code credential is unavailable because this build excludes the native MSAL runtime. Falling back to other credentials; use --azure-cli to select the Azure CLI identity explicitly. shell-connect-devicecode-fallback = Browser authentication failed, falling back to device code authentication... shell-connect-arm-discovery-failed = Using Cosmos DB data plane. shell-connect-arm-discovery-ambiguous = Multiple ARM Cosmos DB accounts match the connected endpoint. Reconnect with --subscription and --resource-group, or use --connect-subscription and --connect-resource-group at startup, to specify which account to use. Using Cosmos DB data plane for now. diff --git a/Directory.Build.props b/Directory.Build.props index 8dcb9c5e..c6db7613 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -15,4 +15,7 @@ + + $(DefineConstants);COSMOSDBSHELL_NO_MSAL_RUNTIME + diff --git a/README.md b/README.md index 5707d758..5efd2b7a 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,11 @@ sudo dnf install ./cosmosdbshell--..rpm cosmosdbshell ``` +The RPM excludes the native MSAL runtime to remain within the Azure Cloud Shell +package-size limit. Visual Studio Code credential authentication is unavailable +in this build; selecting it prints a warning and falls back to other credentials. +Use `--azure-cli` to select the signed-in Azure CLI identity explicitly. + ## Architecture | Folder | Purpose | From e16f7bdd521e370acd1c487fe71da060b08bf38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Tue, 1 Sep 2026 14:38:46 +0200 Subject: [PATCH 07/13] Reduce RPM footprint by excluding MCP and LSP Conditionally omit MCP, LSP, and unavailable broker dependencies from RPM builds while retaining the interactive shell, ARM support, direct/gateway connectivity, and OpenTelemetry. Document and validate the reduced RPM feature set. --- .pipelines/CosmosDB-Shell-Official.yml | 5 +++ CHANGELOG.md | 2 +- .../ShellInterpreter.Highlighter.cs | 1 - .../ShellInterpreter.cs | 2 ++ CosmosDBShell/CosmosDBShell.csproj | 20 +++++++---- CosmosDBShell/Program.cs | 35 +++++++++++++++---- CosmosDBShell/lang/en.ftl | 2 ++ Directory.Build.props | 3 ++ Directory.Packages.props | 1 + README.md | 13 ++++--- packaging/rpm/cosmosdbshell.spec | 3 +- 11 files changed, 67 insertions(+), 20 deletions(-) diff --git a/.pipelines/CosmosDB-Shell-Official.yml b/.pipelines/CosmosDB-Shell-Official.yml index 2658090e..17a4e763 100644 --- a/.pipelines/CosmosDB-Shell-Official.yml +++ b/.pipelines/CosmosDB-Shell-Official.yml @@ -889,6 +889,7 @@ extends: -p:PublishSingleFile=false \ -p:PackAsTool=false \ -p:CosmosDBShellExcludeMsalRuntime=true \ + -p:CosmosDBShellExcludeMcpAndLsp=true \ --output "$publish_dir" \ --configfile "$(Build.SourcesDirectory)/.pipelines/nuget.config" @@ -938,6 +939,10 @@ extends: echo "$(basename "$package") still carries libmsalruntime.so." >&2 exit 1 fi + if rpm -qlp "$package" | grep -Eq '/(ModelContextProtocol|OmniSharp|Azure\.Identity\.Broker|Microsoft\.Identity\.Client\.Broker).*\.dll$'; then + echo "$(basename "$package") unexpectedly contains an excluded feature assembly." >&2 + exit 1 + fi echo "Validated $(basename "$package") [$size bytes]" done displayName: Validate RPM packages diff --git a/CHANGELOG.md b/CHANGELOG.md index ba02fc3c..2f1afaf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Build & pipeline -- The official pipeline now produces compressed `x86_64` and `aarch64` RPM packages from the framework-dependent Linux builds. The packages require the .NET 10 runtime and are validated against the Azure Cloud Shell 25 MB package-size limit. +- The official pipeline now produces compressed `x86_64` and `aarch64` RPM packages from lightweight framework-dependent Linux builds. The packages retain the interactive shell, scripting, ARM management, direct/gateway connectivity, and OpenTelemetry export while excluding MCP, LSP, and brokered Visual Studio Code authentication. They require the .NET 10 runtime and are validated against the Azure Cloud Shell 25 MB package-size limit. ## 1.1.209-preview — 2026-08-26 diff --git a/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.Highlighter.cs b/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.Highlighter.cs index 58c551fe..53ba1405 100644 --- a/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.Highlighter.cs +++ b/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.Highlighter.cs @@ -7,7 +7,6 @@ namespace Azure.Data.Cosmos.Shell.Core; using System.Linq; using System.Text; using Azure.Data.Cosmos.Shell.Parser; -using Microsoft.AspNetCore.Http.Metadata; using RadLine; using Spectre.Console; using Spectre.Console.Rendering; diff --git a/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs b/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs index 3640001a..085c2417 100644 --- a/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs +++ b/CosmosDBShell/Azure.Data.Cosmos.Shell.Core/ShellInterpreter.cs @@ -986,6 +986,7 @@ internal async Task ConnectAsync(string connectionString, string? loginHint = nu { WriteLine(MessageService.GetString("shell-connect-vscode-credential-msal-runtime-missing")); } +#if !COSMOSDBSHELL_NO_MSAL_RUNTIME else { WriteLine(MessageService.GetString("shell-connect-vscode-credential-auth")); @@ -1010,6 +1011,7 @@ internal async Task ConnectAsync(string connectionString, string? loginHint = nu // VS Code credential unavailable or expired; continue the credential chain. WriteLine(MessageService.GetString("shell-connect-vscode-credential-fallback")); } +#endif } // Step 3: Static token from COSMOSDB_SHELL_TOKEN environment variable diff --git a/CosmosDBShell/CosmosDBShell.csproj b/CosmosDBShell/CosmosDBShell.csproj index 50d17844..890eb14a 100644 --- a/CosmosDBShell/CosmosDBShell.csproj +++ b/CosmosDBShell/CosmosDBShell.csproj @@ -74,7 +74,7 @@ - + @@ -86,16 +86,17 @@ - + - - - - + + + + + @@ -108,6 +109,13 @@ + + + + + + + diff --git a/CosmosDBShell/Program.cs b/CosmosDBShell/Program.cs index 4c11ce16..ef972302 100644 --- a/CosmosDBShell/Program.cs +++ b/CosmosDBShell/Program.cs @@ -7,11 +7,15 @@ using System.Reflection; using Azure.Data.Cosmos.Shell.Commands; using Azure.Data.Cosmos.Shell.Core; +#if !COSMOSDBSHELL_NO_MCP_LSP using Azure.Data.Cosmos.Shell.Lsp; using Azure.Data.Cosmos.Shell.Mcp; +#endif using Azure.Data.Cosmos.Shell.Util; using Microsoft.Azure.Cosmos; +#if !COSMOSDBSHELL_NO_MCP_LSP using Microsoft.Extensions.Hosting; +#endif using Spectre.Console; internal class Program @@ -25,6 +29,7 @@ public static async Task Main(string[] args) // accidentally trigger LSP mode. args = NormalizeArguments(args); +#if !COSMOSDBSHELL_NO_MCP_LSP // Handle LSP mode early, before any other code can write to stdout. // The LSP protocol requires exclusive access to stdin/stdout. Only // inspect the prefix before -c / -k so that a command tail of literally @@ -37,8 +42,9 @@ public static async Task Main(string[] args) await server.WaitForExit; return; } +#endif - IHost? host = null; + IDisposable? host = null; TracingBootstrap? tracing = null; try { @@ -181,12 +187,18 @@ public static async Task Main(string[] args) } } - if (o.StartLspServer) + if (o.StartLspServer || o.LspStdio) { +#if COSMOSDBSHELL_NO_MCP_LSP + ShellInterpreter.WriteLine(MessageService.GetString("error-lsp-not-included")); + Environment.ExitCode = ShellExitCode.UsageError; + return; +#else // Already handled above, but keep for completeness var server = await LspServer.CreateLanguageServerAsync(); await server.WaitForExit; return; +#endif } if (!string.IsNullOrWhiteSpace(o.ExecuteAndQuit) && !string.IsNullOrWhiteSpace(o.ExecuteAndContinue)) @@ -399,6 +411,11 @@ await ShellInterpreter.Instance.ConnectAsync( if (o.McpPort is int mcpPort) { +#if COSMOSDBSHELL_NO_MCP_LSP + WriteStartupError(MessageService.GetString("error-mcp-not-included")); + Environment.ExitCode = ShellExitCode.UsageError; + return; +#else if (mcpPort <= 0) { WriteStartupError(MessageService.GetString("mcp-error-invalid-port")); @@ -419,14 +436,15 @@ await ShellInterpreter.Instance.ConnectAsync( if (host != null) { + var mcpHost = (IHost)host; ShellInterpreter.Instance.McpPort = mcpPort; hostTask = Task.Run(async () => { try { var token = CancellationToken.None; - await host.StartAsync(token); - await host.WaitForShutdownAsync(token); + await mcpHost.StartAsync(token); + await mcpHost.WaitForShutdownAsync(token); } catch (Exception ex) { @@ -435,6 +453,7 @@ await ShellInterpreter.Instance.ConnectAsync( } }); } +#endif } if (Console.IsInputRedirected) @@ -516,12 +535,14 @@ private static void WriteVersionHeading() ShellInterpreter.WriteLine(heading); } - private static async Task StopHostAsync(IHost? host, Task? hostTask) + private static async Task StopHostAsync(IDisposable? host, Task? hostTask) { - if (host != null) +#if !COSMOSDBSHELL_NO_MCP_LSP + if (host is IHost mcpHost) { - await host.StopAsync(); + await mcpHost.StopAsync(); } +#endif if (hostTask != null) { diff --git a/CosmosDBShell/lang/en.ftl b/CosmosDBShell/lang/en.ftl index 02ebb4cf..ebe53e1c 100644 --- a/CosmosDBShell/lang/en.ftl +++ b/CosmosDBShell/lang/en.ftl @@ -32,6 +32,8 @@ yes_char = Y no_char = N error = Error: +error-lsp-not-included = LSP support is not included in this build. +error-mcp-not-included = MCP support is not included in this build. error-connection_failed = Failed to connect to the Cosmos DB account. error-emulator_connection_failed = Could not reach the Cosmos DB emulator at { $endpoint }. diff --git a/Directory.Build.props b/Directory.Build.props index c6db7613..d2dc1ddf 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -18,4 +18,7 @@ $(DefineConstants);COSMOSDBSHELL_NO_MSAL_RUNTIME + + $(DefineConstants);COSMOSDBSHELL_NO_MCP_LSP + diff --git a/Directory.Packages.props b/Directory.Packages.props index db1ee944..1f6cd656 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,6 +13,7 @@ + diff --git a/README.md b/README.md index 5efd2b7a..ad2c4c81 100644 --- a/README.md +++ b/README.md @@ -88,10 +88,15 @@ sudo dnf install ./cosmosdbshell--..rpm cosmosdbshell ``` -The RPM excludes the native MSAL runtime to remain within the Azure Cloud Shell -package-size limit. Visual Studio Code credential authentication is unavailable -in this build; selecting it prints a warning and falls back to other credentials. -Use `--azure-cli` to select the signed-in Azure CLI identity explicitly. +The RPM retains the interactive shell, scripting, ARM management, and both +direct and gateway Cosmos DB connectivity. To reduce its deployment footprint, +it excludes MCP, LSP, and the native and managed broker components used by +Visual Studio Code credential authentication. Invoking `--mcp`, `--lsp`, or +`--stdio` reports that the feature is unavailable. OpenTelemetry tracing and +OTLP export remain available through `--otel`. +Selecting Visual Studio Code credential authentication prints a warning and +falls back to other credentials. Use `--azure-cli` to select the signed-in Azure +CLI identity explicitly. ## Architecture diff --git a/packaging/rpm/cosmosdbshell.spec b/packaging/rpm/cosmosdbshell.spec index 6f967763..eedab2c8 100644 --- a/packaging/rpm/cosmosdbshell.spec +++ b/packaging/rpm/cosmosdbshell.spec @@ -21,7 +21,8 @@ AutoReqProv: no %description Azure Cosmos DB Shell is a command-line tool for interactive navigation, -queries, scripting, and MCP server workflows with Azure Cosmos DB. +queries, and scripting with Azure Cosmos DB. This lightweight build excludes +MCP, LSP, and brokered Visual Studio Code authentication. %prep From 9858e0e2176ce1d52d936eccea12b4cdf47e8a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Tue, 1 Sep 2026 16:51:41 +0200 Subject: [PATCH 08/13] Exclude MCP-only documentation from RPM builds Conditionally omit the embedded programming and NoSQL query guides together with the other MCP resources when MCP and LSP are excluded. --- CosmosDBShell/CosmosDBShell.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CosmosDBShell/CosmosDBShell.csproj b/CosmosDBShell/CosmosDBShell.csproj index 890eb14a..a5ebb388 100644 --- a/CosmosDBShell/CosmosDBShell.csproj +++ b/CosmosDBShell/CosmosDBShell.csproj @@ -75,8 +75,8 @@ - - + + From f26c988c89539eeafe9993963d5048c78c9a0fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 3 Sep 2026 10:41:45 +0200 Subject: [PATCH 09/13] Preserve JSON errors in lightweight builds --- .pipelines/CosmosDB-Shell-Official.yml | 12 +++++++++++ CosmosDBShell/Program.cs | 28 +++++++++++++------------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/.pipelines/CosmosDB-Shell-Official.yml b/.pipelines/CosmosDB-Shell-Official.yml index 17a4e763..f13899dd 100644 --- a/.pipelines/CosmosDB-Shell-Official.yml +++ b/.pipelines/CosmosDB-Shell-Official.yml @@ -905,6 +905,18 @@ extends: fi done + set +e + "$publish_dir/CosmosDBShell" --output json --lsp >lsp.stdout 2>lsp.stderr + lsp_exit=$? + set -e + if [[ $lsp_exit -ne 2 || -s lsp.stdout ]]; then + echo "Lightweight --lsp smoke test did not return a machine-mode usage error." >&2 + exit 1 + fi + grep -F '"status":"error"' lsp.stderr + grep -F '"error":"LSP support is not included in this build."' lsp.stderr + rm -f lsp.stdout lsp.stderr + tar -czf "$rpm_root/SOURCES/cosmosdbshell-payload.tar.gz" -C "$publish_dir" . rpmbuild -bb "$rpm_root/SPECS/cosmosdbshell.spec" \ --target "$rpm_arch" \ diff --git a/CosmosDBShell/Program.cs b/CosmosDBShell/Program.cs index ef972302..aaa604f3 100644 --- a/CosmosDBShell/Program.cs +++ b/CosmosDBShell/Program.cs @@ -187,20 +187,6 @@ public static async Task Main(string[] args) } } - if (o.StartLspServer || o.LspStdio) - { -#if COSMOSDBSHELL_NO_MCP_LSP - ShellInterpreter.WriteLine(MessageService.GetString("error-lsp-not-included")); - Environment.ExitCode = ShellExitCode.UsageError; - return; -#else - // Already handled above, but keep for completeness - var server = await LspServer.CreateLanguageServerAsync(); - await server.WaitForExit; - return; -#endif - } - if (!string.IsNullOrWhiteSpace(o.ExecuteAndQuit) && !string.IsNullOrWhiteSpace(o.ExecuteAndContinue)) { Environment.ExitCode = ShellExitCode.UsageError; @@ -252,6 +238,20 @@ void WriteStartupError(string message) AnsiConsole.WriteLine(message); } + if (o.StartLspServer || o.LspStdio) + { +#if COSMOSDBSHELL_NO_MCP_LSP + WriteStartupError(MessageService.GetString("error-lsp-not-included")); + Environment.ExitCode = ShellExitCode.UsageError; + return; +#else + // Already handled above, but keep for completeness + var server = await LspServer.CreateLanguageServerAsync(); + await server.WaitForExit; + return; +#endif + } + if (o.Container != null && o.Database == null) { WriteStartupError(MessageService.GetString("error-startup-container-requires-database")); From ac10044a680d4d9d50ece0001e50b6e24611be62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 3 Sep 2026 10:59:35 +0200 Subject: [PATCH 10/13] Clarify RPM artifact support scope --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 66bdfd14..dc7f1f65 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,11 @@ other RPM-based distributions: - `cosmosdbshell--.x86_64.rpm` - `cosmosdbshell--.aarch64.rpm` +These artifacts are intended for internal Azure Cloud Shell deployment and +controlled environments. They are not currently a supported general-purpose +Linux distribution channel; installation on other RPM-based distributions is +for evaluation in environments that provide the required runtime. + The RPM requires the .NET 10 runtime package (`dotnet-runtime-10.0`), but does not require the .NET SDK. On Azure Linux, install the package that matches the host architecture with `tdnf`: From 2990c7383d127bc820e048812070c6d3e294c9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 3 Sep 2026 11:02:58 +0200 Subject: [PATCH 11/13] Align RPM documentation with support scope --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dc7f1f65..0b94b80b 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,8 @@ dotnet test CosmosDBShell.sln ## Install from RPM Artifacts -The official pipeline produces framework-dependent RPMs for Azure Linux and -other RPM-based distributions: +The official pipeline produces framework-dependent RPMs for internal Azure +Cloud Shell deployments and controlled evaluation environments: - `cosmosdbshell--.x86_64.rpm` - `cosmosdbshell--.aarch64.rpm` From 9d05b8dccc884eab89cfe5ac5e7584f6da811a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 3 Sep 2026 11:12:46 +0200 Subject: [PATCH 12/13] Rename lightweight RPM package --- .pipelines/CosmosDB-Shell-Official.yml | 19 ++++++++++--------- CHANGELOG.md | 2 +- README.md | 14 +++++++------- ...osdbshell.spec => cosmosdbshell-lite.spec} | 6 +++--- 4 files changed, 21 insertions(+), 20 deletions(-) rename packaging/rpm/{cosmosdbshell.spec => cosmosdbshell-lite.spec} (91%) diff --git a/.pipelines/CosmosDB-Shell-Official.yml b/.pipelines/CosmosDB-Shell-Official.yml index f13899dd..42dfa064 100644 --- a/.pipelines/CosmosDB-Shell-Official.yml +++ b/.pipelines/CosmosDB-Shell-Official.yml @@ -827,12 +827,12 @@ extends: allowPackageConflicts: true - job: rpm - displayName: Build RPM packages + displayName: Build lightweight RPM packages pool: type: linux variables: ob_outputDirectory: "$(Build.SourcesDirectory)/out" - ob_artifactBaseName: cosmos_shell_rpm + ob_artifactBaseName: cosmos_shell_lite_rpm ob_git_fetchDepth: -1 steps: - task: UseDotNet@2 @@ -873,7 +873,7 @@ extends: rpm_root="$(Build.SourcesDirectory)/.rpmbuild" output_dir="$(Build.SourcesDirectory)/out/rpm" mkdir -p "$rpm_root"/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} "$output_dir" - cp "$(Build.SourcesDirectory)/packaging/rpm/cosmosdbshell.spec" "$rpm_root/SPECS/" + cp "$(Build.SourcesDirectory)/packaging/rpm/cosmosdbshell-lite.spec" "$rpm_root/SPECS/" cp "$(Build.SourcesDirectory)/LICENSE.md" "$(Build.SourcesDirectory)/NOTICE.html" "$rpm_root/SOURCES/" for entry in "linux-x64:x86_64" "linux-arm64:aarch64"; do @@ -917,21 +917,21 @@ extends: grep -F '"error":"LSP support is not included in this build."' lsp.stderr rm -f lsp.stdout lsp.stderr - tar -czf "$rpm_root/SOURCES/cosmosdbshell-payload.tar.gz" -C "$publish_dir" . - rpmbuild -bb "$rpm_root/SPECS/cosmosdbshell.spec" \ + tar -czf "$rpm_root/SOURCES/cosmosdbshell-lite-payload.tar.gz" -C "$publish_dir" . + rpmbuild -bb "$rpm_root/SPECS/cosmosdbshell-lite.spec" \ --target "$rpm_arch" \ --define "_topdir $rpm_root" \ --define "package_version $(CosmosDBShell_RpmVersion)" \ --define "package_release $(CosmosDBShell_RpmRelease)" done - find "$rpm_root/RPMS" -type f -name '*.rpm' -exec cp {} "$output_dir/" \; - displayName: Build framework-dependent RPMs + find "$rpm_root/RPMS" -type f -name 'cosmosdbshell-lite-*.rpm' -exec cp {} "$output_dir/" \; + displayName: Build lightweight framework-dependent RPMs - script: | set -euo pipefail output_dir="$(Build.SourcesDirectory)/out/rpm" - mapfile -t packages < <(find "$output_dir" -maxdepth 1 -type f -name '*.rpm' | sort) + mapfile -t packages < <(find "$output_dir" -maxdepth 1 -type f -name 'cosmosdbshell-lite-*.rpm' | sort) if [[ ${#packages[@]} -ne 2 ]]; then echo "Expected two RPM packages; found ${#packages[@]}." >&2 exit 1 @@ -943,6 +943,7 @@ extends: echo "$(basename "$package") is $size bytes and exceeds the 25 MB Cloud Shell limit." >&2 exit 1 fi + rpm -qp --queryformat '%{NAME}\n' "$package" | grep -Fx 'cosmosdbshell-lite' rpm -qpR "$package" | grep -Fx 'dotnet-runtime-10.0 >= 10.0' rpm -qlp "$package" | grep -Fx '/usr/bin/cosmosdbshell' rpm -qlp "$package" | grep -Fx '/usr/libexec/cosmosdbshell/CosmosDBShell' @@ -957,7 +958,7 @@ extends: fi echo "Validated $(basename "$package") [$size bytes]" done - displayName: Validate RPM packages + displayName: Validate lightweight RPM packages - job: CodeQLAnalyze displayName: CodeQL (C#) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8d3dfd4..b0025d7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Build & pipeline -- The official pipeline now produces compressed `x86_64` and `aarch64` RPM packages from lightweight framework-dependent Linux builds. The packages retain the interactive shell, scripting, ARM management, direct/gateway connectivity, and OpenTelemetry export while excluding MCP, LSP, and brokered Visual Studio Code authentication. They require the .NET 10 runtime and are validated against the Azure Cloud Shell 25 MB package-size limit. +- The official pipeline now produces compressed `cosmosdbshell-lite` RPM packages for `x86_64` and `aarch64` from lightweight framework-dependent Linux builds. The packages retain the interactive shell, scripting, ARM management, direct/gateway connectivity, and OpenTelemetry export while excluding MCP, LSP, and brokered Visual Studio Code authentication. They require the .NET 10 runtime and are validated against the Azure Cloud Shell 25 MB package-size limit. ### Improvements - Cosmos DB data-plane commands now consistently expose their aggregate observed request charge in structured output and connection-scoped `info` telemetry, including metadata/configuration operations, scripts, change feed reads, paginated operations, handled probes, and charged failures. Azure Resource Manager control-plane operations remain uncharged. diff --git a/README.md b/README.md index 0b94b80b..8405ab59 100644 --- a/README.md +++ b/README.md @@ -68,13 +68,13 @@ Run the tests: dotnet test CosmosDBShell.sln ``` -## Install from RPM Artifacts +## Install from Lightweight RPM Artifacts -The official pipeline produces framework-dependent RPMs for internal Azure -Cloud Shell deployments and controlled evaluation environments: +The official pipeline produces framework-dependent `cosmosdbshell-lite` RPMs +for internal Azure Cloud Shell deployments and controlled evaluation environments: -- `cosmosdbshell--.x86_64.rpm` -- `cosmosdbshell--.aarch64.rpm` +- `cosmosdbshell-lite--.x86_64.rpm` +- `cosmosdbshell-lite--.aarch64.rpm` These artifacts are intended for internal Azure Cloud Shell deployment and controlled environments. They are not currently a supported general-purpose @@ -86,14 +86,14 @@ not require the .NET SDK. On Azure Linux, install the package that matches the host architecture with `tdnf`: ```bash -sudo tdnf install ./cosmosdbshell--..rpm +sudo tdnf install ./cosmosdbshell-lite--..rpm cosmosdbshell ``` On other RPM-based distributions, use `dnf`: ```bash -sudo dnf install ./cosmosdbshell--..rpm +sudo dnf install ./cosmosdbshell-lite--..rpm cosmosdbshell ``` diff --git a/packaging/rpm/cosmosdbshell.spec b/packaging/rpm/cosmosdbshell-lite.spec similarity index 91% rename from packaging/rpm/cosmosdbshell.spec rename to packaging/rpm/cosmosdbshell-lite.spec index eedab2c8..fc6d1407 100644 --- a/packaging/rpm/cosmosdbshell.spec +++ b/packaging/rpm/cosmosdbshell-lite.spec @@ -1,10 +1,10 @@ -Name: cosmosdbshell +Name: cosmosdbshell-lite Version: %{package_version} Release: %{package_release}%{?dist} -Summary: Interactive shell for Azure Cosmos DB +Summary: Lightweight interactive shell for Azure Cosmos DB License: MIT URL: https://github.com/Azure/CosmosDBShell -Source0: cosmosdbshell-payload.tar.gz +Source0: cosmosdbshell-lite-payload.tar.gz Source1: LICENSE.md Source2: NOTICE.html Requires: dotnet-runtime-10.0 >= 10.0 From 51a5240677449c83e50f2b4f1b0db7dd83b554c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 3 Sep 2026 11:36:43 +0200 Subject: [PATCH 13/13] Use type-safe MCP host handling --- CosmosDBShell/Program.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CosmosDBShell/Program.cs b/CosmosDBShell/Program.cs index aaa604f3..868a0b4d 100644 --- a/CosmosDBShell/Program.cs +++ b/CosmosDBShell/Program.cs @@ -434,9 +434,8 @@ await ShellInterpreter.Instance.ConnectAsync( return; } - if (host != null) + if (host is IHost mcpHost) { - var mcpHost = (IHost)host; ShellInterpreter.Instance.McpPort = mcpPort; hostTask = Task.Run(async () => {