l3io-wordpress-database 0.3.5__tar.gz → 0.3.6__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.
Files changed (31) hide show
  1. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/PKG-INFO +2 -2
  2. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/pyproject.toml +4 -4
  3. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/__init__.py +2 -0
  4. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/_observe.py +5 -2
  5. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/_passphrase.py +13 -1
  6. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/credentials.py +1 -1
  7. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/errors.py +9 -0
  8. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/.gitignore +0 -0
  9. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/LICENSE +0 -0
  10. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/README.md +0 -0
  11. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/__main__.py +0 -0
  12. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/_client.py +0 -0
  13. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/_sql.py +0 -0
  14. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/_version.py +0 -0
  15. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/_version_map.py +0 -0
  16. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/auth.py +0 -0
  17. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/cli.py +0 -0
  18. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/connection.py +0 -0
  19. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/encryption.py +0 -0
  20. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/facade.py +0 -0
  21. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/identifiers.py +0 -0
  22. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/inspection.py +0 -0
  23. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/provision.py +0 -0
  24. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/py.typed +0 -0
  25. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/server.py +0 -0
  26. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/state.py +0 -0
  27. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/tls.py +0 -0
  28. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/transfer.py +0 -0
  29. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/verdict.py +0 -0
  30. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/versions.py +0 -0
  31. {l3io_wordpress_database-0.3.5 → l3io_wordpress_database-0.3.6}/src/l3io/wp/database/wpconfig.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: l3io-wordpress-database
3
- Version: 0.3.5
3
+ Version: 0.3.6
4
4
  Summary: Create and inspect WordPress MySQL databases and their users, idempotently.
5
5
  Project-URL: Homepage, https://github.com/LiquidLogicLabs/l3io-wordpress-database
6
6
  Project-URL: Source, https://github.com/LiquidLogicLabs/l3io-wordpress-database
@@ -27,7 +27,7 @@ Requires-Dist: structlog<27,>=26.1
27
27
  Provides-Extra: aws
28
28
  Requires-Dist: boto3<2,>=1.34; extra == 'aws'
29
29
  Provides-Extra: encryption
30
- Requires-Dist: l3io-age-passphrase<0.2,>=0.1.1; extra == 'encryption'
30
+ Requires-Dist: l3io-age-passphrase<0.2,>=0.1.3; extra == 'encryption'
31
31
  Requires-Dist: pyrage<2,>=1.4; extra == 'encryption'
32
32
  Provides-Extra: wpconfig
33
33
  Requires-Dist: l3io-wordpress-config<0.2,>=0.1.2; extra == 'wpconfig'
@@ -40,7 +40,7 @@ aws = ["boto3>=1.34,<2"]
40
40
  wpconfig = ["l3io-wordpress-config>=0.1.2,<0.2"]
41
41
  encryption = [
42
42
  "pyrage>=1.4,<2",
43
- "l3io-age-passphrase>=0.1.1,<0.2",
43
+ "l3io-age-passphrase>=0.1.3,<0.2",
44
44
  ]
45
45
 
46
46
  # Mechanical enforcement of the family's uv version, matching l3io-wordpress-config.
@@ -58,7 +58,7 @@ required-version = "==0.11.6"
58
58
  # build that carries a VCS dependency. Delete this block once public PyPI (or
59
59
  # a documented default index) carries both.
60
60
  l3io-wordpress-config = { git = "https://github.com/LiquidLogicLabs/l3io-wordpress-config.git", tag = "v0.1.3" }
61
- l3io-age-passphrase = { git = "https://github.com/LiquidLogicLabs/l3io-age-passphrase.git", tag = "v0.1.1" }
61
+ l3io-age-passphrase = { git = "https://github.com/LiquidLogicLabs/l3io-age-passphrase.git", tag = "v0.1.3" }
62
62
 
63
63
  [project.scripts]
64
64
  l3io-wordpress-database = "l3io.wp.database.cli:main"
