opskit 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.
Files changed (124) hide show
  1. {opskit-0.1.0 → opskit-0.1.1}/.github/workflows/ci.yml +11 -8
  2. {opskit-0.1.0 → opskit-0.1.1}/.github/workflows/codeql.yml +2 -2
  3. {opskit-0.1.0 → opskit-0.1.1}/.github/workflows/release.yml +2 -2
  4. {opskit-0.1.0 → opskit-0.1.1}/.github/workflows/scorecard.yml +1 -1
  5. {opskit-0.1.0 → opskit-0.1.1}/.github/workflows/snyk.yml +4 -4
  6. opskit-0.1.1/.release-please-manifest.json +3 -0
  7. {opskit-0.1.0 → opskit-0.1.1}/CHANGELOG.md +7 -0
  8. {opskit-0.1.0 → opskit-0.1.1}/CLAUDE.md +7 -0
  9. {opskit-0.1.0 → opskit-0.1.1}/PKG-INFO +4 -4
  10. {opskit-0.1.0 → opskit-0.1.1}/README.md +2 -2
  11. {opskit-0.1.0 → opskit-0.1.1}/pyproject.toml +1 -1
  12. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/__init__.py +1 -1
  13. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_net_tcp.py +15 -4
  14. {opskit-0.1.0 → opskit-0.1.1}/uv.lock +1 -1
  15. opskit-0.1.0/.release-please-manifest.json +0 -3
  16. {opskit-0.1.0 → opskit-0.1.1}/.claude/skills/speckit-analyze/SKILL.md +0 -0
  17. {opskit-0.1.0 → opskit-0.1.1}/.claude/skills/speckit-checklist/SKILL.md +0 -0
  18. {opskit-0.1.0 → opskit-0.1.1}/.claude/skills/speckit-clarify/SKILL.md +0 -0
  19. {opskit-0.1.0 → opskit-0.1.1}/.claude/skills/speckit-constitution/SKILL.md +0 -0
  20. {opskit-0.1.0 → opskit-0.1.1}/.claude/skills/speckit-converge/SKILL.md +0 -0
  21. {opskit-0.1.0 → opskit-0.1.1}/.claude/skills/speckit-implement/SKILL.md +0 -0
  22. {opskit-0.1.0 → opskit-0.1.1}/.claude/skills/speckit-plan/SKILL.md +0 -0
  23. {opskit-0.1.0 → opskit-0.1.1}/.claude/skills/speckit-specify/SKILL.md +0 -0
  24. {opskit-0.1.0 → opskit-0.1.1}/.claude/skills/speckit-tasks/SKILL.md +0 -0
  25. {opskit-0.1.0 → opskit-0.1.1}/.claude/skills/speckit-taskstoissues/SKILL.md +0 -0
  26. {opskit-0.1.0 → opskit-0.1.1}/.coderabbit.yaml +0 -0
  27. {opskit-0.1.0 → opskit-0.1.1}/.github/dependabot.yml +0 -0
  28. {opskit-0.1.0 → opskit-0.1.1}/.gitignore +0 -0
  29. {opskit-0.1.0 → opskit-0.1.1}/.pre-commit-config.yaml +0 -0
  30. {opskit-0.1.0 → opskit-0.1.1}/.specify/feature.json +0 -0
  31. {opskit-0.1.0 → opskit-0.1.1}/.specify/init-options.json +0 -0
  32. {opskit-0.1.0 → opskit-0.1.1}/.specify/integration.json +0 -0
  33. {opskit-0.1.0 → opskit-0.1.1}/.specify/integrations/claude.manifest.json +0 -0
  34. {opskit-0.1.0 → opskit-0.1.1}/.specify/integrations/speckit.manifest.json +0 -0
  35. {opskit-0.1.0 → opskit-0.1.1}/.specify/memory/constitution.md +0 -0
  36. {opskit-0.1.0 → opskit-0.1.1}/.specify/scripts/bash/check-prerequisites.sh +0 -0
  37. {opskit-0.1.0 → opskit-0.1.1}/.specify/scripts/bash/common.sh +0 -0
  38. {opskit-0.1.0 → opskit-0.1.1}/.specify/scripts/bash/create-new-feature.sh +0 -0
  39. {opskit-0.1.0 → opskit-0.1.1}/.specify/scripts/bash/setup-plan.sh +0 -0
  40. {opskit-0.1.0 → opskit-0.1.1}/.specify/scripts/bash/setup-tasks.sh +0 -0
  41. {opskit-0.1.0 → opskit-0.1.1}/.specify/templates/checklist-template.md +0 -0
  42. {opskit-0.1.0 → opskit-0.1.1}/.specify/templates/constitution-template.md +0 -0
  43. {opskit-0.1.0 → opskit-0.1.1}/.specify/templates/plan-template.md +0 -0
  44. {opskit-0.1.0 → opskit-0.1.1}/.specify/templates/spec-template.md +0 -0
  45. {opskit-0.1.0 → opskit-0.1.1}/.specify/templates/tasks-template.md +0 -0
  46. {opskit-0.1.0 → opskit-0.1.1}/.specify/workflows/speckit/workflow.yml +0 -0
  47. {opskit-0.1.0 → opskit-0.1.1}/.specify/workflows/workflow-registry.json +0 -0
  48. {opskit-0.1.0 → opskit-0.1.1}/LICENSE +0 -0
  49. {opskit-0.1.0 → opskit-0.1.1}/SECURITY.md +0 -0
  50. {opskit-0.1.0 → opskit-0.1.1}/docs/PLAN.md +0 -0
  51. {opskit-0.1.0 → opskit-0.1.1}/noxfile.py +0 -0
  52. {opskit-0.1.0 → opskit-0.1.1}/release-please-config.json +0 -0
  53. {opskit-0.1.0 → opskit-0.1.1}/sonar-project.properties +0 -0
  54. {opskit-0.1.0 → opskit-0.1.1}/specs/001-dns-diagnostics/checklists/requirements.md +0 -0
  55. {opskit-0.1.0 → opskit-0.1.1}/specs/001-dns-diagnostics/contracts/cli.md +0 -0
  56. {opskit-0.1.0 → opskit-0.1.1}/specs/001-dns-diagnostics/contracts/json-envelope.md +0 -0
  57. {opskit-0.1.0 → opskit-0.1.1}/specs/001-dns-diagnostics/contracts/python-api.md +0 -0
  58. {opskit-0.1.0 → opskit-0.1.1}/specs/001-dns-diagnostics/data-model.md +0 -0
  59. {opskit-0.1.0 → opskit-0.1.1}/specs/001-dns-diagnostics/plan.md +0 -0
  60. {opskit-0.1.0 → opskit-0.1.1}/specs/001-dns-diagnostics/quickstart.md +0 -0
  61. {opskit-0.1.0 → opskit-0.1.1}/specs/001-dns-diagnostics/research.md +0 -0
  62. {opskit-0.1.0 → opskit-0.1.1}/specs/001-dns-diagnostics/spec.md +0 -0
  63. {opskit-0.1.0 → opskit-0.1.1}/specs/001-dns-diagnostics/tasks.md +0 -0
  64. {opskit-0.1.0 → opskit-0.1.1}/specs/002-tls-verification/checklists/requirements.md +0 -0
  65. {opskit-0.1.0 → opskit-0.1.1}/specs/002-tls-verification/contracts/cli.md +0 -0
  66. {opskit-0.1.0 → opskit-0.1.1}/specs/002-tls-verification/contracts/python-api.md +0 -0
  67. {opskit-0.1.0 → opskit-0.1.1}/specs/002-tls-verification/data-model.md +0 -0
  68. {opskit-0.1.0 → opskit-0.1.1}/specs/002-tls-verification/plan.md +0 -0
  69. {opskit-0.1.0 → opskit-0.1.1}/specs/002-tls-verification/quickstart.md +0 -0
  70. {opskit-0.1.0 → opskit-0.1.1}/specs/002-tls-verification/research.md +0 -0
  71. {opskit-0.1.0 → opskit-0.1.1}/specs/002-tls-verification/spec.md +0 -0
  72. {opskit-0.1.0 → opskit-0.1.1}/specs/002-tls-verification/tasks.md +0 -0
  73. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/__main__.py +0 -0
  74. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/cli.py +0 -0
  75. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/core/__init__.py +0 -0
  76. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/core/cliutils.py +0 -0
  77. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/core/errors.py +0 -0
  78. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/core/exit_codes.py +0 -0
  79. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/core/output.py +0 -0
  80. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/core/result.py +0 -0
  81. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/dns/README.md +0 -0
  82. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/dns/__init__.py +0 -0
  83. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/dns/api.py +0 -0
  84. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/dns/cli.py +0 -0
  85. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/dns/errors.py +0 -0
  86. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/dns/models.py +0 -0
  87. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/dns/output.py +0 -0
  88. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/dns/resolver.py +0 -0
  89. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/net/__init__.py +0 -0
  90. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/net/errors.py +0 -0
  91. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/net/tcp.py +0 -0
  92. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/py.typed +0 -0
  93. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/tls/README.md +0 -0
  94. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/tls/__init__.py +0 -0
  95. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/tls/api.py +0 -0
  96. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/tls/cli.py +0 -0
  97. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/tls/errors.py +0 -0
  98. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/tls/handshake.py +0 -0
  99. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/tls/inspect.py +0 -0
  100. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/tls/models.py +0 -0
  101. {opskit-0.1.0 → opskit-0.1.1}/src/opskit/tls/output.py +0 -0
  102. {opskit-0.1.0 → opskit-0.1.1}/tests/conftest.py +0 -0
  103. {opskit-0.1.0 → opskit-0.1.1}/tests/contract/test_json_envelope.py +0 -0
  104. {opskit-0.1.0 → opskit-0.1.1}/tests/integration/__init__.py +0 -0
  105. {opskit-0.1.0 → opskit-0.1.1}/tests/integration/conftest.py +0 -0
  106. {opskit-0.1.0 → opskit-0.1.1}/tests/integration/test_tls_loopback.py +0 -0
  107. {opskit-0.1.0 → opskit-0.1.1}/tests/integration/test_tls_network.py +0 -0
  108. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_batch.py +0 -0
  109. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_cli_lookup.py +0 -0
  110. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_dns_compare.py +0 -0
  111. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_dns_lookup.py +0 -0
  112. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_dns_lookup_all.py +0 -0
  113. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_dns_reverse.py +0 -0
  114. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_output.py +0 -0
  115. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_resolver.py +0 -0
  116. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_smoke.py +0 -0
  117. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_tls_api.py +0 -0
  118. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_tls_cli.py +0 -0
  119. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_tls_inspect.py +0 -0
  120. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_tls_match.py +0 -0
  121. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_tls_output.py +0 -0
  122. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_tls_target.py +0 -0
  123. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_trace.py +0 -0
  124. {opskit-0.1.0 → opskit-0.1.1}/tests/unit/test_watch.py +0 -0
@@ -20,11 +20,11 @@ jobs:
20
20
  name: Lint & type-check
21
21
  runs-on: ubuntu-latest
22
22
  steps:
23
- - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2
23
+ - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2
24
24
  with:
25
25
  egress-policy: audit
26
26
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
27
- - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
27
+ - uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1
28
28
  with:
29
29
  enable-cache: true
30
30
  - run: uv sync --extra dev
@@ -45,9 +45,12 @@ jobs:
45
45
  steps:
46
46
  - id: set
47
47
  shell: bash
48
+ # PRs test all three OSes on the min+max Python (catches OS-specific bugs pre-merge —
49
+ # socket/TLS/filesystem behavior differs on Windows/macOS and is invisible on ubuntu).
50
+ # main additionally sweeps every Python version.
48
51
  run: |
49
52
  if [ "${{ github.event_name }}" = "pull_request" ]; then
50
- echo 'matrix={"os":["ubuntu-latest"],"python":["3.9","3.13"]}' >> "$GITHUB_OUTPUT"
53
+ echo 'matrix={"os":["ubuntu-latest","macos-latest","windows-latest"],"python":["3.9","3.13"]}' >> "$GITHUB_OUTPUT"
51
54
  else
52
55
  echo 'matrix={"os":["ubuntu-latest","macos-latest","windows-latest"],"python":["3.9","3.10","3.11","3.12","3.13"]}' >> "$GITHUB_OUTPUT"
53
56
  fi
@@ -60,11 +63,11 @@ jobs:
60
63
  matrix: ${{ fromJSON(needs.matrix-setup.outputs.matrix) }}
61
64
  runs-on: ${{ matrix.os }}
62
65
  steps:
63
- - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2
66
+ - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2
64
67
  with:
65
68
  egress-policy: audit
66
69
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
67
- - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
70
+ - uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1
68
71
  with:
69
72
  enable-cache: true
70
73
  python-version: ${{ matrix.python }}
@@ -76,11 +79,11 @@ jobs:
76
79
  name: Dependency audit
77
80
  runs-on: ubuntu-latest
78
81
  steps:
79
- - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2
82
+ - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2
80
83
  with:
81
84
  egress-policy: audit
82
85
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
83
- - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
86
+ - uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1
84
87
  with:
85
88
  enable-cache: true
86
89
  - run: uv sync --extra dev
@@ -97,7 +100,7 @@ jobs:
97
100
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
98
101
  with:
99
102
  fetch-depth: 0
100
- - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
103
+ - uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1
101
104
  with:
102
105
  enable-cache: true
103
106
  - run: uv sync --extra dev
@@ -19,8 +19,8 @@ jobs:
19
19
  security-events: write
20
20
  steps:
21
21
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
22
- - uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4
22
+ - uses: github/codeql-action/init@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4
23
23
  with:
