Compare commits

...

38 Commits

Author SHA1 Message Date
Brad Warren
b973de36d5 build amd64 certbot snap only 2024-11-12 13:05:33 -08:00
Brad Warren
8143f80478 try using python3-dbg 2024-11-12 13:05:29 -08:00
ohemorange
38fc7fcc48 escape backslashes in format string in finish_release.py (#10043) 2024-11-05 23:42:59 +00:00
ohemorange
0e225dcba2 Fix release script main replacement (#10042)
* restore incorrect regex changes to CHANGELOG.md

* Update _release.sh regex to switch only first instance of main in changelog
2024-11-05 14:55:23 -08:00
Brad Warren
4ff5719a65 Merge pull request #10039 from certbot/candidate-3.0.0
Candidate 3.0.0
2024-11-05 12:52:47 -08:00
Will Greenberg
798a61622c Bump version to 3.1.0 2024-11-05 10:55:20 -08:00
Will Greenberg
b20d01e032 Add contents to certbot/CHANGELOG.md for next version 2024-11-05 10:55:20 -08:00
Will Greenberg
990352e371 Remove built packages from git 2024-11-05 10:55:20 -08:00
Will Greenberg
c5a5d6f9a1 Release 3.0.0 2024-11-05 10:55:19 -08:00
Will Greenberg
d4850399c5 Update changelog for 3.0.0 release 2024-11-05 10:54:15 -08:00
Brad Warren
c4be440853 update dependencies (#10036)
this fixes the current [dependabot alert](https://github.com/certbot/certbot/security/dependabot)
2024-11-01 10:04:10 -07:00
Will Greenberg
165c3e32b0 snap: fix generated postrefreshhook script (#9994)
Fixes #9990

If the python oneliner to check certbot's version succeeded, exit_code
would never be set, which would cause our exit_code check to fail. Use
a check that handles unset exit_code
2024-11-01 08:03:57 -07:00
Will Greenberg
2660a2017b Certbot 3.0 outdated plugin warning (#10031)
* Print an error if outdated snap plugins detected

With Certbot 3.0 comes a bump to Python 3.12, so if any snap plugins
are still located in a python3.8 directory, print an error informing
the user.

* tox nitpicks

* personal nitpick

* review fixups

* Update certbot/certbot/_internal/snap_config.py

Co-authored-by: ohemorange <ebportnoy@gmail.com>

* Use LOGGER.warn instead of error

* warn-->warning

* warn-->warning

---------

Co-authored-by: ohemorange <ebportnoy@gmail.com>
2024-11-01 07:52:48 -07:00
ohemorange
6a6544fd90 Update azure standard tests to use macOS-15 and python3.12 (#10032)
macOS-12 is [being deprecated](https://github.com/actions/runner-images/issues/10721) on Azure, so update to the latest available version.

* Upgrade macOS azure tests to use macOS-15

* switch standard azure tests to using python 3.12

* restore mac and linux cover tests to oldest and newest version style, and add explanation that that's what we're doing.
2024-11-01 07:34:16 -07:00
Brad Warren
320cf92944 depecate py38 support (#10034) 2024-10-31 15:48:57 -07:00
Brad Warren
3078c2f3db remove reference to "good first issue" label (#10018) 2024-10-25 11:43:44 -07:00
Brad Warren
c54f99e35b mattermost/action-mattermost-notify still uses master (#10021) 2024-10-04 14:08:25 -07:00
Brad Warren
c81dbb2582 Make Docker builds more verbose (#10022)
* use consistent casing to fix warnings

* don't truncate docker build logs

* make docker build output verbose
2024-10-04 13:54:56 -07:00
Will Greenberg
742f97e11a docs: fix logo url (#10019) 2024-09-26 15:10:06 -07:00
Will Greenberg
84c8dbc52a Migrate master branch to main
We're a few years behind the curve on this one, but using "master" as a
programming term is a callous practice that explicitly uses the
historical institution of slavery as a cheap, racist metaphor. Switch to
using "main", as it's the new default in git and GitHub.
2024-09-26 14:48:10 -07:00
Brad Warren
4b51e3004c remove certbot_dns_route53.authenticator (#10014)
This is another and very minor piece of https://github.com/certbot/certbot/issues/9988.

We've done nothing to warn/migrate installations using the old `certbot-route53:auth` plugin name and installations like that still exist according to https://gist.github.com/bmw/aceb69020dceee50ba827ec17b22e08a. We could try to warn/migrate these users for a future release or decide it's niche enough that we'll just let it break, but I think it's easy enough to keep the simple shim around.

This PR just moves the code raising a deprecation warning into `_internal` as part of cleaning up all deprecation warnings I found in https://github.com/certbot/certbot/issues/9988. I manually tested this with a Certbot config using the `certbot-route53:auth` plugin name and renewal worked just fine.
2024-09-18 14:07:35 -07:00
ohemorange
018800c5cc specify channel in weekly mm message (#10013) 2024-09-16 12:31:52 -07:00
Brad Warren
2eb4154169 allow manually triggering GH actions (#10015) 2024-09-16 12:16:51 -07:00
Brad Warren
becc2c3fee Remove deprecated --dns-route53-propagation-seconds (#10010)
* remove dns-route53-prop-secs

* document design difference
2024-09-13 12:14:49 -07:00
ldlb
cb5382d4d5 Remove deprecated features:--manual-public-ip-logging-ok (#9991)
* Remove parameter '--manual-public-ip-logging-ok'

* Update changelog with removal of '--manual-public-ip-logging-ok' flag
2024-09-12 07:21:55 -07:00
ohemorange
6975e32998 Fix weekly mattermost notifier (#10009) 2024-09-11 11:11:47 -07:00
Brad Warren
62962357c5 add parenthesis (#10008) 2024-09-10 13:06:48 -07:00
ohemorange
343b540970 Use new mattermost action workflow (#10007) 2024-09-10 12:53:21 -07:00
ohemorange
089b7efacd Update syntax for mattermost webhooks (#10006) 2024-09-10 12:16:53 -07:00
Brad Warren
1584b0b58c add macos qol suggestions (#9995) 2024-09-09 12:34:00 -07:00
Brad Warren
141b15077c Update changelog for 3.0 and remove update_symlinks and {csr,key}_dir (#10004)
* update changelog to 3.0

we did a similar thing in https://github.com/certbot/certbot/pull/9461

* remove update_symlinks

* remove {csr,key}_dir
2024-09-09 12:31:25 -07:00
Brad Warren
ee2c4844b9 fix centos9 test (#9999) 2024-09-05 16:14:10 -07:00
Shubham Sharma
181813b9b2 add mijn.host (#10002) 2024-09-05 08:56:03 -07:00
Alexandre Detiste
43d0652b0d remove six leftovers (#9996) 2024-08-30 11:38:44 -07:00
Adrien Ferrand
80e68bec26 Update dependencies (27-08-2024) (#9993)
Update dependencies & proactively defends against major bump to Josepy 2+

Co-authored-by: Brad Warren <bmw@users.noreply.github.com>
2024-08-28 07:22:22 -07:00
Brad Warren
7b2b2b1685 switch from gpg2 to gpg (#9985)
The `gnupg` package from Homebrew only installs a `gpg` binary, not a `gpg2` binary. I had previously worked around this by manually creating an alias, but I think we can do better.

GPG version 1 is ancient and [hasn't seen a release since 2006](https://gnupg.org/download/release_notes.html). Additionally, `gpg` has referred to GPG 2 in Ubuntu since at least 20.04 which is the oldest non-EOL'd version as of writing this so I think this change is safe to make.
2024-08-19 15:24:39 -07:00
Will Greenberg
c3c587001f Update python version to 3.12 and base to core24 in snaps (#9983)
Fixes #9872, originally merged in #9956.

To upgrade to python3.12 as 3.8 is reaching EOL, we need to upgrade the core snap that certbot is based on. The latest version is core24, so we're going with that for longevity. We will want to notify third party snaps to make changes as well. They can release their snaps to a version higher than certbot's, and their users will not be upgraded until the matching (or greater) version of certbot is released. They should do this as otherwise including these changes will break their plugins.

Key documents for this migration are https://snapcraft.io/docs/migrate-core22 and https://snapcraft.io/docs/migrate-core24. The discussion at https://forum.snapcraft.io/t/upgrading-classic-snap-to-core24-using-snapcraft-8-3-causes-python-3-12-errors-at-runtime/ is also relevant to understanding some changes, which may become unnecessary in future versions of snapcraft.


* Migrate primary certbot snap to core24 and python 3.12

* Migrate plugin snaps to core24 and python 3.12

* Migrate to core24 in build_remote

* Run snap tests using python 3.12

* Unstage pyvenv.cfg and set PYTHONPATH

---------

Co-authored-by: Erica Portnoy <ebportnoy@gmail.com>
Co-authored-by: Erica Portnoy <erica@eff.org>
2024-08-08 16:24:11 -07:00
Will Greenberg
281b724996 clarify docs (#9984)
Authored-by: Brad Warren <bmw@eff.org>
2024-08-08 16:16:28 -07:00
73 changed files with 503 additions and 604 deletions

View File

@@ -1,8 +1,8 @@
# Configuring Azure Pipelines with Certbot
Let's begin. All pipelines are defined in `.azure-pipelines`. Currently there are two:
* `.azure-pipelines/main.yml` is the main one, executed on PRs for master, and pushes to master,
* `.azure-pipelines/advanced.yml` add installer testing on top of the main pipeline, and is executed for `test-*` branches, release branches, and nightly run for master.
* `.azure-pipelines/main.yml` is the main one, executed on PRs for main, and pushes to main,
* `.azure-pipelines/advanced.yml` add installer testing on top of the main pipeline, and is executed for `test-*` branches, release branches, and nightly run for main.
Several templates are defined in `.azure-pipelines/templates`. These YAML files aggregate common jobs configuration that can be reused in several pipelines.
@@ -64,7 +64,7 @@ Azure Pipeline needs RW on code, RO on metadata, RW on checks, commit statuses,
RW access here is required to allow update of the pipelines YAML files from Azure DevOps interface, and to
update the status of builds and PRs on GitHub side when Azure Pipelines are triggered.
Note however that no admin access is defined here: this means that Azure Pipelines cannot do anything with
protected branches, like master, and cannot modify the security context around this on GitHub.
protected branches, like main, and cannot modify the security context around this on GitHub.
Access can be defined for all or only selected repositories, which is nice.
```
@@ -91,11 +91,11 @@ grant permissions from Azure Pipelines to GitHub in order to setup a GitHub OAut
then are way too large (admin level on almost everything), while the classic approach does not add any more
permissions, and works perfectly well.__
- Select GitHub in "Select your repository section", choose certbot/certbot in Repository, master in default branch.
- Select GitHub in "Select your repository section", choose certbot/certbot in Repository, main in default branch.
- Click on YAML option for "Select a template"
- Choose a name for the pipeline (eg. test-pipeline), and browse to the actual pipeline YAML definition in the
"YAML file path" input (eg. `.azure-pipelines/test-pipeline.yml`)
- Click "Save & queue", choose the master branch to build the first pipeline, and click "Save and run" button.
- Click "Save & queue", choose the main branch to build the first pipeline, and click "Save and run" button.
_Done. Pipeline is operational. Repeat to add more pipelines from existing YAML files in `.azure-pipelines`._

View File

@@ -1,9 +1,9 @@
# We run the test suite on commits to master so codecov gets coverage data
# about the master branch and can use it to track coverage changes.
# We run the test suite on commits to main so codecov gets coverage data
# about the main branch and can use it to track coverage changes.
trigger:
- master
- main
pr:
- master
- main
- '*.x'
variables:

View File

@@ -1,4 +1,4 @@
# Nightly pipeline running each day for master.
# Nightly pipeline running each day for main.
trigger: none
pr: none
schedules:
@@ -6,7 +6,7 @@ schedules:
displayName: Nightly build
branches:
include:
- master
- main
always: true
variables:

View File

@@ -25,8 +25,9 @@ jobs:
linux-integration-nginx-oldest:
PYTHON_VERSION: 3.8
TOXENV: integration-nginx-oldest
# python 3.8 integration tests are not run here because they're run as
# part of the standard test suite
linux-py38-integration:
PYTHON_VERSION: 3.8
TOXENV: integration
linux-py39-integration:
PYTHON_VERSION: 3.9
TOXENV: integration
@@ -36,20 +37,19 @@ jobs:
linux-py311-integration:
PYTHON_VERSION: 3.11
TOXENV: integration
linux-py312-integration:
PYTHON_VERSION: 3.12
TOXENV: integration
# python 3.12 integration tests are not run here because they're run as
# part of the standard test suite
nginx-compat:
TOXENV: nginx_compat
linux-integration-rfc2136:
IMAGE_NAME: ubuntu-22.04
PYTHON_VERSION: 3.8
PYTHON_VERSION: 3.12
TOXENV: integration-dns-rfc2136
le-modification:
IMAGE_NAME: ubuntu-22.04
TOXENV: modification
farmtest-apache2:
PYTHON_VERSION: 3.8
PYTHON_VERSION: 3.12
TOXENV: test-farm-apache2
pool:
vmImage: $(IMAGE_NAME)

View File

@@ -1,60 +1,4 @@
jobs:
- job: docker_build
pool:
vmImage: ubuntu-22.04
strategy:
matrix:
arm32v6:
DOCKER_ARCH: arm32v6
arm64v8:
DOCKER_ARCH: arm64v8
amd64:
DOCKER_ARCH: amd64
# The default timeout of 60 minutes is a little low for compiling
# cryptography on ARM architectures.
timeoutInMinutes: 180
steps:
- bash: set -e && tools/docker/build.sh $(dockerTag) $DOCKER_ARCH
displayName: Build the Docker images
# We don't filter for the Docker Hub organization to continue to allow
# easy testing of these scripts on forks.
- bash: |
set -e
DOCKER_IMAGES=$(docker images --filter reference='*/certbot' --filter reference='*/dns-*' --format '{{.Repository}}')
docker save --output images.tar $DOCKER_IMAGES
displayName: Save the Docker images
# If the name of the tar file or artifact changes, the deploy stage will
# also need to be updated.
- bash: set -e && mv images.tar $(Build.ArtifactStagingDirectory)
displayName: Prepare Docker artifact
- task: PublishPipelineArtifact@1
inputs:
path: $(Build.ArtifactStagingDirectory)
artifact: docker_$(DOCKER_ARCH)
displayName: Store Docker artifact
- job: docker_test
dependsOn: docker_build
pool:
vmImage: ubuntu-22.04
strategy:
matrix:
arm32v6:
DOCKER_ARCH: arm32v6
arm64v8:
DOCKER_ARCH: arm64v8
amd64:
DOCKER_ARCH: amd64
steps:
- task: DownloadPipelineArtifact@2
inputs:
artifact: docker_$(DOCKER_ARCH)
path: $(Build.SourcesDirectory)
displayName: Retrieve Docker images
- bash: set -e && docker load --input $(Build.SourcesDirectory)/images.tar
displayName: Load Docker images
- bash: |
set -e && tools/docker/test.sh $(dockerTag) $DOCKER_ARCH
displayName: Run integration tests for Docker images
- job: snaps_build
pool:
vmImage: ubuntu-22.04
@@ -62,10 +6,6 @@ jobs:
matrix:
amd64:
SNAP_ARCH: amd64
armhf:
SNAP_ARCH: armhf
arm64:
SNAP_ARCH: arm64
timeoutInMinutes: 0
steps:
- script: |
@@ -76,7 +16,7 @@ jobs:
displayName: Install dependencies
- task: UsePythonVersion@0
inputs:
versionSpec: 3.8
versionSpec: 3.12
addToPath: true
- task: DownloadSecureFile@1
name: credentials
@@ -88,12 +28,11 @@ jobs:
git config --global user.name "$(Build.RequestedFor)"
mkdir -p ~/.local/share/snapcraft/provider/launchpad
cp $(credentials.secureFilePath) ~/.local/share/snapcraft/provider/launchpad/credentials
python3 tools/snap/build_remote.py ALL --archs ${SNAP_ARCH} --timeout $(snapBuildTimeout)
python3 tools/snap/build_remote.py certbot --archs ${SNAP_ARCH} --timeout $(snapBuildTimeout)
displayName: Build snaps
- script: |
set -e
mv *.snap $(Build.ArtifactStagingDirectory)
mv certbot-dns-*/*.snap $(Build.ArtifactStagingDirectory)
displayName: Prepare artifacts
- task: PublishPipelineArtifact@1
inputs:
@@ -107,7 +46,7 @@ jobs:
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: 3.8
versionSpec: 3.12
addToPath: true
- script: |
set -e
@@ -129,31 +68,3 @@ jobs:
set -e
venv/bin/python -m tox run -e integration-external,apacheconftest-external-with-pebble
displayName: Run tox
- job: snap_dns_run
dependsOn: snaps_build
pool:
vmImage: ubuntu-22.04
steps:
- script: |
set -e
sudo apt-get update
sudo apt-get install -y --no-install-recommends snapd
displayName: Install dependencies
- task: UsePythonVersion@0
inputs:
versionSpec: 3.8
addToPath: true
- task: DownloadPipelineArtifact@2
inputs:
artifact: snaps_amd64
path: $(Build.SourcesDirectory)/snap
displayName: Retrieve Certbot snaps
- script: |
set -e
python3 -m venv venv
venv/bin/python tools/pip_install.py -e certbot-ci
displayName: Prepare Certbot-CI
- script: |
set -e
sudo -E venv/bin/pytest certbot-ci/snap_integration_tests/dns_tests --allow-persistent-changes --snap-folder $(Build.SourcesDirectory)/snap --snap-arch amd64
displayName: Test DNS plugins snaps

View File

@@ -5,14 +5,16 @@ jobs:
strategy:
matrix:
macos-py38-cover:
IMAGE_NAME: macOS-12
# mac unit+cover tests with the oldest python we support
IMAGE_NAME: macOS-15
PYTHON_VERSION: 3.8
TOXENV: cover
# As of pip 23.1.0, builds started failing on macOS unless this flag was set.
# See https://github.com/certbot/certbot/pull/9717#issuecomment-1610861794.
PIP_USE_PEP517: "true"
macos-cover:
IMAGE_NAME: macOS-13
# mac unit+cover tests with the newest python we support
IMAGE_NAME: macOS-15
TOXENV: cover
# See explanation under macos-py38-cover.
PIP_USE_PEP517: "true"
@@ -21,10 +23,12 @@ jobs:
PYTHON_VERSION: 3.8
TOXENV: oldest
linux-py38:
# linux unit tests with the oldest python we support
IMAGE_NAME: ubuntu-22.04
PYTHON_VERSION: 3.8
TOXENV: py38
linux-cover:
# linux unit+cover tests with the newest python we support
IMAGE_NAME: ubuntu-22.04
TOXENV: cover
linux-lint:
@@ -35,7 +39,6 @@ jobs:
TOXENV: mypy
linux-integration:
IMAGE_NAME: ubuntu-22.04
PYTHON_VERSION: 3.8
TOXENV: integration
apache-compat:
IMAGE_NAME: ubuntu-22.04

View File

@@ -1,6 +1,4 @@
stages:
- stage: TestAndPackage
jobs:
- template: ../jobs/standard-tests-jobs.yml
- template: ../jobs/extended-tests-jobs.yml
- template: ../jobs/packaging-jobs.yml

View File

@@ -1,6 +1,6 @@
## Pull Request Checklist
- [ ] The Certbot team has recently expressed interest in reviewing a PR for this. If not, this PR may be closed due our limited resources and need to prioritize how we spend them.
- [ ] If the change being made is to a [distributed component](https://certbot.eff.org/docs/contributing.html#code-components-and-layout), edit the `master` section of `certbot/CHANGELOG.md` to include a description of the change being made.
- [ ] If the change being made is to a [distributed component](https://certbot.eff.org/docs/contributing.html#code-components-and-layout), edit the `main` section of `certbot/CHANGELOG.md` to include a description of the change being made.
- [ ] Add or update any documentation as needed to support the changes in this PR.
- [ ] Include your name in `AUTHORS.md` if you like.

View File

@@ -8,25 +8,14 @@ on:
jobs:
if_merged:
# Forked repos can not access Mattermost secret.
if: github.event.pull_request.merged == true && !github.event.pull_request.head.repo.fork
if: github.event.pull_request.merged == true && !github.event.pull_request.head.repo.fork
runs-on: ubuntu-latest
steps:
- name: Create Mattermost Message
# https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#example-of-a-script-injection-attack
env:
NUMBER: ${{ github.event.number }}
PR_URL: https://github.com/${{ github.repository }}/pull/${{ github.event.number }}
REPO: ${{ github.repository }}
USER: ${{ github.actor }}
TITLE: ${{ github.event.pull_request.title }}
run: |
jq --null-input \
--arg number "$NUMBER" \
--arg pr_url "$PR_URL" \
--arg repo "$REPO" \
--arg user "$USER" \
--arg title "$TITLE" \
'{ "text": "[\($repo)] | [\($title) #\($number)](\($pr_url)) was merged into master by \($user)" }' > mattermost.json
- uses: mattermost/action-mattermost-notify@master
env:
with:
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_MERGE_WEBHOOK }}
TEXT: >
[${{ github.repository }}] |
[${{ github.event.pull_request.title }}
#${{ github.event.number }}](https://github.com/${{ github.repository }}/pull/${{ github.event.number }})
was merged into main by ${{ github.actor }}

View File

@@ -4,6 +4,7 @@ on:
schedule:
# Every week on Thursday @ 13:00
- cron: "0 13 * * 4"
workflow_dispatch:
jobs:
send-mattermost-message:
runs-on: ubuntu-latest
@@ -11,15 +12,16 @@ jobs:
steps:
- name: Create Mattermost Message
run: |
DATE=$(date --date="7 days ago" +"%Y-%m-%d")
MERGED_URL="https://github.com/pulls?q=merged%3A%3E${DATE}+org%3Acertbot"
UPDATED_URL="https://github.com/pulls?q=updated%3A%3E${DATE}+org%3Acertbot"
echo "{\"text\":\"## Updates Across Certbot Repos\n\n
- Certbot team members SHOULD look at: [link]($MERGED_URL)\n\n
- Certbot team members MAY also want to look at: [link]($UPDATED_URL)\n\n
- Want to Discuss something today? Place it [here](https://docs.google.com/document/d/17YMUbtC1yg6MfiTMwT8zVm9LmO-cuGVBom0qFn8XJBM/edit?usp=sharing) and we can meet today on Zoom.\n\n
- The key words SHOULD and MAY in this message are to be interpreted as described in [RFC 8147](https://www.rfc-editor.org/rfc/rfc8174). \"
}" > mattermost.json
DATE=$(date --date="7 days ago" +"%Y-%m-%d")
echo "MERGED_URL=https://github.com/pulls?q=merged%3A%3E${DATE}+org%3Acertbot" >> $GITHUB_ENV
echo "UPDATED_URL=https://github.com/pulls?q=updated%3A%3E${DATE}+org%3Acertbot" >> $GITHUB_ENV
- uses: mattermost/action-mattermost-notify@master
env:
with:
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
MATTERMOST_CHANNEL: private-certbot
TEXT: |
## Updates Across Certbot Repos
- Certbot team members SHOULD look at: [link](${{ env.MERGED_URL }})
- Certbot team members MAY also want to look at: [link](${{ env.UPDATED_URL }})
- Want to Discuss something today? Place it [here](https://docs.google.com/document/d/17YMUbtC1yg6MfiTMwT8zVm9LmO-cuGVBom0qFn8XJBM/edit?usp=sharing) and we can meet today on Zoom.
- The key words SHOULD and MAY in this message are to be interpreted as described in [RFC 8147](https://www.rfc-editor.org/rfc/rfc8174).

View File

@@ -3,6 +3,7 @@ on:
schedule:
# Run 1:24AM every night
- cron: '24 1 * * *'
workflow_dispatch:
permissions:
issues: write
jobs:

View File

@@ -6,6 +6,7 @@ This module is an implementation of the `ACME protocol`_.
"""
import sys
import warnings
# This code exists to keep backwards compatibility with people using acme.jose
# before it became the standalone josepy package.
@@ -19,3 +20,10 @@ for mod in list(sys.modules):
# preserved (acme.jose.* is josepy.*)
if mod == 'josepy' or mod.startswith('josepy.'):
sys.modules['acme.' + mod.replace('josepy', 'jose', 1)] = sys.modules[mod]
if sys.version_info[:2] == (3, 8):
warnings.warn(
"Python 3.8 support will be dropped in the next planned release of "
"acme. Please upgrade your Python version.",
PendingDeprecationWarning,
) # pragma: no cover

View File

@@ -3,11 +3,13 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'cryptography>=3.2.1',
'josepy>=1.13.0',
# Josepy 2+ may introduce backward incompatible changes by droping usage of
# deprecated PyOpenSSL APIs.
'josepy>=1.13.0, <2',
# pyOpenSSL 23.1.0 is a bad release: https://github.com/pyca/pyopenssl/issues/1199
'PyOpenSSL>=17.5.0,!=23.1.0',
'pyrfc3339',

View File

@@ -1,7 +1,7 @@
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
# We specify the minimum acme and certbot version as the current plugin

View File

@@ -96,7 +96,6 @@ def _prepare_args_env(certbot_args: List[str], directory_url: str, http_01_port:
'--no-verify-ssl',
'--http-01-port', str(http_01_port),
'--https-port', str(tls_alpn_01_port),
'--manual-public-ip-logging-ok',
'--config-dir', config_dir,
'--work-dir', os.path.join(workspace, 'work'),
'--logs-dir', os.path.join(workspace, 'logs'),

View File

@@ -1,7 +1,7 @@
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'certbot',

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
# for now, do not upgrade to cloudflare>=2.20 to avoid deprecation warnings and the breaking

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'python-digitalocean>=1.11', # 1.15.0 or newer is recommended for TTL support

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
# This version of lexicon is required to address the problem described in

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'google-api-python-client>=1.6.5',

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'dns-lexicon>=3.15.1',

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'dnspython>=1.15.0',

View File

@@ -101,13 +101,4 @@ Examples
--dns-route53 \\
-d example.com \\
-d www.example.com
.. code-block:: bash
:caption: To acquire a certificate for ``example.com``, waiting 30 seconds
for DNS propagation
certbot certonly \\
--dns-route53 \\
--dns-route53-propagation-seconds 30 \\
-d example.com
"""

View File

@@ -6,18 +6,20 @@ from typing import Any
from typing import Callable
from typing import DefaultDict
from typing import Dict
from typing import Iterable
from typing import List
from typing import Type
import boto3
from botocore.exceptions import ClientError
from botocore.exceptions import NoCredentialsError
from acme.challenges import ChallengeResponse
from acme import challenges
from certbot import achallenges
from certbot import errors
from certbot import interfaces
from certbot.achallenges import AnnotatedChallenge
from certbot.plugins import dns_common
from certbot.util import add_deprecated_argument
from certbot.plugins import common
logger = logging.getLogger(__name__)
@@ -27,7 +29,7 @@ INSTRUCTIONS = (
"and add the necessary permissions for Route53 access.")
class Authenticator(dns_common.DNSAuthenticator):
class Authenticator(common.Plugin, interfaces.Authenticator):
"""Route53 Authenticator
This authenticator solves a DNS01 challenge by uploading the answer to AWS
@@ -41,6 +43,7 @@ class Authenticator(dns_common.DNSAuthenticator):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.r53 = boto3.client("route53")
self._attempt_cleanup = False
self._resource_records: DefaultDict[str, List[Dict[str, str]]] = \
collections.defaultdict(list)
@@ -48,9 +51,9 @@ class Authenticator(dns_common.DNSAuthenticator):
return "Solve a DNS01 challenge using AWS Route53"
@classmethod
def add_parser_arguments(cls, add: Callable[..., None], # pylint: disable=arguments-differ
default_propagation_seconds: int = 10) -> None:
add_deprecated_argument(add, 'propagation-seconds', 1)
def add_parser_arguments(cls, add: Callable[..., None]) -> None:
# This authenticator currently adds no extra arguments.
pass
def auth_hint(self, failed_achalls: List[achallenges.AnnotatedChallenge]) -> str:
return (
@@ -58,13 +61,13 @@ class Authenticator(dns_common.DNSAuthenticator):
'--dns-route53. Ensure the above domains have their DNS hosted by AWS Route53.'
)
def _setup_credentials(self) -> None:
def prepare(self) -> None:
pass
def _perform(self, domain: str, validation_name: str, validation: str) -> None:
pass
def get_chall_pref(self, unused_domain: str) -> Iterable[Type[challenges.Challenge]]:
return [challenges.DNS01]
def perform(self, achalls: List[AnnotatedChallenge]) -> List[ChallengeResponse]:
def perform(self, achalls: List[AnnotatedChallenge]) -> List[challenges.ChallengeResponse]:
self._attempt_cleanup = True
try:
@@ -82,7 +85,16 @@ class Authenticator(dns_common.DNSAuthenticator):
raise errors.PluginError("\n".join([str(e), INSTRUCTIONS]))
return [achall.response(achall.account_key) for achall in achalls]
def _cleanup(self, domain: str, validation_name: str, validation: str) -> None:
def cleanup(self, achalls: List[achallenges.AnnotatedChallenge]) -> None:
if self._attempt_cleanup:
for achall in achalls:
domain = achall.domain
validation_domain_name = achall.validation_domain_name(domain)
validation = achall.validation(achall.account_key)
self._cleanup(validation_domain_name, validation)
def _cleanup(self, validation_name: str, validation: str) -> None:
try:
self._change_txt_record("DELETE", validation_name, validation)
except (NoCredentialsError, ClientError) as e:
@@ -166,3 +178,13 @@ class Authenticator(dns_common.DNSAuthenticator):
raise errors.PluginError(
"Timed out waiting for Route53 change. Current status: %s" %
response["ChangeInfo"]["Status"])
# Our route53 plugin was initially a 3rd party plugin named `certbot-route53:auth` as described at
# https://github.com/certbot/certbot/issues/4688. This shim exists to allow installations using the
# old plugin name of `certbot-route53:auth` to continue to work without cluttering things like
# Certbot's help output with two route53 plugins.
class HiddenAuthenticator(Authenticator):
"""A hidden shim around certbot-dns-route53 for backwards compatibility."""
hidden = True

View File

@@ -6,17 +6,27 @@ from unittest import mock
from botocore.exceptions import ClientError
from botocore.exceptions import NoCredentialsError
import josepy as jose
import pytest
from acme import challenges
from certbot import achallenges
from certbot import errors
from certbot.compat import os
from certbot.plugins import dns_test_common
from certbot.plugins.dns_test_common import DOMAIN
from certbot.tests import acme_util
from certbot.tests import util as test_util
DOMAIN = 'example.com'
KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem"))
class AuthenticatorTest(unittest.TestCase, dns_test_common.BaseAuthenticatorTest):
class AuthenticatorTest(unittest.TestCase):
# pylint: disable=protected-access
achall = achallenges.KeyAuthorizationAnnotatedChallenge(
challb=acme_util.DNS01, domain=DOMAIN, account_key=KEY)
def setUp(self):
from certbot_dns_route53._internal.dns_route53 import Authenticator
@@ -35,6 +45,12 @@ class AuthenticatorTest(unittest.TestCase, dns_test_common.BaseAuthenticatorTest
del os.environ["AWS_ACCESS_KEY_ID"]
del os.environ["AWS_SECRET_ACCESS_KEY"]
def test_more_info(self) -> None:
self.assertTrue(isinstance(self.auth.more_info(), str))
def test_get_chall_pref(self) -> None:
self.assertEqual(self.auth.get_chall_pref("example.org"), [challenges.DNS01])
def test_perform(self):
self.auth._change_txt_record = mock.MagicMock()
self.auth._wait_for_change = mock.MagicMock()
@@ -85,13 +101,6 @@ class AuthenticatorTest(unittest.TestCase, dns_test_common.BaseAuthenticatorTest
self.auth.cleanup([self.achall])
def test_parser_arguments(self) -> None:
from certbot.util import DeprecatedArgumentAction
m = mock.MagicMock()
self.auth.add_parser_arguments(m) # pylint: disable=no-member
m.assert_any_call('propagation-seconds', action=DeprecatedArgumentAction,
help=mock.ANY, nargs=1)
class ClientTest(unittest.TestCase):
# pylint: disable=protected-access

View File

@@ -1,17 +0,0 @@
"""Shim around `~certbot_dns_route53._internal.dns_route53` for backwards compatibility."""
from typing import Any
import warnings
from certbot_dns_route53._internal import dns_route53
class Authenticator(dns_route53.Authenticator):
"""Shim around `~certbot_dns_route53._internal.dns_route53.Authenticator`
for backwards compatibility."""
hidden = True
def __init__(self, *args: Any, **kwargs: Any) -> None:
warnings.warn("The 'authenticator' module was renamed 'dns_route53'",
DeprecationWarning)
super().__init__(*args, **kwargs)

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'boto3>=1.15.15',
@@ -71,7 +71,7 @@ setup(
entry_points={
'certbot.plugins': [
'dns-route53 = certbot_dns_route53._internal.dns_route53:Authenticator',
'certbot-route53:auth = certbot_dns_route53.authenticator:Authenticator'
'certbot-route53:auth = certbot_dns_route53._internal.dns_route53:HiddenAuthenticator',
],
},
)

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',

View File

@@ -294,7 +294,7 @@ def dumps(blocks: UnspacedList) -> str:
"""Dump to a Unicode string.
:param UnspacedList blocks: The parsed tree
:rtype: six.text_type
:rtype: str
"""
return str(RawNginxDumper(blocks.spaced))

View File

@@ -1,7 +1,7 @@
from setuptools import find_packages
from setuptools import setup
version = '2.12.0.dev0'
version = '3.1.0.dev0'
install_requires = [
# We specify the minimum acme and certbot version as the current plugin

View File

@@ -1,8 +1,9 @@
# Certbot change log
Certbot adheres to [Semantic Versioning](https://semver.org/).
## 2.12.0 - master
## 3.1.0 - main
### Added
@@ -18,6 +19,31 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
More details about these changes can be found on our GitHub repo.
## 3.0.0 - 2024-11-05
### Added
*
### Changed
* The update_symlinks command was removed.
* The `csr_dir` and `key_dir` attributes on
`certbot.configuration.NamespaceConfig` were removed.
* The `--manual-public-ip-logging-ok` command line flag was removed.
* The `--dns-route53-propagation-seconds` command line flag was removed.
* The `certbot_dns_route53.authenticator` module has been removed. This should
not affect any users of the plugin and instead would only affect developers
trying to develop on top of the old code.
* Support for Python 3.8 was deprecated and will be removed in our next planned
release.
### Fixed
*
More details about these changes can be found on our GitHub repo.
## 2.11.0 - 2024-06-05
### Added

View File

@@ -2,10 +2,10 @@
|build-status|
.. |build-status| image:: https://img.shields.io/azure-devops/build/certbot/ba534f81-a483-4b9b-9b4e-a60bec8fee72/5/master
.. |build-status| image:: https://img.shields.io/azure-devops/build/certbot/ba534f81-a483-4b9b-9b4e-a60bec8fee72/5/main
:target: https://dev.azure.com/certbot/certbot/_build?definitionId=5
:alt: Azure Pipelines CI status
.. image:: https://raw.githubusercontent.com/EFForg/design/master/logos/eff-certbot-lockup.png
:width: 200
:alt: EFF Certbot Logo
@@ -39,7 +39,7 @@ Documentation: https://certbot.eff.org/docs
Software project: https://github.com/certbot/certbot
Changelog: https://github.com/certbot/certbot/blob/master/certbot/CHANGELOG.md
Changelog: https://github.com/certbot/certbot/blob/main/certbot/CHANGELOG.md
For Contributors: https://certbot.eff.org/docs/contributing.html

View File

@@ -1,4 +1,13 @@
"""Certbot client."""
import sys
import warnings
# version number like 1.2.3a0, must have at least 2 parts, like 1.2
__version__ = '2.12.0.dev0'
__version__ = '3.1.0.dev0'
if sys.version_info[:2] == (3, 8):
warnings.warn(
"Python 3.8 support will be dropped in the next planned release of "
"certbot. Please upgrade your Python version.",
PendingDeprecationWarning,
) # pragma: no cover

View File

@@ -30,22 +30,6 @@ logger = logging.getLogger(__name__)
###################
def update_live_symlinks(config: configuration.NamespaceConfig) -> None:
"""Update the certificate file family symlinks to use archive_dir.
Use the information in the config file to make symlinks point to
the correct archive directory.
.. note:: This assumes that the installation is using a Reverter object.
:param config: Configuration.
:type config: :class:`certbot._internal.configuration.NamespaceConfig`
"""
for renewal_file in storage.renewal_conf_files(config):
storage.RenewableCert(renewal_file, config, update_symlinks=True)
def rename_lineage(config: configuration.NamespaceConfig) -> None:
"""Rename the specified lineage to the new name.

View File

@@ -58,7 +58,6 @@ class HelpfulArgumentParser:
"revoke": main.revoke,
"rollback": main.rollback,
"everything": main.run,
"update_symlinks": main.update_symlinks,
"certificates": main.certificates,
"delete": main.delete,
"enhance": main.enhance,

View File

@@ -182,9 +182,6 @@ BACKUP_DIR = "backups"
"""Directory (relative to `certbot.configuration.NamespaceConfig.work_dir`)
where backups are kept."""
CSR_DIR = "csr"
"""See `certbot.configuration.NamespaceConfig.csr_dir`."""
IN_PROGRESS_DIR = "IN_PROGRESS"
"""Directory used before a permanent checkpoint is finalized (relative to
`certbot.configuration.NamespaceConfig.work_dir`)."""

View File

@@ -15,7 +15,6 @@ from typing import Optional
from typing import Tuple
from typing import TypeVar
from typing import Union
import warnings
import configobj
import josepy as jose
@@ -1266,27 +1265,6 @@ def rollback(config: configuration.NamespaceConfig, plugins: plugins_disco.Plugi
client.rollback(config.installer, config.checkpoints, config, plugins)
def update_symlinks(config: configuration.NamespaceConfig,
unused_plugins: plugins_disco.PluginsRegistry) -> None:
"""Update the certificate file family symlinks
Use the information in the config file to make symlinks point to
the correct archive directory.
:param config: Configuration object
:type config: configuration.NamespaceConfig
:param unused_plugins: List of plugins (deprecated)
:type unused_plugins: plugins_disco.PluginsRegistry
:returns: `None`
:rtype: None
"""
warnings.warn("update_symlinks is deprecated and will be removed", PendingDeprecationWarning)
cert_manager.update_live_symlinks(config)
def rename(config: configuration.NamespaceConfig,
unused_plugins: plugins_disco.PluginsRegistry) -> None:
"""Rename a certificate
@@ -1888,6 +1866,10 @@ def main(cli_args: Optional[List[str]] = None) -> Optional[Union[str, int]]:
if config.func != plugins_cmd: # pylint: disable=comparison-with-callable
raise
if sys.version_info[:2] == (3, 8):
logger.warning("Python 3.8 support will be dropped in the next planned release "
"of Certbot - please upgrade your Python version.")
with make_displayer(config) as displayer:
display_obj.set_display(displayer)

View File

@@ -108,7 +108,6 @@ permitted by DNS standards.)
help='Path or command to execute for the authentication script')
add('cleanup-hook',
help='Path or command to execute for the cleanup script')
util.add_deprecated_argument(add, 'public-ip-logging-ok', 0)
def prepare(self) -> None: # pylint: disable=missing-function-docstring
if self.config.noninteractive_mode and not self.conf('auth-hook'):

View File

@@ -33,6 +33,7 @@ _ARCH_TRIPLET_MAP = {
'amd64': 'x86_64-linux-gnu',
's390x': 's390x-linux-gnu',
}
CURRENT_PYTHON_VERSION_STRING = 'python3.12'
LOGGER = logging.getLogger(__name__)
@@ -71,10 +72,35 @@ def prepare_env(cli_args: List[str]) -> List[str]:
raise e
data = response.json()
connections = ['/snap/{0}/current/lib/python3.8/site-packages/'.format(item['slot']['snap'])
for item in data.get('result', {}).get('established', [])
if item.get('plug', {}).get('plug') == 'plugin'
and item.get('plug-attrs', {}).get('content') == 'certbot-1']
connections = []
outdated_plugins = []
for plugin in data.get('result', {}).get('established', []):
plug: str = plugin.get('plug', {}).get('plug')
plug_content: str = plugin.get('plug-attrs', {}).get('content')
if plug == 'plugin' and plug_content == 'certbot-1':
plugin_name: str = plugin['slot']['snap']
# First, check that the plugin is using our expected python version,
# i.e. its "read" slot is something like
# "$SNAP/lib/python3.12/site-packages". If not, skip it and print an
# error.
slot_read: str = plugin.get('slot-attrs', {}).get('read', [])
if len(slot_read) != 0 and CURRENT_PYTHON_VERSION_STRING not in slot_read[0]:
outdated_plugins.append(plugin_name)
continue
connections.append('/snap/{0}/current/lib/{1}/site-packages/'.format(
plugin_name,
CURRENT_PYTHON_VERSION_STRING
))
if outdated_plugins:
LOGGER.warning('The following plugins are using an outdated python version and must be '
'updated to be compatible with Certbot 3.0. Please see '
'https://community.letsencrypt.org/t/'
'certbot-3-0-could-have-potential-third-party-snap-breakages/226940 '
'for more information:')
plugin_list = '\n'.join(' * {}'.format(plugin) for plugin in outdated_plugins)
LOGGER.warning(plugin_list)
os.environ['CERTBOT_PLUGIN_PATH'] = ':'.join(connections)

View File

@@ -455,8 +455,7 @@ class RenewableCert(interfaces.RenewableCert):
renewal configuration file and/or systemwide defaults.
"""
def __init__(self, config_filename: str, cli_config: configuration.NamespaceConfig,
update_symlinks: bool = False) -> None:
def __init__(self, config_filename: str, cli_config: configuration.NamespaceConfig) -> None:
"""Instantiate a RenewableCert object from an existing lineage.
:param str config_filename: the path to the renewal config file
@@ -505,8 +504,6 @@ class RenewableCert(interfaces.RenewableCert):
self.live_dir = os.path.dirname(self.cert)
self._fix_symlinks()
if update_symlinks:
self._update_symlinks()
self._check_symlinks()
@property
@@ -593,17 +590,6 @@ class RenewableCert(interfaces.RenewableCert):
raise errors.CertStorageError("target {0} of symlink {1} does "
"not exist".format(target, link))
def _update_symlinks(self) -> None:
"""Updates symlinks to use archive_dir"""
for kind in ALL_FOUR:
link = getattr(self, kind)
previous_link = get_link_target(link)
new_link = os.path.join(self.relative_archive_dir(link),
os.path.basename(previous_link))
os.unlink(link)
os.symlink(new_link, link)
def _consistent(self) -> bool:
"""Are the files associated with this lineage self-consistent?
@@ -636,10 +622,7 @@ class RenewableCert(interfaces.RenewableCert):
"cert lineage's directory within the "
"official archive directory. Link: %s, "
"target directory: %s, "
"archive directory: %s. If you've specified "
"the archive directory in the renewal configuration "
"file, you may need to update links by running "
"certbot update_symlinks.",
"archive directory: %s.",
link, os.path.dirname(target), self.archive_dir)
return False

View File

@@ -65,44 +65,6 @@ class BaseCertManagerTest(test_util.ConfigTestCase):
return config_file
class UpdateLiveSymlinksTest(BaseCertManagerTest):
"""Tests for certbot._internal.cert_manager.update_live_symlinks
"""
def test_update_live_symlinks(self):
"""Test update_live_symlinks"""
# create files with incorrect symlinks
from certbot._internal import cert_manager
archive_paths = {}
for domain in self.domains:
custom_archive = self.domains[domain]
if custom_archive is not None:
archive_dir_path = custom_archive
else:
archive_dir_path = os.path.join(self.config.default_archive_dir, domain)
archive_paths[domain] = {kind:
os.path.join(archive_dir_path, kind + "1.pem") for kind in ALL_FOUR}
for kind in ALL_FOUR:
live_path = self.config_files[domain][kind]
archive_path = archive_paths[domain][kind]
open(archive_path, 'a').close()
# path is incorrect but base must be correct
os.symlink(os.path.join(self.config.config_dir, kind + "1.pem"), live_path)
# run update symlinks
cert_manager.update_live_symlinks(self.config)
# check that symlinks go where they should
prev_dir = os.getcwd()
try:
for domain in self.domains:
for kind in ALL_FOUR:
os.chdir(os.path.dirname(self.config_files[domain][kind]))
assert filesystem.realpath(filesystem.readlink(self.config_files[domain][kind])) == \
filesystem.realpath(archive_paths[domain][kind])
finally:
os.chdir(prev_dir)
class DeleteTest(storage_test.BaseRenewableCertTest):
"""Tests for certbot._internal.cert_manager.delete
"""

View File

@@ -594,7 +594,7 @@ class ParseTest(unittest.TestCase):
assert_set_by_user_with_value(namespace, 'text_mode', True)
assert_set_by_user_with_value(namespace, 'verbose_count', 1)
assert_set_by_user_with_value(namespace, 'email', 'foo@example.com')
def test_arg_with_contained_spaces(self):
# This can happen if a user specifies an arg like "-d foo.com" enclosed
# in double quotes, or as its own line in a docker-compose.yml file (as

View File

@@ -48,7 +48,6 @@ class NamespaceConfigTest(test_util.ConfigTestCase):
def test_dynamic_dirs(self, mock_constants):
mock_constants.ACCOUNTS_DIR = 'acc'
mock_constants.BACKUP_DIR = 'backups'
mock_constants.CSR_DIR = 'csr'
mock_constants.IN_PROGRESS_DIR = '../p'
mock_constants.KEY_DIR = 'keys'
@@ -60,12 +59,6 @@ class NamespaceConfigTest(test_util.ConfigTestCase):
os.path.normpath(os.path.join(self.config.config_dir, ref_path))
assert os.path.normpath(self.config.backup_dir) == \
os.path.normpath(os.path.join(self.config.work_dir, 'backups'))
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
assert os.path.normpath(self.config.csr_dir) == \
os.path.normpath(os.path.join(self.config.config_dir, 'csr'))
assert os.path.normpath(self.config.key_dir) == \
os.path.normpath(os.path.join(self.config.config_dir, 'keys'))
assert os.path.normpath(self.config.in_progress_dir) == \
os.path.normpath(os.path.join(self.config.work_dir, '../p'))
assert os.path.normpath(self.config.temp_checkpoint_dir) == \
@@ -100,10 +93,6 @@ class NamespaceConfigTest(test_util.ConfigTestCase):
os.path.join(os.getcwd(), logs_base)
assert os.path.isabs(config.accounts_dir)
assert os.path.isabs(config.backup_dir)
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
assert os.path.isabs(config.csr_dir)
assert os.path.isabs(config.key_dir)
assert os.path.isabs(config.in_progress_dir)
assert os.path.isabs(config.temp_checkpoint_dir)

View File

@@ -1215,11 +1215,6 @@ class MainTest(test_util.ConfigTestCase):
client.rollback.assert_called_once_with(
mock.ANY, 123, mock.ANY, mock.ANY)
@mock.patch('certbot._internal.cert_manager.update_live_symlinks')
def test_update_symlinks(self, mock_cert_manager):
self._call_no_clientmock(['update_symlinks'])
assert 1 == mock_cert_manager.call_count
@mock.patch('certbot._internal.cert_manager.certificates')
def test_certificates(self, mock_cert_manager):
self._call_no_clientmock(['certificates'])

View File

@@ -838,21 +838,6 @@ class RenewableCertTests(BaseRenewableCertTest):
assert stat.S_IMODE(os.lstat(temp).st_mode) == \
stat.S_IMODE(os.lstat(temp2).st_mode)
def test_update_symlinks(self):
from certbot._internal import storage
archive_dir_path = os.path.join(self.config.config_dir, "archive", "example.org")
for kind in ALL_FOUR:
live_path = self.config_file[kind]
basename = kind + "1.pem"
archive_path = os.path.join(archive_dir_path, basename)
open(archive_path, 'a').close()
os.symlink(os.path.join(self.config.config_dir, basename), live_path)
with pytest.raises(errors.CertStorageError):
storage.RenewableCert(self.config_file.filename,
self.config)
storage.RenewableCert(self.config_file.filename, self.config,
update_symlinks=True)
def test_truncate(self):
# It should not do anything when there's less than 5 cert history
for kind in ALL_FOUR:

View File

@@ -8,7 +8,6 @@ from typing import Dict
from typing import List
from typing import Optional
from urllib import parse
import warnings
from certbot import errors
from certbot import util
@@ -43,9 +42,7 @@ class NamespaceConfig:
paths defined in :py:mod:`certbot._internal.constants`:
- `accounts_dir`
- `csr_dir`
- `in_progress_dir`
- `key_dir`
- `temp_checkpoint_dir`
And the following paths are dynamically resolved using
@@ -285,25 +282,11 @@ class NamespaceConfig:
"""Configuration backups directory."""
return os.path.join(self.namespace.work_dir, constants.BACKUP_DIR)
@property
def csr_dir(self) -> str:
"""Directory where new Certificate Signing Requests (CSRs) are saved."""
warnings.warn("NamespaceConfig.csr_dir is deprecated and will be removed in an upcoming "
"release of Certbot", DeprecationWarning)
return os.path.join(self.namespace.config_dir, constants.CSR_DIR)
@property
def in_progress_dir(self) -> str:
"""Directory used before a permanent checkpoint is finalized."""
return os.path.join(self.namespace.work_dir, constants.IN_PROGRESS_DIR)
@property
def key_dir(self) -> str:
"""Keys storage."""
warnings.warn("NamespaceConfig.key_dir is deprecated and will be removed in an upcoming "
"release of Certbot", DeprecationWarning)
return os.path.join(self.namespace.config_dir, constants.KEY_DIR)
@property
def temp_checkpoint_dir(self) -> str:
"""Temporary checkpoint directory."""

View File

@@ -25,6 +25,10 @@ from certbot.plugins import common
logger = logging.getLogger(__name__)
# As of writing this, the only one of our plugins that does not inherit from this class (either
# directly or indirectly through certbot.plugins.dns_common_lexicon.LexiconDNSAuthenticator) is
# certbot-dns-route53. If you are attempting to make changes to all of our DNS plugins, please keep
# this difference in mind.
class DNSAuthenticator(common.Plugin, interfaces.Authenticator, metaclass=abc.ABCMeta):
"""Base class for DNS Authenticators"""

View File

@@ -122,7 +122,7 @@ options:
case, and to know when to deprecate support for past
Python versions and flags. If you wish to hide this
information from the Let's Encrypt server, set this to
"". (default: CertbotACMEClient/2.11.0 (certbot;
"". (default: CertbotACMEClient/3.0.0 (certbot;
OS_NAME OS_VERSION) Authenticator/XXX Installer/YYY
(SUBCOMMAND; flags: FLAGS) Py/major.minor.patchlevel).
The flags encoded in the user agent are: --duplicate,

View File

@@ -17,8 +17,11 @@ its dependencies, Certbot needs to be run on a UNIX-like OS so if you're using
Windows, you'll need to set up a (virtual) machine running an OS such as Linux
and continue with these instructions on that UNIX-like OS.
If you're using macOS, it is recommended to first check out the `macOS
suggestions`_ section before continuing with the installation instructions
below.
.. _local copy:
.. _prerequisites:
Running a local copy of the client
----------------------------------
@@ -48,9 +51,10 @@ Install and configure the OS system dependencies required to run Certbot.
sudo dnf install python3 augeas-libs
# For macOS installations with Homebrew already installed and configured
# NB: If you also run `brew install python` you don't need the ~/lib
# directory created below, however, Certbot's Apache plugin won't work
# if you use Python installed from other sources such as pyenv or the
# version provided by Apple.
# directory created below, however, without this directory and symlinks
# to augeas, Certbot's Apache plugin won't work if you use Python
# installed from other sources such as pyenv or the version provided by
# Apple.
brew install augeas
mkdir ~/lib
ln -s $(brew --prefix)/lib/libaugeas* ~/lib
@@ -92,17 +96,15 @@ found in the `virtualenv docs`_.
Find issues to work on
----------------------
You can find the open issues in the `github issue tracker`_. Comparatively
easy ones are marked `good first issue`_. If you're starting work on
something, post a comment to let others know and seek feedback on your plan
where appropriate.
You can find the open issues in the `github issue tracker`_. If you're starting
work on something, post a comment to let others know and seek feedback on your
plan where appropriate.
Once you've got a working branch, you can open a pull request. All changes in
your pull request must have thorough unit test coverage, pass our
tests, and be compliant with the :ref:`coding style <coding-style>`.
.. _github issue tracker: https://github.com/certbot/certbot/issues
.. _good first issue: https://github.com/certbot/certbot/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22
.. _testing:
@@ -254,8 +256,8 @@ certificate once it is issued. Some plugins, like the built-in Apache and Nginx
plugins, implement both interfaces and perform both tasks. Others, like the
built-in Standalone authenticator, implement just one interface.
.. _interfaces.py: https://github.com/certbot/certbot/blob/master/certbot/certbot/interfaces.py
.. _plugins/common.py: https://github.com/certbot/certbot/blob/master/certbot/certbot/plugins/common.py#L45
.. _interfaces.py: https://github.com/certbot/certbot/blob/main/certbot/certbot/interfaces.py
.. _plugins/common.py: https://github.com/certbot/certbot/blob/main/certbot/certbot/plugins/common.py#L45
Authenticators
@@ -375,8 +377,8 @@ Certbot plugin snaps expose their Python modules to the Certbot snap via a
`snap content interface`_ where ``certbot-1`` is the value for the ``content``
attribute. The Certbot snap only uses this to find the names of connected
plugin snaps and it expects to find the Python modules to be loaded under
``lib/python3.8/site-packages/`` in the plugin snap. This location is the
default when using the ``core20`` `base snap`_ and the `python snapcraft
``lib/python3.12/site-packages/`` in the plugin snap. This location is the
default when using the ``core24`` `base snap`_ and the `python snapcraft
plugin`_.
The Certbot snap also provides a separate content interface which
@@ -385,7 +387,7 @@ identifier ``metadata-1``.
The script used to generate the snapcraft.yaml files for our own externally
snapped plugins can be found at
https://github.com/certbot/certbot/blob/master/tools/snap/generate_dnsplugins_snapcraft.sh.
https://github.com/certbot/certbot/blob/main/tools/snap/generate_dnsplugins_snapcraft.sh.
For more information on building externally snapped plugins, see the section on
:ref:`Building snaps`.
@@ -558,7 +560,7 @@ Building the Certbot and DNS plugin snaps
Instructions for how to manually build and run the Certbot snap and the externally
snapped DNS plugins that the Certbot project supplies are located in the README
file at https://github.com/certbot/certbot/tree/master/tools/snap.
file at https://github.com/certbot/certbot/tree/main/tools/snap.
Updating the documentation
==========================
@@ -647,3 +649,28 @@ If a dependency is already packaged in these distros and is acceptable for use i
the oldest packaged version of that dependency should be chosen and set as the minimum
version in ``setup.py``.
macOS suggestions
=================
If you're developing on macOS, before :ref:`setting up your Certbot development
environment <local copy>`, it is recommended you perform the following steps.
None of this is required, but it is the approach used by all/most of the
current Certbot developers on macOS as of writing this:
0. Install `Homebrew <https://brew.sh/>`_. It is the most popular package
manager on macOS by a wide margin and works well enough.
1. Install `pyenv <https://github.com/pyenv/pyenv>`_, ideally through Homebrew
by running ``brew install pyenv``. Using Homebrew's Python for Certbot
development is annoying because it regularly updates and every time it does
it breaks your virtual environments. Using Python from ``pyenv`` avoids this
problem and gives you easy access to all versions of Python.
2. If you're using ``pyenv``, make sure you've set up your shell for it by
following instructions like
https://github.com/pyenv/pyenv?tab=readme-ov-file#set-up-your-shell-environment-for-pyenv.
3. Configure ``git`` to ignore the ``.DS_Store`` files that are created by
macOS's file manager Finder by running something like:
.. code-block:: shell
mkdir -p ~/.config/git
echo '.DS_Store' >> ~/.config/git/ignore

View File

@@ -25,7 +25,7 @@ We release packages and upload them to PyPI (wheels and source tarballs).
The following scripts are used in the process:
- https://github.com/certbot/certbot/blob/master/tools/release.sh
- https://github.com/certbot/certbot/blob/main/tools/release.sh
We use git tags to identify releases, using `Semantic Versioning`_. For
example: `v0.11.1`.
@@ -50,7 +50,7 @@ key servers.
Notes for package maintainers
=============================
0. Please use our tagged releases, not ``master``!
0. Please use our tagged releases, not ``main``!
1. Do not package ``certbot-compatibility-test`` as it's only used internally.

View File

@@ -99,7 +99,7 @@ Apache
------
The Apache plugin currently `supports
<https://github.com/certbot/certbot/blob/master/certbot-apache/certbot_apache/_internal/entrypoint.py>`_
<https://github.com/certbot/certbot/blob/main/certbot-apache/certbot_apache/_internal/entrypoint.py>`_
modern OSes based on Debian, Fedora, SUSE, Gentoo, CentOS and Darwin.
This automates both obtaining *and* installing certificates on an Apache
webserver. To specify this plugin on the command line, simply include
@@ -327,6 +327,7 @@ standalone-nfq_ Y N HTTP Authentication that works with any webserver (
dns-solidserver_ Y N DNS Authentication using SOLIDserver (EfficientIP)
dns-stackit_ Y N DNS Authentication using STACKIT DNS
dns-ionos_ Y N DNS Authentication using IONOS Cloud DNS
dns-mijn-host_ Y N DNS Authentication using mijn.host DNS
================== ==== ==== ===============================================================
.. _haproxy: https://github.com/greenhost/certbot-haproxy
@@ -355,6 +356,7 @@ dns-ionos_ Y N DNS Authentication using IONOS Cloud DNS
.. _dns-solidserver: https://gitlab.com/charlyhong/certbot-dns-solidserver
.. _dns-stackit: https://github.com/stackitcloud/certbot-dns-stackit
.. _dns-ionos: https://github.com/ionos-cloud/certbot-dns-ionos-cloud
.. _dns-mijn-host: https://github.com/mijnhost/certbot-dns-mijn-host
If you're interested, you can also :ref:`write your own plugin <dev-plugin>`.

View File

@@ -34,7 +34,9 @@ install_requires = [
'distro>=1.0.1',
'importlib_resources>=1.3.1; python_version < "3.9"',
'importlib_metadata>=4.6; python_version < "3.10"',
'josepy>=1.13.0',
# Josepy 2+ may introduce backward incompatible changes by droping usage of
# deprecated PyOpenSSL APIs.
'josepy>=1.13.0, <2',
'parsedatetime>=2.4',
'pyrfc3339',
'pytz>=2019.3',
@@ -83,7 +85,6 @@ test_extras = [
'types-pywin32',
'types-requests',
'types-setuptools',
'types-six',
'wheel',
]

View File

@@ -66,9 +66,9 @@ parser.add_argument('--branch',
parser.add_argument('--pull_request',
default='~',
help='certbot/certbot pull request to trial')
parser.add_argument('--merge_master',
parser.add_argument('--merge_main',
action='store_true',
help="if set merges PR into master branch of certbot/certbot")
help="if set merges PR into main branch of certbot/certbot")
parser.add_argument('--saveinstances',
action='store_true',
help="don't kill EC2 instances after run, useful for debugging")
@@ -207,7 +207,7 @@ def block_until_instance_ready(booting_instance, extra_wait_time=20):
# Fabric Routines
#-------------------------------------------------------------------------------
def local_git_clone(local_cxn, repo_url, log_dir):
"""clones master of repo_url"""
"""clones main of repo_url"""
local_cxn.local('cd %s && if [ -d letsencrypt ]; then rm -rf letsencrypt; fi' % log_dir)
local_cxn.local('cd %s && git clone %s letsencrypt'% (log_dir, repo_url))
local_cxn.local('cd %s && tar czf le.tar.gz letsencrypt'% log_dir)
@@ -219,17 +219,17 @@ def local_git_branch(local_cxn, repo_url, branch_name, log_dir):
(log_dir, repo_url, branch_name))
local_cxn.local('cd %s && tar czf le.tar.gz letsencrypt' % log_dir)
def local_git_PR(local_cxn, repo_url, PRnumstr, log_dir, merge_master=True):
"""clones specified pull request from repo_url and optionally merges into master"""
def local_git_PR(local_cxn, repo_url, PRnumstr, log_dir, merge_main=True):
"""clones specified pull request from repo_url and optionally merges into main"""
local_cxn.local('cd %s && if [ -d letsencrypt ]; then rm -rf letsencrypt; fi' % log_dir)
local_cxn.local('cd %s && git clone %s letsencrypt' % (log_dir, repo_url))
local_cxn.local('cd %s && cd letsencrypt && '
'git fetch origin pull/%s/head:lePRtest' % (log_dir, PRnumstr))
local_cxn.local('cd %s && cd letsencrypt && git checkout lePRtest' % log_dir)
if merge_master:
if merge_main:
local_cxn.local('cd %s && cd letsencrypt && git remote update origin' % log_dir)
local_cxn.local('cd %s && cd letsencrypt && '
'git merge origin/master -m "testmerge"' % log_dir)
'git merge origin/main -m "testmerge"' % log_dir)
local_cxn.local('cd %s && tar czf le.tar.gz letsencrypt' % log_dir)
def local_repo_to_remote(cxn, log_dir):
@@ -286,15 +286,15 @@ def create_client_instance(ec2_client, target, security_group_id, subnet_id, sel
# 32 bit systems
machine_type = 'c1.medium'
name = 'le-%s'%target['name']
print(name, end=" ")
return make_instance(ec2_client,
name,
target['ami'],
KEYNAME,
machine_type=machine_type,
security_group_id=security_group_id,
subnet_id=subnet_id,
self_destruct=self_destruct)
try:
instance = make_instance(ec2_client, name, target['ami'], KEYNAME,
machine_type=machine_type, security_group_id=security_group_id,
subnet_id=subnet_id, self_destruct=self_destruct)
except Exception:
print(f'FAIL: Unable to create instance {name}')
raise
print(f'Created instance {name}')
return instance
def test_client_process(fab_config, inqueue, outqueue, log_dir):
@@ -382,9 +382,9 @@ def main():
print("Making local git repo")
if cl_args.pull_request != '~':
print('Testing PR %s ' % cl_args.pull_request,
"MERGING into master" if cl_args.merge_master else "")
"MERGING into main" if cl_args.merge_main else "")
local_git_PR(local_cxn, cl_args.repo, cl_args.pull_request, log_dir,
cl_args.merge_master)
cl_args.merge_main)
elif cl_args.branch != '~':
print('Testing branch %s of %s' % (cl_args.branch, cl_args.repo))
local_git_branch(local_cxn, cl_args.repo, cl_args.branch, log_dir)
@@ -435,7 +435,6 @@ def main():
instances = []
try:
print("Creating instances: ", end="")
# If we want to preserve instances, do not have them self-destruct.
self_destruct = not cl_args.saveinstances
for target in targetlist:
@@ -444,7 +443,6 @@ def main():
security_group_id, subnet_id,
self_destruct)
)
print()
# Install and launch client scripts in parallel
#-------------------------------------------------------------------------------

View File

@@ -33,7 +33,7 @@ targets:
#-----------------------------------------------------------------------------
# CentOS
# These AMI were found on https://centos.org/download/aws-images/.
- ami: ami-08f2fe20b72b2ffa7
- ami: ami-00d53d23711185071
name: centos9stream
type: centos
virt: hvm

View File

@@ -19,17 +19,19 @@
# unit tests. This warning should be ignored until our (transitive)
# dependency on requests-toolbelt is removed or our pinned version can be
# updated.
# 4) Ignore our own PendingDeprecationWarning about update_symlinks soon to be dropped.
# See https://github.com/certbot/certbot/issues/6284.
# 5) Ignore DeprecationWarning for datetime.utcfromtimestamp() triggered
# 4) Ignore DeprecationWarning for datetime.utcfromtimestamp() triggered
# from dateutil. See https://github.com/dateutil/dateutil/issues/1314.
# 6) Ignoring this allows us to continue to update pyOpenSSL (one of our crypto
# 5) Ignoring this allows us to continue to update pyOpenSSL (one of our crypto
# dependencies) until https://github.com/certbot/certbot/issues/9828 is resolved.
# 6) Similarly to 6), CSR support is deprecated in pyOpenSSL since 24.2, we silence
# the warning until https://github.com/certbot/certbot/issues/9992 is resolved.
# 7) Ignore our own PendingDeprecationWarning about Python 3.8 soon to be dropped.
filterwarnings =
error
ignore:decodestring\(\) is a deprecated alias:DeprecationWarning:dns
ignore:.*rsyncdir:DeprecationWarning
ignore:'urllib3.contrib.pyopenssl:DeprecationWarning:requests_toolbelt
ignore:update_symlinks is deprecated:PendingDeprecationWarning
ignore:.*datetime.utcfromtimestamp\(\) is deprecated:DeprecationWarning:dateutil
ignore:X509Extension support in pyOpenSSL is deprecated:DeprecationWarning
ignore:CSR support in pyOpenSSL is deprecated:DeprecationWarning
ignore:Python 3.8 support will be dropped:PendingDeprecationWarning

View File

@@ -14,13 +14,16 @@ description: |
- Keep track of when your certificate is going to expire, and renew it
- Help you revoke the certificate if that ever becomes necessary.
confinement: classic
base: core20
base: core24
grade: stable
adopt-info: certbot
environment:
PYTHONPATH: "$SNAP/lib/python3.12/site-packages:${PYTHONPATH}"
apps:
certbot:
command: bin/python3 -s $SNAP/bin/certbot
command: bin/python3-dbg -s $SNAP/bin/certbot
environment:
PATH: "$SNAP/bin:$SNAP/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
AUGEAS_LENS_LIB: "$SNAP/usr/share/augeas/lenses/dist"
@@ -47,7 +50,8 @@ parts:
- ./certbot-apache
- ./certbot-nginx
stage:
- -usr/lib/python3.8/sitecustomize.py # maybe unnecessary
- -usr/lib/python3.12/sitecustomize.py # maybe unnecessary
- -pyvenv.cfg
# Old versions of this file used to unstage
# lib/python3.8/site-packages/augeas.py to avoid conflicts between
# python-augeas 0.5.0 which was pinned in snap-constraints.txt and
@@ -57,19 +61,20 @@ parts:
# effect so we now stage the file to keep the auto-generated cffi file.
stage-packages:
- libaugeas0
- libpython3.8-dev
- libpython3.12-dev
# added to stage python:
- libpython3-stdlib
- libpython3.8-stdlib
- libpython3.8-minimal
- libpython3.12-stdlib
- libpython3.12-minimal
- python3-pip
- python3-wheel
- python3-venv
- python3-minimal
- python3-distutils
- python3-pkg-resources
- python3.8-minimal
# To build cryptography and cffi if needed
- python3.12-minimal
- libpython3-all-dbg
- python3-dbg
- python3.12-dbg
build-packages:
- gcc
- git
@@ -77,7 +82,9 @@ parts:
- build-essential
- libssl-dev
- libffi-dev
- python3-dev
- libpython3-all-dbg
- python3-dbg
- python3-venv
- cargo
- pkg-config
build-environment:
@@ -85,28 +92,31 @@ parts:
# stability of fetching the rust crates needed to build the cryptography
# library.
- CARGO_NET_GIT_FETCH_WITH_CLI: "true"
- SNAPCRAFT_PYTHON_VENV_ARGS: --upgrade
- PARTS_PYTHON_VENV_ARGS: --upgrade
# Constraints are passed through the environment variable PIP_CONSTRAINTS instead of using the
# parts.[part_name].constraints option available in snapcraft.yaml when the Python plugin is
# used. This is done to let these constraints be applied not only on the certbot package
# build, but also on any isolated build that pip could trigger when building wheels for
# dependencies. See https://github.com/certbot/certbot/pull/8443 for more info.
- PIP_CONSTRAINT: $SNAPCRAFT_PART_SRC/snap-constraints.txt
- PIP_CONSTRAINT: $CRAFT_PART_SRC/snap-constraints.txt
- PARTS_PYTHON_INTERPRETER: "python3-dbg"
override-build: |
python3 -m venv "${SNAPCRAFT_PART_INSTALL}"
"${SNAPCRAFT_PART_INSTALL}/bin/python3" "${SNAPCRAFT_PART_SRC}/tools/pipstrap.py"
snapcraftctl build
python3-dbg -m venv "${CRAFT_PART_INSTALL}"
"${CRAFT_PART_INSTALL}/bin/python3-dbg" "${CRAFT_PART_SRC}/tools/pipstrap.py"
craftctl default
override-pull: |
snapcraftctl pull
grep -v python-augeas "${SNAPCRAFT_PART_SRC}/tools/requirements.txt" >> "${SNAPCRAFT_PART_SRC}/snap-constraints.txt"
snapcraftctl set-version `grep -oP "__version__ = '\K.*(?=')" "${SNAPCRAFT_PART_SRC}/certbot/certbot/__init__.py"`
craftctl default
grep -v python-augeas "${CRAFT_PART_SRC}/tools/requirements.txt" >> "${CRAFT_PART_SRC}/snap-constraints.txt"
craftctl set version=$(grep -oP "__version__ = '\K.*(?=')" "${CRAFT_PART_SRC}/certbot/certbot/__init__.py")
build-attributes:
- enable-patchelf
shared-metadata:
plugin: dump
source: .
override-pull: |
snapcraftctl pull
craftctl default
mkdir -p certbot-metadata
grep -oP "__version__ = '\K.*(?=')" $SNAPCRAFT_PART_SRC/certbot/certbot/__init__.py > certbot-metadata/certbot-version.txt
grep -oP "__version__ = '\K.*(?=')" $CRAFT_PART_SRC/certbot/certbot/__init__.py > certbot-metadata/certbot-version.txt
stage: [certbot-metadata/certbot-version.txt]
plugs:

View File

@@ -1,4 +1,4 @@
## nextversion - master
## nextversion - main
### Added

View File

@@ -39,7 +39,7 @@ if [ "$RELEASE_GPG_KEY" = "" ]; then
F2871B4152AE13C49519111F447BF683AA3B26C3
"
for key in $TRUSTED_KEYS; do
if gpg2 --with-colons --card-status | grep -q "$key"; then
if gpg --with-colons --card-status | grep -q "$key"; then
RELEASE_GPG_KEY="$key"
break
fi
@@ -97,7 +97,7 @@ fi
git checkout "$RELEASE_BRANCH"
# Update changelog
sed -i "s/master/$(date +'%Y-%m-%d')/" certbot/CHANGELOG.md
sed -i "0,/main/ s/main/$(date +'%Y-%m-%d')/" certbot/CHANGELOG.md
git add certbot/CHANGELOG.md
git commit -m "Update changelog for $version release"
@@ -157,7 +157,7 @@ done
cd "$built_package_dir"
echo "Generating checksum file and signing it"
sha256sum *.tar.gz > SHA256SUMS
gpg2 -u "$RELEASE_GPG_KEY" --detach-sign --armor --sign --digest-algo sha256 SHA256SUMS
gpg -u "$RELEASE_GPG_KEY" --detach-sign --armor --sign --digest-algo sha256 SHA256SUMS
git add *.tar.gz SHA256SUMS*
echo "Installing packages to generate documentation"
@@ -196,8 +196,8 @@ deactivate
git add certbot/docs/cli-help.txt
while ! git commit --gpg-sign="$RELEASE_GPG_KEY" -m "Release $version"; do
echo "Unable to sign the release commit using git."
echo "You may have to configure git to use gpg2 by running:"
echo 'git config --global gpg.program $(command -v gpg2)'
echo "You may have to configure git to use gpg by running:"
echo 'git config --global gpg.program $(command -v gpg)'
read -p "Press enter to try signing again."
done
git tag --local-user "$RELEASE_GPG_KEY" --sign --message "Release $version" "$tag"
@@ -205,7 +205,7 @@ git tag --local-user "$RELEASE_GPG_KEY" --sign --message "Release $version" "$ta
git rm --cached -r "$built_package_dir"
git commit -m "Remove built packages from git"
# Add master section to CHANGELOG.md
# Add main section to CHANGELOG.md
header=$(head -n 4 certbot/CHANGELOG.md)
body=$(sed s/nextversion/$nextversion/ tools/_changelog_top.txt)
footer=$(tail -n +5 certbot/CHANGELOG.md)

View File

@@ -1,5 +1,5 @@
#base image
FROM python:3.12-alpine3.18 as certbot
FROM python:3.12-alpine3.18 AS certbot
ENTRYPOINT [ "certbot" ]
EXPOSE 80 443
@@ -25,6 +25,12 @@ RUN apk add --no-cache --virtual .certbot-deps \
# cryptography library
ARG CARGO_NET_GIT_FETCH_WITH_CLI=true
# Install certbot from sources
#
# For some reason, setting the CARGO_LOG and CARGO_TERM_VERBOSE environment
# variables and -v/--verbose flags on pip seems to help cryptography builds not
# hang when building Docker images for other architectures using QEMU. See
# https://github.com/certbot/certbot/issues/10020. This may hopefully also help
# us to get more information about the problem to aid further debugging.
RUN apk add --no-cache --virtual .build-deps \
gcc \
linux-headers \
@@ -35,7 +41,8 @@ RUN apk add --no-cache --virtual .build-deps \
cargo \
git \
pkgconfig \
&& python tools/pip_install.py --no-cache-dir \
&& CARGO_LOG=trace CARGO_TERM_VERBOSE=true python tools/pip_install.py \
--no-cache-dir -vvv \
--editable src/acme \
--editable src/certbot \
&& apk del .build-deps \
@@ -44,6 +51,6 @@ RUN apk add --no-cache --virtual .build-deps \
#static definition for making a plugin, but beware that
#using this layer definition will cause collisions if you make
#extensive use of the cache.
FROM certbot as certbot-plugin
FROM certbot AS certbot-plugin
COPY --from=plugin-src . /opt/certbot/src/plugin
RUN python tools/pip_install.py --no-cache-dir --editable /opt/certbot/src/plugin

View File

@@ -70,7 +70,7 @@ ParseArgs() {
local IFS=","
# Handle the special value "all"
if [[ "${ARCH_LIST}" == "all" ]]; then
# Replace with comma separated
# Replace with comma separated
ARCH_LIST="${ALL_TARGET_ARCH[*]}"
fi
@@ -88,7 +88,7 @@ ParseArgs() {
}
# Function for use with trap in the primary scripts to remove the
# Function for use with trap in the primary scripts to remove the
# docker builder and restore the original directory
Cleanup() {
docker buildx rm certbot_builder || true
@@ -106,5 +106,11 @@ CreateBuilder() {
# just incase the env is not perfectly clean, remove any old instance of the builder
docker buildx rm certbot_builder || true
# create the builder instance
docker buildx create --name certbot_builder --driver docker-container --driver-opt=network=host --bootstrap
}
#
# BUILDKIT_STEP_LOG_MAX_* environment variables are set to prevent docker
# from truncating build logs that can be useful during debugging. See
# https://github.com/docker/buildx/issues/484#issuecomment-749352728
docker buildx create --name certbot_builder --driver docker-container \
--driver-opt=network=host --driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=-1 \
--driver-opt env.BUILDKIT_STEP_LOG_MAX_SPEED=-1 --bootstrap
}

View File

@@ -111,7 +111,7 @@ def get_snap_revisions(snap, channel, version):
print('Getting revision numbers for', snap, version)
cmd = ['snapcraft', 'status', snap]
process = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, universal_newlines=True)
pattern = f'^\s+{channel}\s+{version}\s+(\d+)\s*'
pattern = f'^\\s+{channel}\\s+{version}\\s+(\\d+)\\s*'
revisions = re.findall(pattern, process.stdout, re.MULTILINE)
assert len(revisions) == SNAP_ARCH_COUNT, f'Unexpected number of snaps found for {channel} {snap} {version} (expected {SNAP_ARCH_COUNT}, found {len(revisions)})'
return revisions

View File

@@ -2,98 +2,98 @@
# that script.
apacheconfig==0.3.2 ; python_version >= "3.8" and python_version < "3.9"
asn1crypto==0.24.0 ; python_version >= "3.8" and python_version < "3.9"
astroid==3.0.1 ; python_version >= "3.8" and python_version < "3.9"
beautifulsoup4==4.12.2 ; python_version >= "3.8" and python_version < "3.9"
astroid==3.2.4 ; python_version >= "3.8" and python_version < "3.9"
beautifulsoup4==4.12.3 ; python_version >= "3.8" and python_version < "3.9"
boto3==1.15.15 ; python_version >= "3.8" and python_version < "3.9"
botocore==1.18.15 ; python_version >= "3.8" and python_version < "3.9"
cachetools==5.3.2 ; python_version >= "3.8" and python_version < "3.9"
certifi==2023.11.17 ; python_version >= "3.8" and python_version < "3.9"
cachetools==5.5.0 ; python_version >= "3.8" and python_version < "3.9"
certifi==2024.7.4 ; python_version >= "3.8" and python_version < "3.9"
cffi==1.12.3 ; python_version >= "3.8" and python_version < "3.9"
chardet==3.0.4 ; python_version >= "3.8" and python_version < "3.9"
cloudflare==1.5.1 ; python_version >= "3.8" and python_version < "3.9"
colorama==0.4.6 ; python_version >= "3.8" and python_version < "3.9" and sys_platform == "win32"
configargparse==1.5.3 ; python_version >= "3.8" and python_version < "3.9"
configobj==5.0.6 ; python_version >= "3.8" and python_version < "3.9"
coverage==7.3.2 ; python_version >= "3.8" and python_version < "3.9"
coverage==7.6.1 ; python_version >= "3.8" and python_version < "3.9"
cryptography==3.2.1 ; python_version >= "3.8" and python_version < "3.9"
cython==0.29.36 ; python_version >= "3.8" and python_version < "3.9"
dill==0.3.7 ; python_version >= "3.8" and python_version < "3.9"
distlib==0.3.7 ; python_version >= "3.8" and python_version < "3.9"
cython==0.29.37 ; python_version >= "3.8" and python_version < "3.9"
dill==0.3.8 ; python_version >= "3.8" and python_version < "3.9"
distlib==0.3.8 ; python_version >= "3.8" and python_version < "3.9"
distro==1.0.1 ; python_version >= "3.8" and python_version < "3.9"
dns-lexicon==3.15.1 ; python_version >= "3.8" and python_version < "3.9"
dnspython==1.15.0 ; python_version >= "3.8" and python_version < "3.9"
exceptiongroup==1.2.0 ; python_version >= "3.8" and python_version < "3.9"
execnet==2.0.2 ; python_version >= "3.8" and python_version < "3.9"
filelock==3.13.1 ; python_version >= "3.8" and python_version < "3.9"
exceptiongroup==1.2.2 ; python_version >= "3.8" and python_version < "3.9"
execnet==2.1.1 ; python_version >= "3.8" and python_version < "3.9"
filelock==3.15.4 ; python_version >= "3.8" and python_version < "3.9"
funcsigs==0.4 ; python_version >= "3.8" and python_version < "3.9"
future==0.18.3 ; python_version >= "3.8" and python_version < "3.9"
future==1.0.0 ; python_version >= "3.8" and python_version < "3.9"
google-api-python-client==1.6.5 ; python_version >= "3.8" and python_version < "3.9"
google-auth==2.16.0 ; python_version >= "3.8" and python_version < "3.9"
httplib2==0.9.2 ; python_version >= "3.8" and python_version < "3.9"
idna==2.6 ; python_version >= "3.8" and python_version < "3.9"
importlib-metadata==4.6.4 ; python_version >= "3.8" and python_version < "3.9"
importlib-resources==6.1.1 ; python_version >= "3.8" and python_version < "3.9"
importlib-resources==6.4.4 ; python_version >= "3.8" and python_version < "3.9"
iniconfig==2.0.0 ; python_version >= "3.8" and python_version < "3.9"
ipaddress==1.0.16 ; python_version >= "3.8" and python_version < "3.9"
isort==5.12.0 ; python_version >= "3.8" and python_version < "3.9"
isort==5.13.2 ; python_version >= "3.8" and python_version < "3.9"
jmespath==0.10.0 ; python_version >= "3.8" and python_version < "3.9"
josepy==1.14.0 ; python_version >= "3.8" and python_version < "3.9"
logger==1.4 ; python_version >= "3.8" and python_version < "3.9"
mccabe==0.7.0 ; python_version >= "3.8" and python_version < "3.9"
mypy-extensions==1.0.0 ; python_version >= "3.8" and python_version < "3.9"
mypy==1.7.1 ; python_version >= "3.8" and python_version < "3.9"
mypy==1.11.2 ; python_version >= "3.8" and python_version < "3.9"
ndg-httpsclient==0.3.2 ; python_version >= "3.8" and python_version < "3.9"
oauth2client==4.1.3 ; python_version >= "3.8" and python_version < "3.9"
packaging==23.2 ; python_version >= "3.8" and python_version < "3.9"
packaging==24.1 ; python_version >= "3.8" and python_version < "3.9"
parsedatetime==2.4 ; python_version >= "3.8" and python_version < "3.9"
pbr==1.8.0 ; python_version >= "3.8" and python_version < "3.9"
pip==23.3.1 ; python_version >= "3.8" and python_version < "3.9"
platformdirs==4.0.0 ; python_version >= "3.8" and python_version < "3.9"
pluggy==1.3.0 ; python_version >= "3.8" and python_version < "3.9"
pip==24.2 ; python_version >= "3.8" and python_version < "3.9"
platformdirs==4.2.2 ; python_version >= "3.8" and python_version < "3.9"
pluggy==1.5.0 ; python_version >= "3.8" and python_version < "3.9"
ply==3.4 ; python_version >= "3.8" and python_version < "3.9"
py==1.11.0 ; python_version >= "3.8" and python_version < "3.9"
pyasn1-modules==0.3.0 ; python_version >= "3.8" and python_version < "3.9"
pyasn1-modules==0.4.0 ; python_version >= "3.8" and python_version < "3.9"
pyasn1==0.4.8 ; python_version >= "3.8" and python_version < "3.9"
pycparser==2.14 ; python_version >= "3.8" and python_version < "3.9"
pylint==3.0.2 ; python_version >= "3.8" and python_version < "3.9"
pylint==3.2.6 ; python_version >= "3.8" and python_version < "3.9"
pyopenssl==17.5.0 ; python_version >= "3.8" and python_version < "3.9"
pyotp==2.9.0 ; python_version >= "3.8" and python_version < "3.9"
pyparsing==2.2.1 ; python_version >= "3.8" and python_version < "3.9"
pyrfc3339==1.0 ; python_version >= "3.8" and python_version < "3.9"
pytest-cov==4.1.0 ; python_version >= "3.8" and python_version < "3.9"
pytest-xdist==3.5.0 ; python_version >= "3.8" and python_version < "3.9"
pytest==7.4.3 ; python_version >= "3.8" and python_version < "3.9"
pytest-cov==5.0.0 ; python_version >= "3.8" and python_version < "3.9"
pytest-xdist==3.6.1 ; python_version >= "3.8" and python_version < "3.9"
pytest==8.3.2 ; python_version >= "3.8" and python_version < "3.9"
python-augeas==0.5.0 ; python_version >= "3.8" and python_version < "3.9"
python-dateutil==2.8.2 ; python_version >= "3.8" and python_version < "3.9"
python-dateutil==2.9.0.post0 ; python_version >= "3.8" and python_version < "3.9"
python-digitalocean==1.11 ; python_version >= "3.8" and python_version < "3.9"
pytz==2019.3 ; python_version >= "3.8" and python_version < "3.9"
pywin32==306 ; python_version >= "3.8" and python_version < "3.9" and sys_platform == "win32"
pyyaml==6.0.1 ; python_version >= "3.8" and python_version < "3.9"
requests-file==1.5.1 ; python_version >= "3.8" and python_version < "3.9"
pyyaml==6.0.2 ; python_version >= "3.8" and python_version < "3.9"
requests-file==2.1.0 ; python_version >= "3.8" and python_version < "3.9"
requests==2.20.0 ; python_version >= "3.8" and python_version < "3.9"
rsa==4.9 ; python_version >= "3.8" and python_version < "3.9"
s3transfer==0.3.7 ; python_version >= "3.8" and python_version < "3.9"
setuptools==41.6.0 ; python_version >= "3.8" and python_version < "3.9"
six==1.11.0 ; python_version >= "3.8" and python_version < "3.9"
soupsieve==2.5 ; python_version >= "3.8" and python_version < "3.9"
tldextract==5.1.1 ; python_version >= "3.8" and python_version < "3.9"
soupsieve==2.6 ; python_version >= "3.8" and python_version < "3.9"
tldextract==5.1.2 ; python_version >= "3.8" and python_version < "3.9"
tomli==2.0.1 ; python_version >= "3.8" and python_version < "3.9"
tomlkit==0.12.3 ; python_version >= "3.8" and python_version < "3.9"
tomlkit==0.13.2 ; python_version >= "3.8" and python_version < "3.9"
tox==1.9.2 ; python_version >= "3.8" and python_version < "3.9"
types-cryptography==3.3.23.2 ; python_version >= "3.8" and python_version < "3.9"
types-httplib2==0.22.0.2 ; python_version >= "3.8" and python_version < "3.9"
types-httplib2==0.22.0.20240310 ; python_version >= "3.8" and python_version < "3.9"
types-pyopenssl==23.0.0.0 ; python_version >= "3.8" and python_version < "3.9"
types-pyrfc3339==1.1.1.5 ; python_version >= "3.8" and python_version < "3.9"
types-python-dateutil==2.8.19.14 ; python_version >= "3.8" and python_version < "3.9"
types-pytz==2023.3.1.1 ; python_version >= "3.8" and python_version < "3.9"
types-pywin32==306.0.0.6 ; python_version >= "3.8" and python_version < "3.9"
types-python-dateutil==2.9.0.20240821 ; python_version >= "3.8" and python_version < "3.9"
types-pytz==2024.1.0.20240417 ; python_version >= "3.8" and python_version < "3.9"
types-pywin32==306.0.0.20240822 ; python_version >= "3.8" and python_version < "3.9"
types-requests==2.31.0.6 ; python_version >= "3.8" and python_version < "3.9"
types-setuptools==69.0.0.0 ; python_version >= "3.8" and python_version < "3.9"
types-six==1.16.21.9 ; python_version >= "3.8" and python_version < "3.9"
types-setuptools==73.0.0.20240822 ; python_version >= "3.8" and python_version < "3.9"
types-six==1.16.21.20240513 ; python_version >= "3.8" and python_version < "3.9"
types-urllib3==1.26.25.14 ; python_version >= "3.8" and python_version < "3.9"
typing-extensions==4.8.0 ; python_version >= "3.8" and python_version < "3.9"
typing-extensions==4.12.2 ; python_version >= "3.8" and python_version < "3.9"
uritemplate==3.0.1 ; python_version >= "3.8" and python_version < "3.9"
urllib3==1.24.2 ; python_version >= "3.8" and python_version < "3.9"
virtualenv==20.25.0 ; python_version >= "3.8" and python_version < "3.9"
virtualenv==20.26.3 ; python_version >= "3.8" and python_version < "3.9"
wheel==0.33.6 ; python_version >= "3.8" and python_version < "3.9"
zipp==3.17.0 ; python_version >= "3.8" and python_version < "3.9"
zipp==3.20.1 ; python_version >= "3.8" and python_version < "3.9"

View File

@@ -19,7 +19,7 @@ CheckVersion() {
CheckVersion "$1"
CheckVersion "$2"
if [ "$RELEASE_GPG_KEY" = "" ] && ! gpg2 --card-status >/dev/null 2>&1; then
if [ "$RELEASE_GPG_KEY" = "" ] && ! gpg --card-status >/dev/null 2>&1; then
echo OpenPGP card not found!
echo Please insert your PGP card and run this script again.
exit 1

View File

@@ -10,62 +10,62 @@ apacheconfig==0.3.2 ; python_version >= "3.8" and python_version < "4.0"
appnope==0.1.4 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "darwin"
astroid==3.0.3 ; python_version >= "3.8" and python_version < "4.0"
asttokens==2.4.1 ; python_version >= "3.8" and python_version < "4.0"
attrs==23.2.0 ; python_version >= "3.8" and python_version < "4.0"
azure-core==1.30.1 ; python_version >= "3.8" and python_version < "4.0"
attrs==24.2.0 ; python_version >= "3.8" and python_version < "4.0"
azure-core==1.32.0 ; python_version >= "3.8" and python_version < "4.0"
azure-devops==7.1.0b4 ; python_version >= "3.8" and python_version < "4.0"
babel==2.15.0 ; python_version >= "3.8" and python_version < "4.0"
babel==2.16.0 ; python_version >= "3.8" and python_version < "4.0"
backcall==0.2.0 ; python_version >= "3.8" and python_version < "4.0"
bcrypt==4.1.3 ; python_version >= "3.8" and python_version < "4.0"
bcrypt==4.2.0 ; python_version >= "3.8" and python_version < "4.0"
beautifulsoup4==4.12.3 ; python_version >= "3.8" and python_version < "4.0"
boto3==1.34.116 ; python_version >= "3.8" and python_version < "4.0"
botocore==1.34.116 ; python_version >= "3.8" and python_version < "4.0"
build==1.2.1 ; python_version >= "3.8" and python_version < "4.0"
boto3==1.35.53 ; python_version >= "3.8" and python_version < "4.0"
botocore==1.35.53 ; python_version >= "3.8" and python_version < "4.0"
build==1.2.2.post1 ; python_version >= "3.8" and python_version < "4.0"
cachecontrol==0.14.0 ; python_version >= "3.8" and python_version < "4.0"
cachetools==5.3.3 ; python_version >= "3.8" and python_version < "4.0"
certifi==2024.2.2 ; python_version >= "3.8" and python_version < "4.0"
cffi==1.16.0 ; python_version >= "3.8" and python_version < "4.0"
cachetools==5.5.0 ; python_version >= "3.8" and python_version < "4.0"
certifi==2024.8.30 ; python_version >= "3.8" and python_version < "4.0"
cffi==1.17.1 ; python_version >= "3.8" and python_version < "4.0"
chardet==5.2.0 ; python_version >= "3.8" and python_version < "4.0"
charset-normalizer==3.3.2 ; python_version >= "3.8" and python_version < "4.0"
charset-normalizer==3.4.0 ; python_version >= "3.8" and python_version < "4.0"
cleo==2.1.0 ; python_version >= "3.8" and python_version < "4.0"
cloudflare==2.19.4 ; python_version >= "3.8" and python_version < "4.0"
colorama==0.4.6 ; python_version >= "3.8" and python_version < "4.0"
configargparse==1.7 ; python_version >= "3.8" and python_version < "4.0"
configobj==5.0.8 ; python_version >= "3.8" and python_version < "4.0"
coverage==7.5.3 ; python_version >= "3.8" and python_version < "4.0"
configobj==5.0.9 ; python_version >= "3.8" and python_version < "4.0"
coverage==7.6.1 ; python_version >= "3.8" and python_version < "4.0"
crashtest==0.4.1 ; python_version >= "3.8" and python_version < "4.0"
cryptography==42.0.7 ; python_version >= "3.8" and python_version < "4.0"
cryptography==43.0.3 ; python_version >= "3.8" and python_version < "4.0"
cython==0.29.37 ; python_version >= "3.8" and python_version < "4.0"
decorator==5.1.1 ; python_version >= "3.8" and python_version < "4.0"
deprecated==1.2.14 ; python_version >= "3.8" and python_version < "4.0"
dill==0.3.8 ; python_version >= "3.8" and python_version < "4.0"
distlib==0.3.8 ; python_version >= "3.8" and python_version < "4.0"
dill==0.3.9 ; python_version >= "3.8" and python_version < "4.0"
distlib==0.3.9 ; python_version >= "3.8" and python_version < "4.0"
distro==1.9.0 ; python_version >= "3.8" and python_version < "4.0"
dns-lexicon==3.17.0 ; python_version >= "3.8" and python_version < "4.0"
dns-lexicon==3.18.0 ; python_version >= "3.8" and python_version < "4.0"
dnspython==2.6.1 ; python_version >= "3.8" and python_version < "4.0"
docutils==0.20.1 ; python_version >= "3.8" and python_version < "4.0"
dulwich==0.21.7 ; python_version >= "3.8" and python_version < "4.0"
exceptiongroup==1.2.1 ; python_version >= "3.8" and python_version < "3.11"
exceptiongroup==1.2.2 ; python_version >= "3.8" and python_version < "3.11"
execnet==2.1.1 ; python_version >= "3.8" and python_version < "4.0"
executing==2.0.1 ; python_version >= "3.8" and python_version < "4.0"
executing==2.1.0 ; python_version >= "3.8" and python_version < "4.0"
fabric==3.2.2 ; python_version >= "3.8" and python_version < "4.0"
fastjsonschema==2.19.1 ; python_version >= "3.8" and python_version < "4.0"
filelock==3.14.0 ; python_version >= "3.8" and python_version < "4.0"
google-api-core==2.19.0 ; python_version >= "3.8" and python_version < "4.0"
google-api-python-client==2.131.0 ; python_version >= "3.8" and python_version < "4.0"
fastjsonschema==2.20.0 ; python_version >= "3.8" and python_version < "4.0"
filelock==3.16.1 ; python_version >= "3.8" and python_version < "4.0"
google-api-core==2.22.0 ; python_version >= "3.8" and python_version < "4.0"
google-api-python-client==2.151.0 ; python_version >= "3.8" and python_version < "4.0"
google-auth-httplib2==0.2.0 ; python_version >= "3.8" and python_version < "4.0"
google-auth==2.29.0 ; python_version >= "3.8" and python_version < "4.0"
googleapis-common-protos==1.63.0 ; python_version >= "3.8" and python_version < "4.0"
google-auth==2.35.0 ; python_version >= "3.8" and python_version < "4.0"
googleapis-common-protos==1.65.0 ; python_version >= "3.8" and python_version < "4.0"
httplib2==0.22.0 ; python_version >= "3.8" and python_version < "4.0"
idna==3.7 ; python_version >= "3.8" and python_version < "4.0"
idna==3.10 ; python_version >= "3.8" and python_version < "4.0"
imagesize==1.4.1 ; python_version >= "3.8" and python_version < "4.0"
importlib-metadata==7.1.0 ; python_version >= "3.8" and python_version < "4.0"
importlib-resources==6.4.0 ; python_version >= "3.8" and python_version < "4.0"
importlib-metadata==8.5.0 ; python_version >= "3.8" and python_version < "4.0"
importlib-resources==6.4.5 ; python_version >= "3.8" and python_version < "4.0"
iniconfig==2.0.0 ; python_version >= "3.8" and python_version < "4.0"
installer==0.7.0 ; python_version >= "3.8" and python_version < "4.0"
invoke==2.2.0 ; python_version >= "3.8" and python_version < "4.0"
ipdb==0.13.13 ; python_version >= "3.8" and python_version < "4.0"
ipython==8.12.3 ; python_version >= "3.8" and python_version < "4.0"
isodate==0.6.1 ; python_version >= "3.8" and python_version < "4.0"
isodate==0.7.2 ; python_version >= "3.8" and python_version < "4.0"
isort==5.13.2 ; python_version >= "3.8" and python_version < "4.0"
jaraco-classes==3.4.0 ; python_version >= "3.8" and python_version < "4.0"
jedi==0.19.1 ; python_version >= "3.8" and python_version < "4.0"
@@ -74,63 +74,63 @@ jinja2==3.1.4 ; python_version >= "3.8" and python_version < "4.0"
jmespath==1.0.1 ; python_version >= "3.8" and python_version < "4.0"
josepy==1.14.0 ; python_version >= "3.8" and python_version < "4.0"
jsonlines==4.0.0 ; python_version >= "3.8" and python_version < "4.0"
jsonpickle==3.0.4 ; python_version >= "3.8" and python_version < "4.0"
jsonpickle==3.3.0 ; python_version >= "3.8" and python_version < "4.0"
keyring==24.3.1 ; python_version >= "3.8" and python_version < "4.0"
markdown-it-py==3.0.0 ; python_version >= "3.8" and python_version < "4.0"
markupsafe==2.1.5 ; python_version >= "3.8" and python_version < "4.0"
matplotlib-inline==0.1.7 ; python_version >= "3.8" and python_version < "4.0"
mccabe==0.7.0 ; python_version >= "3.8" and python_version < "4.0"
mdurl==0.1.2 ; python_version >= "3.8" and python_version < "4.0"
more-itertools==10.2.0 ; python_version >= "3.8" and python_version < "4.0"
msgpack==1.0.8 ; python_version >= "3.8" and python_version < "4.0"
more-itertools==10.5.0 ; python_version >= "3.8" and python_version < "4.0"
msgpack==1.1.0 ; python_version >= "3.8" and python_version < "4.0"
msrest==0.7.1 ; python_version >= "3.8" and python_version < "4.0"
mypy-extensions==1.0.0 ; python_version >= "3.8" and python_version < "4.0"
mypy==1.9.0 ; python_version >= "3.8" and python_version < "4.0"
nh3==0.2.17 ; python_version >= "3.8" and python_version < "4.0"
nh3==0.2.18 ; python_version >= "3.8" and python_version < "4.0"
oauthlib==3.2.2 ; python_version >= "3.8" and python_version < "4.0"
packaging==24.0 ; python_version >= "3.8" and python_version < "4.0"
paramiko==3.4.0 ; python_version >= "3.8" and python_version < "4.0"
packaging==24.1 ; python_version >= "3.8" and python_version < "4.0"
paramiko==3.5.0 ; python_version >= "3.8" and python_version < "4.0"
parsedatetime==2.6 ; python_version >= "3.8" and python_version < "4.0"
parso==0.8.4 ; python_version >= "3.8" and python_version < "4.0"
pexpect==4.9.0 ; python_version >= "3.8" and python_version < "4.0"
pickleshare==0.7.5 ; python_version >= "3.8" and python_version < "4.0"
pip==24.0 ; python_version >= "3.8" and python_version < "4.0"
pip==24.3.1 ; python_version >= "3.8" and python_version < "4.0"
pkginfo==1.10.0 ; python_version >= "3.8" and python_version < "4.0"
platformdirs==4.2.2 ; python_version >= "3.8" and python_version < "4.0"
platformdirs==4.3.6 ; python_version >= "3.8" and python_version < "4.0"
pluggy==1.5.0 ; python_version >= "3.8" and python_version < "4.0"
ply==3.11 ; python_version >= "3.8" and python_version < "4.0"
poetry-core==1.9.0 ; python_version >= "3.8" and python_version < "4.0"
poetry-core==1.9.1 ; python_version >= "3.8" and python_version < "4.0"
poetry-plugin-export==1.8.0 ; python_version >= "3.8" and python_version < "4.0"
poetry==1.8.3 ; python_version >= "3.8" and python_version < "4.0"
prompt-toolkit==3.0.45 ; python_version >= "3.8" and python_version < "4.0"
proto-plus==1.23.0 ; python_version >= "3.8" and python_version < "4.0"
protobuf==4.25.3 ; python_version >= "3.8" and python_version < "4.0"
poetry==1.8.4 ; python_version >= "3.8" and python_version < "4.0"
prompt-toolkit==3.0.48 ; python_version >= "3.8" and python_version < "4.0"
proto-plus==1.25.0 ; python_version >= "3.8" and python_version < "4.0"
protobuf==5.28.3 ; python_version >= "3.8" and python_version < "4.0"
ptyprocess==0.7.0 ; python_version >= "3.8" and python_version < "4.0"
pure-eval==0.2.2 ; python_version >= "3.8" and python_version < "4.0"
pyasn1-modules==0.4.0 ; python_version >= "3.8" and python_version < "4.0"
pyasn1==0.6.0 ; python_version >= "3.8" and python_version < "4.0"
pure-eval==0.2.3 ; python_version >= "3.8" and python_version < "4.0"
pyasn1-modules==0.4.1 ; python_version >= "3.8" and python_version < "4.0"
pyasn1==0.6.1 ; python_version >= "3.8" and python_version < "4.0"
pycparser==2.22 ; python_version >= "3.8" and python_version < "4.0"
pygments==2.18.0 ; python_version >= "3.8" and python_version < "4.0"
pylint==3.0.2 ; python_version >= "3.8" and python_version < "4.0"
pynacl==1.5.0 ; python_version >= "3.8" and python_version < "4.0"
pynsist==2.7 ; python_version >= "3.8" and python_version < "4.0"
pyopenssl==24.1.0 ; python_version >= "3.8" and python_version < "4.0"
pyopenssl==24.2.1 ; python_version >= "3.8" and python_version < "4.0"
pyotp==2.9.0 ; python_version >= "3.8" and python_version < "4.0"
pyparsing==3.1.2 ; python_version >= "3.8" and python_version < "4.0"
pyproject-api==1.6.1 ; python_version >= "3.8" and python_version < "4.0"
pyproject-hooks==1.1.0 ; python_version >= "3.8" and python_version < "4.0"
pyparsing==3.1.4 ; python_version >= "3.8" and python_version < "4.0"
pyproject-api==1.8.0 ; python_version >= "3.8" and python_version < "4.0"
pyproject-hooks==1.2.0 ; python_version >= "3.8" and python_version < "4.0"
pyrfc3339==1.1 ; python_version >= "3.8" and python_version < "4.0"
pytest-cov==5.0.0 ; python_version >= "3.8" and python_version < "4.0"
pytest-xdist==3.6.1 ; python_version >= "3.8" and python_version < "4.0"
pytest==8.2.1 ; python_version >= "3.8" and python_version < "4.0"
pytest==8.3.3 ; python_version >= "3.8" and python_version < "4.0"
python-augeas==1.1.0 ; python_version >= "3.8" and python_version < "4.0"
python-dateutil==2.9.0.post0 ; python_version >= "3.8" and python_version < "4.0"
python-digitalocean==1.17.0 ; python_version >= "3.8" and python_version < "4.0"
pytz==2024.1 ; python_version >= "3.8" and python_version < "4.0"
pywin32-ctypes==0.2.2 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "win32"
pywin32==306 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "win32"
pyyaml==6.0.1 ; python_version >= "3.8" and python_version < "4.0"
rapidfuzz==3.9.2 ; python_version >= "3.8" and python_version < "4.0"
pytz==2024.2 ; python_version >= "3.8" and python_version < "4.0"
pywin32-ctypes==0.2.3 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "win32"
pywin32==308 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "win32"
pyyaml==6.0.2 ; python_version >= "3.8" and python_version < "4.0"
rapidfuzz==3.9.7 ; python_version >= "3.8" and python_version < "4.0"
readme-renderer==43.0 ; python_version >= "3.8" and python_version < "4.0"
requests-download==0.1.2 ; python_version >= "3.8" and python_version < "4.0"
requests-file==2.1.0 ; python_version >= "3.8" and python_version < "4.0"
@@ -138,18 +138,18 @@ requests-oauthlib==2.0.0 ; python_version >= "3.8" and python_version < "4.0"
requests-toolbelt==1.0.0 ; python_version >= "3.8" and python_version < "4.0"
requests==2.32.3 ; python_version >= "3.8" and python_version < "4.0"
rfc3986==2.0.0 ; python_version >= "3.8" and python_version < "4.0"
rich==13.7.1 ; python_version >= "3.8" and python_version < "4.0"
rich==13.9.3 ; python_version >= "3.8" and python_version < "4.0"
rsa==4.9 ; python_version >= "3.8" and python_version < "4"
s3transfer==0.10.1 ; python_version >= "3.8" and python_version < "4.0"
s3transfer==0.10.3 ; python_version >= "3.8" and python_version < "4.0"
secretstorage==3.3.3 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "linux"
semantic-version==2.10.0 ; python_version >= "3.8" and python_version < "4.0"
setuptools-rust==1.9.0 ; python_version >= "3.8" and python_version < "4.0"
setuptools==70.0.0 ; python_version >= "3.8" and python_version < "4.0"
setuptools-rust==1.10.2 ; python_version >= "3.8" and python_version < "4.0"
setuptools==75.3.0 ; python_version >= "3.8" and python_version < "4.0"
shellingham==1.5.4 ; python_version >= "3.8" and python_version < "4.0"
six==1.16.0 ; python_version >= "3.8" and python_version < "4.0"
snowballstemmer==2.2.0 ; python_version >= "3.8" and python_version < "4.0"
soupsieve==2.5 ; python_version >= "3.8" and python_version < "4.0"
sphinx-rtd-theme==2.0.0 ; python_version >= "3.8" and python_version < "4.0"
soupsieve==2.6 ; python_version >= "3.8" and python_version < "4.0"
sphinx-rtd-theme==3.0.1 ; python_version >= "3.8" and python_version < "4.0"
sphinx==7.1.2 ; python_version >= "3.8" and python_version < "4.0"
sphinxcontrib-applehelp==1.0.4 ; python_version >= "3.8" and python_version < "4.0"
sphinxcontrib-devhelp==1.0.2 ; python_version >= "3.8" and python_version < "4.0"
@@ -160,30 +160,29 @@ sphinxcontrib-qthelp==1.0.3 ; python_version >= "3.8" and python_version < "4.0"
sphinxcontrib-serializinghtml==1.1.5 ; python_version >= "3.8" and python_version < "4.0"
stack-data==0.6.3 ; python_version >= "3.8" and python_version < "4.0"
tldextract==5.1.2 ; python_version >= "3.8" and python_version < "4.0"
tomli==2.0.1 ; python_version >= "3.8" and python_full_version <= "3.11.0a6"
tomlkit==0.12.5 ; python_version >= "3.8" and python_version < "4.0"
tox==4.15.0 ; python_version >= "3.8" and python_version < "4.0"
tomli==2.0.2 ; python_version >= "3.8" and python_full_version <= "3.11.0a6"
tomlkit==0.13.2 ; python_version >= "3.8" and python_version < "4.0"
tox==4.23.2 ; python_version >= "3.8" and python_version < "4.0"
traitlets==5.14.3 ; python_version >= "3.8" and python_version < "4.0"
trove-classifiers==2024.5.22 ; python_version >= "3.8" and python_version < "4.0"
twine==5.1.0 ; python_version >= "3.8" and python_version < "4.0"
trove-classifiers==2024.10.21.16 ; python_version >= "3.8" and python_version < "4.0"
twine==5.1.1 ; python_version >= "3.8" and python_version < "4.0"
types-cffi==1.16.0.20240331 ; python_version >= "3.8" and python_version < "4.0"
types-httplib2==0.22.0.20240310 ; python_version >= "3.8" and python_version < "4.0"
types-pyopenssl==24.1.0.20240425 ; python_version >= "3.8" and python_version < "4.0"
types-pyopenssl==24.1.0.20240722 ; python_version >= "3.8" and python_version < "4.0"
types-pyrfc3339==1.1.1.5 ; python_version >= "3.8" and python_version < "4.0"
types-python-dateutil==2.9.0.20240316 ; python_version >= "3.8" and python_version < "4.0"
types-pytz==2024.1.0.20240417 ; python_version >= "3.8" and python_version < "4.0"
types-pywin32==306.0.0.20240408 ; python_version >= "3.8" and python_version < "4.0"
types-python-dateutil==2.9.0.20241003 ; python_version >= "3.8" and python_version < "4.0"
types-pytz==2024.2.0.20241003 ; python_version >= "3.8" and python_version < "4.0"
types-pywin32==308.0.0.20241029 ; python_version >= "3.8" and python_version < "4.0"
types-requests==2.31.0.6 ; python_version >= "3.8" and python_version < "4.0"
types-setuptools==70.0.0.20240524 ; python_version >= "3.8" and python_version < "4.0"
types-six==1.16.21.20240513 ; python_version >= "3.8" and python_version < "4.0"
types-setuptools==75.2.0.20241025 ; python_version >= "3.8" and python_version < "4.0"
types-urllib3==1.26.25.14 ; python_version >= "3.8" and python_version < "4.0"
typing-extensions==4.12.0 ; python_version >= "3.8" and python_version < "4.0"
typing-extensions==4.12.2 ; python_version >= "3.8" and python_version < "4.0"
uritemplate==4.1.1 ; python_version >= "3.8" and python_version < "4.0"
urllib3==1.26.18 ; python_version >= "3.8" and python_version < "4.0"
virtualenv==20.26.2 ; python_version >= "3.8" and python_version < "4.0"
urllib3==1.26.20 ; python_version >= "3.8" and python_version < "4.0"
virtualenv==20.27.1 ; python_version >= "3.8" and python_version < "4.0"
wcwidth==0.2.13 ; python_version >= "3.8" and python_version < "4.0"
wheel==0.43.0 ; python_version >= "3.8" and python_version < "4.0"
wheel==0.44.0 ; python_version >= "3.8" and python_version < "4.0"
wrapt==1.16.0 ; python_version >= "3.8" and python_version < "4.0"
xattr==1.1.0 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "darwin"
yarg==0.1.9 ; python_version >= "3.8" and python_version < "4.0"
zipp==3.19.1 ; python_version >= "3.8" and python_version < "4.0"
yarg==0.1.10 ; python_version >= "3.8" and python_version < "4.0"
zipp==3.20.2 ; python_version >= "3.8" and python_version < "4.0"

View File

@@ -12,7 +12,7 @@ These steps need to be done once to set up your VM and do not need to be run aga
1. Start with a Focal VM. You need a full virtual machine using something like DigitalOcean, EC2, or VirtualBox. Docker won't work. Another version of Ubuntu can probably be used, but Focal was used when writing these instructions.
2. Set up a user other than root with sudo privileges for use with snapcraft and run all of the following commands with it. A command to do this for a user named certbot looks like `adduser certbot && usermod -aG sudo certbot && su - certbot`.
3. Install git and python with `sudo apt update && sudo apt install -y git python`.
4. Set up lxd for use with snapcraft by running `sudo snap install lxd && sudo /snap/bin/lxd.migrate -yes; sudo /snap/bin/lxd waitready && sudo /snap/bin/lxd init --auto` (errors here are ok; it may already
4. Set up lxd for use with snapcraft by running `sudo snap install lxd; sudo /snap/bin/lxd waitready && sudo /snap/bin/lxd init --auto` (errors here are ok; it may already
have been installed on your system).
5. Add your current user to the lxd group and update your shell to have the new assignment by running `sudo usermod -a -G lxd ${USER} && newgrp lxd`.
6. Install snapcraft with `sudo snap install --classic snapcraft`.

View File

@@ -49,26 +49,32 @@ def _snap_log_name(target: str, arch: str):
def _execute_build(
target: str, archs: Set[str], status: Dict[str, Dict[str, str]],
workspace: str, output_lock: Lock) -> Tuple[int, List[str]]:
# snapcraft remote-build accepts a --build-id flag with snapcraft version
# 5.0+. We make use of this feature to set a unique build ID so a fresh
# build is started for each run instead of potentially reusing an old
# build. See https://github.com/certbot/certbot/pull/8719 and
# https://github.com/snapcore/snapcraft/pull/3554 for more info.
# The implementation of remote-build recovery has changed over time.
# Currently, you cannot set a build-id, and the build-id is instead derived
# from a hash of the contents of the files in the directory:
# https://github.com/canonical/craft-application/blob/5b09ab3d9152a2b61ffcdf57691289023ed6ba26/craft_application/remote/utils.py#L64
#
# This random string was chosen because snapcraft uses a MD5 hash
# represented as a 32 character hex string by default, so we use the same
# length but from a larger character set just because we can.
# We want a unique build ID so a fresh build is started for each run instead
# of potentially reusing an old build. See https://github.com/certbot/certbot/pull/8719
# and https://github.com/snapcore/snapcraft/pull/3554 for more info.
#
# In the hope that one day you can again set a build ID, we will modify
# the directory by creating a file containing a build ID that conforms
# to the shape of snapcraft's build ID: using a MD5 hash represented as a
# 32 character hex string (we use a larger character set).
random_string = ''.join(random.choice(string.ascii_lowercase + string.digits)
for _ in range(32))
build_id = f'snapcraft-{target}-{random_string}'
# place random string in build_id file inside `workspace` directory
with open(join(workspace, 'build_id'), 'w') as build_id_file:
build_id_file.write(random_string)
with tempfile.TemporaryDirectory() as tempdir:
environ = os.environ.copy()
environ['XDG_CACHE_HOME'] = tempdir
process = subprocess.Popen([
'snapcraft', 'remote-build', '--launchpad-accept-public-upload',
'--build-for', ','.join(archs), '--build-id', build_id],
'--build-for', ','.join(archs)],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True, env=environ, cwd=workspace)
@@ -103,6 +109,10 @@ def _build_snap(
workspace = CERTBOT_DIR
else:
workspace = join(CERTBOT_DIR, target)
# init and commit git repo in workspace
subprocess.run(['git', 'init'], capture_output=True, check=True, cwd=workspace)
subprocess.run(['git', 'add', '-A'], capture_output=True, check=True, cwd=workspace)
subprocess.run(['git', 'commit', '-m', 'init'], capture_output=True, check=True, cwd=workspace)
build_success = False
retry = 3
@@ -115,7 +125,7 @@ def _build_snap(
print(f'Build {target} for {",".join(archs)} (attempt {4-retry}/3) ended with '
f'exit code {exit_code}.')
failed_archs = [arch for arch in archs if status[target][arch] != 'Successfully built']
failed_archs = [arch for arch in archs if status[target][arch] != 'Succeeded']
# If the command failed or any architecture wasn't built
# successfully, let's try to print all the output about the problem
# that we can.
@@ -147,17 +157,17 @@ def _build_snap(
def _extract_state(project: str, output: str, status: Dict[str, Dict[str, str]]) -> None:
state = status[project]
if "Sending build data to Launchpad..." in output:
if "Starting new build" in output:
for arch in state.keys():
state[arch] = "Sending build data"
state[arch] = "Starting new build"
match = re.match(r'^.*arch=(\w+)\s+state=([\w ]+).*$', output)
match = re.match(r'^(\w+): (\w+)$', output)
if match:
arch = match.group(1)
state[arch] = match.group(2)
arch = match.group(2)
state[arch] = match.group(1)
# You need to reassign the value of status[project] here (rather than doing
# something like status[project][arch] = match.group(2)) for the state change
# something like status[project][arch] = match.group(1)) for the state change
# to propagate to other processes. See
# https://docs.python.org/3.8/library/multiprocessing.html#proxy-objects for
# more info.
@@ -187,18 +197,18 @@ def _dump_status(
def _dump_failed_build_logs(
target: str, archs: Set[str], status: Dict[str, Dict[str, str]],
workspace: str) -> None:
logs_list = glob.glob(join(workspace, f'snapcraft-{target}-*.txt'))
for arch in archs:
result = status[target][arch]
if result != 'Successfully built':
if result != 'Succeeded':
failures = True
build_output_name = _snap_log_name(target, arch)
build_output_path = join(workspace, build_output_name)
if not exists(build_output_path):
build_output_path = [log_name for log_name in logs_list if arch in log_name]
if not build_output_path:
build_output = f'No output has been dumped by snapcraft remote-build.'
else:
with open(build_output_path) as file_h:
with open(build_output_path[0]) as file_h:
build_output = file_h.read()
print(f'Output for failed build target={target} arch={arch}')
@@ -240,10 +250,6 @@ def main():
subprocess.run(['tools/snap/generate_dnsplugins_all.sh'],
check=True, cwd=CERTBOT_DIR)
# Use the legacy remote launchpad build until
# https://github.com/certbot/certbot/issues/9890 is fixed
os.environ['SNAPCRAFT_REMOTE_BUILD_STRATEGY'] = 'force-fallback'
print('Start remote snap builds...')
print(f' - archs: {", ".join(archs)}')
print(f' - projects: {", ".join(sorted(targets))}')

View File

@@ -25,7 +25,7 @@ cb_required=\$(grep -oP "version = '\K.*(?=')" \$SNAP/setup.py)
\$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if\
version.parse('\$cb_installed') < version.parse('\$cb_required') else sys.exit(0)" || exit_code=\$?
if [ "\$exit_code" -eq 1 ]; then
if [ "\$exit_code" = "1" ]; then
echo "Certbot is version \$cb_installed but needs to be at least \$cb_required before" \\
"this plugin can be updated; will try again on next refresh."
exit 1

View File

@@ -16,7 +16,7 @@ summary: ${DESCRIPTION}
description: ${DESCRIPTION}
confinement: strict
grade: stable
base: core20
base: core24
adopt-info: ${PLUGIN}
parts:
@@ -24,8 +24,8 @@ parts:
plugin: python
source: .
override-pull: |
snapcraftctl pull
snapcraftctl set-version \`grep ^version \$SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"\`
craftctl default
craftctl set version=\$(grep ^version \$SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]")
build-environment:
# We set this environment variable while building to try and increase the
# stability of fetching the rust crates needed to build the cryptography
@@ -53,7 +53,7 @@ parts:
source: .
stage: [setup.py, certbot-shared]
override-pull: |
snapcraftctl pull
craftctl default
mkdir -p \$SNAPCRAFT_PART_SRC/certbot-shared
slots:
@@ -61,7 +61,7 @@ slots:
interface: content
content: certbot-1
read:
- \$SNAP/lib/python3.8/site-packages
- \$SNAP/lib/python3.12/site-packages
plugs:
certbot-metadata: