From bf0115bd18bbb062b226e72913f0070c54d5b596 Mon Sep 17 00:00:00 2001 From: Montoya Edu Date: Tue, 9 Jun 2026 23:11:07 +0200 Subject: [PATCH] fix: adapt certbot flags to modern certbot (2.3.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The container builds FROM certbot/certbot:latest, so a newer certbot broke two commands on ethicserver: - `easy proxy certbot-ionos` aborted with "ambiguous option: --dns-ionos". The bare --dns-ionos selector only exists for certbot's official plugins; with the third-party dns-ionos plugin it is an ambiguous prefix of --dns-ionos-credentials / --dns-ionos-propagation-seconds. Select the plugin with `--authenticator dns-ionos` instead. - `easy proxy certbot` aborted with "unrecognized arguments: --manual-public-ip-logging-ok". That flag was removed from modern certbot (IP-logging consent is no longer prompted). Dropped it. Tests: new mock_docker_running_record helper records `docker exec` args; two bats tests assert the corrected flags. Full suite 54/54. Knowledge base: recorded the certbot:latest flag-drift gotcha. Note: `easy proxy rfc2136` failing on ethicserver is server-side config, not a code bug — /etc/letsencrypt/secret.txt has a hostname for dns_rfc2136_server (certbot requires an IP) and loose file permissions. Co-Authored-By: Claude Opus 4.8 (1M context) --- .beads/knowledge/gotchas.jsonl | 1 + CHANGELOG.md | 13 +++++++++++++ CLAUDE.md | 4 ++-- commands/proxy.sh | 4 ++-- package.json | 2 +- test/dispatcher.bats | 4 ++-- test/proxy.bats | 22 ++++++++++++++++++++++ test/test_helper.bash | 14 ++++++++++++++ 8 files changed, 57 insertions(+), 7 deletions(-) diff --git a/.beads/knowledge/gotchas.jsonl b/.beads/knowledge/gotchas.jsonl index 5011e56..5ab5740 100644 --- a/.beads/knowledge/gotchas.jsonl +++ b/.beads/knowledge/gotchas.jsonl @@ -3,3 +3,4 @@ # Example entry: {"id":"gotcha-example-001","type":"gotcha","fact":"Example: Truthy check on numeric values fails for explicit zero - if (value) is false when value === 0.","recommendation":"Use !== undefined or !== null instead of truthy checks when the value could legitimately be 0 or empty string.","confidence":"high","provenance":[{"source":"coderabbit","reference":"PR review","date":"2026-01-09"}],"tags":["javascript","type-coercion","validation"],"affectedFiles":["**/*.ts"],"affectedServices":[],"createdAt":"2026-01-09T00:00:00Z","updatedAt":"2026-01-09T00:00:00Z","usageCount":0,"helpfulCount":0,"outdatedReports":0} {"id":"gotcha-pin-shellcheck-version","type":"gotcha","fact":"GitHub-hosted runners ship a preinstalled ShellCheck whose version drifts; different versions report different findings (SC2236 fired on the runner but not on local 0.11.0).","recommendation":"Pin ShellCheck in CI by downloading the official koalaman release; keep SHELLCHECK_VERSION in ci.yml in sync with local dev (currently v0.11.0).","confidence":"high","provenance":[{"source":"agent","reference":"discovered fixing CI in PR #11","date":"2026-05-18"}],"tags":["ci","shellcheck","lint"],"affectedFiles":[".github/workflows/ci.yml"],"affectedServices":[],"createdAt":"2026-05-18T00:00:00Z","updatedAt":"2026-05-18T00:00:00Z","usageCount":0,"helpfulCount":0,"outdatedReports":0} +{"id":"gotcha-certbot-latest-flag-drift","type":"gotcha","fact":"The container is built FROM certbot/certbot:latest, so certbot's CLI drifts with each rebuild. Two flags broke: --manual-public-ip-logging-ok was removed (certbot errors 'unrecognized arguments'), and the bare --dns-ionos plugin selector became an ambiguous prefix of --dns-ionos-credentials/--dns-ionos-propagation-seconds ('ambiguous option: --dns-ionos').","recommendation":"Select third-party DNS plugins with '--authenticator dns-' (unambiguous), never the bare '--dns-' selector (that convenience flag only exists for certbot's official plugins). Avoid deprecated certbot flags. Consider pinning the certbot image to a known tag instead of :latest to stop silent CLI drift on rebuild.","confidence":"high","provenance":[{"source":"agent","reference":"fixing certbot failures on ethicserver","date":"2026-06-09"}],"tags":["certbot","docker","dns-ionos","flags","letsencrypt"],"affectedFiles":["commands/proxy.sh","Dockerfile"],"affectedServices":[],"createdAt":"2026-06-09T00:00:00Z","updatedAt":"2026-06-09T00:00:00Z","usageCount":0,"helpfulCount":0,"outdatedReports":0} diff --git a/CHANGELOG.md b/CHANGELOG.md index 2736273..330941e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ All notable changes to this project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/). +## [2.3.1] — 2026-06-09 + +### Fixed + +- `easy proxy certbot-ionos` — select the DNS plugin with `--authenticator + dns-ionos` instead of the bare `--dns-ionos` flag. On recent certbot the bare + flag is an ambiguous prefix of `--dns-ionos-credentials` / + `--dns-ionos-propagation-seconds` and the command aborted with + `ambiguous option: --dns-ionos`. +- `easy proxy certbot` — drop the `--manual-public-ip-logging-ok` flag, removed + from modern certbot. It caused `unrecognized arguments`. IP-logging consent is + no longer prompted, so the flag is obsolete. + ## [2.3.0] — 2026-05-19 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index e7e4522..b31cd1c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,8 +1,8 @@ # easy-proxy — CLAUDE.md > Nginx reverse proxy CLI con Let's Encrypt SSL automation e multi-DNS provider. -> Stato: **ATTIVO** — v2.3.0 -> Ultimo aggiornamento: 2026-05-18 +> Stato: **ATTIVO** — v2.3.1 +> Ultimo aggiornamento: 2026-06-09 --- diff --git a/commands/proxy.sh b/commands/proxy.sh index 5eb4970..10b07c7 100644 --- a/commands/proxy.sh +++ b/commands/proxy.sh @@ -100,7 +100,7 @@ function __easy_command_proxy { echo "Invalid Domain. Set environment variable EASY_LETSENCRYPT_DOMAIN" return 1 fi - docker exec -it "${EASY_PROXY_NAME}" sudo certbot --email "${EASY_LETSENCRYPT_EMAIL}" --agree-tos --manual-public-ip-logging-ok certonly --manual --preferred-challenges dns -d "${EASY_LETSENCRYPT_DOMAIN},*.${EASY_LETSENCRYPT_DOMAIN}" + docker exec -it "${EASY_PROXY_NAME}" sudo certbot --email "${EASY_LETSENCRYPT_EMAIL}" --agree-tos certonly --manual --preferred-challenges dns -d "${EASY_LETSENCRYPT_DOMAIN},*.${EASY_LETSENCRYPT_DOMAIN}" return $? fi if [[ "certbot-ionos" == "$2" ]]; then @@ -154,7 +154,7 @@ chmod 600 /etc/letsencrypt/ionos.ini" --non-interactive \ --agree-tos \ --email "${EASY_LETSENCRYPT_EMAIL}" \ - --dns-ionos \ + --authenticator dns-ionos \ --dns-ionos-credentials /etc/letsencrypt/ionos.ini \ -d "${domain}" -d "*.${domain}" diff --git a/package.json b/package.json index 1d0b996..c62bd3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ethiclab/easy-cli", - "version": "2.3.0", + "version": "2.3.1", "description": "Nginx reverse proxy with Let's Encrypt SSL automation, multi-DNS provider support (IONOS, Route53, Cloudflare, DigitalOcean)", "files": [ "easy", diff --git a/test/dispatcher.bats b/test/dispatcher.bats index 6e0fed1..995ba2f 100644 --- a/test/dispatcher.bats +++ b/test/dispatcher.bats @@ -8,14 +8,14 @@ setup() { easy_setup; } @test "easy --version prints the package.json version" { run easy --version [ "$status" -eq 0 ] - [ "$output" = "2.3.0" ] + [ "$output" = "2.3.1" ] } @test "easy --version works without the runtime env vars set" { unset EASY_LETSENCRYPT_DIR EASY_DOMAINS_DIR run easy --version [ "$status" -eq 0 ] - [ "$output" = "2.3.0" ] + [ "$output" = "2.3.1" ] } @test "easy with no command prints usage and fails" { diff --git a/test/proxy.bats b/test/proxy.bats index 310afaa..60065e5 100644 --- a/test/proxy.bats +++ b/test/proxy.bats @@ -92,3 +92,25 @@ setup() { easy_setup; } [ "$status" -eq 1 ] [[ "$output" == *"IONOS API credentials not found"* ]] } + +@test "easy proxy certbot-ionos selects the plugin with --authenticator (not the ambiguous --dns-ionos)" { + export DOCKER_LOG="$BATS_TEST_TMPDIR/docker.log" + mock_docker_running_record + export EASY_LETSENCRYPT_EMAIL="test@example.com" + export IONOS_API_KEY="key" IONOS_API_SECRET="secret" + run easy proxy certbot-ionos example.com + [ "$status" -eq 0 ] + # The bare --dns-ionos selector is ambiguous on modern certbot; must use --authenticator. + grep -q -- "--authenticator dns-ionos" "$DOCKER_LOG" + ! grep -Eq -- "--dns-ionos( |$)" "$DOCKER_LOG" +} + +@test "easy proxy certbot does not pass the removed --manual-public-ip-logging-ok flag" { + export DOCKER_LOG="$BATS_TEST_TMPDIR/docker.log" + mock_docker_running_record + export EASY_LETSENCRYPT_EMAIL="test@example.com" + export EASY_LETSENCRYPT_DOMAIN="example.com" + run easy proxy certbot + [ "$status" -eq 0 ] + ! grep -q -- "--manual-public-ip-logging-ok" "$DOCKER_LOG" +} diff --git a/test/test_helper.bash b/test/test_helper.bash index 9f5ff8e..50af43e 100644 --- a/test/test_helper.bash +++ b/test/test_helper.bash @@ -67,6 +67,20 @@ MOCK chmod +x "$MOCK_BIN/docker" } +# Mock `docker`: the proxy is running AND every invocation is logged to +# $DOCKER_LOG. Lets a test assert the exact certbot flags passed via `docker exec`. +mock_docker_running_record() { + cat > "$MOCK_BIN/docker" <<'MOCK' +#!/usr/bin/env bash +echo "$*" >> "${DOCKER_LOG:-/dev/null}" +case "$1" in + ps) echo "deadbeefcafe1234" ;; + *) exit 0 ;; +esac +MOCK + chmod +x "$MOCK_BIN/docker" +} + # Mock `pass` so credential lookups always miss (no stored secrets). mock_pass_empty() { printf '#!/usr/bin/env bash\nexit 1\n' > "$MOCK_BIN/pass"