24
24
  languages: python
25
25
  queries: security-extended
26
- - uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4
26
+ - uses: github/codeql-action/analyze@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4
@@ -43,11 +43,11 @@ jobs:
43
43
  permissions:
44
44
  id-token: write # OIDC for PyPI Trusted Publishing
45
45
  steps:
46
- - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2
46
+ - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2
47
47
  with:
48
48
  egress-policy: audit
49
49
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
50
- - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
50
+ - uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1
51
51
  - run: uv sync --extra dev
52
52
  - name: Final security re-scan (zero-day gate)
53
53
  run: uv run pip-audit
@@ -30,6 +30,6 @@ jobs:
30
30
  results_file: results.sarif
31
31
  results_format: sarif
32
32
  publish_results: true
33
- - uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4
33
+ - uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4
34
34
  with:
35
35
  sarif_file: results.sarif
@@ -25,14 +25,14 @@ jobs:
25
25
  env:
26
26
  SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
27
27
  steps:
28
- - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2
28
+ - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2
29
29
  with:
30
30
  egress-policy: audit
31
31
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
32
32
  - name: Notice when unconfigured
33
33
  if: ${{ env.SNYK_TOKEN == '' }}
34
34
  run: echo "SNYK_TOKEN is not set — skipping Snyk. Add the repo secret to enable."
35
- - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
35
+ - uses: astral-sh/setup-uv@f98e06938123ccabd21905ea5d0069192241f9f1 # v8.3.1
36
36
  if: ${{ env.SNYK_TOKEN != '' }}
37
37
  - name: Install Snyk CLI
38
38
  if: ${{ env.SNYK_TOKEN != '' }}
@@ -55,13 +55,13 @@ jobs:
55
55
  run: snyk code test --severity-threshold=high --sarif-file-output=snyk-code.sarif
56
56
  - name: Upload Open Source SARIF
57
57
  if: ${{ env.SNYK_TOKEN != '' && hashFiles('snyk-oss.sarif') != '' }}
58
- uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4
58
+ uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4
59
59
  with:
60
60
  sarif_file: snyk-oss.sarif
61
61
  category: snyk-oss
62
62
  - name: Upload Snyk Code SARIF
63
63
  if: ${{ env.SNYK_TOKEN != '' && hashFiles('snyk-code.sarif') != '' }}
64
- uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4
64
+ uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4
65
65
  with:
66
66
  sarif_file: snyk-code.sarif
67
67
  category: snyk-code
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.1.1"
3
+ }
@@ -5,6 +5,13 @@ All notable changes to opskit are documented in this file. The format is based o
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Releases and this changelog are
6
6
  generated automatically by release-please from Conventional Commits.
7
7
 
8
+ ## [0.1.1](https://github.com/Prabhakar-cg/opskit/compare/opskit-v0.1.0...opskit-v0.1.1) (2026-07-08)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **ci:** cross-platform closed-port test; fix README badges ([#23](https://github.com/Prabhakar-cg/opskit/issues/23)) ([6736872](https://github.com/Prabhakar-cg/opskit/commit/673687205e0f6c205023951e998a76a6ac98c73c))
14
+
8
15
  ## 0.1.0 (2026-07-07)
