Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 25 additions & 48 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,63 +1,40 @@
# Org-wide default owners.
# Code owners for THIS repository.
#
# GitHub falls back to this file for any repo in `mzizi-dev` that does not
# ship its own `.github/CODEOWNERS`. Today that is EVERY repo except
# `mzizi-registry` — and that repo's own file is broken (see the note at the
# bottom), so in practice nothing in this org has working review routing
# until this file lands.
# SCOPE — read this before assuming it does more than it does.
# CODEOWNERS is NOT one of the files an organisation's `.github` repo can
# supply as an org-wide default. GitHub's list of inheritable community
# health files is CODE_OF_CONDUCT.md, CONTRIBUTING.md, discussion category
# forms, FUNDING.yml, issue and PR templates, SECURITY.md and SUPPORT.md —
# CODEOWNERS is absent from it, and the CODEOWNERS docs say the file is read
# from `.github/`, the root, or `docs/` "of the repository". So this file
# governs `mzizi-dev/.github` and nothing else.
#
# To get review routing in another repo, COPY `CODEOWNERS.example` from the
# root of this repo into that repo's own `.github/CODEOWNERS`. There is no
# way to do it centrally.
#
# The org has two members: @bryanfawcett (admin) and @michellellawson
# (member). There are no teams, so owners are named as users. A team handle
# here would resolve to nobody and CODEOWNERS would silently do nothing —
# which is exactly the failure `mzizi-registry` is in.
# would resolve to nobody and CODEOWNERS would silently do nothing — which is
# exactly the state `mzizi-registry` is in (ORG_STANDARDS.md, gap 1).
#
# GitHub applies the LAST matching pattern, so the catch-all must stay at the
# top. Add narrower rules BELOW it, never above.
# GitHub applies the LAST matching pattern, so the catch-all stays at the top.
# Add narrower rules BELOW it, never above.

* @bryanfawcett

# ---------------------------------------------------------------------------
# Narrower rules
# Narrower rules — paths that exist in THIS repo
# ---------------------------------------------------------------------------
# These paths are named individually because they are the ones where an
# unreviewed change is expensive, not because they are the ones that change
# most. Paths are matched against the repo the PR is opened in, so a pattern
# that does not exist in a given repo simply never matches there.

# The compiler and the primitive corpus in `mzizi-dev/mzizi`. Bundu
# Foundation IP, and the artefact every other repo is downstream of.
/compiler/ @bryanfawcett
/primitives/ @bryanfawcett
/examples/ @bryanfawcett

# The charter and the migration plan are the two documents that decide what
# this project is. They should not drift by accident.
/CHARTER.md @bryanfawcett
/MIGRATION.md @bryanfawcett

# Anything that changes what CI runs, or what may merge. A PR that edits its
# own gate should be read by a human before it lands.
# The reusable workflows other repos will call. A change here changes CI in
# every repo that has adopted one, from a PR in a repo they do not watch.
/.github/workflows/ @bryanfawcett
/.github/CODEOWNERS @bryanfawcett
/github-rulesets/ @bryanfawcett

# Deployment configuration for the two Workers (`mzizi-api-gateway`,
# `mzizi-console`). `wrangler.jsonc` carries the custom-domain routes; a
# wrong edit here takes a hostname down rather than failing a build.
/wrangler.jsonc @bryanfawcett
# Ruleset definitions. These decide what may merge across nine repos once
# applied.
/github-rulesets/ @bryanfawcett

# Secrets policy and the allowlist that decides what gitleaks ignores.
/.gitleaks.toml @bryanfawcett
# The org's factual record and the security policy every repo inherits.
/ORG_STANDARDS.md @bryanfawcett
/SECURITY.md @bryanfawcett

