> For the complete documentation index, see [llms.txt](https://help.resouris.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.resouris.com/part-2-running-resouris/install-a-licence.md).

# Install a licence

**Who:** platform admin on a self-hosted or air-gapped install. **Perm:** `platform.about.view` + shell access to the ReSouris host. **Time:** \~5 minutes for the install; longer if you also need to configure the trust anchor.

ReSouris requires a valid, signed licence to operate. A licence is a small JSON file signed with Ed25519 under the `R-LICENCE-2026` subkey, issued by the [ReSouris Licence](https://github.com/metkhoo/ReSouris-Licence-Generator) service. Without a licence installed, the platform runs in an evaluation state for 30 days from first boot and then refuses further logins.

**SaaS users:** you never install a licence manually. The SaaS instance auto-fetches your licence on the standard cron (v1.7 D1). This guide is for self-hosted and air-gapped deployments.

## Before you start

You need:

* The signed licence file, provided by ReSouris staff. Filename typically `<tenant-slug>-licence.json` or similar.
* Shell access to the ReSouris host, with `bin/rostaire-licence` on the PATH.
* The trust anchor at `dist/trust-anchor-v1.1.json` present on the host — this ships with every ReSouris release; you should not need to place it manually.

## 1. Verify the licence file's provenance

Before installing, verify the file's SHA-256 against the fingerprint ReSouris provided out-of-band (email, phone, secure portal):

```
sha256sum tenant-slug-licence.json
```

Compare the output byte-for-byte against the fingerprint from ReSouris. If the fingerprints don't match, do not install — the file may have been tampered with in transit.

## 2. Inspect (dry run)

Before committing, inspect the licence to confirm it's what you expect:

```
bin/rostaire-licence inspect --path tenant-slug-licence.json
```

The output shows:

* `licence_id`, `issued_utc`, `issued_to.display_name`.
* `deployment_mode` — **must match your install**. A self-hosted licence installed on an air-gapped host will fail verification even if the signature is valid.
* `not_before` and `not_after` — the validity window.
* `grants` — the entitlements the licence unlocks. Compare against the order confirmation.
* `revocation_check_url` — where the revocation list will be pulled from.

If any field is wrong, contact ReSouris staff before proceeding. Fixing a mis-issued licence means a re-issue, not an in-place edit.

## 3. Install

```
bin/rostaire-licence install --path tenant-slug-licence.json
```

The installer:

1. Verifies the signature against the trust anchor's `R-LICENCE-2026` subkey.
2. Verifies the RFC 8785 canonical body sha256 matches the signed hash.
3. Checks the current time is within `[not_before, not_after)`.
4. If `installation_id` is set, checks it matches this install's fingerprint.
5. Persists to the `licences` table.
6. Emits `licence.install.attempted` audit event with the outcome.

On success, the grants activate immediately. No restart needed.

## 4. Verify from the UI

Sign into `/ui/admin/about`. The **Licence** section should show:

* **Status** — green.
* **Display name** — matches your organisation.
* **Not before / Not after** — validity window.
* **Grants** — the entitlements now active.
* **Days until renewal** — count down to the `renewal_window_days_before_expiry` threshold.

If the status is red or amber, click through to `/ui/licences` for the full history — the most recent install attempt will show the reason for rejection.

## 5. First revocation-list pull (self-hosted, online)

On self-hosted installs with outbound HTTPS, the revocation-list pull cron runs daily at 03:15 UTC. On first install you can trigger it manually:

```
bin/rostaire-licence pull-revocations
```

The command:

1. Reads `revocation_check_url` from the currently-active licence body.
2. Fetches the signed revocation list.
3. Verifies the signature against the trust anchor.
4. Imports any new revocation entries.
5. Emits `licence.revocation.imported`.

## 6. Air-gapped revocation import

Air-gapped installs skip the pull. Instead, download the signed revocation list on a workstation with internet (`curl https://portal.licence.rostaire.com/revocations.json > revocations.json`), transfer via USB, and:

```
bin/rostaire-licence import-revocations --path revocations.json
```

Same signature verification path, then import.

**Watch the 30-day air-gapped-stale banner** on the admin nav — if you fall behind on revocation imports by 30+ days, the banner surfaces as a yellow warning. Not a hard block, but a signal that a revoked licence somewhere may not have been detected yet.

## 7. Renewal

Two paths depending on your deployment:

* **Self-hosted, online** — the v1.7 D1 auto-fetch cron will pull the renewed licence from `renewal.renewal_endpoint_url` on its daily schedule. You don't need to do anything.
* **Air-gapped** — before your licence expires, run the MAK-style request flow:
  1. Generate the request: `bin/rostaire-licence request --order-number <hint> --output request.json`.
  2. Transfer `request.json` to a workstation with internet.
  3. Upload to the ReSouris Licence portal's air-gap page.
  4. Wait for the approval + issuance.
  5. Download the response licence file.
  6. Transfer back to the ReSouris host.
  7. Install with the standard `bin/rostaire-licence install --path <renewed>.json`.

The expiry-warning banner (v1.7 D4) surfaces N days before expiry per the licence's own `renewal.renewal_window_days_before_expiry` field. Start the MAK dance when the banner appears, not on the expiry day.

## Common issues

* **"Signature verification failed"** — usually a trust-anchor mismatch. Check `dist/trust-anchor-v1.1.json` is present and hasn't been modified. If the file is intact but verification still fails, the licence was signed by a different subkey (possibly a dev-stage licence delivered by mistake). Contact ReSouris staff.
* **"deployment\_mode mismatch"** — the licence was issued for a different install profile. You need a re-issue.
* **"NOT\_YET\_VALID"** — the current time is before `not_before`. Check the host clock; a clock-drift alert usually accompanies this. See the deep-sleep guard automation.
* **"ALREADY\_EXPIRED"** — the current time is after `not_after`. Start the renewal flow.
* **"installation\_id mismatch"** — the licence is bound to a different install fingerprint. Either the licence was issued for a different host, or you've regenerated the installation key. ReSouris re-issue.

## What comes next

* Complete the fresh-install bring-up → [Quick start](/start-here/quick-start.md).
* Understand the licence lifecycle at the wire level → [Deployment modes](/part-2-running-resouris/deployment-modes.md).
* Verify the audit chain that the install produced → [Audit and compliance](/part-2-running-resouris/audit-and-compliance.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://help.resouris.com/part-2-running-resouris/install-a-licence.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
