Help us shape the future of Go! Take the 2026 Go Developer Survey

policy

package module
v1.55.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2026 License: MIT Imports: 1 Imported by: 0

README

policy

The engineering contracts a service is held to: how it is configured, how it starts and stops, how it is built and released — and one worked example that runs them, in its own repository (truvity/url-shortener).

A contract here is short, normative and testable. The reasoning lives beside it as a decision record, the allowed libraries as a canon, and the whole thing is proven by an example service, kept in its own repository, rather than by assertion.

What ships

Artifact Where Published as
the contracts, canons, guides, decisions and glossary docs/ the tagged source
configuration schemas (JSON Schema) schemas/ the tagged source, and inside every loader
the Go configuration loader, conformance helpers and chart schema composer config/, conformance/, chartschema/ Go module github.com/truvity/policy
the TypeScript, Python and Kotlin loaders ts/, python/, kotlin/ in the url-shortener repository moved there on 2026-10-22; this repository no longer publishes @truvity/policy or the wheel (versions up to v1.54.2 stay where they were published)
the shared lint configuration lint/ the tagged source, copied into a repository
the local cluster the example is tested on hack/kind/ the tagged source, fetched at a pinned tag
the library chart service charts render with charts/service-lib chart service-lib under oci://ghcr.io/truvity/charts; embedded for tests by the Go package charts/
the worked example, a URL shortener truvity/url-shortener moved there on 2026-10-22: charts url-shortener and url-shortener-infra under oci://ghcr.io/truvity/charts, released from that repository's own tags (up to v1.54.2 they were released from here, images under ghcr.io/truvity/policy/url-shortener/)

One tag stamps all of them: vX.Y.Z releases the documents, the schemas, the Go module and the library chart together. A consumer pins one version.

Who it is for

A team running services on Kubernetes that wants the same shape in every repository and every language, without a framework in the way. The contracts bind at the process boundary — a configuration file, a set of probe endpoints, a log format, a signal — so a Go service, a Node service and a JVM service satisfy them the same way and share no code.

The component contract extends the same idea to the repositories that ship mechanism rather than services — charts, images, Go libraries, CLIs, actions — so that every public repository an estate consumes looks the same from the outside.

It deliberately does not ship a framework, a dependency-injection container, a code generator or a base image. The example is the reference implementation; there is nothing to import in order to conform.

This repository is itself public, for the reasons in 0004; a private repository consumes the same contracts and the same libraries, with a different gate and a different release destination — see docs/guides/private-consumer.md.

The model

Three things, in order of how much they bind:

  • Contracts (docs/contracts/) are normative. Each one is short enough to read in a sitting, carries a version, and has a conformance section saying how it is checked mechanically.
  • Canons (docs/canon/) are the allowed lists: which libraries, which toolchain versions, which build tools, and the scope they apply to.
  • Guides (docs/guides/) are how to satisfy the contracts, walking the example.

Decisions (docs/decisions/) record why a contract reads the way it does. They are never edited after acceptance; they are superseded by a later one that links back. The glossary pins down the words the documents use narrowly — estate, platform, ring, tier, lane.

Install and a worked example

Pin one version; every artifact carries the same one. v1.29.0 is the latest tag at the time of writing — the releases page lists every one.

go get github.com/truvity/policy@v1.29.0

The TypeScript, Python and Kotlin loaders are not installed from here any more: they moved to the url-shortener repository together with the example that consumes them.

A Go service loads its configuration in three lines, and a misconfiguration is refused before anything is constructed:

var cfg Config
if err := config.Load(path, schemaBytes, &cfg); err != nil {
    return err // names the file and every failing key
}

The worked example runs every contract end to end, and its application chart renders from the release with only the names it refuses to guess — the database's host, the root its certificate chains to and the two Secrets holding its credentials, the broker, the bucket:

# values.yaml
database:
  host: pg
  tls:
    rootCA:
      configMapName: pg-root-ca
  owner:
    passwordSecret: owner
  app:
    passwordSecret: app
events:
  url: nats://nats:4222
archive:
  bucket:
    name: archive
helm template example oci://ghcr.io/truvity/charts/url-shortener --version 1.29.0 -f values.yaml

What provides those names is the infrastructure chart's job, installed per install beside it (platform.md §11); the example's README walks what each component proves.

Consumers

The repositories that consume a release, and through which surface. No versions: each consumer's own pin is the record of that.

Consumer Surface
truvity/ci-actions the cluster action fetches hack/kind/ at a pinned release tag
14 repositories copy lint/golangci-depguard.yaml into their .golangci.yaml
truvity/gitops deploys the url-shortener example's charts (released from the url-shortener repository)
every public component repository is held to the component contract

Neighbours

  • ci-workflows runs this repository's gate (check.yaml), its release (release-public.yaml) and the cluster lane of any repository that calls it (integration.yaml, whose kind tier stands up hack/kind/ at the policy-version it is given).
  • ci-actions holds the cluster action that fetches hack/kind/ from a policy release; the box is defined here and nowhere else.
  • gemaal provides the harness package the url-shortener example's end-to-end suite reaches every Service through.
  • ocictl provides helmctl, which bakes image digests into the url-shortener example's charts at its release.
  • Every other public component repository is held to the contracts here; component.md lists them.

