name: certbot
summary: Automatically configure HTTPS using Let's Encrypt
description: |
 The objective of Certbot, Let's Encrypt, and the ACME (Automated
 Certificate Management Environment) protocol is to make it possible
 to set up an HTTPS server and have it automatically obtain a
 browser-trusted certificate, without any human intervention. This is
 accomplished by running a certificate management agent on the web
 server.

 This agent is used to:
   - Automatically prove to the Let's Encrypt CA that you control the website
   - Obtain a browser-trusted certificate and set it up on your web server
   - 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: core24
grade: stable
adopt-info: certbot

environment:
  AUGEAS_LENS_LIB: "$SNAP/usr/share/augeas/lenses/dist"
  CERTBOT_SNAPPED: "True"
  # This is needed to help openssl find its legacy provider on architectures
  # where we cannot use cryptography's pre-built wheels. See
  # https://github.com/certbot/certbot/issues/10055.
  OPENSSL_MODULES: "$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/ossl-modules"
  PATH: "$SNAP/bin:$SNAP/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
  # Disable FIPS mode detection. See
  # https://git.launchpad.net/ubuntu/+source/openssl/tree/debian/patches/fips/crypto-Add-kernel-FIPS-mode-detection.patch?h=applied/ubuntu/noble
  # for more on this flag, and https://github.com/certbot/certbot/issues/10044
  # for more on the issue.
  #
  # This is needed because the Python + OpenSSL bundled in core24 don't include
  # an OpenSSL FIPS provider, which causes crashes on host systems with OpenSSL
  # 1.1.1f (e.g. Ubuntu Pro 20.04). For some reason, core24's OpenSSL also looks
  # in a non-standard location for the provider, which also causes crashes on
  # systems with OpenSSL 3.x (e.g. RHEL 9). If you need FIPS functionality in
  # certbot, install via pip.
  OPENSSL_FORCE_FIPS_MODE: "0"

apps:
  certbot:
    command: bin/python3 -s $SNAP/bin/certbot
  renew:
    command: bin/python3 -s $SNAP/bin/certbot -q renew
    daemon: oneshot
    # Run approximately twice a day with randomization
    timer: 00:00~24:00/2


parts:
  certbot:
    plugin: python
    source: .
    python-packages:
      - git+https://github.com/certbot/python-augeas.git@certbot-patched
      - ./acme
      - ./certbot
      - ./certbot-apache
      - ./certbot-nginx
    stage:
      - -usr/lib/python3.12/sitecustomize.py # maybe unnecessary
      # 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
      # our python-augeas fork which creates an auto-generated cffi file at
      # the same path. Since we've combined things in one part and removed the
      # python-augeas pinning, unstaging this file had a different, unintended
      # effect so we now stage the file to keep the auto-generated cffi file.
    stage-packages:
      - libaugeas0
      - libpython3.12-dev
      # This library included so openssl has a legacy provider available at
      # runtime when we are unable to use cryptography's pre-built wheels. See
      # https://github.com/certbot/certbot/issues/10055.
      - libssl3t64
      # added to stage python:
      - libpython3-stdlib
      - libpython3.12-stdlib
      - libpython3.12-minimal
      - python3-pip
      - python3-wheel
      - python3-venv
      - python3-minimal
      - python3-pkg-resources
      - python3.12-minimal
    # To build cryptography and cffi if needed
    build-packages:
      - gcc
      - git
      - libaugeas-dev
      - build-essential
      - libssl-dev
      - libffi-dev
      - python3-dev
      - cargo
      - pkg-config
    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
      # library.
      - CARGO_NET_GIT_FETCH_WITH_CLI: "true"
      - 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: $CRAFT_PART_SRC/snap-constraints.txt
      # This is a workaround for
      # https://github.com/pypa/setuptools/issues/5039 forcing pip to use
      # modern build conventions even in the absence of pyproject.toml files.
      - PIP_USE_PEP517: "true"
    override-build: |
      python3 -m venv "${CRAFT_PART_INSTALL}"
      "${CRAFT_PART_INSTALL}/bin/python3" "${CRAFT_PART_SRC}/tools/pipstrap.py"
      craftctl default
      # Workaround for misconfigured pyvenv.cfg; see discussion on snapcraft forum for more info
      # https://forum.snapcraft.io/t/upgrading-classic-snap-to-core24-using-snapcraft-8-3-causes-python-3-12-errors-at-runtime/
      sed -i "${CRAFT_PART_INSTALL}/pyvenv.cfg" \
          -e 's@^home = '"${CRAFT_PART_INSTALL}"'/usr/bin$@home = /snap/certbot/current/usr/bin@g'
    override-pull: |
      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/src/certbot/__init__.py")
    build-attributes:
      # https://snapcraft.io/docs/how-to-classic#fix-linter-warnings-by-patching-elf-binaries
      - enable-patchelf
  shared-metadata:
    plugin: dump
    source: .
    override-pull: |
      craftctl default
      mkdir -p certbot-metadata
      grep -oP "__version__ = '\K.*(?=')" $CRAFT_PART_SRC/certbot/src/certbot/__init__.py > certbot-metadata/certbot-version.txt
    stage: [certbot-metadata/certbot-version.txt]

plugs:
  plugin:
    interface: content
    content: certbot-1
    target: $SNAP/certbot-plugin

slots:
  certbot-metadata:
    interface: content
    content: metadata-1
    read: [$SNAP/certbot-metadata]
