-
Notifications
You must be signed in to change notification settings - Fork 41
/
Copy pathSAST-Migrate-Project.ps1
382 lines (286 loc) · 12.4 KB
/
SAST-Migrate-Project.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
<#
.SYNOPSIS
Used to migrate project configurations from one instance of CxSAST to a new instance of CxSAST.
.DESCRIPTION
This is intended to be used to migrate projects that are configured with a "Local" source location. Given the scope
of this script, the following limitations apply:
* Location data is not migrated (migrated projects default to "Local" source location)
* Scheduling configurations are not migrated (it is not possible to schedule scans for "Local" source location)
* Issue tracking settings are not migrated
* Post scan actions are not migrated
* OSA settings are not migrated
* Policy settings are not migrated
* Data retention settings are not migrated
* Preset selections are migrated, but there is no verification that the presets between the two systems are equivalent
* The user accounts can not be SSO accounts since there is no interactive login component for the API
Example 1 shows migrating projects from an 8.9 instance to a 9.x instance. Note the team path separator changed between 8.9 and 9.x.
Example 2 shows migrating projects between 9.x instances.
.PARAMETER old_sast_url
The URL to the old CxSAST instance where the project is currently defined.
.PARAMETER new_sast_url
The URL to the new CxSAST instance where the migrated project will be created.
.PARAMETER old_sast_username
The name of the user in the old CxSAST system that will be used to read the migrating project definition.
.PARAMETER new_sast_username
The name of the user in the new CxSAST system that will be used to create the new project definition.
.PARAMETER old_sast_password
The password for the user in the old CxSAST system.
.PARAMETER new_sast_password
The password for the user in the new CxSAST system.
.PARAMETER old_sast_team_path
The team path in the old system where the project to be migrated is assigned.
.PARAMETER new_sast_team_path
The team path in the new system where the migrated project definition will be created.
.PARAMETER project_name
The name of the project to migrate from the old system to the new system.
.PARAMETER new_preset_name
(Optional) The preset definition to use in the new system. If not provided, the chosen preset definition of the original project is used
if it exists in the new system. If there is a mismatch in the name of the preset for the preset id used in the old system,
the script will end in error.
.PARAMETER new_engine_config_name
(Optional) The engine configuration to use in the new system. If not provided, the engine configuration of the original project is used
if it exists in the new system. If there is a mismatch in the engine configuration name, the script will end in error.
.PARAMETER dbg
(Optional Flag) Runs in debug mode and prints verbose information to the screen while processing.
.INPUTS
None
.OUTPUTS
None
.EXAMPLE
.\SAST-Migrate-Project.ps1 `
-old_sast_url http://sast89.company.com `
-old_sast_username ... `
-old_sast_password ... `
-new_sast_url http://sast9x.company.com `
-new_sast_username ... `
-new_sast_password ... `
-old_sast_team_path "\CxServer\SP\Company\Users" `
-new_sast_team_path /CxServer/ThisIsASubTeam `
-project_name "My Project"
.EXAMPLE
.\SAST-Migrate-Project.ps1 `
-old_sast_url http://old.system.company.com `
-old_sast_username ... `
-old_sast_password ... `
-new_sast_url http://new.system.company.com `
-new_sast_username ... `
-new_sast_password ... `
-old_sast_team_path "/CxServer/MyTeam" `
-new_sast_team_path /CxServer/Organization/MyTeam `
-project_name "My Project"
#>
param(
[Parameter(Mandatory = $true)]
[System.Uri]$old_sast_url,
[Parameter(Mandatory = $true)]
[System.Uri]$new_sast_url,
[Parameter(Mandatory = $true)]
[String]$old_sast_username,
[Parameter(Mandatory = $true)]
[String]$new_sast_username,
[Parameter(Mandatory = $true)]
[String]$old_sast_password,
[Parameter(Mandatory = $true)]
[String]$new_sast_password,
[Parameter(Mandatory = $true)]
[String]$old_sast_team_path,
[Parameter(Mandatory = $true)]
[String]$new_sast_team_path,
[Parameter(Mandatory = $true)]
[String]$project_name,
[String]$new_preset_name,
[String]$new_engine_config_name,
[Switch]$dbg
)
. "$PSScriptRoot/support/debug.ps1"
setupDebug($dbg.IsPresent)
function GetTeamId
{
param($team_path, $team_json)
$result = $null
$team_json | % {
if ($_.fullName.CompareTo($team_path) -eq 0) {
$result = $_.id
Write-Debug "Matched: $result"
return $result
}
elseif ($dbg.IsPresent) {
Write-Debug "$($_.fullName) != $team_path"
}
}
}
Write-Output "Logging in as $old_sast_username to $old_sast_url"
$old_session = &"$PSScriptRoot/support/rest/sast/login.ps1" $old_sast_url $old_sast_username $old_sast_password -dbg:$dbg.IsPresent
Write-Output "Logging in as $new_sast_username to $new_sast_url"
$new_session = &"$PSScriptRoot/support/rest/sast/login.ps1" $new_sast_url $new_sast_username $new_sast_password -dbg:$dbg.IsPresent
$timer = $(Get-Date)
Write-Output "Fetching teams from $old_sast_url"
$teams = &"$PSScriptRoot/support/rest/sast/teams.ps1" $old_session
Write-Output "$($teams.Length) teams fetched - elapsed time $($(Get-Date).Subtract($timer))"
$old_team_id = GetTeamId $old_sast_team_path $teams
if ($null -eq $old_team_id) {
throw "The old project team could not be found."
}
else {
Write-Output "Old team id: $old_team_id"
}
$timer = $(Get-Date)
Write-Output "Fetching teams from $new_sast_url"
$teams = &"$PSScriptRoot/support/rest/sast/teams.ps1" $new_session
Write-Output "$($teams.Length) teams fetched - elapsed time $($(Get-Date).Subtract($timer))"
$new_team_id = GetTeamId $new_sast_team_path $teams
if ($null -eq $new_team_id) {
throw "The new project team could not be found."
}
else {
Write-Output "New team id: $new_team_id"
}
$timer = $(Get-Date)
Write-Output "Fetching projects from $old_sast_url"
$project_list = &"$PSScriptRoot/support/rest/sast/projects.ps1" $old_session
Write-Output "$($project_list.Length) projects fetched - elapsed time $($(Get-Date).Subtract($timer))"
$old_project = $null
$project_list | %{
if ($_.teamId.CompareTo($old_team_id) -eq 0) {
if ($_.name.CompareTo($project_name) -eq 0) {
$old_project = $_
return
}
}
}
if ($null -eq $old_project) {
throw "The project to migrate could not be found."
}
$old_scan_settings = $null
$old_project.links | %{
if ($_.rel.CompareTo("scansettings") -eq 0)
{
$old_scan_settings = &"$PSScriptRoot/support/rest/sast/scanSettings" $old_session $_.uri
}
}
if ($null -eq $old_scan_settings) {
throw "Could not retreive scan settings for $($old_project.name)"
}
function GetConfigIdFromList{
param ($script_path,$pname,$new_name,$old_id)
if ([String]::IsNullOrEmpty($new_name) -ne $true) {
Write-Debug "New $pname name $new_name specified"
# Find config in new system by name
$list = &"$script_path" $new_session
$found = $null
$list | %{
if ($_.name.CompareTo($new_name) -eq 0) {
$found = $_.id
return
}
}
if ($found -eq $null) {
throw "Unable to find a $pname named $new_name at $new_sast_url"
}
else {
Write-Debug "New $pname name $new_name found with id: $found"
return $found
}
}
else {
# Using config id, check the names between new and old system are the same
Write-Debug "Attempting to use existing $pname"
$old_list = &$script_path $old_session
$new_list = &$script_path $new_session
$old_name = $null
$old_list | %{
if ($_.id -eq $old_id) {
$old_name = $_.name
return
}
}
if ($old_name -eq $null) {
throw "Unable to find the name of the $pname id $old_id at $old_sast_url"
}
Write-Debug "Existing project $pname $($old_id):$old_name"
$result = $null
$new_list | %{
if ($_.id -eq $old_id) {
if ($_.name.CompareTo($old_name) -eq 0) {
Write-Debug "Matched existing $pname in the new system"
$result = $_.id
return
}
else {
throw "Old preset $($old_id):$old_name does not match preset $($_.id):$($_.name)."
}
}
}
if ($result -eq $null) {
throw "Could not find a $pname matching $($old_id):$old_name in $new_sast_url"
}
return $result
}
}
$new_preset = GetConfigIdFromList "$PSScriptRoot/support/rest/sast/presets.ps1" "preset" $new_preset_name $old_scan_settings.preset.id
$new_engine_config = GetConfigIdFromList "$PSScriptRoot/support/rest/sast/engineConfigurations.ps1" "engine config" $new_engine_config_name `
$old_scan_settings.engineConfiguration.id
# Validate custom fields
$old_project_config = &"$PSScriptRoot/support/rest/sast/projects.ps1" $old_session $old_scan_settings.project.id
$custom_fields_to_update = New-Object 'System.Collections.Generic.List[PSCustomObject]'
if ($old_project_config.customFields.length -ne 0) {
Write-Debug "Found $($old_project_config.customFields.length) custom fields defined in the old project"
$old_fields_dict = New-Object 'System.Collections.Generic.Dictionary[String, PSCustomObject]'
$old_project_config.customFields | %{
$old_fields_dict.Add($_.name, $_)
}
$new_system_fields = &"$PSScriptRoot/support/rest/sast/customFields.ps1" $new_session
$new_system_fields_map = New-Object 'System.Collections.Generic.Dictionary[String, PSCustomObject]'
$new_system_fields | %{
$new_system_fields_map.Add($_.name, $_)
}
$old_fields_dict.Keys | %{
if ($new_system_fields_map.ContainsKey($_) -ne $true)
{
throw "Custom field $_ is not defined in $new_sast_url"
}
else {
$custom_fields_to_update.Add(@{
id = $new_system_fields_map[$_].id
value = $old_fields_dict[$_].value
})
}
}
}
$timer = $(Get-Date)
Write-Output "Fetching projects from $new_sast_url"
$project_list = &"$PSScriptRoot/support/rest/sast/projects.ps1" $new_session
Write-Output "$($project_list.Length) projects fetched - elapsed time $($(Get-Date).Subtract($timer))"
$new_project = $null
$project_list | %{
if ($_.teamId.CompareTo($new_team_id) -eq 0) {
if ($_.name.CompareTo($project_name) -eq 0) {
$new_project = $_
return
}
}
}
if ($null -eq $new_project) {
# Create the new project with default settings
Write-Output "$project_name does not exist in team $new_sast_team_path on $new_sast_url, creating."
$new_project = &"$PSScriptRoot/support/rest/sast/create/projects.ps1" $new_session $project_name $new_team_id
}
Write-Output "New project id: $($new_project.id)"
&"$PSScriptRoot/support/rest/sast/update/scanSettings.ps1" $new_session $new_project.id $new_preset $new_engine_config `
$old_scan_settings.emailNotifications.failedScan `
$old_scan_settings.emailNotifications.beforeScan `
$old_scan_settings.emailNotifications.afterScan | Out-Null
if ($custom_fields_to_update.Count -ne 0) {
$update_payload = [ordered]@{
name = $project_name
owningTeam = $new_team_id
customFields = $custom_fields_to_update
}
&"$PSScriptRoot/support/rest/sast/update/projects.ps1" $new_session $new_project.id $update_payload
}
$old_exclude_settings = &"$PSScriptRoot/support/rest/sast/excludeSettings.ps1" $old_session $old_scan_settings.project.id
&"$PSScriptRoot/support/rest/sast/update/excludeSettings.ps1" $new_session $new_project.id `
@{
excludeFoldersPattern = $old_exclude_settings.excludeFoldersPattern
excludeFilesPattern = $old_exclude_settings.excludeFilesPattern
} | Out-Null