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 runningfeed— arrived through the signed catalog feedlocal— 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:
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:
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.