dploydb 0.1.0__tar.gz → 0.1.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.
- {dploydb-0.1.0 → dploydb-0.1.1}/CHANGELOG.md +12 -1
- {dploydb-0.1.0 → dploydb-0.1.1}/PKG-INFO +4 -4
- {dploydb-0.1.0 → dploydb-0.1.1}/README.md +3 -3
- {dploydb-0.1.0 → dploydb-0.1.1}/RELEASING.md +8 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/docs/first-run.md +1 -1
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/redaction.py +4 -1
- {dploydb-0.1.0 → dploydb-0.1.1}/pyproject.toml +1 -1
- {dploydb-0.1.0 → dploydb-0.1.1}/scripts/verify_clean_linux.py +7 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_deploy_end_to_end.py +10 -2
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/test_redaction.py +7 -1
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_deploy.py +31 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_milestone8_docs.py +1 -1
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_release_readiness.py +19 -4
- {dploydb-0.1.0 → dploydb-0.1.1}/uv.lock +1 -1
- {dploydb-0.1.0 → dploydb-0.1.1}/.gitignore +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/CODE_OF_CONDUCT.md +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/CONTRIBUTING.md +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/LICENSE +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/NOTICE +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/SECURITY.md +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/.dockerignore +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/Dockerfile +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/__init__.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/compose.yaml +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/controller.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/dploydb.yaml +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/prepare.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/releases/broken-health/migration.sql +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/releases/broken-health/release.json +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/releases/broken-migration/migration.sql +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/releases/broken-migration/release.json +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/releases/final-health-failure/migration.sql +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/releases/final-health-failure/release.json +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/releases/v1/migration.sql +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/releases/v1/release.json +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/releases/v2/migration.sql +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/releases/v2/release.json +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/runtime/__init__.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/runtime/app.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/runtime/migration.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/runtime/production_migration_failure.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/runtime/release.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/demo/runtime/traffic_hook.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/docs/limitations.md +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/docs/security.md +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/docs/uninstall.md +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/__init__.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/__main__.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/backup.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/candidate.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/cli.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/config.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/cutover.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/deploy.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/deployment_dependencies.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/deployment_evidence.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/diagnostics.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/errors.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/health.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/locking.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/manual_restore.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/migration.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/models.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/recovery.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/releases.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/restore.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/retention.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/runners/__init__.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/runners/base.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/runners/docker_compose.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/runners/docker_compose_production.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/sqlite_checks.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/state.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/storage/__init__.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/storage/base.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/storage/local.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/storage/s3.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/subprocesses.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/dploydb/traffic.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/examples/nginx/README.md +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/examples/nginx/dploydb-hook.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/examples/nginx/dploydb.yaml +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/examples/nginx/site.conf +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/scripts/release_notes.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/scripts/verify_distribution.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/scripts/verify_pipx_install.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/scripts/verify_registry.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/scripts/verify_release_tag.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/scripts/verify_s3_compatibility.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/fault_injection/test_lock_interruption.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/fault_injection/test_release_state_interruption.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/fault_injection/test_state_interruption.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/fault_injection/test_subprocess_tree_cleanup.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_backup_cli.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_backup_engine.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_candidate_runner.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_candidate_validation.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_demo_docker.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_demo_prepare.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_demo_runtime.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_migration_rehearsal.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_milestone1_gate.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_nginx_hook_example.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/integration/test_production_runner.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/test_cli.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/test_config.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/test_errors.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_backup.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_candidate.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_cutover.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_deploy_cli.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_diagnostics.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_docker_compose_production_runner.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_docker_compose_runner.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_health.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_locking.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_manual_restore.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_migration.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_milestone8_cli.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_recover_cli.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_recovery.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_release_cli.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_releases.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_restore.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_restore_cli.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_retention.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_s3_storage.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_sqlite_checks.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_state.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_subprocesses.py +0 -0
- {dploydb-0.1.0 → dploydb-0.1.1}/tests/unit/test_traffic.py +0 -0
|
@@ -6,6 +6,16 @@ All notable changes to DployDB are documented here. The project follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.1.1] - 2026-07-19
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Treat the standard uppercase Linux `PWD` environment variable as a working
|
|
14
|
+
directory rather than a password field, preventing exact-value redaction from
|
|
15
|
+
invalidating absolute release-manifest paths during deployment.
|
|
16
|
+
- Exercise the installed clean-Linux deployment with `PWD` equal to the project
|
|
17
|
+
root and require the active release to retain an absolute operation-log path.
|
|
18
|
+
|
|
9
19
|
## [0.1.0] - 2026-07-19
|
|
10
20
|
|
|
11
21
|
### Added
|
|
@@ -32,5 +42,6 @@ All notable changes to DployDB are documented here. The project follows
|
|
|
32
42
|
- During `0.x`, breaking public-contract changes may occur only in minor releases
|
|
33
43
|
and will include explicit migration guidance.
|
|
34
44
|
|
|
35
|
-
[Unreleased]: https://github.com/recursiveway/dployDB/compare/v0.1.
|
|
45
|
+
[Unreleased]: https://github.com/recursiveway/dployDB/compare/v0.1.1...HEAD
|
|
46
|
+
[0.1.1]: https://github.com/recursiveway/dployDB/releases/tag/v0.1.1
|
|
36
47
|
[0.1.0]: https://github.com/recursiveway/dployDB/releases/tag/v0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dploydb
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Deployment safety for SQLite applications
|
|
5
5
|
Project-URL: Homepage, https://github.com/recursiveway/dployDB
|
|
6
6
|
Project-URL: Repository, https://github.com/recursiveway/dployDB
|
|
@@ -38,7 +38,7 @@ Description-Content-Type: text/markdown
|
|
|
38
38
|
DployDB is being built as a deployment-safety tool for applications that use one SQLite database on one Linux server.
|
|
39
39
|
|
|
40
40
|
> [!WARNING]
|
|
41
|
-
> DployDB 0.1.
|
|
41
|
+
> DployDB 0.1.1 is Alpha software. Its safety gates are real and extensively
|
|
42
42
|
> tested, but public interfaces may still change in documented `0.x` minor
|
|
43
43
|
> releases. Read the [supported limits](docs/limitations.md), keep independent
|
|
44
44
|
> backups, and prove the complete failure/restore flow on a non-production host
|
|
@@ -59,7 +59,7 @@ docker compose version
|
|
|
59
59
|
|
|
60
60
|
git clone https://github.com/recursiveway/dployDB.git
|
|
61
61
|
cd dployDB
|
|
62
|
-
pipx install dploydb==0.1.
|
|
62
|
+
pipx install dploydb==0.1.1
|
|
63
63
|
dploydb --no-color version
|
|
64
64
|
```
|
|
65
65
|
|
|
@@ -187,7 +187,7 @@ off-server backup, and protected retention are implemented.
|
|
|
187
187
|
Install the published Alpha CLI:
|
|
188
188
|
|
|
189
189
|
```bash
|
|
190
|
-
pipx install dploydb==0.1.
|
|
190
|
+
pipx install dploydb==0.1.1
|
|
191
191
|
dploydb version
|
|
192
192
|
```
|
|
193
193
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
DployDB is being built as a deployment-safety tool for applications that use one SQLite database on one Linux server.
|
|
9
9
|
|
|
10
10
|
> [!WARNING]
|
|
11
|
-
> DployDB 0.1.
|
|
11
|
+
> DployDB 0.1.1 is Alpha software. Its safety gates are real and extensively
|
|
12
12
|
> tested, but public interfaces may still change in documented `0.x` minor
|
|
13
13
|
> releases. Read the [supported limits](docs/limitations.md), keep independent
|
|
14
14
|
> backups, and prove the complete failure/restore flow on a non-production host
|
|
@@ -29,7 +29,7 @@ docker compose version
|
|
|
29
29
|
|
|
30
30
|
git clone https://github.com/recursiveway/dployDB.git
|
|
31
31
|
cd dployDB
|
|
32
|
-
pipx install dploydb==0.1.
|
|
32
|
+
pipx install dploydb==0.1.1
|
|
33
33
|
dploydb --no-color version
|
|
34
34
|
```
|
|
35
35
|
|
|
@@ -157,7 +157,7 @@ off-server backup, and protected retention are implemented.
|
|
|
157
157
|
Install the published Alpha CLI:
|
|
158
158
|
|
|
159
159
|
```bash
|
|
160
|
-
pipx install dploydb==0.1.
|
|
160
|
+
pipx install dploydb==0.1.1
|
|
161
161
|
dploydb version
|
|
162
162
|
```
|
|
163
163
|
|
|
@@ -66,6 +66,14 @@ different bytes. Keep the GitHub release as a draft, diagnose the failure, and
|
|
|
66
66
|
rerun the immutable tag workflow when safe. PyPI files cannot be replaced or
|
|
67
67
|
rolled back; a bad public release must be yanked and superseded by a new patch.
|
|
68
68
|
|
|
69
|
+
If a tag-triggered run fails before artifacts are built because the runner did
|
|
70
|
+
not materialize the annotated tag object, preserve the verified tag. Fix the
|
|
71
|
+
workflow through a protected pull request, merge it to `main`, and manually
|
|
72
|
+
dispatch `Publish release` from `main` with the existing canonical tag. The
|
|
73
|
+
recovery path explicitly fetches that remote tag object and checks out the
|
|
74
|
+
immutable tagged source; it must not be used to move or recreate a tag. The
|
|
75
|
+
normal protected TestPyPI and PyPI approvals still apply.
|
|
76
|
+
|
|
69
77
|
## One-time repository setup
|
|
70
78
|
|
|
71
79
|
- Make the repository public, enable Issues, private vulnerability reporting,
|
|
@@ -127,7 +127,10 @@ _URL_USERINFO = re.compile(
|
|
|
127
127
|
|
|
128
128
|
def is_sensitive_key(key: str) -> bool:
|
|
129
129
|
"""Return whether a mapping key conventionally contains a secret value."""
|
|
130
|
-
|
|
130
|
+
normalized = key.strip().strip("\"'")
|
|
131
|
+
if normalized == "PWD":
|
|
132
|
+
return False
|
|
133
|
+
candidate = normalized.removeprefix("--")
|
|
131
134
|
return _SENSITIVE_KEY.fullmatch(candidate) is not None
|
|
132
135
|
|
|
133
136
|
|
|
@@ -198,6 +198,7 @@ def _demo_environment() -> dict[str, str]:
|
|
|
198
198
|
"DPLOYDB_DEMO_UID": "0",
|
|
199
199
|
"DPLOYDB_VERSION": "v1",
|
|
200
200
|
"NO_COLOR": "1",
|
|
201
|
+
"PWD": "/workspace",
|
|
201
202
|
"PYTHONPATH": "/workspace",
|
|
202
203
|
}
|
|
203
204
|
|
|
@@ -288,6 +289,12 @@ def _run_readme_demo(container: str, executable: str) -> dict[str, Any]:
|
|
|
288
289
|
release_payload = json.loads(releases.stdout)
|
|
289
290
|
if release_payload.get("active_release_id") != deployment_payload.get("release_id"):
|
|
290
291
|
_stop("clean Linux release history does not select the deployed release")
|
|
292
|
+
selected_releases = release_payload.get("releases")
|
|
293
|
+
if not isinstance(selected_releases, list) or len(selected_releases) != 1:
|
|
294
|
+
_stop(f"clean Linux release history was unexpected: {release_payload!r}")
|
|
295
|
+
operation_log = selected_releases[0].get("log_path")
|
|
296
|
+
if not isinstance(operation_log, str) or not operation_log.startswith("/workspace/"):
|
|
297
|
+
_stop(f"clean Linux release log path was not absolute: {operation_log!r}")
|
|
291
298
|
|
|
292
299
|
database_check = _exec(
|
|
293
300
|
container,
|
|
@@ -23,6 +23,8 @@ import yaml
|
|
|
23
23
|
|
|
24
24
|
from dploydb.config import STARTER_CONFIGURATION
|
|
25
25
|
from dploydb.models import new_operation_id
|
|
26
|
+
from dploydb.redaction import SecretRegistry
|
|
27
|
+
from dploydb.releases import ReleaseStore
|
|
26
28
|
from dploydb.storage.local import LocalBackupStorage
|
|
27
29
|
|
|
28
30
|
ROOT = Path(__file__).resolve().parents[2]
|
|
@@ -390,6 +392,8 @@ def test_real_docker_deploy_flows_and_pre_activation_traffic_isolation(
|
|
|
390
392
|
time.sleep(0.025)
|
|
391
393
|
assert any(record["observed"] == "old" for record in monitor.records)
|
|
392
394
|
|
|
395
|
+
deployment_environment = _environment(data, production_port, release)
|
|
396
|
+
deployment_environment["PWD"] = str(tmp_path)
|
|
393
397
|
result = subprocess.run(
|
|
394
398
|
[
|
|
395
399
|
str(ROOT / ".venv" / "bin" / "dploydb"),
|
|
@@ -401,8 +405,8 @@ def test_real_docker_deploy_flows_and_pre_activation_traffic_isolation(
|
|
|
401
405
|
"--json",
|
|
402
406
|
"--non-interactive",
|
|
403
407
|
],
|
|
404
|
-
cwd=
|
|
405
|
-
env=
|
|
408
|
+
cwd=tmp_path,
|
|
409
|
+
env=deployment_environment,
|
|
406
410
|
capture_output=True,
|
|
407
411
|
text=True,
|
|
408
412
|
timeout=300,
|
|
@@ -413,6 +417,10 @@ def test_real_docker_deploy_flows_and_pre_activation_traffic_isolation(
|
|
|
413
417
|
assert payload["outcome"] == expected_outcome
|
|
414
418
|
assert payload["traffic_activated"] is (scenario == "success")
|
|
415
419
|
assert payload["recovery_required"] is False
|
|
420
|
+
release_store = ReleaseStore(tmp_path / "state", secrets=SecretRegistry())
|
|
421
|
+
persisted_release, _pointers = release_store.lookup_history_release(payload["release_id"])
|
|
422
|
+
assert persisted_release.operation_log_path.is_absolute()
|
|
423
|
+
assert persisted_release.operation_log_path.is_relative_to(tmp_path)
|
|
416
424
|
|
|
417
425
|
if scenario == "success":
|
|
418
426
|
_wait_for_release(production_port, "v2")
|
|
@@ -46,6 +46,9 @@ def test_empty_secret_values_are_ignored_without_corrupting_output() -> None:
|
|
|
46
46
|
"key",
|
|
47
47
|
(
|
|
48
48
|
"password",
|
|
49
|
+
"pwd",
|
|
50
|
+
"DATABASE_PWD",
|
|
51
|
+
"--pwd",
|
|
49
52
|
"DATABASE_PASSWORD",
|
|
50
53
|
"api-key",
|
|
51
54
|
"S3_SECRET_ACCESS_KEY",
|
|
@@ -61,7 +64,10 @@ def test_sensitive_keys_are_recognized(key: str) -> None:
|
|
|
61
64
|
assert is_sensitive_key(key)
|
|
62
65
|
|
|
63
66
|
|
|
64
|
-
@pytest.mark.parametrize(
|
|
67
|
+
@pytest.mark.parametrize(
|
|
68
|
+
"key",
|
|
69
|
+
("PWD", "project", "candidate_port", "secretary", "tokenizer"),
|
|
70
|
+
)
|
|
65
71
|
def test_non_sensitive_keys_are_not_over_redacted(key: str) -> None:
|
|
66
72
|
assert not is_sensitive_key(key)
|
|
67
73
|
|
|
@@ -72,6 +72,7 @@ from dploydb.subprocesses import (
|
|
|
72
72
|
CapturedOutput,
|
|
73
73
|
CommandOutcome,
|
|
74
74
|
CommandResult,
|
|
75
|
+
SubprocessRunner,
|
|
75
76
|
TerminationReason,
|
|
76
77
|
)
|
|
77
78
|
from dploydb.traffic import TrafficAction, TrafficHookResult
|
|
@@ -868,6 +869,36 @@ def test_successful_coordinator_activates_checked_release_in_exact_order(
|
|
|
868
869
|
assert "traffic_activation_started" in {event.stage for event in events}
|
|
869
870
|
|
|
870
871
|
|
|
872
|
+
def test_standard_pwd_environment_preserves_absolute_release_paths(tmp_path: Path) -> None:
|
|
873
|
+
config_path, loaded = loaded_project(tmp_path)
|
|
874
|
+
command = SubprocessRunner(secrets=loaded.secrets).run(
|
|
875
|
+
[sys.executable, "-c", "pass"],
|
|
876
|
+
timeout_seconds=5,
|
|
877
|
+
environment={"PWD": str(tmp_path)},
|
|
878
|
+
working_directory=tmp_path,
|
|
879
|
+
)
|
|
880
|
+
assert command.succeeded
|
|
881
|
+
assert command.working_directory == str(tmp_path)
|
|
882
|
+
|
|
883
|
+
selected = harness(loaded, config_path)
|
|
884
|
+
result = run_deploy(loaded, config_path, selected)
|
|
885
|
+
|
|
886
|
+
persisted = ReleaseStore(
|
|
887
|
+
loaded.config.state_directory,
|
|
888
|
+
secrets=loaded.secrets,
|
|
889
|
+
).read_manifest(result.release.release_id)
|
|
890
|
+
assert result.active is True
|
|
891
|
+
assert persisted.status is DeploymentState.ACTIVE
|
|
892
|
+
assert persisted.operation_log_path.is_absolute()
|
|
893
|
+
assert persisted.operation_log_path.is_relative_to(tmp_path)
|
|
894
|
+
assert persisted.previous_application is not None
|
|
895
|
+
assert persisted.previous_application.database_directory.is_absolute()
|
|
896
|
+
assert persisted.previous_application.database_directory.is_relative_to(tmp_path)
|
|
897
|
+
assert persisted.new_application is not None
|
|
898
|
+
assert persisted.new_application.database_directory.is_absolute()
|
|
899
|
+
assert persisted.new_application.database_directory.is_relative_to(tmp_path)
|
|
900
|
+
|
|
901
|
+
|
|
871
902
|
def test_required_remote_final_backup_is_verified_before_production_migration(
|
|
872
903
|
tmp_path: Path,
|
|
873
904
|
) -> None:
|
|
@@ -38,7 +38,7 @@ def test_readme_quick_start_uses_the_installed_cli_and_parses_real_json() -> Non
|
|
|
38
38
|
readme = (ROOT / "README.md").read_text(encoding="utf-8")
|
|
39
39
|
|
|
40
40
|
for required in (
|
|
41
|
-
"pipx install dploydb==0.1.
|
|
41
|
+
"pipx install dploydb==0.1.1",
|
|
42
42
|
"git clone https://github.com/recursiveway/dployDB.git",
|
|
43
43
|
"python3 -m demo.prepare",
|
|
44
44
|
"dploydb --no-color doctor --deep",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Release-readiness contracts for DployDB 0.1.
|
|
1
|
+
"""Release-readiness contracts for DployDB 0.1.1 Alpha."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -29,7 +29,7 @@ def test_public_package_metadata_declares_alpha_license_owner_and_urls() -> None
|
|
|
29
29
|
|
|
30
30
|
assert metadata["build-system"]["requires"] == ["hatchling>=1.27"]
|
|
31
31
|
assert project["name"] == "dploydb"
|
|
32
|
-
assert project["version"] == "0.1.
|
|
32
|
+
assert project["version"] == "0.1.1"
|
|
33
33
|
assert project["license"] == "Apache-2.0"
|
|
34
34
|
assert project["license-files"] == ["LICENSE", "NOTICE"]
|
|
35
35
|
assert project["authors"] == [{"name": "RecursiveWay"}]
|
|
@@ -80,8 +80,8 @@ def test_license_notice_and_public_policies_are_present() -> None:
|
|
|
80
80
|
def test_readme_is_explicitly_alpha_and_publicly_installable() -> None:
|
|
81
81
|
readme = (ROOT / "README.md").read_text(encoding="utf-8")
|
|
82
82
|
|
|
83
|
-
assert "DployDB 0.1.
|
|
84
|
-
assert "pipx install dploydb==0.1.
|
|
83
|
+
assert "DployDB 0.1.1 is Alpha software" in readme
|
|
84
|
+
assert "pipx install dploydb==0.1.1" in readme
|
|
85
85
|
assert "Apache License 2.0" in readme
|
|
86
86
|
assert "1.0.0" in readme
|
|
87
87
|
assert "SECURITY.md" in readme
|
|
@@ -110,6 +110,21 @@ def test_workflows_pin_actions_and_limit_publish_permissions() -> None:
|
|
|
110
110
|
assert "--draft=false --prerelease=true" in release
|
|
111
111
|
|
|
112
112
|
|
|
113
|
+
def test_release_workflow_recovers_an_existing_immutable_tag_from_main() -> None:
|
|
114
|
+
release = WORKFLOWS[1].read_text(encoding="utf-8")
|
|
115
|
+
|
|
116
|
+
assert "workflow_dispatch:" in release
|
|
117
|
+
assert "Existing verified release tag to recover" in release
|
|
118
|
+
assert "release tag is not canonical" in release
|
|
119
|
+
assert 'test "$GITHUB_REF" = "refs/heads/main"' in release
|
|
120
|
+
assert '"refs/tags/${TAG}:refs/tags/${TAG}"' in release
|
|
121
|
+
assert 'test "$object_type" = "tag"' in release
|
|
122
|
+
assert 'test "$remote_target" = "$(git rev-parse "${TAG}^{}")"' in release
|
|
123
|
+
assert ".verification.verified" in release
|
|
124
|
+
assert release.count("ref: refs/tags/${{ env.RELEASE_TAG }}") == 4
|
|
125
|
+
assert "${{ github.ref_name }}" not in release
|
|
126
|
+
|
|
127
|
+
|
|
113
128
|
def _write_wheel(path: Path, version: str) -> None:
|
|
114
129
|
with zipfile.ZipFile(path, "w") as archive:
|
|
115
130
|
archive.writestr(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|