Metadata-Version: 2.4
Name: openmv-ota
Version: 1.0.0
Summary: Secure over-the-air update tooling for OpenMV cameras (ROMFS OTA, with room for firmware/bootloader OTA).
Author-email: OpenMV <openmv@openmv.io>
License-Expression: MIT
Project-URL: Homepage, https://github.com/openmv/openmv-ota
Project-URL: Source, https://github.com/openmv/openmv-ota
Project-URL: Issues, https://github.com/openmv/openmv-ota/issues
Keywords: openmv,ota,romfs,firmware,update,ecdsa,embedded
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Embedded Systems
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography>=42
Requires-Dist: pyserial>=3.5
Requires-Dist: mpremote>=1.20
Requires-Dist: httpx>=0.27
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-cov>=4; extra == "dev"
Requires-Dist: pytest-xdist>=3; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: hypothesis>=6; extra == "dev"
Provides-Extra: server
Requires-Dist: fastapi>=0.110; extra == "server"
Requires-Dist: uvicorn[standard]>=0.29; extra == "server"
Requires-Dist: pydantic-settings>=2; extra == "server"
Requires-Dist: python-multipart>=0.0.9; extra == "server"
Provides-Extra: server-s3
Requires-Dist: boto3>=1.34; extra == "server-s3"
Provides-Extra: server-postgres
Requires-Dist: psycopg[binary,pool]>=3.1; extra == "server-postgres"
Provides-Extra: hsm
Requires-Dist: python-pkcs11>=0.7; extra == "hsm"
Provides-Extra: aws-kms
Requires-Dist: boto3[crt]>=1.34; extra == "aws-kms"
Provides-Extra: gcp-kms
Requires-Dist: google-cloud-kms>=2; extra == "gcp-kms"
Provides-Extra: azure-kms
Requires-Dist: azure-keyvault-keys>=4; extra == "azure-kms"
Requires-Dist: azure-identity>=1; extra == "azure-kms"
Dynamic: license-file

<p align="center">
  <img src="docs/under-construction.svg" width="100%" alt="Under Construction — this project is a work in progress">
</p>

[![CI](https://github.com/openmv/openmv-ota/actions/workflows/ci.yml/badge.svg)](https://github.com/openmv/openmv-ota/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/openmv/openmv-ota/graph/badge.svg?token=KNAA28U57K)](https://codecov.io/gh/openmv/openmv-ota)
[![GitHub license](https://img.shields.io/github/license/openmv/openmv-ota?label=license%20%E2%9A%96)](https://github.com/openmv/openmv-ota/blob/main/LICENSE)
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/openmv/openmv-ota?sort=semver)
[![GitHub forks](https://img.shields.io/github/forks/openmv/openmv-ota?color=green)](https://github.com/openmv/openmv-ota/network)
[![GitHub stars](https://img.shields.io/github/stars/openmv/openmv-ota?color=yellow)](https://github.com/openmv/openmv-ota/stargazers)
[![GitHub issues](https://img.shields.io/github/issues/openmv/openmv-ota?color=orange)](https://github.com/openmv/openmv-ota/issues)

<img  width="480" src="https://raw.githubusercontent.com/openmv/openmv-media/master/logos/openmv-logo/logo.png">

# OpenMV OTA

Secure over-the-air updates for OpenMV cameras: build your application into a
signed ROMFS image, publish it, and a camera downloads, verifies, and installs
it — falling back to the last release that worked if anything goes wrong.

What a camera downloads is **encrypted**, under a key minted with the project and
baked into your own firmware, so a published release is ciphertext to the update
server, to the store it sits in, and to anyone who gets hold of it.

**Start with the [tutorial](https://github.com/openmv/openmv-ota/blob/main/docs/tutorial/00-introduction.md)** — the complete,
navigable reference for every command and the update server's HTTP API, in the
order you use them: install → project → build → flash → device runtime → update
server. The command documentation lives there and only there, so it has one
place to be right.

Shipping in the EU? [The compliance mapping](https://github.com/openmv/openmv-ota/blob/main/docs/compliance/cra-red-alignment.md)
lays out how this stack lines up with the Cyber Resilience Act and RED 3.3 —
what's covered, and the [residual threats](https://github.com/openmv/openmv-ota/blob/main/docs/compliance/residual-threats.md)
that aren't — and `project new --ota` scaffolds the fill-in templates
(conformity checklist, EU DoC, disclosure policy, security.txt) into your
project's `compliance/`. Found a vulnerability in this stack itself? See
[the security policy](https://github.com/openmv/openmv-ota/blob/main/SECURITY.md).

## Installation

> Not yet published. Once the package lands on PyPI, all tools install together:

```bash
pip install openmv-ota
```

For development, install from a checkout:

```bash
pip install -e .
```

## Contributing to the project

Contributions are most welcome. If you are interested in contributing to the project, start by creating a fork of the repository:

* https://github.com/openmv/openmv-ota.git

Clone the forked repository, and add a remote to the main openmv-ota repository:
```bash
git clone https://github.com/<username>/openmv-ota.git
git -C openmv-ota remote add upstream https://github.com/openmv/openmv-ota.git
```

Now the repository is ready for pull requests. To send a pull request, create a new feature branch and push it to origin, and use Github to create the pull request from the forked repository to the upstream openmv/openmv-ota repository. For example:
```bash
git checkout -b <some_branch_name>
<commit changes>
git push origin -u <some_branch_name>
```

### Contribution guidelines
Please follow the [best practices](https://developers.google.com/blockly/guides/modify/contribute/write_a_good_pr) when sending pull requests upstream. In general, the pull request should:
* Fix one problem. Don't try to tackle multiple issues at once.
* Split the changes into logical groups using git commits.
* Pull request title should be less than 78 characters, and match this pattern:
  * `<scope>:<1 space><description><.>`
* Commit subject line should be less than 78 characters, and match this pattern:
  * `<scope>:<1 space><description><.>`
