Skip to content

Commit 1ffd985

Browse files
author
Andrew Nelson
committed
Fix release workflow permissions
1 parent d2f1de5 commit 1ffd985

File tree

7 files changed

+72
-32
lines changed

7 files changed

+72
-32
lines changed

src/main/java/com/qualys/plugins/scanner/QualysScanAction.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ public class QualysScanAction implements RunAction2 {
2323
private final boolean scanPassed;
2424
private final String reportPath;
2525

26-
// Detailed report data
2726
private ScanReportDetails reportDetails;
2827
private String imageName;
28+
private String evaluationMode;
2929

3030
private transient Run<?, ?> run;
3131

@@ -40,6 +40,7 @@ public QualysScanAction(int totalVulnerabilities, int criticalCount, int highCou
4040
this.policyResult = policyResult;
4141
this.scanPassed = scanPassed;
4242
this.reportPath = reportPath;
43+
this.evaluationMode = "threshold";
4344
}
4445

4546
@Override
@@ -58,7 +59,6 @@ public void onLoad(Run<?, ?> run) {
5859

5960
@Override
6061
public String getIconFileName() {
61-
// Use Jenkins built-in clipboard icon
6262
return "clipboard.png";
6363
}
6464

@@ -72,7 +72,6 @@ public String getUrlName() {
7272
return "qualys-scan";
7373
}
7474

75-
// Basic getters for Jelly view
7675
public int getTotalVulnerabilities() { return totalVulnerabilities; }
7776
public int getCriticalCount() { return criticalCount; }
7877
public int getHighCount() { return highCount; }
@@ -82,7 +81,6 @@ public String getUrlName() {
8281
public boolean isScanPassed() { return scanPassed; }
8382
public String getReportPath() { return reportPath; }
8483

85-
// Detailed report getters/setters
8684
public ScanReportDetails getReportDetails() { return reportDetails; }
8785
public void setReportDetails(ScanReportDetails reportDetails) {
8886
this.reportDetails = reportDetails;
@@ -91,7 +89,15 @@ public void setReportDetails(ScanReportDetails reportDetails) {
9189
public String getImageName() { return imageName; }
9290
public void setImageName(String imageName) { this.imageName = imageName; }
9391

94-
// Convenience methods for Jelly
92+
public String getEvaluationMode() { return evaluationMode; }
93+
public void setEvaluationMode(String evaluationMode) { this.evaluationMode = evaluationMode; }
94+
95+
public String getPolicyResultDisplay() {
96+
String result = scanPassed ? "PASS" : "FAIL";
97+
String mode = "policy".equals(evaluationMode) ? "Policy" : "Threshold";
98+
return result + " (" + mode + ")";
99+
}
100+
95101
public String getImageId() {
96102
return reportDetails != null ? reportDetails.getImageId() : null;
97103
}

src/main/java/com/qualys/plugins/scanner/QualysScannerBuilder.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,6 @@ private QScannerConfig buildConfig(QualysApiToken credentials, FilePath workspac
222222
.skipTlsVerify(skipTlsVerify)
223223
.outputDir(workspace.child("qualys-scan-results").getRemote());
224224

225-
// Expand environment variables
226225
if (imageId != null) {
227226
builder.imageId(env.expand(imageId));
228227
}
@@ -314,7 +313,7 @@ private void processResults(Run<?, ?> run, FilePath workspace, TaskListener list
314313
listener.getLogger().println("\nSecurity scan passed!");
315314
}
316315

317-
exportBuildVariables(run, result, listener);
316+
exportBuildVariables(run, result, listener, config);
318317
}
319318

320319
private void createJiraIssuesFromSarif(Run<?, ?> run, TaskListener listener, String sarifPath) {
@@ -363,7 +362,7 @@ private void createJiraIssuesFromSarif(Run<?, ?> run, TaskListener listener, Str
363362
}
364363
}
365364

366-
private void exportBuildVariables(Run<?, ?> run, QScannerResult result, TaskListener listener) {
365+
private void exportBuildVariables(Run<?, ?> run, QScannerResult result, TaskListener listener, QScannerConfig config) {
367366
VulnerabilitySummary summary = result.getVulnerabilitySummary();
368367

369368
QualysScanAction scanAction = new QualysScanAction(
@@ -377,14 +376,22 @@ private void exportBuildVariables(Run<?, ?> run, QScannerResult result, TaskList
377376
result.getSarifReportPath()
378377
);
379378

379+
if (config != null && config.isUsePolicyEvaluation()) {
380+
scanAction.setEvaluationMode("policy");
381+
} else {
382+
scanAction.setEvaluationMode("threshold");
383+
}
384+
380385
if (result.getSarifReportPath() != null) {
381386
try {
382387
FilePath sarifFile = new FilePath(new java.io.File(result.getSarifReportPath()));
383388
if (sarifFile.exists()) {
384389
ScanReportDetails details = SarifParser.parseDetailed(sarifFile);
385-
details.setImageName(imageId);
390+
if (details.getImageName() == null) {
391+
details.setImageName(imageId);
392+
}
386393
scanAction.setReportDetails(details);
387-
scanAction.setImageName(imageId);
394+
scanAction.setImageName(details.getImageName() != null ? details.getImageName() : imageId);
388395
}
389396
} catch (Exception e) {
390397
listener.getLogger().println("Warning: Could not parse detailed report: " + e.getMessage());
@@ -440,7 +447,6 @@ private void handleError(Run<?, ?> run, TaskListener listener, String message)
440447
public String getJiraLabels() { return jiraLabels; }
441448
public String getJiraAssignee() { return jiraAssignee; }
442449

443-
// Setters with @DataBoundSetter
444450
@DataBoundSetter
445451
public void setScannerBackend(String scannerBackend) { this.scannerBackend = scannerBackend; }
446452

src/main/java/com/qualys/plugins/scanner/issues/JiraIssueCreator.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,19 +198,16 @@ private void createIssue(VulnerabilityInfo info, List<String> labels, String ass
198198
issueType.addProperty("name", "Bug");
199199
fields.add("issuetype", issueType);
200200

201-
// Priority mapping
202201
JsonObject priority = new JsonObject();
203202
priority.addProperty("name", mapSeverityToPriority(info.severity));
204203
fields.add("priority", priority);
205204

206-
// Labels
207205
JsonArray labelsArray = new JsonArray();
208206
for (String label : allLabels) {
209207
labelsArray.add(label.replaceAll("[^a-zA-Z0-9_-]", "_"));
210208
}
211209
fields.add("labels", labelsArray);
212210

213-
// Assignee
214211
if (assignee != null && !assignee.isEmpty()) {
215212
JsonObject assigneeObj = new JsonObject();
216213
assigneeObj.addProperty("name", assignee);
@@ -219,7 +216,6 @@ private void createIssue(VulnerabilityInfo info, List<String> labels, String ass
219216

220217
issueData.add("fields", fields);
221218

222-
// Make API call
223219
HttpURLConnection conn = createConnection("/rest/api/2/issue");
224220
conn.setRequestMethod("POST");
225221
conn.setDoOutput(true);
@@ -243,7 +239,6 @@ private void createIssue(VulnerabilityInfo info, List<String> labels, String ass
243239
}
244240

245241
private boolean issueExists(String vulnTag) throws IOException {
246-
// Search for existing issue with the vulnerability tag
247242
String jql = String.format("project = %s AND description ~ \"%s\"", projectKey, vulnTag);
248243

249244
HttpURLConnection conn = createConnection("/rest/api/2/search?jql=" +
@@ -267,7 +262,6 @@ private HttpURLConnection createConnection(String path) throws IOException {
267262
conn.setRequestProperty("Content-Type", "application/json");
268263
conn.setRequestProperty("Accept", "application/json");
269264

270-
// Basic auth with API token
271265
String auth = jiraUsername + ":" + jiraApiToken;
272266
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
273267
conn.setRequestProperty("Authorization", "Basic " + encodedAuth);

src/main/java/com/qualys/plugins/scanner/pipeline/QualysScanStep.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ public class QualysScanStep extends Step implements Serializable {
4949
private final String credentialsId;
5050
private final String scanType;
5151

52-
// Optional parameters
5352
private String imageId;
5453
private String storageDriver;
5554
private String platform;
@@ -262,7 +261,6 @@ private QualysScanResult processResults(Run<?, ?> run, FilePath workspace,
262261
return pipelineResult;
263262
}
264263

265-
// Parse SARIF
266264
if (result.getSarifReportPath() != null) {
267265
try {
268266
FilePath sarifFile = new FilePath(workspace.getChannel(), result.getSarifReportPath());
@@ -279,7 +277,6 @@ private QualysScanResult processResults(Run<?, ?> run, FilePath workspace,
279277
}
280278
}
281279

282-
// Evaluate
283280
boolean shouldFail = false;
284281
String failureReason = null;
285282

@@ -309,7 +306,6 @@ private QualysScanResult processResults(Run<?, ?> run, FilePath workspace,
309306
pipelineResult.setJsonReportPath(result.getJsonReportPath());
310307
pipelineResult.setSbomPath(result.getSbomPath());
311308

312-
// Add build action with detailed report
313309
QualysScanAction scanAction = new QualysScanAction(
314310
pipelineResult.getTotalVulnerabilities(),
315311
pipelineResult.getCriticalCount(),
@@ -321,7 +317,12 @@ private QualysScanResult processResults(Run<?, ?> run, FilePath workspace,
321317
result.getSarifReportPath()
322318
);
323319

324-
// Parse detailed report from SARIF
320+
if (config.isUsePolicyEvaluation()) {
321+
scanAction.setEvaluationMode("policy");
322+
} else {
323+
scanAction.setEvaluationMode("threshold");
324+
}
325+
325326
if (result.getSarifReportPath() != null) {
326327
try {
327328
FilePath sarifFile = new FilePath(new java.io.File(result.getSarifReportPath()));

src/main/java/com/qualys/plugins/scanner/qscanner/SarifParser.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,27 @@ public static ScanReportDetails parseDetailed(String sarifFilePath) throws IOExc
122122
private static void extractTargetInfo(JsonObject run, ScanReportDetails details) {
123123
JsonObject runProps = getObjectOrNull(run, "properties");
124124
if (runProps != null) {
125-
details.setImageId(getStringOrNull(runProps, "imageId"));
125+
String imageId = getStringOrNull(runProps, "imageID");
126+
if (imageId == null) {
127+
imageId = getStringOrNull(runProps, "imageId");
128+
}
129+
details.setImageId(imageId);
126130
details.setImageDigest(getStringOrNull(runProps, "imageDigest"));
127131
details.setOperatingSystem(getStringOrNull(runProps, "os"));
128132
if (details.getOperatingSystem() == null) {
129133
details.setOperatingSystem(getStringOrNull(runProps, "operatingSystem"));
130134
}
131135
details.setImageName(getStringOrNull(runProps, "imageName"));
136+
137+
if (details.getImageName() == null) {
138+
JsonArray repoTags = getArrayOrNull(runProps, "repoTags");
139+
if (repoTags != null && !repoTags.isEmpty()) {
140+
JsonElement firstTag = repoTags.get(0);
141+
if (!firstTag.isJsonNull()) {
142+
details.setImageName(firstTag.getAsString());
143+
}
144+
}
145+
}
132146
}
133147

134148
JsonArray artifacts = getArrayOrNull(run, "artifacts");
@@ -143,7 +157,11 @@ private static void extractTargetInfo(JsonObject run, ScanReportDetails details)
143157
JsonObject artifactProps = getObjectOrNull(artifact, "properties");
144158
if (artifactProps != null) {
145159
if (details.getImageId() == null) {
146-
details.setImageId(getStringOrNull(artifactProps, "imageId"));
160+
String imgId = getStringOrNull(artifactProps, "imageID");
161+
if (imgId == null) {
162+
imgId = getStringOrNull(artifactProps, "imageId");
163+
}
164+
details.setImageId(imgId);
147165
}
148166
if (details.getImageDigest() == null) {
149167
details.setImageDigest(getStringOrNull(artifactProps, "repoDigest"));

src/main/java/com/qualys/plugins/scanner/types/QScannerConfig.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ public QScannerConfig build() {
227227
public String getOutputDir() { return outputDir; }
228228
public String getReportFormat() { return reportFormat; }
229229

230-
// Setters
231230
public void setPod(String pod) { this.pod = pod; }
232231
public void setAccessToken(String accessToken) { this.accessToken = accessToken; }
233232
public void setProxyUrl(String proxyUrl) { this.proxyUrl = proxyUrl; }

src/main/resources/com/qualys/plugins/scanner/QualysScanAction/index.jelly

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@
160160
</div>
161161
<div>
162162
<div class="qualys-info-row">
163-
<span class="qualys-info-label">Policy Result:</span>
164-
<span class="qualys-info-value">${it.policyResult != null ? it.policyResult : 'N/A'}</span>
163+
<span class="qualys-info-label">Evaluation:</span>
164+
<span class="qualys-info-value">${it.policyResultDisplay}</span>
165165
</div>
166166
<div class="qualys-info-row">
167167
<span class="qualys-info-label">Total Packages:</span>
@@ -217,6 +217,17 @@
217217
<div class="qualys-filter-controls">
218218
<div class="qualys-filter-row">
219219
<input type="text" id="vuln-search" placeholder="Search by title, package, CVE, or QID..." class="qualys-search-input" />
220+
<j:if test="${it.hasLayers()}">
221+
<div class="qualys-page-size">
222+
<label>Layer:</label>
223+
<select id="vuln-layer-filter">
224+
<option value="all">All Layers</option>
225+
<j:forEach var="layer" items="${it.layers}">
226+
<option value="${layer}">${layer.length() > 19 ? layer.substring(7, 19) : layer}</option>
227+
</j:forEach>
228+
</select>
229+
</div>
230+
</j:if>
220231
<div class="qualys-page-size">
221232
<label>Show:</label>
222233
<select id="vuln-page-size">
@@ -247,7 +258,7 @@
247258
</thead>
248259
<tbody id="vuln-tbody">
249260
<j:forEach var="vuln" items="${it.vulnerabilities}">
250-
<tr data-severity="${vuln.severityClass}">
261+
<tr data-severity="${vuln.severityClass}" data-layer="${vuln.layerSHA != null ? vuln.layerSHA : ''}">
251262
<td>
252263
<span class="qualys-badge ${vuln.severityClass}">${vuln.severity}</span>
253264
</td>
@@ -386,23 +397,26 @@
386397
function createTableFilter(config) {
387398
var search = document.getElementById(config.searchId);
388399
var pageSize = document.getElementById(config.pageSizeId);
400+
var layerFilter = document.getElementById(config.layerFilterId);
389401
var showing = document.getElementById(config.showingId);
390402
var tbody = document.getElementById(config.tbodyId);
391403
var table = document.getElementById(config.tableId);
392404
var noResults = document.getElementById(config.noResultsId);
393405
var countEl = document.getElementById(config.countId);
394406
if (!tbody) return null;
395407
var rows = Array.prototype.slice.call(tbody.querySelectorAll('tr'));
396-
var state = { search: '', severity: 'all', pageSize: 25 };
408+
var state = { search: '', severity: 'all', layer: 'all', pageSize: 25 };
397409

398410
function update() {
399411
var matched = [];
400412
rows.forEach(function(row) {
401413
var text = row.textContent.toLowerCase();
402414
var sev = row.getAttribute('data-severity');
415+
var layer = row.getAttribute('data-layer') || '';
403416
var matchSearch = state.search === '' || text.indexOf(state.search) !== -1;
404417
var matchSev = !config.hasSeverity || state.severity === 'all' || sev === state.severity;
405-
if (matchSearch &amp;&amp; matchSev) {
418+
var matchLayer = !config.hasLayer || state.layer === 'all' || layer === state.layer;
419+
if (matchSearch &amp;&amp; matchSev &amp;&amp; matchLayer) {
406420
matched.push(row);
407421
}
408422
});
@@ -420,20 +434,22 @@
420434

421435
if (search) search.addEventListener('input', function() { state.search = search.value.toLowerCase().trim(); update(); });
422436
if (pageSize) pageSize.addEventListener('change', function() { state.pageSize = pageSize.value; update(); });
437+
if (layerFilter) layerFilter.addEventListener('change', function() { state.layer = layerFilter.value; update(); });
423438
update();
424439
return { setState: function(key, val) { state[key] = val; update(); } };
425440
}
426441

427442
var vulnFilter = createTableFilter({
428443
searchId: 'vuln-search', pageSizeId: 'vuln-page-size', showingId: 'vuln-showing',
444+
layerFilterId: 'vuln-layer-filter',
429445
tbodyId: 'vuln-tbody', tableId: 'vuln-table', noResultsId: 'no-results',
430-
countId: 'vuln-count', hasSeverity: true
446+
countId: 'vuln-count', hasSeverity: true, hasLayer: true
431447
});
432448

433449
createTableFilter({
434450
searchId: 'pkg-search', pageSizeId: 'pkg-page-size', showingId: 'pkg-showing',
435451
tbodyId: 'pkg-tbody', tableId: 'pkg-table', noResultsId: 'pkg-no-results',
436-
countId: 'pkg-count', hasSeverity: false
452+
countId: 'pkg-count', hasSeverity: false, hasLayer: false
437453
});
438454

439455
var sevFilters = document.querySelectorAll('#severity-filters .qualys-severity');

0 commit comments

Comments
 (0)