netprotocols 1.3.0__tar.gz → 2.2.0__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.
- netprotocols-2.2.0/.github/workflows/ci.yml +114 -0
- netprotocols-2.2.0/.github/workflows/fuzz.yml +64 -0
- netprotocols-2.2.0/.github/workflows/release.yml +61 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/.gitignore +8 -0
- netprotocols-2.2.0/ARCHITECTURE.md +476 -0
- netprotocols-2.2.0/CHANGELOG.md +952 -0
- netprotocols-2.2.0/PKG-INFO +446 -0
- netprotocols-2.2.0/README.md +421 -0
- netprotocols-2.2.0/benchmarks/baseline.json +13 -0
- netprotocols-2.2.0/docs/CLAIMS.md +809 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/pyproject.toml +10 -1
- netprotocols-2.2.0/scripts/benchmark.py +449 -0
- netprotocols-2.2.0/scripts/benchmark_encode.py +107 -0
- netprotocols-2.2.0/scripts/benchmark_import.py +63 -0
- netprotocols-2.2.0/scripts/pyodide/check_in_pyodide.py +137 -0
- netprotocols-2.2.0/scripts/pyodide/package-lock.json +53 -0
- netprotocols-2.2.0/scripts/pyodide/package.json +9 -0
- netprotocols-2.2.0/scripts/pyodide/run_in_pyodide.mjs +44 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/__init__.py +54 -3
- netprotocols-2.2.0/src/netprotocols/_base.py +241 -0
- netprotocols-2.2.0/src/netprotocols/_defaults.py +105 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/checksum.py +9 -3
- netprotocols-2.2.0/src/netprotocols/flow.py +96 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer2/arp.py +68 -18
- netprotocols-2.2.0/src/netprotocols/layer2/ethernet.py +108 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer2/vlan.py +37 -10
- netprotocols-2.2.0/src/netprotocols/layer3/__init__.py +28 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer3/gre.py +23 -7
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer3/icmp.py +69 -5
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer3/igmp.py +28 -5
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer3/ip.py +222 -77
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer3/ipv6_ext.py +153 -25
- netprotocols-2.2.0/src/netprotocols/layer4/__init__.py +4 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer4/_ports.py +30 -15
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer4/tcp.py +51 -11
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer4/udp.py +6 -4
- netprotocols-2.2.0/src/netprotocols/layer7/__init__.py +20 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer7/dhcp.py +154 -8
- netprotocols-2.2.0/src/netprotocols/layer7/dns.py +736 -0
- netprotocols-2.2.0/src/netprotocols/packet.py +174 -0
- netprotocols-2.2.0/src/netprotocols/pcap.py +504 -0
- netprotocols-2.2.0/src/netprotocols/registry.py +385 -0
- netprotocols-2.2.0/src/netprotocols/utils/exceptions.py +136 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/utils/ipv4.py +19 -3
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/utils/mac.py +22 -4
- netprotocols-2.2.0/src/netprotocols/walk.py +173 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/conftest.py +13 -21
- netprotocols-2.2.0/tests/strategies.py +274 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_arp.py +16 -2
- netprotocols-2.2.0/tests/test_contract.py +217 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_corpus.py +18 -18
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_dhcp.py +117 -3
- netprotocols-2.2.0/tests/test_diagnostics.py +552 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_dns.py +149 -2
- netprotocols-2.2.0/tests/test_docs.py +115 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_ethernet.py +3 -1
- netprotocols-2.2.0/tests/test_exports.py +82 -0
- netprotocols-2.2.0/tests/test_flow.py +174 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_fuzz.py +141 -4
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_gre.py +9 -6
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_icmp.py +48 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_igmp.py +2 -2
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_ip.py +163 -2
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_ipv6_ext.py +175 -3
- netprotocols-2.2.0/tests/test_packet.py +103 -0
- netprotocols-2.2.0/tests/test_pattern_matching.py +341 -0
- netprotocols-2.2.0/tests/test_pcap.py +367 -0
- netprotocols-2.2.0/tests/test_registry.py +296 -0
- netprotocols-2.2.0/tests/test_version.py +54 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_vlan.py +3 -0
- netprotocols-2.2.0/tests/test_walk.py +414 -0
- netprotocols-2.2.0/tests/test_workflows.py +118 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/uv.lock +27 -1
- netprotocols-1.3.0/.github/workflows/ci.yml +0 -47
- netprotocols-1.3.0/.github/workflows/release.yml +0 -18
- netprotocols-1.3.0/ARCHITECTURE.md +0 -295
- netprotocols-1.3.0/CHANGELOG.md +0 -296
- netprotocols-1.3.0/PKG-INFO +0 -198
- netprotocols-1.3.0/README.md +0 -173
- netprotocols-1.3.0/src/netprotocols/_base.py +0 -128
- netprotocols-1.3.0/src/netprotocols/layer2/ethernet.py +0 -90
- netprotocols-1.3.0/src/netprotocols/layer3/__init__.py +0 -21
- netprotocols-1.3.0/src/netprotocols/layer4/__init__.py +0 -4
- netprotocols-1.3.0/src/netprotocols/layer7/__init__.py +0 -3
- netprotocols-1.3.0/src/netprotocols/layer7/dns.py +0 -436
- netprotocols-1.3.0/src/netprotocols/packet.py +0 -88
- netprotocols-1.3.0/src/netprotocols/utils/exceptions.py +0 -48
- netprotocols-1.3.0/tests/test_contract.py +0 -108
- netprotocols-1.3.0/tests/test_packet.py +0 -37
- {netprotocols-1.3.0 → netprotocols-2.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/.github/ISSUE_TEMPLATE/protocol_request.yml +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/.github/pull_request_template.md +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/CONTRIBUTING.md +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/LICENSE +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/scripts/capture_fixtures.sh +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/scripts/capture_fixtures_dhcp.sh +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/scripts/capture_fixtures_dns_tcp.sh +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/scripts/capture_fixtures_gre.sh +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/scripts/capture_fixtures_igmp.sh +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/scripts/capture_fixtures_supplement.sh +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/scripts/capture_fixtures_vlan.sh +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/scripts/check_fixtures.py +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/_enums.py +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/layer2/__init__.py +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/py.typed +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/src/netprotocols/utils/__init__.py +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/MANIFEST.md +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/arp_exchange.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/dhcp.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/dns_tcp.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/gre.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/icmpv4_echo_lo.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/icmpv4_external.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/icmpv4_ttl_exceeded.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/icmpv6_echo_lo.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/igmp.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/ipv4_fragments.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/ipv6_fragments.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/ipv6_mld.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/ipv6_ndp_mld.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/arp_exchange.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/dhcp.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/dns_tcp.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/gre.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/icmpv4_echo_lo.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/icmpv4_external.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/icmpv4_ttl_exceeded.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/icmpv6_echo_lo.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/igmp.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/ipv4_fragments.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/ipv6_fragments.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/ipv6_mld.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/ipv6_ndp_mld.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/tcp_http.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/tcp_https.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/udp_dns.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/staging/vlan_icmp.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/tcp_http.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/tcp_https.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/udp_dns.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/fixtures/vlan_icmp.pcap +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_checksum.py +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_tcp.py +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_udp.py +0 -0
- {netprotocols-1.3.0 → netprotocols-2.2.0}/tests/test_utils.py +0 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
# Callable so the release workflow can run this exact ladder against a
|
|
9
|
+
# tagged commit before publishing (see release.yml). Keeping one
|
|
10
|
+
# definition means the release gate cannot drift from the PR gate.
|
|
11
|
+
workflow_call:
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
lint:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v5
|
|
18
|
+
- uses: astral-sh/setup-uv@v6
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
- run: uv run ruff check
|
|
22
|
+
- run: uv run ruff format --check
|
|
23
|
+
|
|
24
|
+
typecheck:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v5
|
|
28
|
+
- uses: astral-sh/setup-uv@v6
|
|
29
|
+
with:
|
|
30
|
+
python-version: "3.12"
|
|
31
|
+
- run: uv run mypy
|
|
32
|
+
|
|
33
|
+
test:
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
strategy:
|
|
36
|
+
matrix:
|
|
37
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v5
|
|
40
|
+
- uses: astral-sh/setup-uv@v6
|
|
41
|
+
with:
|
|
42
|
+
python-version: ${{ matrix.python-version }}
|
|
43
|
+
- run: uv run --frozen pytest --cov=netprotocols --cov-report=term
|
|
44
|
+
|
|
45
|
+
build:
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v5
|
|
49
|
+
- uses: astral-sh/setup-uv@v6
|
|
50
|
+
- run: uv build
|
|
51
|
+
- run: uv run --isolated --no-project --with dist/*.whl python -c "import netprotocols; print(netprotocols.__version__)"
|
|
52
|
+
|
|
53
|
+
# Proves the README's browser/WASM claim (#99) against the real
|
|
54
|
+
# thing, not a simulation of it: boots an actual Pyodide runtime
|
|
55
|
+
# (scripts/pyodide/run_in_pyodide.mjs, via Node — no browser needed,
|
|
56
|
+
# same WebAssembly build either way) and decodes the whole
|
|
57
|
+
# real-capture corpus with the wheel this job just built. See
|
|
58
|
+
# scripts/pyodide/check_in_pyodide.py for what it checks and why.
|
|
59
|
+
pyodide:
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
steps:
|
|
62
|
+
- uses: actions/checkout@v5
|
|
63
|
+
- uses: astral-sh/setup-uv@v6
|
|
64
|
+
with:
|
|
65
|
+
python-version: "3.12"
|
|
66
|
+
- run: uv build
|
|
67
|
+
- uses: actions/setup-node@v4
|
|
68
|
+
with:
|
|
69
|
+
node-version: "22"
|
|
70
|
+
- run: npm ci
|
|
71
|
+
working-directory: scripts/pyodide
|
|
72
|
+
- run: >-
|
|
73
|
+
node scripts/pyodide/run_in_pyodide.mjs
|
|
74
|
+
"$GITHUB_WORKSPACE" scripts/pyodide/check_in_pyodide.py
|
|
75
|
+
|
|
76
|
+
# Blocking, at 15% below the committed baseline. The threshold has
|
|
77
|
+
# runner data behind it: this job's first run measured 3.7% away from
|
|
78
|
+
# a baseline recorded on entirely different hardware, and run-to-run
|
|
79
|
+
# spread on one machine is ~2%. 15% is therefore roughly four times
|
|
80
|
+
# the noise it has to tolerate, which leaves real regressions (Tier 1
|
|
81
|
+
# moved this number by 30-90% a step) nowhere to hide.
|
|
82
|
+
#
|
|
83
|
+
# A failure re-measures once before failing, because a shared runner
|
|
84
|
+
# can lose a slice of CPU to a neighbour: a genuine regression fails
|
|
85
|
+
# both attempts, a noisy one usually does not.
|
|
86
|
+
#
|
|
87
|
+
# Pinned to the baseline's interpreter on purpose: normalization
|
|
88
|
+
# cancels how fast the machine is, not which CPython it runs (see the
|
|
89
|
+
# module docstring in scripts/benchmark.py). If a change is a
|
|
90
|
+
# deliberate trade, re-record with --update-baseline and say why.
|
|
91
|
+
benchmark:
|
|
92
|
+
runs-on: ubuntu-latest
|
|
93
|
+
steps:
|
|
94
|
+
- uses: actions/checkout@v5
|
|
95
|
+
- uses: astral-sh/setup-uv@v6
|
|
96
|
+
with:
|
|
97
|
+
python-version: "3.12"
|
|
98
|
+
- name: Corpus decode throughput
|
|
99
|
+
shell: bash
|
|
100
|
+
run: |
|
|
101
|
+
# Keep the benchmark's own exit status: piping the whole thing
|
|
102
|
+
# into tee would report tee's, and wrapping it in a { } group
|
|
103
|
+
# would report the trailing echo's -- either way the gate
|
|
104
|
+
# would pass while the check failed.
|
|
105
|
+
status=0
|
|
106
|
+
uv run --frozen --group bench python scripts/benchmark.py \
|
|
107
|
+
--check --threshold 15 --compare >benchmark.out 2>&1 || status=$?
|
|
108
|
+
{
|
|
109
|
+
echo '```'
|
|
110
|
+
cat benchmark.out
|
|
111
|
+
echo '```'
|
|
112
|
+
} >>"$GITHUB_STEP_SUMMARY"
|
|
113
|
+
cat benchmark.out
|
|
114
|
+
exit "$status"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: Nightly fuzz
|
|
2
|
+
|
|
3
|
+
# Separate from ci.yml on purpose: ci.yml is reused via workflow_call
|
|
4
|
+
# by release.yml specifically so the release gate and the PR gate never
|
|
5
|
+
# drift apart (see the comment at the top of ci.yml). Folding a
|
|
6
|
+
# schedule trigger into it would fire that whole ladder on a cron too,
|
|
7
|
+
# not just this exploratory job.
|
|
8
|
+
on:
|
|
9
|
+
schedule:
|
|
10
|
+
# Arbitrary; 03:00 UTC lands after most contributors' working day
|
|
11
|
+
# across common timezones, clear of any push/PR traffic.
|
|
12
|
+
- cron: "0 3 * * *"
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
# tests/test_fuzz.py's own "netprotocols" profile is deliberately
|
|
20
|
+
# derandomize=True at 200 examples, so CI has run the *same* 200
|
|
21
|
+
# inputs on every push since it was written. This job runs the whole
|
|
22
|
+
# suite under the "nightly" profile instead (10,000 examples, a real
|
|
23
|
+
# random seed each time — see tests/test_fuzz.py's module docstring),
|
|
24
|
+
# so it explores new ground every run rather than replaying the same
|
|
25
|
+
# counterexample search forever. Pinned to Python 3.12 only, unlike
|
|
26
|
+
# the "test" job's full matrix: this is an exploratory job, not a
|
|
27
|
+
# compatibility gate, and 3x the interpreters would 3x its cost for
|
|
28
|
+
# no extra coverage of what it is actually looking for.
|
|
29
|
+
fuzz:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v5
|
|
33
|
+
- uses: astral-sh/setup-uv@v6
|
|
34
|
+
with:
|
|
35
|
+
python-version: "3.12"
|
|
36
|
+
# Keyed by run id with a prefix restore-key: a fixed key would
|
|
37
|
+
# restore forever but (actions/cache never overwrites an existing
|
|
38
|
+
# key) never actually save a new one, so nothing would
|
|
39
|
+
# accumulate. This restores the most recent run's cache and saves
|
|
40
|
+
# today's as a new entry, so Hypothesis's example database grows
|
|
41
|
+
# night over night instead of starting cold every time.
|
|
42
|
+
- name: Restore accumulated Hypothesis examples
|
|
43
|
+
uses: actions/cache@v4
|
|
44
|
+
with:
|
|
45
|
+
path: .hypothesis
|
|
46
|
+
key: hypothesis-nightly-${{ github.run_id }}
|
|
47
|
+
restore-keys: |
|
|
48
|
+
hypothesis-nightly-
|
|
49
|
+
- name: Run the full suite under the nightly fuzz profile
|
|
50
|
+
env:
|
|
51
|
+
HYPOTHESIS_PROFILE: nightly
|
|
52
|
+
run: uv run --frozen pytest
|
|
53
|
+
# A failed scheduled run already notifies repo watchers by
|
|
54
|
+
# default (GitHub's standard behavior) — that red run *is* the
|
|
55
|
+
# report; nothing here files an issue on top of it. This just
|
|
56
|
+
# makes the minimal counterexample recoverable without needing
|
|
57
|
+
# repo write access to re-run the job locally.
|
|
58
|
+
- name: Upload the failing example database
|
|
59
|
+
if: failure()
|
|
60
|
+
uses: actions/upload-artifact@v4
|
|
61
|
+
with:
|
|
62
|
+
name: hypothesis-nightly-failure-${{ github.run_id }}
|
|
63
|
+
path: .hypothesis
|
|
64
|
+
retention-days: 30
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
# Run the full QA ladder against the tagged commit before anything is
|
|
12
|
+
# uploaded. This is not redundant with the CI workflow's own triggers:
|
|
13
|
+
# those fire on pushes and pull requests targeting master, and a tag
|
|
14
|
+
# push matches neither, so without this job a release ran no checks at
|
|
15
|
+
# all. A tag can also point at a commit that never landed on master.
|
|
16
|
+
# A published version can only be yanked, never replaced.
|
|
17
|
+
ci:
|
|
18
|
+
uses: ./.github/workflows/ci.yml
|
|
19
|
+
|
|
20
|
+
publish:
|
|
21
|
+
needs: ci
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
environment: pypi
|
|
24
|
+
permissions:
|
|
25
|
+
id-token: write
|
|
26
|
+
contents: read
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v5
|
|
29
|
+
- uses: astral-sh/setup-uv@v6
|
|
30
|
+
- run: uv build
|
|
31
|
+
# The QA ladder cannot catch a mistagged release: every check
|
|
32
|
+
# passes because the code is fine and only the tag is wrong. Read
|
|
33
|
+
# the version back out of the artifact that is about to be
|
|
34
|
+
# uploaded, rather than re-parsing pyproject.toml, so this
|
|
35
|
+
# compares against what PyPI will actually receive.
|
|
36
|
+
- name: Verify the tag matches the version being published
|
|
37
|
+
run: |
|
|
38
|
+
set -euo pipefail
|
|
39
|
+
# Only the "v*" trigger keeps a bare "1.3.0" tag from reaching
|
|
40
|
+
# this step, where it would compare equal and pass. Check the
|
|
41
|
+
# prefix here too, so the contract survives a wider trigger.
|
|
42
|
+
case "${GITHUB_REF_NAME}" in
|
|
43
|
+
v*) tag="${GITHUB_REF_NAME#v}" ;;
|
|
44
|
+
*)
|
|
45
|
+
echo "::error::Tag ${GITHUB_REF_NAME} does not start with 'v'."
|
|
46
|
+
echo "Release tags must be of the form v<version>." >&2
|
|
47
|
+
exit 1
|
|
48
|
+
;;
|
|
49
|
+
esac
|
|
50
|
+
built=$(uv run --isolated --no-project --with dist/*.whl \
|
|
51
|
+
python -c \
|
|
52
|
+
"from importlib.metadata import version; print(version('netprotocols'))")
|
|
53
|
+
if [ "$tag" != "$built" ]; then
|
|
54
|
+
echo "::error::Tag ${GITHUB_REF_NAME} would publish version ${built}."
|
|
55
|
+
echo "The tag and the packaged version must agree." >&2
|
|
56
|
+
echo "Either retag as v${built}, or set the version in" >&2
|
|
57
|
+
echo "pyproject.toml (and __version__) to ${tag} and retag." >&2
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
echo "Tag ${GITHUB_REF_NAME} matches packaged version ${built}."
|
|
61
|
+
- run: uv publish --trusted-publishing always
|
|
@@ -147,3 +147,11 @@ amass.log
|
|
|
147
147
|
|
|
148
148
|
# Application-specific
|
|
149
149
|
.logs/tests/fixtures/staging/
|
|
150
|
+
|
|
151
|
+
# Written by the benchmark CI step (scripts/benchmark.py output)
|
|
152
|
+
benchmark.out
|
|
153
|
+
|
|
154
|
+
# npm dependency (the pyodide package itself) for scripts/pyodide/ —
|
|
155
|
+
# CI installs it fresh from package-lock.json, same as any other
|
|
156
|
+
# lockfile-pinned dependency.
|
|
157
|
+
scripts/pyodide/node_modules/
|