Skip to content
Merged
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
7 changes: 6 additions & 1 deletion documentation/src/main/markdown/currentreleasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@
* Support for pnpm now extends to 10.32.1.
* npm detectors now allow for aliases to be used when specifying dependencies in the package.json file.
* Ivy CLI Detector, leveraging the `ivy:dependencytree` Ant task to extract direct and transitive dependencies for Ant + Ivy projects. For further information, see [Ivy (Ant) support](packagemgrs/ivy.md).
* Introduced the `detect.quack.patch.output property` to control the Quack Patch output information path. If not set, the current working directory will be used as the default.
* When [detect_product_short] is integrated with [bd_product_long] version 2026.4 or later, relevant [bd_product_short] server configuration details will be retrieved for use by [detect_product_short]. With this release of [detect_product_short], the [bd_product_short] server administrator can choose to set the detect.blackduck.correlated.scanning.enabled property, which will be retrieved and used if the user has not specified this property locally.
* In future releases the retrieval of additional [bd_product_short] server properties will be supported.
* In future releases the retrieval of additional [bd_product_short] server properties will be supported.

### Changed features

* The default output directory of the Quack Patch feature has been updated to use a quack-patch subdirectory of the present working directory.

### Resolved issues

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.blackduck.integration.detect.configuration;

import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;

import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
Expand All @@ -21,7 +21,6 @@
import com.blackduck.integration.blackduck.codelocation.signaturescanner.command.SnippetMatching;
import com.blackduck.integration.configuration.property.Properties;
import com.blackduck.integration.configuration.property.Property;
import com.blackduck.integration.configuration.util.ProductMajorVersion;
import com.blackduck.integration.configuration.property.base.PassthroughProperty;
import com.blackduck.integration.configuration.property.base.TypedProperty;
import com.blackduck.integration.configuration.property.types.bool.BooleanProperty;
Expand All @@ -44,6 +43,7 @@
import com.blackduck.integration.configuration.property.types.string.NullableStringProperty;
import com.blackduck.integration.configuration.property.types.string.StringListProperty;
import com.blackduck.integration.configuration.property.types.string.StringProperty;
import com.blackduck.integration.configuration.util.ProductMajorVersion;
import com.blackduck.integration.detect.configuration.enumeration.BlackduckScanMode;
import com.blackduck.integration.detect.configuration.enumeration.DetectCategory;
import com.blackduck.integration.detect.configuration.enumeration.DetectGroup;
Expand All @@ -53,8 +53,8 @@
import com.blackduck.integration.detect.tool.signaturescanner.enums.ExtendedIndividualFileMatchingMode;
import com.blackduck.integration.detect.tool.signaturescanner.enums.ExtendedReducedPersistanceMode;
import com.blackduck.integration.detect.tool.signaturescanner.enums.ExtendedSnippetMode;
import com.blackduck.integration.detectable.detectables.bazel.WorkspaceRule;
import com.blackduck.integration.detectable.detectables.bazel.DependencySource;
import com.blackduck.integration.detectable.detectables.bazel.WorkspaceRule;
import com.blackduck.integration.detectable.detectables.bitbake.BitbakeDependencyType;
import com.blackduck.integration.detectable.detectables.cargo.CargoDependencyType;
import com.blackduck.integration.detectable.detectables.conan.cli.config.ConanDependencyType;
Expand Down Expand Up @@ -1146,6 +1146,16 @@ private DetectProperties() {
"Only supported for Rapid and Stateless Scan modes. detect.llm.api.key, detect.llm.api.endpoint, and detect.llm.name must also be set. See <xref href=\"https://documentation%2Eblackduck%2Ecom/bundle/detect/page/runningdetect/quack%2Dpatch%2Ehtml\" scope=\"external\" outputclass=\"external\" format=\"html\" target=\"_blank\">Quack Patch</xref> for further details.")
.setGroups(DetectGroup.QUACKPATCH)
.build();

