Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions eng/Bundle.proj
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,15 @@
<BundleVersion Condition="'$(BundleVersion)' == '' and '$(VersionSuffix)' != ''">$(VersionPrefix)-$(VersionSuffix)</BundleVersion>
<BundleVersion Condition="'$(BundleVersion)' == ''">$(VersionPrefix)-dev</BundleVersion>

<!-- Forward VersionSuffix to Exec-invoked dotnet commands (MSBuild properties don't flow to child processes) -->
<!-- Forward CI/signing/version properties to Exec-invoked dotnet commands (MSBuild properties don't flow to child processes) -->
<_ContinuousIntegrationBuildArg Condition="'$(ContinuousIntegrationBuild)' != ''">/p:ContinuousIntegrationBuild=$(ContinuousIntegrationBuild)</_ContinuousIntegrationBuildArg>
<_VersionSuffixArg Condition="'$(VersionSuffix)' != ''">/p:VersionSuffix=$(VersionSuffix)</_VersionSuffixArg>
<_OfficialBuildIdArg Condition="'$(OfficialBuildId)' != ''">/p:OfficialBuildId=$(OfficialBuildId)</_OfficialBuildIdArg>
<_SignArg Condition="'$(Sign)' != ''">/p:Sign=$(Sign)</_SignArg>
<_DotNetSignTypeArg Condition="'$(DotNetSignType)' != ''">/p:DotNetSignType=$(DotNetSignType)</_DotNetSignTypeArg>
<_DotNetPublishUsingPipelinesArg Condition="'$(DotNetPublishUsingPipelines)' != ''">/p:DotNetPublishUsingPipelines=$(DotNetPublishUsingPipelines)</_DotNetPublishUsingPipelinesArg>
<_TeamNameArg Condition="'$(TeamName)' != ''">/p:TeamName=$(TeamName)</_TeamNameArg>
<_PostBuildSignArg Condition="'$(PostBuildSign)' != ''">/p:PostBuildSign=$(PostBuildSign)</_PostBuildSignArg>

<!-- Binlog arguments for dotnet commands -->
<_BinlogArg Condition="'$(ContinuousIntegrationBuild)' == 'true'">-bl:$(ArtifactsLogDir)</_BinlogArg>
Expand Down Expand Up @@ -91,7 +98,7 @@
<_BundleArchivePath>$(ArtifactsDir)bundle\aspire-$(BundleVersion)-$(TargetRid).tar.gz</_BundleArchivePath>
</PropertyGroup>
<Message Importance="high" Text="Publishing native AOT CLI with embedded bundle: $(_BundleArchivePath)" />
<Exec Command="dotnet publish &quot;$(CliProjectPath)&quot; -c $(Configuration) -r $(TargetRid) /p:BundlePayloadPath=&quot;$(_BundleArchivePath)&quot; $(_VersionSuffixArg) $(_CliBinlog)" />
<Exec Command="dotnet publish &quot;$(CliProjectPath)&quot; -c $(Configuration) -r $(TargetRid) /p:BundlePayloadPath=&quot;$(_BundleArchivePath)&quot; $(_ContinuousIntegrationBuildArg) $(_VersionSuffixArg) $(_OfficialBuildIdArg) $(_SignArg) $(_DotNetSignTypeArg) $(_DotNetPublishUsingPipelinesArg) $(_TeamNameArg) $(_PostBuildSignArg) $(_CliBinlog)" />
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@radical @joperezr - do the sign args do anything here? I wouldn't think signing would happen during dotnet publish of these projects, but instead at a later step that signs things in the output directory.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It usually happens as a post build step as you say, but here it might be a bit different and tricky given we are zipping the contents and bundling them into aspire exe. I'm looking at details here to see how we can orchestrate this so it works, and also seeing if the current implementation works or not.

</Target>

<Target Name="_PublishManagedProjects" Condition="'$(SkipManagedBuild)' != 'true'">
Expand All @@ -100,7 +107,7 @@
</PropertyGroup>
<Message Importance="high" Text="Publishing aspire-managed (self-contained)..." />
<!-- Publish as self-contained single-file for the target RID -->
<Exec Command="dotnet publish &quot;$(ManagedProjectPath)&quot; -c $(Configuration) -r $(TargetRid) --self-contained /p:GenerateDocumentationFile=false /p:EnforceCodeStyleInBuild=false $(_VersionSuffixArg) $(_ManagedBinlog)" />
<Exec Command="dotnet publish &quot;$(ManagedProjectPath)&quot; -c $(Configuration) -r $(TargetRid) --self-contained /p:GenerateDocumentationFile=false /p:EnforceCodeStyleInBuild=false $(_ContinuousIntegrationBuildArg) $(_VersionSuffixArg) $(_OfficialBuildIdArg) $(_SignArg) $(_DotNetSignTypeArg) $(_DotNetPublishUsingPipelinesArg) $(_TeamNameArg) $(_PostBuildSignArg) $(_ManagedBinlog)" />
</Target>

<Target Name="_RestoreDcpPackage">
Expand Down
3 changes: 3 additions & 0 deletions eng/Signing.props
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@
<FileSignInfo Include="Tuf.dll" CertificateName="3PartySHA2" />

<FileSignInfo Condition="$([System.OperatingSystem]::IsWindows())" Include="aspire.exe" CertificateName="MicrosoftDotNet500" />
<FileSignInfo Condition="$([System.OperatingSystem]::IsWindows())" Include="aspire-managed.exe" CertificateName="MicrosoftDotNet500" />
<FileSignInfo Condition="$([System.OperatingSystem]::IsLinux())" Include="aspire" CertificateName="MicrosoftDotNet500" />
<FileSignInfo Condition="$([System.OperatingSystem]::IsLinux())" Include="aspire-managed" CertificateName="MicrosoftDotNet500" />
<FileSignInfo Condition="$([System.OperatingSystem]::IsMacOS())" Include="aspire" CertificateName="MacDeveloperHardenWithNotarization" />
<FileSignInfo Condition="$([System.OperatingSystem]::IsMacOS())" Include="aspire-managed" CertificateName="MacDeveloperHardenWithNotarization" />
<FileSignInfo Condition="$([System.OperatingSystem]::IsWindows())" Include="get-aspire-cli.ps1" CertificateName="MicrosoftDotNet500" />

<!-- Sign the manifest catalog on Windows -->
Expand Down
12 changes: 9 additions & 3 deletions eng/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,15 @@ if ($bundle) {
"/p:TargetRid=$rid"
)

# Pass through SkipNativeBuild if set
if ($properties -contains "/p:SkipNativeBuild=true") {
$bundleArgs += "/p:SkipNativeBuild=true"
foreach ($property in $properties) {
if ($property -eq "-sign") {
$bundleArgs += "/p:Sign=true"
continue
}

if ($property.StartsWith("/p:", [System.StringComparison]::OrdinalIgnoreCase)) {
$bundleArgs += $property
}
}

# CI flag is passed to Bundle.proj which handles version computation via Versions.props
Expand Down
16 changes: 9 additions & 7 deletions eng/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ usage()

arguments=''
extraargs=''
bundle_passthrough_args=()
build_bundle=false
runtime_version=""
config="Debug"
Expand Down Expand Up @@ -169,6 +170,11 @@ while [[ $# > 0 ]]; do
;;

*)
if [[ "$opt" == "-sign" ]]; then
bundle_passthrough_args+=("/p:Sign=true")
elif [[ "$1" == "/p:"* || "$1" == "-p:"* ]]; then
bundle_passthrough_args+=("$1")
fi
extraargs="$extraargs $1"
shift 1
;;
Expand Down Expand Up @@ -246,13 +252,9 @@ if [ "$build_bundle" = true ]; then
"/p:TargetRid=$rid"
)

# Pass through SkipNativeBuild if set
for arg in "$@"; do
if [[ "$arg" == *"SkipNativeBuild=true"* ]]; then
bundle_args+=("/p:SkipNativeBuild=true")
break
fi
done
if [ ${#bundle_passthrough_args[@]} -gt 0 ]; then
bundle_args+=("${bundle_passthrough_args[@]}")
fi

# CI flag is passed to Bundle.proj which handles version computation via Versions.props
if [ "${CI:-}" = "true" ]; then
Expand Down
19 changes: 19 additions & 0 deletions eng/pipelines/templates/BuildAndTest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,28 @@ steps:
/p:BundleVersion=ci-bundlepayload
/p:SkipNativeBuild=true
/p:ContinuousIntegrationBuild=true
$(_SignArgs)
$(_OfficialBuildIdArgs)
/bl:${{ parameters.repoLogPath }}/BundlePayload-${{ targetRid }}.binlog
displayName: 🟣Build bundle payload (${{ targetRid }})

- pwsh: |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why are we trying to verify the signed status of the aspire-managed.exe, but not any other files? Seems odd that we'd do that here.

$managedPath = Join-Path '${{ parameters.repoArtifactsPath }}/bin/Aspire.Managed/${{ parameters.buildConfig }}/net10.0/${{ targetRid }}/publish' 'aspire-managed.exe'
if (-not (Test-Path $managedPath)) {
Write-Host "##[error]aspire-managed.exe not found at $managedPath"
exit 1
}

$signature = Get-AuthenticodeSignature $managedPath
if ($signature.Status -eq [System.Management.Automation.SignatureStatus]::NotSigned) {
Write-Host "##[error]aspire-managed.exe is not signed: $managedPath"
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

Get-AuthenticodeSignature can return statuses other than NotSigned (e.g., HashMismatch, NotTrusted, UnknownError). The current check only fails on NotSigned, so an invalid or broken signature could still pass. Consider failing unless the status is Valid (or explicitly allow only the statuses you consider acceptable).

Suggested change
if ($signature.Status -eq [System.Management.Automation.SignatureStatus]::NotSigned) {
Write-Host "##[error]aspire-managed.exe is not signed: $managedPath"
if ($signature.Status -ne [System.Management.Automation.SignatureStatus]::Valid) {
Write-Host "##[error]aspire-managed.exe has an invalid signature status '$($signature.Status)': $managedPath"

Copilot uses AI. Check for mistakes.
exit 1
}

Write-Host "✅ aspire-managed.exe signature status: $($signature.Status)"
displayName: 🟣Verify managed bundle signature (${{ targetRid }})
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), in(variables['_SignType'], 'real', 'test'), startsWith('${{ targetRid }}', 'win-'))
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

The signature verification step is likely to run on PR builds where signing is disabled (e.g., _Sign is false and _SignArgs is empty). In that case aspire-managed.exe will legitimately be unsigned and this step will fail the pipeline. Update the condition to also require that signing is actually enabled (for example by checking variables['_Sign'] or that _SignArgs is non-empty).

Suggested change
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), in(variables['_SignType'], 'real', 'test'), startsWith('${{ targetRid }}', 'win-'))
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['_Sign'], 'true'), in(variables['_SignType'], 'real', 'test'), startsWith('${{ targetRid }}', 'win-'))

Copilot uses AI. Check for mistakes.

- script: ${{ parameters.buildScript }}
-restore -build
-pack
Expand Down
1 change: 1 addition & 0 deletions eng/pipelines/templates/build_sign_native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ jobs:
/p:BundleVersion=ci-bundlepayload
/p:SkipNativeBuild=true
/p:ContinuousIntegrationBuild=true
${{ parameters.extraBuildArgs }}
/bl:$(Build.Arcade.LogsPath)BundlePayload.binlog
displayName: 🟣Build bundle payload

Expand Down
Loading