With:
curl_version="$(command curl --version | awk 'NR==1 {print $2}')" declare -r curl_version
within a function, you're setting the $curl_version global variable to some value and then creating a separate local and readonly variable which is initially unset.
It looks like you want:
# instantiate a new local variable (but in bash it inherits the "export"
# attribute if any of the variable with same name in the parent scope)
local curl_version
# unset to remove that export attribute if any. Though you could
# also change the above to local +x curl_version
unset -v curl_version
# give a value:
curl_version="$(command curl --version | awk 'NR==1 {print $2}')"
# make that local variable read only
local -r curl_version
(here using local instead of declare to make it clearer that you want to make the variable local¹).
Or do all at the same time with:
local +x -r curl_version="$(command curl --version | awk '{print $2; exit}')"
(though as noted by shellcheck, you then lose the exit status of the pipeline²).
In any case, I wouldn't use readonly / typeset -r in shells like you would use const in C especially in bash. Shells (other than ksh93) don't have static scoping like in C. And in bash (contrary to zsh for instance), you can't create a variable local to a function if it has been made readonly in the global scope.
For instance:
count() {
local n
for (( n = 0; n < $1; n++ )) { echo "$n"; }
}
readonly n=5
count "$n"
would work in zsh but not in bash. It may be OK if you only use local -r and never readonly.
¹ in any case typeset / declare / local are all the same in bash, the only difference being that if you try to use local outside of a function, it reports an error. The difference between typeset -r and readonly (same as between typeset -x and export) being that the latter doesn't instantiate a new variable if called within a function.
² See how with that exit in awk in that version for awk to stop processing the input after the first line, curl could be killed with a SIGPIPE (very unlikely in practice as curl would send its output in one go and it would fit in the pipe) and because of pipefail, the pipeline could end up failing with 141 exit status, but local itself would still succeed as long as it can assign a value to the variable.