diff --git a/.gitattributes b/.gitattributes index efdba87..a64eec2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ * text=auto *.sh text eol=lf +*.bash-completion text eol=lf diff --git a/bash-completion/README.md b/bash-completion/README.md new file mode 100644 index 0000000..233e8fb --- /dev/null +++ b/bash-completion/README.md @@ -0,0 +1,82 @@ +# Автодополнение bash для `pkica` + +`pkica.bash-completion` — правила автодополнения (TAB) в bash для утилиты `pkica` +(командная строка управления инфраструктурой КриптоПро УЦ 2.0). + +## Установка + +Требуется пакет `bash-completion`. + +Для всех пользователей: + +```bash +sudo install -m 644 pkica.bash-completion /usr/share/bash-completion/completions/pkica +``` + +Для текущего пользователя: + +```bash +mkdir -p ~/.local/share/bash-completion/completions +cp pkica.bash-completion ~/.local/share/bash-completion/completions/pkica +``` + +Для текущей сессии: + +```bash +source pkica.bash-completion +``` + +После установки откройте новый терминал. Дополнение работает для `pkica` +из `PATH` и для запуска по пути (`./pkica`, `/opt/.../pkica`). + +## Что дополняется + +* команды и подкоманды всех уровней (`pkica ca signing-key change-usage`); +* опции текущей команды: после `-` — короткие и длинные, без `-` — только длинные. + Уже указанные опции (и их синонимы) повторно не предлагаются; +* значения опций с фиксированным набором значений: + +| Опция | Значения | +| --- | --- | +| `--format` | `Json`, `Yaml` | +| `-s`, `--storage-type` | `PostgreSql`, `SqlServer` | +| `--sign-tool-class` | `KC1` … `KA1` | +| `-k`, `--key-spec` | `Signature`, `KeyExchange` | +| `--key-location`, `--store-location` | `CurrentUser`, `LocalMachine` | +| `--store-name` | `My`, `Root`, `CertificateAuthority`, … | +| `--serial-number-algorithm` | `CryptoPro`, `Msca` | +| `-p`, `--provider-type` | `80`, `81` | +| `-u`, `--usage` (signing-key) | `SignCertAndCrl`, `SignCrl`, `Retired` | +| `-d`, `--default-template` | `SubCa`, `User`, `Tls`, `Ocsp`, `Tsp`, `Qual`, `QualOcsp`, `QualTsp` | +| `-v`, `--value` (identification-kind) | `Personal`, `RemoteCert`, `RemotePassport`, `RemoteSystem` | +| `-n`, `--name` (ra settings) | `NamePolicy`, `Templates`, `DefaultAuthority` | +| `-v`, `--validity`, `-V`, `--key-validity` | `Years:`, `Months:`, `Weeks:`, `Days:`, `Hours:`, `Minutes:` | + +* пути к файлам: `-f`/`--file`, `-o`/`--out-file`, `--extensions-file`, + `--tls-cert-file`, `--signing-cert-file`; каталоги: `-o`/`--output-folder` + (`ca crl get`, `ca crl issue`); +* поддерживается форма `--опция=значение`. + +Одна и та же короткая опция в разных командах может означать разное +(например, `-f` в `ra operator add` — это `--first-name`, а не файл) — это учитывается. + +## Ограничения + +* Утилита при дополнении не вызывается: дерево команд зашито в файл + (запуск .NET-приложения занимает заметное время). +* Имена экземпляров ЦС, шаблонов, папок, групп, операторов не дополняются — + для этого нужен доступ к БД. + +## Тесты + +Запуск в Linux или WSL из каталога `bash-completion`: + +```bash +bash tests/test_completion.sh # модульные тесты функции дополнения +bash tests/test_interactive.sh # реальный TAB в bash через tmux (нужен tmux) +bash tests/check_tree.sh [pkica] # сверка с выводом `pkica ... --help` +``` + +`check_tree.sh` рекурсивно обходит справку утилиты (без аргумента берётся `pkica` +из `PATH`) и сообщает о расхождениях команд и опций с таблицами в +`pkica.bash-completion`. Запускайте его после обновления `pkica`. diff --git a/bash-completion/pkica.bash-completion b/bash-completion/pkica.bash-completion new file mode 100644 index 0000000..3c3c1e6 --- /dev/null +++ b/bash-completion/pkica.bash-completion @@ -0,0 +1,251 @@ +# bash completion for pkica (КриптоПро УЦ: командная строка управления инфраструктурой УЦ) +# +# Установка: +# sudo install -m 644 pkica.bash-completion /usr/share/bash-completion/completions/pkica +# или для текущего пользователя: +# mkdir -p ~/.local/share/bash-completion/completions +# cp pkica.bash-completion ~/.local/share/bash-completion/completions/pkica +# или разово: +# source pkica.bash-completion +# +# Дерево команд и опций снято с `pkica ... --help`. Утилита при дополнении +# не вызывается (запуск .NET-приложения слишком медленный). + +# Подкоманды узлов дерева. Ключ - путь команды. +declare -gA _pkica_cmds=( + [pkica]="ca cert-registry ra" + [pkica ca]="authority cert cert-request crl db import-legacy issue-cert new-cert-req new-root-cert rev-request signing-key template" + [pkica ca authority]="export-settings import-settings list new remove set-default show" + [pkica ca cert]="get list" + [pkica ca cert-request]="get list" + [pkica ca crl]="get issue schedule" + [pkica ca crl schedule]="get update" + [pkica ca db]="info new upgrade" + [pkica ca rev-request]="get list" + [pkica ca signing-key]="add change-usage list load replace show unload" + [pkica ca template]="add encode-extension get list remove update" + [pkica ca template encode-extension]="certificate-template identification-kind" + [pkica cert-registry]="db import-legacy" + [pkica cert-registry db]="info new upgrade" + [pkica ra]="db folder group import-legacy operator permission settings" + [pkica ra db]="info new upgrade" + [pkica ra folder]="add delete get list rename" + [pkica ra group]="add add-operator get list remove-operator rename" + [pkica ra operator]="activate add deactivate get list update" + [pkica ra permission]="get grant revoke" + [pkica ra settings]="get set" +) + +# Опции команд. Синонимы разделены "|", "=" в конце - опция принимает значение. +# Для узлов, отсутствующих в таблице, используется "-h|--help". +declare -gA _pkica_opts=( + [pkica]="-v|--version -h|--help" + [pkica ca authority export-settings]="-n|--name= -f|--file= -h|--help --format=" + [pkica ca authority import-settings]="-n|--name= -f|--file= -h|--help --format=" + [pkica ca authority list]="-h|--help --format=" + [pkica ca authority new]="-n|--name= -h|--help" + [pkica ca authority remove]="-n|--name= -h|--help" + [pkica ca authority set-default]="-n|--name= --none -h|--help" + [pkica ca authority show]="-n|--name= -h|--help --format=" + [pkica ca cert get]="-i|--id= -s|--serial-number= -f|--file= --force -h|--help --format=" + [pkica ca cert list]="--from= --to= --take= --oldest-first -h|--help --format=" + [pkica ca cert-request get]="-i|--id= -f|--file= --force -h|--help --format=" + [pkica ca cert-request list]="--from= --to= --take= --oldest-first -h|--help --format=" + [pkica ca crl get]="-n|--name= -v|--valid-at= --all -o|--output-folder= --force -h|--help" + [pkica ca crl issue]="-n|--name= -d|--delta-only -u|--next-update= --final --key-index= -o|--output-folder= --force -h|--help" + [pkica ca crl schedule get]="-n|--name= -h|--help" + [pkica ca crl schedule update]="-n|--name= -b|--base= -d|--delta= -h|--help" + [pkica ca db info]="-h|--help --format=" + [pkica ca db new]="-s|--storage-type= -c|--connection-string= --command-timeout= -b|--begin-use-empty --force -h|--help" + [pkica ca db upgrade]="--command-timeout= -h|--help" + [pkica ca import-legacy]="-c|--connection-string= -t|--timeout= -h|--help" + [pkica ca issue-cert]="-f|--file= -o|--out-file= -n|--name= -t|--timeout= -h|--help" + [pkica ca new-cert-req]="-o|--out-file= -t|--template= --template-major-version= --template-minor-version= --is-ca --path-length= -i|--key-index= --subject-sign-tool= --sign-tool-class= --extensions-file= -s|--subject= -c|--container-name= --hash-algorithm= -l|--key-length= --use-existing-key -e|--exportable --prompt-for-media -p|--provider-type= -n|--provider-name= --pin= --no-pin -k|--key-spec= --key-location= --silent -h|--help" + [pkica ca new-root-cert]="-o|--out-file= -v|--validity= -V|--key-validity= --path-length= -i|--key-index= --extensions-file= --serial-number-algorithm= -s|--subject= -c|--container-name= --hash-algorithm= -l|--key-length= --use-existing-key -e|--exportable --prompt-for-media -p|--provider-type= -n|--provider-name= --pin= --no-pin -k|--key-spec= --key-location= --silent -h|--help" + [pkica ca rev-request get]="-i|--id= -f|--file= --force -h|--help --format=" + [pkica ca rev-request list]="--from= --to= --take= --oldest-first -h|--help --format=" + [pkica ca signing-key add]="-n|--name= -t|--thumbprint= --store-name= --store-location= -u|--usage= --hash-algorithm= --accept-new-subject --planned-key-change-date= --planned-retirement-date= --pin= --no-pin --skip-container-check -h|--help" + [pkica ca signing-key change-usage]="-n|--name= -i|--index= -u|--usage= --force -h|--help" + [pkica ca signing-key list]="-n|--name= -l|--loaded --status --timeout= -h|--help --format=" + [pkica ca signing-key load]="-n|--name= -i|--index= --pin= --no-pin -u|--usage= -h|--help" + [pkica ca signing-key replace]="-n|--name= -i|--index= -t|--thumbprint= --store-name= --store-location= --hash-algorithm= --accept-new-subject --planned-key-change-date= --planned-retirement-date= --pin= --no-pin --skip-container-check -h|--help" + [pkica ca signing-key show]="-n|--name= -i|--index= --status --timeout= -h|--help --format=" + [pkica ca signing-key unload]="-n|--name= -i|--index= -h|--help" + [pkica ca template add]="-f|--file= -d|--default-template= -h|--help" + [pkica ca template encode-extension certificate-template]="-n|--name= -f|--file= --force -h|--help" + [pkica ca template encode-extension identification-kind]="-v|--value= -f|--file= --force -h|--help" + [pkica ca template get]="-n|--name= -f|--file= -h|--help" + [pkica ca template list]="-f|--file= -d|--detailed -h|--help --format=" + [pkica ca template remove]="-n|--name= -h|--help" + [pkica ca template update]="-f|--file= -d|--default-template= -h|--help" + [pkica cert-registry db info]="-h|--help --format=" + [pkica cert-registry db new]="-s|--storage-type= -c|--connection-string= --command-timeout= -b|--begin-use-empty --force -h|--help" + [pkica cert-registry db upgrade]="--command-timeout= -h|--help" + [pkica cert-registry import-legacy]="-c|--connection-string= -t|--timeout= -h|--help" + [pkica ra db info]="-h|--help --format=" + [pkica ra db new]="-s|--storage-type= -c|--connection-string= --command-timeout= -b|--begin-use-empty --force -h|--help" + [pkica ra db upgrade]="--command-timeout= -h|--help" + [pkica ra folder add]="-n|--name= -h|--help" + [pkica ra folder delete]="-n|--name= -h|--help" + [pkica ra folder get]="-n|--name= -h|--help --format=" + [pkica ra folder list]="-h|--help --format=" + [pkica ra folder rename]="-n|--name= --new-name= -h|--help" + [pkica ra group add]="-n|--name= -h|--help" + [pkica ra group add-operator]="-n|--name= -l|--login= -h|--help" + [pkica ra group get]="-n|--name= -h|--help --format=" + [pkica ra group list]="-h|--help --format=" + [pkica ra group remove-operator]="-n|--name= -l|--login= -h|--help" + [pkica ra group rename]="-n|--name= --new-name= -h|--help" + [pkica ra import-legacy]="-c|--connection-string= -l|--login= --folder-id= --include-subfolders --skip-empty-users --skip-revoked-certs --skip-expired-certs -t|--timeout= -h|--help" + [pkica ra operator activate]="--login= -h|--help" + [pkica ra operator add]="-l|--last-name= -f|--first-name= -m|--middle-name= --tls-cert-file= --signing-cert-file= -g|--group= --default-folder= --login= -h|--help" + [pkica ra operator deactivate]="--login= -h|--help" + [pkica ra operator get]="-l|--login= -h|--help --format=" + [pkica ra operator list]="-g|--group= -l|--last-name= -f|--first-name= -m|--middle-name= -t|--take= -h|--help --format=" + [pkica ra operator update]="--login= --new-login= -l|--last-name= -f|--first-name= -m|--middle-name= --tls-cert-file= --signing-cert-file= --default-folder= --clear-default-folder -h|--help" + [pkica ra permission get]="--folder= --group= -h|--help --format=" + [pkica ra permission grant]="--folder= --all-folders --group= --all-groups --manage-user --submit-cert-request --resolve-cert-request --submit-rev-request --resolve-rev-request --all -h|--help" + [pkica ra permission revoke]="--folder= --all-folders --group= --all-groups --manage-user --submit-cert-request --resolve-cert-request --submit-rev-request --resolve-rev-request -h|--help" + [pkica ra settings get]="-n|--name= -f|--file= -h|--help" + [pkica ra settings set]="-n|--name= -v|--value= -d|--default -f|--file= -h|--help" +) + +# Если $2 - опция команды $1, принимающая значение, печатает ее длинное имя. +_pkica_argopt() +{ + local spec + for spec in ${_pkica_opts[$1]:--h|--help}; do + [[ $spec == *= ]] || continue + spec=${spec%=} + if [[ "|$spec|" == *"|$2|"* ]]; then + printf '%s\n' "${spec##*|}" + return 0 + fi + done + return 1 +} + +# Дополнение значения опции $2 (длинное имя) команды $1. +_pkica_values() +{ + local path=$1 opt=$2 values= + + case $opt in + --format) values="Json Yaml" ;; + --storage-type) values="PostgreSql SqlServer" ;; + --sign-tool-class) values="KC1 KC2 KC3 KB1 KB2 KA1" ;; + --key-spec) values="Signature KeyExchange" ;; + --key-location | --store-location) values="CurrentUser LocalMachine" ;; + --store-name) values="My Root CertificateAuthority AuthRoot AddressBook Disallowed TrustedPeople TrustedPublisher" ;; + --serial-number-algorithm) values="CryptoPro Msca" ;; + --provider-type) values="80 81" ;; + --default-template) values="SubCa User Tls Ocsp Tsp Qual QualOcsp QualTsp" ;; + --usage) + if [[ $path == "pkica ca signing-key load" ]]; then + values="SignCertAndCrl SignCrl" + else + values="SignCertAndCrl SignCrl Retired" + fi + ;; + --value) + [[ $path == *" identification-kind" ]] && + values="Personal RemoteCert RemotePassport RemoteSystem" + ;; + --name) + [[ $path == "pkica ra settings "* ]] && + values="NamePolicy Templates DefaultAuthority" + ;; + --validity | --key-validity) + COMPREPLY=($(compgen -W "Years: Months: Weeks: Days: Hours: Minutes:" -- "$cur")) + [[ ${COMPREPLY-} == *: ]] && compopt -o nospace 2>/dev/null + declare -F __ltrim_colon_completions >/dev/null && + __ltrim_colon_completions "$cur" + return + ;; + --file | --out-file | --extensions-file | --tls-cert-file | --signing-cert-file) + if declare -F _filedir >/dev/null; then + _filedir + else + compopt -o filenames 2>/dev/null + COMPREPLY=($(compgen -f -- "$cur")) + fi + return + ;; + --output-folder) + if declare -F _filedir >/dev/null; then + _filedir -d + else + compopt -o filenames 2>/dev/null + COMPREPLY=($(compgen -d -- "$cur")) + fi + return + ;; + esac + + COMPREPLY=($(compgen -W "$values" -- "$cur")) +} + +_pkica() +{ + local cur prev words cword split=false + if declare -F _init_completion >/dev/null; then + _init_completion -s -n : || return + else + words=("${COMP_WORDS[@]}") + cword=$COMP_CWORD + cur=${COMP_WORDS[COMP_CWORD]} + prev=${COMP_WORDS[COMP_CWORD - 1]} + fi + + # Определяем путь команды, пропуская опции и их значения. + local path=pkica i w skip=false + for ((i = 1; i < cword; i++)); do + w=${words[i]} + if $skip; then + skip=false + elif [[ $w == -* ]]; then + [[ $w != *=* ]] && _pkica_argopt "$path" "$w" >/dev/null && skip=true + elif [[ " ${_pkica_cmds[$path]-} " == *" $w "* ]]; then + path+=" $w" + fi + done + + # Значение опции: "--opt value" или "--opt=value". + local opt + if $skip || $split; then + if opt=$(_pkica_argopt "$path" "$prev"); then + _pkica_values "$path" "$opt" + fi + return + fi + + local subcmds=${_pkica_cmds[$path]-} + if [[ $cur != -* && -n $subcmds ]]; then + COMPREPLY=($(compgen -W "$subcmds" -- "$cur")) + return + fi + + # Опции, еще не указанные в командной строке. Без "-" в начале + # предлагаются только длинные имена. + local spec alias used list=() aliases + for spec in ${_pkica_opts[$path]:--h|--help}; do + spec=${spec%=} + used=false + IFS='|' read -ra aliases <<<"$spec" + for ((i = 1; i < cword; i++)); do + w=${words[i]%%=*} + for alias in "${aliases[@]}"; do + [[ $w == "$alias" ]] && used=true && break 2 + done + done + $used && continue + if [[ $cur == -* ]]; then + list+=("${aliases[@]}") + else + list+=("${aliases[${#aliases[@]} - 1]}") + fi + done + COMPREPLY=($(compgen -W "${list[*]}" -- "$cur")) +} + +complete -F _pkica pkica diff --git a/bash-completion/tests/check_tree.sh b/bash-completion/tests/check_tree.sh new file mode 100644 index 0000000..5481d81 --- /dev/null +++ b/bash-completion/tests/check_tree.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# Сверка таблиц pkica.bash-completion с реальным выводом `pkica ... --help`. +# Запуск (из WSL/Linux): bash tests/check_tree.sh [путь к pkica] +# Без аргумента используется pkica из PATH. + +root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +pkica=${1:-$(command -v pkica)} +[[ -x $pkica ]] || { echo "pkica not found: укажите путь аргументом"; exit 1; } + +# shellcheck disable=SC1091 +source "$root/pkica.bash-completion" || exit 1 + +fail=0 nodes=0 + +walk() +{ + local path=$1 help cmds opts expected_cmds expected_opts sub + help=$("$pkica" ${path#pkica} --help 2>&1) + nodes=$((nodes + 1)) + + cmds=$(awk '/^Commands:/{f=1;next} f&&/^$/{f=0} f&&/^ [a-z]/{print $1}' <<<"$help" | + tr '\n' ' ' | sed 's/ $//') + opts=$(awk '/^Options:/{f=1;next} /^(Commands:)?$/{f=0} + f&&/^ -/{s=$1; gsub(/-\?\|/,"",s); if($2 ~ /^&1 | grep -q "^Usage: $key " || { + fail=$((fail + 1)) + printf 'UNKNOWN node in completion: [%s]\n' "$key" + } +done + +echo "checked nodes: $nodes, mismatches: $fail" +((fail == 0)) diff --git a/bash-completion/tests/test_completion.sh b/bash-completion/tests/test_completion.sh new file mode 100644 index 0000000..45bfd37 --- /dev/null +++ b/bash-completion/tests/test_completion.sh @@ -0,0 +1,150 @@ +#!/usr/bin/env bash +# Модульные тесты pkica.bash-completion. +# Запуск (из WSL/Linux): bash tests/test_completion.sh + +root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) + +# shellcheck disable=SC1091 +source /usr/share/bash-completion/bash_completion || exit 1 +# shellcheck disable=SC1091 +source "$root/pkica.bash-completion" || exit 1 + +pass=0 fail=0 + +# Разбивает строку на слова так же, как readline: по пробелам и символам +# COMP_WORDBREAKS (группа подряд идущих разделителей - отдельное слово). +_split_line() +{ + local line=$1 c word= i + COMP_WORDS=() + for ((i = 0; i < ${#line}; i++)); do + c=${line:i:1} + if [[ $c == ' ' ]]; then + [[ -n $word ]] && COMP_WORDS+=("$word") + word= + elif [[ $c == [=:] ]]; then + if [[ -n $word && $word != *[=:] ]]; then + COMP_WORDS+=("$word") + word= + fi + word+=$c + else + if [[ $word == *[=:] ]]; then + COMP_WORDS+=("$word") + word= + fi + word+=$c + fi + done + COMP_WORDS+=("$word") + COMP_CWORD=$((${#COMP_WORDS[@]} - 1)) +} + +# complete_line "строка" -> печатает отсортированные варианты через пробел +complete_line() +{ + COMP_LINE=$1 + COMP_POINT=${#COMP_LINE} + _split_line "$COMP_LINE" + COMPREPLY=() + _pkica pkica "${COMP_WORDS[COMP_CWORD]}" "${COMP_WORDS[COMP_CWORD - 1]}" + printf '%s\n' "${COMPREPLY[@]}" | sed '/^$/d' | sort | tr '\n' ' ' | sed 's/ $//' +} + +check() +{ + local line=$1 expected got + expected=$(printf '%s\n' $2 | sort | tr '\n' ' ' | sed 's/ $//') + got=$(complete_line "$line") + if [[ $got == "$expected" ]]; then + pass=$((pass + 1)) + printf 'PASS %s\n' "$line|" + else + fail=$((fail + 1)) + printf 'FAIL %s\n expected: [%s]\n got: [%s]\n' "$line|" "$expected" "$got" + fi +} + +# --- команды --- +check "pkica " "ca cert-registry ra" +check "pkica c" "ca cert-registry" +check "pkica -" "-v --version -h --help" +check "pkica ca " "authority cert cert-request crl db import-legacy issue-cert new-cert-req new-root-cert rev-request signing-key template" +check "pkica ca cert" "cert cert-request" +check "pkica ca -" "-h --help" +check "pkica ca crl schedule " "get update" +check "pkica ca template encode-extension " "certificate-template identification-kind" +check "pkica ra " "db folder group import-legacy operator permission settings" +check "pkica cert-registry db " "info new upgrade" +check "pkica ra group add" "add add-operator" + +# --- опции --- +check "pkica ca crl issue --" "--name --delta-only --next-update --final --key-index --output-folder --force --help" +check "pkica ca crl issue " "--name --delta-only --next-update --final --key-index --output-folder --force --help" +check "pkica ca authority show -" "-n --name -h --help --format" +check "pkica ca authority set-default --n" "--name --none" +check "pkica ra permission grant --all" "--all-folders --all-groups --all" +check "pkica ra settings set -" "-n --name -v --value -d --default -f --file -h --help" + +# уже указанные опции (и их синонимы) не предлагаются +check "pkica ca authority show -n x -" "-h --help --format" +check "pkica ca authority show --name x --format Json -" "-h --help" +check "pkica ca authority show --name=x --" "--help --format" + +# значения опций не мешают определению пути +check "pkica ca crl issue -n ca1 -d -" "-u --next-update --final --key-index -o --output-folder --force -h --help" + +# --- значения опций --- +check "pkica ca authority show --format " "Json Yaml" +check "pkica ca authority show --format J" "Json" +check "pkica ca authority show --format=" "Json Yaml" +check "pkica ca authority show --format=Y" "Yaml" +check "pkica ca db new -s " "PostgreSql SqlServer" +check "pkica ra db new --storage-type P" "PostgreSql" +check "pkica ca new-cert-req --sign-tool-class K" "KC1 KC2 KC3 KB1 KB2 KA1" +check "pkica ca new-cert-req -k " "Signature KeyExchange" +check "pkica ca new-root-cert --key-location " "CurrentUser LocalMachine" +check "pkica ca new-root-cert --serial-number-algorithm " "CryptoPro Msca" +check "pkica ca new-root-cert -v " "Years: Months: Weeks: Days: Hours: Minutes:" +check "pkica ca new-root-cert -V M" "Months: Minutes:" +check "pkica ca signing-key add --store-location " "CurrentUser LocalMachine" +check "pkica ca signing-key add -u " "SignCertAndCrl SignCrl Retired" +check "pkica ca signing-key change-usage --usage S" "SignCertAndCrl SignCrl" +check "pkica ca signing-key load -u " "SignCertAndCrl SignCrl" +check "pkica ca template add -d " "SubCa User Tls Ocsp Tsp Qual QualOcsp QualTsp" +check "pkica ca template update --default-template Q" "Qual QualOcsp QualTsp" +check "pkica ca template encode-extension identification-kind -v " "Personal RemoteCert RemotePassport RemoteSystem" +check "pkica ra settings get -n " "NamePolicy Templates DefaultAuthority" +check "pkica ra settings set --name=T" "Templates" + +# опции со свободным значением - без вариантов +check "pkica ca authority show -n " "" +check "pkica ca crl issue -u " "" +check "pkica ca crl get -v " "" +check "pkica ra settings set -v " "" +check "pkica ra operator add -f " "" +check "pkica ca new-cert-req -s " "" +check "pkica ca new-cert-req -n " "" + +# флаг с той же буквой, что и опция с аргументом в других командах +check "pkica ca crl issue -d " "--name --next-update --final --key-index --output-folder --force --help" +check "pkica ca template list -d " "--file --help --format" + +# --- файлы и каталоги --- +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT +mkdir "$tmp/outdir" +touch "$tmp/request.req" "$tmp/ext.bin" +cd "$tmp" || exit 1 +check "pkica ca issue-cert -f r" "request.req" +check "pkica ca issue-cert --file=r" "request.req" +check "pkica ca issue-cert -o o" "outdir" +check "pkica ca new-cert-req --extensions-file e" "ext.bin" +check "pkica ra operator add --tls-cert-file e" "ext.bin" +check "pkica ra settings set -f r" "request.req" +check "pkica ca crl get -o " "outdir" +check "pkica ca crl issue --output-folder " "outdir" + +echo +echo "passed: $pass, failed: $fail" +((fail == 0)) diff --git a/bash-completion/tests/test_interactive.sh b/bash-completion/tests/test_interactive.sh new file mode 100644 index 0000000..acce1d3 --- /dev/null +++ b/bash-completion/tests/test_interactive.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# Интерактивные тесты pkica.bash-completion: реальный bash + readline в tmux, +# нажатие TAB и проверка содержимого строки ввода. +# Запуск (из WSL/Linux, нужен tmux): bash tests/test_interactive.sh + +root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +command -v tmux >/dev/null || { echo "tmux not found"; exit 1; } + +sess=pkica-compl-$$ +tmp=$(mktemp -d) +trap 'tmux kill-session -t "$sess" 2>/dev/null; rm -rf "$tmp"' EXIT + +mkdir "$tmp/outdir" +touch "$tmp/request.req" +cat >"$tmp/rc" <\n' "$input" + else + fail=$((fail + 1)) + printf 'FAIL %s\n expected: [%s]\n got: [%s]\n' "$input" "$expected" "$got" + fi + tmux send-keys -t "$sess" C-u + tmux send-keys -t "$sess" C-l + sleep 0.2 +} + +check "pkica ce" "pkica cert-registry " +check "pkica ca sig" "pkica ca signing-key " +check "pkica ca signing-key cha" "pkica ca signing-key change-usage " +check "pkica ca authority show --fo" "pkica ca authority show --format " +check "pkica ca authority show --format Y" "pkica ca authority show --format Yaml " +check "pkica ca authority show --format=J" "pkica ca authority show --format=Json " +check "pkica ca new-root-cert -v Y" "pkica ca new-root-cert -v Years:" +check "pkica ca template add -d Su" "pkica ca template add -d SubCa " +check "pkica ca issue-cert -f " "pkica ca issue-cert -f " +check "pkica ca issue-cert -f req" "pkica ca issue-cert -f request.req " +check "pkica ca crl get -o " "pkica ca crl get -o outdir/" +check "./pkica ra fo" "./pkica ra folder " + +# Пустое слово: при TAB TAB в списке должны быть и файлы, и каталоги. +tmux send-keys -t "$sess" C-u "pkica ca issue-cert -f " Tab Tab +sleep 0.5 +screen=$(tmux capture-pane -p -t "$sess") +if [[ $screen == *request.req* && $screen == *outdir/* ]]; then + pass=$((pass + 1)) + echo "PASS pkica ca issue-cert -f lists files" +else + fail=$((fail + 1)) + printf 'FAIL pkica ca issue-cert -f lists files\n%s\n' "$screen" +fi + +echo +echo "passed: $pass, failed: $fail" +((fail == 0)) diff --git a/readme.md b/readme.md index 99a7cb3..03ab573 100644 --- a/readme.md +++ b/readme.md @@ -742,3 +742,9 @@ fi * операции выполняются с административными правами через `sudo`; * пароли не сохраняются и не попадают в журналы; * все результаты доступны в локальных log-файлах. + +--- + +# 27. Автодополнение bash для `pkica` + +В каталоге [`bash-completion`](bash-completion/README.md) находятся правила автодополнения (TAB) в bash для утилиты `pkica` КриптоПро УЦ и тесты к ним.