public static final StringProperty DETECT_QUACK_PATCH_OUTPUT =
StringProperty.newBuilder("detect.quack.patch.output", Path.of("").toAbsolutePath().toString())
.setInfo("Quack Patch Output Directory", DetectPropertyFromVersion.VERSION_11_4_0)
.setHelp(
"Specifies the output directory for Quack Patch results.",
"If not set, the Quack Patch results are placed in a 'quack-patch' subdirectory of the present working directory."
)
.setGroups(DetectGroup.QUACKPATCH)
.build();

public static final StringProperty DETECT_LLM_API_KEY =
StringProperty.newBuilder("detect.llm.api.key", "")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.blackduck.integration.detect.configuration.validation;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -17,6 +19,7 @@
import com.blackduck.integration.configuration.property.base.TypedProperty;
import com.blackduck.integration.configuration.property.deprecation.DeprecatedValueUsage;
import com.blackduck.integration.detect.configuration.DetectProperties;
import com.blackduck.integration.detect.configuration.DetectPropertyConfiguration;
import com.blackduck.integration.detect.configuration.DetectUserFriendlyException;
import com.blackduck.integration.detect.configuration.enumeration.ExitCodeType;
import com.blackduck.integration.detect.workflow.event.EventSystem;
Expand Down Expand Up @@ -102,4 +105,48 @@ public Optional<DetectUserFriendlyException> validateForPropertyParseErrors() th
}
return Optional.empty();
}

