Documentation for v2.9.0. Read the latest, v2.12.0.

Reference

Corporate best practices

Sanshain's rules are the same for one team and for two hundred. What changes at scale is how much of the setup is decided once, centrally, so that no repository has to be touched when the server moves, a token expires or a release policy changes. These are the practices that keep a large installation flexible, safe and maintainable.

What changed in 2.6.0

  • Webhooks notify teams of publishes, rejections and cuts; receivers must be on an admin-managed allow-list.
  • The catalog push also records the owner, description and links of a system, so the graph shows who owns what.
  • Backup: a consistent SQLite snapshot on request and a Helm CronJob for either engine.

In short#

  1. Environment over hardcoding: leave sanshainUrl out of sanshain.yaml; the URL and the token come from CI variables.
  2. Tokens with a scope and an expiry: full for pipelines, read_only for AI assistants, never in version control.
  3. Releases gated twice: the ga switch only on the protected-branch pipeline, the releaser role only on the accounts that pipeline uses.
  4. Honest versions: take the server's proposed version on a 409, never work around it.
  5. The directory decides who is who: LDAP/AD or OIDC for people, groups mirrored to roles, a root account outside the database.
  6. Production infrastructure: PostgreSQL, backups, metrics, webhooks on an allow-list, a verified image.

Configuration from the environment#

Hardcoding the server URL in every project's sanshain.yaml means editing hundreds of repositories when the instance moves. Every client reads the URL and the token from the environment instead:

Tokens with a scope and an expiry#

Machine clients authenticate with an API token, a credential a user mints for themselves on the account page. Three properties matter at scale:

Tokens never travel in a URL; the Authorization header is the only place the service reads them from, so they do not end up in proxy logs or referrers. See Using the API.

Releases gated by pipeline and role#

Sanshain never sees a git repository. Whether a build publishes a snapshot or a GA is declared by the build, and two independent gates keep that declaration honest:

Consumers can opt into a snapshot by pinning its number; the dependency graph flags them as snapshot-pinned, so a release review can find every system that would ship against unreleased work.

Honest versions and breaking changes#

A pinned Consumer can never be broken by a new version; Sanshain's job is to keep the numbers honest, so that a Consumer deciding on an upgrade can trust what they claim. A GA whose changes are breaking without a major bump, or that reuses a number with different content, is refused with 409 and a proposed version.

Ownership from the catalog#

In a large graph the question is rarely "what depends on this" but "whom do I call". Let every build push its Backstage catalog-info.yaml (catalogInfo in sanshain.yaml, or PUT /catalog/{systemname}): the owner, description, source location and links appear as the system's catalog context on its page and in the graph's node panel, and the databases, buckets and queues it lists under dependsOn appear as peripheral resources shared between the systems that use them. Teams that already maintain a catalog file get this for free; for the others, the file is a few lines. See The catalog phase.

Notifications through webhooks#

Instead of polling the graph, let the service tell the teams: a webhook delivers signed events (a version published or deprecated, a provide rejected, a new Consumer recorded, a sanshain-branch cut, a catalog push) as a JSON envelope or a ready-made Slack or Teams message.

Events are written to an outbox with the fact they describe and retried for 24 hours, so a receiver that is down over a weekend still gets its events. See Webhooks.

People from the directory, roles from groups#

Production infrastructure#

Checked against v2.6.0.