mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-01 21:10:13 +00:00
Harden PVE setup token extraction (#1312)
This commit is contained in:
parent
c12f5fb5a4
commit
4d4344911a
2 changed files with 100 additions and 4 deletions
|
|
@ -4308,6 +4308,66 @@ resolve_setup_auth_token() {
|
|||
fi
|
||||
}
|
||||
|
||||
extract_json_string_field() {
|
||||
local json_input="$1"
|
||||
local field_name="$2"
|
||||
|
||||
printf '%%s\n' "$json_input" | sed -n 's/.*"'$field_name'"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1
|
||||
}
|
||||
|
||||
extract_pve_token_value() {
|
||||
local token_output="$1"
|
||||
local token_value=""
|
||||
|
||||
token_value=$(extract_json_string_field "$token_output" "value")
|
||||
if [ -n "$token_value" ]; then
|
||||
printf '%%s\n' "$token_value"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf '%%s\n' "$token_output" | awk -F'[|│]' '
|
||||
function trim(value) {
|
||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
|
||||
return value
|
||||
}
|
||||
|
||||
{
|
||||
key = trim($2)
|
||||
value = trim($3)
|
||||
if (key == "value" && value != "") {
|
||||
print value
|
||||
exit
|
||||
}
|
||||
}
|
||||
'
|
||||
}
|
||||
|
||||
create_pve_token() {
|
||||
if TOKEN_OUTPUT=$(pveum user token add pulse-monitor@pam "$TOKEN_NAME" --privsep 0 --output-format json 2>&1); then
|
||||
TOKEN_CREATE_RC=0
|
||||
else
|
||||
TOKEN_CREATE_RC=$?
|
||||
fi
|
||||
|
||||
if [ "$TOKEN_CREATE_RC" -eq 0 ]; then
|
||||
TOKEN_VALUE=$(extract_pve_token_value "$TOKEN_OUTPUT")
|
||||
return 0
|
||||
fi
|
||||
|
||||
if echo "$TOKEN_OUTPUT" | grep -Eqi 'unknown option|unknown command|no such option|unable to parse option|output-format'; then
|
||||
if TOKEN_OUTPUT=$(pveum user token add pulse-monitor@pam "$TOKEN_NAME" --privsep 0 2>&1); then
|
||||
TOKEN_CREATE_RC=0
|
||||
else
|
||||
TOKEN_CREATE_RC=$?
|
||||
fi
|
||||
if [ "$TOKEN_CREATE_RC" -eq 0 ]; then
|
||||
TOKEN_VALUE=$(extract_pve_token_value "$TOKEN_OUTPUT")
|
||||
fi
|
||||
fi
|
||||
|
||||
return "$TOKEN_CREATE_RC"
|
||||
}
|
||||
|
||||
attempt_auto_registration() {
|
||||
resolve_setup_auth_token
|
||||
|
||||
|
|
@ -4407,8 +4467,7 @@ fi
|
|||
|
||||
if [ "$TOKEN_ROTATION_SKIPPED" != true ]; then
|
||||
# Create token and capture value (shown once by Proxmox)
|
||||
TOKEN_OUTPUT=$(pveum user token add pulse-monitor@pam "$TOKEN_NAME" --privsep 0 2>&1)
|
||||
TOKEN_CREATE_RC=$?
|
||||
create_pve_token
|
||||
if [ "$TOKEN_CREATE_RC" -ne 0 ]; then
|
||||
echo "❌ Failed to create token '$TOKEN_NAME'"
|
||||
echo "$TOKEN_OUTPUT"
|
||||
|
|
@ -4416,8 +4475,6 @@ if [ "$TOKEN_ROTATION_SKIPPED" != true ]; then
|
|||
echo "Manual registration may be required."
|
||||
echo ""
|
||||
else
|
||||
TOKEN_VALUE=$(echo "$TOKEN_OUTPUT" | grep "│ value" | awk -F'│' '{print $3}' | tr -d ' ' | tail -1)
|
||||
|
||||
if [ -z "$TOKEN_VALUE" ]; then
|
||||
echo ""
|
||||
echo "================================================================"
|
||||
|
|
|
|||
|
|
@ -67,6 +67,33 @@ echo "STATE AUTO_REG_SUCCESS=${AUTO_REG_SUCCESS} TOKEN_ROTATION_SKIPPED=${TOKEN_
|
|||
assertContains(t, trace, "pveum user token add pulse-monitor@pam pulse-sentinel-url --privsep 0")
|
||||
assertContains(t, trace, "curl -s -X POST")
|
||||
})
|
||||
|
||||
t.Run("json_output_auto_registers_without_legacy_fallback", func(t *testing.T) {
|
||||
output, trace := runSetupHarness(t, harness, mocks, map[string]string{
|
||||
"MOCK_PVE_TOKEN_FORMAT": "json",
|
||||
})
|
||||
|
||||
assertContains(t, output, "API token generated successfully")
|
||||
assertContains(t, output, "Node registered successfully")
|
||||
assertContains(t, output, "STATE AUTO_REG_SUCCESS=true TOKEN_ROTATION_SKIPPED=false TOKEN_VALUE=mocked-pve-secret")
|
||||
|
||||
assertContains(t, trace, "pveum user token add pulse-monitor@pam pulse-sentinel-url --privsep 0 --output-format json")
|
||||
assertNotContains(t, trace, "pveum user token add pulse-monitor@pam pulse-sentinel-url --privsep 0\n")
|
||||
})
|
||||
|
||||
t.Run("legacy_output_falls_back_when_json_format_is_unsupported", func(t *testing.T) {
|
||||
output, trace := runSetupHarness(t, harness, mocks, map[string]string{
|
||||
"MOCK_PVE_JSON_UNSUPPORTED": "1",
|
||||
})
|
||||
|
||||
assertContains(t, output, "API token generated successfully")
|
||||
assertContains(t, output, "Node registered successfully")
|
||||
assertContains(t, output, "STATE AUTO_REG_SUCCESS=true TOKEN_ROTATION_SKIPPED=false TOKEN_VALUE=mocked-pve-secret")
|
||||
|
||||
assertContains(t, trace, "pveum user token add pulse-monitor@pam pulse-sentinel-url --privsep 0 --output-format json")
|
||||
assertContains(t, trace, "pveum user token add pulse-monitor@pam pulse-sentinel-url --privsep 0")
|
||||
assertContains(t, trace, "curl -s -X POST")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetupScriptTokenLifecycleIntegration_PBS(t *testing.T) {
|
||||
|
|
@ -228,6 +255,18 @@ case "$*" in
|
|||
;;
|
||||
"user token remove pulse-monitor@pam pulse-sentinel-url")
|
||||
;;
|
||||
"user token add pulse-monitor@pam pulse-sentinel-url --privsep 0 --output-format json")
|
||||
if [ "${MOCK_PVE_JSON_UNSUPPORTED:-0}" = "1" ]; then
|
||||
echo "unknown option: output-format" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "${MOCK_PVE_TOKEN_FORMAT:-table}" = "json" ]; then
|
||||
echo '{"tokenid":"pulse-monitor@pam!pulse-sentinel-url","value":"mocked-pve-secret"}'
|
||||
exit 0
|
||||
fi
|
||||
# Some versions support the flag but still keep older text rendering in wrappers.
|
||||
printf '\342\224\202 value \342\224\202 mocked-pve-secret \342\224\202\n'
|
||||
;;
|
||||
"user token add pulse-monitor@pam pulse-sentinel-url --privsep 0")
|
||||
# Emit the box-drawing format parsed by the setup script (│ value │ secret │)
|
||||
printf '\342\224\202 value \342\224\202 mocked-pve-secret \342\224\202\n'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue