diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000..06b68ea --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/build.proj b/build.proj deleted file mode 100644 index 9c7399a..0000000 --- a/build.proj +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - Release - $(MSBuildProjectDirectory)\out - - false - Configuration=$(Configuration);PackageOutputPath=$(PackageOutputPath);GitSkipCache=true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build/CredScanSuppressions.json b/build/CredScanSuppressions.json new file mode 100644 index 0000000..0ffa6c2 --- /dev/null +++ b/build/CredScanSuppressions.json @@ -0,0 +1,9 @@ +{ + "tool": "Credential Scanner", + "suppressions": [ + { + "file": "src\\IntegrationTests\\AuthenticationSpec.cs", + "_justification": "Dummy credentials for testing purposes" + } + ] +} \ No newline at end of file diff --git a/build/PoliCheckExclusions.xml b/build/PoliCheckExclusions.xml new file mode 100644 index 0000000..dba1ad4 --- /dev/null +++ b/build/PoliCheckExclusions.xml @@ -0,0 +1,3 @@ + + + diff --git a/build/stages/build.yml b/build/stages/build.yml new file mode 100644 index 0000000..0196d91 --- /dev/null +++ b/build/stages/build.yml @@ -0,0 +1,124 @@ +# Build Stage + +stages: +- stage: Build + jobs: + - job: Windows + timeoutInMinutes: 10 + pool: + name: $(WindowsPoolName) + + steps: + - checkout: self + clean: true + + - task: UseDotNet@2 + displayName: 'Use .Net Core SDK $(DotNetCoreVersion)' + inputs: + version: '$(DotNetCoreVersion)' + condition: always() + + - script: 'mkdir "$(Build.ArtifactStagingDirectory)\binlogs"' + displayName: 'Create Logs Dir' + condition: always() + + # Ensure we clear bot-provided feeds, for reliability + - powershell: | + $configPath = "$(Build.SourcesDirectory)\NuGet.Config" + [xml]$config = get-content $configPath + $config.configuration.packageSources.PrependChild($config.CreateElement("clear")) + $config.Save($configPath) + displayName: 'Ensure Clean NuGet Sources' + condition: always() + + - task: NuGetCommand@2 + displayName: 'Restore Packages' + inputs: + restoreSolution: '$(Build.SourcesDirectory)/src/Hermes.sln' + feedsToUse: config + nugetConfigPath: '$(Build.SourcesDirectory)/NuGet.Config' + condition: always() + + - task: MSBuild@1 + displayName: 'Build Solution' + inputs: + solution: '$(Build.SourcesDirectory)/src/Hermes.sln' + msbuildArguments: /t:Build /noautoresponse /bl:"$(Build.ArtifactStagingDirectory)\binlogs\build.binlog" + condition: always() + + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact: packages' + inputs: + PathtoPublish: '$(Build.SourcesDirectory)\pack' + ArtifactName: packages + continueOnError: true + condition: always() + + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact: unit-tests' + inputs: + PathtoPublish: '$(Build.SourcesDirectory)\src\Tests\bin\$(Configuration)' + ArtifactName: unit-tests + continueOnError: true + condition: always() + + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact: integration-tests' + inputs: + PathtoPublish: '$(Build.SourcesDirectory)\src\IntegrationTests\bin\$(Configuration)' + ArtifactName: integration-tests + continueOnError: true + condition: always() + + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact: logs' + inputs: + PathtoPublish: '$(Build.ArtifactStagingDirectory)\binlogs' + ArtifactName: logs + continueOnError: true + condition: always() + + - task: CopyFiles@2 + displayName: 'Copy Symbols' + inputs: + SourceFolder: '$(Build.SourcesDirectory)/src/Server/bin/$(Configuration)' + Contents: | + **/System.Net.Mqtt.?(dll|pdb) + **/System.Net.Mqtt.Server.?(dll|pdb) + TargetFolder: '$(Build.ArtifactStagingDirectory)/Symbols' + CleanTargetFolder: true + FlattenFolders: true + OverWrite: true # Check if we should copy to $(TargetFramework) subfolders instead + condition: always() + + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact: symbols' + inputs: + PathtoPublish: '$(Build.ArtifactStagingDirectory)/Symbols' + ArtifactName: symbols + condition: always() + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Governance' + condition: and(succeeded(), eq(variables['Build.SourceBranch'], variables['MainBranch'])) + + - powershell: | + $complianceEnabled = if ($env:COMPLIANCEENABLED) { $env:COMPLIANCEENABLED } else { '' } + + if ($complianceEnabled -eq '') { + $branch = '$(Build.SourceBranch)' + $reason = '$(Build.Reason)' + + if($branch -eq '$(MainBranch)' -or $reason -eq 'PullRequest') { + $complianceEnabled = 'true' + } else { + $complianceEnabled = 'false' + } + } + + Write-Host "Source Branch: $branch, Build Reason: $reason" + Write-Host "Requires Compliance Stage: $complianceEnabled" + Write-Host "##vso[task.setvariable variable=Xamarin.ComplianceEnabled;isOutput=true]$complianceEnabled" + name: 'SetComplianceNeed' + displayName: 'Evaluate Compliance Need' + condition: always() diff --git a/build/stages/compliance.yml b/build/stages/compliance.yml new file mode 100644 index 0000000..6b9041b --- /dev/null +++ b/build/stages/compliance.yml @@ -0,0 +1,101 @@ +# Compliance Stage + +stages: +- stage : Compliance + dependsOn: Build + condition: eq(stageDependencies.Build.outputs['Windows.SetComplianceNeed.Xamarin.ComplianceEnabled'], 'true') + jobs: + - job: CodeAnalysis + displayName: Security & Analysis + pool: $(WindowsPoolName) + timeoutInMinutes: 60 + cancelTimeoutInMinutes: 5 + steps: + - checkout: self + clean: true + submodules: recursive + - task: DownloadBuildArtifacts@0 + displayName: Download Symbols + inputs: + artifactName: symbols + downloadPath: '$(Build.ArtifactStagingDirectory)' + - task: AntiMalware@3 + displayName: Run AntiMalware Scan + inputs: + FileDirPath: $(System.DefaultWorkingDirectory) + EnableServices: true + continueOnError: true + condition: succeededOrFailed() + - task: BinSkim@3 + displayName: Run BinSkim Analysis + inputs: + InputType: Basic + AnalyzeTarget: '$(Build.ArtifactStagingDirectory)\Symbols\*.dll' + AnalyzeVerbose: true + continueOnError: true + condition: succeededOrFailed() + - template: security\credscan\v2.yml@templates # from xamarin/yaml-templates repository + parameters: + suppressionsFile: $(System.DefaultWorkingDirectory)\build\CredScanSuppressions.json + - template: security\policheck\v1.yml@templates # from xamarin/yaml-templates repository + parameters: + exclusionFile: $(System.DefaultWorkingDirectory)\build\PoliCheckExclusions.xml + - task: CodeInspector@2 + displayName: Run Code Inspector Analysis + inputs: + ProductId: '$(System.TeamProjectId)' + continueOnError: true + condition: succeededOrFailed() + - task: SdtReport@1 + displayName: Create Security Analysis Report + inputs: + AntiMalware: true + BinSkim: true + CredScan: true + RoslynAnalyzers: true + PoliCheck: true + CodeInspector: true + continueOnError: true + condition: succeededOrFailed() + - task: PublishSecurityAnalysisLogs@2 + displayName: Publish Security Analysis Logs + inputs: + ArtifactName: ComplianceLogs + continueOnError: true + condition: succeededOrFailed() + - task: PostAnalysis@1 + displayName: Run Security Post Analysis + inputs: + AntiMalware: true + BinSkim: true + CredScan: true + RoslynAnalyzers: true + PoliCheck: true + CodeInspector: true + continueOnError: true + condition: succeededOrFailed() + - task: TSAUpload@1 + inputs: + tsaVersion: 'TsaV2' + codebase: 'NewOrUpdate' + tsaEnvironment: 'PROD' + codeBaseName: 'mqtt_main' + notificationAlias: 'xvs@microsoft.com,maagno@microsoft.com' + notifyAlwaysV2: false + codeBaseAdmins: 'REDMOND\maagno;REDMOND\vsengxamarin' + instanceUrlForTsaV2: 'DEVDIV' + projectNameDEVDIV: 'DevDiv' + areaPath: 'DevDiv\Xamarin Tools\XamarinVS\XMA' + iterationPath: 'DevDiv\OneVS' + uploadAPIScan: true + uploadBinSkim: true + uploadCredScan: true + uploadFortifySCA: true + uploadFxCop: true + uploadModernCop: true + uploadPoliCheck: true + uploadPREfast: true + uploadRoslyn: true + uploadTSLint: true + uploadAsync: true + condition: succeededOrFailed() diff --git a/build/stages/push.yml b/build/stages/push.yml new file mode 100644 index 0000000..5f27313 --- /dev/null +++ b/build/stages/push.yml @@ -0,0 +1,37 @@ +# Upload Stage + +stages: +- stage : Package + dependsOn: + - Test + - Compliance + condition: and(succeeded(), eq(variables['Build.SourceBranch'], variables['MainBranch'])) + jobs: + - job: Push + displayName: Pack & Push + timeoutInMinutes: 10 + pool: + name: $(WindowsPoolName) + steps: + - checkout: self + + - task: DownloadBuildArtifacts@0 + displayName: Download Packages + inputs: + artifactName: packages + downloadPath: '$(Build.ArtifactStagingDirectory)' + + - task: NuGetCommand@2 + displayName: 'NuGet Update' + inputs: + command: custom + arguments: 'update -self' + + - task: NuGetCommand@2 + displayName: Push Packages + continueOnError: true + inputs: + command: push + packagesToPush: '$(Build.ArtifactStagingDirectory)/packages/*.nupkg' + nuGetFeedType: external + publishFeedCredentials: '$(PackagesFeedCredentials)' diff --git a/build/stages/test.yml b/build/stages/test.yml new file mode 100644 index 0000000..69fe0a7 --- /dev/null +++ b/build/stages/test.yml @@ -0,0 +1,57 @@ +# Test Stage + +stages: +- stage: Test + dependsOn: Build + jobs: + - job: Unit + timeoutInMinutes: 10 + pool: + name: $(WindowsPoolName) + + steps: + - checkout: none + + - task: DownloadBuildArtifacts@0 + inputs: + artifactName: unit-tests + + - task: VSTest@2 + displayName: 'Unit Tests' + timeoutInMinutes: 10 + inputs: + testSelector: 'testAssemblies' + testAssemblyVer2: | + **\Tests.dll + searchFolder: '$(Build.ArtifactStagingDirectory)\unit-tests' + testFiltercriteria: 'Flaky!=true' + codeCoverageEnabled: true + runInParallel: true + rerunFailedTests: true + rerunMaxAttempts: 5 + + - job: Integration + timeoutInMinutes: 10 + pool: + name: $(WindowsPoolName) + + steps: + - checkout: none + + - task: DownloadBuildArtifacts@0 + inputs: + artifactName: integration-tests + + - task: VSTest@2 + displayName: 'Integration Tests' + timeoutInMinutes: 10 + inputs: + testSelector: 'testAssemblies' + testAssemblyVer2: | + **\IntegrationTests.dll + searchFolder: '$(Build.ArtifactStagingDirectory)\integration-tests' + codeCoverageEnabled: false + diagnosticsEnabled: false + runInParallel: false + rerunFailedTests: true + rerunMaxAttempts: 5 \ No newline at end of file diff --git a/build/variables.yml b/build/variables.yml new file mode 100644 index 0000000..0c8cdd0 --- /dev/null +++ b/build/variables.yml @@ -0,0 +1,21 @@ +# Common Variables + +variables: +- group: Xamarin Release +- group: Xamarin Signing +- group: Xamarin Notarization +- group: Xamarin-Secrets +- group: xamops-azdev-secrets +- group: akaxvs-secrets +- name: MSBUILDDISABLENODEREUSE + value: 1 +- name: VSS_NUGET_EXTERNAL_FEED_ENDPOINTS + value: $(ExternalFeedEndpoints) +- name: DotNetCoreVersion + value: '3.1.102' +- name: WindowsPoolName + value: $(PoolName) +- name: Configuration + value: Release +- name: MainBranch + value: refs/heads/main diff --git a/pipeline.yml b/pipeline.yml new file mode 100644 index 0000000..059153d --- /dev/null +++ b/pipeline.yml @@ -0,0 +1,24 @@ +resources: + repositories: + - repository: templates + type: github + name: xamarin/yaml-templates + ref: refs/heads/main + endpoint: xamarin + +trigger: + batch: false + branches: + include: + - main +pr: + - main + +variables: +- template: build/variables.yml + +stages: +- template: build/stages/build.yml +- template: build/stages/compliance.yml +- template: build/stages/test.yml +- template: build/stages/push.yml diff --git a/src/Client/Client.csproj b/src/Client/Client.csproj index b1bc6ab..de0151b 100644 --- a/src/Client/Client.csproj +++ b/src/Client/Client.csproj @@ -1,14 +1,13 @@ - - + net46;netstandard2.0 - true - System.Net.Mqtt System.Net.Mqtt - $(AssemblyName) $(IntermediateOutputPath)\$(TargetFramework)\$(AssemblyName).xml + + + $(AssemblyName) A lightweight and simple MQTT client implementation written entirely in C#. @@ -26,5 +25,4 @@ Resources.Designer.cs - \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 77ead03..c3f691c 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -5,7 +5,7 @@ System.Net.Mqtt - + Microsoft true https://raw.githubusercontent.com/xamarin/mqtt/main/LICENSE @@ -14,13 +14,16 @@ © Microsoft Corporation. All rights reserved. m2m iot sockets mqtt + true + $(MSBuildThisFileDirectory)..\pack + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + false + true - true $(MSBuildThisFileDirectory)Hermes.snk - diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 371faa9..7892e04 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -7,6 +7,7 @@ + diff --git a/src/Server/Server.csproj b/src/Server/Server.csproj index ee7c6b6..c6483cc 100644 --- a/src/Server/Server.csproj +++ b/src/Server/Server.csproj @@ -1,14 +1,13 @@  - net46;netstandard2.0 - true - System.Net.Mqtt.Server System.Net.Mqtt.Server - $(AssemblyName) $(IntermediateOutputPath)\$(TargetFramework)\$(AssemblyName).xml + + + $(AssemblyName) A lightweight and simple MQTT Server implementation written entirely in C#. @@ -22,5 +21,4 @@ Resources.Designer.cs - \ No newline at end of file