|
25 | 25 | 3. GenerateCycloneDxSbom (after build, before pack) |
26 | 26 | --> |
27 | 27 |
|
| 28 | + <!-- Inline task to URL-encode component name and version --> |
| 29 | + <UsingTask TaskName="UrlEncodeCycloneDxProps" TaskFactory="CodeTaskFactory" AssemblyName="Microsoft.Build.Tasks.Core"> |
| 30 | + <ParameterGroup> |
| 31 | + <ComponentName ParameterType="System.String" Required="true" /> |
| 32 | + <Version ParameterType="System.String" Required="true" /> |
| 33 | + <EncodedComponentName ParameterType="System.String" Output="true" /> |
| 34 | + <EncodedVersion ParameterType="System.String" Output="true" /> |
| 35 | + </ParameterGroup> |
| 36 | + <Task> |
| 37 | + <Reference Include="System" /> |
| 38 | + <Code Type="Fragment" Language="cs"> |
| 39 | + <![CDATA[ |
| 40 | + EncodedComponentName = System.Uri.EscapeDataString(ComponentName ?? ""); |
| 41 | + EncodedVersion = System.Uri.EscapeDataString(Version ?? ""); |
| 42 | + ]]> |
| 43 | + </Code> |
| 44 | + </Task> |
| 45 | + </UsingTask> |
| 46 | + |
| 47 | + <!-- Inline task to XML-escape strings --> |
| 48 | + <UsingTask TaskName="XmlEscapeCycloneDxProps" TaskFactory="CodeTaskFactory" AssemblyName="Microsoft.Build.Tasks.Core"> |
| 49 | + <ParameterGroup> |
| 50 | + <InputString ParameterType="System.String" Required="true" /> |
| 51 | + <EscapedString ParameterType="System.String" Output="true" /> |
| 52 | + </ParameterGroup> |
| 53 | + <Task> |
| 54 | + <Reference Include="System.Xml" /> |
| 55 | + <Code Type="Fragment" Language="cs"> |
| 56 | + <![CDATA[ |
| 57 | + if (!string.IsNullOrEmpty(InputString)) |
| 58 | + { |
| 59 | + EscapedString = InputString |
| 60 | + .Replace("&", "&") |
| 61 | + .Replace("<", "<") |
| 62 | + .Replace(">", ">") |
| 63 | + .Replace("\"", """) |
| 64 | + .Replace("'", "'"); |
| 65 | + } |
| 66 | + else |
| 67 | + { |
| 68 | + EscapedString = ""; |
| 69 | + } |
| 70 | + ]]> |
| 71 | + </Code> |
| 72 | + </Task> |
| 73 | + </UsingTask> |
| 74 | + |
28 | 75 | <Target Name="ValidateCycloneDxConfiguration" |
29 | 76 | BeforeTargets="Build" |
30 | 77 | Condition="'$(GenerateCycloneDxSbom)' == 'true'"> |
|
136 | 183 | <!-- Build package URL (purl) --> |
137 | 184 | </PropertyGroup> |
138 | 185 |
|
139 | | - <!-- Inline task to URL-encode component name and version --> |
140 | | - <UsingTask TaskName="UrlEncodeCycloneDxProps" TaskFactory="CodeTaskFactory" AssemblyName="Microsoft.Build.Tasks.Core"> |
141 | | - <ParameterGroup> |
142 | | - ComponentName ParameterType="System.String" Required="true" /> |
143 | | - Version ParameterType="System.String" Required="true" /> |
144 | | - EncodedComponentName ParameterType="System.String" Output="true" /> |
145 | | - EncodedVersion ParameterType="System.String" Output="true" /> |
146 | | - </ParameterGroup> |
147 | | - <Task> |
148 | | - <Reference Include="System" /> |
149 | | - <Code Type="Fragment" Language="cs"> |
150 | | - EncodedComponentName = System.Uri.EscapeDataString(ComponentName ?? ""); |
151 | | - EncodedVersion = System.Uri.EscapeDataString(Version ?? ""); |
152 | | - </Code> |
153 | | - </Task> |
154 | | - </UsingTask> |
155 | | - |
156 | 186 | <UrlEncodeCycloneDxProps |
157 | 187 | ComponentName="$(_CycloneDxComponentName)" |
158 | 188 | Version="$(_CycloneDxVersion)"> |
|
163 | 193 | <PropertyGroup> |
164 | 194 | <_CycloneDxPurl>pkg:nuget/$(_CycloneDxComponentNameEncoded)@$(_CycloneDxVersionEncoded)</_CycloneDxPurl> |
165 | 195 | </PropertyGroup> |
| 196 | + |
| 197 | + <!-- Escape all values for XML --> |
| 198 | + <XmlEscapeCycloneDxProps InputString="$(_CycloneDxPurl)"> |
| 199 | + <Output TaskParameter="EscapedString" PropertyName="_CycloneDxPurlEscaped" /> |
| 200 | + </XmlEscapeCycloneDxProps> |
| 201 | + |
| 202 | + <XmlEscapeCycloneDxProps InputString="$(_CycloneDxComponentName)"> |
| 203 | + <Output TaskParameter="EscapedString" PropertyName="_CycloneDxComponentNameEscaped" /> |
| 204 | + </XmlEscapeCycloneDxProps> |
| 205 | + |
| 206 | + <XmlEscapeCycloneDxProps InputString="$(_CycloneDxVersion)"> |
| 207 | + <Output TaskParameter="EscapedString" PropertyName="_CycloneDxVersionEscaped" /> |
| 208 | + </XmlEscapeCycloneDxProps> |
| 209 | + |
| 210 | + <XmlEscapeCycloneDxProps InputString="$(_CycloneDxDescription)" Condition="'$(_CycloneDxDescription)' != ''"> |
| 211 | + <Output TaskParameter="EscapedString" PropertyName="_CycloneDxDescriptionEscaped" /> |
| 212 | + </XmlEscapeCycloneDxProps> |
| 213 | + |
| 214 | + <XmlEscapeCycloneDxProps InputString="$(_CycloneDxAuthors)" Condition="'$(_CycloneDxAuthors)' != ''"> |
| 215 | + <Output TaskParameter="EscapedString" PropertyName="_CycloneDxAuthorsEscaped" /> |
| 216 | + </XmlEscapeCycloneDxProps> |
| 217 | + |
| 218 | + <XmlEscapeCycloneDxProps InputString="$(_CycloneDxCopyright)" Condition="'$(_CycloneDxCopyright)' != ''"> |
| 219 | + <Output TaskParameter="EscapedString" PropertyName="_CycloneDxCopyrightEscaped" /> |
| 220 | + </XmlEscapeCycloneDxProps> |
| 221 | + |
| 222 | + <XmlEscapeCycloneDxProps InputString="$(_CycloneDxLicense)" Condition="'$(_CycloneDxLicense)' != ''"> |
| 223 | + <Output TaskParameter="EscapedString" PropertyName="_CycloneDxLicenseEscaped" /> |
| 224 | + </XmlEscapeCycloneDxProps> |
| 225 | + |
166 | 226 | <Message Importance="low" Text="[CycloneDX] Generating metadata from assembly information..." /> |
167 | 227 | <Message Importance="low" Text="[CycloneDX] Version: $(_CycloneDxVersion)" /> |
168 | 228 | <Message Importance="low" Text="[CycloneDX] Name: $(_CycloneDxComponentName)" /> |
169 | 229 | <Message Importance="low" Text="[CycloneDX] Authors: $(_CycloneDxAuthors)" Condition="'$(_CycloneDxAuthors)' != ''" /> |
170 | 230 |
|
171 | | - <!-- Build metadata XML content --> |
| 231 | + <!-- Build metadata XML content using escaped values without CDATA interleaving --> |
172 | 232 | <PropertyGroup> |
173 | | - <_CycloneDxMetadataContent><![CDATA[<?xml version="1.0" encoding="utf-8"?> |
174 | | -<bom xmlns="http://cyclonedx.org/schema/bom/1.6"> |
175 | | - <metadata> |
176 | | - <component type="application" bom-ref="$([System.Security.SecurityElement::Escape('$(_CycloneDxPurl)'))]"> |
177 | | - <name>$([System.Security.SecurityElement::Escape('$(_CycloneDxComponentName)'))]</name> |
178 | | - <version>$([System.Security.SecurityElement::Escape('$(_CycloneDxVersion)'))]</version>]]></_CycloneDxMetadataContent> |
| 233 | + <_CycloneDxMetadataContent> |
| 234 | + <?xml version="1.0" encoding="utf-8"?> |
| 235 | + <bom xmlns="http://cyclonedx.org/schema/bom/1.6"> |
| 236 | + <metadata> |
| 237 | + <component type="application" bom-ref="$(_CycloneDxPurlEscaped)"> |
| 238 | + <name>$(_CycloneDxComponentNameEscaped)</name> |
| 239 | + <version>$(_CycloneDxVersionEscaped)</version> |
| 240 | + </_CycloneDxMetadataContent> |
179 | 241 |
|
180 | 242 | <!-- Add description if available --> |
181 | | - <_CycloneDxMetadataContent Condition="'$(_CycloneDxDescription)' != ''">$(_CycloneDxMetadataContent)<![CDATA[ |
182 | | - <description>$([System.Security.SecurityElement::Escape('$(_CycloneDxDescription)'))]</description>]]></_CycloneDxMetadataContent> |
| 243 | + <_CycloneDxMetadataContent Condition="'$(_CycloneDxDescription)' != ''">$(_CycloneDxMetadataContent) <description>$(_CycloneDxDescriptionEscaped)</description></_CycloneDxMetadataContent> |
183 | 244 |
|
184 | 245 | <!-- Add authors/supplier if available --> |
185 | | - <_CycloneDxMetadataContent Condition="'$(_CycloneDxAuthors)' != ''">$(_CycloneDxMetadataContent)<![CDATA[ |
186 | | - <supplier> |
187 | | - <name>$([System.Security.SecurityElement::Escape('$(_CycloneDxAuthors)'))]</name> |
188 | | - </supplier>]]></_CycloneDxMetadataContent> |
| 246 | + <_CycloneDxMetadataContent Condition="'$(_CycloneDxAuthors)' != ''">$(_CycloneDxMetadataContent) |
| 247 | + <supplier> |
| 248 | + <name>$(_CycloneDxAuthorsEscaped)</name> |
| 249 | + </supplier></_CycloneDxMetadataContent> |
189 | 250 |
|
190 | 251 | <!-- Add copyright if available --> |
191 | | - <_CycloneDxMetadataContent Condition="'$(_CycloneDxCopyright)' != ''">$(_CycloneDxMetadataContent)<![CDATA[ |
192 | | - <copyright>$([System.Security.SecurityElement::Escape('$(_CycloneDxCopyright)'))]</copyright>]]></_CycloneDxMetadataContent> |
| 252 | + <_CycloneDxMetadataContent Condition="'$(_CycloneDxCopyright)' != ''">$(_CycloneDxMetadataContent) <copyright>$(_CycloneDxCopyrightEscaped)</copyright></_CycloneDxMetadataContent> |
193 | 253 |
|
194 | 254 | <!-- Add license if available --> |
195 | | - <_CycloneDxMetadataContent Condition="'$(_CycloneDxLicense)' != ''">$(_CycloneDxMetadataContent)<![CDATA[ |
196 | | - <licenses> |
197 | | - <license> |
198 | | - <id>$([System.Security.SecurityElement::Escape('$(_CycloneDxLicense)'))]</id> |
199 | | - </license> |
200 | | - </licenses>]]></_CycloneDxMetadataContent> |
201 | | - |
202 | | - <!-- Add purl --> |
203 | | - <_CycloneDxMetadataContent>$(_CycloneDxMetadataContent)<![CDATA[ |
204 | | - <purl>$([System.Security.SecurityElement::Escape('$(_CycloneDxPurl)'))]</purl> |
205 | | - </component> |
206 | | - </metadata> |
207 | | -</bom>]]></_CycloneDxMetadataContent> |
| 255 | + <_CycloneDxMetadataContent Condition="'$(_CycloneDxLicense)' != ''">$(_CycloneDxMetadataContent) |
| 256 | + <licenses> |
| 257 | + <license> |
| 258 | + <id>$(_CycloneDxLicenseEscaped)</id> |
| 259 | + </license> |
| 260 | + </licenses></_CycloneDxMetadataContent> |
| 261 | + |
| 262 | + <!-- Add purl and close tags --> |
| 263 | + <_CycloneDxMetadataContent>$(_CycloneDxMetadataContent) |
| 264 | + <purl>$(_CycloneDxPurlEscaped)</purl> |
| 265 | + </component> |
| 266 | + </metadata> |
| 267 | + </bom></_CycloneDxMetadataContent> |
208 | 268 | </PropertyGroup> |
209 | 269 |
|
210 | 270 | <!-- Write metadata to temporary file --> |
|
0 commit comments