9
16
 
10
17
 
@@ -91,6 +91,13 @@ Apply these from the start of every new category (`net`/`tls`/`ad`); each one co
91
91
  - **Test gotcha (CodeQL):** don't assert `"<host.tld>" in output` — CodeQL's
92
92
  `py/incomplete-url-substring-sanitization` flags it as a URL-host check. Assert on record
93
93
  values / IPs / non-hostname substrings instead.
94
+ - **A green PR is not a green `main`.** CI runs all three OSes on PRs but only the min+max Python;
95
+ `main` sweeps every Python version. **Socket / TLS / filesystem / path / subprocess behavior
96
+ differs across OSes** (e.g. a closed loopback port *refuses* on Linux but *times out* on Windows;
97
+ trust stores, IPv6, and path separators differ) — write those tests to tolerate platform variance
98
+ (assert the typed error *class family*, not one exact subclass) and lean on the loopback/mock
99
+ layers. If a `main`-only matrix leg fails after merge, reproduce by widening the PR matrix, not by
100
+ guessing. The `net`/`tls` refused-vs-timeout classification is the canonical example.
94
101
 
95
102
  ## Testing
96
103
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opskit
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Cross-platform diagnostics for engineers — one toolkit, every OS.
5
5
  Project-URL: Homepage, https://github.com/Prabhakar-cg/opskit
6
6
  Project-URL: Repository, https://github.com/Prabhakar-cg/opskit
@@ -25,7 +25,7 @@ Classifier: Topic :: System :: Networking
25
25
  Classifier: Topic :: Utilities
26
26
  Classifier: Typing :: Typed
27
27
  Requires-Python: >=3.9.2
28
- Requires-Dist: cryptography<49,>=48.0.1
28
+ Requires-Dist: cryptography<50,>=48.0.1
29
29
  Requires-Dist: dnspython<3,>=2.6
30
30
  Requires-Dist: platformdirs<5,>=4
31
31
  Requires-Dist: pyopenssl<27,>=24
