sentineldeck 0.1.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.
Files changed (62) hide show
  1. sentineldeck-0.1.0/LICENSE +21 -0
  2. sentineldeck-0.1.0/PKG-INFO +356 -0
  3. sentineldeck-0.1.0/README.md +323 -0
  4. sentineldeck-0.1.0/pyproject.toml +73 -0
  5. sentineldeck-0.1.0/setup.cfg +4 -0
  6. sentineldeck-0.1.0/src/sentineldeck/__init__.py +3 -0
  7. sentineldeck-0.1.0/src/sentineldeck/alerts.py +72 -0
  8. sentineldeck-0.1.0/src/sentineldeck/cli.py +217 -0
  9. sentineldeck-0.1.0/src/sentineldeck/diff.py +156 -0
  10. sentineldeck-0.1.0/src/sentineldeck/models.py +59 -0
  11. sentineldeck-0.1.0/src/sentineldeck/monitor.py +52 -0
  12. sentineldeck-0.1.0/src/sentineldeck/py.typed +0 -0
  13. sentineldeck-0.1.0/src/sentineldeck/remediation.py +278 -0
  14. sentineldeck-0.1.0/src/sentineldeck/reporters/__init__.py +1 -0
  15. sentineldeck-0.1.0/src/sentineldeck/reporters/badge.py +126 -0
  16. sentineldeck-0.1.0/src/sentineldeck/reporters/diff_report.py +168 -0
  17. sentineldeck-0.1.0/src/sentineldeck/reporters/html_report.py +383 -0
  18. sentineldeck-0.1.0/src/sentineldeck/reporters/json_report.py +24 -0
  19. sentineldeck-0.1.0/src/sentineldeck/risk/__init__.py +1 -0
  20. sentineldeck-0.1.0/src/sentineldeck/risk/scoring.py +546 -0
  21. sentineldeck-0.1.0/src/sentineldeck/scanner.py +87 -0
  22. sentineldeck-0.1.0/src/sentineldeck/scanners/__init__.py +1 -0
  23. sentineldeck-0.1.0/src/sentineldeck/scanners/dns_hygiene.py +24 -0
  24. sentineldeck-0.1.0/src/sentineldeck/scanners/dns_lookup.py +255 -0
  25. sentineldeck-0.1.0/src/sentineldeck/scanners/domain.py +27 -0
  26. sentineldeck-0.1.0/src/sentineldeck/scanners/domain_intel.py +69 -0
  27. sentineldeck-0.1.0/src/sentineldeck/scanners/email_security.py +117 -0
  28. sentineldeck-0.1.0/src/sentineldeck/scanners/http_headers.py +179 -0
  29. sentineldeck-0.1.0/src/sentineldeck/scanners/subdomains.py +102 -0
  30. sentineldeck-0.1.0/src/sentineldeck/scanners/takeover.py +104 -0
  31. sentineldeck-0.1.0/src/sentineldeck/scanners/tls.py +166 -0
  32. sentineldeck-0.1.0/src/sentineldeck/suppressions.py +36 -0
  33. sentineldeck-0.1.0/src/sentineldeck.egg-info/PKG-INFO +356 -0
  34. sentineldeck-0.1.0/src/sentineldeck.egg-info/SOURCES.txt +60 -0
  35. sentineldeck-0.1.0/src/sentineldeck.egg-info/dependency_links.txt +1 -0
  36. sentineldeck-0.1.0/src/sentineldeck.egg-info/entry_points.txt +2 -0
  37. sentineldeck-0.1.0/src/sentineldeck.egg-info/requires.txt +6 -0
  38. sentineldeck-0.1.0/src/sentineldeck.egg-info/top_level.txt +1 -0
  39. sentineldeck-0.1.0/tests/test_alerts.py +58 -0
  40. sentineldeck-0.1.0/tests/test_badge.py +63 -0
  41. sentineldeck-0.1.0/tests/test_cli.py +7 -0
  42. sentineldeck-0.1.0/tests/test_cli_diff.py +61 -0
  43. sentineldeck-0.1.0/tests/test_cli_monitor.py +57 -0
  44. sentineldeck-0.1.0/tests/test_cli_report.py +59 -0
  45. sentineldeck-0.1.0/tests/test_cli_scan.py +57 -0
  46. sentineldeck-0.1.0/tests/test_diff.py +189 -0
  47. sentineldeck-0.1.0/tests/test_dns_hygiene.py +33 -0
  48. sentineldeck-0.1.0/tests/test_dns_lookup.py +157 -0
  49. sentineldeck-0.1.0/tests/test_domain.py +12 -0
  50. sentineldeck-0.1.0/tests/test_domain_intel.py +52 -0
  51. sentineldeck-0.1.0/tests/test_email_security.py +142 -0
  52. sentineldeck-0.1.0/tests/test_html_report.py +106 -0
  53. sentineldeck-0.1.0/tests/test_http_headers.py +65 -0
  54. sentineldeck-0.1.0/tests/test_json_report.py +37 -0
  55. sentineldeck-0.1.0/tests/test_monitor.py +55 -0
  56. sentineldeck-0.1.0/tests/test_remediation.py +106 -0
  57. sentineldeck-0.1.0/tests/test_scanner.py +31 -0
  58. sentineldeck-0.1.0/tests/test_scoring.py +128 -0
  59. sentineldeck-0.1.0/tests/test_subdomains.py +90 -0
  60. sentineldeck-0.1.0/tests/test_suppressions.py +68 -0
  61. sentineldeck-0.1.0/tests/test_takeover.py +110 -0
  62. sentineldeck-0.1.0/tests/test_tls.py +88 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 sanmaxdev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,356 @@
