Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ according to your preferences.
After the analysis finishes, you can view any recommendations and remediation by clicking the _More actions..._ menu
from the highlighted image name.
Any recommendations for an alternative image does not replace the current image.
By clicking _Switch to..._, you go to Red Hat's Ecosystem Catalog for the recommended image.

<br >You must have the [`syft`](https://github.com/anchore/syft#installation)
and [`skopeo`](https://www.redhat.com/en/topics/containers/what-is-skopeo) binaries installed on your workstation to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class DockerfileAnnotator extends ExternalAnnotator<DockerfileAnnotator.Info, Map<BaseImage, DockerfileAnnotator.Result>> {

Expand Down Expand Up @@ -117,7 +115,7 @@ private static boolean hasProviderRecommendations(ProviderReport provider) {
.orElse(false);
}

static String generateMessage(String image, AnalysisReport report, String recommendation,
static String generateMessage(String image, AnalysisReport report,
List<String> hardenedRecommendations) {
var messageBuilder = new StringBuilder(image);

Expand Down Expand Up @@ -155,21 +153,16 @@ static String generateMessage(String image, AnalysisReport report, String recomm
}
}));

if (recommendation != null) {
messageBuilder.append(System.lineSeparator())
.append("Replace your image with RedHat UBI: ")
.append(recommendation);
}
if (hardenedRecommendations != null && !hardenedRecommendations.isEmpty()) {
messageBuilder.append(System.lineSeparator())
.append("Red Hat Hardened Image available: ")
.append("Recommended image: ")
.append(String.join(", ", hardenedRecommendations));
}

return messageBuilder.toString();
}

static String generateTooltip(String image, AnalysisReport report, String recommendation,
static String generateTooltip(String image, AnalysisReport report,
List<String> hardenedRecommendations) {
var tooltipBuilder = new StringBuilder("<html>").append("<p>").append(image).append("</p>");

Expand Down Expand Up @@ -211,15 +204,9 @@ static String generateTooltip(String image, AnalysisReport report, String recomm
}
}));

if (recommendation != null) {
tooltipBuilder.append("<p/>")
.append("<p>Replace your image with RedHat UBI: ")
.append(recommendation)
.append("</p>");
}
if (hardenedRecommendations != null && !hardenedRecommendations.isEmpty()) {
tooltipBuilder.append("<p/>")
.append("<p>Red Hat Hardened Image available: ")
.append("<p>Recommended image: ")
.append(String.join(", ", hardenedRecommendations))
.append("</p>");
}
Expand All @@ -245,23 +232,6 @@ static boolean hasIssue(AnalysisReport report) {
.orElse(false);
}

/** Returns the UBI image recommendation (from source-level dependencies), or null if none. */
static String getRecommendation(AnalysisReport report, ImageRef imageRef) {
var deps = Optional.ofNullable(report.getProviders())
.stream()
.flatMap(provider -> provider.values().stream())
.filter(Objects::nonNull)
.map(ProviderReport::getSources)
.filter(Objects::nonNull)
.map(Map::values)
.flatMap(Collection::stream)
.filter(Objects::nonNull)
.map(Source::getDependencies)
.filter(Objects::nonNull)
.flatMap(Collection::stream);
return findMatchingRecommendation(deps, imageRef, DependencyReport::getRef, DependencyReport::getRecommendation);
}

