Metadata-Version: 2.4
Name: truesignal
Version: 0.1.0
Summary: Provenance-first OSINT/security intelligence feed CLI. Every item ships a real source URL, a real timestamp, and an explicit live/fallback flag -- never a fabricated or silently-replayed data point.
Project-URL: Homepage, https://github.com/RudrenduPaul/truesignal
Project-URL: Repository, https://github.com/RudrenduPaul/truesignal
Project-URL: Bug Tracker, https://github.com/RudrenduPaul/truesignal/issues
Project-URL: Changelog, https://github.com/RudrenduPaul/truesignal/blob/main/CHANGELOG.md
Project-URL: Documentation, https://github.com/RudrenduPaul/truesignal/blob/main/docs/getting-started.md
Project-URL: Author - Rudrendu Paul, https://github.com/RudrenduPaul
Project-URL: Author - Sourav Nandy, https://github.com/Sourav-nandy-ai
Author: Rudrendu Paul, Sourav Nandy
License-Expression: MIT
License-File: LICENSE
Keywords: cisa-kev,cli,cloudflare-radar,cve,gdelt,osint,provenance,security,threat-intelligence
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet
Classifier: Topic :: Security
Requires-Python: >=3.9
Provides-Extra: dev
Requires-Dist: build<2,>=1.0; extra == 'dev'
Requires-Dist: pytest<9,>=7.0; extra == 'dev'
Requires-Dist: twine<7,>=5.0; extra == 'dev'
Description-Content-Type: text/markdown

# truesignal (Python)

A provenance-first OSINT/security intelligence feed. Every item ships a real
source URL, a real upstream timestamp, and an explicit `live`/`fallback`
flag -- never a fabricated or silently-replayed data point.

[![PyPI version](https://img.shields.io/pypi/v/truesignal.svg)](https://pypi.org/project/truesignal/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/RudrenduPaul/truesignal/blob/main/LICENSE)
[![Python versions](https://img.shields.io/pypi/pyversions/truesignal.svg)](https://pypi.org/project/truesignal/)
[![CI](https://github.com/RudrenduPaul/truesignal/actions/workflows/ci.yml/badge.svg)](https://github.com/RudrenduPaul/truesignal/actions/workflows/ci.yml)

## Why this exists

Personal OSINT/security feeds are easy to build and easy to get wrong in one
specific way: silently showing stale or synthetic data as if it were
current. TrueSignal's answer is structural, not a documentation promise --
every connector's failure path is enforced by a dedicated test suite to
return either a real cached item honestly labeled `fallback` with its real
age, or nothing at all. This package is the Python distribution -- a
genuine, independent port of the npm package, not a wrapper around the
Node binary.

## Install

```bash
pip install truesignal
```

or with [uv](https://docs.astral.sh/uv/):

```bash
uv add truesignal
```

No separate install step, no external binary to fetch. The complementary
JS/TS distribution installs the same way on the npm side:
`npm install -g truesignal-cli` (or `npx truesignal-cli init` to run it once
without installing) -- see the
[project README](https://github.com/RudrenduPaul/truesignal#readme) for
that package. Both are first-class, maintained together; neither is
deprecated in favor of the other.

## Quickstart

```bash
truesignal init
truesignal feed
```

`init` reports which connectors are ready right now -- CISA-KEV and GDELT
need no configuration -- and which environment variables are still missing
for the rest (Cloudflare Radar, Reddit, Telegram). `feed` pulls from every
configured connector.

Or call the library directly (the agent-native path):

```python
from truesignal import ALL_CONNECTORS

for connector in ALL_CONNECTORS:
    if connector.requires_config and not connector.is_configured():
        continue
    for item in connector.fetch_items():
        print(item.status, item.source, item.url)
```

## How it works

```
connector.fetch_items()
   -> fetch_with_fallback(source, fetch_live)
        -> upstream API call succeeds -> stamp_live() -> write_cache() -> real "live" items
        -> upstream API call fails    -> read_cache() -> stamp_fallback() -> real "fallback"
                                          items with an honest fallback_age_seconds, or []
                                          if nothing has ever been cached
```

Every connector implements the same `Connector` interface
(`truesignal/types.py`) and calls `fetch_with_fallback` instead of touching
the network directly -- that single function is what gives every connector
its live/fallback/nothing guarantee. See
[docs/concepts.md](https://github.com/RudrenduPaul/truesignal/blob/main/docs/concepts.md)
for the full data model and what each of the five connectors actually
returns.

## No-fabrication guarantee

Every connector's live, fallback, and empty-cache-failure path is covered
by a dedicated pytest suite (`tests/test_no_fabrication.py`), ported
directly from the TypeScript suite's `no-fabrication.test.ts`: it proves,
for every connector, that a failed upstream fetch never produces
synthetic, randomized, or silently-relabeled-as-current data -- only a real
cached fallback item with an honest age, or nothing. A companion static
check scans every connector source file in `src/truesignal/connectors/`
for forbidden patterns (`random.random()`, a fake-data library,
`datetime.now()` used to construct an item's timestamp).

## CLI command reference

```
usage: truesignal [-h] [--version] {init,feed,verify} ...

Commands:
  init [--json]                     Check which connectors are ready right now.
  feed [--source NAME] [--json]     Pull the current feed from every configured
                                     connector, or one connector with --source.
  verify <item-id> [--json]         Re-fetch the source named in <item-id> and
                                     confirm its current provenance.
```

Exit codes: `0` success, `1` general error, `2` no connectors configured,
`3` network error (a configured connector's fetch failed with no fallback
data), `4` a malformed or unknown `verify` item id -- documented in full in
[docs/concepts.md](https://github.com/RudrenduPaul/truesignal/blob/main/docs/concepts.md).

## Security

No connector ever `eval()`s, `exec()`s, or dynamically imports anything
read from an upstream response -- responses are only ever parsed as JSON
and mapped into typed fields. Credentials are read only from real
environment variables (`CLOUDFLARE_RADAR_API_TOKEN`, `REDDIT_CLIENT_ID`,
`REDDIT_CLIENT_SECRET`, `TELEGRAM_BOT_TOKEN`) -- never accepted as a CLI
flag, never auto-loaded from a `.env` file. To report a vulnerability, see
[SECURITY.md](https://github.com/RudrenduPaul/truesignal/blob/main/SECURITY.md).
**Honest note**: this project does not currently publish SLSA provenance,
Sigstore signatures, or an SBOM, and has no OpenSSF Scorecard badge set up
-- none of that infrastructure exists yet for either distribution, so it
isn't claimed here.

## Contributing

See [CONTRIBUTING.md](https://github.com/RudrenduPaul/truesignal/blob/main/CONTRIBUTING.md)
for the full guide, covering both the TypeScript and Python codebases.

```bash
cd python
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
```

## License

MIT, see [LICENSE](https://github.com/RudrenduPaul/truesignal/blob/main/LICENSE).
