From 7bd603838a17cad6fd264f16574a80c56aebccd2 Mon Sep 17 00:00:00 2001 From: Gabriele Bartolini Date: Mon, 14 Sep 2026 13:21:29 +0200 Subject: [PATCH 1/3] chore: sync generated files with cnpg-infra policy These files are generated from cloudnative-pg/cnpg-infra and landed here by scripts/sync-ownership-files.sh, so propose a change there rather than editing them in this repository: - CODEOWNERS, from componentowners-policy.yaml. - COMPONENT_OWNERS.md, from repo-tiers.yaml's owners field, which is the same entry that populates this repo's -owners GitHub team. It is the public record of who owns this component, which a GitHub team cannot be, since team membership is only visible to other org members. - .gitvote.yml, so a vote held on an issue here actually has an electorate. Until now /vote-component-owner did nothing in this repo. Assisted-by: Claude Signed-off-by: Gabriele Bartolini --- .../component-owner-proposal.yml | 110 ++++++++++++++++++ .gitvote.yml | 63 ++++++++++ COMPONENT_OWNERS.md | 33 ++++++ 3 files changed, 206 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/component-owner-proposal.yml create mode 100644 .gitvote.yml create mode 100644 COMPONENT_OWNERS.md diff --git a/.github/ISSUE_TEMPLATE/component-owner-proposal.yml b/.github/ISSUE_TEMPLATE/component-owner-proposal.yml new file mode 100644 index 00000000..1f209122 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/component-owner-proposal.yml @@ -0,0 +1,110 @@ +name: "Propose a Component Owner" +description: "Nominate a Contributor to become Component Owner of a repository" +title: "[Component Owner Proposal]: " +labels: ["component-owner-proposal"] +body: + - type: markdown + attributes: + value: | + ## Component Owner proposal + + This template is an org-wide default (defined in `cloudnative-pg/.github`), + but **the issue itself must be created in the repository the nominee is + being proposed for** -- if you opened "New issue" from that repository's + own page, you're already in the right place; don't move this to + `governance`, `.github`, or `cnpg-infra`. gitvote reads a repository's + own `.gitvote.yml`, so the vote this issue leads to only uses the right + voters (that repository's Component Owners) if the issue lives there. + + Promotion process, thresholds, and who may propose: see + `CONTRIBUTOR_LADDER.md` in + [cloudnative-pg/governance](https://github.com/cloudnative-pg/governance). + That document arrives with the federated-model rewrite, which is + pending ratification; progress is tracked in + [cloudnative-pg/governance#67](https://github.com/cloudnative-pg/governance/issues/67). + + - type: input + id: nominee + attributes: + label: Proposed Component Owner + description: GitHub handle of the person being nominated. + placeholder: "@handle" + validations: + required: true + + - type: input + id: lfid + attributes: + label: Nominee's LFID profile + description: "Component Owner status requires a Linux Foundation ID (LFID) with the nominee's GitHub account linked to it -- this is what lets CNCF's own tooling map the GitHub handle above to an organization at all. Look it up, or register/link one, at https://openprofile.dev. Paste the profile URL." + placeholder: "e.g. https://openprofile.dev/profile/gabriele.bartolini" + validations: + required: true + + - type: input + id: organization + attributes: + label: Nominee's organization (employer) + description: "Must match the LFID profile's own \"Current Organization\" field above, not just what you believe it to be. This is what org-balanced voting and the Steering seat cap actually count -- a profile with no employer set, or the wrong one, silently misstates an organization's real seat count. Use the literal word Independent (not blank, not N/A) if the nominee has no employer tied to their contribution." + placeholder: "e.g. EDB -- or literally: Independent" + validations: + required: true + + - type: checkboxes + id: eligibility + attributes: + label: Proposer eligibility + description: "Per CONTRIBUTOR_LADDER.md, a nomination comes from a member of the body that decides it: this repository's Component Owners, or, where fewer than three of them are named, its subproject's maintainer committee. If that isn't you, ask one of them to open this issue instead of opening it on their behalf, so the record shows who actually nominated. Nobody here can verify the LFID/organization fields above by API -- this is a self-attestation, same as the two below." + options: + - label: I am a Component Owner of this repository, or a member of its subproject's maintainer committee. + required: true + - label: I opened this issue inside the target repository itself (see note above), not in governance, .github, or cnpg-infra. + required: true + - label: I opened the LFID profile above myself and confirmed the nominee's GitHub account is linked to it, and its "Current Organization" field matches the organization given above (or Independent). + required: true + + - type: textarea + id: justification + attributes: + label: Track record / justification + description: Why does this contributor merit Component Owner status on this repository? Reference specific contributions -- PRs authored or reviewed, issue triage, sustained involvement, etc. + validations: + required: true + + - type: textarea + id: links + attributes: + label: Relevant links + description: PRs, issues, or discussions that support this nomination. + validations: + required: false + + - type: markdown + attributes: + value: | + ## Next steps + + 1. Let this issue sit long enough for this repository's other Component + Owners to weigh in. + 2. An existing Maintainer or Component Owner of this repository comments + `/vote-component-owner` to open voting: two-thirds majority of this + repository's Component Owners, one week, per this repository's own + `.gitvote.yml`. If this repository has fewer than three named + Component Owners (or none), the vote defaults to the subproject + maintainer committee instead -- see `CONTRIBUTOR_LADDER.md` in the + governance repository. + 3. If the vote passes: open a PR against + [cloudnative-pg/cnpg-infra](https://github.com/cloudnative-pg/cnpg-infra) + adding the nominee to this repository's `owners:` list in + `repo-tiers.yaml`. Once merged, `scripts/sync-project-owner-teams.sh + --apply` (run by an admin, from their own machine -- + see that repo's README) grants the actual GitHub access. + Automating this step from a passed vote is on the roadmap; for now + it's a manual follow-up. + 4. The LFID and organization collected above have nowhere durable to + land yet: `.project`'s `maintainers.yaml` doesn't have fields for + either today (confirmed against the + [dot-project schema](https://github.com/cncf/automation/tree/main/utilities/dot-project) + -- it only lists GitHub handles). Until that's resolved, note the + organization in this issue and in the `cnpg-infra` PR from step 3, + so it's at least on the record somewhere. diff --git a/.gitvote.yml b/.gitvote.yml new file mode 100644 index 00000000..604e329f --- /dev/null +++ b/.gitvote.yml @@ -0,0 +1,63 @@ +# GitVote configuration for cloudnative-pg/cnpg-i. +# +# Rendered by cnpg-infra's scripts/render-gitvote-config.sh -- see +# cnpg-infra's gitvote-policy.yaml and scripts/check-gitvote-config.sh / +# fix-gitvote-config.sh for how this file is generated and enforced. +# +# Voters are this repository's own cnpg-i-owners GitHub team (repo-tiers.yaml's +# owners field is what populates it; see sync-project-owner-teams.sh). +# Component Owner-level decisions per CONTRIBUTOR_LADDER.md are scoped to +# the repository, not org-wide. The profiles below mirror +# CONTRIBUTOR_LADDER.md's two repository-level thresholds: +# - default: simple majority, Contributor promotion/removal +# - component-owner: two-thirds majority, Component Owner +# promotion/removal (/vote-component-owner) +# plus, where this repo belongs to a subproject, the same two scoped to +# that subproject's maintainer committee, for the case where this repo has +# too few named owners to decide for itself. +automation: + enabled: false + rules: + - patterns: [] + profile: default + +profiles: + default: + duration: 1w + pass_threshold: 50 + allowed_voters: + teams: + - cnpg-i-owners + users: [] + close_on_passing: true + close_on_passing_min_wait: "10 minutes" + + component-owner: + duration: 1w + pass_threshold: 66 + allowed_voters: + teams: + - cnpg-i-owners + users: [] + close_on_passing: true + close_on_passing_min_wait: "10 minutes" + + committee: + duration: 1w + pass_threshold: 50 + allowed_voters: + teams: + - extensibility-maintainers + users: [] + close_on_passing: true + close_on_passing_min_wait: "10 minutes" + + committee-component-owner: + duration: 1w + pass_threshold: 66 + allowed_voters: + teams: + - extensibility-maintainers + users: [] + close_on_passing: true + close_on_passing_min_wait: "10 minutes" diff --git a/COMPONENT_OWNERS.md b/COMPONENT_OWNERS.md new file mode 100644 index 00000000..c278f72e --- /dev/null +++ b/COMPONENT_OWNERS.md @@ -0,0 +1,33 @@ +# Component Owners + + + +`cnpg-i` is a component of the **Extensibility** subproject of +CloudNativePG (see `subprojects/extensibility.md` in +[cloudnative-pg/governance](https://github.com/cloudnative-pg/governance)). + +The people below are its **Component Owners**: they hold `Write` on this +repository through the `cnpg-i-owners` GitHub team, and are its default +[`CODEOWNERS`](CODEOWNERS) entry, so every pull request here is routed to +them for review. + +| Name | GitHub Handle | Country | +| :--- | :--- | :--- | +| Gabriele Bartolini | [@gbartolini](https://github.com/gbartolini) | | +| Francesco Canovai | [@fcanovai](https://github.com/fcanovai) | | +| Leonardo Cecchi | [@leonardoce](https://github.com/leonardoce) | | +| Marco Nenciarini | [@mnencia](https://github.com/mnencia) | | +| Armando Ruocco | [@armru](https://github.com/armru) | | + +Component Owner is a rung of the CloudNativePG contributor ladder. A new +owner is added by a ⅔ vote of this repository's existing Component Owners, +held on an issue in this repository; the change is then recorded in +`cnpg-infra`, which grants the access and regenerates this file. See +`CONTRIBUTOR_LADDER.md` in [cloudnative-pg/governance](https://github.com/cloudnative-pg/governance) +for the full process, including what happens when a repository has too few +owners to reach that threshold. From 85631f55256fc63acb34a2b8aec40d48951bbe6b Mon Sep 17 00:00:00 2001 From: Gabriele Bartolini Date: Mon, 14 Sep 2026 16:50:05 +0200 Subject: [PATCH 2/3] ci: don't spellcheck the generated COMPONENT_OWNERS.md The file is rendered from cloudnative-pg/cnpg-infra and lists people by name, so pyspelling flags maintainer surnames along with `cloudnative` and `subproject`. Adding those to .wordlist.txt would work today and rot tomorrow, since the list would need an entry on every roster change. The sources line already excludes generated files for the same reason. Assisted-by: Claude Signed-off-by: Gabriele Bartolini --- .spellcheck.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.spellcheck.yaml b/.spellcheck.yaml index f5863755..843f2678 100644 --- a/.spellcheck.yaml +++ b/.spellcheck.yaml @@ -2,7 +2,7 @@ matrix: - name: Markdown sources: # Ignore the autogenerated markdown files - - ./**/*.md|!./CHANGELOG.md + - ./**/*.md|!./CHANGELOG.md|!./COMPONENT_OWNERS.md dictionary: wordlists: - .wordlist.txt From 0c42dad9d6f2d0369d992a9a776e8a663d041750 Mon Sep 17 00:00:00 2001 From: Gabriele Bartolini Date: Tue, 15 Sep 2026 09:48:47 +0200 Subject: [PATCH 3/3] fix: require a strict majority to pass a gitvote vote Gitvote decides a vote with `in_favor_percentage >= pass_threshold`, so a flat 50 let an even-sized electorate pass its own tie: 2-2 on a four-owner repo cleared the bar. A simple majority is strictly more than half, and a percentage cannot express "half plus one vote", so the threshold moves to 50.01 -- above any exact tie, below the smallest real majority, which is 50 + 100/N percent for N voters and stays above 50.01 up to N = 10000. The two-thirds profiles move from 66 to 66.66 for the same reason: two thirds is 66.666..., so a flat 66 sat just under its own bar (33 of 50 is 66.0 and would have passed). Not 66.67 -- for an electorate divisible by three the exact two-thirds computes to 66.6666..., which falls under 66.67 and would break a legitimate 2-of-3. This file is rendered from cnpg-infra's gitvote-policy.yaml; the change is made there and regenerated here. Assisted-by: Claude Opus 5 Signed-off-by: Gabriele Bartolini --- .gitvote.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.gitvote.yml b/.gitvote.yml index 604e329f..96d62980 100644 --- a/.gitvote.yml +++ b/.gitvote.yml @@ -15,6 +15,11 @@ # plus, where this repo belongs to a subproject, the same two scoped to # that subproject's maintainer committee, for the case where this repo has # too few named owners to decide for itself. +# +# The thresholds are 50.01 and 66.66, not 50 and 66, because gitvote +# passes a vote on >= rather than >: a flat 50 would let an even-sized +# electorate tie and still pass. See cnpg-infra's +# scripts/render-gitvote-config.sh for the full reasoning. automation: enabled: false rules: @@ -24,7 +29,7 @@ automation: profiles: default: duration: 1w - pass_threshold: 50 + pass_threshold: 50.01 allowed_voters: teams: - cnpg-i-owners @@ -34,7 +39,7 @@ profiles: component-owner: duration: 1w - pass_threshold: 66 + pass_threshold: 66.66 allowed_voters: teams: - cnpg-i-owners @@ -44,7 +49,7 @@ profiles: committee: duration: 1w - pass_threshold: 50 + pass_threshold: 50.01 allowed_voters: teams: - extensibility-maintainers @@ -54,7 +59,7 @@ profiles: committee-component-owner: duration: 1w - pass_threshold: 66 + pass_threshold: 66.66 allowed_voters: teams: - extensibility-maintainers