Metadata-Version: 2.4
Name: umarise-s3
Version: 0.2.0
Summary: Anchor every S3 upload to Bitcoin. Async, with retry queue and reconciliation ledger.
Author-email: Umarise <partners@umarise.com>
License: Unlicense
Project-URL: Homepage, https://umarise.com
Project-URL: Documentation, https://umarise.com/api-reference
Project-URL: Repository, https://github.com/AnchoringTrust/umarise-s3
Keywords: umarise,s3,akave,anchoring,bitcoin,proof-of-existence
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Security :: Cryptography
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: umarise-core-sdk>=1.1.0
Requires-Dist: boto3>=1.20

# umarise-s3

Anchor every S3 upload to Bitcoin. Works with any S3-compatible backend.

```
pip install umarise-s3
```

## Quick start

```python
from umarise_s3 import AnchoredS3Client

# Works with Akave, AWS S3, MinIO, GCS, etc.
s3 = AnchoredS3Client(
    endpoint_url="https://o3.akave.xyz",  # or any S3-compatible endpoint
    aws_access_key_id="your_key",
    aws_secret_access_key="your_secret",
)

# Every upload is automatically anchored (async — zero latency overhead)
s3.upload_file("model.pt", "my-bucket", "models/model.pt")
s3.put_object(Bucket="my-bucket", Key="data.csv", Body=open("data.csv", "rb").read())
```

## What happens

1. File is uploaded to your S3 backend (unchanged)
2. SHA-256 hash is computed locally (bytes never leave your machine)
3. Hash is submitted **async** to Umarise Core API (fire-and-forget)
4. `origin_id` is stored as S3 object metadata (`x-amz-meta-umarise-origin-id`)
5. Every event is logged to a local **reconciliation ledger** (`~/.umarise/ledger.db`)
6. Within ~12 hours, proof is confirmed on the Bitcoin blockchain

## v0.2.0 — Production-ready

### Async anchoring (fire-and-forget)

Uploads return **immediately**. Anchoring happens in a background thread with automatic retry (3 attempts, exponential backoff).

```python
# Default: async (zero latency overhead)
s3 = AnchoredS3Client(endpoint_url="...")

# Legacy: synchronous (v0.1.0 behavior)
s3 = AnchoredS3Client(endpoint_url="...", sync=True)
```

### Reconciliation ledger

Every anchor event is logged locally in SQLite. If metadata writes fail, the link between file and proof is never lost.

```python
# Check status
print(s3.ledger.stats())
# {'total': 42, 'anchored': 40, 'metadata_pending': 1, 'failed': 1}

# Find entries where metadata write failed
failed = s3.ledger.get_failed_metadata()

# Look up a specific object
records = s3.ledger.lookup("my-bucket", "models/model.pt")

# Custom ledger location
s3 = AnchoredS3Client(ledger_path="/var/log/umarise/ledger.db")
```

### Graceful shutdown

```python
# Wait for all pending anchors to complete before exit
s3.flush(timeout=10.0)
print(f"Pending: {s3.pending_anchors}")
```

## S3 metadata written

| Metadata key | Value |
|---|---|
| `umarise-origin-id` | UUID |
| `umarise-proof-status` | `pending` or `anchored` |
| `umarise-hash` | SHA-256 hex |

## Environment

```bash
export UMARISE_API_KEY=um_your_key
export UMARISE_LEDGER_PATH=/custom/path/ledger.db  # optional
```

Or pass `api_key=` and `ledger_path=` to `AnchoredS3Client()`.

## Compatible backends

- [Akave Cloud](https://akave.com) (S3-compatible, decentralized)
- AWS S3
- MinIO
- Google Cloud Storage (S3-compatible mode)
- Any S3-compatible endpoint

## Verify independently

The proof is yours. Verify without Umarise:
- [verify-anchoring.org](https://verify-anchoring.org)
- `ots verify proof.ots`

## License

[Unlicense](https://unlicense.org/) — Public Domain
