recon-tool 0.4.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.
- recon_tool-0.4.1/.github/workflows/ci.yml +72 -0
- recon_tool-0.4.1/.github/workflows/release.yml +102 -0
- recon_tool-0.4.1/.gitignore +49 -0
- recon_tool-0.4.1/CHANGELOG.md +163 -0
- recon_tool-0.4.1/CLAUDE.md +62 -0
- recon_tool-0.4.1/CONTRIBUTING.md +56 -0
- recon_tool-0.4.1/LICENSE +21 -0
- recon_tool-0.4.1/PKG-INFO +203 -0
- recon_tool-0.4.1/README.md +162 -0
- recon_tool-0.4.1/docs/fingerprints.md +54 -0
- recon_tool-0.4.1/docs/legal.md +30 -0
- recon_tool-0.4.1/docs/mcp.md +51 -0
- recon_tool-0.4.1/docs/roadmap.md +94 -0
- recon_tool-0.4.1/docs/signals.md +56 -0
- recon_tool-0.4.1/examples/README.md +8 -0
- recon_tool-0.4.1/examples/sample-batch.txt +9 -0
- recon_tool-0.4.1/examples/sample-output.json +50 -0
- recon_tool-0.4.1/pyproject.toml +90 -0
- recon_tool-0.4.1/recon_tool/__init__.py +10 -0
- recon_tool-0.4.1/recon_tool/cache.py +260 -0
- recon_tool-0.4.1/recon_tool/chain.py +204 -0
- recon_tool-0.4.1/recon_tool/cli.py +883 -0
- recon_tool-0.4.1/recon_tool/constants.py +27 -0
- recon_tool-0.4.1/recon_tool/data/fingerprints.yaml +1716 -0
- recon_tool-0.4.1/recon_tool/data/posture.yaml +218 -0
- recon_tool-0.4.1/recon_tool/data/signals.yaml +278 -0
- recon_tool-0.4.1/recon_tool/delta.py +148 -0
- recon_tool-0.4.1/recon_tool/fingerprints.py +390 -0
- recon_tool-0.4.1/recon_tool/formatter.py +1138 -0
- recon_tool-0.4.1/recon_tool/http.py +248 -0
- recon_tool-0.4.1/recon_tool/insights.py +398 -0
- recon_tool-0.4.1/recon_tool/merger.py +392 -0
- recon_tool-0.4.1/recon_tool/models.py +256 -0
- recon_tool-0.4.1/recon_tool/posture.py +375 -0
- recon_tool-0.4.1/recon_tool/resolver.py +318 -0
- recon_tool-0.4.1/recon_tool/server.py +526 -0
- recon_tool-0.4.1/recon_tool/signals.py +290 -0
- recon_tool-0.4.1/recon_tool/sources/__init__.py +5 -0
- recon_tool-0.4.1/recon_tool/sources/azure_metadata.py +82 -0
- recon_tool-0.4.1/recon_tool/sources/base.py +28 -0
- recon_tool-0.4.1/recon_tool/sources/dns.py +1123 -0
- recon_tool-0.4.1/recon_tool/sources/google.py +190 -0
- recon_tool-0.4.1/recon_tool/sources/google_identity.py +205 -0
- recon_tool-0.4.1/recon_tool/sources/oidc.py +119 -0
- recon_tool-0.4.1/recon_tool/sources/userrealm.py +176 -0
- recon_tool-0.4.1/recon_tool/validator.py +77 -0
- recon_tool-0.4.1/tests/__init__.py +1 -0
- recon_tool-0.4.1/tests/conftest.py +26 -0
- recon_tool-0.4.1/tests/test_batch.py +133 -0
- recon_tool-0.4.1/tests/test_chain.py +99 -0
- recon_tool-0.4.1/tests/test_cli.py +157 -0
- recon_tool-0.4.1/tests/test_cli_coverage.py +145 -0
- recon_tool-0.4.1/tests/test_crtsh.py +185 -0
- recon_tool-0.4.1/tests/test_custom_signals.py +136 -0
- recon_tool-0.4.1/tests/test_delta.py +146 -0
- recon_tool-0.4.1/tests/test_dns_subdetectors.py +403 -0
- recon_tool-0.4.1/tests/test_enrichment.py +77 -0
- recon_tool-0.4.1/tests/test_fingerprints.py +157 -0
- recon_tool-0.4.1/tests/test_formatter.py +202 -0
- recon_tool-0.4.1/tests/test_formatter_v2.py +289 -0
- recon_tool-0.4.1/tests/test_google_identity.py +276 -0
- recon_tool-0.4.1/tests/test_gws_features.py +740 -0
- recon_tool-0.4.1/tests/test_http.py +65 -0
- recon_tool-0.4.1/tests/test_http_advanced.py +228 -0
- recon_tool-0.4.1/tests/test_insights.py +224 -0
- recon_tool-0.4.1/tests/test_insights_unit.py +242 -0
- recon_tool-0.4.1/tests/test_integration.py +46 -0
- recon_tool-0.4.1/tests/test_merger.py +288 -0
- recon_tool-0.4.1/tests/test_models.py +122 -0
- recon_tool-0.4.1/tests/test_new_fingerprints_signals.py +66 -0
- recon_tool-0.4.1/tests/test_new_signals.py +52 -0
- recon_tool-0.4.1/tests/test_posture.py +102 -0
- recon_tool-0.4.1/tests/test_resolver.py +384 -0
- recon_tool-0.4.1/tests/test_security.py +119 -0
- recon_tool-0.4.1/tests/test_server.py +155 -0
- recon_tool-0.4.1/tests/test_server_cache.py +96 -0
- recon_tool-0.4.1/tests/test_signals.py +154 -0
- recon_tool-0.4.1/tests/test_signals_validation.py +72 -0
- recon_tool-0.4.1/tests/test_sources/__init__.py +1 -0
- recon_tool-0.4.1/tests/test_sources/test_azure_metadata.py +121 -0
- recon_tool-0.4.1/tests/test_sources/test_dns.py +278 -0
- recon_tool-0.4.1/tests/test_sources/test_oidc.py +257 -0
- recon_tool-0.4.1/tests/test_sources/test_userrealm.py +143 -0
- recon_tool-0.4.1/tests/test_userrealm_xml.py +77 -0
- recon_tool-0.4.1/tests/test_validator.py +219 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Set up Python
|
|
16
|
+
uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
|
|
20
|
+
- name: Install dependencies
|
|
21
|
+
run: pip install -e ".[dev]"
|
|
22
|
+
|
|
23
|
+
- name: Lint
|
|
24
|
+
run: ruff check recon_tool/
|
|
25
|
+
|
|
26
|
+
typecheck:
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
|
|
31
|
+
- name: Set up Node.js
|
|
32
|
+
uses: actions/setup-node@v4
|
|
33
|
+
with:
|
|
34
|
+
node-version: "20"
|
|
35
|
+
|
|
36
|
+
- name: Set up Python
|
|
37
|
+
uses: actions/setup-python@v5
|
|
38
|
+
with:
|
|
39
|
+
python-version: "3.12"
|
|
40
|
+
|
|
41
|
+
- name: Install dependencies
|
|
42
|
+
run: pip install -e ".[dev]"
|
|
43
|
+
|
|
44
|
+
- name: Type check
|
|
45
|
+
run: pyright recon_tool/
|
|
46
|
+
|
|
47
|
+
test:
|
|
48
|
+
runs-on: ${{ matrix.os }}
|
|
49
|
+
strategy:
|
|
50
|
+
fail-fast: false
|
|
51
|
+
matrix:
|
|
52
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
53
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
54
|
+
exclude:
|
|
55
|
+
- os: macos-latest
|
|
56
|
+
python-version: "3.10"
|
|
57
|
+
- os: windows-latest
|
|
58
|
+
python-version: "3.10"
|
|
59
|
+
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v4
|
|
62
|
+
|
|
63
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
64
|
+
uses: actions/setup-python@v5
|
|
65
|
+
with:
|
|
66
|
+
python-version: ${{ matrix.python-version }}
|
|
67
|
+
|
|
68
|
+
- name: Install dependencies
|
|
69
|
+
run: pip install -e ".[dev]"
|
|
70
|
+
|
|
71
|
+
- name: Test
|
|
72
|
+
run: pytest tests/ --cov=recon_tool --cov-report=term-missing
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
id-token: write # Required for PyPI trusted publishing
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: pip install -e ".[dev]"
|
|
25
|
+
|
|
26
|
+
- name: Run tests
|
|
27
|
+
run: pytest tests/ -q
|
|
28
|
+
|
|
29
|
+
- name: Lint
|
|
30
|
+
run: ruff check recon_tool/
|
|
31
|
+
|
|
32
|
+
build:
|
|
33
|
+
needs: test
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v4
|
|
37
|
+
|
|
38
|
+
- name: Set up Python
|
|
39
|
+
uses: actions/setup-python@v5
|
|
40
|
+
with:
|
|
41
|
+
python-version: "3.12"
|
|
42
|
+
|
|
43
|
+
- name: Install build tools
|
|
44
|
+
run: pip install build
|
|
45
|
+
|
|
46
|
+
- name: Build package
|
|
47
|
+
run: python -m build
|
|
48
|
+
|
|
49
|
+
- name: Upload build artifacts
|
|
50
|
+
uses: actions/upload-artifact@v4
|
|
51
|
+
with:
|
|
52
|
+
name: dist
|
|
53
|
+
path: dist/
|
|
54
|
+
|
|
55
|
+
publish-pypi:
|
|
56
|
+
needs: build
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
environment: pypi
|
|
59
|
+
permissions:
|
|
60
|
+
id-token: write # Trusted publishing via OIDC
|
|
61
|
+
steps:
|
|
62
|
+
- name: Download build artifacts
|
|
63
|
+
uses: actions/download-artifact@v4
|
|
64
|
+
with:
|
|
65
|
+
name: dist
|
|
66
|
+
path: dist/
|
|
67
|
+
|
|
68
|
+
- name: Publish to PyPI
|
|
69
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
70
|
+
|
|
71
|
+
github-release:
|
|
72
|
+
needs: build
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
permissions:
|
|
75
|
+
contents: write
|
|
76
|
+
steps:
|
|
77
|
+
- uses: actions/checkout@v4
|
|
78
|
+
|
|
79
|
+
- name: Extract changelog
|
|
80
|
+
id: changelog
|
|
81
|
+
run: |
|
|
82
|
+
# Extract the section for this version from CHANGELOG.md
|
|
83
|
+
VERSION="${GITHUB_REF_NAME#v}"
|
|
84
|
+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
85
|
+
# Grab everything between this version header and the next
|
|
86
|
+
awk "/^## \[${VERSION}\]/{found=1; next} /^## \[/{if(found) exit} found{print}" CHANGELOG.md > release_notes.md
|
|
87
|
+
cat release_notes.md
|
|
88
|
+
|
|
89
|
+
- name: Download build artifacts
|
|
90
|
+
uses: actions/download-artifact@v4
|
|
91
|
+
with:
|
|
92
|
+
name: dist
|
|
93
|
+
path: dist/
|
|
94
|
+
|
|
95
|
+
- name: Create GitHub Release
|
|
96
|
+
uses: softprops/action-gh-release@v2
|
|
97
|
+
with:
|
|
98
|
+
name: "v${{ steps.changelog.outputs.version }}"
|
|
99
|
+
body_path: release_notes.md
|
|
100
|
+
draft: false
|
|
101
|
+
prerelease: false
|
|
102
|
+
files: dist/*
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
*.egg
|
|
7
|
+
*.egg-info/
|
|
8
|
+
pip-log.txt
|
|
9
|
+
pip-delete-this-directory.txt
|
|
10
|
+
|
|
11
|
+
# Build
|
|
12
|
+
dist/
|
|
13
|
+
build/
|
|
14
|
+
*.whl
|
|
15
|
+
|
|
16
|
+
# Test / Coverage
|
|
17
|
+
.pytest_cache/
|
|
18
|
+
.hypothesis/
|
|
19
|
+
.coverage
|
|
20
|
+
.coverage.*
|
|
21
|
+
coverage.xml
|
|
22
|
+
htmlcov/
|
|
23
|
+
|
|
24
|
+
# Linting
|
|
25
|
+
.ruff_cache/
|
|
26
|
+
|
|
27
|
+
# IDE
|
|
28
|
+
.vscode/
|
|
29
|
+
.idea/
|
|
30
|
+
*.swp
|
|
31
|
+
*.swo
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|
|
36
|
+
Desktop.ini
|
|
37
|
+
|
|
38
|
+
# Env
|
|
39
|
+
.env
|
|
40
|
+
.venv/
|
|
41
|
+
venv/
|
|
42
|
+
env/
|
|
43
|
+
|
|
44
|
+
# Logs
|
|
45
|
+
*.log
|
|
46
|
+
|
|
47
|
+
# Kiro
|
|
48
|
+
.kiro/
|
|
49
|
+
/archive
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.4.1] — 2026-04-11
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Added PyPI trusted publishing via GitHub Actions (OIDC, no API tokens).
|
|
13
|
+
- Added package metadata: classifiers, keywords, project URLs for PyPI listing.
|
|
14
|
+
- Fixed duplicate file warnings in wheel build by removing redundant `force-include`.
|
|
15
|
+
|
|
16
|
+
## [0.4.0] — 2026-04-11
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- `--html` output — self-contained single-file HTML report with inline CSS, no JavaScript. Professional styling for sharing via email or archiving.
|
|
21
|
+
- `--csv` output for batch mode — flat CSV with one row per domain. Columns: domain, provider, display_name, tenant_id, auth_type, confidence, email_security_score, service_count, dmarc_policy, mta_sts_mode, google_auth_type.
|
|
22
|
+
- Lightweight local disk cache — `~/.recon/cache/` with configurable TTL (default 24h). CLI flags: `--no-cache` to bypass, `--cache-ttl` to override. JSON files on disk, lazy eviction, no external dependencies.
|
|
23
|
+
- `recon mcp` subcommand — start the MCP server from the CLI instead of `python -m recon_tool.server`.
|
|
24
|
+
- `recon doctor --fix` — scaffolds template `~/.recon/fingerprints.yaml` and `~/.recon/signals.yaml` with inline YAML comments explaining the format.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Inference language tightened across insights and signals. Derived claims now use hedged language ("suggests," "indicators," "likely") instead of declarative phrasing. Factual observations (DMARC values, DKIM presence, email security scores) remain declarative.
|
|
29
|
+
- Removed `_preprocess_args()` sys.argv mutation hack. Domain shorthand routing (`recon pepsi.com`) now uses a custom Typer group with `resolve_command()` override — cleaner, safer for library imports, no global state mutation.
|
|
30
|
+
- `_SUBCOMMANDS` now includes `"mcp"`.
|
|
31
|
+
- Mutual exclusion enforced for output format flags (`--json`, `--md`, `--html`, `--csv`).
|
|
32
|
+
|
|
33
|
+
## [0.3.0] — 2026-04-11
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- Google Workspace identity routing — new `GoogleIdentitySource` detects federated vs. managed auth by querying Google's public login flow. Extracts IdP name (Okta, Ping, Entra, etc.) for federated domains. Produces `google-federated`/`google-managed` slugs.
|
|
38
|
+
- Google Workspace CNAME module probing — detects active GWS modules (Mail, Calendar, Docs, Drive, Sites, Groups) via `ghs.googlehosted.com` CNAME resolution. Concurrent queries for all 6 prefixes.
|
|
39
|
+
- BIMI/VMC corporate identity extraction — fetches VMC certificates from BIMI `a=` URLs and extracts legally verified organization name, country, state, locality. Falls back to regex parsing when `cryptography` library is unavailable.
|
|
40
|
+
- Google site-verification token extraction — captures `google-site-verification` token values from TXT records for cross-domain organizational relationship mapping.
|
|
41
|
+
- MTA-STS policy fetch — when `_mta-sts` TXT record is found, fetches the policy file and extracts the mode (enforce/testing/none). Adds `mta-sts-enforce` slug for enforcing domains.
|
|
42
|
+
- TLS-RPT detection — detects `v=TLSRPTv1` records at `_smtp._tls.{domain}` with `tls-rpt` slug.
|
|
43
|
+
- Enhanced CSE config probing — extracts KACLS URL and multiple key service provider names from Google Workspace CSE configuration.
|
|
44
|
+
- Evidence traceability — new `EvidenceRecord` frozen dataclass captures source type, raw value, rule name, and slug for every detection. Propagated through the merge pipeline to `TenantInfo`. Included in `--json` output and `--verbose` display.
|
|
45
|
+
- Confidence separation — dual confidence model: `evidence_confidence` (how many sources contributed) and `inference_confidence` (strength of logical chain). Backward-compatible `confidence` field = min of both.
|
|
46
|
+
- Per-detection corroboration scoring — each detected slug gets a confidence score (high/medium/low) based on how many independent record types corroborate it.
|
|
47
|
+
- Fingerprint metadata enrichment — `provider_group` and `display_group` fields on fingerprint YAML entries. Formatter uses these for categorization, falling back to keyword heuristics.
|
|
48
|
+
- Cross-domain site-verification correlation in chain mode — domains sharing identical `google-site-verification` tokens are surfaced as organizationally related.
|
|
49
|
+
- 5 new Google Workspace signals: Google Workspace Full Suite, Google Federated Identity, Google MTA-STS Enforcing, plus updates to Google-Native Identity and Google Cloud Investment.
|
|
50
|
+
- 4 new posture rules: google_federated_identity, google_managed_identity, mta_sts_enforcing, tls_rpt_configured.
|
|
51
|
+
- Google Workspace insight generators: federated/managed identity insights, module summary insights.
|
|
52
|
+
- New data models: `EvidenceRecord`, `BIMIIdentity`. Extended `SourceResult`, `TenantInfo`, `Fingerprint` with new fields.
|
|
53
|
+
- 98 new tests (506 → 604 total). Test coverage 84%.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- `default_pool()` now includes `GoogleIdentitySource` (5 sources total).
|
|
58
|
+
- `merge_results()` propagates evidence, computes dual confidence, detection scores, and merges Google auth/BIMI/MTA-STS/site-verification data.
|
|
59
|
+
- `build_insights_with_signals()` accepts `google_auth_type` and `google_idp_name` parameters.
|
|
60
|
+
- `format_tenant_dict()` includes all new fields in JSON output.
|
|
61
|
+
- `format_tenant_markdown()` includes Google Workspace section and dual confidence.
|
|
62
|
+
- `render_tenant_panel()` shows GWS auth/modules, verbose evidence chains and detection scores.
|
|
63
|
+
- `lookup_tenant` MCP tool text format includes GWS auth and module summary.
|
|
64
|
+
- `_detect_email_security()` now also queries TLS-RPT, fetches MTA-STS policy, and parses BIMI VMC.
|
|
65
|
+
- `_detect_txt()` extracts site-verification tokens and creates evidence records.
|
|
66
|
+
- Fingerprints YAML: added `provider_group`/`display_group` to Microsoft 365, Google Workspace, and other key entries. Added TLS-RPT fingerprint.
|
|
67
|
+
- 29 signals (was 26). 22 posture rules (was 18).
|
|
68
|
+
|
|
69
|
+
## [0.2.0] — 2026-04-11
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- Certificate intelligence — crt.sh metadata extraction (issuance velocity, issuer diversity, cert age, top issuers) from the existing crt.sh JSON response. No additional HTTP requests. Surfaced in panel, JSON, and markdown output.
|
|
74
|
+
- Metadata-aware signal engine — signals can now match on `dmarc_policy`, `auth_type`, `email_security_score`, `spf_include_count`, and `issuance_velocity` via YAML `metadata` conditions. Supports slug-only, metadata-only, and conjunction signals. 23 → 26 signals (4 layers).
|
|
75
|
+
- Neutral posture analysis — new `--posture` flag and `analyze_posture` MCP tool. Produces factual observations about domain configuration (email, identity, infrastructure, SaaS footprint, certificates, consistency) without attack/defense framing. YAML-driven rules in `data/posture.yaml` with `~/.recon/posture.yaml` additive override.
|
|
76
|
+
- Delta mode — `--compare previous.json` compares a live lookup against a previous JSON export. Surfaces added/removed services, slugs, signals, and scalar field changes (auth type, DMARC, confidence, domain count). Panel output with +/- markers, JSON output with structured diff.
|
|
77
|
+
- Recursive domain chaining — `--chain --depth N` (max 3) follows related domains via CNAME/CT breadcrumbs using BFS. 50-domain cap, visited-set deduplication, aggregate timeout. New `chain_lookup` MCP tool.
|
|
78
|
+
- 3 new metadata-aware signals: Federated Identity with Complex Email Delegation, Active Email Sending with Minimal Security, High Certificate Issuance Activity.
|
|
79
|
+
- 18 posture observation rules across 6 categories.
|
|
80
|
+
- 7 new frozen dataclasses: `CertSummary`, `MetadataCondition`, `SignalContext`, `Observation`, `DeltaReport`, `ChainResult`, `ChainReport`.
|
|
81
|
+
- 51 new tests (455 → 506 total). Test coverage 83%.
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
|
|
85
|
+
- `--full` now implies `--posture` in addition to `--services`, `--domains`, `--verbose`.
|
|
86
|
+
- `evaluate_signals()` now accepts a `SignalContext` instead of positional args. All callers updated.
|
|
87
|
+
- "Security Gap — Gateway Without DMARC Enforcement" signal moved from hardcoded Python check to YAML metadata conditions.
|
|
88
|
+
- `reload_data` MCP tool now also clears posture rule cache and reports posture rule count.
|
|
89
|
+
- README updated: broader audience description, new feature table rows, new CLI examples, new MCP tools listed.
|
|
90
|
+
- Roadmap updated: completed items marked, new future items added.
|
|
91
|
+
|
|
92
|
+
## [0.1.3] — 2026-04-11
|
|
93
|
+
|
|
94
|
+
### Added
|
|
95
|
+
|
|
96
|
+
- Common subdomain probing — ~35 high-signal prefixes (auth, login, sso, shop, api, status, cdn, etc.) are probed directly via DNS CNAME lookups. Works even when crt.sh is down.
|
|
97
|
+
- 30 new CNAME-based fingerprints for SaaS services discovered via subdomain CNAMEs: Okta (CNAME), Auth0, OneLogin, Salesforce Marketing Cloud, AWS ELB/S3/Elastic Beanstalk, Azure Front Door, Google Cloud Run/App Engine, Zendesk/Freshdesk (hosted), Contentful, Braze, Segment, Statuspage, LaunchDarkly, Cloudinary, Imgix, Optimizely, WalkMe, and more (156 → 186 total).
|
|
98
|
+
- crt.sh degraded notice — when crt.sh is unreachable, a subtle note appears in panel, markdown, and JSON output (`"partial": true`) so users know results may be incomplete.
|
|
99
|
+
- Lightweight subdomain enrichment — subdomains get CNAME+TXT-only lookups (2 queries each) instead of full DNS fingerprinting (~20 queries each), keeping enrichment fast.
|
|
100
|
+
|
|
101
|
+
### Changed
|
|
102
|
+
|
|
103
|
+
- crt.sh subdomain cap raised from 20 to 100, with signal-based prioritization (auth/login/shop/api subdomains first, deep internal subdomains last).
|
|
104
|
+
- Enrichment cap raised from 10 to 25, with priority sorting so high-signal subdomains survive the cap.
|
|
105
|
+
- Two-tier enrichment: subdomains get lightweight CNAME+TXT lookups, separate domains get full DNS fingerprinting.
|
|
106
|
+
- Updated 8 signal rules to include new CNAME-detected slugs (imperva, auth0, onelogin, salesforce-mc, aws-elb, aws-s3, gcp-app, azure-fd, optimizely, walkme, braze, iterable, customerio, launchdarkly, contentful, etc.).
|
|
107
|
+
|
|
108
|
+
## [0.1.2] — 2026-04-11
|
|
109
|
+
|
|
110
|
+
### Added
|
|
111
|
+
|
|
112
|
+
- Google Workspace source — passive CSE config probing (`cse.{domain}/.well-known/cse-configuration`) for detecting Client-Side Encryption and external key managers.
|
|
113
|
+
- Google DKIM attribution — `google._domainkey` now adds the `google-workspace` slug, so Google Workspace is detected even when MX points to an email gateway (Proofpoint, Mimecast, Trend Micro, etc.).
|
|
114
|
+
- 4 new signal rules: Google-Native Identity, High-Security Posture (CSE), Google Cloud Investment, Dual Email Provider (13 → 24 total).
|
|
115
|
+
- Custom signals support via `~/.recon/signals.yaml` (additive, mirrors fingerprint extensibility).
|
|
116
|
+
- Certificate transparency integration via crt.sh for passive subdomain discovery.
|
|
117
|
+
- Expanded DKIM selector coverage — now checks common ESP selectors (Mailchimp, SendGrid, Mailgun, Postmark, Mimecast) in addition to Exchange and Google.
|
|
118
|
+
- SRV record detection for Microsoft Teams (legacy SIP/federation), XMPP, CalDAV, CardDAV.
|
|
119
|
+
- 13 new fingerprints: Box, Egnyte, Glean, Datadog, New Relic, PagerDuty, Render, Ping Identity, CyberArk, Lakera, Cato Networks, Rippling, Deel (143 → 156 total).
|
|
120
|
+
- `recon doctor` now checks crt.sh connectivity, signal database loading, and custom signals path.
|
|
121
|
+
- "Why recon?" comparison table in README.
|
|
122
|
+
- Expanded MCP Server section with setup steps, tools table, and config file locations per client.
|
|
123
|
+
- `CLAUDE.md` for Claude Code project context.
|
|
124
|
+
- `.kiro/steering/recon-project.md` for Kiro IDE context.
|
|
125
|
+
- `CHANGELOG.md`, `CONTRIBUTING.md`.
|
|
126
|
+
- `examples/` folder with sample JSON output and batch file (all fictional data).
|
|
127
|
+
- GitHub Actions CI workflow (Python 3.10–3.13, lint, type check, tests).
|
|
128
|
+
|
|
129
|
+
### Changed
|
|
130
|
+
|
|
131
|
+
- Confidence scoring — M365 domains now reach High when OIDC tenant ID is corroborated by UserRealm (display name, auth type, or tenant domains). Previously required 2+ sources returning the same tenant ID, which never happened in practice.
|
|
132
|
+
- Non-M365 confidence — domains with 8+ DNS services and 2+ successful sources now reach High. Thresholds adjusted (was: 5 services for Medium, High unreachable).
|
|
133
|
+
- Skype for Business / Lync → Microsoft Teams — SRV records `_sip._tls` and `_sipfederationtls._tcp` pointing to `lync.com` now labeled as "Microsoft Teams" (deduplicated with CNAME-based detection). Microsoft retired Skype for Business Online in July 2021.
|
|
134
|
+
- Dual provider insight — shortened from "Hybrid/migration signal: Google email + Microsoft services detected" to "Dual provider: Google + Microsoft coexistence". No longer styled as a warning.
|
|
135
|
+
- Panel color palette — muted, modern tones replacing harsh ANSI primaries. Labels use `dim` instead of `bold`. Panel border is `dim`. Confidence colors: sage green (High), sky blue (Medium), terracotta (Low).
|
|
136
|
+
- Panel alignment — services and insights now use consistent label:value column alignment. Service continuation lines align under the first service name. Long insights word-wrap within the panel.
|
|
137
|
+
- All README examples now use fictional companies (Northwind Traders, Contoso, Fabrikam).
|
|
138
|
+
- README tagline updated to be more precise and humble.
|
|
139
|
+
- Panel output: fixed width (80 chars), related domains now dim instead of cyan.
|
|
140
|
+
- Updated Enterprise Security Stack, Zero Trust Posture, and Enterprise IT Maturity signals to include new security slugs.
|
|
141
|
+
|
|
142
|
+
## [0.1.0] — 2026-04-10
|
|
143
|
+
|
|
144
|
+
### Added
|
|
145
|
+
|
|
146
|
+
- Initial release.
|
|
147
|
+
- Domain intelligence CLI (`recon lookup`, `recon batch`, `recon doctor`).
|
|
148
|
+
- MCP server with `lookup_tenant` and `reload_data` tools.
|
|
149
|
+
- Three concurrent data sources: OIDC Discovery, GetUserRealm + Autodiscover, DNS records.
|
|
150
|
+
- 143 SaaS/service fingerprints in `data/fingerprints.yaml` across 14 categories.
|
|
151
|
+
- Signal intelligence engine with 3-layer evaluation (single-category, cross-category composites, consistency checks).
|
|
152
|
+
- Email security scoring (0–5) based on DMARC, DKIM, SPF strict, MTA-STS, BIMI.
|
|
153
|
+
- Related domain auto-enrichment from CNAME breadcrumbs.
|
|
154
|
+
- Custom fingerprint support via `~/.recon/fingerprints.yaml`.
|
|
155
|
+
- Rich terminal output with bordered panels, colored signals, and provider detection.
|
|
156
|
+
- Output formats: default panel, `--json`, `--md`, `--services`, `--full`, `--sources`.
|
|
157
|
+
- Batch mode with configurable concurrency (1–20) and ordered output.
|
|
158
|
+
- Input normalization (URLs, schemes, www prefix, paths, whitespace).
|
|
159
|
+
- SSRF protection in HTTP transport.
|
|
160
|
+
- Retry with exponential backoff on 429/503 responses.
|
|
161
|
+
- Structured exit codes (0, 2, 3, 4).
|
|
162
|
+
- `defusedxml` for safe XML parsing.
|
|
163
|
+
- Strict type checking with Pyright, linting with Ruff.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# recon
|
|
2
|
+
|
|
3
|
+
Passive domain intelligence CLI and MCP server. Queries public DNS records and unauthenticated Microsoft/Google endpoints — no credentials or API keys.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
`recon <domain>` returns: company name, email provider, tenant ID, auth type, email security score (0-5), 186 SaaS service fingerprints, security stack detection, signal intelligence (AI adoption, GTM maturity, org size hints), and related domains (via CNAME breadcrumbs + certificate transparency + common subdomain probing).
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
recon northwindtraders.com # default panel output
|
|
13
|
+
recon northwindtraders.com --json # structured JSON
|
|
14
|
+
recon northwindtraders.com --md # markdown report
|
|
15
|
+
recon northwindtraders.com --full # everything
|
|
16
|
+
recon batch domains.txt --json # batch mode
|
|
17
|
+
recon doctor # connectivity check
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Project structure
|
|
21
|
+
|
|
22
|
+
- `recon_tool/` — source code
|
|
23
|
+
- `cli.py` — Typer CLI, entry point is `run()`
|
|
24
|
+
- `resolver.py` — orchestrates concurrent source queries
|
|
25
|
+
- `sources/` — OIDC, UserRealm, DNS lookup sources (DNS includes crt.sh cert transparency)
|
|
26
|
+
- `fingerprints.py` + `data/fingerprints.yaml` — SaaS detection (data-driven, no code changes needed)
|
|
27
|
+
- `signals.py` + `data/signals.yaml` — signal intelligence engine
|
|
28
|
+
- `insights.py` — derived intelligence from fingerprint matches
|
|
29
|
+
- `merger.py` — result merging, confidence scoring
|
|
30
|
+
- `formatter.py` — Rich terminal output, JSON, markdown
|
|
31
|
+
- `server.py` — MCP server (FastMCP, stdio transport)
|
|
32
|
+
- `http.py` — SSRF-safe HTTP client with retry/backoff
|
|
33
|
+
- `validator.py` — domain input validation
|
|
34
|
+
- `models.py` — frozen dataclasses (TenantInfo, SourceResult)
|
|
35
|
+
- `tests/` — 455 tests, pytest + hypothesis
|
|
36
|
+
- `data/fingerprints.yaml` — 186 SaaS fingerprints
|
|
37
|
+
- `data/signals.yaml` — 3-layer signal definitions (23 signals)
|
|
38
|
+
|
|
39
|
+
## Development
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install -e ".[dev]"
|
|
43
|
+
pytest tests/ # run tests
|
|
44
|
+
ruff check recon_tool/ # lint
|
|
45
|
+
pyright recon_tool/ # type check
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Key patterns
|
|
49
|
+
|
|
50
|
+
- All source queries run concurrently via `asyncio.gather`
|
|
51
|
+
- Fingerprints and signals are YAML-driven — edit data files, not code
|
|
52
|
+
- Models are frozen dataclasses (immutable)
|
|
53
|
+
- HTTP transport has SSRF protection and retry with exponential backoff
|
|
54
|
+
- MCP server has TTL cache (120s) and per-domain rate limiting
|
|
55
|
+
- Custom fingerprints go in `~/.recon/fingerprints.yaml` (additive only)
|
|
56
|
+
- Custom signals go in `~/.recon/signals.yaml` (additive only)
|
|
57
|
+
|
|
58
|
+
## Testing
|
|
59
|
+
|
|
60
|
+
- Integration tests are skipped by default (`-m 'not integration'`)
|
|
61
|
+
- Run `pytest -m integration` for network tests
|
|
62
|
+
- All examples in README use fictional companies (Northwind Traders, Contoso, Fabrikam)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing to recon.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/blisspixel/recon.git
|
|
9
|
+
cd recon
|
|
10
|
+
pip install -e ".[dev]"
|
|
11
|
+
pytest tests/
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Adding Fingerprints
|
|
15
|
+
|
|
16
|
+
The easiest way to contribute is adding new SaaS fingerprints. Edit `recon_tool/data/fingerprints.yaml`:
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
- name: Service Name
|
|
20
|
+
slug: service-slug # lowercase, unique identifier
|
|
21
|
+
category: Category Name # use an existing category if possible
|
|
22
|
+
confidence: high # high, medium, or low
|
|
23
|
+
detections:
|
|
24
|
+
- type: txt # txt, spf, mx, ns, cname, subdomain_txt, caa, srv
|
|
25
|
+
pattern: "^service-domain-verification="
|
|
26
|
+
description: What this record means
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Run `recon doctor` to validate your fingerprint loads correctly, then test against a domain you know uses the service.
|
|
30
|
+
|
|
31
|
+
## Adding Signals
|
|
32
|
+
|
|
33
|
+
Custom signal rules go in `~/.recon/signals.yaml`:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
signals:
|
|
37
|
+
- name: My Custom Signal
|
|
38
|
+
category: Custom
|
|
39
|
+
confidence: medium
|
|
40
|
+
description: What this signal means
|
|
41
|
+
requires:
|
|
42
|
+
any: [slug-a, slug-b, slug-c] # fingerprint slugs to match
|
|
43
|
+
min_matches: 2 # how many must be present
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Code Changes
|
|
47
|
+
|
|
48
|
+
- Run `ruff check recon_tool/` and `pyright recon_tool/` before submitting.
|
|
49
|
+
- Run `pytest tests/` to verify nothing breaks.
|
|
50
|
+
- Integration tests (`pytest -m integration`) require network access and are skipped by default.
|
|
51
|
+
|
|
52
|
+
## Pull Requests
|
|
53
|
+
|
|
54
|
+
- Keep PRs focused — one feature or fix per PR.
|
|
55
|
+
- Fingerprint-only PRs are welcome and easy to review.
|
|
56
|
+
- Include a brief description of what you changed and why.
|
recon_tool-0.4.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 recon-tool contributors
|
|
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.
|