#!/usr/bin/env bash
# Generated by StackToIT from execution-plan.json. StackToIT has not run this script and runs none.
# Action: API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db
# Call: secrets-manager-vault v1, operation WriteSecret (POST /v1/{instanceId}/data/{path})
# Request: 004-writesecret.json (this script is a rendering of it)
# Idempotency: READ_BEFORE_CREATE. Authorisation: the username and password of a Secrets Manager user of the instance with write access (the stackit_secretsmanager_user the draft creates, write_enabled = true), which the script exchanges for a token (login) and sends as X-Vault-Token.
# Expected response: HTTP 200 (the script stops (exit 7) when the answer has another status).
# Step state: generated, tested offline. A test of StackToIT ran a script of this call under a real shell against a local stub that answers as the API is documented to; it was not run against the live STACKIT API.
# Operator checks before running: (1) the endpoint: STACKIT_API_URL_SECRETS_MANAGER_VAULT, https://prod.sm.eu01.stackit.cloud when it is not set; (2) the project: the Secrets Manager instance (instanceId) and the user of the call are those the draft creates in the target project (the call carries no project id: the instance id names the instance); (3) the read before the write: what the read before the write finds (ReadSecret): a secret that already has a current version stops the script unless STACKIT_CONFIRM_REPLACE names it, so read what it reports.
set -euo pipefail

printf '%s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db is blocked: it waits for the decision DEC-GEN-CONVERT-API-OPT-IN. Answer the decision and generate the package again; nothing was called.' >&2
exit 3
# The call logs in as the Secrets Manager user of the draft (its username and password are inputs of this script), not with a STACKIT access token.
base="${STACKIT_API_URL_SECRETS_MANAGER_VAULT:-https://prod.sm.eu01.stackit.cloud}"
case "$base" in https://*) ;; *)
  printf '%s\n' 'The base address in STACKIT_API_URL_SECRETS_MANAGER_VAULT is not an https address. Nothing was called.' >&2
  exit 5;;
esac
case "${base#https://}" in ''|*[!A-Za-z0-9.:/_~-]*)
  printf '%s\n' 'The base address in STACKIT_API_URL_SECRETS_MANAGER_VAULT holds a character an address of the call cannot (only letters, digits and . : / _ ~ -). Nothing was called.' >&2
  exit 5;;
esac
if [ -n "${STACKIT_CA_BUNDLE:-}" ] && [ ! -f "$STACKIT_CA_BUNDLE" ]; then
  printf '%s\n' 'STACKIT_CA_BUNDLE is not a file. Nothing was called.' >&2
  exit 5
fi
call_timeout="${STACKIT_CALL_TIMEOUT_SECONDS:-120}"
case "$call_timeout" in ''|*[!0-9]*)
  printf '%s\n' 'STACKIT_CALL_TIMEOUT_SECONDS is no whole number of seconds. Nothing was called.' >&2
  exit 5;;
esac
if [ "${#call_timeout}" -gt 4 ] || [ "$call_timeout" -lt 1 ] || [ "$call_timeout" -gt 3600 ]; then
  printf '%s\n' 'STACKIT_CALL_TIMEOUT_SECONDS is not between 1 and 3600 seconds. Nothing was called.' >&2
  exit 5
fi
if ! command -v jq >/dev/null 2>&1; then
  printf '%s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db reads JSON with jq, which is not installed. Nothing was called.' >&2
  exit 5
fi
here="${BASH_SOURCE[0]%/*}"
if [ "$here" = "${BASH_SOURCE[0]}" ]; then here=.; fi
if [ -z "${STACKIT_INPUT_INSTANCEID:-}" ] && command -v tofu >/dev/null 2>&1; then
  tofu_out="$(tofu -chdir="$here/../../../terraform" output -no-color -raw stackit_secretsmanager_instance_migrated_secrets_instance_id 2>/dev/null)" || tofu_out=''
  case "$tofu_out" in ''|*[!A-Za-z0-9._~:@/+=-]*) tofu_out='';; esac
  if [ -n "$tofu_out" ]; then
    STACKIT_INPUT_INSTANCEID="$tofu_out"
    printf '%s\n' 'The input instanceId is the output stackit_secretsmanager_instance_migrated_secrets_instance_id of the draft in terraform/, read with tofu output (set STACKIT_INPUT_INSTANCEID to use another value).'
  fi