@@ -83,10 +83,10 @@ dev = [
83
83
  # dependency on it.
84
84
  "packaging==26.3",
85
85
  # Span assertions need a real SDK; the package itself depends on the API only.
86
- "opentelemetry-sdk==1.45.1",
86
+ "opentelemetry-sdk==1.45.2",
87
87
  # The encryption extra, also here because `uv run` prunes extras.
88
88
  "pyrage==1.4.0",
89
- "l3io-age-passphrase>=0.1.1,<0.2",
89
+ "l3io-age-passphrase>=0.1.3,<0.2",
90
90
  # The optional extras are dev dependencies too, so a bare `uv run` can
91
91
  # exercise the code paths behind them. `uv run` syncs the default groups
92
92
  # only, which PRUNES extras -- without this, every `uv run` silently
@@ -53,6 +53,7 @@ from .errors import (
53
53
  TlsHandshakeError,
54
54
  TlsVerificationError,
55
55
  TransferError,
56
+ WorkFactorTooHighError,
56
57
  )
57
58
  from .facade import Database
58
59
  from .identifiers import (
@@ -155,6 +156,7 @@ __all__ = [
155
156
  "TransferError",
156
157
  "TransferResult",
157
158
  "Verdict",
159
+ "WorkFactorTooHighError",
158
160
  "WpConfigFile",
159
161
  "__version__",
160
162
  "check_drop_database",
@@ -136,11 +136,14 @@ def _complete(
136
136
  # must never raise here, because this runs inside the exception handlers.
137
137
  # The event name is structlog's first positional parameter, so it travels as a
138
138
  # keyword too; otherwise a caller field named "event" collides with it.
139
+ # Event names are stable snake_case tokens so consumers can group and alert
140
+ # on them; free-text prose belongs in ``message`` (Finding.message, etc.).
139
141
  verdict = fields.pop(VERDICT_KEY, None)
140
142
  if isinstance(verdict, Verdict):
141
143
  for finding in verdict.warnings:
142
144
  _log.warning(
143
- event=finding.message,
145
+ event=str(finding.code),
146
+ message=finding.message,
144
147
  code=str(finding.code),
145
148
  operation=name,
146
149
  database=connection.database,
@@ -148,7 +151,7 @@ def _complete(
148
151
  caller_fields = {k: v for k, v in fields.items() if k not in _STRUCTLOG_PARAMETERS}
149
152
  event: dict[str, object] = {
150
153
  **caller_fields,
151
- "event": "operation complete",
154
+ "event": "operation_completed",
152
155
  "operation": name,
153
156
  "outcome": outcome,
154
157
  "duration_ms": round((time.monotonic() - started) * 1000, 1),
@@ -18,7 +18,13 @@ import subprocess
18
18
  import threading
19
19
  from typing import IO, Any, Literal
20
20
 
21
- from .errors import CorruptDumpError, DecryptionError, InvalidArgumentsError, MissingDependencyError
21
+ from .errors import (
22
+ CorruptDumpError,
23
+ DecryptionError,
24
+ InvalidArgumentsError,
25
+ MissingDependencyError,
26
+ WorkFactorTooHighError,
27
+ )
22
28
 
23
29
  BackendName = Literal["binder", "cli"]
24
30
  _ENV = "L3IO_AGE_PASSPHRASE_BACKEND"
@@ -121,6 +127,9 @@ def _binder_decrypt(reader: IO[bytes], writer: IO[bytes], passphrase: str) -> No
121
127
  if text == "Decryption failed":
122
128
  msg = "the passphrase cannot decrypt this dump"
123
129
  raise DecryptionError(msg) from exc
130
+ if "Excessive work parameter" in text:
131
+ msg = "the Archive's scrypt work factor exceeds this machine's limit"
132
+ raise WorkFactorTooHighError(msg) from exc
124
133
  msg = "the encrypted dump is damaged or not an age file"
125
134
  raise CorruptDumpError(msg) from exc
126
135
  except OSError as exc:
@@ -223,6 +232,9 @@ def _map_cli_failure(*, encrypt: bool, err: str, code: int) -> None:
223
232
  if "no identity matched" in lower or "incorrect" in lower or "wrong" in lower:
224
233
  msg = "the passphrase cannot decrypt this dump"
225
234
  raise DecryptionError(msg)
235
+ if "excessive work" in lower:
236
+ msg = "the Archive's scrypt work factor exceeds this machine's limit"
237
+ raise WorkFactorTooHighError(msg)
226
238
  if "failed to read header" in lower or "not an age" in lower or "parsing" in lower:
227
239
  msg = "the encrypted dump is damaged or not an age file"
228
240
  raise CorruptDumpError(msg)
@@ -138,7 +138,7 @@ class AwsSecretsManager:
138
138
  if not region:
139
139
  raise RegionNotKnownError
140
140
 
141
- _log.debug("resolving secret", source=self.source, region=region)
141
+ _log.debug("resolving_secret", source=self.source, region=region)
142
142
  try:
143
143
  client = boto3.client("secretsmanager", region_name=region)
144
144
  payload: Any = client.get_secret_value(SecretId=self.secret_id)["SecretString"]
@@ -182,5 +182,14 @@ class DecryptionError(DatabaseError):
182
182
  """None of the supplied identities or the passphrase can decrypt the source."""
183
183
 
184
184
 
185
+ class WorkFactorTooHighError(DatabaseError):
186
+ """The Archive's scrypt work factor exceeds this machine's decrypt limit.
187
+
188
+ Distinct from :class:`CorruptDumpError`: the payload is intact, but this
189
+ host refuses the work (e.g. binder ``Excessive work parameter``). Never
190
+ names the passphrase.
191
+ """
192
+
193
+
185
194
  class CorruptDumpError(DatabaseError):
186
195
  """An encrypted source is truncated, damaged, or not an age file."""