@@ -55,7 +55,7 @@ Cross-platform diagnostics for engineers — one toolkit, every OS.
55
55
  [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/13462/badge)](https://www.bestpractices.dev/projects/13462)
56
56
  [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Prabhakar-cg_opskit&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Prabhakar-cg_opskit)
57
57
  [![Known Vulnerabilities](https://snyk.io/test/github/Prabhakar-cg/opskit/badge.svg)](https://snyk.io/test/github/Prabhakar-cg/opskit)
58
- ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/Prabhakar-cg/opskit?utm_source=oss&utm_medium=github&utm_campaign=Prabhakar-cg%2Fopskit&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)
58
+ [![Reviewed by CodeRabbit](https://img.shields.io/badge/reviewed%20by-CodeRabbit-FF570A?labelColor=171717)](https://coderabbit.ai)
59
59
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
60
60
  [![Python](https://img.shields.io/badge/python-3.9%20|%203.10%20|%203.11%20|%203.12%20|%203.13-blue)](pyproject.toml)
61
61
 
@@ -64,7 +64,7 @@ troubleshooting commands that behave **identically on Windows, macOS, and Linux*
64
64
  juggling `nslookup` vs `dig` vs PowerShell cmdlets. It's a **CLI *and* an importable Python
65
65
  library**, is pure-Python (nothing to shell out to), and never phones home.
66
66
 
67
- > ⚠️ **Early development.** v1 ships **DNS diagnostics**; network / TLS / AD categories follow.
67
+ > ⚠️ **Early development.** Ships **DNS** and **TLS** diagnostics today; network / AD categories follow.
68
68
 
69
69
  ---
70
70
 
@@ -8,7 +8,7 @@ Cross-platform diagnostics for engineers — one toolkit, every OS.
8
8
  [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/13462/badge)](https://www.bestpractices.dev/projects/13462)
9
9
  [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Prabhakar-cg_opskit&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Prabhakar-cg_opskit)
10
10
  [![Known Vulnerabilities](https://snyk.io/test/github/Prabhakar-cg/opskit/badge.svg)](https://snyk.io/test/github/Prabhakar-cg/opskit)
11
- ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/Prabhakar-cg/opskit?utm_source=oss&utm_medium=github&utm_campaign=Prabhakar-cg%2Fopskit&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)
11
+ [![Reviewed by CodeRabbit](https://img.shields.io/badge/reviewed%20by-CodeRabbit-FF570A?labelColor=171717)](https://coderabbit.ai)
12
12
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
13
13
  [![Python](https://img.shields.io/badge/python-3.9%20|%203.10%20|%203.11%20|%203.12%20|%203.13-blue)](pyproject.toml)
14
14
 
@@ -17,7 +17,7 @@ troubleshooting commands that behave **identically on Windows, macOS, and Linux*
17
17
  juggling `nslookup` vs `dig` vs PowerShell cmdlets. It's a **CLI *and* an importable Python
18
18
  library**, is pure-Python (nothing to shell out to), and never phones home.
19
19
 
20
- > ⚠️ **Early development.** v1 ships **DNS diagnostics**; network / TLS / AD categories follow.
20
+ > ⚠️ **Early development.** Ships **DNS** and **TLS** diagnostics today; network / AD categories follow.
21
21
 
22
22
  ---
23
23
 
@@ -36,7 +36,7 @@ dependencies = [
36
36
  "tomli>=2 ; python_version < '3.11'",
37
37
  # TLS category: handshake/chain retrieval + certificate parsing (PyCA-maintained).
38
38
  "pyopenssl>=24,<27",
39
- "cryptography>=48.0.1,<49", # 48.0.1 fixes GHSA-537c-gmf6-5ccf
39
+ "cryptography>=48.0.1,<50", # 48.0.1 fixes GHSA-537c-gmf6-5ccf
40
40
  ]
41
41
 
42
42
  [project.urls]
@@ -8,7 +8,7 @@ from __future__ import annotations
8
8
 
9
9
  import logging
10
10
 
11
- __version__ = "0.1.0" # x-release-please-version
11
+ __version__ = "0.1.1" # x-release-please-version
12
12
 
13
13
  __all__ = ["__version__"]
14
14
 
@@ -47,11 +47,22 @@ def test_connect_success_reports_address_and_timing():
47
47
  server.close()
48
48
 
49
49
 
50
+ def _closed_port() -> int:
51
+ """A loopback port that is closed (bound then released, never listened)."""
52
+ probe = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
53
+ probe.bind(("127.0.0.1", 0))
54
+ port = int(probe.getsockname()[1])
55
+ probe.close()
56
+ return port
57
+
58
+
50
59
  def test_connect_refused_on_closed_port():
51
- server, port = _loopback_listener()
52
- server.close() # port now closed -> RST on connect
53
- with pytest.raises(ConnectRefused) as excinfo:
54
- connect("127.0.0.1", port, timeout=2.0)
60
+ # A closed loopback port refuses on Linux/macOS. Windows refuses a never-listened port
61
+ # (this pattern) but may *time out* on a port that was listen()ed then closed so accept
62
+ # either "cannot connect" NetError. The precise refused mapping is asserted deterministically
63
+ # in test_refusal_wins_over_timeout_for_dual_stack.
64
+ with pytest.raises((ConnectRefused, ConnectTimeout)) as excinfo:
65
+ connect("127.0.0.1", _closed_port(), timeout=1.0, retries=0)
55
66
  assert excinfo.value.hint
56
67
 
57
68
 
@@ -1257,7 +1257,7 @@ dev = [
1257
1257
 
1258
1258
  [package.metadata]
1259
1259
  requires-dist = [
1260
- { name = "cryptography", specifier = ">=48.0.1,<49" },
1260
+ { name = "cryptography", specifier = ">=48.0.1,<50" },
1261
1261
  { name = "dnslib", marker = "extra == 'dev'", specifier = ">=0.9" },
1262
1262
  { name = "dnspython", specifier = ">=2.6,<3" },
1263
1263
  { name = "hypothesis", marker = "extra == 'dev'", specifier = ">=6" },
@@ -1,3 +0,0 @@
1
- {
2
- ".": "0.1.0"
3
- }
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