fi
in_0="${STACKIT_INPUT_INSTANCEID:?set STACKIT_INPUT_INSTANCEID to the output TF/stackit_secretsmanager_instance.migrated_secrets#instance_id, or apply the draft in terraform/ so that tofu output -raw stackit_secretsmanager_instance_migrated_secrets_instance_id answers}"
in_1="${STACKIT_INPUT_SECRET_NAME_RETAIL_APP_ECS_ORDERS_DB:?set STACKIT_INPUT_SECRET_NAME_RETAIL_APP_ECS_ORDERS_DB to the path of the secret in the Secrets Manager instance (the source does not state it as a literal)}"
if [ -z "${STACKIT_INPUT_USERNAME:-}" ] && command -v tofu >/dev/null 2>&1; then
  tofu_out="$(tofu -chdir="$here/../../../terraform" output -no-color -raw stackit_secretsmanager_user_migration_username 2>/dev/null)" || tofu_out=''
  case "$tofu_out" in ''|*[!A-Za-z0-9._~:@/+=-]*) tofu_out='';; esac
  if [ -n "$tofu_out" ]; then
    STACKIT_INPUT_USERNAME="$tofu_out"
    printf '%s\n' 'The input username is the output stackit_secretsmanager_user_migration_username of the draft in terraform/, read with tofu output (set STACKIT_INPUT_USERNAME to use another value).'
  fi
fi
in_2="${STACKIT_INPUT_USERNAME:?set STACKIT_INPUT_USERNAME to the output TF/stackit_secretsmanager_user.migration#username, or apply the draft in terraform/ so that tofu output -raw stackit_secretsmanager_user_migration_username answers}"
if [ -z "${STACKIT_INPUT_PASSWORD:-}" ] && command -v tofu >/dev/null 2>&1; then
  tofu_secret="$(tofu -chdir="$here/../../../terraform" output -no-color -json stackit_secretsmanager_user_migration_password 2>/dev/null | jq -er 'select(type == "string" and length > 0)' 2>/dev/null)" || tofu_secret=''
  if [ -n "$tofu_secret" ]; then
    STACKIT_INPUT_PASSWORD="${tofu_secret}"
    unset tofu_secret
    printf '%s\n' 'The input password is the sensitive output stackit_secretsmanager_user_migration_password of the draft in terraform/, read with tofu output (it is not printed; set STACKIT_INPUT_PASSWORD to use another value).'
  fi
fi
in_3="${STACKIT_INPUT_PASSWORD:?set STACKIT_INPUT_PASSWORD to the output TF/stackit_secretsmanager_user.migration#password, or apply the draft in terraform/ so that tofu output -json stackit_secretsmanager_user_migration_password answers}"
in_4="${STACKIT_INPUT_SECRET_DOCUMENT_RETAIL_APP_ECS_ORDERS_DB:?set STACKIT_INPUT_SECRET_DOCUMENT_RETAIL_APP_ECS_ORDERS_DB to the file that holds the JSON object of key/value pairs this step writes as the secret (the risks of the step say what it is)}"
case "$in_0" in ''|*[!A-Za-z0-9._~-]*)
  printf '%s\n' 'The input instanceId is empty or holds a character a segment of the path cannot (only letters, digits and . _ ~ -). Nothing was called.' >&2
  exit 5;;
esac
case "$in_1" in ''|*[!A-Za-z0-9._~/-]*|/*|*/|*//*|.|..|./*|../*|*/.|*/..|*/./*|*/../*)
  printf '%s\n' 'The input path is empty or is no path of plain segments (letters, digits and . _ ~ - separated by single slashes, no segment . or ..). Nothing was called.' >&2
  exit 5;;
esac
tmp="$(mktemp -d)"
trap 'rm -rf -- "$tmp"' EXIT
doc="$in_4"
if [ ! -f "$doc" ] || [ ! -r "$doc" ]; then
  printf '%s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db: STACKIT_INPUT_SECRET_DOCUMENT_RETAIL_APP_ECS_ORDERS_DB must name a readable file that holds the document of key/value pairs of the secret. Nothing was called.' >&2
  exit 5
fi
if ! jq -e 'type == "object" and length > 0' "$doc" >/dev/null 2>&1; then
  printf '%s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db: the file named by STACKIT_INPUT_SECRET_DOCUMENT_RETAIL_APP_ECS_ORDERS_DB is not a JSON object with at least one key. The document is the key/value pairs of the secret, for example {"username": "<the user name>", "password": "<the password>"}. Nothing was called.' >&2
  exit 5
