Skip to main content

hyperscale-trust

Trust center for Hyperscale Django apps: a public /trust page of policy-level security claims generated from the app's data classification and the platform's published controls, a questionnaire CSV export, and a private evidence pack for auditors and buyers under NDA. Imported as hyperscale.trust.

Every claim on the page comes from the host app's data classification, this package's control catalogue, or the platform's published document — not from prose someone typed into a form — so the page cannot go stale because someone forgot to edit it. The only hand-written fields carried through trust.json are the operator name and the security contact.

Install

uv add hyperscale-trust
INSTALLED_APPS = [
    # ...
    "hyperscale.trust",
]

urlpatterns = [
    # ...
    path("trust/", include("hyperscale.trust.urls")),
]

hyperscale/trust/urls.py sets app_name = "hyperscale_trust", so including the module resolves URLs as hyperscale_trust:page etc. without an explicit namespace= (passing one is harmless).

The evidence pack's key inventory (keyset_status.json, key_rotation_events.csv) comes from hyperscale.crypto. Install it with the crypto extra:

uv add "hyperscale-trust[crypto]"

Without it — or before its tables are migrated — the pack still builds; those two files just report that the key inventory is unavailable rather than being omitted (see The evidence pack).

Settings

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

HYPERSCALE_TRUST = {
    "trust_json_path": BASE_DIR / "trust.json",  # required
    "snapshot_path": BASE_DIR / "platform-controls.json",  # required
}
Key Default Meaning
trust_json_path none (required) path to the app's trust.json
snapshot_path none (required) path to the build-time platform-document snapshot
document_url "" URL to fetch the live platform document from; empty means never fetch — always serve the snapshot
cache_seconds 86400 how long a successful platform-document fetch is cached
evidence_permission "hyperscale.trust.permissions.superuser_only" dotted path to a Callable[[HttpRequest], bool] deciding who may open the evidence pack

An unknown key, a missing trust_json_path/snapshot_path, a non-positive cache_seconds, or an evidence_permission path that doesn't import to a callable all raise ImproperlyConfigured. This is checked in AppConfig.ready(), so a bad setting fails at Django startup, not on the first request.

The default evidence_permission, hyperscale.trust.permissions.superuser_only, is True only for an authenticated Django superuser. Supply your own dotted path to gate the evidence pack on an app-specific owner or admin role instead.

URLs

Name Path Access
hyperscale_trust:page /trust/ public
hyperscale_trust:questionnaire /trust/questionnaire.csv public
hyperscale_trust:evidence /trust/evidence/ login + evidence_permission
hyperscale_trust:evidence_zip /trust/evidence.zip login + evidence_permission

(Paths shown are the conventional mount point above; the host app chooses where to include() the URLconf.)

When trust.json's app.enabled is false (or trust.json itself is missing or malformed), the public routes 404, and the evidence routes 404 once the caller is logged in (anonymous callers are redirected to LOGIN_URL first) — a disabled trust center gives no sign of what it would otherwise contain. The evidence routes are checked in this order: an unauthenticated request is redirected to LOGIN_URL first; an authenticated request against a disabled trust center 404s; only then is evidence_permission consulted, raising PermissionDenied (403) if it returns False. This ordering means a disabled center never reveals whether the caller would have been authorised.

What the page shows, and what it deliberately does not

GET /trust/ renders, in order: an overview (app name and description, operator and security contact — each labelled "Declared by the operator", since they're the only founder-supplied inputs — region, and the date the page's source was generated); the data categories processed and how each is handled, plus a negative claim for every category the app doesn't process; the controls that protect that data (app-specific and platform, each with an ISO 27001:2022 Annex A reference, labelled "Enforced by the platform"); the cryptography policy in prose (algorithms, key custody, rotation, transport); the subprocessor list; and the operator's own responsibilities (such as a DPIA) that the data categories imply.

It deliberately carries no category or control ids, no row or attribute counts, no key ids or rotation dates, no deployment identifiers, and no canary results — only two ISO dates ever appear: trust.json's generated_at (as "last updated on …") and, whenever the page is rendered from the bundled snapshot rather than a live fetch (the default when document_url is unset, and also the fallback after a failed fetch), that snapshot's published_at, shown as a "Platform information as of …" badge so a stale or never-fetched document is visible rather than served as current without comment. GET /trust/questionnaire.csv carries the same restriction — it is the same catalogue, exported as question,answer,annex_a,source rows, one per control and per data-category question plus rows for region, operator, contact and subprocessors.

Templates

trust.html and evidence.html both {% extends "base_anonymous.html" %} and use only the title and content blocks — the host app must supply base_anonymous.html. Markup uses DaisyUI class names (card, badge, table, btn) but renders sensibly without DaisyUI or Tailwind loaded.

trust.json