/**
* Returns hardened image references from provider-level recommendations matching the given image.
* Each entry is a displayable image reference suitable for Dockerfile FROM line replacement.
Expand Down Expand Up @@ -296,26 +266,6 @@ static List<String> getHardenedRecommendations(AnalysisReport report, ImageRef i
.collect(Collectors.toList());
}

private static <T> String findMatchingRecommendation(Stream<T> items, ImageRef imageRef,
Function<T, PackageRef> refExtractor,
Function<T, PackageRef> recommendationExtractor) {
return items
.filter(r -> refExtractor.apply(r) != null)
.filter(r -> {
try {
return imageRef.getPackageURL().equals(refExtractor.apply(r).purl());
} catch (MalformedPackageURLException e) {
LOG.warn("Skipping recommendation with malformed PURL", e);
return false;
}
})
.map(recommendationExtractor)
.filter(Objects::nonNull)
.findAny()
.map(DockerfileAnnotator::toImageName)
.orElse(null);
}

private static String toImageName(io.github.guacsec.trustifyda.api.PackageRef ref) {
try {
var purl = ref.purl();
Expand Down Expand Up @@ -352,13 +302,12 @@ private static String fullyDecode(String value) {
}

@NotNull
private static HighlightSeverity getHighlightSeverity(AnalysisReport report, String recommendation,
private static HighlightSeverity getHighlightSeverity(AnalysisReport report,
List<String> hardenedRecommendations, boolean hasIssue,
@NotNull PsiElement context) {
// Recommendation-only (no vulnerabilities): use INFORMATION severity (blue)
if (!hasIssue) {
boolean hasAnyRecommendation = recommendation != null
|| (hardenedRecommendations != null && !hardenedRecommendations.isEmpty());
boolean hasAnyRecommendation = hardenedRecommendations != null && !hardenedRecommendations.isEmpty();
if (hasAnyRecommendation) {
return HighlightSeverity.INFORMATION;
}
Expand All @@ -375,10 +324,7 @@ private static HighlightSeverity getHighlightSeverity(AnalysisReport report, Str
}
}

// Fallback to original logic if inspection settings can't be determined
return hasIssue || recommendation == null ?
HighlightSeverity.ERROR :
HighlightSeverity.WEAK_WARNING;
return HighlightSeverity.ERROR;
}

@Override
Expand Down Expand Up @@ -461,18 +407,16 @@ public void apply(@NotNull PsiFile file, Map<BaseImage, Result> annotationResult
if (isReportAvailable(report)) {
var hasIssue = hasIssue(report);
boolean recommendationsEnabled = ApiSettingsState.getInstance().recommendationsEnabled;
var recommendation = recommendationsEnabled
? getRecommendation(report, value.getImageRef()) : null;
var hardenedRecommendations = recommendationsEnabled
? getHardenedRecommendations(report, value.getImageRef()) : List.<String>of();

var message = generateMessage(key.getImageName(), report,
recommendation, hardenedRecommendations);
hardenedRecommendations);
var tooltip = generateTooltip(key.getImageName(), report,
recommendation, hardenedRecommendations);
hardenedRecommendations);

elements.forEach(e -> {
var severity = getHighlightSeverity(report, recommendation,
var severity = getHighlightSeverity(report,
hardenedRecommendations, hasIssue, e);
if (e != null) {
var builder = holder
Expand All @@ -486,7 +430,6 @@ public void apply(@NotNull PsiFile file, Map<BaseImage, Result> annotationResult
builder = builder.enforcedTextAttributes(attrs);
}
builder = builder.withFix(new ImageReportIntentionAction());
builder = builder.withFix(new UBIIntentionAction());
for (String hardenedImage : hardenedRecommendations) {
builder = builder.withFix(
new HardenedImageIntentionAction(hardenedImage));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

/**
* Intention action that replaces a Dockerfile FROM line's image reference
* with a recommended Red Hat Hardened Image.
* with a recommended image.
*/
public class HardenedImageIntentionAction implements IntentionAction {

Expand All @@ -41,7 +41,7 @@ public HardenedImageIntentionAction(String imageReference) {

@Override
public @IntentionName @NotNull String getText() {
return "Replace with Red Hat Hardened Image: " + imageReference;
return "Switch to " + imageReference + " for enhanced security";
}

@Override
Expand Down

This file was deleted.

1 change: 0 additions & 1 deletion src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@
<br>After the analysis finishes, you can view any recommendations and remediation by clicking the <i>More
actions...</i> menu from the highlighted image name.
<br>Any recommendations for an alternative image does not replace the current image.
<br>By clicking <i>Switch to...</i>, you go to Red Hat's Ecosystem Catalog for the recommended image.
<br>
<br>You must have the <a href="https://github.com/anchore/syft#installation"
rel="noopener noreferrer" target="_blank">syft</a> and <a href="https://www.redhat.com/en/topics/containers/what-is-skopeo"
Expand Down
Loading
Loading