diff --git a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/output/writer/record/table/TableRecordWriter.java b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/output/writer/record/table/TableRecordWriter.java index 6c958aab2e..1c03f1ff0a 100644 --- a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/output/writer/record/table/TableRecordWriter.java +++ b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/output/writer/record/table/TableRecordWriter.java @@ -68,7 +68,11 @@ private String getTable(String[] fields, String[][] data) { private String getHeader(String fieldName) { String header = getConfig().getMessageResolver().getMessageString("output.header."+fieldName); - return header!=null ? header : PropertyPathFormatter.humanReadable(fieldName); + return header!=null ? header : PropertyPathFormatter.humanReadable(getNormalizedFieldName(fieldName)); + } + + private String getNormalizedFieldName(String fieldName) { + return fieldName.replaceAll("String$", ""); } private String[] getFields(ObjectNode firstObjectNode) { diff --git a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/cli/cmd/AbstractToolInstallCommand.java b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/cli/cmd/AbstractToolInstallCommand.java index acbb57f75a..78e081b53e 100644 --- a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/cli/cmd/AbstractToolInstallCommand.java +++ b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/cli/cmd/AbstractToolInstallCommand.java @@ -30,11 +30,9 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.fortify.cli.common.cli.mixin.CommonOptionMixins; import com.fortify.cli.common.cli.util.CommandGroup; -import com.fortify.cli.common.http.proxy.helper.ProxyHelper; import com.fortify.cli.common.output.cli.cmd.AbstractOutputCommand; import com.fortify.cli.common.output.cli.cmd.IJsonNodeSupplier; import com.fortify.cli.common.output.transform.IActionCommandResultSupplier; -import com.fortify.cli.common.rest.unirest.GenericUnirestFactory; import com.fortify.cli.common.util.FileUtils; import com.fortify.cli.common.util.StringUtils; import com.fortify.cli.tool._common.helper.OsAndArchHelper; @@ -45,7 +43,6 @@ import com.fortify.cli.tool._common.helper.ToolInstallationDescriptor; import com.fortify.cli.tool._common.helper.ToolOutputDescriptor; -import kong.unirest.UnirestInstance; import lombok.SneakyThrows; import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; @@ -205,16 +202,10 @@ private static final void warnIfDifferentInstallPath(ToolInstallationDescriptor private static final File download(ToolDefinitionArtifactDescriptor artifactDescriptor) throws IOException { File tempDownloadFile = File.createTempFile("fcli-tool-download", null); tempDownloadFile.deleteOnExit(); - download(artifactDescriptor.getDownloadUrl(), tempDownloadFile); + ToolHelper.download(artifactDescriptor.getDownloadUrl(), tempDownloadFile); return tempDownloadFile; } - private static final void download(String downloadUrl, File destFile) { - UnirestInstance unirest = GenericUnirestFactory.getUnirestInstance("tool", - u->ProxyHelper.configureProxy(u, "tool", downloadUrl)); - unirest.get(downloadUrl).asFile(destFile.getAbsolutePath(), StandardCopyOption.REPLACE_EXISTING).getBody(); - } - private static final void updateBinPermissions(Path binPath) throws IOException { try (Stream walk = Files.walk(binPath)) { walk.forEach(AbstractToolInstallCommand::updateFilePermissions); diff --git a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/cli/mixin/ToolDefinitionsUpdateMixin.java b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/cli/mixin/ToolDefinitionsUpdateMixin.java new file mode 100644 index 0000000000..5f6db48ab8 --- /dev/null +++ b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/cli/mixin/ToolDefinitionsUpdateMixin.java @@ -0,0 +1,69 @@ +package com.fortify.cli.tool._common.cli.mixin; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.util.Date; + +import com.fortify.cli.common.util.DateTimePeriodHelper; +import com.fortify.cli.common.util.DateTimePeriodHelper.Period; +import com.fortify.cli.common.util.FcliDataHelper; +import com.fortify.cli.tool._common.helper.ToolDefinitionsStateDescriptor; +import com.fortify.cli.tool._common.helper.ToolHelper; + +import lombok.Getter; +import picocli.CommandLine.Option; + +public class ToolDefinitionsUpdateMixin { + // When updating this URL, please also update the URL in the resource bundle + private static final String DEFAULT_URL = "https://github.com/fortify-ps/tool-definitions/raw/main/v1/tool-definitions.yaml.zip"; + private static final DateTimePeriodHelper periodHelper = DateTimePeriodHelper.byRange(Period.SECONDS, Period.DAYS); + private static final Path DESCRIPTOR_PATH = ToolHelper.DEFINITIONS_STATE_DIR.resolve("state.json"); + @Getter @Option(names={"-s", "--definitions-source"}, required = false, descriptionKey="fcli.tool.definitions.update.definitions-source") + private String source = DEFAULT_URL; + @Getter @Option(names={"-a", "--max-definitions-age"}, required = false, defaultValue = "1h", descriptionKey="fcli.tool.definitions.update.max-definitions-age") + private String maxAge; + + public final ToolDefinitionsStateDescriptor updateToolDefinitions() throws IOException { + createDefinitionsStateDir(ToolHelper.DEFINITIONS_STATE_DIR); + var zip = ToolHelper.DEFINITIONS_STATE_ZIP; + ToolDefinitionsStateDescriptor descriptor = FcliDataHelper.readFile(DESCRIPTOR_PATH, ToolDefinitionsStateDescriptor.class, false); + if ( descriptor==null || !Files.exists(zip) || isMaxAgeExpired(descriptor, maxAge) ) { + update(source, zip); + descriptor = new ToolDefinitionsStateDescriptor(source, new Date(getModifiedTime(zip).toMillis()), "UPDATED"); + } else { + descriptor = new ToolDefinitionsStateDescriptor(descriptor.getSource(), descriptor.getLastUpdate(), "SKIPPED"); + } + FcliDataHelper.saveFile(DESCRIPTOR_PATH, descriptor, true); + return descriptor; + } + + private static final void createDefinitionsStateDir(Path dir) throws IOException { + if( !Files.exists(dir) ) { + Files.createDirectories(dir); + } + } + + private static final boolean isMaxAgeExpired(ToolDefinitionsStateDescriptor descriptor, String maxAge) { + var lastUpdate = descriptor.getLastUpdate().toInstant(); + return periodHelper.getCurrentOffsetDateTimeMinusPeriod(maxAge).toInstant().compareTo(lastUpdate)>0; + } + + private static FileTime getModifiedTime(Path path) throws IOException { + BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class); + return attr.lastModifiedTime(); + } + + private static final void update(String source, Path dest) throws IOException { + try { + ToolHelper.download(new URL(source).toString(), dest.toFile()); + } catch ( MalformedURLException e ) { + Files.copy(Path.of(source), dest, StandardCopyOption.REPLACE_EXISTING); + } + } +} diff --git a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/helper/ToolDefinitionsStateDescriptor.java b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/helper/ToolDefinitionsStateDescriptor.java new file mode 100644 index 0000000000..9d1a89c92e --- /dev/null +++ b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/helper/ToolDefinitionsStateDescriptor.java @@ -0,0 +1,34 @@ +/** + * Copyright 2023 Open Text. + * + * The only warranties for products and services of Open Text + * and its affiliates and licensors (“Open Text”) are as may + * be set forth in the express warranty statements accompanying + * such products and services. Nothing herein should be construed + * as constituting an additional warranty. Open Text shall not be + * liable for technical or editorial errors or omissions contained + * herein. The information contained herein is subject to change + * without notice. + */ +package com.fortify.cli.tool._common.helper; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.formkiq.graalvm.annotations.Reflectable; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Reflectable @NoArgsConstructor @AllArgsConstructor +@Data +public final class ToolDefinitionsStateDescriptor{ + private String source; + private Date lastUpdate; + private String __action__; + + public final String getLastUpdateString() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(getLastUpdate()); + } +} \ No newline at end of file diff --git a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/helper/ToolHelper.java b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/helper/ToolHelper.java index 293177bd78..26583e8d44 100644 --- a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/helper/ToolHelper.java +++ b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_common/helper/ToolHelper.java @@ -13,23 +13,26 @@ package com.fortify.cli.tool._common.helper; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fortify.cli.common.http.proxy.helper.ProxyHelper; +import com.fortify.cli.common.rest.unirest.GenericUnirestFactory; import com.fortify.cli.common.util.FcliDataHelper; import com.fortify.cli.common.util.FileUtils; public final class ToolHelper { + public static final Path DEFINITIONS_STATE_DIR = FcliDataHelper.getFcliStatePath().resolve("tool"); + public static final Path DEFINITIONS_STATE_ZIP = DEFINITIONS_STATE_DIR.resolve("tool-definitions.yaml.zip"); + private static final String DEFINITIONS_INTERNAL_ZIP = "com/fortify/cli/tool/config/tool-definitions.yaml.zip"; private static final ObjectMapper yamlObjectMapper = new ObjectMapper(new YAMLFactory()); - private static final String internalToolDefinitionsLocation = "com/fortify/cli/tool/config/tool-definitions.yaml.zip"; - private static final File configuredToolDefinitionsFile = FcliDataHelper.getFcliConfigPath().resolve("tool/tool-definitions.yaml.zip").toFile(); public static final ToolDefinitionRootDescriptor getToolDefinitionRootDescriptor(String toolName) { String yamlFileName = toolName + ".yaml"; @@ -66,48 +69,19 @@ public static final String getResourceFile(String toolName, String fileName) { return String.format("%s/%s", getResourceDir(toolName.replace('-', '_')), fileName); } - private static final Path getInstallDescriptorPath(String toolName, String version) { - return FcliDataHelper.getFcliStatePath().resolve("tools").resolve(toolName).resolve(version); - } - - private static final InputStream getToolDefinitionsInputStream() throws FileNotFoundException { - return configuredToolDefinitionsFile.exists() - ? new FileInputStream(configuredToolDefinitionsFile) - : FileUtils.getResourceInputStream(internalToolDefinitionsLocation); + public static final File download(String url, File dest) { + GenericUnirestFactory.getUnirestInstance("tool", u->ProxyHelper.configureProxy(u, "tool", url)) + .get(url).asFile(dest.getAbsolutePath(), StandardCopyOption.REPLACE_EXISTING).getBody(); + return dest; } - /* - private static final void initializeZipBundle() throws IOException { - if(!toolDefinitions.toFile().exists()) { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - String resourceFile = "com/fortify/cli/tool/config/tool-definitions.yaml.zip"; - try ( InputStream stream = classLoader.getResourceAsStream(resourceFile) ) { - if(!FcliDataHelper.getFcliConfigPath().resolve("tool").toFile().exists()) { - Files.createDirectories(FcliDataHelper.getFcliConfigPath().resolve("tool")); - } - Files.copy(stream, toolDefinitions, StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - throw e; - } - } + private static final Path getInstallDescriptorPath(String toolName, String version) { + return FcliDataHelper.getFcliStatePath().resolve("tools").resolve(toolName).resolve(version); } - private static final ToolDefinitionRootDescriptor loadDescriptorFromZipBundle(String toolName) throws IOException { - ZipFile bundle = new ZipFile(toolDefinitions.toString()); - Enumeration entries = bundle.entries(); - - while(entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - if(entry.getName().equals(String.format("%s.yaml", toolName))) { - - try (InputStream file = bundle.getInputStream(entry)) { - return yamlObjectMapper.readValue(file, ToolDefinitionRootDescriptor.class); - } catch (IOException e) { - throw e; - } - } - } - throw new FileNotFoundException(String.format("%s.yaml", toolName)); + private static final InputStream getToolDefinitionsInputStream() throws IOException { + return Files.exists(DEFINITIONS_STATE_ZIP) + ? Files.newInputStream(DEFINITIONS_STATE_ZIP) + : FileUtils.getResourceInputStream(DEFINITIONS_INTERNAL_ZIP); } - */ } diff --git a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_main/cli/cmd/ToolCommands.java b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_main/cli/cmd/ToolCommands.java index 0703fa02af..ad2f5997e7 100644 --- a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_main/cli/cmd/ToolCommands.java +++ b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/_main/cli/cmd/ToolCommands.java @@ -14,8 +14,8 @@ import com.fortify.cli.common.cli.cmd.AbstractContainerCommand; import com.fortify.cli.tool.bugtracker_utility.cli.cmd.ToolBugTrackerUtilityCommands; -import com.fortify.cli.tool.config.cli.cmd.ToolConfigCommands; import com.fortify.cli.tool.debricked_cli.cli.cmd.ToolDebrickedCliCommands; +import com.fortify.cli.tool.definitions.cli.cmd.ToolDefinitionsCommands; import com.fortify.cli.tool.fcli.cli.cmd.ToolFcliCommands; import com.fortify.cli.tool.fod_uploader.cli.cmd.ToolFoDUploaderCommands; import com.fortify.cli.tool.sc_client.cli.cmd.ToolSCClientCommands; @@ -33,7 +33,7 @@ ToolFoDUploaderCommands.class, ToolSCClientCommands.class, ToolVulnExporterCommands.class, - ToolConfigCommands.class + ToolDefinitionsCommands.class } ) public class ToolCommands extends AbstractContainerCommand {} diff --git a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/config/cli/cmd/ToolConfigCommands.java b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/config/cli/cmd/ToolConfigCommands.java deleted file mode 100644 index c9a69b6868..0000000000 --- a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/config/cli/cmd/ToolConfigCommands.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.fortify.cli.tool.config.cli.cmd; -import com.fortify.cli.common.cli.cmd.AbstractContainerCommand; - -import picocli.CommandLine.Command; - -@Command( - name = "config", - aliases = {}, - subcommands = { - ToolConfigUpdateCommand.class - } -) - -public class ToolConfigCommands extends AbstractContainerCommand { -} \ No newline at end of file diff --git a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/config/cli/cmd/ToolConfigUpdateCommand.java b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/config/cli/cmd/ToolConfigUpdateCommand.java deleted file mode 100644 index ad66986821..0000000000 --- a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/config/cli/cmd/ToolConfigUpdateCommand.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.fortify.cli.tool.config.cli.cmd; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fortify.cli.common.http.proxy.helper.ProxyHelper; -import com.fortify.cli.common.output.cli.cmd.AbstractOutputCommand; -import com.fortify.cli.common.output.cli.cmd.IJsonNodeSupplier; -import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; -import com.fortify.cli.common.output.transform.IActionCommandResultSupplier; -import com.fortify.cli.common.rest.unirest.GenericUnirestFactory; -import com.fortify.cli.common.util.FcliDataHelper; -import com.fortify.cli.tool.config.cli.mixin.ToolConfigSourceMixin; - -import kong.unirest.UnirestInstance; -import lombok.Getter; -import picocli.CommandLine.ArgGroup; -import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; - -@Command(name=OutputHelperMixins.Update.CMD_NAME) -public class ToolConfigUpdateCommand extends AbstractOutputCommand implements IJsonNodeSupplier, IActionCommandResultSupplier{ - @Mixin @Getter private OutputHelperMixins.Update outputHelper; - @ArgGroup(exclusive=true, multiplicity="0..1") - private ToolConfigSourceMixin toolConfigSourceMixin; - private String defaultDownloadUrl= "https://github.com/fortify-ps/tool-definitions/raw/main/v1/tool-definitions.yaml.zip"; - - @Override - public boolean isSingular() { - return true; - } - - @Override - public JsonNode getJsonNode() { - try { - return new ObjectMapper().valueToTree(updateToolDefinitions()); - } catch (IOException e) { - throw new RuntimeException("Error updating tool definitions", e); - } - } - - private ToolBundleDownloadDescriptor updateToolDefinitions() throws IOException { - if(!getZipPath().toFile().exists()) { - Files.createDirectories(getZipPath()); - } - if(toolConfigSourceMixin!=null) { - if(toolConfigSourceMixin.getFile()!=null) { - return getFromLocalPath(toolConfigSourceMixin.getFile()); - } - if(toolConfigSourceMixin.getUrl()!=null) { - return downloadFromWeblink(toolConfigSourceMixin.getUrl()); - } - } - return downloadFromWeblink(defaultDownloadUrl); - } - - private ToolBundleDownloadDescriptor downloadFromWeblink(String url) throws IOException { - File pkg = download(url, getZipPath().toFile()); - return new ToolBundleDownloadDescriptor(url, pkg.getPath()); - } - - private ToolBundleDownloadDescriptor getFromLocalPath(String path) throws IOException { - Path pkg = Files.copy(Path.of(path), getZipPath(), StandardCopyOption.REPLACE_EXISTING); - return new ToolBundleDownloadDescriptor(path, pkg.toString()); - } - - private final File download(String downloadUrl, File destFile) { - UnirestInstance unirest = GenericUnirestFactory.getUnirestInstance("toolversions", - u->ProxyHelper.configureProxy(u, "toolversions", downloadUrl)); - unirest.get(downloadUrl).asFile(destFile.getAbsolutePath(), StandardCopyOption.REPLACE_EXISTING).getBody(); - return destFile; - } - - private Path getZipPath() { - return FcliDataHelper.getFcliConfigPath().resolve("tool/tool-definitions.yaml.zip"); - } - - private class ToolBundleDownloadDescriptor{ - public String remotePath; - public String localPath; - public ToolBundleDownloadDescriptor(String remotePath, String localPath) { - this.remotePath = remotePath; - this.localPath = localPath; - } - } - - @Override - public String getActionCommandResult() { - return "UPDATED"; - } -} diff --git a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/config/cli/mixin/ToolConfigSourceMixin.java b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/config/cli/mixin/ToolConfigSourceMixin.java deleted file mode 100644 index 847702afe4..0000000000 --- a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/config/cli/mixin/ToolConfigSourceMixin.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.fortify.cli.tool.config.cli.mixin; - -import lombok.Getter; -import picocli.CommandLine.Option; - -public class ToolConfigSourceMixin { - @Getter @Option(names={"--url"}, required = false, descriptionKey="fcli.tool.config.update.url") - private String url; - @Getter @Option(names={"--file"}, required = false, descriptionKey="fcli.tool.config.update.file") - private String file; -} diff --git a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/definitions/cli/cmd/ToolDefinitionsCommands.java b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/definitions/cli/cmd/ToolDefinitionsCommands.java new file mode 100644 index 0000000000..5d6a55fa4a --- /dev/null +++ b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/definitions/cli/cmd/ToolDefinitionsCommands.java @@ -0,0 +1,15 @@ +package com.fortify.cli.tool.definitions.cli.cmd; +import com.fortify.cli.common.cli.cmd.AbstractContainerCommand; + +import picocli.CommandLine.Command; + +@Command( + name = "definitions", + aliases = {}, + subcommands = { + ToolDefinitionsUpdateCommand.class + } +) + +public class ToolDefinitionsCommands extends AbstractContainerCommand { +} \ No newline at end of file diff --git a/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/definitions/cli/cmd/ToolDefinitionsUpdateCommand.java b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/definitions/cli/cmd/ToolDefinitionsUpdateCommand.java new file mode 100644 index 0000000000..dc39e4323f --- /dev/null +++ b/fcli-core/fcli-tool/src/main/java/com/fortify/cli/tool/definitions/cli/cmd/ToolDefinitionsUpdateCommand.java @@ -0,0 +1,41 @@ +package com.fortify.cli.tool.definitions.cli.cmd; + +import java.io.IOException; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fortify.cli.common.output.cli.cmd.AbstractOutputCommand; +import com.fortify.cli.common.output.cli.cmd.IJsonNodeSupplier; +import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; +import com.fortify.cli.common.output.transform.IActionCommandResultSupplier; +import com.fortify.cli.tool._common.cli.mixin.ToolDefinitionsUpdateMixin; + +import lombok.Getter; +import picocli.CommandLine.Command; +import picocli.CommandLine.Mixin; + +@Command(name=OutputHelperMixins.Update.CMD_NAME) +public class ToolDefinitionsUpdateCommand extends AbstractOutputCommand implements IJsonNodeSupplier, IActionCommandResultSupplier{ + @Mixin @Getter private OutputHelperMixins.Update outputHelper; + @Mixin private ToolDefinitionsUpdateMixin toolDefinitionsUpdateMixin; + + @Override + public JsonNode getJsonNode() { + try { + return new ObjectMapper().valueToTree(toolDefinitionsUpdateMixin.updateToolDefinitions()); + } catch (IOException e) { + throw new RuntimeException("Error updating tool definitions", e); + } + } + + @Override + public boolean isSingular() { + return true; + } + + @Override + public String getActionCommandResult() { + return "UPDATED"; + } +} diff --git a/fcli-core/fcli-tool/src/main/resources/com/fortify/cli/tool/i18n/ToolMessages.properties b/fcli-core/fcli-tool/src/main/resources/com/fortify/cli/tool/i18n/ToolMessages.properties index 4a6da1dab5..69d8ac029e 100644 --- a/fcli-core/fcli-tool/src/main/resources/com/fortify/cli/tool/i18n/ToolMessages.properties +++ b/fcli-core/fcli-tool/src/main/resources/com/fortify/cli/tool/i18n/ToolMessages.properties @@ -4,30 +4,49 @@ usage.header = usage.description = +# Shared resources +fcli.tool.install.platform = By default, fcli will try to install tool binaries that match the current operating system \ + & architecture. Use this option to override automatic platform detection. The list-platforms command lists available \ + platforms. +fcli.tool.install.version = Tool version to install; see output of list command to view available versions. If not \ + specified, the default version as shown in the output of the list command will be installed. +fcli.tool.install.install-dir = Tool installation directory. Deprecated, use --tools-dir instead. +fcli.tool.install.base-dir = Directory under which the tool will be installed. Defaults to ~/fortify. \ + Tools will be installed to //. +fcli.tool.install.on-digest-mismatch = Action to take if there is a digest mismatch. Allowed values: \ + ${COMPLETION-CANDIDATES}. Default action is to fail. +fcli.tool.uninstall.version = Tool version to uninstall. +fcli.tool.list-platforms.version = Tool version for which to list available platforms. fcli.tool.install.confirmPrompt = Confirm removal of existing installation directory %s? +fcli.tool.definitions.update.definitions-source = URL or file to get the tool definitions from. If not specified, \ + tool definitions are downloaded from a predefined public Internet URL. +fcli.tool.definitions.update.max-definitions-age = Only update tool definitions if the current definitions are older \ + than the specified maximum age, for example 0s (0 seconds, force update), 4h (4 hours) or 1d (1 day), to avoid \ + downloading the definitions multiple times in a short period of time. Default value: ${DEFAULT-VALUE} fcli.tool.uninstall.confirmPrompt = Confirm removal of installation directory %s? # fcli tool fcli.tool.usage.header = Install and manage other Fortify tools and utilities. fcli.tool.usage.description = The commands in this module allow for installing other Fortify tools like FoD Uploader, ScanCentral Client and FortifyVulnerabilityExporter, and managing those installations. -#fcli tool config -fcli.tool.config.usage.header = Manage tool related configuration -fcli.tool.config.usage.description = The commands in this module allow for managing tool related configuration like updating tool definitions. -fcli.tool.config.update.usage.header = Update tool definitions (available versions) -fcli.tool.config.update.usage.description = This command downloads an updated version of the tool definition files fcli uses to display currently available versions of tools -fcli.tool.config.update.url = Custom URL from which to download the tool definitions bundle -fcli.tool.config.update.file = Local or UNC path from which to load the tool definitions bundle - -# Shared options -fcli.tool.install.platform = By default, fcli will try to install tool binaries that match the current operating system & architecture. Use this option to override automatic platform detection. The list-platforms command lists available platforms. -fcli.tool.install.version = Tool version to install; see output of list command to view available versions. If not specified, the default version as shown in the output of the list command will be installed. -fcli.tool.install.install-dir = Tool installation directory. Deprecated, use --tools-dir instead. -fcli.tool.install.base-dir = Directory under which the tool will be installed. Defaults to ~/fortify. Tools will be installed to //. -fcli.tool.install.on-digest-mismatch = Action to take if there is a digest mismatch. Allowed values: ${COMPLETION-CANDIDATES}. Default action is to fail. When installing 'latest', you may consider setting this option to 'warn' to avoid failures if fcli hasn't been updated yet with the latest digest. Please consider submitting an issue on the fcli issue tracker if digest check consistently fails. -fcli.tool.uninstall.version = Tool version to uninstall. -fcli.tool.list-platforms.version = Tool version for which to list available versions. -fcli.tool.output.header.isDefaultVersion = Default +#fcli tool definitions +fcli.tool.definitions.generic-description = Tool definitions list the available versions, corresponding download \ + location, and other details for each tool. These tool definitions are used by the various 'fcli tool' commands \ + to identify what tool versions are currently available and where to download them from. By default, each fcli \ + release ships with the latest tool definitions that were available at the time that release was built. +fcli.tool.definitions.usage.header = Manage tool definitions +fcli.tool.definitions.usage.description.0 = ${fcli.tool.definitions.generic-description}\n +fcli.tool.definitions.usage.description.1 = The commands in this module allow for managing tool definitions, like \ + updating tool definitions from a URL or local file. +fcli.tool.definitions.update.usage.header = Update tool definitions +fcli.tool.definitions.update.usage.description.0 = ${fcli.tool.definitions.generic-description}\n +fcli.tool.definitions.update.usage.description.1 = The update command allows for updating the tool definitions from \ + a URL or local file. This allows for the current fcli installation to be aware of new tool versions that were \ + released after the current fcli release was built, and also allows users to use a custom tool definitions bundle.\n +fcli.tool.definitions.update.usage.description.2 = For example, if it's not allowed to download tool \ + installation bundles from public sites like github.com or tools.fortify.com, companies can host tool installation \ + bundles internally and provide a tool definitions bundle that points to the internally hosted installation bundles. \ + At the same time, companies can restrict which versions of each tool users are allowed to install. # fcli tool bugtracker-utility fcli.tool.bugtracker-utility.usage.header = Manage Fortify on Demand (FoD) Uploader installations. (https://github.com/fod-dev/fod-uploader-java) @@ -102,11 +121,9 @@ fcli.tool.vuln-exporter.uninstall.usage.header = Uninstall Fortify Vulnerability fcli.tool.sc-client.uninstall.usage.description = This command removes a Fortify Vulnerability Exporter installation that was previously installed using the 'fcli tool vuln-exporter install' command. fcli.tool.vuln-exporter.uninstall.confirm = Confirm removal of Fortify Vulnerability Exporter. -fcli.tool.output.header.aliasesString = Aliases - ################################################################################################################# # The following are technical properties that shouldn't be internationalized #################################### ################################################################################################################# fcli.tool.output.table.options = name,version,aliasesString,stable,installDir fcli.tool.list-platforms.output.table.options = platform -fcli.tool.config.update.output.table.options = remotePath,localPath \ No newline at end of file +fcli.tool.definitions.output.table.options = source,lastUpdateString