Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/coverage-comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ jobs:
if tests not in ('success', 'failure', 'cancelled', 'skipped'):
sys.exit(f'invalid test outcome in artifact: {tests!r}')
total = number(data['total'])
# The leg's version, from the artifact; one written before #1660 has none.
# The leg's version, from the artifact; one without it reads as the coverage leg.
python = data.get('python')
if python is not None and not (isinstance(python, str) and re.fullmatch(r'3\.\d+', python)):
sys.exit(f'invalid Python version in artifact: {python!r}')
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/create-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -752,8 +752,7 @@ jobs:
- macos-latest
- macos-26-intel
- ubuntu-latest
# #2060: win-64, once Conda Update's leg had built and smoke-tested it
# green. Its `run:` steps name `bash`, as Windows runs `pwsh`.
# #2060: win-64. Its `run:` steps name `bash`, as Windows runs `pwsh`.
- windows-latest
# #1633, #1660: the supported tier only. No KTLO 3.10 leg: the list
# util/conda_vendor.py derives omits typing-extensions, which
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cron-conda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ jobs:
- macos-26-intel
- ubuntu-latest
# #2060: win-64, uploaded with the anaconda-client CLI as the Intel
# leg is, once its runs had built and smoke-tested it green.
# leg is.
- windows-latest
# #1633: the supported tier, from .github/python-versions.toml through
# `conda-update` (#1660); create-release.yml's ``conda`` job says why
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/cron-vendor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,10 @@ jobs:
find pcapkit/const -mindepth 2 -name '*.py' -exec isort -l100 -ppcapkit {} +

# #1853: both gates in `head` judge the commit from before the crawl, so
# 1.5.0b13 was committed with a test failing on it. The owner's ruling:
# test it here under #872's rule -- a module the tests fail with goes
# back to HEAD's copy, the rest are committed. util/vendor_test_gate.py's
# docstring gives the rule.
# they pass a crawl the tests fail on, as they did 1.5.0b13's. The
# owner's ruling: test it here under #872's rule -- a module the tests
# fail with goes back to HEAD's copy, the rest are committed.
# util/vendor_test_gate.py's docstring gives the rule.
#
# `continue-on-error`, so the tests never fail the job; if the step fails
# or times out, the next one discards every regenerated module. `.[test]`
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:
github.event.workflow_run.head_branch == 'main' &&
needs.head.outputs.verified == 'true'
))
concurrency: ci-${{ github.event_name == 'workflow_dispatch' && github.run_id || github.ref }} # Recommended if you intend to make multiple deployments in quick succession.
concurrency: ci-${{ github.event_name == 'workflow_dispatch' && github.run_id || github.ref }}
runs-on: macos-latest
steps:
- name: Checkout 🛎️
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ on:
pull_request:
branches: [main]
schedule:
# Saturdays, an hour clear of the other Saturday jobs.
# Saturdays, at an hour no other Saturday job uses.
- cron: '0 6 * * 6'
workflow_dispatch:

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/milestone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ name: Milestone
# "Milestone" in docs/source/contributing/workflows.rst: an open item, a merged
# pull request or an issue closed as completed gets the open milestone named
# after the checked-out `pcapkit.__version__`, unless it already holds another;
# an unmerged pull request or an issue closed as not planned loses whichever
# milestone it holds. A missing milestone is a warning, never created.
# an unmerged pull request or an issue closed as not planned or as a duplicate
# loses whichever milestone it holds. A missing milestone is a warning, never created.
#
# SECURITY. `pull_request_target` gives this run a write token on events a
# stranger can cause, so it must never execute anything the pull request
# supplies. The job below:
#
# * checks out `github.sha`, which under `pull_request_target` is the tip of
# the *base* branch, never the PR head, and only the three files it reads,
# the *base* branch, never the PR head, and only the files it reads,
# without persisting the token;
# * reads `__version__` from pcapkit/__init__.py as text, importing nothing;
# * takes nothing from the event payload but the item number, passed through
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/project-status.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Project Status