fi
url="${base%/}/v1/${in_0}/data/${in_1}"
login_url="${base%/}/v1/auth/userpass/login/${in_2}"
# the token and the password are in shell variables and on pipes only; no value of the document is printed
: > "$tmp/login"
status="$(printf '%s' "$in_3" | jq -Rsc '{password: .}' | curl ${STACKIT_CA_BUNDLE:+--cacert "$STACKIT_CA_BUNDLE"} --connect-timeout 30 --max-time "$call_timeout" --silent --show-error --output "$tmp/login" --write-out '%{http_code}' --request POST --header 'Content-Type: application/json' --header 'Expect:' --data-binary @- -- "$login_url")"
if [ "$status" != 200 ]; then
  printf '%s HTTP %s%s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db: the login of the Secrets Manager user answered' "$status" '; nothing was written. Check that the username and the password are those of the stackit_secretsmanager_user of the draft and that the user still exists.' >&2
  case "$status" in 2[0-9][0-9]) ;; *) printf 'The answer: %s\n' "$(head -c 2000 "$tmp/login")" >&2;; esac
  exit 7
fi
if ! vault_token="$(jq -er '.auth.client_token | select(type == "string" and length > 0)' "$tmp/login" 2>/dev/null)"; then
  printf '%s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db: the login answered HTTP 200 without auth.client_token, so the token for the next requests is not known. Nothing was written.' >&2
  exit 7
fi
rm -f -- "$tmp/login"
# ReadSecret before the write: 200 is a secret with a current version, 404 one without. The answer holds the values and is not stored.
status="$(printf 'X-Vault-Token: %s\n' "$vault_token" | curl ${STACKIT_CA_BUNDLE:+--cacert "$STACKIT_CA_BUNDLE"} --connect-timeout 30 --max-time "$call_timeout" --silent --show-error --output /dev/null --write-out '%{http_code}' --request GET --header @- -- "$url")"
case "$status" in
  200) exists=1;;
  404) exists=0;;
  *)
    printf '%s HTTP %s%s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db: the read ReadSecret answered' "$status" '; whether the secret has a current version is not known. Nothing was written.' >&2
    exit 6;;
esac
if [ "$exists" = 1 ]; then
  if [ "${STACKIT_CONFIRM_REPLACE:-}" != "$in_1" ]; then
    printf '%s %s %s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db: the secret' "$in_1" 'already has a current version in the instance. This step writes a new version, which becomes the current one (how many earlier versions are kept is the version limit of the instance). Nothing was written. If the secret may get a new version, set STACKIT_CONFIRM_REPLACE to the path of the secret and run the script again.' >&2
    exit 4
  fi
  printf '%s %s %s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db: the secret' "$in_1" 'has a current version; STACKIT_CONFIRM_REPLACE names it, so a new version is written.'
fi
jq -c '{data: .}' "$doc" > "$tmp/payload" 2>/dev/null
: > "$tmp/write"
status="$(printf 'X-Vault-Token: %s\n' "$vault_token" | curl ${STACKIT_CA_BUNDLE:+--cacert "$STACKIT_CA_BUNDLE"} --connect-timeout 30 --max-time "$call_timeout" --silent --show-error --output "$tmp/write" --write-out '%{http_code}' --request POST --header @- --header 'Content-Type: application/json' --header 'Expect:' --data-binary @"$tmp/payload" -- "$url")"
if [ "$status" != 200 ]; then
  printf '%s HTTP %s%s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db: the call WriteSecret answered' "$status" '; the plan expects HTTP 200. The request was sent: check the target (read that the secret has a current version) before running this script again.' >&2
  case "$status" in 2[0-9][0-9]) ;; *) printf 'The answer: %s\n' "$(head -c 2000 "$tmp/write")" >&2;; esac
  exit 7
fi
rm -f -- "$tmp/payload" "$tmp/write"
# the postcondition: the secret has a current version now (ReadSecret answers 200); the values are not read
status="$(printf 'X-Vault-Token: %s\n' "$vault_token" | curl ${STACKIT_CA_BUNDLE:+--cacert "$STACKIT_CA_BUNDLE"} --connect-timeout 30 --max-time "$call_timeout" --silent --show-error --output /dev/null --write-out '%{http_code}' --request GET --header @- -- "$url")"
if [ "$status" != 200 ]; then
  printf '%s HTTP %s%s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db: after the write, the read ReadSecret answered' "$status" '; the secret should have a current version. The write was made: check the target before running this script again.' >&2
  exit 8
fi
printf '%s %s %s\n' 'Step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db: the call WriteSecret answered HTTP 200 and the secret' "$in_1" 'has a current version. The values were not printed or read back.'