Produced by the host app (App Studio's build_bundle, for a generated app) and shipped next to the app. Full shape and the rules behind it are in the design spec: docs/superpowers/specs/2026-09-24-trust-center-design.md. A worked example is in tests/fixtures/trust.full.json. Excerpt:

{
  "generated_at": "2026-09-24T12:00:00Z",
  "app": {"name": "Clinic Notes", "operator_name": "Acme Health Ltd", "enabled": true},
  "data": {
    "categories": [
      {"id": "health", "label": "Health", "definition": "…", "level": "restricted", "handling": "…", "attribute_count": 2, "models": ["Patient"]}
    ],
    "not_processed": [{"id": "payment_card", "label": "Payment card"}],
    "free_text_attribute_count": 3
  },
  "controls": [{"id": "app.encryption.restricted", "annex_a": "A.8.24"}],
  "levels": {"restricted": "Encrypted by the application before storage, …"}
}

Two things worth calling out because they're easy to get wrong:

  • Each category may carry its own definition and handling prose, and the top-level levels map gives each sensitivity level a plain description — this is the host app's classification vocabulary, copied in so the package owns no category wording. not_processed is a list of {id, label} objects, not a list of ids.
  • The package's catalogue (hyperscale.trust.catalogue.APP_CONTROLS) is authoritative for a control's Annex A reference, title, statement, question and answer, looked up by id. The annex_a value on a control entry in trust.json itself is informational only and is not rendered.

The platform document and the snapshot

hyperscale.trust.documents.PlatformDocument — version, published_at, region, hosting_provider, email_provider and a list of controls (id, title, statement, annex_a) — either fetched live from HYPERSCALE_TRUST["document_url"] or loaded from the on-disk snapshot_path. See tests/fixtures/platform-controls.json for a complete example.

  • document_url unset (the default): the snapshot at snapshot_path is loaded fresh on every request; nothing is fetched over the network.
  • document_url set: a successful fetch (5-second timeout) is cached under a fixed key for cache_seconds (default 24 hours) before it is fetched again.
  • A failed fetch — network error, non-200 status, invalid JSON, or a document missing a required field — falls back to the on-disk snapshot. That fallback is itself cached, but only for min(300, cache_seconds) seconds: long enough that a dead document_url doesn't pay the fetch timeout on every request, short enough to retry soon after the upstream recovers.
  • A document served from the snapshot (whether because document_url is unset, or as a fallback) is marked stale. The public page then shows a "Platform information as of <published_at>" badge, and the evidence pack's platform-controls.json carries "stale_snapshot": true and an explanatory note.

The evidence pack

GET /trust/evidence/ (an HTML summary) and GET /trust/evidence.zip (the download) are gated on login plus evidence_permission — the app's owner, admin, or whoever the host app's callable decides; by default, a Django superuser. The zip contains:

File Contents
README.md index of the other files and which Annex A control each evidences
cryptography-policy.md the cryptography policy rendered as a document, with the operator name and date
keyset_status.json hyperscale.crypto's live key inventory (statuses, last rotation, canary result), or {"unavailable": "<reason>"} if hyperscale.crypto isn't installed or its tables aren't migrated
key_rotation_events.csv every recorded KeyRotationEvent, or a single row explaining why none could be read
platform-controls.json the whole platform document as fetched or loaded, plus stale_snapshot and, when stale, a note
classification.json Data categories processed, with their sensitivity levels and the level definitions
deployment.json GIT_SHA, DEPLOYED_AT, and installed versions of hyperscale-trust, hyperscale-crypto and django

The spec also lists a per-attribute classification export; that is not yet part of the trust.json contract, so classification.json carries category aggregates until App Studio exports it.

keyset_status.json and key_rotation_events.csv never disappear from the pack just because hyperscale.crypto is absent or not yet migrated — the failure is recorded in the file instead, so an auditor sees why evidence is missing rather than a shorter zip.

Environment

GIT_SHA and DEPLOYED_AT are read from the process environment (os.environ) when the evidence pack is built and written into deployment.json; they default to an empty string when unset. Neither ever appears on the public page — only inside the evidence pack.

Wording policy

Control titles, statements, questions, answers (in hyperscale.trust.catalogue) and the cryptography-policy paragraphs are vendor-neutral: a reviewer reads "FIPS 140-3 validated key management service", never a product name. tests/test_catalogue.py asserts none of that prose contains a name from catalogue.VENDOR_DENY_LIST (currently AWS, Amazon, KMS, Secrets Manager, RDS, CloudFront, S3, Stripe, Anthropic). The one place a vendor is named is the subprocessor list, resolved from the platform document's hosting_provider/email_provider or from names the host app declares in trust.json — subprocessor lists must name who they are.

Development

Requires uv and Python 3.14+.

uv sync                             # create the venv and install dependencies
uv run pytest                       # run the tests
uv run pre-commit run --all-files   # lint, format and lockfile checks

See CONTRIBUTING.md for the full set of checks.

Releasing

Bump version in pyproject.toml and __version__ in src/hyperscale/trust/__init__.py, update CHANGELOG.md, then publish a GitHub release tagged v<version>. The publish workflow checks the tag matches the package version, builds, runs twine check and publishes to PyPI with trusted publishing.

Before the first release, register the project on PyPI with this repository and publish.yml as a trusted publisher, and create a pypi environment in the repository settings.

Design

Design spec: docs/superpowers/specs/2026-09-24-trust-center-design.md

Implementation plan: docs/superpowers/plans/2026-09-25-hyperscale-trust.md

License

MIT. See LICENSE.

Release files for hyperscale-trust 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hyperscale-trust 0.1.0
File Size Uploaded
hyperscale_trust-0.1.0.tar.gz 18.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hyperscale-trust 0.1.0
File Interpreter ABI Platform
hyperscale_trust-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 43.1 kB

Release files / hyperscale_trust-0.1.0.tar.gz

Download URL hyperscale_trust-0.1.0.tar.gz
Size 18.8 kB
Tags Source
SHA-256 checksum
How to use checksums
97cc1a3510baf108899fa874337082cfb1bb51c15a2172ee0e7bb76507a1ab52
BLAKE2b-256 checksum
How to use checksums
1359e3e0fc533c56a26644f0390e4fa1fae4b51722c8984f5884201b293683db
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release files / hyperscale_trust-0.1.0-py3-none-any.whl

Download URL hyperscale_trust-0.1.0-py3-none-any.whl
Size 24.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
778b2cf8a72826eab51cb6a7790e3b56e6ad55ee7fa8d697f60d67ec38799afe
BLAKE2b-256 checksum
How to use checksums
fd9a1f99df8cf53be423ad4a5bf6e58299ec293ce99c142d35705535a8b1e872
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page