# Keeps the project board's Status field (users/JarryShaw/projects/2) in line with
# each item's state labels, which no built-in board workflow observes. The mapping
# is util/project_status.py:status_for; it and the PROJECT_TOKEN setup are
# is `status_for` in util/project_status.py; it and the PROJECT_TOKEN setup are
# documented under "Milestones and the Project Board" in
# docs/source/contributing/conventions/process.rst.
#
Expand Down
11 changes: 6 additions & 5 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ jobs:
cache: pip

# DPKT (#729), crypto and NGAP (#738) are here so the unit-tier tests
# gated on them run instead of skipping; all three install cleanly. On
# gated on them run instead of skipping; each installs cleanly. On
# PyPy 8.0 PyPI has no Linux wheel of cryptography, so pip builds it with
# the image's Rust and libssl-dev (#1958). `cli` (emoji) is not here: its
# only gated tests are in tests/integration, which this job ignores.
Expand Down Expand Up @@ -1166,8 +1166,8 @@ jobs:
runs-on: ubuntu-latest
# 45, as `test`'s: this is the only test job with no xdist, so a cell
# carries its whole serial cost, and a contended run once passed 20
# minutes. The slowest cell, with #1029's split, is 8.2m; even #1029's slowdown
# window, at least 1.6x, leaves it far inside the cap.
# minutes. Each cell is held well inside it by its run step's own cap,
# which ci-timing.yml's weekly report watches (#2254).
timeout-minutes: 45
strategy:
fail-fast: false
Expand Down Expand Up @@ -1224,8 +1224,9 @@ jobs:
python -c "import os; print('cpu_count', os.cpu_count())"

