devnomads-cli 0.4.0__tar.gz → 0.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/PKG-INFO +12 -3
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/README.md +10 -1
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/devnomads_cli.egg-info/PKG-INFO +12 -3
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/devnomads_cli.egg-info/requires.txt +1 -1
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/dncli.py +26 -6
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/pyproject.toml +2 -2
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/tests/test_cert.py +50 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/LICENSE +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/devnomads_cli.egg-info/SOURCES.txt +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/devnomads_cli.egg-info/dependency_links.txt +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/devnomads_cli.egg-info/entry_points.txt +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/devnomads_cli.egg-info/top_level.txt +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/setup.cfg +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/tests/test_cli.py +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/tests/test_config.py +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/tests/test_generate.py +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/tests/test_generated_cli.py +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/tests/test_helpers.py +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/tests/test_hook.py +0 -0
- {devnomads_cli-0.4.0 → devnomads_cli-0.4.1}/tests/test_transfer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devnomads-cli
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Manage your DevNomads services from the command line
|
|
5
5
|
Author-email: DevNomads <support@devnomads.nl>
|
|
6
6
|
License: MIT
|
|
@@ -11,7 +11,7 @@ Requires-Dist: typer>=0.12
|
|
|
11
11
|
Requires-Dist: httpx>=0.27
|
|
12
12
|
Requires-Dist: rich>=13
|
|
13
13
|
Requires-Dist: cryptography>=42
|
|
14
|
-
Requires-Dist: devnomads[acme]>=0.2.
|
|
14
|
+
Requires-Dist: devnomads[acme]>=0.2.3
|
|
15
15
|
Dynamic: license-file
|
|
16
16
|
|
|
17
17
|
# dncli
|
|
@@ -129,9 +129,18 @@ dncli services list | jq -r '.[].entity'
|
|
|
129
129
|
`dncli` issues Let's Encrypt certificates over DNS-01 and HTTP-01:
|
|
130
130
|
|
|
131
131
|
```sh
|
|
132
|
-
dncli cert issue example.com -d "*.example.com"
|
|
132
|
+
dncli cert issue example.com -d www.example.com -d "*.example.com"
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
+
The first argument is the primary domain (the certificate CN); add
|
|
136
|
+
extra names (SANs) by repeating `--san`/`-d`. The certificate is
|
|
137
|
+
written to `~/.config/dncli/certs/<domain>/` as `cert.pem`,
|
|
138
|
+
`fullchain.pem`, `chain.pem`, and `privkey.pem` (0600); override the
|
|
139
|
+
location with `--out`.
|
|
140
|
+
|
|
141
|
+
Keys are ECDSA P-384 by default. Pick another with `--key-type`
|
|
142
|
+
(`ecdsa256`, `ecdsa384`, `ecdsa521`, `rsa2048`, `rsa4096`).
|
|
143
|
+
|
|
135
144
|
A dehydrated-compatible DNS-01 hook ships as `dncli-dns-hook`:
|
|
136
145
|
|
|
137
146
|
```sh
|
|
@@ -113,9 +113,18 @@ dncli services list | jq -r '.[].entity'
|
|
|
113
113
|
`dncli` issues Let's Encrypt certificates over DNS-01 and HTTP-01:
|
|
114
114
|
|
|
115
115
|
```sh
|
|
116
|
-
dncli cert issue example.com -d "*.example.com"
|
|
116
|
+
dncli cert issue example.com -d www.example.com -d "*.example.com"
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
+
The first argument is the primary domain (the certificate CN); add
|
|
120
|
+
extra names (SANs) by repeating `--san`/`-d`. The certificate is
|
|
121
|
+
written to `~/.config/dncli/certs/<domain>/` as `cert.pem`,
|
|
122
|
+
`fullchain.pem`, `chain.pem`, and `privkey.pem` (0600); override the
|
|
123
|
+
location with `--out`.
|
|
124
|
+
|
|
125
|
+
Keys are ECDSA P-384 by default. Pick another with `--key-type`
|
|
126
|
+
(`ecdsa256`, `ecdsa384`, `ecdsa521`, `rsa2048`, `rsa4096`).
|
|
127
|
+
|
|
119
128
|
A dehydrated-compatible DNS-01 hook ships as `dncli-dns-hook`:
|
|
120
129
|
|
|
121
130
|
```sh
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devnomads-cli
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Manage your DevNomads services from the command line
|
|
5
5
|
Author-email: DevNomads <support@devnomads.nl>
|
|
6
6
|
License: MIT
|
|
@@ -11,7 +11,7 @@ Requires-Dist: typer>=0.12
|
|
|
11
11
|
Requires-Dist: httpx>=0.27
|
|
12
12
|
Requires-Dist: rich>=13
|
|
13
13
|
Requires-Dist: cryptography>=42
|
|
14
|
-
Requires-Dist: devnomads[acme]>=0.2.
|
|
14
|
+
Requires-Dist: devnomads[acme]>=0.2.3
|
|
15
15
|
Dynamic: license-file
|
|
16
16
|
|
|
17
17
|
# dncli
|
|
@@ -129,9 +129,18 @@ dncli services list | jq -r '.[].entity'
|
|
|
129
129
|
`dncli` issues Let's Encrypt certificates over DNS-01 and HTTP-01:
|
|
130
130
|
|
|
131
131
|
```sh
|
|
132
|
-
dncli cert issue example.com -d "*.example.com"
|
|
132
|
+
dncli cert issue example.com -d www.example.com -d "*.example.com"
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
+
The first argument is the primary domain (the certificate CN); add
|
|
136
|
+
extra names (SANs) by repeating `--san`/`-d`. The certificate is
|
|
137
|
+
written to `~/.config/dncli/certs/<domain>/` as `cert.pem`,
|
|
138
|
+
`fullchain.pem`, `chain.pem`, and `privkey.pem` (0600); override the
|
|
139
|
+
location with `--out`.
|
|
140
|
+
|
|
141
|
+
Keys are ECDSA P-384 by default. Pick another with `--key-type`
|
|
142
|
+
(`ecdsa256`, `ecdsa384`, `ecdsa521`, `rsa2048`, `rsa4096`).
|
|
143
|
+
|
|
135
144
|
A dehydrated-compatible DNS-01 hook ships as `dncli-dns-hook`:
|
|
136
145
|
|
|
137
146
|
```sh
|
|
@@ -1362,6 +1362,16 @@ LE_STAGING_DIRECTORY = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
|
|
1362
1362
|
CERT_RENEW_WINDOW_DAYS = 30
|
|
1363
1363
|
|
|
1364
1364
|
|
|
1365
|
+
class KeyType(str, Enum):
|
|
1366
|
+
"""Certificate key types. ECDSA is the default; RSA on request."""
|
|
1367
|
+
|
|
1368
|
+
ecdsa256 = "ecdsa256"
|
|
1369
|
+
ecdsa384 = "ecdsa384"
|
|
1370
|
+
ecdsa521 = "ecdsa521"
|
|
1371
|
+
rsa2048 = "rsa2048"
|
|
1372
|
+
rsa4096 = "rsa4096"
|
|
1373
|
+
|
|
1374
|
+
|
|
1365
1375
|
def _load_acme() -> Any:
|
|
1366
1376
|
"""Import devnomads.acme lazily, so non-cert commands skip the ACME
|
|
1367
1377
|
stack at startup."""
|
|
@@ -1498,8 +1508,13 @@ def cert_issue(
|
|
|
1498
1508
|
str | None, typer.Option("--email", help="ACME account contact email.")
|
|
1499
1509
|
] = None,
|
|
1500
1510
|
key_type: Annotated[
|
|
1501
|
-
|
|
1502
|
-
|
|
1511
|
+
KeyType,
|
|
1512
|
+
typer.Option(
|
|
1513
|
+
"--key-type",
|
|
1514
|
+
help="Certificate key type "
|
|
1515
|
+
"(ecdsa256/ecdsa384/ecdsa521/rsa2048/rsa4096).",
|
|
1516
|
+
),
|
|
1517
|
+
] = KeyType.ecdsa384,
|
|
1503
1518
|
staging: Annotated[
|
|
1504
1519
|
bool, typer.Option("--staging", help="Use the Let's Encrypt staging CA.")
|
|
1505
1520
|
] = False,
|
|
@@ -1528,7 +1543,7 @@ def cert_issue(
|
|
|
1528
1543
|
webroot=webroot,
|
|
1529
1544
|
standalone=standalone,
|
|
1530
1545
|
email=email,
|
|
1531
|
-
key_type=key_type,
|
|
1546
|
+
key_type=key_type.value,
|
|
1532
1547
|
staging=staging,
|
|
1533
1548
|
out_dir=_cert_out_dir(out, domain),
|
|
1534
1549
|
)
|
|
@@ -1564,8 +1579,13 @@ def cert_renew(
|
|
|
1564
1579
|
str | None, typer.Option("--email", help="ACME account contact email.")
|
|
1565
1580
|
] = None,
|
|
1566
1581
|
key_type: Annotated[
|
|
1567
|
-
|
|
1568
|
-
|
|
1582
|
+
KeyType,
|
|
1583
|
+
typer.Option(
|
|
1584
|
+
"--key-type",
|
|
1585
|
+
help="Certificate key type "
|
|
1586
|
+
"(ecdsa256/ecdsa384/ecdsa521/rsa2048/rsa4096).",
|
|
1587
|
+
),
|
|
1588
|
+
] = KeyType.ecdsa384,
|
|
1569
1589
|
staging: Annotated[
|
|
1570
1590
|
bool, typer.Option("--staging", help="Use the Let's Encrypt staging CA.")
|
|
1571
1591
|
] = False,
|
|
@@ -1597,7 +1617,7 @@ def cert_renew(
|
|
|
1597
1617
|
webroot=None,
|
|
1598
1618
|
standalone=False,
|
|
1599
1619
|
email=email,
|
|
1600
|
-
key_type=key_type,
|
|
1620
|
+
key_type=key_type.value,
|
|
1601
1621
|
staging=staging,
|
|
1602
1622
|
out_dir=out_dir,
|
|
1603
1623
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "devnomads-cli"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.1"
|
|
4
4
|
description = "Manage your DevNomads services from the command line"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -11,7 +11,7 @@ dependencies = [
|
|
|
11
11
|
"httpx>=0.27",
|
|
12
12
|
"rich>=13",
|
|
13
13
|
"cryptography>=42",
|
|
14
|
-
"devnomads[acme]>=0.2.
|
|
14
|
+
"devnomads[acme]>=0.2.3",
|
|
15
15
|
]
|
|
16
16
|
|
|
17
17
|
[project.scripts]
|
|
@@ -57,6 +57,56 @@ def test_issue_dns01_default_uses_dns_provider(configured, captured, isolated_co
|
|
|
57
57
|
assert stat.S_IMODE(privkey.stat().st_mode) == 0o600
|
|
58
58
|
|
|
59
59
|
|
|
60
|
+
def _spy_generate_key(monkeypatch, seen):
|
|
61
|
+
import devnomads.acme as acme
|
|
62
|
+
|
|
63
|
+
def spy(algo):
|
|
64
|
+
seen["algo"] = algo
|
|
65
|
+
return object()
|
|
66
|
+
|
|
67
|
+
monkeypatch.setattr(acme, "generate_key", spy)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_issue_default_key_type_is_ecdsa384(
|
|
71
|
+
configured, captured, isolated_config, monkeypatch
|
|
72
|
+
):
|
|
73
|
+
seen = {}
|
|
74
|
+
_spy_generate_key(monkeypatch, seen)
|
|
75
|
+
result = runner.invoke(app, ["cert", "issue", "example.com"])
|
|
76
|
+
assert result.exit_code == 0, result.output
|
|
77
|
+
assert seen["algo"] == "ecdsa384"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_issue_key_type_ecdsa521(configured, captured, isolated_config, monkeypatch):
|
|
81
|
+
seen = {}
|
|
82
|
+
_spy_generate_key(monkeypatch, seen)
|
|
83
|
+
result = runner.invoke(
|
|
84
|
+
app, ["cert", "issue", "example.com", "--key-type", "ecdsa521"]
|
|
85
|
+
)
|
|
86
|
+
assert result.exit_code == 0, result.output
|
|
87
|
+
assert seen["algo"] == "ecdsa521"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_issue_key_type_is_selectable(
|
|
91
|
+
configured, captured, isolated_config, monkeypatch
|
|
92
|
+
):
|
|
93
|
+
seen = {}
|
|
94
|
+
_spy_generate_key(monkeypatch, seen)
|
|
95
|
+
result = runner.invoke(
|
|
96
|
+
app, ["cert", "issue", "example.com", "--key-type", "rsa4096"]
|
|
97
|
+
)
|
|
98
|
+
assert result.exit_code == 0, result.output
|
|
99
|
+
assert seen["algo"] == "rsa4096"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_issue_rejects_unknown_key_type():
|
|
103
|
+
result = runner.invoke(
|
|
104
|
+
app, ["cert", "issue", "example.com", "--key-type", "ed25519"]
|
|
105
|
+
)
|
|
106
|
+
assert result.exit_code != 0
|
|
107
|
+
assert "ed25519" in result.output
|
|
108
|
+
|
|
109
|
+
|
|
60
110
|
def test_issue_http01_webroot_uses_webroot_solver(
|
|
61
111
|
configured, captured, isolated_config, tmp_path
|
|
62
112
|
):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|