# ---------------------------------------------------------------------------
# Known defect this file does NOT fix
# ---------------------------------------------------------------------------
# `mzizi-dev/mzizi-registry` ships its own `.github/CODEOWNERS`, which takes
# precedence over this one for that repo. Every rule in it names
# `@nyuchi/core` — a team in the `nyuchi` org, not this one. Verified
# 2026-09-11: the `nyuchi` org's teams are docs, maintainers, marketing,
# mukoko, nyuchi-open-projects, platform and security. There is no `core`
# team, and a team from another org cannot own code here in any case. That
# file therefore assigns no reviewers at all. Fixing it is a PR against
# `mzizi-registry`, not this repo — see ORG_STANDARDS.md, "Known gaps".
7 changes: 4 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Dependabot for THIS repo only.
#
# A `dependabot.yml` in the org `.github` repo is NOT inherited by other
# repos — unlike CODEOWNERS, issue templates and SECURITY.md, Dependabot has
# no org-wide fallback. Each repo needs its own file. See
# `dependabot.example.yml` beside this one for a starting point to copy.
# repos. Issue and PR templates, SECURITY.md, CONTRIBUTING.md, SUPPORT.md and
# CODE_OF_CONDUCT.md do fall back to this repo; Dependabot and CODEOWNERS do
# not. Each repo needs its own copy of both. See `dependabot.example.yml` and
# `CODEOWNERS.example` at the root for starting points.
#
# The only thing here is a Cargo.toml-free repo of workflows, so
# github-actions is the only ecosystem that applies.
Expand Down
63 changes: 63 additions & 0 deletions CODEOWNERS.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Copy this to `.github/CODEOWNERS` in a consuming repo, then delete the
# sections that do not apply.
#
# WHY A TEMPLATE AND NOT A CENTRAL FILE
# CODEOWNERS is NOT inheritable from an organisation's `.github` repo.
# GitHub's list of community health files an org can supply as defaults is
# CODE_OF_CONDUCT.md, CONTRIBUTING.md, discussion category forms, FUNDING.yml,
# issue and PR templates, SECURITY.md and SUPPORT.md. CODEOWNERS is not on it,
# and the CODEOWNERS docs read the file from `.github/`, the root, or `docs/`
# "of the repository". Unlike SECURITY.md or the PR template, there is no
# central copy that covers the org — every repo needs its own file or it has
# no review routing at all.
#
# STATUS, 2026-09-11: `mzizi-registry` is the only repo in the org with a
# CODEOWNERS, and every rule in it names `@nyuchi/core` — a team in another
# org, which does not exist there either. It assigns nobody. So in practice
# no repo in `mzizi-dev` has working review routing today.
#
# RULES OF THE FORMAT
# - The LAST matching pattern wins. Keep the catch-all first and add
# narrower rules below it.
# - An owner must have write access to THIS repo. A user or team from
# another org silently matches nobody — no error, no warning, no
# reviewer. That is the failure mode above.
# - This org has no teams, so name users.

# Default owner for everything.
* @bryanfawcett

# ---------------------------------------------------------------------------
# Add below, not above. Uncomment what exists in your repo.
# ---------------------------------------------------------------------------

# --- Anything that changes what CI runs, or what may merge ---
# A PR that edits its own gate should be read by a human before it lands.
# /.github/workflows/ @bryanfawcett
# /.github/CODEOWNERS @bryanfawcett

# --- mzizi: the compiler and the corpus it must keep accepting ---
# /compiler/ @bryanfawcett
# /primitives/ @bryanfawcett
# /examples/ @bryanfawcett
# /CHARTER.md @bryanfawcett
# /MIGRATION.md @bryanfawcett

# --- mzizi-api-gateway, mzizi-console: deployment configuration ---
# wrangler.jsonc carries the custom-domain routes. A wrong edit takes a
# hostname down rather than failing a build, so it fails late and loudly
# instead of early and cheaply.
# /wrangler.jsonc @bryanfawcett

# --- mzizi-registry: what downstream consumers actually install ---
# This repo serves source into other people's production apps, so the files
# that decide what is served matter more than their size suggests.
# /registry.json @bryanfawcett
# /app/globals.css @bryanfawcett
# /lib/db/ @bryanfawcett

# --- Secrets policy ---
# .gitleaks.toml is an allowlist: a change to it is a change to what the
# secret scan agrees to ignore.
# /.gitleaks.toml @bryanfawcett
# /SECURITY.md @bryanfawcett
7 changes: 6 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ The PR title must parse as a Conventional Commit. Allowed types:

Rules:

- Subject starts **lowercase**.
- Subject starts **lowercase**. This catches more than sloppiness: a subject
beginning with an all-caps identifier fails too, so
`fix: CODEOWNERS is not inheritable` is rejected and
`fix: stop claiming CODEOWNERS is inheritable` passes. Reword rather than
ask for the rule to be loosened — lowercasing the identifier itself would
be worse.
- Subject is **imperative** — "add", not "adds" or "added".
- No trailing period.
- Scope is optional: `feat(compiler): ...` is fine, `feat: ...` is fine.
Expand Down
51 changes: 36 additions & 15 deletions ORG_STANDARDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,14 +332,23 @@ fallback repo held a one-line README.
`.github/dependabot.yml`. Its own copies take precedence over anything here,
so two of them being broken (gaps 1 and 2) is not something this repo can fix.

What now applies org-wide by fallback: `.github/CODEOWNERS`,
`.github/PULL_REQUEST_TEMPLATE.md`, `.github/ISSUE_TEMPLATE/` (bug form,
feature form, and a `config.yml` routing security to a private advisory),
`SECURITY.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md` (Contributor Covenant
2.1) and `SUPPORT.md`.

**Dependabot does not have an org-wide fallback.** `.github/dependabot.yml`
here covers only this repo; `dependabot.example.yml` is a template to copy.
What now applies org-wide by fallback: `.github/PULL_REQUEST_TEMPLATE.md`,
`.github/ISSUE_TEMPLATE/` (bug form, feature form, and a `config.yml` routing
security to a private advisory), `SECURITY.md`, `CONTRIBUTING.md`,
`CODE_OF_CONDUCT.md` (Contributor Covenant 2.1) and `SUPPORT.md`.

**Two things are NOT inheritable, and it is easy to assume otherwise.**