# `--verbose` names every test as it runs, so a hung cell shows where it
# was. The step cap is about twice the slowest cell's measured maximum,
# under the job's, so a hang reports as this step timing out.
# was. The step cap sits under the job's, so a hang reports as this step
# timing out. util/ci_timing.py flags a cell whose p90 reaches half of
# it, and such a cell is split, as `project` is (#2254).
- name: Run tests/${{ matrix.leg }} and the root-level modules under plain unittest
timeout-minutes: 20
run: python util/cap_file_size.py python util/run_unittest_leg.py ${{ matrix.leg }} ${{ matrix.exclude }} ${{ matrix.shard }} --verbose
Expand Down
25 changes: 12 additions & 13 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,19 @@ pcapkit-temp.html
# generated captures at examples/sample/, and nothing should track them.
examples/sample/
examples/captures/*
# Only the two genuine *inputs* are tracked. Everything else in this directory is
# build output: the captures `examples/generators/make_samples.py` writes, and the
# reference reports `examples/legacy_smoke/` renders out of these two inputs --
# out.json, out.plist, out.txt and pcapng.txt, via `make fixtures` there.
# Only the genuine *inputs*, re-included below, are tracked. Everything else in
# this directory is build output: the captures `examples/generators/make_samples.py`
# writes, and the reference reports `examples/legacy_smoke/` renders out of those
# inputs -- out.json, out.plist, out.txt and pcapng.txt, via `make fixtures` there.
#
# Those four used to be tracked, and the reason they no longer are is that a
# tracked report goes stale silently. Nothing reads one back, so nothing notices
# when a parser change alters how a frame renders: #685 was exactly that, with
# pcapng.txt still recording `packet -> NIL` for four blocks long after #683 gave
# PCAP-NG packet blocks their captured octets back. Regenerating them on every such
# change is work with no reader, and the tier guard in `tests/_tiers.py` asks git
# which captures are tracked rather than hardcoding a list, so dropping them here
# is the whole change -- see `examples/legacy_smoke/README.md` for how to rebuild
# them locally.
# The reports are not tracked because a tracked report goes stale silently.
# Nothing reads one back, so nothing notices when a parser change alters how a
# frame renders: #685 was exactly that, with pcapng.txt still recording
# `packet -> NIL` for four blocks long after #683 gave PCAP-NG packet blocks their
# captured octets back. Regenerating them on every such change is work with no
# reader, and the tier guard in `tests/_tiers.py` asks git which captures are
# tracked rather than hardcoding a list, so ignoring them here is all it takes --
# see `examples/legacy_smoke/README.md` for how to rebuild them locally.
!examples/captures/in.pcap
!examples/captures/dhcp.pcapng

Expand Down
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ pipenv:
vendor:
pipenv run pcapkit-vendor

# Sample captures under examples/captures/ are not tracked (see .gitignore);
# regenerate the ones the runtime, regression and integration tests read.
# Sample captures under examples/captures/, but for the inputs .gitignore
# lists, are not tracked; regenerate the ones the runtime, regression and
# integration tests read.
samples:
pipenv run python examples/generators/make_samples.py

Expand Down
3 changes: 2 additions & 1 deletion examples/benchmark/benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
__all__ = ['ENGINES', 'ROUNDS', 'REPEATS', 'expected_drivers', 'preflight', 'measure', 'run']

#: Every engine ``pcapkit.extract(engine=...)`` accepts, in the order the suite
#: exercises them. Matches :data:`examples.legacy_smoke._engine_support.ENGINES`.
#: exercises them. The same engines as
#: :data:`examples.legacy_smoke._engine_support.ENGINES`, in a different order.
#: ``'default'`` is ``pcapkit``'s own parser and is the cross-environment
#: baseline, so it is always measured first and never dropped from the list.
ENGINES = ('default', 'dpkt', 'scapy', 'pypcap', 'pcap_ct', 'pypcapfile', 'pyshark')
Expand Down
2 changes: 1 addition & 1 deletion examples/benchmark/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -1083,7 +1083,7 @@ def render_versions_rst(rows: 'Sequence[Row]', documents: 'Sequence[dict[str, An
lines.extend(_simple_table(headers, body, numeric=True))
lines.append('')

# The owner's own sentence about the hand-maintained table, kept word for word:
# The sentence docs/source/engines.rst carries under its table, kept word for word:
# it is the right warning, and a regenerated table that rewords it would show up as
# a diff in the prose every time the numbers changed. It sits between the table and
# the footnotes, where docs/source/engines.rst has it.
Expand Down
17 changes: 8 additions & 9 deletions examples/generators/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
*resolves* to the right class object, but that is a weaker property than the one
that actually matters -- it is satisfied by a table whose target could not parse
a packet if it tried.
:file:`tests/protocols/test_dispatch_bindings_unit.py` exists because exactly
that shipped once: its own docstring records that
:class:`~pcapkit.protocols.application.ospf.OSPF` "was reachable from no table at all
and could not have parsed a packet if it had been". But that module hand-picks
:file:`tests/protocols/test_dispatch_bindings_unit.py` asserts on the parsed
protocol chain for exactly that reason: as its own docstring records, a
protocol can be reachable from no table at all, and unable to parse a packet
if it were. But that module hand-picks
its cases rather than enumerating, so it guards the entries someone
remembered rather than the registries themselves. See GitHub issue #496.

Expand Down Expand Up @@ -59,7 +59,7 @@
a minimal dispatch probe, so both use the same placeholder payload
:meth:`~tests.protocols.transport.test_sctp_unit.SCTPUnitTests.test_ppid_dispatch_hook`
already does, and for the same documented reason -- one PPID is DTLS-wrapped,
which pcapkit implements no DTLS for, and the other degrades identically
and pcapkit implements no DTLS; the other degrades identically
because the payload is not an aligned PER encoding, exactly as that test's own
docstring records.

Expand Down Expand Up @@ -136,9 +136,8 @@ def code_name(code: 'Any', enum: 'Optional[Any]' = None) -> 'str':
"""Render a registry key as a name usable in a test id.

Most ``__proto__`` tables are keyed entirely by enumeration members, whose
own ``.name`` is used directly. ``Link.__proto__`` and
``Internet.__proto__`` each hold an entry keyed by a bare :class:`int`
instead (0x8137 for IPX, in ``Link``'s case) -- :func:`_resolve` does not
own ``.name`` is used directly. ``Link.__proto__`` holds an entry keyed by
a bare :class:`int` instead (0x8137 for IPX) -- :func:`_resolve` does not
care, since dict lookup does not distinguish an :class:`~enum.IntEnum`
member from the plain :class:`int` it equals, but a case label needs a
name. ``enum`` is consulted for that one, so the label reads
Expand Down Expand Up @@ -188,7 +187,7 @@ def _pcapng_bytes(linktype: 'Any', packet_data: 'bytes') -> 'bytes':
Built through :mod:`pcapkit`'s own :class:`~pcapkit.protocols.misc.pcapng.PCAPNG`
construction API rather than hand-rolled :mod:`struct` packing, the same way
:func:`examples.generators.options._pcapng_context` does -- GitHub issue
#496 judged hand-building a valid SHB+IDB+EPB stream by hand riskier than
#496 judged hand-building a valid SHB+IDB+EPB stream riskier than
the check was worth, and this sidesteps that by reusing the library's own
``make`` path, which is exactly what is under test one layer further down
anyway.
Expand Down
4 changes: 2 additions & 2 deletions examples/generators/endian.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
swallows the rest of the file and the read that follows is handed a negative
payload length, raising
``ValueError: read length must be non-negative or -1`` out of
:file:`pcapkit/protocols/schema/schema.py`. The fix is one character, and
nothing but these fixtures can tell whether it works.
:file:`pcapkit/protocols/schema/schema.py`. The defect is one character, and
nothing but these fixtures can tell whether it is present.

=============================== ==========================================
Fixture Exercises
Expand Down
15 changes: 8 additions & 7 deletions examples/generators/legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
The demonstration scripts under ``examples/legacy_smoke/`` predate the test
suite and read their captures out of ``examples/captures/`` by relative path.
Most of them read fixtures the sibling generators in this directory already
write, but two read captures that exist nowhere in the repository, so those two
scripts cannot run at all on a fresh checkout. This module writes them, with
write, but ``test_reassembly.py`` and ``test_analyse.py`` read captures that
exist nowhere in the repository, so those scripts cannot run at all on a fresh
checkout. This module writes them, with
:mod:`scapy`, deterministically and without network access.

``test.pcap``
Expand Down Expand Up @@ -66,7 +67,7 @@
4. The payload of a complete datagram goes to
:meth:`pcapkit.protocols.transport.transport.Transport.analyze`, which
picks the application protocol from the two port numbers. Port 80 is what
maps to HTTP/1.*, so every connection in both fixtures runs on port 80.
maps to HTTP, so every connection in both fixtures runs on port 80.

One absence is deliberate and worth flagging, because it looks like an
oversight and is not: neither fixture contains a datagram that reassembles
Expand All @@ -79,10 +80,10 @@
RST that submits the buffer.

``submit`` converts each hole's absolute bounds -- TCP sequence numbers,
``first=tcp_info.seq`` in ``pcapkit/toolkit/pcap.py`` -- into offsets into the
buffer it is reading, which is indexed from the start of the direction's data,
and decides completeness from that payload buffer's own gap list (GitHub issue
#349). Were it to slice with the absolute bounds instead, every slice would
``first=segment.seq`` in ``tcp_reassembly`` (``pcapkit/toolkit/pcap.py``) --
into offsets into the buffer it is reading, which is indexed from the start of
the direction's data, and decides completeness from that payload buffer's own
gap list (GitHub issue #349). Were it to slice with the absolute bounds instead, every slice would
start far beyond the end of the buffer for any real initial sequence number,
every fragment would come out empty, and ``if data:`` would discard the
datagram without a word, so no capture could reach the incomplete branch at
Expand Down
Loading
Loading