1
+ Metadata-Version: 2.4
2
+ Name: sentineldeck
3
+ Version: 0.1.0
4
+ Summary: Passive attack-surface visibility and client-ready security reports for small businesses.
5
+ Author: sanmaxdev
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/sanmaxdev/SentinelDeck
8
+ Project-URL: Repository, https://github.com/sanmaxdev/SentinelDeck
9
+ Project-URL: Issues, https://github.com/sanmaxdev/SentinelDeck/issues
10
+ Project-URL: Changelog, https://github.com/sanmaxdev/SentinelDeck/blob/main/CHANGELOG.md
11
+ Keywords: security,attack-surface,osint,headers,ssl,sme
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Information Technology
15
+ Classifier: Intended Audience :: System Administrators
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Security
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: dnspython>=2.0
28
+ Requires-Dist: cryptography>=41.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7; extra == "dev"
31
+ Requires-Dist: ruff>=0.4; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ <div align="center">
35
+
36
+ <img src="assets/banner.svg" alt="SentinelDeck" width="820">
37
+
38
+ <p>
39
+ <strong>Passive attack-surface radar for small businesses, agencies, and security consultants.</strong><br>
40
+ One safe scan turns a domain into a clear risk grade, structured JSON, and a client-ready report.
41
+ </p>
42
+
43
+ </div>
44
+
45
+ <table>
46
+ <tr>
47
+ <td><b>Testing</b></td>
48
+ <td>
49
+ <a href="https://github.com/sanmaxdev/SentinelDeck/actions/workflows/ci.yml"><img alt="tests" src="https://img.shields.io/github/actions/workflow/status/sanmaxdev/SentinelDeck/ci.yml?style=flat-square&labelColor=0a0a0f&color=dc2626&label=tests"></a>
50
+ </td>
51
+ </tr>
52
+ <tr>
53
+ <td><b>Code quality</b></td>
54
+ <td>
55
+ <a href="https://github.com/sanmaxdev/SentinelDeck/actions/workflows/security.yml"><img alt="security" src="https://img.shields.io/github/actions/workflow/status/sanmaxdev/SentinelDeck/security.yml?style=flat-square&labelColor=0a0a0f&color=dc2626&label=security"></a>
56
+ <a href="https://github.com/sanmaxdev/SentinelDeck/blob/main/.pre-commit-config.yaml"><img alt="pre-commit" src="https://img.shields.io/badge/pre--commit-enabled-dc2626?style=flat-square&labelColor=0a0a0f&logo=pre-commit&logoColor=white"></a>
57
+ </td>
58
+ </tr>
59
+ <tr>
60
+ <td><b>Code style</b></td>
61
+ <td>
62
+ <a href="https://github.com/astral-sh/ruff"><img alt="ruff" src="https://img.shields.io/badge/code%20style-ruff-dc2626?style=flat-square&labelColor=0a0a0f"></a>
63
+ <img alt="typed" src="https://img.shields.io/badge/typed-PEP%20561-dc2626?style=flat-square&labelColor=0a0a0f">
64
+ </td>
65
+ </tr>
66
+ <tr>
67
+ <td><b>Package</b></td>
68
+ <td>
69
+ <a href="https://pypi.org/project/sentineldeck/"><img alt="pypi" src="https://img.shields.io/pypi/v/sentineldeck?style=flat-square&labelColor=0a0a0f&color=dc2626&label=pypi"></a>
70
+ <img alt="downloads" src="https://img.shields.io/pypi/dm/sentineldeck?style=flat-square&labelColor=0a0a0f&color=dc2626&label=downloads">
71
+ <img alt="status" src="https://img.shields.io/badge/status-alpha-dc2626?style=flat-square&labelColor=0a0a0f">
72
+ <img alt="python" src="https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-dc2626?style=flat-square&labelColor=0a0a0f">
73
+ <a href="LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-dc2626?style=flat-square&labelColor=0a0a0f"></a>
74
+ </td>
75
+ </tr>
76
+ <tr>
77
+ <td><b>Safety</b></td>
78
+ <td>
79
+ <img alt="passive" src="https://img.shields.io/badge/scans-passive%20only-dc2626?style=flat-square&labelColor=0a0a0f">
80
+ <a href="SECURITY.md"><img alt="security policy" src="https://img.shields.io/badge/security-policy-dc2626?style=flat-square&labelColor=0a0a0f"></a>
81
+ </td>
82
+ </tr>
83
+ </table>
84
+
85
+ SentinelDeck inspects the public-facing posture of a domain across DNS, HTTP,
86
+ TLS, email authentication, and its certificate-transparency footprint, using
87
+ only the kind of normal lookups any browser or mail server would make. There is
88
+ no intrusive scanning, no exploitation, and nothing a domain owner would not
89
+ expect. The result is a risk score, an A to F grade, and a set of prioritised
90
+ findings, each with a concrete copy-paste fix.
91
+
92
+ It is built for the people who need that picture fast: an agency qualifying a
93
+ prospect, a consultant producing a client report, or a small team checking its
94
+ own footprint.
95
+
96
+ ## Contents
97
+
98
+ - [Features](#features)
99
+ - [What it checks](#what-it-checks)
100
+ - [Installation](#installation)
101
+ - [Usage](#usage)
102
+ - [Example output](#example-output)
103
+ - [How it works](#how-it-works)
104
+ - [Development](#development)
105
+ - [Safety model](#safety-model)
106
+ - [Support](#support)
107
+ - [License](#license)
108
+
109
+ ## Features
110
+
111
+ <table>
112
+ <tr>
113
+ <td width="50%" valign="top">
114
+ <h3>Passive and safe by design</h3>
115
+ Only standard DNS, HTTP, TLS, and email lookups, the same requests any
116
+ browser or mail server makes. Run it against any domain you are authorised
117
+ to assess.
118
+ </td>
119
+ <td width="50%" valign="top">
120
+ <h3>Accurate, with a confidence model</h3>
121
+ DNS is resolved in-process and certificates are parsed directly. Any check
122
+ that cannot be confirmed is marked unverified and kept out of the score, so
123
+ a client never sees a guess presented as fact.
124
+ </td>
125
+ </tr>
126
+ <tr>
127
+ <td width="50%" valign="top">
128
+ <h3>Five surfaces in one pass</h3>
129
+ DNS hygiene, HTTP security headers, TLS certificate quality, email
130
+ authentication, and domain registration intelligence, scored together into
131
+ a single picture.
132
+ </td>
133
+ <td width="50%" valign="top">
134
+ <h3>Clear risk score and grade</h3>
135
+ Every finding is weighted by severity into a 0 to 100 risk score and an A to
136
+ F grade, each paired with a prioritised, plain-language remediation step.
137
+ </td>
138
+ </tr>
139
+ <tr>
140
+ <td width="50%" valign="top">
141
+ <h3>Copy-paste remediation</h3>
142
+ Every finding ships the exact fix, not just advice: the precise DNS record,
143
+ HTTP header, or server config that resolves it, each with an authoritative
144
+ reference. Carried in both the JSON and the HTML report.
145
+ </td>
146
+ <td width="50%" valign="top">
147
+ <h3>Interactive remediation simulator</h3>
148
+ The HTML report lets a client tick off the fixes they plan to make and
149
+ watch the projected score and grade climb live, with one-click "quick wins"
150
+ that picks the shortest path to grade A.
151
+ </td>
152
+ </tr>
153
+ <tr>
154
+ <td width="50%" valign="top">
155
+ <h3>Attack-surface mapping</h3>
156
+ Reads certificate transparency logs to discover the domain's public
157
+ subdomains, flags potentially sensitive names (dev, staging, admin, vpn),
158
+ and detects dangling CNAMEs an attacker could take over.
159
+ </td>
160
+ <td width="50%" valign="top">
161
+ <h3>Monitoring and alerts</h3>
162
+ Diff any two scans, or run the monitor command on a schedule to scan,
163
+ compare against the last run, and post a webhook alert (Slack, Discord, or
164
+ custom) the moment a domain's posture regresses.
165
+ </td>
166
+ </tr>
167
+ <tr>
168
+ <td width="50%" valign="top">
169
+ <h3>Report-ready outputs</h3>
170
+ Structured JSON for automation, a polished dark and red HTML report for
171
+ clients, a shareable score card, an embeddable grade badge, and an HTML
172
+ change report.
173
+ </td>
174
+ <td width="50%" valign="top">
175
+ <h3>Resilient by design</h3>
176
+ Two certificate-transparency sources (crt.sh with a CertSpotter fallback)
177
+ and a DNS-over-HTTPS fallback for blocked networks, so a scan keeps working
178
+ where a naive tool would silently fail.
179
+ </td>
180
+ </tr>
181
+ </table>
182
+
183
+ ## What it checks
184
+
185
+ | Area | Checks |
186
+ | --- | --- |
187
+ | **DNS** | Resolution, CAA issuance control, DNSSEC |
188
+ | **HTTP** | HTTPS reachability, HTTP to HTTPS redirect, security-header presence **and** value quality, security.txt, cookie flags, version disclosure |
189
+ | **TLS** | Trust and failure reason (expired, self-signed, hostname mismatch, untrusted), expiry, protocol version, key strength, signature algorithm, hostname match |
190
+ | **Email** | MX, SPF (policy, multiple records, 10-lookup limit), DMARC (policy, subdomain policy, enforcement coverage), DKIM, MTA-STS, TLS-RPT, BIMI |
191
+ | **Domain** | Registrar, registration age, and expiry via RDAP |
192
+ | **Subdomains** | Public subdomain discovery via certificate transparency (crt.sh, CertSpotter), sensitive-name flagging, and dangling-CNAME takeover detection |
193
+
194
+ Every issue is scored by severity into a 0 to 100 risk score and an A to F grade.
195
+
196
+ ## Installation
197
+
198
+ SentinelDeck requires **Python 3.10 or newer**.
199
+
200
+ From PyPI (available once the first release is published, see
201
+ [RELEASING.md](RELEASING.md)):
202
+
203
+ ```bash
204
+ pip install sentineldeck
205
+ ```
206
+
207
+ From source:
208
+
209
+ ```bash
210
+ git clone https://github.com/sanmaxdev/SentinelDeck.git
211
+ cd SentinelDeck
212
+ python3 -m venv .venv
213
+ . .venv/bin/activate # Windows: .venv\Scripts\activate
214
+ pip install -e .
215
+ ```
216
+
217
+ Either way, this puts the `sentineldeck` command on your path. To verify:
218
+
219
+ ```bash
220
+ sentineldeck --version
221
+ ```
222
+
223
+ For development, install the dev extras (pytest and ruff):
224
+
225
+ ```bash
226
+ pip install -e ".[dev]"
227
+ ```
228
+
229
+ ## Usage
230
+
231
+ Scan a domain and write a JSON report:
232
+
233
+ ```bash
234
+ sentineldeck scan example.com --output reports/example.json
235
+ ```
236
+
237
+ Accept findings you have already reviewed so they stop affecting the score, by
238
+ listing their ids in a suppressions file:
239
+
240
+ ```bash
241
+ sentineldeck scan example.com --suppress .sentineldeck-ignore
242
+ ```
243
+
244
+ Each line is a finding id (globs allowed, e.g. `subdomain-takeover:*`), and `#`
245
+ starts a comment. Accepted findings still appear under "Accepted" in the report
246
+ but are kept out of the risk score, so a known and accepted risk does not drag
247
+ the grade down on every re-scan.
248
+
249
+ Render a client-ready HTML report, a shareable score card, and a badge. The HTML
250
+ report includes the attack-surface map and the interactive remediation
251
+ simulator:
252
+
253
+ ```bash
254
+ sentineldeck report reports/example.json \
255
+ --html reports/example.html \
256
+ --svg reports/example-card.svg \
257
+ --badge reports/example-badge.svg
258
+ ```
259
+
260
+ Track how a domain's posture changes between two scans:
261
+
262
+ ```bash
263
+ sentineldeck diff reports/example-may.json reports/example-june.json \
264
+ --html reports/example-change.html
265
+ ```
266
+
267
+ The `diff` command shows what is new, what was resolved, score and grade
268
+ movement, and any severity escalations. It exits non-zero with `--exit-code`
269
+ when the posture regresses (a new high or critical finding, or a higher score),
270
+ so it drops straight into a cron job or CI step for scheduled monitoring.
271
+
272
+ Watch a domain on a schedule and get alerted when it regresses:
273
+
274
+ ```bash
275
+ sentineldeck monitor example.com --webhook https://hooks.slack.com/services/...
276
+ ```
277
+
278
+ The `monitor` command scans, compares against the previous run (stored under
279
+ `.sentineldeck/` by default), and saves the new report as the latest, so a cron
280
+ job or scheduled task becomes a standing watch. With `--webhook` it posts an
281
+ alert (Slack, Discord, or any custom endpoint) when the posture regresses. The
282
+ first run establishes a baseline; use `--alert-on change` to hear about any
283
+ change, and `--exit-code` to fail a job on regression.
284
+
285
+ Useful flags: `--pretty` prints the full JSON to stdout, `--timeout` bounds the
286
+ HTTP and TLS probes, and `diff --json` or `diff -o` emit the structured delta.
287
+
288
+ ## Example output
289
+
290
+ ```json
291
+ {
292
+ "target": "example.com",
293
+ "risk_score": 27,
294
+ "grade": "B",
295
+ "findings": [
296
+ { "id": "dmarc-missing", "severity": "medium", "confidence": "confirmed", "...": "..." }
297
+ ]
298
+ }
299
+ ```
300
+
301
+ ## How it works
302
+
303
+ ```
304
+ src/sentineldeck/
305
+ ├── scanner.py # runs every probe concurrently and assembles the report
306
+ ├── scanners/ # one module per surface: dns, dns_hygiene, tls, http_headers,
307
+ │ # email_security, domain_intel, subdomains, takeover
308
+ ├── risk/scoring.py # turns raw check results into scored findings
309
+ ├── remediation.py # maps each finding to a concrete copy-paste fix
310
+ ├── diff.py # compares two reports into a structured change delta
311
+ ├── monitor.py # scan, compare to the last run, and persist state
312
+ ├── alerts.py # webhook delivery on regression
313
+ ├── reporters/ # json, html, svg (card + badge), and diff renderers
314
+ └── models.py # Finding and ScanReport data models
315
+ ```
316
+
317
+ Each scanner is independent and keeps its network call injectable, so the whole
318
+ suite is tested offline with mocked DNS, HTTP, and certificate-transparency data.
319
+
320
+ ## Development
321
+
322
+ ```bash
323
+ pip install -e ".[dev]"
324
+ ruff check .
325
+ pytest -q
326
+ ```
327
+
328
+ Optionally enable the pre-commit hooks so linting runs on every commit:
329
+
330
+ ```bash
331
+ pip install pre-commit && pre-commit install
332
+ ```
333
+
334
+ CI runs ruff and the full test suite on Python 3.10, 3.11, and 3.12, and CodeQL
335
+ scans the codebase for security issues on every push.
336
+
337
+ ## Safety model
338
+
339
+ SentinelDeck is **passive-first**. It performs only normal DNS lookups and
340
+ standard HTTP and TLS metadata requests against the supplied domain, plus public
341
+ certificate-transparency queries. It does not probe, fuzz, or exploit anything.
342
+ Use it only on domains you own or are authorised to assess.
343
+
344
+ ## Support
345
+
346
+ - **Questions and bug reports**: open an issue on the
347
+ [issue tracker](https://github.com/sanmaxdev/SentinelDeck/issues).
348
+ - **Security issues**: please follow the [security policy](SECURITY.md) instead
349
+ of filing a public issue.
350
+ - **Contributing**: see [CONTRIBUTING.md](CONTRIBUTING.md). New checks must be
351
+ passive-safe and come with tests. This project follows a
352
+ [Code of Conduct](CODE_OF_CONDUCT.md).
353
+
354
+ ## License
355
+
356
+ [MIT](LICENSE)