Repository navigation
Releases
Releases · fyannk/pgToolBox
pgToolBox v0.1.0-rc.1
The first public release: a console, an optional operator and an evidence agent
for CloudNativePG 1.30 and later, on Kubernetes and
OpenShift.
Known limitation: with NetworkPolicy enabled and no trusted proxy addresses set, the
console trusts X-Forwarded-For from the peers its policy admits. On a network plugin that
does not enforce NetworkPolicy, set console.trustedProxyCIDRs (or
spec.exposure.trustedProxy.cidrs): otherwise any pod can fake the client address seen by
the per-address sign-in limits and the audit log (identity is not affected).
Added
- The console, installed once per team namespace by the
pgtoolschart or
declared as aPgToolBoxConsole. It shows the CloudNativePG Clusters of the
namespaces it watches: an overview with the sources and blind spots each verdict
rests on, instances as the operator, the Pod and the instance's own/pg/status
report them, replication and a failover rehearsal, storage with a forecast of
when each volume fills, backups next to the repository evidence, diagnostics
and triage, events, a revision history with structural diffs, an incident
timeline, logs, metrics (built-in or from Prometheus), the declarative objects,
the topology, and two Clusters side by side. - Authorization by the API server. People sign in with OIDC, OpenShift OAuth
or a pasted API-server token; every read is checked with a
SelfSubjectAccessReview sent with the person's own token. The console stores
no level, role or group of its own. - Four operations (backup, reload, restart, promote), off unless enabled,
each sent to the API server with the signed-in person's token, plus opt-in
restore drills that restore the latest backup into a throwaway Cluster, check
it and delete it. - Access requests (
PgAccessRequest): a person asks for a role in the
console, someone who may grant it approves, and the grant is a RoleBinding the
operator removes when the request expires or is revoked. - An MCP endpoint (
/mcp, off by default, read-only unless its write tools
are enabled) that serves the same facts as the screens to AI agents, as the
token's owner. - A daily digest, alerting rules and Grafana dashboards, the insight pack
(PostgreSQL metrics from the instances' exporter), and OpenTelemetry tracing. - The operator (optional), reconciling
PgAdmin(one pgAdmin per team,
registered against many Clusters, with libpq credential files written by a
sidecar),EvidenceAgent,PgToolBoxConsoleandPgAccessRequest, and honouring
PgAdminAccessgrants across namespaces. It never writes to a CloudNativePG
Clusterand puts no secret material in status, events or logs. - The evidence agent, a read-only reader of backup repositories: the Barman
Cloud layout on S3, Azure Blob Storage and Google Cloud Storage, and the
pgBackRest layout (repository format 5) for Clusters backed up through the
Dalibo or Opera CNPG-I plugin. It reports what the repository actually holds,
with conservative roll-ups, so the console can compare it with what
CloudNativePG claims. It is the only component that holds object-store
credentials. - Install paths: the
pgtoolboxchart (the operator and its CRDs), the
pgtoolschart (a team's console, evidence agents and pgAdmin, without the
operator), kustomize, and an OLM bundle and catalog. With
operator.config.watchNamespaces, the Helm chart binds the operator's
namespaced rules (Secrets included) per namespace, keeping only cluster-scoped
rules cluster-wide. Images forlinux/amd64
andlinux/arm64:ghcr.io/fyannk/pgtoolbox-operator,
ghcr.io/fyannk/pgtoolbox-consoleandghcr.io/fyannk/pgtoolbox-evidence-agent.
WithwatchNamespacesthe operator also gets a name-scoped Role for its own
ConfigMap and Secret, so it starts without its namespace listed; the cluster-wide
role holds nobind; each mode has its own ClusterRoleBinding name, sohelm upgradecan switch modes; a watched namespace deleted after install is left out
at start and logged.
The restore-drill delete guard exempts holders of*on restore drills in
the Cluster's namespace (a namespaced Argo CD or OpenShift GitOps controller, a
Flux tenant bound to cluster-admin); start-up reads have a 60 s deadline per step,
a 401 at start fails it instead of leaving a namespace out, and
pgtoolbox_config_infolists only the namespaces watched. - The custom resources are
pgtoolbox.fyannk.dev/v1alpha1. - Opening a pgAdmin behind the OpenShift OAuth proxy takes the
connect
verb onpgadmins/<name>(granted bypgtoolbox-console-operatorand by
admin), notget, which OLM gives to everyviewuser. - Release candidates (
v0.1.0-rc.N) publish end to end: the bundle, catalog
and installer manifests are pinned by digest from the tree's core version, a
pin that changes nothing fails the release, andlatestmoves only after the
packages are verified public. - Release verification. The notes of a release are its CHANGELOG section and a
link to the commit log (the compare view, or the history for the first release),
not the log pasted in; the OLM bundle and catalog
images are scanned on every pull request and push, not first in the release; the
release rehearsal pins the bundle and catalog on every run; after the prune, and
weekly,verify-release.ymlpulls every image and both charts with no
credentials and verifies signatures and attestations. A failed candidate is
superseded by the next one (-rc.N+1), never moved. The images are not claimed
to be bit-for-bit reproducible. The catalog image builds opm and
grpc_health_probefrom source (opm v1.74.0) with the repository's Go and
dependency versions, since the upstream opm image ships fixable high
vulnerabilities. - Release gates that hold on every commit. Merges made by auto-merge start no
workflow of their own, soautomerge.ymlnow dispatches the fullci.ymland
security.ymlonmainfor a commit that has no run (after the merge, and every
30 minutes as a net);make release-preflight TAG=vX.Y.Zchecks the dated
CHANGELOG, the annotated tag and greenci-okandsecurity-gateon the tagged
commit before the tag is pushed. A nested-module release is never marked latest, a
release candidate never is either, and the product's stable release is. The
signature and attestation check of each image is retried,npm ciandpnpm installin the image build are retried, and the anonymous verification still runs
when the prune fails. The envtest suites run on Kubernetes 1.35 and 1.36 in the
nightly and dispatched runs (1.34 on every change). Dependabot proposes the
Playwright npm packages as one group, and the e2e image moves with them. - The restore check without an evidence agent reads the primary's last
archived WAL time: "may well be possible" only while archiving is healthy, and
"likely not in the repository" when it fails. With an agent, a time between
its WAL frontier and its scan is unknown, not "not covered". Restore-check and
recovery-window sentences are translated; the Overview shows the last archived
WAL; the failover data-loss answer shows the age of its sweep and is unknown
when the sweep is stale. - Backup cadence is read with CloudNativePG's own cron parser (robfig/cron
v1.2.0), so descriptors,@every, lists, ranges and day-restricted schedules
are checked. On a CloudNativePG minor whose phase table was not verified, a
healthy phase reads as a warning. Restore-drill pruning keeps the newest pass
of a recreated Cluster. - Admission policy: an EvidenceAgent's
allowedSecretsneedsgeton those
Secrets; a kept Secret reference whose destination changes is checked again;
a PgAdmin that offers Cluster credentials needsgeton the namespace's
Secrets. A kustomize component (config/components/admission) ships the same
policies; the OLM bundle has none, as its page says. On OpenShift, pgAdmin's
OAuth proxy sessions last one hour. - Recovery evidence follows
recovery_target_timeline 'latest'as PostgreSQL
resolves it, in both formats: a missing middle history file, or an unreadable
newest one, no longer reads as healthy coverage, and an off-target path names
the timeline a restore must ask for. Snapshots carryproducer.features; the
console takes no coverage from an agent withoutrecovery-timeline-latest, or
whose timeline evidence is not healthy. - Client addresses behind a proxy:
X-Forwarded-Foris read only from peers
inTRUSTED_PROXY_CIDRS; hops without CIDRs ignore it, so a pod in the cluster
cannot forge its address.spec.exposure.trustedProxysets hops and CIDRs, and
an exposed console gets an ingress NetworkPolicy (by default behind a Route,
withspec.exposure.networkPolicy.frombehind an Ingress or Gateway), reported
by the advisoryExposureConfinedcondition. MCP bearer reviews share the
process-wide review budget, streams keep their feed through the shutdown
drain, and the console warns at start about hops 0 behind a public URL. - Sign-in budgets behind a shared proxy address. Behind a proxy declared
withoutTRUSTED_PROXY_CIDRS, junk callbacks on self-started OIDC flows, junk
pasted tokens, or floods of the MCP and OAuth endpoints no longer lock everyone
out: sign-ins are bounded per flow, per token, per person and per replica (20/s,
burst 40) instead of per shared address. The docs say what stays open after an
access request expires (the console's caches, the pgAdmin session, open
connections) and that the four-eyes check covers only the console's path. - Exposure trust is confined, or withdrawn. A PgToolBoxConsole trusts every
peer'sX-Forwarded-Foronly while no other NetworkPolicy or broadfrompeer
reopens its port (new reasonsExposurePolicyBypassed,ExposurePeersBroad...