Documentation

docs/ is the index, by audience: authoring a service, authoring a component, reviewing one, operating one. docs/landscape.md is the other direction: one page naming every public repository the contracts below apply to today, and how they fit together. The contracts:

  • repository — layout, toolchain, the gate
  • service — the process boundary
  • config — one typed configuration per binary
  • platform — what a service asks of what runs it
  • delivery interface — the one number a chart declares so a platform hands it only what it can take
  • release — one tag, what a version means
  • component — the rules C1–C18 for every public repository that ships charts, images, libraries, CLIs or actions

The rule that makes this repository public

Mechanism only. Nothing here names an organisation, an account, a cluster, a hostname, an environment, a team, a person, an internal repository or a ticket. Every such thing is an input with a neutral default, supplied by the consuming estate from its own private repository. hack/leak-canary.sh enforces the mechanical part of that rule on every commit and in CI; the rest is a review rule.

The one exception is Consumers: it names a consuming repository and the surface it uses, and never a version, an environment or a cluster (component.md C8).

Status

Used in production by its maintainers. Released from v0.1.0; tags follow semver from v1.25.0 (release.md §2). Every contract is at version 1.0, effective 2026-09-29.

In progress: the url-shortener's data contracts are also written in Pkl and generated beside the hand-written schemas, which stay authoritative (guides/pkl-shadow.md: the shadow phase of decision 0010), in the url-shortener repository.

What is not done: two guides — keys and signing, and migrating off a framework — arrive with the component that proves them (guides/README.md).

Development

devbox shell   # or direnv, which does it on cd
just check     # the gate: exactly what CI runs
just example-canary   # build and test the url-shortener example against this checkout

just check needs no credentials, no container runtime and no cluster. The cluster tier needs a container runtime, stands up a local cluster (hack/kind/); the example installs onto it from the same artifacts a release publishes, from its own repository:

just cluster          # the box: about a minute from nothing
just cluster-verify   # ask each server a real question
just cluster-down     # remove it

AGENTS.md is the entry point for anyone — or anything — arriving without context: what to read first, what the gate checks that surprises people, and the separate set of rules for bringing another repository to this shape.

Releasing

Manual tags: every first release, minor and major is a tag pushed by a person after the CHANGELOG heading for that version has merged (release.md §4). Automatic patch releases are cut by a bot and need no CHANGELOG heading: their notes are the GitHub release's, and the next hand-cut heading covers them.

Licence

MIT. See LICENSE.

Documentation

Overview

Package policy publishes the configuration shapes these contracts define, and nothing else. The loaders are in the packages beside it.

Index

Constants

View Source
const SchemaBase = "https://github.com/truvity/policy/schemas/"

SchemaBase is the prefix every `$id` in Schemas carries. A document at `schemas/fragments/log.json` is identified by SchemaBase + "fragments/log.json".

Variables

View Source
var Schemas embed.FS

Schemas holds the shared configuration schemas, rooted at `schemas/`.

They are embedded rather than fetched: a `$id` in this repository is an identifier, not an address. Validation therefore needs no network, works in a test with no egress, and pins the shapes to the version of this module a service depends on.

Functions

This section is empty.

Types

This section is empty.

Directories

Path Synopsis
Package charts carries the library chart, so that the tests of every chart that depends on it render the library as it stands in this tree.
Package charts carries the library chart, so that the tests of every chart that depends on it render the library as it stands in this tree.
Package chartschema composes the values schema of a service chart.
Package chartschema composes the values schema of a service chart.
Package config loads a service's configuration: read one file, validate it against a schema, decode it into a type, and stop.
Package config loads a service's configuration: read one file, validate it against a schema, decode it into a type, and stop.
Package conformance holds the test helpers that make the configuration contract checkable, so that a service and the chart that deploys it are held to one schema rather than to two beliefs about it.
Package conformance holds the test helpers that make the configuration contract checkable, so that a service and the chart that deploys it are held to one schema rather than to two beliefs about it.
hack
compose-chart-schema command
Command compose-chart-schema writes the values schema of every service chart under a directory: for each `values.schema.src.json` it finds, the composed `values.schema.json` beside it (see package chartschema).
Command compose-chart-schema writes the values schema of every service chart under a directory: for each `values.schema.src.json` it finds, the composed `values.schema.json` beside it (see package chartschema).
Package telemetry starts the OpenTelemetry SDK from OpenTelemetry's own environment, and stops it cleanly.
Package telemetry starts the OpenTelemetry SDK from OpenTelemetry's own environment, and stops it cleanly.
Package transport turns the `tls` fragment of a service's configuration into the two TLS configurations a service needs: one for the listener it serves, one for the connections it makes.
Package transport turns the `tls` fragment of a service's configuration into the two TLS configurations a service needs: one for the listener it serves, one for the connections it makes.
catalog
Package catalog is the who-calls-whom catalog for workload mutual TLS: for each callee (a component of a project's chart that exposes `tls.peers.<component>`, see the `tls` fragment) the identities outside its own release that may call it, per environment.
Package catalog is the who-calls-whom catalog for workload mutual TLS: for each callee (a component of a project's chart that exposes `tls.peers.<component>`, see the `tls` fragment) the identities outside its own release that may call it, per environment.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL