Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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."
7 changes: 6 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
73 changes: 73 additions & 0 deletions pull-secrets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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#*<<}"
Comment on lines +64 to +66

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse heredoc syntax only before the value

When Vault returns a valid single-line env-file entry whose secret value contains << (for example TOKEN=abc<<def), GitHub still treats it as the documented name=value form, but this parser enters the multiline branch, turns the key into TOKEN=abc, and consumes following lines until def. That makes secrets_json omit or corrupt this and subsequent secrets even though they are correctly appended to GITHUB_ENV; the multiline check should only match the NAME<<DELIMITER header form, not any occurrence of << in the line.

Useful? React with 👍 / 👎.

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
Expand All @@ -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"

Expand Down Expand Up @@ -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"