diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9a60d04..0ef88fe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,14 +23,21 @@ jobs: steps: - uses: actions/checkout@v5 - - uses: ./ + - id: vault + uses: ./ with: secrets: vault-pull-secrets.test_variable - name: Verify test variable + env: + OUTPUT_TEST_VARIABLE: ${{ fromJSON(steps.vault.outputs.secrets_json).TEST_VARIABLE }} run: | if [ "${TEST_VARIABLE:-}" != "$EXPECTED_TEST_VARIABLE" ]; then echo "TEST_VARIABLE did not match the expected canary value." >&2 exit 1 fi + if [ "${OUTPUT_TEST_VARIABLE:-}" != "$EXPECTED_TEST_VARIABLE" ]; then + echo "secrets_json did not include the expected canary value." >&2 + exit 1 + fi echo "TEST_VARIABLE matched the expected canary value." diff --git a/action.yml b/action.yml index 59d202d..cd8798a 100644 --- a/action.yml +++ b/action.yml @@ -15,10 +15,15 @@ inputs: description: Expected OIDC audience configured by Vault. required: false default: gaucho-racing-vault +outputs: + secrets_json: + description: JSON object of exported environment variable names to secret values. + value: ${{ steps.pull-secrets.outputs.secrets_json }} runs: using: composite steps: - - shell: bash + - id: pull-secrets + shell: bash env: VAULT_URL: ${{ inputs.vault_url }} VAULT_SECRETS: ${{ inputs.secrets }} diff --git a/pull-secrets.sh b/pull-secrets.sh index bb77faf..70e679b 100755 --- a/pull-secrets.sh +++ b/pull-secrets.sh @@ -55,6 +55,71 @@ mask_env_file_values() { done < "$env_file" } +env_file_to_json() { + local env_file="$1" + local line delimiter name value has_value + local json="{}" + + while IFS= read -r line || [ -n "$line" ]; do + if [[ "$line" == *"<<"* ]]; then + name="${line%%<<*}" + delimiter="${line#*<<}" + value="" + has_value=false + + while IFS= read -r line; do + if [[ "$line" == "$delimiter" ]]; then + break + fi + if [[ "$has_value" == true ]]; then + value+=$'\n' + fi + value+="$line" + has_value=true + done + + json="$(jq -c --arg name "$name" --arg value "$value" '. + {($name): $value}' <<< "$json")" + elif [[ "$line" == *=* ]]; then + name="${line%%=*}" + value="${line#*=}" + json="$(jq -c --arg name "$name" --arg value "$value" '. + {($name): $value}' <<< "$json")" + fi + done < "$env_file" + + printf '%s' "$json" +} + +output_delimiter() { + local name="$1" + local value="$2" + local prefix delimiter suffix + + prefix="${name^^}" + prefix="${prefix//[!A-Z0-9_]/_}" + delimiter="VAULT_OUTPUT_${prefix}_EOF" + suffix=1 + + while [[ "$value" == *"$delimiter"* ]]; do + delimiter="VAULT_OUTPUT_${prefix}_EOF_${suffix}" + suffix=$((suffix + 1)) + done + + printf '%s' "$delimiter" +} + +write_multiline_output() { + local name="$1" + local value="$2" + local delimiter + + delimiter="$(output_delimiter "$name" "$value")" + { + printf '%s<<%s\n' "$name" "$delimiter" + printf '%s\n' "$value" + printf '%s\n' "$delimiter" + } >> "$GITHUB_OUTPUT" +} + if [ -z "${VAULT_URL:-}" ]; then echo "vault_url is required." >&2 exit 1 @@ -75,6 +140,11 @@ if [ -z "${GITHUB_ENV:-}" ]; then exit 1 fi +if [ -z "${GITHUB_OUTPUT:-}" ]; then + echo "GITHUB_OUTPUT is unavailable." >&2 + exit 1 +fi + vault_base_url="${VAULT_URL%/}" vault_api_url="${vault_base_url%/api}/api" @@ -120,5 +190,8 @@ if [[ "$status_code" -lt 200 || "$status_code" -ge 300 ]]; then fi mask_env_file_values "$response_file" +secrets_json="$(env_file_to_json "$response_file")" +add_mask "$secrets_json" +write_multiline_output "secrets_json" "$secrets_json" cat "$response_file" >> "$GITHUB_ENV" rm -f "$response_file"