Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
e03e710
chore: add dev tooling, CI workflow, and project configuration
tboy1337 Mar 13, 2026
ece2dfd
chore: update project configuration and dependencies
tboy1337 Mar 13, 2026
cf82cc3
chore: simplify development dependencies in requirements-dev.txt
tboy1337 Mar 13, 2026
1b74b6b
chore: merge upstream/main, resolve .gitignore conflict
tboy1337 Mar 13, 2026
cfea62f
chore: remove formatting and type checking steps from CI workflow
tboy1337 Mar 13, 2026
14c2559
chore: remove autopep8 from development dependencies in requirements-…
tboy1337 Mar 13, 2026
5c0e7fe
Add comprehensive test suite and fix async/coverage issues
tboy1337 Mar 13, 2026
7d5bdf8
Merge remote-tracking branch 'upstream/main' into chore/dev-tooling-a…
tboy1337 Mar 13, 2026
f00c8ed
Fix tests after upstream merge: update assertions for changed API and…
tboy1337 Mar 13, 2026
5a222ec
test: add comprehensive test suite for all dns_utils modules
tboy1337 Mar 14, 2026
55fa5cb
fix: update tests to match upstream source changes
tboy1337 Mar 14, 2026
25e72cb
chore: merge upstream/main into dev-tooling-and-ci, fix conflicts and…
tboy1337 Mar 17, 2026
e185cff
chore: merge upstream/main into tests, fix BOM, struct.debug typo, an…
tboy1337 Mar 17, 2026
7cba0d1
chore: remove test files from dev-tooling branch (belong in PR #41 te…
tboy1337 Mar 17, 2026
7c093d6
refactor: simplify exception handling in ARQ and DnsPacketParser, upd…
tboy1337 Mar 17, 2026
bb57c5c
fix: correct typo in exception handling for DnsPacketParser
tboy1337 Mar 17, 2026
1d907cf
revert: restore client.py to match upstream main (re-add BOM)
tboy1337 Mar 17, 2026
6c96613
chore: merge dev-tooling-and-ci and tests branches into combined branch
tboy1337 Mar 17, 2026
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
16 changes: 16 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[run]
source = dns_utils
omit =
build_setup.py
tests/*
branch = true

[report]
fail_under = 90
show_missing = true
exclude_lines =
pragma: no cover
def __repr__
raise NotImplementedError
if __name__ == .__main__.:
pass$
46 changes: 46 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Tests

on:
push:
branches: ["**"]
pull_request:
branches: ["**"]

jobs:
test:
name: Test Python ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: "pip"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt

- name: Run tests with coverage
run: |
python -m pytest tests/ \
--cov=dns_utils \
--cov-report=term-missing \
--cov-report=xml \
--cov-fail-under=90 \
-v

- name: Upload coverage report
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-${{ matrix.python-version }}
path: coverage.xml
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ logs/
*.tmp
*.exe
build/
.hypothesis/
.coverage
55 changes: 55 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
[MAIN]
jobs = 0
py-version = 3.10

[MESSAGES CONTROL]
disable =
line-too-long,
missing-module-docstring,
missing-class-docstring,
missing-function-docstring,
too-many-arguments,
too-many-instance-attributes,
too-many-locals,
too-few-public-methods,
too-many-branches,
too-many-return-statements,
too-many-statements,
too-many-lines,
too-many-nested-blocks,
too-many-public-methods,
too-many-positional-arguments,
fixme,
redefined-outer-name,
attribute-defined-outside-init,
deprecated-class,
consider-using-sys-exit,
unnecessary-lambda,
no-else-return,
raise-missing-from,
try-except-raise,
condition-evals-to-constant,
use-implicit-booleaness-not-comparison,
chained-comparison,
pointless-string-statement,
simplifiable-if-expression,
consider-using-min-builtin,
consider-using-f-string,
unnecessary-pass,
unreachable,
unused-argument,
unused-variable,
unused-import,
reimported,
superfluous-parens

[FORMAT]
max-line-length = 100

[BASIC]
good-names = i,j,k,n,e,f,p,q,r,s,t,fd,cb,sn,ok,hb,an,ns,ar,qd

[DESIGN]
max-args = 20
max-attributes = 30
max-bool-expr = 10
10 changes: 5 additions & 5 deletions dns_utils/DnsPacketParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,9 @@ def __init__(
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

self._aesgcm = AESGCM(self.key)
except ImportError:
if self.logger:
self.logger.debug("AES-GCM missing.")
except ImportError: # pragma: no cover
if self.logger: # pragma: no cover
self.logger.debug("AES-GCM missing.") # pragma: no cover

elif self.encryption_method == 2:
try:
Expand All @@ -209,8 +209,8 @@ def __init__(
self._Cipher = Cipher
self._default_backend = default_backend
self._chacha_algo = algorithms.ChaCha20
except ImportError:
pass
except ImportError: # pragma: no cover
pass # pragma: no cover

self._setup_crypto_dispatch()
self._alphabet_cache = {}
Expand Down
8 changes: 4 additions & 4 deletions dns_utils/compression.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
import zstandard as zstd

ZSTD_AVAILABLE = True
except ImportError:
ZSTD_AVAILABLE = False
except ImportError: # pragma: no cover
ZSTD_AVAILABLE = False # pragma: no cover

try:
import lz4.block as lz4block

LZ4_AVAILABLE = True
except ImportError:
LZ4_AVAILABLE = False
except ImportError: # pragma: no cover
LZ4_AVAILABLE = False # pragma: no cover


class Compression_Type:
Expand Down
4 changes: 2 additions & 2 deletions dns_utils/config_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

try:
import tomllib
except ImportError:
except ImportError: # pragma: no cover
try:
import tomli as tomllib # type: ignore[no-redef]
import tomli as tomllib # type: ignore[no-redef,import-not-found]
except ImportError:
raise ImportError(
"TOML support requires Python 3.11+ or the 'tomli' package. "
Expand Down
94 changes: 94 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
[mypy]
python_version = 3.10
strict = true
disallow_any_generics = true
disallow_any_unimported = true
disallow_any_expr = true
disallow_any_explicit = true
disallow_any_decorated = true
no_implicit_reexport = true
warn_return_any = true
warn_unreachable = true
show_error_codes = true

[mypy-loguru.*]
ignore_missing_imports = true

[mypy-cryptography.*]
ignore_missing_imports = true

[mypy-zstandard.*]
ignore_missing_imports = true

[mypy-lz4.*]
ignore_missing_imports = true

[mypy-uvloop.*]
ignore_missing_imports = true

[mypy-tomli.*]
ignore_missing_imports = true

[mypy-tomllib.*]
ignore_missing_imports = true

# Existing source modules not written with strict typing - relax to avoid
# false-positive noise on inherited code. Full annotation is a separate effort.
[mypy-dns_utils]
# Dynamic attribute injection via _try_export cannot be typed without rewriting
ignore_errors = true

[mypy-dns_utils.ARQ]
# Complex async state machine with untyped internal state; full annotation is a separate effort
ignore_errors = true

[mypy-dns_utils.compression]
ignore_errors = true

[mypy-dns_utils.config_loader]
disallow_any_expr = false
disallow_any_explicit = false
warn_return_any = false
disallow_untyped_defs = false
disallow_incomplete_defs = false

[mypy-dns_utils.DNSBalancer]
ignore_errors = true

[mypy-dns_utils.DnsPacketParser]
# Large parser with untyped dict-based packet representation; full annotation is a separate effort
ignore_errors = true

[mypy-dns_utils.DNS_ENUMS]
disallow_any_expr = false
disallow_untyped_defs = false

[mypy-dns_utils.PacketQueueMixin]
ignore_errors = true

[mypy-dns_utils.PingManager]
disallow_any_expr = false
disallow_untyped_defs = false
disallow_incomplete_defs = false

[mypy-dns_utils.PrependReader]
disallow_any_expr = false
disallow_untyped_defs = false

[mypy-dns_utils.utils]
# Complex async network utils with untyped socket/loop APIs
ignore_errors = true

[mypy-client]
# Large application module (3000+ lines) without type annotations; annotation is a separate effort
ignore_errors = true

[mypy-server]
# Large application module (2000+ lines) without type annotations; annotation is a separate effort
ignore_errors = true

# Tests use dynamic mocking, @patch decorators, and untyped fixtures that cannot
# be fully typed without significant overhead; suppress all mypy errors for the
# test suite rather than maintaining a long per-error-code allowlist.
[mypy-tests.*]
ignore_errors = true
17 changes: 17 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"

[project]
name = "masterdnsvpn"
version = "1.0.0"
description = "DNS tunneling VPN that encapsulates TCP traffic in DNS queries to bypass censorship"
requires-python = ">=3.10"

[tool.black]
line-length = 100
target-version = ["py310"]

[tool.isort]
profile = "black"
line_length = 100
5 changes: 5 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[pytest]
testpaths = tests
asyncio_mode = auto
timeout = 30
addopts = -v
13 changes: 13 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-r requirements.txt

pytest
pytest-asyncio
pytest-timeout
pytest-xdist
pytest-mock
pytest-cov
hypothesis
black
isort
mypy
pylint
5 changes: 2 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
loguru
cryptography
tomli; python_version < "3.11"
uvloop; sys_platform != "win32"
cryptography>=41.0.0
tomli; python_version < "3.11"
zstandard>=0.22.0
lz4>=4.3.2
uvloop; sys_platform != "win32"
Empty file added tests/__init__.py
Empty file.
Loading
Loading