From 9b54695fe708dab13ee3e49b8649add5dc905415 Mon Sep 17 00:00:00 2001 From: kim-codefresh Date: Wed, 10 Jan 2024 10:30:13 +0200 Subject: [PATCH 1/3] add Docker file for oidc and aws assume role step curl jq and aws usage (#671) * add Docker file for oidc and aws assume role step curl jq and aws usage * remove unnecessary arg * add comment --- .../aws-sts-assume-role-with-web-identity/Dockerfile | 9 +++++++++ incubating/obtain-oidc-id-token/Dockerfile | 5 +++++ 2 files changed, 14 insertions(+) create mode 100644 incubating/aws-sts-assume-role-with-web-identity/Dockerfile create mode 100644 incubating/obtain-oidc-id-token/Dockerfile diff --git a/incubating/aws-sts-assume-role-with-web-identity/Dockerfile b/incubating/aws-sts-assume-role-with-web-identity/Dockerfile new file mode 100644 index 000000000..8d2e24d5d --- /dev/null +++ b/incubating/aws-sts-assume-role-with-web-identity/Dockerfile @@ -0,0 +1,9 @@ +FROM python:alpine + +# using same aws-cli that was used before moving to quay images to prevent regressions +ARG CLI_VERSION=1.16.284 + +RUN apk -uv add --no-cache groff jq less && \ + pip install --no-cache-dir awscli==$CLI_VERSION + +WORKDIR /aws \ No newline at end of file diff --git a/incubating/obtain-oidc-id-token/Dockerfile b/incubating/obtain-oidc-id-token/Dockerfile new file mode 100644 index 000000000..9dbf13cf2 --- /dev/null +++ b/incubating/obtain-oidc-id-token/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:3.14 + +RUN apk add --no-cache curl jq bash + +CMD ["/bin/sh"] \ No newline at end of file From 9addaf7b72c1293f6af8ee013e2ce51e0252e56d Mon Sep 17 00:00:00 2001 From: Laurent Rochette Date: Tue, 23 Jan 2024 11:51:45 -0700 Subject: [PATCH 2/3] Kubescape integration (#674) * first draft * Remove composition from example * Fix syntax * Add script * fix indentation * add script inline * Add missing shell * Moving script to file * Pull base image from quay * make executable * change image base and version * fix script and variable names * Adding missing parameters * Add example and fix README --------- Signed-off-by: Laurent Rochette --- incubating/kubescape/CHANGELOG.md | 5 + incubating/kubescape/Dockerfile | 8 ++ incubating/kubescape/README.md | 11 ++ incubating/kubescape/entrypoint.sh | 171 +++++++++++++++++++++++++++++ incubating/kubescape/icon.png | Bin 0 -> 12018 bytes incubating/kubescape/step.yaml | 146 ++++++++++++++++++++++++ 6 files changed, 341 insertions(+) create mode 100644 incubating/kubescape/CHANGELOG.md create mode 100644 incubating/kubescape/Dockerfile create mode 100644 incubating/kubescape/README.md create mode 100755 incubating/kubescape/entrypoint.sh create mode 100644 incubating/kubescape/icon.png create mode 100644 incubating/kubescape/step.yaml diff --git a/incubating/kubescape/CHANGELOG.md b/incubating/kubescape/CHANGELOG.md new file mode 100644 index 000000000..6661463f0 --- /dev/null +++ b/incubating/kubescape/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## [1.0.0] - 2024-01-22 + +Original version diff --git a/incubating/kubescape/Dockerfile b/incubating/kubescape/Dockerfile new file mode 100644 index 000000000..aa167d80d --- /dev/null +++ b/incubating/kubescape/Dockerfile @@ -0,0 +1,8 @@ +FROM quay.io/kubescape/kubescape-cli:v3.0.1 + +# Kubescape uses root privileges for writing the results to a file +USER root + +COPY entrypoint.sh /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/incubating/kubescape/README.md b/incubating/kubescape/README.md new file mode 100644 index 000000000..fa309c519 --- /dev/null +++ b/incubating/kubescape/README.md @@ -0,0 +1,11 @@ +# kubescape CLI + +Docker image which invokes security script using kubescape CLI + +### Prerequisites: + +Codefresh Subscription (Dedicated Infrastructure/Hybrid) - https://codefresh.io/ + +### Documentation: + +kubescape CLI: https://github.com/kubescape/kubescape/blob/master/docs/getting-started.md diff --git a/incubating/kubescape/entrypoint.sh b/incubating/kubescape/entrypoint.sh new file mode 100755 index 000000000..0c413a415 --- /dev/null +++ b/incubating/kubescape/entrypoint.sh @@ -0,0 +1,171 @@ +#!/busybox/sh + +# Checks if `string` contains `substring`. +# +# Arguments: +# String to check. +# +# Returns: +# 0 if `string` contains `substring`, otherwise 1. +contains() { + case "$1" in + *$2*) return 0 ;; + *) return 1 ;; + esac +} + +set -e + +# Kubescape uses the client name to make a request for checking for updates +export KS_CLIENT="codefresh" + +if [ -n "${FRAMEWORKS}" ] && [ -n "${CONTROLS}" ]; then + echo "Framework and Control are specified. Please specify either one of them" + exit 1 +fi + +if [ -z "${FRAMEWORKS}" ] && [ -z "${CONTROLS}" ] && [ -z "${IMAGE}" ]; then + echo "Neither Framework, Control nor image are specified. Please specify one of them" + exit 1 +fi + + +if [ -n "${FRAMEWORKS}" ] && [ -n "${IMAGE}" ] || [ -n "${CONTROLS}" ] && [ -n "${IMAGE}" ] ; then + errmsg="Image and Framework / Control are specified. Kubescape does not support scanning both at the moment." + errmsg="${errmsg} Please specify either one of them or neither." + echo "${errmsg}" + exit 1 +fi + +if [ -n "${IMAGE}" ] && [ "${FIXFILES}" = "true" ]; then + errmsg="The run requests both an image scan and file fix suggestions. Kubescape does not support fixing image scan results at the moment." + errmsg="${errmsg} Please specify either one of them or neither." + echo "${errmsg}" + exit 1 +fi + +# Split the controls by comma and concatenate with quotes around each control +if [ -n "${CONTROLS}" ]; then + controls="" + set -f + IFS=',' + set -- "${CONTROLS}" + set +f + unset IFS + for control in "$@"; do + control=$(echo "${control}" | xargs) # Remove leading/trailing whitespaces + controls="${controls}\"${control}\"," + done + controls=$(echo "${controls%?}") +fi + +frameworks_cmd=$([ -n "${FRAMEWORKS}" ] && echo "framework ${FRAMEWORKS}" || echo "") +controls_cmd=$([ -n "${CONTROLS}" ] && echo control "${controls}" || echo "") + +scan_input=$([ -n "${FILES}" ] && echo "${FILES}" || echo .) + +output_formats="${FORMAT}" +have_json_format="false" +if [ -n "${output_formats}" ] && contains "${output_formats}" "json"; then + have_json_format="true" +fi + +verbose="" +if [ -n "${VERBOSE}" ] && [ "${VERBOSE}" != "false" ]; then + verbose="--verbose" +fi + +exceptions="" +if [ -n "$EXCEPTIONS" ]; then + exceptions="--exceptions ${EXCEPTIONS}" +fi + +controls_config="" +if [ -n "$CONTROLSCONFIG" ]; then + controls_config="--controls-config ${CONTROLSCONFIG}" +fi + +should_fix_files="false" +if [ "${FIXFILES}" = "true" ]; then + should_fix_files="true" +fi + +# If a user requested Kubescape to fix their files, but forgot to ask for JSON +# output, do it for them +if [ "${should_fix_files}" = "true" ] && [ "${have_json_format}" != "true" ]; then + output_formats="${output_formats},json" +fi + +output_file=$([ -n "${OUTPUTFILE}" ] && echo "${OUTPUTFILE}" || echo "results") + +account_opt=$([ -n "${ACCOUNT}" ] && echo --account "${ACCOUNT}" || echo "") +access_key_opt=$([ -n "${ACCESSKEY}" ] && echo --access-key "${ACCESSKEY}" || echo "") +server_opt=$([ -n "${SERVER}" ] && echo --server "${SERVER}" || echo "") + +# If account ID is empty, we load artifacts from the local path, otherwise we +# load from the cloud (this will enable custom framework support) +artifacts_path="/home/ks/.kubescape" +artifacts_opt=$([ -n "${ACCOUNT}" ] && echo "" || echo --use-artifacts-from "${artifacts_path}") + +if [ -n "${FAILEDTHRESHOLD}" ] && [ -n "${COMPLIANCETHRESHOLD}" ]; then + echo "Both failedThreshold and complianceThreshold are specified. Please specify either one of them or neither" + exit 1 +fi + +fail_threshold_opt=$([ -n "${FAILEDTHRESHOLD}" ] && echo --fail-threshold "${FAILEDTHRESHOLD}" || echo "") +compliance_threshold_opt=$([ -n "${COMPLIANCETHRESHOLD}" ] && echo --compliance-threshold "${COMPLIANCETHRESHOLD}" || echo "") + +# When a user requests to fix files, the action should not fail because the +# results exceed severity. This is subject to change in the future. +severity_threshold_opt=$( + [ -n "${SEVERITYTHRESHOLD}" ] && + [ "${should_fix_files}" = "false" ] && + echo --severity-threshold "${SEVERITYTHRESHOLD}" || + echo "" +) + +# Handle image scanning request +image_subcmd="" +echo "image is <${IMAGE}>" +if [ -n "${IMAGE}" ]; then + + # By default, assume we are not authenticated. This means we can pull public + # images from the container runtime daemon + image_arg="${IMAGE}" + + severity_threshold_opt=$( + [ -n "${SEVERITYTHRESHOLD}" ] && + echo --severity-threshold "${SEVERITYTHRESHOLD}" || + echo "" + ) + + auth_opts="" + if [ -n "${REGISTRYUSERNAME}" ] && [ -n "${REGISTRYPASSWORD}" ]; then + auth_opts="--username=${REGISTRYUSERNAME} --password=${REGISTRYPASSWORD}" + + # When trying to authenticate, we cannot assume that the runner has access + # to an *authenticated* container runtime daemon, so we should always try + # to pull images from the registry + image_arg="registry://${image_arg}" + else + echo "NOTICE: Received no registry credentials, pulling without authentication." + printf "Hint: If you provide credentials, make sure you include both the username and password.\n\n" + fi + + # Build the image scanning subcommand with options + image_subcmd="image ${auth_opts}" + # Override the scan input + scan_input="${image_arg}" + echo "Scan subcommand: ${image_subcmd}" +fi + +# TODO: include artifacts_opt once https://github.com/kubescape/kubescape/issues/1040 is resolved +scan_command="kubescape scan ${image_subcmd} ${frameworks_cmd} ${controls_cmd} ${scan_input} ${account_opt} ${access_key_opt} ${server_opt} ${fail_threshold_opt} ${compliance_threshold_opt} ${severity_threshold_opt} --format ${output_formats} --output ${output_file} ${verbose} ${exceptions} ${controls_config}" + +echo "${scan_command}" +eval "${scan_command}" + +if [ "$should_fix_files" = "true" ]; then + fix_command="kubescape fix --no-confirm ${output_file}.json" + eval "${fix_command}" +fi diff --git a/incubating/kubescape/icon.png b/incubating/kubescape/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e93cda3fc1618b21a72d4084ddefd87bfc5a78c4 GIT binary patch literal 12018 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 literal 0 HcmV?d00001 diff --git a/incubating/kubescape/step.yaml b/incubating/kubescape/step.yaml new file mode 100644 index 000000000..3a4118f65 --- /dev/null +++ b/incubating/kubescape/step.yaml @@ -0,0 +1,146 @@ +kind: step-type +version: '1.0' +metadata: + name: kubescape + version: 3.0.1 + title: Run a kubescape security scan + isPublic: true + description: Scan a cluster with the kubescape security service. + sources: + - 'https://github.com/codefresh-io/steps/tree/master/incubating/kubescape' + stage: incubating + maintainers: + - name: Laurent Rochette + email: laurent.rochette@codefresh.io + - name: Matthias Bertschy + email: matthiasb@armosec.io + categories: + - security + official: true + tags: [] + icon: + type: image + size: + large: + url: >- + https://cdn.jsdelivr.net/gh/codefresh-io/steps/incubating/kubescape/icon.png + examples: + - description: example-1 + workflow: + kubescape: + type: kubescape:3.0.1 + arguments: + VERBOSE: on + OUTPUTFILE: results + FRAMEWORKS: MITRE + ACCESSKEY: ${{KEY}} + ACCOUNT: ${{ACCOUNT_ID}} + FORMAT: sarif + +spec: + arguments: |- + { + "definitions": {}, + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": false, + "patterns": [], + "required": [], + "properties": { + "FILES": { + "type": "string", + "description": "YAML files or Helm charts to scan for misconfigurations. The files need to be provided with the complete path from the root of the repository. Default is '.' which scans the whole repository" + }, + "OUTPUTFILE": { + "type": "string", + "description": "Name of the output file where the scan result will be stored without the extension. Default is 'result'" + }, + "FRAMEWORKS": { + "type": "string", + "description": "Security framework(s) to scan the files against. Multiple frameworks can be specified separated by a comma with no spaces. Example - nsa,devopsbest. Run kubescape list frameworks in the Kubescape CLI to get a list of all frameworks. Either frameworks have to be specified or controls." + }, + "CONTROLS": { + "type": "string", + "description": "Security control(s) to scan the files against. Multiple controls can be specified separated by a comma with no spaces. Example - Configured liveness probe,Pods in default namespace. Run kubescape list controls in the Kubescape CLI to get a list of all controls. You can use either the complete control name or the control ID such as C-0001 to specify the control you want use. You must specify either the control(s) or the framework(s) you want used in the scan." + }, + "ACCOUNT": { + "type": "string", + "description": "account ID for integrating with a third-party server" + }, + "ACCESSKEY": { + "type": "string", + "description": "access-key for integrating with a third-party server" + }, + "SERVER": { + "type": "string", + "description": "URL for integrating with a third-party server" + }, + "FAILEDTHRESHOLD": { + "type": "string", + "description": "Failure threshold is the percent above which the command fails and returns exit code 1. Default is 0 i.e, action fails if any control fails" + }, + "SEVERITYTHRESHOLD": { + "type": "string", + "description": "Severity threshold is the severity of a failed control at or above which the command terminates with an exit code 1. Default is 'high', i.e. the action fails if any High severity control fails" + }, + "COMPLIANCETHRESHOLD": { + "type": "string", + "description": "Compliance threshold is the percent bellow which the command fails and returns exit code 1 (example: if set to 100 the command will fail if any control fails)" + }, + "VERBOSE": { + "type": "string", + "description": "on|off - Display all of the input resources and not only failed resources. Default is 'off'" + }, + "EXCEPTIONS": { + "type": "string", + "description": "The JSON file containing at least one resource and one policy. Refer exceptions docs for more info. Objects with exceptions will be presented as exclude and not fail." + }, + "FORMAT": { + "type": "string", + "description": "Output format. Can take one or more formats, comma separated", + "default": "junit" + }, + "CONTROLSCONFIG": { + "type": "string", + "description": "The file containing controls configuration. Use 'kubescape download controls-inputs' to download the configured controls-inputs." + }, + "FIXFILES": { + "type": "string", + "default": "false", + "description": "Whether Kubescape will automatically fix files or not. If enabled, Kubescape will make fixes to the input files. You can then use these fixes to open Pull Requests from your CI/CD pipeline." + }, + "IMAGE": { + "type": "string", + "description": "The image you wish to scan. Launches an image scan, which cannot run together with configuration scans." + }, + "REGISTRYUSERNAME": { + "type": "string", + "description": "Username to a private registry that hosts the scanned image." + }, + "REGISTRYPASSWORD": { + "type": "string", + "description": "Password to a private registry that hosts the scanned image." + }, + "KS_IMAGE": { + "type": "string", + "default": "quay.io/codefreshplugins/kubescape", + "description": "Kubescape image to use" + }, + "KS_IMAGE_VERSION": { + "type": "string", + "default": "3.0.1", + "description": "Version of the kubescape image to use" + } + } + } + stepsTemplate: |- + kubescan: + image: '[[.Arguments.KS_IMAGE]]:[[.Arguments.KS_IMAGE_VERSION]]' + title: kubescape scan + environment: + [[ range $key, $val := .Arguments ]] + - '[[ $key ]]=[[ $val ]]' + [[- end ]] + delimiters: + left: '[[' + right: ']]' From c791f9c6990ed8a968601fe750414df1affad1d8 Mon Sep 17 00:00:00 2001 From: Laurent Rochette Date: Tue, 6 Feb 2024 13:42:47 -0700 Subject: [PATCH 3/3] Change API call for app status (#673) * [1.4.2] change API call to improve performance and decrease lag * change some info message into debug * Change logging default level to error to match step * Update default version for image --- incubating/argo-cd-sync/CHANGELOG.md | 4 ++ incubating/argo-cd-sync/argocd_sync.py | 44 +++++++++---------- .../queries/get_app_status.graphql | 25 +++++------ .../queries/get_app_status.orig.graphql | 18 ++++++++ incubating/argo-cd-sync/step.yaml | 4 +- 5 files changed, 57 insertions(+), 38 deletions(-) create mode 100644 incubating/argo-cd-sync/queries/get_app_status.orig.graphql diff --git a/incubating/argo-cd-sync/CHANGELOG.md b/incubating/argo-cd-sync/CHANGELOG.md index 36c40d8d6..58f430cde 100644 --- a/incubating/argo-cd-sync/CHANGELOG.md +++ b/incubating/argo-cd-sync/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [1.4.2] - 2024-01-17 +### Changed +New graphql call to speed up query + ## [1.4.1] - 2023-10-31 ### Changed Add CA_BUNDLE option diff --git a/incubating/argo-cd-sync/argocd_sync.py b/incubating/argo-cd-sync/argocd_sync.py index 8ad448bf9..3deb5a3b9 100644 --- a/incubating/argo-cd-sync/argocd_sync.py +++ b/incubating/argo-cd-sync/argocd_sync.py @@ -22,7 +22,7 @@ CF_URL = os.getenv('CF_URL', 'https://g.codefresh.io') CF_API_KEY = os.getenv('CF_API_KEY') CF_STEP_NAME= os.getenv('CF_STEP_NAME', 'STEP_NAME') -LOG_LEVEL = os.getenv('LOG_LEVEL', "info") +LOG_LEVEL = os.getenv('LOG_LEVEL', "error") # Check the certificate or not accessing the API endpoint VERIFY = True if os.getenv('INSECURE', "False").lower() == "false" else False @@ -50,24 +50,24 @@ def main(): ingress_host = get_runtime_ingress_host() execute_argocd_sync(ingress_host) namespace=get_runtime_ns() - status = get_app_status(namespace) + status = get_app_status(ingress_host) if WAIT_HEALTHY: - status=waitHealthy (namespace) + status=waitHealthy (ingress_host) # if Wait failed, it's time for rollback if status != "HEALTHY" and ROLLBACK: logging.info("Application '%s' did not sync properly. Initiating rollback ", APPLICATION) revision = getRevision(namespace) - logging.info("latest healthy revision is %d", revision) + logging.info("Latest healthy revision is %d", revision) rollback(ingress_host, namespace, revision) logging.info("Waiting for rollback to happen") if WAIT_ROLLBACK: - status=waitHealthy (namespace) + status=waitHealthy (ingress_host) else: time.sleep(INTERVAL) - status=get_app_status(namespace) + status=get_app_status(ingress_host) else: export_variable('ROLLBACK_EXECUTED', "false") else: @@ -108,7 +108,7 @@ def getRevision(namespace): } } result = client.execute(query, variable_values=variables) - logging.info(result) + logging.debug("getRevision result: %s", result) loop=0 revision = -1 @@ -124,18 +124,18 @@ def getRevision(namespace): loop += 1 # we did not find a HEALTHY one in our page export_variable('ROLLBACK_EXECUTED', "false") - logging.error("Did not find a HEALTHY release among the lat %d", PAGE_SIZE) + logging.error("Did not find a HEALTHY release among the last %d", PAGE_SIZE) sys.exit(1) -def waitHealthy (namespace): - logging.debug ("Entering waitHealthy (ns: %s)", namespace) +def waitHealthy (ingress_host): + logging.debug ("Entering waitHealthy (ns: %s)", ingress_host) time.sleep(INTERVAL) - status = get_app_status(namespace) + status = get_app_status(ingress_host) logging.info("App status is %s", status) loop=0 while status != "HEALTHY" and loop < MAX_CHECKS: - status=get_app_status(namespace) + status=get_app_status(ingress_host) time.sleep(INTERVAL) logging.info("App status is %s after %d checks", status, loop) loop += 1 @@ -160,15 +160,15 @@ def rollback(ingress_host, namespace, revision): "dryRun": False, "prune": True } - logging.info("Rollback app: %s", variables) + logging.debug("Rollback variables: %s", variables) result = client.execute(query, variable_values=variables) - logging.info(result) + logging.debug("Rollback result: %s", result) export_variable('ROLLBACK_EXECUTED', "true") -def get_app_status(namespace): +def get_app_status(ingress_host): ## Get the health status of the app - gql_api_endpoint = CF_URL + '/2.0/api/graphql' + gql_api_endpoint = ingress_host + '/app-proxy/api/graphql' transport = RequestsHTTPTransport( url=gql_api_endpoint, headers={'authorization': CF_API_KEY}, @@ -178,13 +178,12 @@ def get_app_status(namespace): client = Client(transport=transport, fetch_schema_from_transport=False) query = get_query('get_app_status') ## gets gql query variables = { - "runtime": RUNTIME, - "name": APPLICATION, - "namespace": namespace + "name": APPLICATION } result = client.execute(query, variable_values=variables) - health = result['application']['healthStatus'] + logging.debug("App Status result: %s", result) + health = result['applicationProxyQuery']['status']['health']['status'] return health def get_query(query_name): @@ -245,9 +244,8 @@ def execute_argocd_sync(ingress_host): "prune": True } } - logging.info("Syncing app: %s", variables) result = client.execute(query, variable_values=variables) - logging.info(result) + logging.debug("Syncing App result: %s", result) def export_variable(var_name, var_value): @@ -260,7 +258,7 @@ def export_variable(var_name, var_value): with open('/meta/env_vars_to_export', 'a') as a_writer: a_writer.write(var_name + "=" + var_value+'\n') - logging.info("Exporting variable: %s=%s", var_name, var_value) + logging.debug("Exporting variable: %s=%s", var_name, var_value) ############################################################## diff --git a/incubating/argo-cd-sync/queries/get_app_status.graphql b/incubating/argo-cd-sync/queries/get_app_status.graphql index 796f42dd4..574b0d645 100644 --- a/incubating/argo-cd-sync/queries/get_app_status.graphql +++ b/incubating/argo-cd-sync/queries/get_app_status.graphql @@ -1,18 +1,17 @@ -query ApplicationsStatusesQuery( - $runtime: String! - $name: String! - $namespace: String -) { - application(runtime: $runtime, name: $name, namespace: $namespace) { +query appstatus ($name: String!) { + applicationProxyQuery( + name: $name + ){ metadata { - runtime name - namespace - cluster - __typename } - healthStatus - syncStatus - syncPolicy + status { + health { + status + } + sync { + status + } + } } } diff --git a/incubating/argo-cd-sync/queries/get_app_status.orig.graphql b/incubating/argo-cd-sync/queries/get_app_status.orig.graphql new file mode 100644 index 000000000..796f42dd4 --- /dev/null +++ b/incubating/argo-cd-sync/queries/get_app_status.orig.graphql @@ -0,0 +1,18 @@ +query ApplicationsStatusesQuery( + $runtime: String! + $name: String! + $namespace: String +) { + application(runtime: $runtime, name: $name, namespace: $namespace) { + metadata { + runtime + name + namespace + cluster + __typename + } + healthStatus + syncStatus + syncPolicy + } +} diff --git a/incubating/argo-cd-sync/step.yaml b/incubating/argo-cd-sync/step.yaml index 702452bf6..8874a8e20 100644 --- a/incubating/argo-cd-sync/step.yaml +++ b/incubating/argo-cd-sync/step.yaml @@ -1,7 +1,7 @@ kind: step-type metadata: name: argo-cd-sync - version: 1.4.1 + version: 1.4.2 isPublic: true description: Syncs Argo CD apps managed by our GitOps Runtimes sources: @@ -120,7 +120,7 @@ spec: }, "IMAGE_TAG": { "type": "string", - "default": "1.3.1", + "default": "1.4.2", "description": "OPTIONAL - To overwrite the tag to use" } }