# file : brep/handler/submit/submit-git.bash.in # license : MIT; see accompanying LICENSE file # Utility functions for the submit-git handler. if [ "$brep_handler_submit_git" ]; then return 0 else brep_handler_submit_git=true fi @import brep/handler/handler@ @import brep/handler/submit/submit@ # If the section is mapped to a directory in the repository configuration then # return this directory path and empty string otherwise. # function section_dir () #
{ trace_func "$@" local sec="$1" local rep="$2" local owners # Unused but is declared to avoid polluting the global space. local -A sections run source "$rep/submit.config.bash" local r="${sections[$sec]}" if [ -z "$r" ]; then r="${sections['*']}" fi echo "$r" } # If the owners directory is set in the repository configuration then return # this directory path prefixed with the repository directory path and the # empty string otherwise. # function owners_dir () # { local rep="$1" local owners local -A sections # Is declared to avoid polluting the global space. run source "$rep/submit.config.bash" local r= if [ -n "$owners" ]; then r="$rep/$owners" fi echo "$r" } # Check if a repository already contains the package. Respond with the # 'duplicate submission' result manifest and exit if that's the case. # function check_package_duplicate () # { trace_func "$@" local nam="$1" local ver="$2" local rep="$3" local owners # Unused but is declared to avoid polluting the global space. local -A sections run source "$rep/submit.config.bash" # Check for duplicate package in all sections. Use -.* # without .tar.gz in case we want to support more archive types later. # local s for s in "${!sections[@]}"; do local p IFS=$'\n' eval \ 'p=($(run pkg_find_archive "$nam-$ver.*" "$rep/${sections[$s]}"))' if [ "${#p[@]}" -ne 0 ]; then local n="${p[0]}" local v="${p[1]}" trace "found: $n/$v in ${p[3]}" if [ "$n" == "$nam" ]; then exit_with_manifest 422 "duplicate submission" else exit_with_manifest 422 "submission conflicts with $n/$v" fi fi done } # Serialize the project or package owner manifest (they have the same set of # values) to the specified manifest file. # function create_owner_manifest () # { # trace_func "$@" local nam="$1" local anm="$2" local aem="$3" local ctl="$4" local man="$5" if [ -f "$man" ]; then error "'$man' already exists" fi manifest_serializer_start "$man" manifest_serialize "" "1" # Start of manifest. manifest_serialize "name" "$nam" manifest_serialize "author-name" "$anm" manifest_serialize "author-email" "$aem" manifest_serialize "control" "$ctl" manifest_serializer_finish } # Strip the query part and the leaf path component from the repository URL. # The resulting URL contains the trailing slash. # function repository_base () # { # First, strip the URL query part, then component. # sed -n -r -e 's%^([^?]*).*$%\1%' -e 's%^(.*/)[^/]+/?$%\1%p' <<<"$1" } # Authenticate the project name owner. Make sure that the control manifest # value is specified unless authentication is disabled. # # Possible return values: # # - 'project' if the project belongs to the submitter # - 'unknown' if the project name is not yet known # - 'disabled' if the owners directory is not configured # - result manifest describing the authentication error # # Note that the authentication error result always starts with ':'. # function auth_project () # { trace_func "$@" local prj="$1" local ctl="$2" local rep="$3" local d d="$(owners_dir "$rep")" if [ -z "$d" ]; then echo "disabled" return fi if [ -z "$ctl" ]; then exit_with_manifest 400 "control manifest value expected" fi local r="unknown" local m="$d/$prj/project-owner.manifest" # If the project owner manifest exists then parse it and try to authenticate # the submitter as the project owner. # if [ -f "$m" ]; then # Parse the project owner manifest. # manifest_parser_start "$m" local n v while IFS=: read -ru "$manifest_parser_ofd" -d '' n v; do if [[ "$n" == "control" && "$ctl" == "$v"* ]]; then r="project" break fi done manifest_parser_finish if [ "$r" != "project" ]; then exit_with_manifest 401 "project owner authentication failed" fi fi echo "$r" } # Authenticate the package name owner. Make sure that the control manifest # value is specified unless authentication is disabled. It is assumed that the # project ownership is already authenticated (possibly by another repository). # # Possible return values: # # - 'package' if the package belongs to the submitter # - 'unknown' if the package name is not taken in the project # - 'disabled' if the owners directory is not configured # - result manifest describing the authentication error # # Note that the authentication error result always starts with ':'. # function auth_package () # { trace_func "$@" local prj="$1" local pkg="$2" local ctl="${3%.git}" # Strip the potential .git extension. local rep="$4" local d d="$(owners_dir "$rep")" if [ -z "$d" ]; then echo "disabled" return fi if [ -z "$ctl" ]; then exit_with_manifest 400 "control manifest value expected" fi local r="unknown" local m="$d/$prj/$pkg/package-owner.manifest" # If the package owner manifest exists then parse it and try to authenticate # the submitter as the package owner. # if [ -f "$m" ]; then # Parse the package owner manifest. # manifest_parser_start "$m" # Match the control URL without regards to the potential .git extension. # local n v while IFS=: read -ru "$manifest_parser_ofd" -d '' n v; do if [ "$n" == "control" -a "${v%.git}" == "$ctl" ]; then r="package" break fi done manifest_parser_finish if [ "$r" != "package" ]; then exit_with_manifest 401 "package owner authentication failed" fi fi echo "$r" } # Check that the package name is unknown to the repository. Owners directory # is expected to be configured. # function auth_package_unknown () # { trace_func "$@" local pkg="$1" local rep="$2" local d d="$(owners_dir "$rep")" # Sanity check that the owners directory configured for the repository. # if [ -z "$d" ]; then error "no owners directory configured for '$rep'" fi # While configured, the owners directory may not yet exist. # if [ -d "$d" ]; then local f f="$(run find "$d" -path "$d/*/$pkg/package-owner.manifest")" if [ -n "$f" ]; then trace "found: $f" exit_with_manifest 401 "package owner authentication failed" fi fi } # Return lower-case URL scheme or empty string if the argument doesn't look # like a URL. # function url_scheme () # { sed -n -re 's%^(.*)://.*$%\L\1%p' <<<"$1" } # Check that the repository properly responds to the probing request before # the timeout (in seconds). Noop for protocols other than HTTP(S). # # If the repository is other than ours (e.g., control) then don't log a # failure and respond with the 422 (client) rather than 503 (server) HTTP # error. # function check_connectivity () # { trace_func "$@" local url="$1" local tmo="$2" local our="$3" local s s="$(url_scheme "$url")" if [ "$s" == "http" -o "$s" == "https" ]; then local u q u="$(sed -n -re 's%^([^?]*).*$%\1%p' <<<"$url")" # Strips query part. q="$(sed -n -re 's%^[^?]*(.*)$%\1%p' <<<"$url")" # Query part. if [ -z "$q" ]; then u="$u/info/refs?service=git-upload-pack" else u="$u/info/refs$q&service=git-upload-pack" fi local cmd=(curl -S -s --max-time "$tmo" "$u") if [ "$our" ]; then if ! run "${cmd[@]}" >/dev/null; then exit_with_manifest 503 "submission service temporarily unavailable" fi elif ! run_silent "${cmd[@]}" >/dev/null; then exit_with_manifest 422 "repository $url unavailable" fi fi }