Skip to content

Commit b39d6f2

Browse files
authored
feat: add publish suffix, swap to uv and update ci (#6)
1 parent d1bd3b1 commit b39d6f2

File tree

7 files changed

+539
-805
lines changed

7 files changed

+539
-805
lines changed

.github/workflows/docker-publish.yml

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,58 @@ jobs:
99
name: Docker Image 🐳
1010
runs-on: ubuntu-latest
1111
steps:
12+
- name: Checkout code ✍️
13+
uses: actions/checkout@v4
14+
with:
15+
fetch-depth: 0
16+
17+
- name: Get latest tag 🤔
18+
id: get_tag
19+
run: |
20+
git fetch --tags
21+
TAG=$(git describe --tags --abbrev=0)
22+
# Extract version without v prefix
23+
VERSION=${TAG#v}
24+
25+
echo "TAG=${TAG}" >> $GITHUB_ENV
26+
echo "VERSION=${VERSION}" >> $GITHUB_ENV
27+
echo "MAJOR=$(echo $VERSION | cut -d. -f1)" >> $GITHUB_ENV
28+
echo "MINOR=$(echo $VERSION | cut -d. -f2)" >> $GITHUB_ENV
29+
echo "PATCH=$(echo $VERSION | cut -d. -f3)" >> $GITHUB_ENV
30+
31+
echo "Found tag: ${TAG}"
32+
echo "Version: ${VERSION}"
33+
34+
# Check out the tagged commit
35+
git checkout ${TAG}
36+
1237
- name: Set up QEMU 🔨
1338
uses: docker/setup-qemu-action@v3
39+
1440
- name: Set up Docker Buildx 🔧
1541
uses: docker/setup-buildx-action@v3
42+
1643
- name: Login to Docker Hub 🔒
1744
uses: docker/login-action@v3
1845
with:
1946
username: ${{ secrets.DOCKERHUB_USERNAME }}
2047
password: ${{ secrets.DOCKERHUB_TOKEN }}
21-
-
22-
name: Build distribution 📦
23-
uses: docker/build-push-action@v5
48+
49+
- name: Set up Docker tags 🤔
50+
id: docker_tags
51+
run: |
52+
TAGS="alamellama/certbot-dns-synergy-wholesale:latest"
53+
TAGS="${TAGS},alamellama/certbot-dns-synergy-wholesale:${VERSION}"
54+
TAGS="${TAGS},alamellama/certbot-dns-synergy-wholesale:${MAJOR}"
55+
TAGS="${TAGS},alamellama/certbot-dns-synergy-wholesale:${MAJOR}.${MINOR}"
56+
echo "TAGS=${TAGS}" >> $GITHUB_ENV
57+
echo "Will push the following tags: ${TAGS}"
58+
59+
- name: Build distribution 📦
60+
uses: docker/build-push-action@v6
2461
with:
62+
context: ./
63+
platforms: linux/amd64,linux/arm64
64+
file: ./Dockerfile
2565
push: true
26-
tags: alamellama/certbot-dns-synergy-wholesale:latest
66+
tags: ${{ env.TAGS }}
Lines changed: 17 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,28 @@
1-
name: Publish Python 🐍 distribution 📦 to PyPI
1+
name: "Publish 🚀"
22

33
on:
44
release:
5-
types: [published]
5+
types: ["published"]
66

77
jobs:
8-
build:
9-
name: Build distribution 📦
8+
run:
9+
name: "Build and publish release 📦"
1010
runs-on: ubuntu-latest
1111

1212
steps:
13-
- uses: actions/checkout@v4
14-
- name: Set up Python
15-
uses: actions/setup-python@v4
16-
with:
17-
python-version: "3.x"
18-
- name: Install pypa/build
19-
run: |
20-
python3 -m pip install build --user
21-
- name: Build a binary wheel and a source tarball
22-
run: python3 -m build
23-
- name: Store the distribution packages
24-
uses: actions/upload-artifact@v4
25-
with:
26-
name: python-package-distributions-${{ runner.os }}
27-
path: dist/
13+
- uses: actions/checkout@v4
2814

29-
merge:
30-
name: Merge Artifacts 🛠️
31-
runs-on: ubuntu-latest
32-
needs: build
33-
steps:
34-
- name: Merge Artifacts
35-
uses: actions/upload-artifact/merge@v4
36-
with:
37-
name: python-package-distributions
38-
pattern: python-package-distributions-*
39-
merge-multiple: true
15+
- name: Install uv ⚡
16+
uses: astral-sh/setup-uv@v6
17+
with:
18+
enable-cache: true
19+
cache-dependency-glob: uv.lock
4020

41-
publish-to-pypi:
42-
name: Publish Python 🐍 distribution 📦 to PyPI
43-
if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
44-
needs:
45-
- merge
46-
runs-on: ubuntu-latest
47-
environment:
48-
name: pypi
49-
url: https://pypi.org/p/certbot-dns-synergy-wholesale
50-
permissions:
51-
id-token: write # IMPORTANT: mandatory for trusted publishing
21+
- name: Set up Python 🐍
22+
run: uv python install 3.12
5223

53-
steps:
54-
- name: Download All Artifacts
55-
uses: actions/download-artifact@v4
56-
with:
57-
name: python-package-distributions
58-
path: dist/
59-
- name: Publish distribution 📦 to PyPI
60-
uses: pypa/gh-action-pypi-publish@release/v1
24+
- name: Build 🛠️
25+
run: uv build
26+
27+
- name: Publish 🚀
28+
uses: pypa/gh-action-pypi-publish@release/v1

README.md

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
certbot-dns-synergy-wholesale
2-
==================
1+
# certbot-dns-synergy-wholesale
2+
33
<p align="center">
44
<a href="https://github.com/ALameLlama/certbot-dns-synergy-wholesale/actions/workflows/docker-publish.yml"><img src="https://img.shields.io/github/actions/workflow/status/ALameLlama/certbot-dns-synergy-wholesale/.github/workflows/docker-publish.yml" alt="Build"></a>
55
<a href="https://hub.docker.com/r/alamellama/certbot-dns-synergy-wholesale"><img alt="Docker Image Version" src="https://img.shields.io/docker/v/alamellama/certbot-dns-synergy-wholesale"></a>
@@ -8,10 +8,10 @@ certbot-dns-synergy-wholesale
88
<a href="https://github.com/ALameLlama/certbot-dns-synergy-wholesale/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg" alt="License"></a>
99
</p>
1010

11-
A [Synergy Wholesale](https://synergywholesale.com) DNS plugin for [Cerbot](https://certbot.eff.org/) to authenticate and retrieve Lets Encrypt certificates. Automates the process of completing a `dns-01` challenge by creating, and subsequently removing, `TXT` records
11+
A [Synergy Wholesale](https://synergywholesale.com) DNS plugin for [Cerbot](https://certbot.eff.org/) to authenticate and retrieve Lets Encrypt certificates. Automates the process of completing a `dns-01` challenge by creating, and subsequently removing, `TXT` records
12+
13+
## Installation
1214

13-
Installation
14-
------------
1515
```
1616
# create a virtual environment, to avoid conflicts
1717
python3 -m venv /some/path
@@ -24,34 +24,31 @@ python3 -m venv /some/path
2424
/some/path/bin/certbot
2525
```
2626

27-
Named Arguments
28-
---------------
27+
## Named Arguments
28+
2929
To start using DNS authentication for Synergy Wholesale, pass the following arguments on certbot's command line:
3030

31-
| Option | Description |
32-
|-----------------------------------------|---------------------------------------------------------------------------------------|
33-
| `--authenticator dns-synergy-wholesale` | select the authenticator plugin (Required) |
34-
| `--dns-synergy-wholesale-credentials FILE` | credentials INI file. (Required) |
31+
| Option | Description |
32+
| ------------------------------------------ | ------------------------------------------ |
33+
| `--authenticator dns-synergy-wholesale` | select the authenticator plugin (Required) |
34+
| `--dns-synergy-wholesale-credentials FILE` | credentials INI file. (Required) |
3535

36-
Credentials
37-
-----------
36+
## Credentials
3837

3938
Use of this plugin requires a configuration file containing API credentials, obtained from your [manage.synergywholesale.com](https://manage.synergywholesale.com/home/resellers/api).
4039

4140
**Warning:** You must whitelist the IP address from where certbot will run, Otherwise you'll run into API errors.
4241

4342
Remember this file will need to have 600 permissions.
4443

45-
4644
An example `credentials.ini` file:
4745

48-
``` {.sourceCode .ini}
46+
```{.sourceCode .ini}
4947
dns_synergy_wholesale_reseller_id = 1
5048
dns_synergy_wholesale_api_key = abc123
5149
```
5250

53-
Examples
54-
--------
51+
## Examples
5552

5653
To acquire a single certificate for both `example.com` and `*.example.com`
5754

@@ -63,9 +60,7 @@ To acquire a single certificate for both `example.com` and `*.example.com`
6360

6461
You can also add addtional paramaters such as `--keep-until-expiring --non-interactive --expand` for automation. More information [here](https://eff-certbot.readthedocs.io/en/stable/using.html#certbot-command-line-options)
6562

66-
67-
Docker
68-
------
63+
## Docker
6964

7065
You can build a docker image from source using the included `Dockerfile` or pull the latest version directly from Docker Hub:
7166

@@ -86,3 +81,17 @@ Once that's finished, the application can be run as follows:
8681
-d example.com -d '*.example.com'
8782

8883
You may want to change the volumes `/var/lib/letsencrypt` and `/etc/letsencrypt` to local directories where the certificates and configuration should be stored.
84+
85+
## Dev Setup
86+
87+
```
88+
# Create and activate a virtual environment
89+
python3 -m venv .venv
90+
source .venv/bin/activate
91+
92+
# Install uv (if not already installed)
93+
pip install uv
94+
95+
# Install all dependencies using the lockfile
96+
uv sync --dev
97+
```

certbot_dns_synergy_wholesale.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from certbot import errors
55
from certbot.plugins import dns_common
66
from certbot.plugins.dns_common import CredentialsConfiguration
7+
from publicsuffixlist import PublicSuffixList
78
from zeep import Client, Settings
89

910
logger = logging.getLogger(__name__)
@@ -114,19 +115,20 @@ def _parse_domain(self, full_domain):
114115
Returns tuple of (domain, subdomain)
115116
"""
116117

117-
# extract the parent domain
118-
root_domain = '.'.join(full_domain.split(sep='.')[-2:])
118+
# extract the root domain
119+
psl = PublicSuffixList()
120+
root_domain =psl.privatesuffix(full_domain)
121+
119122
# And extract the subdomain
120-
subdomain = full_domain.removesuffix(parentdomain).removesuffix(".")
123+
subdomain = full_domain.removesuffix(root_domain).removesuffix(".")
121124

122-
return parentdomain, subdomain
125+
return root_domain, subdomain
123126

124127
def add_txt_record(self, domain, validation_name, validation) -> Union[str, None]:
125-
126-
domain, subdomain = self.domainsplitter(validation_name)
128+
root_domain, _ = self._parse_domain(validation_name)
127129

128130
request_data = {
129-
"domainName": domain,
131+
"domainName": root_domain,
130132
"recordName": validation_name,
131133
"recordType": "TXT",
132134
"recordContent": validation,
@@ -141,17 +143,16 @@ def add_txt_record(self, domain, validation_name, validation) -> Union[str, None
141143
return None if response["status"] == "OK" else response["errorMessage"]
142144

143145
def del_txt_record(self, domain, validation) -> Union[str, None]:
146+
root_domain, _ = self._parse_domain(domain)
144147

145-
domain, subdomain = self.domainsplitter(domain)
146-
147-
id = self.find_txt_record_id(domain, validation)
148+
id = self._find_txt_record_id(root_domain, validation)
148149

149150
# If we failed to get id, return early
150151
if id is None:
151152
return "Failed to find record"
152153

153154
request_data = {
154-
"domainName": domain,
155+
"domainName": root_domain,
155156
"recordID": id,
156157
}
157158

@@ -160,7 +161,7 @@ def del_txt_record(self, domain, validation) -> Union[str, None]:
160161

161162
return None if response["status"] == "OK" else response["errorMessage"]
162163

163-
def find_txt_record_id(self, domain, validation) -> Union[str, None]:
164+
def _find_txt_record_id(self, domain, validation) -> Union[str, None]:
164165
request_data = {"domainName": domain}
165166

166167
request_data.update(self.base_request)

0 commit comments

Comments
 (0)