// Method to validate Quack Patch output path and return an Optional containing a DetectUserFriendlyException if the validation fails, or an empty Optional if it passes.
public Optional<DetectUserFriendlyException> validateQuackPatchOutputPath(DetectPropertyConfiguration detectConfiguration) {
String quackPatchOutput = detectConfiguration.getValue(DetectProperties.DETECT_QUACK_PATCH_OUTPUT).trim();

// Fail for empty string since that would cause issues later on when we try to write to it, and it's likely the user just forgot to set it if they enabled Quack Patch but left this blank.
if (quackPatchOutput.isEmpty()) {
return Optional.of(new DetectUserFriendlyException(
"Invalid value for Quack Patch output path: " + quackPatchOutput,
ExitCodeType.FAILURE_CONFIGURATION
));
}
// Validate the path exists and is a directory
Path path = Path.of(quackPatchOutput);

if (!Files.exists(path)) {
// create the directory if it doesn't exist, since that would cause issues later on when we try to write to it, and it's likely the user just forgot to create it if they enabled Quack Patch and set a path that doesn't exist.
try {
logger.debug("Creating quack patch output path: {}", quackPatchOutput);
Files.createDirectories(path);
} catch (Exception e) {
return Optional.of(new DetectUserFriendlyException(
"Quack Patch output path does not exist and could not be created: " + quackPatchOutput,
ExitCodeType.FAILURE_CONFIGURATION
));
}
}

if (!Files.isDirectory(path)) {
return Optional.of(new DetectUserFriendlyException(
"Quack Patch output path is not a directory: " + quackPatchOutput,
ExitCodeType.FAILURE_CONFIGURATION
));
}

if (!Files.isWritable(path)) {
return Optional.of(new DetectUserFriendlyException(
"Quack Patch output path is not writable: " + quackPatchOutput,
ExitCodeType.FAILURE_CONFIGURATION
));
}

return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,24 @@
import java.io.PrintStream;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Collections;
import java.util.LinkedHashMap;

import com.blackduck.integration.configuration.config.MaskedRawValueResult;
import com.blackduck.integration.configuration.property.base.TypedProperty;
import com.blackduck.integration.configuration.property.types.enumallnone.list.AllEnumList;
import com.blackduck.integration.configuration.property.types.path.PathValue;
import com.blackduck.integration.detect.configuration.connection.BlackDuckConnectionDetails;
import com.blackduck.integration.detect.configuration.help.yaml.HelpYamlWriter;
import com.blackduck.integration.detect.workflow.status.DetectIssue;
import com.blackduck.integration.detect.workflow.status.DetectIssueType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.blackduck.integration.configuration.config.MaskedRawValueResult;
import com.blackduck.integration.configuration.config.PropertyConfiguration;
import com.blackduck.integration.configuration.property.base.TypedProperty;
import com.blackduck.integration.configuration.property.types.enumallnone.list.AllEnumList;
import com.blackduck.integration.configuration.property.types.path.PathValue;
import com.blackduck.integration.configuration.property.types.path.SimplePathResolver;
import com.blackduck.integration.configuration.source.MapPropertySource;
import com.blackduck.integration.configuration.source.PropertySource;
Expand All @@ -36,6 +32,7 @@
import com.blackduck.integration.detect.configuration.DetectPropertyUtil;
import com.blackduck.integration.detect.configuration.DetectUserFriendlyException;
import com.blackduck.integration.detect.configuration.DetectableOptionFactory;
import com.blackduck.integration.detect.configuration.connection.BlackDuckConnectionDetails;
import com.blackduck.integration.detect.configuration.enumeration.BlackduckScanMode;
import com.blackduck.integration.detect.configuration.enumeration.DetectGroup;
import com.blackduck.integration.detect.configuration.enumeration.DetectTargetType;
Expand All @@ -44,6 +41,7 @@
import com.blackduck.integration.detect.configuration.help.DetectArgumentState;
import com.blackduck.integration.detect.configuration.help.json.HelpJsonManager;
import com.blackduck.integration.detect.configuration.help.print.HelpPrinter;
import com.blackduck.integration.detect.configuration.help.yaml.HelpYamlWriter;
import com.blackduck.integration.detect.configuration.validation.DeprecationResult;
import com.blackduck.integration.detect.configuration.validation.DetectConfigurationBootManager;
import com.blackduck.integration.detect.interactive.InteractiveManager;
Expand All @@ -55,22 +53,24 @@
import com.blackduck.integration.detect.lifecycle.boot.product.ProductBoot;
import com.blackduck.integration.detect.lifecycle.run.data.ProductRunData;
import com.blackduck.integration.detect.lifecycle.run.singleton.BootSingletons;
import com.blackduck.integration.detect.workflow.blackduck.settings.DetectPropertiesSetting;
import com.blackduck.integration.detect.tool.cache.InstalledToolLocator;
import com.blackduck.integration.detect.tool.cache.InstalledToolManager;
import com.blackduck.integration.detect.util.filter.DetectToolFilter;
import com.blackduck.integration.detect.workflow.airgap.AirGapCreator;
import com.blackduck.integration.detect.workflow.airgap.AirGapType;
import com.blackduck.integration.detect.workflow.airgap.AirGapTypeDecider;
import com.blackduck.integration.detect.workflow.blackduck.settings.DetectPropertiesSetting;
import com.blackduck.integration.detect.workflow.diagnostic.DiagnosticDecision;
import com.blackduck.integration.detect.workflow.diagnostic.DiagnosticSystem;
import com.blackduck.integration.detect.workflow.event.Event;
import com.blackduck.integration.detect.workflow.event.EventSystem;
import com.blackduck.integration.detect.workflow.file.DirectoryManager;
import com.blackduck.integration.detect.workflow.status.DetectIssue;
import com.blackduck.integration.detect.workflow.status.DetectIssueType;
import com.blackduck.integration.rest.proxy.ProxyInfo;
import com.google.gson.Gson;

import freemarker.template.Configuration;
import java.util.Set;

public class DetectBoot {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
Expand Down Expand Up @@ -161,6 +161,11 @@ public Optional<DetectBootResult> boot(String detectVersion, String detectBuildD

Configuration freemarkerConfiguration = detectBootFactory.createFreemarkerConfiguration();
DetectPropertyConfiguration detectConfiguration = new DetectPropertyConfiguration(propertyConfiguration, new SimplePathResolver());
// If quack patch is enabled, we need to validate the output path before doing anything else since it could cause Detect to fail later on if it's not valid, and we want to fail as early as possible with a clear message about what the issue is.
Optional<DetectUserFriendlyException> quackPatchError = detectConfigurationBootManager.validateQuackPatchOutputPath(detectConfiguration);
if (quackPatchError.isPresent()) {
return Optional.of(DetectBootResult.exception(quackPatchError.get(), propertyConfiguration));
}

DetectConfigurationFactory detectConfigurationFactory = new DetectConfigurationFactory(detectConfiguration, gson);

Expand Down
Loading