- **CODEOWNERS.** GitHub's list of community health files an org `.github`
repo can supply as defaults is CODE_OF_CONDUCT.md, CONTRIBUTING.md,
discussion category forms, FUNDING.yml, issue and PR templates, SECURITY.md
and SUPPORT.md. CODEOWNERS is not on it, and the CODEOWNERS docs read the
file from `.github/`, the root, or `docs/` *of the repository*. So
`.github/CODEOWNERS` in this repo governs this repo and nothing else.
`CODEOWNERS.example` at the root is the template to copy into each repo.
This is gap 14.
- **Dependabot.** `.github/dependabot.yml` here covers only this repo;
`dependabot.example.yml` is the template.

---

Expand All @@ -354,9 +363,10 @@ names `@nyuchi/core`. That is a team in the `nyuchi` org, not this one — and
`nyuchi` has no `core` team either (its teams are docs, maintainers,
marketing, mukoko, nyuchi-open-projects, platform, security). A team from
another org cannot own code here in any case. Because a repo-local
`CODEOWNERS` takes precedence, the largest repo in the org is the one this
repo's `CODEOWNERS` does not reach. **Fix: a PR against `mzizi-registry`
replacing `@nyuchi/core` with `@bryanfawcett`.**
`CODEOWNERS` is the only kind there is — it is not inheritable from this repo
(gap 14) — the largest repo in the org has no working review routing at all.
**Fix: a PR against `mzizi-registry` replacing `@nyuchi/core` with
`@bryanfawcett`.**

**2. `mzizi-registry`'s `SECURITY.md` points at the old org.** It sends
reporters to `https://github.com/nyuchi/mzizi/security/advisories/new`. The
Expand Down Expand Up @@ -429,6 +439,11 @@ If the fold is complete, the repo should be archived rather than left as a
second place a roadmap might live — which `MIGRATION.md` §1 explicitly warns
against: "do not leave a roadmap living apart from the code it plans."

**12. `allow_auto_merge` and `has_wiki` are inconsistent across repos.**
Cosmetic, but `has_wiki: true` on five repos leaves an unused, unwatched
surface open on a public org. `mzizi-roadmap` and `.github` also carry no
licence.

**13. GitHub can enforce SHA-pinning org-wide, and it is switched off.**
`GET /orgs/mzizi-dev/actions/permissions` reports
`sha_pinning_required: false` (with `enabled_repositories: all` and
Expand All @@ -443,7 +458,13 @@ revisiting: every workflow in the org starts with a read-write `GITHUB_TOKEN`
unless it narrows its own `permissions`, and `read` would be the safer
default given all five workflows in this repo declare what they need.

**12. `allow_auto_merge` and `has_wiki` are inconsistent across repos.**
Cosmetic, but `has_wiki: true` on five repos leaves an unused, unwatched
surface open on a public org. `mzizi-roadmap` and `.github` also carry no
licence.
**14. No repo has working CODEOWNERS, and this repo cannot fix that
centrally.** CODEOWNERS is not an inheritable community health file (see
[Community-health files](#community-health-files) for the citation), so the
copy in this repo covers only this repo. `mzizi-registry` has the org's only
other CODEOWNERS and it assigns nobody (gap 1). Every other repo has none.
**Fix: copy `CODEOWNERS.example` into `.github/CODEOWNERS` in each repo — one
small PR per repo, eight of them.** Worth doing before
`require_code_owner_review` is ever turned on in a ruleset, because that
setting against a repo with no CODEOWNERS does nothing, and against one with
a broken CODEOWNERS blocks every PR.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ in each repo today, and an explicit list of what does not exist yet.

| Path | Applies to |
|---|---|
| [`.github/CODEOWNERS`](./.github/CODEOWNERS) | Every repo without its own |
| [`.github/CODEOWNERS`](./.github/CODEOWNERS) | **This repo only.** CODEOWNERS is not inheritable — see [`CODEOWNERS.example`](./CODEOWNERS.example) |
| [`.github/PULL_REQUEST_TEMPLATE.md`](./.github/PULL_REQUEST_TEMPLATE.md) | Every repo without its own |
| [`.github/ISSUE_TEMPLATE/`](./.github/ISSUE_TEMPLATE) | Every repo without its own |
| [`SECURITY.md`](./SECURITY.md) · [`CONTRIBUTING.md`](./CONTRIBUTING.md) · [`CODE_OF_CONDUCT.md`](./CODE_OF_CONDUCT.md) · [`SUPPORT.md`](./SUPPORT.md) | Every repo without its own |
| [`.github/workflows/reusable-*.yml`](./.github/workflows) | Any repo that calls them — opt-in, per repo |
| [`github-rulesets/`](./github-rulesets) | Proposals. **Not applied.** |
| [`dependabot.example.yml`](./dependabot.example.yml) | A template to copy — Dependabot has no org-wide fallback |
| [`CODEOWNERS.example`](./CODEOWNERS.example) · [`dependabot.example.yml`](./dependabot.example.yml) | Templates to copy — neither CODEOWNERS nor Dependabot has an org-wide fallback |

## Reusable workflows

Expand Down