diff --git a/graduated/github-release/step.yaml b/graduated/github-release/step.yaml index bed42c0ef..de53eeecb 100644 --- a/graduated/github-release/step.yaml +++ b/graduated/github-release/step.yaml @@ -3,7 +3,7 @@ version: '1.0' metadata: name: github-release title: Create a GitHub release - version: 1.2.0 + version: 1.2.1 isPublic: true description: Create a GitHub release. sources: @@ -20,7 +20,7 @@ metadata: tags: [] icon: type: svg - url: https://cdn.jsdelivr.net/gh/codefresh-io/steps/incubating/github-release/icon.svg + url: https://cdn.jsdelivr.net/gh/codefresh-io/steps/graduated/github-release/icon.svg background: "#f4f4f4" examples: - description: typical diff --git a/incubating/argo-cd-sync/CHANGELOG.md b/incubating/argo-cd-sync/CHANGELOG.md index e2ad2bf05..58f430cde 100644 --- a/incubating/argo-cd-sync/CHANGELOG.md +++ b/incubating/argo-cd-sync/CHANGELOG.md @@ -1,7 +1,18 @@ # Changelog -## [1.3.1] - 2023-09-18 + +## [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 + +## [1.4.0] - 2023-10-30 +### Changed +Add INSECURE option + +## [1.3.1] - 2023-09-18 ### Fixed - CVE-2023-37920 - upgrade Python module certifi to 2023.7.22 - CVE-2019-8457 - upgrade base image to python:3.11.5-slim-bookworm @@ -10,5 +21,3 @@ ### Changed - Adding IMAGE_NAME parameter - Adding example - -### Fixed diff --git a/incubating/argo-cd-sync/Dockerfile b/incubating/argo-cd-sync/Dockerfile index ad8e53afd..87f72ded1 100644 --- a/incubating/argo-cd-sync/Dockerfile +++ b/incubating/argo-cd-sync/Dockerfile @@ -1,6 +1,7 @@ -FROM python:3.11.5-slim-bookworm +FROM python:3.12.0-bookworm WORKDIR /app COPY requirements.txt requirements.txt +RUN pip3 install --upgrade pip RUN pip3 install -r requirements.txt COPY queries queries/ COPY argocd_sync.py run.py diff --git a/incubating/argo-cd-sync/argocd_sync.py b/incubating/argo-cd-sync/argocd_sync.py index 71a0c14d6..3deb5a3b9 100644 --- a/incubating/argo-cd-sync/argocd_sync.py +++ b/incubating/argo-cd-sync/argocd_sync.py @@ -22,7 +22,14 @@ 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 +CA_BUNDLE = os.getenv('CA_BUNDLE') + +if CA_BUNDLE != None: + VERIFY='/root/bundle.pem' ####################################################################### @@ -37,28 +44,30 @@ def main(): logging.debug("INTERVAL: %d", INTERVAL) logging.debug("MAX CHECKS: %s", MAX_CHECKS) logging.debug("ROLLBACK: %s", ROLLBACK) + logging.debug("VERIFY: %s", VERIFY) + logging.debug("BUNDLE: %s", CA_BUNDLE) 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: @@ -83,7 +92,7 @@ def getRevision(namespace): transport = RequestsHTTPTransport( url=gql_api_endpoint, headers={'authorization': CF_API_KEY}, - verify=True, + verify=VERIFY, retries=3, ) client = Client(transport=transport, fetch_schema_from_transport=False) @@ -99,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 @@ -115,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 @@ -139,7 +148,7 @@ def rollback(ingress_host, namespace, revision): transport = RequestsHTTPTransport( url=runtime_api_endpoint, headers={'authorization': CF_API_KEY}, - verify=True, + verify=VERIFY, retries=3, ) client = Client(transport=transport, fetch_schema_from_transport=False) @@ -151,31 +160,30 @@ 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}, - verify=True, + verify=VERIFY, retries=3, ) 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): @@ -189,7 +197,7 @@ def get_runtime(): transport = RequestsHTTPTransport( url = CF_URL + '/2.0/api/graphql', headers={'authorization': CF_API_KEY}, - verify=True, + verify=VERIFY, retries=3, ) client = Client(transport=transport, fetch_schema_from_transport=False) @@ -225,7 +233,7 @@ def execute_argocd_sync(ingress_host): transport = RequestsHTTPTransport( url=runtime_api_endpoint, headers={'authorization': CF_API_KEY}, - verify=True, + verify=VERIFY, retries=3, ) client = Client(transport=transport, fetch_schema_from_transport=False) @@ -236,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): @@ -251,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/requirements.txt b/incubating/argo-cd-sync/requirements.txt index 926e106b1..6d0b95f2b 100644 --- a/incubating/argo-cd-sync/requirements.txt +++ b/incubating/argo-cd-sync/requirements.txt @@ -7,5 +7,5 @@ idna==3.4 multidict==6.0.4 requests==2.28.2 requests-toolbelt==0.10.1 -urllib3==1.26.15 -yarl==1.8.2 +urllib3==1.26.16 +yarl==1.9.2 diff --git a/incubating/argo-cd-sync/step.yaml b/incubating/argo-cd-sync/step.yaml index a5065a626..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.3.1 + version: 1.4.2 isPublic: true description: Syncs Argo CD apps managed by our GitOps Runtimes sources: @@ -9,9 +9,9 @@ metadata: stage: incubating maintainers: - name: Francisco Cocozza - - email: francisco@codefresh.io + email: francisco@codefresh.io - name: Laurent Rochette - - email: laurent.rochette@codefresh.io + email: laurent.rochette@codefresh.io categories: - GitOps official: true @@ -99,6 +99,15 @@ spec: "description": "OPTIONAL - Wait for the app to be healthy after a rollback. Forces ROLLBACK to true", "default": false }, + "CA_BUNDLE": { + "type": "string", + "description": "OPTIONAL - a base64 encoded stringnthat contain the complete CA Certificate Bundle" + }, + "INSECURE": { + "type": "boolean", + "description": "OPTIONAL - to allow the usage of a self-signed certificate in the chain to reach the API endpoint", + "default": false + }, "LOG_LEVEL": { "type": "string", "description": "OPTIONAL - set the log level, e.g. 'debug', 'info', 'warn', 'error', 'critical' (default 'error')", @@ -111,7 +120,7 @@ spec: }, "IMAGE_TAG": { "type": "string", - "default": "1.3.1", + "default": "1.4.2", "description": "OPTIONAL - To overwrite the tag to use" } } @@ -145,8 +154,12 @@ spec: - '[[ $key ]]=[[ $val ]]' [[- end ]] commands: + [[ if .Arguments.CA_BUNDLE ]] + - echo [[ .Arguments.CA_BUNDLE ]] | base64 -d >/root/bundle.pem + [[ end ]] - cd /app - python3 run.py + delimiters: left: '[[' right: ']]' 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/aws-sts-assume-role-with-web-identity/step.yaml b/incubating/aws-sts-assume-role-with-web-identity/step.yaml index b8a265d98..15311fa32 100644 --- a/incubating/aws-sts-assume-role-with-web-identity/step.yaml +++ b/incubating/aws-sts-assume-role-with-web-identity/step.yaml @@ -1,7 +1,7 @@ version: '1.0' kind: step-type metadata: - version: 1.0.0 + version: 1.2.0 name: aws-sts-assume-role-with-web-identity description: >- Obtain AWS STS credentials using OIDC ID token and export them as environment variables diff --git a/incubating/git-commit/step.yaml b/incubating/git-commit/step.yaml index 3295b36b1..428b60391 100644 --- a/incubating/git-commit/step.yaml +++ b/incubating/git-commit/step.yaml @@ -2,7 +2,7 @@ kind: step-type version: '1.0' metadata: name: git-commit - version: 0.1.2 + version: 0.1.3 isPublic: true description: Commit and push changes to repository icon: @@ -144,7 +144,7 @@ spec: steps: export_access_token: title: "Export git access token" - image: quay.io/codefreshplugins/cli + image: quay.io/codefresh/cli:0.87.2 environment: - GIT_INTEGRATION_NAME=${{git}} - ALLOW_EMPTY_BOOL=${{allow_empty}} @@ -165,7 +165,7 @@ spec: commit_and_push: title: "Commit and push" - image: codefreshplugins/git-commit:0.1.0 + image: codefreshplugins/git-commit:0.1.3 shell: bash environment: - REPO=${{repo}} 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 000000000..e93cda3fc Binary files /dev/null and b/incubating/kubescape/icon.png differ 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: ']]' diff --git a/incubating/newrelic-deployment-marker/step.yaml b/incubating/newrelic-deployment-marker/step.yaml index 6247bbdca..afae7cea9 100644 --- a/incubating/newrelic-deployment-marker/step.yaml +++ b/incubating/newrelic-deployment-marker/step.yaml @@ -2,7 +2,7 @@ version: '1.0' kind: step-type metadata: name: newrelic-deployment-marker - version: 1.0.0 + version: 1.0.1 isPublic: true description: Createa a new deployment marker in New Relic. sources: @@ -18,7 +18,7 @@ metadata: - notifications icon: type: svg - url: https://newrelic.com/themes/custom/curio/assets/mediakit/NR_logo_Horizontal.svg + url: https://newrelic.com/themes/custom/erno/assets/mediakit/new_relic_logo_horizontal.svg background: '#f4f4f4' examples: - description: example-1 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 diff --git a/incubating/obtain-oidc-id-token/step.yaml b/incubating/obtain-oidc-id-token/step.yaml index f3d398a62..61fcd73bb 100644 --- a/incubating/obtain-oidc-id-token/step.yaml +++ b/incubating/obtain-oidc-id-token/step.yaml @@ -1,7 +1,7 @@ version: '1.0' kind: step-type metadata: - version: 1.0.0 + version: 1.2.1 name: obtain-oidc-id-token description: >- Obtain ID token from Codefresh OIDC Provider @@ -25,7 +25,7 @@ metadata: url: https://raw.githubusercontent.com/codefresh-io/steps/master/incubating/obtain-oidc-id-token/icon.svg background: '#f4f4f4' examples: - - description: example-with-print-output + - description: example-basic workflow: version: '1.0' steps: @@ -38,6 +38,21 @@ metadata: commands: - echo $ID_TOKEN - echo ${{steps.obtain_id_token.output.ID_TOKEN}} + - description: example-with-custom-audience + workflow: + version: '1.0' + steps: + obtain_id_token: + title: Obtain ID Token + type: obtain-oidc-id-token + arguments: + AUDIENCE: https://my-audience.com + print_output: + title: Printing output from previous step + image: alpine + commands: + - echo $ID_TOKEN + - echo ${{steps.obtain_id_token.output.ID_TOKEN}} - description: example-with-aws-sts-assume-role-step workflow: version: '1.0' @@ -57,6 +72,21 @@ metadata: commands: - aws s3 ls "s3://bucket-name/" spec: + arguments: |- + { + "definitions": {}, + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": false, + "patterns": [], + "required": [], + "properties": { + "AUDIENCE": { + "type": "string", + "description": "the audience of the ID token. For multiple audiences, use a comma-separated list. Defaults to the address of the Codefresh platform instance (For SaaS, https://g.codefresh.io)" + } + } + } returns: |- { "definitions": {}, @@ -77,8 +107,28 @@ spec: steps: main: name: obtain-oidc-id-token - image: dwdraju/alpine-curl-jq + image: quay.io/curl/curl-base + environment: + - 'AUDIENCE=${{AUDIENCE}}' commands: - | - ID_TOKEN=$(curl -H "Authorization: $CF_OIDC_REQUEST_TOKEN" "$CF_OIDC_REQUEST_URL" | jq -r ".id_token") + apk add jq + + URL="$CF_OIDC_REQUEST_URL" + + # This means that audience was provided by the user + if [ -z "$(echo "$AUDIENCE" | grep '${{AUDIENCE')" ]; then + ENCODED_AUDIENCE=$(echo -n "$AUDIENCE" | jq -s -R -r '@uri') + URL="$URL?audience=$ENCODED_AUDIENCE" + fi + + RESPONSE=$(curl -H "Authorization: $CF_OIDC_REQUEST_TOKEN" "$URL") + ID_TOKEN=$(echo "$RESPONSE" | jq -r ".id_token") + + if [ -z "$ID_TOKEN" ] || [ "$ID_TOKEN" = "null" ]; then + echo "Failed to obtain ID token; API response:" + echo "$RESPONSE" + exit 1 + fi + cf_export ID_TOKEN=$ID_TOKEN --mask