engineering-process 1.2.2__tar.gz → 1.2.3__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.
- {engineering_process-1.2.2/engineering_process.egg-info → engineering_process-1.2.3}/PKG-INFO +1 -1
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/__init__.py +1 -1
- {engineering_process-1.2.2 → engineering_process-1.2.3/engineering_process.egg-info}/PKG-INFO +1 -1
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process.egg-info/SOURCES.txt +1 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/pyproject.toml +1 -1
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_automation.py +27 -0
- engineering_process-1.2.3/tests/test_pypi_cache_horizon.py +81 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/LICENSE +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/MANIFEST.in +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/README.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/__main__.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/_supervisor_contract.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/_supervisor_posix.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/_supervisor_windows.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/_windows_job.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/adoption.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/cli.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/commands.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/contracts.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/distribution.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/helper_launch.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/lifecycle.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/production_engineering.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/project.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/publication_compat.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/release.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/repository.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/requirements-dev.txt +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/requirements-runtime.txt +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/skills.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/supervision.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process.egg-info/dependency_links.txt +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process.egg-info/entry_points.txt +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process.egg-info/requires.txt +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process.egg-info/top_level.txt +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/process-graph.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/finish-change/SKILL.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/implement-change/SKILL.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/improve-process/SKILL.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/plan-change/SKILL.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/production-engineering/SKILL.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/production-engineering/invariants.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/review-change/SKILL.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/run-change/SKILL.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/start-change/SKILL.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/verify-change/SKILL.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/change.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/plan.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/process-graph.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/process-lock.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/production-engineering.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/project-legacy.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/project.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/receipt.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/release-change.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/release.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/review.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/run.schema.json +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/setup.cfg +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/templates/AGENTS.process.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/templates/PULL_REQUEST_TEMPLATE.md +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/templates/adopt-process-windows-job.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/templates/adopt-process.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_adoption.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_architecture.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_cli.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_commands.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_contracts.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_distribution.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_lifecycle.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_production_engineering.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_publication_compat.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_release.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_repository.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_skills.py +0 -0
- {engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_supervisor_posix.py +0 -0
|
@@ -105,6 +105,31 @@ class AutomationTests(unittest.TestCase):
|
|
|
105
105
|
" dispatch-adoption:\n name: Dispatch consumer adoption\n", workflow
|
|
106
106
|
)
|
|
107
107
|
self.assertIn("needs: [metadata, publish]", workflow)
|
|
108
|
+
dispatch_job = workflow.split("\n dispatch-adoption:\n", maxsplit=1)[1]
|
|
109
|
+
self.assertIn(" timeout-minutes: 20\n", dispatch_job)
|
|
110
|
+
cache_wait = dispatch_job.split(
|
|
111
|
+
" - name: Wait for consumer Simple caches to expire\n", maxsplit=1
|
|
112
|
+
)[1].split(
|
|
113
|
+
" - name: Create short-lived Renovate event token\n", maxsplit=1
|
|
114
|
+
)[0]
|
|
115
|
+
self.assertIn(
|
|
116
|
+
"python verification/wait_for_pypi_cache_horizon.py",
|
|
117
|
+
cache_wait,
|
|
118
|
+
)
|
|
119
|
+
self.assertIn("${{ steps.release.outputs.published_at }}", cache_wait)
|
|
120
|
+
self.assertIn(
|
|
121
|
+
"ref: ${{ github.sha }}",
|
|
122
|
+
dispatch_job,
|
|
123
|
+
)
|
|
124
|
+
self.assertNotIn("ref: ${{ needs.metadata.outputs.source_sha }}", dispatch_job)
|
|
125
|
+
self.assertIn(
|
|
126
|
+
'published_at=$(gh release view "$RELEASE_TAG"',
|
|
127
|
+
dispatch_job,
|
|
128
|
+
)
|
|
129
|
+
self.assertLess(
|
|
130
|
+
dispatch_job.index(" - name: Bind the published distribution\n"),
|
|
131
|
+
dispatch_job.index(" - name: Wait for consumer Simple caches to expire\n"),
|
|
132
|
+
)
|
|
108
133
|
self.assertIn("Verify PyPI exposes the exact built hashes", workflow)
|
|
109
134
|
visibility = workflow.split(
|
|
110
135
|
" - name: Verify PyPI exposes the exact built hashes\n", maxsplit=1
|
|
@@ -142,6 +167,8 @@ class AutomationTests(unittest.TestCase):
|
|
|
142
167
|
publish_job = workflow.split(" publish:\n", maxsplit=1)[1].split(
|
|
143
168
|
"\n dispatch-adoption:\n", maxsplit=1
|
|
144
169
|
)[0]
|
|
170
|
+
self.assertIn("ref: ${{ needs.metadata.outputs.source_sha }}", publish_job)
|
|
171
|
+
self.assertNotIn("ref: ${{ github.sha }}", publish_job)
|
|
145
172
|
self.assertIn("id: release-token", publish_job)
|
|
146
173
|
self.assertIn("repositories: engineering-process", publish_job)
|
|
147
174
|
self.assertIn("permission-contents: write", publish_job)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
from email.message import Message
|
|
3
|
+
import unittest
|
|
4
|
+
from unittest.mock import patch
|
|
5
|
+
|
|
6
|
+
from verification.wait_for_pypi_cache_horizon import (
|
|
7
|
+
MAX_SIMPLE_CACHE_SECONDS,
|
|
8
|
+
read_simple_max_age,
|
|
9
|
+
parse_max_age,
|
|
10
|
+
remaining_seconds,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class _Response:
|
|
15
|
+
def __init__(self, headers: Message) -> None:
|
|
16
|
+
self.headers = headers
|
|
17
|
+
|
|
18
|
+
def __enter__(self) -> "_Response":
|
|
19
|
+
return self
|
|
20
|
+
|
|
21
|
+
def __exit__(self, *args: object) -> None:
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PyPICacheHorizonTests(unittest.TestCase):
|
|
26
|
+
NOW = datetime(2026, 9, 4, 13, 30, tzinfo=timezone.utc)
|
|
27
|
+
|
|
28
|
+
def test_parses_current_bounded_header(self) -> None:
|
|
29
|
+
self.assertEqual(600, parse_max_age(["max-age=600, public"]))
|
|
30
|
+
self.assertEqual(
|
|
31
|
+
MAX_SIMPLE_CACHE_SECONDS,
|
|
32
|
+
parse_max_age([f"public, max-age={MAX_SIMPLE_CACHE_SECONDS}"]),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def test_rejects_missing_duplicate_malformed_and_excessive_max_age(self) -> None:
|
|
36
|
+
invalid = [
|
|
37
|
+
None,
|
|
38
|
+
["public"],
|
|
39
|
+
["max-age=600", "max-age=300"],
|
|
40
|
+
["max-age=-1"],
|
|
41
|
+
["max-age=invalid"],
|
|
42
|
+
[f"max-age={MAX_SIMPLE_CACHE_SECONDS + 1}"],
|
|
43
|
+
]
|
|
44
|
+
for values in invalid:
|
|
45
|
+
with self.subTest(values=values), self.assertRaises(RuntimeError):
|
|
46
|
+
parse_max_age(values)
|
|
47
|
+
|
|
48
|
+
def test_reads_every_cache_control_field(self) -> None:
|
|
49
|
+
headers = Message()
|
|
50
|
+
headers["Content-Type"] = "application/vnd.pypi.simple.v1+json"
|
|
51
|
+
headers["Cache-Control"] = "public, max-age=600"
|
|
52
|
+
headers["Cache-Control"] = "max-age=300"
|
|
53
|
+
with patch(
|
|
54
|
+
"verification.wait_for_pypi_cache_horizon.urlopen",
|
|
55
|
+
return_value=_Response(headers),
|
|
56
|
+
), self.assertRaises(RuntimeError):
|
|
57
|
+
read_simple_max_age()
|
|
58
|
+
|
|
59
|
+
def test_current_horizon_and_elapsed_resume(self) -> None:
|
|
60
|
+
self.assertEqual(
|
|
61
|
+
305,
|
|
62
|
+
remaining_seconds("2026-09-04T13:20:00Z", 900, now=self.NOW),
|
|
63
|
+
)
|
|
64
|
+
self.assertEqual(
|
|
65
|
+
0,
|
|
66
|
+
remaining_seconds("2026-09-04T13:00:00Z", 600, now=self.NOW),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def test_rejects_malformed_naive_and_future_timestamps(self) -> None:
|
|
70
|
+
invalid = [
|
|
71
|
+
"invalid",
|
|
72
|
+
"2026-09-04T13:20:00",
|
|
73
|
+
"2026-09-04T13:31:01Z",
|
|
74
|
+
]
|
|
75
|
+
for published_at in invalid:
|
|
76
|
+
with self.subTest(published_at=published_at), self.assertRaises(RuntimeError):
|
|
77
|
+
remaining_seconds(published_at, 600, now=self.NOW)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/_supervisor_contract.py
RENAMED
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/_supervisor_posix.py
RENAMED
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/_supervisor_windows.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/helper_launch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/publication_compat.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/requirements-dev.txt
RENAMED
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process/requirements-runtime.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process.egg-info/requires.txt
RENAMED
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/engineering_process.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/finish-change/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/plan-change/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/review-change/SKILL.md
RENAMED
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/run-change/SKILL.md
RENAMED
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/start-change/SKILL.md
RENAMED
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/process_assets/skills/verify-change/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/schemas/production-engineering.schema.json
RENAMED
|
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
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/templates/adopt-process-windows-job.py
RENAMED
|
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
|
{engineering_process-1.2.2 → engineering_process-1.2.3}/tests/test_production_engineering.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|