Skip to content

Profiles and tiers

A profile is a per-service read-only allowlist: every tool the vendor exposes, each with an explicit verdict, a tier and a classification. They are public, readable, and live in prodpeek/profiles under Apache-2.0.

What one looks like

spec:
  service: coolify
  tier: 2
  tools:
    - name: list_applications
      verdict: allow
      tier: 1
      classification: pure_read
      note: Inventory of deployed applications and their status.

    - name: get_application_envs
      verdict: deny
      classification: read_leaks
      note: >
        Returns an application's environment variables. This is the read that
        hands over your database password.

    - name: deploy_application
      verdict: deny
      classification: write
      note: Triggers a deployment.

Three things to notice. Every tool is named explicitly — absence is denial, so anything not here is refused. get_application_envs is a genuine read and is denied anyway. And each verdict carries a note saying why, because a policy nobody can read is a policy nobody can check.

Tiers

Tier 1 — the credential itself cannot write. A Coolify read-only token with read-sensitive off, a non-superuser Postgres role, a fine-grained GitHub token. Prodpeek is the second fence; if it had a bug, the credential would still refuse.

Tier 2 — Prodpeek is the only fence, because the vendor's credential is coarse or absent. Prometheus has no authentication at all. Grafana's service account roles are broad.

The service tier is derived, not declared: it is the worst tier among the tools the profile actually allows. The loader refuses a file whose declared tier flatters its tools.

An honest Tier 2 is worth more than an unprovable Tier 1. prodpeek prove asks each vendor what your credential can really do, and a "can write" answer demotes the service and tells you.

Classifications

pure_read A GET, no side effects
read_with_side_effects Reads, but creates a snapshot, annotation or audit artifact
read_leaks A genuine read whose output is the risk
write Mutates
unknown Not yet reviewed — and therefore denied

read_leaks is the one a generic read-only proxy cannot do, because it requires someone to have looked at each tool and decided. It is also an AI egress rule: the output of a read_leaks tool is never sent to an LLM, whatever a project opted into.

Note that read_leaks is a classification, not a verdict. A log reader can legitimately be allowed — an operator needs logs — while its output must never reach a model. What it may not be is Tier 1: no credential can refuse to leak what an application already wrote into its own log.

Verification levels

community Submitted, lints pass, nothing else
reviewed Source review plus a replay against a recorded tool list. No live run
verified The live harness ran against a testbed, with the mutation oracle

Every profile in the catalog today is community. None claims a badge it has not earned, and verified is set by an ingested attestation rather than typed into a file.

Provenance

Where a profile came from, set by the loader and rejected if a file tries to declare it — a file that could call itself trusted would not be worth trusting.

  • catalog — bundled into the release you are running
  • feed — arrived through the signed catalog feed
  • local — a directory on your own disk

Narrowing a profile yourself

You can make a policy stricter locally. Put a file in data/profiles/ with the same metadata.name:

PRODPEEK_PROFILES_DIR=/etc/prodpeek/profiles.d

An allow may become a deny; constraints may tighten. A local profile that would widen anything is refused at load with the offending tool named:

In the logs
refusing local profile /etc/prodpeek/profiles.d/coolify.yaml: it would WIDEN
coolify/read-only. get_application_envs: coolify/read-only denies this tool and
the local profile allows it — a local profile may remove permissions, never add them.

You may distrust us further than we distrust ourselves. You may not use a file on your own disk to grant what the published policy refused — because the moment that is possible, "read the profile" stops being a way to know what an instance permits.

A local profile also never carries the verified badge, whatever its file says. The badge means a harness of ours ran against a testbed, and no file on your disk can make that true.

Contributing one

Open a pull request on prodpeek/profiles. CI runs verifier lint and a replay against a recorded tool list on every PR, including from a fork — neither needs a credential. The live harness runs only from main, on one runner.

That split is what lets the repository be genuinely open without the verification results being forgeable: anyone can propose a profile, and only one machine can say it was verified.