From 12160ffcd30f2b2f9b0f799b628db6021ef169ea Mon Sep 17 00:00:00 2001 From: Sall Date: Sat, 18 Jul 2026 10:05:46 +0100 Subject: [PATCH 1/5] docs(adr): reconcile proposed governance policies --- decisions/0008-branching-model.md | 119 +++++++++++-------- decisions/0009-testing-ci-strategy.md | 95 +++++++++------ decisions/0010-security-incident-response.md | 103 +++++++++++----- 3 files changed, 202 insertions(+), 115 deletions(-) diff --git a/decisions/0008-branching-model.md b/decisions/0008-branching-model.md index 494fdb189..07441e2a1 100644 --- a/decisions/0008-branching-model.md +++ b/decisions/0008-branching-model.md @@ -16,44 +16,54 @@ inconsistency is real, not cosmetic: - Others are trunk-based on `main` only (`zd`, packaged `zsh`, `z-a-meta-plugins`, `zsh-fancy-completions`, `zunit`, `.github`). -The meta-workspace catalog (`workspace/repos.yml`) had drifted from this reality -and had to be reconciled by inspecting live remotes. The root cause is that no -decision says *which class of repo uses a `next` branch and which does not*, so -each repo's model is discovered empirically rather than governed. `zsh-lint` -recently gained a `next` branch during its Go reboot, which re-surfaced the -ambiguity. +An audit on 2026-07-18 found that all listed repositories use `main` as their +GitHub default branch. Only `src`, `wiki`, `zi`, `zsh-lint`, and `zsh-eza` have +a live `next` branch for development or integration. In this ADR, **GitHub +default branch** and **development branch** are therefore separate concepts. + +The private meta-workspace catalog (`workspace/repos.yml`) is still drifted. Its +`default_branch` field conflates those concepts, and some entries name `next` +for repositories that do not have that branch. The catalog has not yet been +reconciled; that is a separate meta-workspace change after a maintainer decides +whether to accept this proposal. `decisions/0007-release-publication-flow.md` already defines four repository -classes by delivery model. Branching should be derived from those classes rather -than decided per repo, so the catalog stops drifting at the source. +classes by delivery model. Those classes constrain publication behavior, but +the live branch inventory shows that class alone does not select a repository's +development branch. ## Decision -The **canonical per-repo table below is the authoritative source** for branch -model, and `workspace/repos.yml` derives from it. The ADR-0007 repository class -is an *input* to the choice (it sets the publication boundary and a default), but -it does **not** by itself determine the branch model — repo churn/scale does. -Reality confirms this: within class 1, `wiki`/`src` run `next` → `main` while -`zd` is trunk-only; within class 2, `zsh-lint` uses `next` while `zunit` is -trunk. So the table, not the class, is binding. There is no ad-hoc per-repo -discretion: a repo's branch model is whatever this table says, and changing it -requires amending this ADR (or a superseding one), not creating a branch. +If accepted, the **canonical per-repo table below becomes the authoritative +source** for the development branch and branch model. The ADR-0007 repository +class is an _input_ to the choice because it sets the publication boundary and +a default, but it does **not** by itself determine the branch model — repo +churn/scale does. Within class 1, `wiki`/`src` use `next` → `main` while `zd` is +trunk-only; within class 2, `zsh-lint` uses `next` while `zunit` is trunk. Under +this proposal, changing a repository's assigned model requires amending this +ADR (or a superseding one), not merely creating or deleting a branch. ### Canonical branch model -| Repo | Class | Branch model | Development branch | Publication boundary | -| ---------------------- | ----- | ---------------- | ------------------ | --------------------------- | -| `wiki` | 1 | `next` → `main` | `next` | merge to `main` (deploy) | -| `src` | 1 | `next` → `main` | `next` | merge to `main` (deploy) | -| `zd` | 1 | trunk on `main` | `main` | push to `main` (image) | -| `zunit` | 2 | trunk on `main` | `main` | `vX.Y.Z` tag | -| `zsh-lint` | 2 | `next` → `main` | `next` | `vX.Y.Z` tag | -| packaged `zsh` | 2 | trunk on `main` | `main` | `vX.Y.Z` tag (deferred) | -| `zi` | 3 | `next` → `main` | `next` | `main` is consumable ref | -| `zsh-eza` | 3 | `next` → `main` | `next` | `main` is consumable ref | -| `z-a-meta-plugins` | 3 | trunk on `main` | `main` | `main` is consumable ref | -| `zsh-fancy-completions`| 3 | trunk on `main` | `main` | `main` is consumable ref | -| `.github` | 4 | trunk on `main` | `main` | n/a | +| Repo | Class | Branch model | Development branch | Publication boundary | +| ----------------------- | ----- | --------------- | ------------------ | ------------------------ | +| `wiki` | 1 | `next` → `main` | `next` | merge to `main` (deploy) | +| `src` | 1 | `next` → `main` | `next` | merge to `main` (deploy) | +| `zd` | 1 | trunk on `main` | `main` | push to `main` (image) | +| `zunit` | 2 | trunk on `main` | `main` | `vX.Y.Z` tag | +| `zsh-lint` | 2 | `next` → `main` | `next` | `vX.Y.Z` tag | +| packaged `zsh` | 2 | trunk on `main` | `main` | `vX.Y.Z` tag (deferred) | +| `zi` | 3 | `next` → `main` | `next` | `main` is consumable ref | +| `zsh-eza` | 3 | `next` → `main` | `next` | `main` is consumable ref | +| `z-a-meta-plugins` | 3 | trunk on `main` | `main` | `main` is consumable ref | +| `zsh-fancy-completions` | 3 | trunk on `main` | `main` | `main` is consumable ref | +| `.github` | 4 | trunk on `main` | `main` | n/a | + +The publication-boundary column states the proposed policy, not a complete +inventory of live workflow triggers. At the 2026-07-18 audit, `src` and `zd` +also had semantic-tag publication triggers that the table does not capture. +Whether those triggers remain accepted class-1 exceptions is a maintainer +decision. ### How the class informs the default @@ -71,25 +81,37 @@ requires amending this ADR (or a superseding one), not creating a branch. branch (the "Development branch" column). For trunk repos, feature branches also start from `main`. -`workspace/repos.yml` mirrors this table and must match it. Adding or removing a -repo's `next` branch is a decision recorded here first, then reflected in the -catalog in the same change. +If this ADR is accepted, the private catalog/schema and root agent guidance need +a separate meta-workspace reconciliation. They are deliberately not changed by +this public factual-reconciliation draft. + +## Decision review required + +Before acceptance, a maintainer must: + +1. Confirm that GitHub defaults remain `main` while the table's development + branch identifies the normal integration base. +2. Decide whether the live `src` and `zd` semantic-tag publication triggers are + accepted exceptions or whether the proposed publication wording must change. +3. Accept, amend, supersede, or reject this proposal and record the decider and + decision date. ## Consequences -- `workspace/repos.yml` derives from the canonical table above, so drift is - structurally prevented: the catalog is validated against an explicit table, not - "use judgment." -- New repos are added to the table (with their ADR-0007 class) as part of repo - creation, before the first branch is cut. -- **Action on acceptance:** the workspace `CLAUDE.md` currently states "default - development branch: `next` … all other work branches from `next`" as a universal - rule. On acceptance, update that section to reference this ADR's per-repo table - so agents do not get conflicting guidance for trunk-only repos. (Not done while - this ADR is PROPOSED — `CLAUDE.md` should not cite an unaccepted decision.) -- Promotion from `next` to `main` is a publication boundary only for class 1 - (deploy) repos; for other classes the merge validates but does not mint a - release (consistent with ADR-0007). +- If accepted, the table gives branch-policy audits an explicit public + comparison point; the ADR alone does not prevent catalog or repository drift. +- New repositories would be added to the table (with their ADR-0007 class) as + part of repository creation, before the first branch is cut. +- **Action on acceptance:** the private meta-workspace root guidance currently + states "default development branch: `next` … all other work branches from + `next`" as a universal rule. On acceptance, update that guidance to reference + this ADR's per-repository table so agents do not get conflicting instructions + for trunk-only repositories. This separate meta-workspace change is not made + while the ADR remains proposed. +- Promotion from `next` to `main` is a publication trigger for class-1 deploy + repositories; the live tag-trigger exceptions above remain under review. For + other classes the merge validates but does not mint a release (consistent + with ADR-0007). ## Alternatives considered @@ -100,10 +122,11 @@ catalog in the same change. from a staging branch before a change goes live, and `zi`'s scale warrants an integration buffer. - **Leave it per-repo and informal.** Rejected: that is the status quo that let - the catalog drift and required a manual remote audit to repair. + the catalog drift and required a manual remote audit to identify. ## References - `decisions/0007-release-publication-flow.md` — repository classes this builds on. -- `workspace/repos.yml` (meta-workspace) — per-repo branch model catalog. - `decisions/0003-conventional-commits.md` — commit/branch naming conventions. +- [Issue #454](https://github.com/z-shell/.github/issues/454) — dated live audit + and maintainer decision record. diff --git a/decisions/0009-testing-ci-strategy.md b/decisions/0009-testing-ci-strategy.md index 236ba5bf8..39764b458 100644 --- a/decisions/0009-testing-ci-strategy.md +++ b/decisions/0009-testing-ci-strategy.md @@ -12,46 +12,49 @@ CI exists across the org's repos but its scope is decided per repo and per workflow rather than from a shared policy. The result is uneven: some repos run `zsh -n` syntax checks plus `zcompile`, others add ZUnit suites, `zsh-lint` has Go tests, and the container repo builds a multi-arch matrix. There is no written -statement of *what level of testing each repository class owes*, which makes it +statement of _what level of testing each repository class owes_, which makes it hard to know whether a repo is under- or over-tested, and what a reviewer should require before merge. -ADR-0007 classified repos by delivery model and ADR-0008 derived branching from -those classes. Testing depth should be derived the same way, so CI scope is a -property of the repo class rather than an accident of history. +ADR-0007 classified repositories by delivery model and ADR-0008 proposes a +branch model informed by those classes. This ADR similarly proposes a target CI +scope by class. It does not claim that every listed control is already live or +configured as a required check. ## Decision -Required CI scope follows the ADR-0007 repository class. Every class shares a -common baseline; higher-risk classes add to it. +If accepted, required CI scope follows the ADR-0007 repository class. Every +class shares a common target baseline; higher-risk classes add to it. Live +rollout gaps and the dated evidence behind them are tracked in issue #454 rather +than copied into this ADR as a transient workflow inventory. ### Baseline (all repos) -- All workflows comply with the org workflow conventions (SHA-pinned actions, +- Workflows comply with the org workflow conventions (SHA-pinned actions, least-privilege `permissions:`, `concurrency:`, no-emoji `name:` per ADR-0005, - kebab-case filenames). These conventions are defined in the workspace `CLAUDE.md` - and the CI instructions — this ADR references them rather than restating, so - there is a single source of truth. + kebab-case filenames). These conventions are defined in `AGENTS.md` and the CI + instructions; this ADR references them rather than duplicating their details. - Zsh sources pass `zsh -n` (syntax) and `zcompile` (compile) checks. -- Dependency and secret scanning per `decisions/0004-dependabot-unification.md`. -- **Target state (not yet a live org-wide control):** Conventional Commits - (ADR-0003) and the disallowed-trailer rule enforced in CI. Today the - disallowed-trailer check runs via the `DISALLOWED_TRAILER_PATTERN` org secret; - Conventional Commits is convention-and-review, not a uniform CI gate. Adding a - shared commit/PR-title-lint check is a follow-up, tracked separately. +- Dependency-update and vulnerability-remediation ownership follows accepted + ADR-0012. ADR-0012 does **not** establish organization-wide secret-scanning + coverage; that requires separately configured and verified controls. +- Under the target policy, Conventional Commits (ADR-0003), PR-title validation, + and the disallowed-trailer rule would be enforced in CI. This is not a claim + of uniform live enforcement. ### By class -1. **Continuously deployed artifacts** (`wiki`, `src`, `zd`) — build must succeed - on the development branch before deploy. Wiki runs lint (ESLint/Stylelint) and - a production build; `zd` runs the Docker build matrix; `src` validates the - installer/loader. CodeQL where a supported language is present. -2. **Versioned tools and packages** (`zunit`, `zsh-lint`, packaged `zsh`) — full - functional test suite is **required** and gates release tags. ZUnit for Zsh - tools; `go test` for the `zsh-lint` Go CLI. A release tag must not be cut from - a commit whose suite is red. Compiled tools additionally run SAST (CodeQL - and/or `gosec` for the `zsh-lint` Go CLI); a release artifact is part of the - security surface governed by `decisions/0010-security-incident-response.md`. +1. **Continuously deployed artifacts** (`wiki`, `src`, `zd`) — the build succeeds + on the development branch before deploy. The target checks cover the wiki's + lint and production build, `zd`'s Docker build matrix, and `src`'s + installer/loader validation, plus CodeQL where a supported language is + present. +2. **Versioned tools and packages** (`zunit`, `zsh-lint`, packaged `zsh`) — a full + functional suite is **required** before a release tag is cut. ZUnit is the + target for Zsh tools and `go test` for the `zsh-lint` Go CLI. Compiled tools + additionally run an appropriate SAST control, such as CodeQL or `gosec`; a + release artifact is part of the security surface governed by + `decisions/0010-security-incident-response.md`. 3. **Git-consumed source** (`zi`, most plugins/annexes) — **validation-only**: the baseline checks above, plus ZUnit where the plugin ships tests. No release automation and no coverage gate; these repos are consumed from source and the @@ -66,19 +69,36 @@ ratcheting is a per-repo maintainer decision. ### Required checks -Each repo marks its class-appropriate checks as required for merge to its -publication branch (`main`, or `next`→`main` per ADR-0008). Validation-only repos -require the baseline; class-2 repos additionally require the functional suite. +Under the target policy, each repository marks its class-appropriate checks as +required for merge to its publication branch (`main`, or `next` → `main` per +ADR-0008). Validation-only repositories require the baseline; class-2 +repositories additionally require the functional suite. Actual rulesets and +required-check configuration must be verified repository by repository; this +ADR does not assert that they are live. + +## Decision review required + +Before acceptance, a maintainer must: + +1. Decide whether to accept this ADR now as target policy with owned rollout + gaps, or defer acceptance until the selected controls are implemented. +2. Define the full functional suite for packaged `zsh` and the release-gate + requirement for `zunit`. +3. Select and verify each repository's actual required checks, development-branch + validation, SAST coverage, and release-suite gate. +4. Accept, amend, supersede, or reject this proposal and record the decider and + decision date. ## Consequences -- A reviewer can determine the expected CI bar from the repo's class instead of - reading each workflow. -- New repos start with the correct CI scope for their class. -- "Validation-only for git-consumed repos" is now an explicit rule, preventing - release machinery from creeping into class-3 repos (consistent with ADR-0007). +- If accepted, a reviewer can determine the target CI bar from the repository's + class instead of inferring policy from each workflow. +- New repositories have an explicit target CI scope for their class. +- "Validation-only for git-consumed repositories" becomes an explicit rule, + discouraging release machinery in class-3 repositories (consistent with + ADR-0007). - The testing instruction file (`.github/instructions/testing.instructions.md`) - operationalizes this ADR for day-to-day authoring. + would be reconciled after acceptance; it is not changed by this draft. ## Alternatives considered @@ -96,6 +116,9 @@ require the baseline; class-2 repos additionally require the functional suite. - `decisions/0007-release-publication-flow.md` — repository classes. - `decisions/0008-branching-model.md` — branch model per class. - `decisions/0005-workflow-naming-conventions.md` — workflow naming baseline. -- `decisions/0004-dependabot-unification.md` — dependency scanning baseline. +- `decisions/0012-hybrid-dependency-management.md` — dependency-update and + vulnerability-remediation ownership. - `decisions/0010-security-incident-response.md` — SAST/release security surface. - `z-shell/zd` `.github/workflows/test-native.yml` — reusable ZUnit workflow. +- [Issue #454](https://github.com/z-shell/.github/issues/454) — dated rollout-gap + evidence and maintainer decision record. diff --git a/decisions/0010-security-incident-response.md b/decisions/0010-security-incident-response.md index e99f28a5e..9568a5d05 100644 --- a/decisions/0010-security-incident-response.md +++ b/decisions/0010-security-incident-response.md @@ -8,7 +8,7 @@ ## Context -`.github/SECURITY.md` tells reporters *how to report* a vulnerability and the +`.github/SECURITY.md` tells reporters _how to report_ a vulnerability and the coordinated-disclosure expectation. It says nothing about what the org does once a report arrives: who owns it, how fast it is acknowledged and triaged, how a fix is shipped, and what happens afterward. Without that, response time and quality @@ -24,45 +24,57 @@ them predictably." ### Intake channel -Private reports are received and tracked through **GitHub repository Security -Advisories** (the "Report a vulnerability" / draft-advisory flow), which provides -private collaboration, a private fork for the fix, and CVE issuance. Public repos -have no private issues, so a draft advisory — not an issue — is the tracking -record. `SECURITY.md` is the reporter-facing entry point. +When an affected public repository exposes **Report a vulnerability**, reporters +use that private GitHub repository Security Advisory flow. If the option is not +available, reporters use a private contact method on the organization profile +and must not include vulnerability details in a public issue or pull request. + +An authorized maintainer creates or uses a draft repository security advisory +as the access-controlled tracking record. A temporary private fork and a CVE +request are optional GitHub capabilities, not guaranteed outcomes. ### Ownership -An org maintainer is the incident owner for each report. The owner acknowledges, -triages severity, coordinates the fix, and runs the post-incident review. The -**security contact** (currently **ss-o**) owns incidents by default unless -explicitly reassigned. +An organization maintainer is the incident owner for each report. The owner +acknowledges, triages severity, coordinates the fix, and runs the post-incident +review. **ss-o** is currently the only documented maintainer and therefore the +proposed default incident owner. A named backup with verified access to the +affected repository and advisory is required before escalation is operational. ### Acknowledgement SLA +The proposed targets, subject to maintainer confirmation, are: + - Acknowledge a security report within **3 business days** of receipt. - Triage to a severity within **5 business days**. ### Severity and remediation targets -Severity uses CVSS-style judgment (impact × exploitability). Target time-to-fix -or documented mitigation from triage: +Severity uses CVSS-style judgment (impact × exploitability). The proposed +time-to-fix or documented-mitigation targets from triage, also subject to +maintainer confirmation, are: -| Severity | Examples | Target | -| -------- | ------------------------------------------------- | --------------- | -| Critical | RCE, secret/credential exposure, supply-chain | **7 days** | -| High | Privilege escalation, auth bypass | **30 days** | -| Medium | Limited-scope info disclosure, DoS | **90 days** | -| Low | Hardening, defense-in-depth | Best effort | +| Severity | Examples | Target | +| -------- | --------------------------------------------- | ----------- | +| Critical | RCE, secret/credential exposure, supply-chain | **7 days** | +| High | Privilege escalation, auth bypass | **30 days** | +| Medium | Limited-scope info disclosure, DoS | **90 days** | +| Low | Hardening, defense-in-depth | Best effort | Targets are goals, not guarantees; the owner records the rationale when a target slips. ### Escalation -If the owner cannot act within the acknowledgement SLA, the report is escalated -to another org maintainer. Critical incidents are worked immediately and may -warrant a temporary mitigation (yank a tag, pin a dependency, disable a workflow) -before the full fix. +If the owner cannot act within the acknowledgement SLA, use the named, +permission-verified backup route. Until that route exists, escalation is an +acknowledged rollout gap rather than an operational promise. + +Critical incidents are worked immediately. Before the full fix, prefer a +coordinated private mitigation, disabling or pinning affected functionality, +and channel-supported withdrawal, deprecation, or artifact revocation. Publish +a new patched version tag when a release is required. Never move or reuse a +published version tag. ### Remediation and disclosure @@ -72,22 +84,46 @@ before the full fix. until a fix is published or the report is declined, and credit the reporter. - Where a release artifact exists (ADR-0007 class 2), cut a patched tag and note the security fix in the release notes. +- Keep exploit details and reporter data in the advisory or another + access-controlled record. Only a sanitized review or follow-up may be public. ### Post-incident review For Critical and High incidents, the owner writes a short post-incident review: -timeline, root cause, fix, and a follow-up action (often a tracker issue) to -prevent recurrence. The review is kept in the owning repo or the tracker, not in -ephemeral notes. +timeline, root cause, fix, and a follow-up action to prevent recurrence. The +full review remains access-controlled when it contains exploit details or +reporter data; only a sanitized version may be placed in a public repository or +tracker. + +### Administrative verification + +As of the 2026-07-18 audit, private vulnerability reporting, advisory +notifications, backup access, and release immutability were not administratively +verified. This ADR does not claim that those controls are enabled. + +## Decision review required + +Before acceptance, a maintainer must: + +1. Confirm the proposed 3/5-business-day acknowledgement and triage targets and + the 7/30/90-day remediation targets. +2. Name a backup incident contact and verify that contact's repository and + advisory permissions. +3. Confirm where private vulnerability reporting, notifications, and release + immutability are enabled or required. +4. Accept, amend, supersede, or reject this proposal and record the decider and + decision date. ## Consequences -- Reports get a predictable acknowledgement and remediation path instead of - ad-hoc handling. -- `runbooks/security-incident-response.md` operationalizes this ADR step by step. -- `SECURITY.md` remains the reporter-facing entry point; this ADR governs the - internal response. -- Post-incident reviews build durable security memory and feed the tracker. +- If accepted and its rollout gaps are closed, reports get a predictable + acknowledgement and remediation path instead of ad-hoc handling. +- `runbooks/security-incident-response.md` would be reconciled after acceptance; + it is not changed by this draft. +- `SECURITY.md` remains the reporter-facing entry point and would be reconciled + after acceptance; this ADR defines the proposed internal response. +- Sanitized post-incident reviews build durable security memory without exposing + restricted report data. ## Alternatives considered @@ -106,3 +142,8 @@ ephemeral notes. - `runbooks/security-incident-response.md` — step-by-step responder runbook. - `decisions/0007-release-publication-flow.md` — how patched releases are cut. - `decisions/0008-branching-model.md` — hotfix branching for critical fixes. +- [GitHub repository security advisories](https://docs.github.com/en/code-security/concepts/vulnerability-reporting-and-management/repository-security-advisories) +- [Configuring private vulnerability reporting](https://docs.github.com/en/code-security/how-tos/report-and-fix-vulnerabilities/configure-vulnerability-reporting/configure-for-a-repository) +- [GitHub immutable releases](https://docs.github.com/en/code-security/concepts/supply-chain-security/immutable-releases) +- [Issue #454](https://github.com/z-shell/.github/issues/454) — dated control-gap + evidence and maintainer decision record. From 3dda97a58098a6fdbd812fec1e6018d2f83c2823 Mon Sep 17 00:00:00 2001 From: Sall Date: Fri, 24 Jul 2026 23:56:25 +0100 Subject: [PATCH 2/5] docs(adr): fix grammar nit and restore trailer-sweep evidence 0008: "is still drifted" -> "is still out of date" per Copilot review. 0009: the copilot-swe-agent conflict resolution against origin/main (59753e0e) took this branch's reworded disallowed-trailer bullet and silently dropped main's independently-added evidence (the 86-repository sweep finding no live DISALLOWED_TRAILER_PATTERN workflow, and the zi next-branch exception). Restored that evidence inside the target-policy framing instead of picking one side over the other. --- decisions/0008-branching-model.md | 2 +- decisions/0009-testing-ci-strategy.md | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/decisions/0008-branching-model.md b/decisions/0008-branching-model.md index 07441e2a1..6dc2b89e8 100644 --- a/decisions/0008-branching-model.md +++ b/decisions/0008-branching-model.md @@ -21,7 +21,7 @@ GitHub default branch. Only `src`, `wiki`, `zi`, `zsh-lint`, and `zsh-eza` have a live `next` branch for development or integration. In this ADR, **GitHub default branch** and **development branch** are therefore separate concepts. -The private meta-workspace catalog (`workspace/repos.yml`) is still drifted. Its +The private meta-workspace catalog (`workspace/repos.yml`) is still out of date. Its `default_branch` field conflates those concepts, and some entries name `next` for repositories that do not have that branch. The catalog has not yet been reconciled; that is a separate meta-workspace change after a maintainer decides diff --git a/decisions/0009-testing-ci-strategy.md b/decisions/0009-testing-ci-strategy.md index 39764b458..c4c33e879 100644 --- a/decisions/0009-testing-ci-strategy.md +++ b/decisions/0009-testing-ci-strategy.md @@ -39,8 +39,13 @@ than copied into this ADR as a transient workflow inventory. ADR-0012. ADR-0012 does **not** establish organization-wide secret-scanning coverage; that requires separately configured and verified controls. - Under the target policy, Conventional Commits (ADR-0003), PR-title validation, - and the disallowed-trailer rule would be enforced in CI. This is not a claim - of uniform live enforcement. + and the disallowed-trailer rule would be enforced in CI. Neither is a live + org-wide gate today: a sweep of the default branches of all 86 active, + non-fork, non-archived repositories found no workflow that runs the + `DISALLOWED_TRAILER_PATTERN` check or validates commit messages. Non-default + branches were not swept. The only implementation is a `commit-lint` workflow + on the `next` branch of `z-shell/zi`, which has never reached a default + branch. This is not a claim of uniform live enforcement. ### By class From 9b8a4cdce24dc7c21d33b564111d6dff4e8d5be1 Mon Sep 17 00:00:00 2001 From: Sall Date: Sat, 25 Jul 2026 00:14:42 +0100 Subject: [PATCH 3/5] docs(adr): cite concrete CI-convention sources and flag drift Copilot review: AGENTS.md is a high-level summary, not the source of the specific conventions this bullet lists; cite the instructions file and ADR-0005 that actually define them. Also flag that testing.instructions.md currently states enforcement in the present tense, which is target-state language this ADR should not let stand uncontextualized. --- decisions/0009-testing-ci-strategy.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/decisions/0009-testing-ci-strategy.md b/decisions/0009-testing-ci-strategy.md index c4c33e879..3c18385c2 100644 --- a/decisions/0009-testing-ci-strategy.md +++ b/decisions/0009-testing-ci-strategy.md @@ -32,8 +32,11 @@ than copied into this ADR as a transient workflow inventory. - Workflows comply with the org workflow conventions (SHA-pinned actions, least-privilege `permissions:`, `concurrency:`, no-emoji `name:` per ADR-0005, - kebab-case filenames). These conventions are defined in `AGENTS.md` and the CI - instructions; this ADR references them rather than duplicating their details. + kebab-case filenames). These conventions are defined in + `.github/instructions/github-actions-ci-cd-best-practices.instructions.md` + and `decisions/0005-workflow-naming-conventions.md`; `AGENTS.md` only + summarizes them. This ADR references the concrete sources rather than + duplicating their details. - Zsh sources pass `zsh -n` (syntax) and `zcompile` (compile) checks. - Dependency-update and vulnerability-remediation ownership follows accepted ADR-0012. ADR-0012 does **not** establish organization-wide secret-scanning @@ -103,7 +106,10 @@ Before acceptance, a maintainer must: discouraging release machinery in class-3 repositories (consistent with ADR-0007). - The testing instruction file (`.github/instructions/testing.instructions.md`) - would be reconciled after acceptance; it is not changed by this draft. + currently reads as present-tense enforcement (for example, it states + Conventional Commits and the disallowed-trailer check "are enforced"). That + is target-state language, not evidence of current conformance, and the file + would be reconciled after acceptance. It is not changed by this draft. ## Alternatives considered From 0a586ec94642bb8960e20f41eb69cee79ad4d587 Mon Sep 17 00:00:00 2001 From: Sall Date: Sat, 25 Jul 2026 01:34:24 +0100 Subject: [PATCH 4/5] docs(adr): record maintainer disposition on ADRs 0008-0010 Per the decision packet in #454 (comment 5013565657), decider ss-o, 2026-07-25: ADR-0008: ACCEPTED (8A). The src/zd semantic-tag publication triggers are recorded as accepted class-1 compatibility paths rather than an open question. Removed the now-resolved 'Decision review required' section and converted conditional 'if accepted' wording to direct statements throughout. ADR-0009: ACCEPTED as target policy (9A). Wove in the 9Z1 packaged-zsh release-gate definition, the 9U1 zunit release-gate requirement, and the 9R1 per-repository verification methodology. Reframed the 'Baseline (all repos)' bullets with a single target-policy lead-in instead of one hedged bullet among unhedged ones, closing the framing gap Copilot flagged after the 9A/9B question was open. Removed the now-resolved 'Decision review required' section. ADR-0010: stays PROPOSED (10D1). Recorded the 10S1 confirmation of the acknowledgement/triage/remediation targets directly in the SLA and severity sections and marked item 1 of the review checklist done, while items 2 (backup contact) and 3 (administrative verification) remain open and continue to block acceptance. --- decisions/0008-branching-model.md | 75 ++++++++---------- decisions/0009-testing-ci-strategy.md | 83 ++++++++++---------- decisions/0010-security-incident-response.md | 34 ++++---- 3 files changed, 92 insertions(+), 100 deletions(-) diff --git a/decisions/0008-branching-model.md b/decisions/0008-branching-model.md index 6dc2b89e8..dd722eb04 100644 --- a/decisions/0008-branching-model.md +++ b/decisions/0008-branching-model.md @@ -1,8 +1,8 @@ # 8. Branching Model -- **Status:** PROPOSED -- **Date:** 2026-05-29 -- **Deciders:** TBD +- **Status:** ACCEPTED +- **Date:** 2026-07-25 +- **Deciders:** ss-o - **Supersedes:** None - **Superseded by:** None @@ -24,8 +24,7 @@ default branch** and **development branch** are therefore separate concepts. The private meta-workspace catalog (`workspace/repos.yml`) is still out of date. Its `default_branch` field conflates those concepts, and some entries name `next` for repositories that do not have that branch. The catalog has not yet been -reconciled; that is a separate meta-workspace change after a maintainer decides -whether to accept this proposal. +reconciled; that is a separate meta-workspace change tracked outside this ADR. `decisions/0007-release-publication-flow.md` already defines four repository classes by delivery model. Those classes constrain publication behavior, but @@ -34,14 +33,14 @@ development branch. ## Decision -If accepted, the **canonical per-repo table below becomes the authoritative -source** for the development branch and branch model. The ADR-0007 repository -class is an _input_ to the choice because it sets the publication boundary and -a default, but it does **not** by itself determine the branch model — repo -churn/scale does. Within class 1, `wiki`/`src` use `next` → `main` while `zd` is -trunk-only; within class 2, `zsh-lint` uses `next` while `zunit` is trunk. Under -this proposal, changing a repository's assigned model requires amending this -ADR (or a superseding one), not merely creating or deleting a branch. +The **canonical per-repo table below is the authoritative source** for the +development branch and branch model. The ADR-0007 repository class is an +_input_ to the choice because it sets the publication boundary and a default, +but it does **not** by itself determine the branch model — repo churn/scale +does. Within class 1, `wiki`/`src` use `next` → `main` while `zd` is +trunk-only; within class 2, `zsh-lint` uses `next` while `zunit` is trunk. +Changing a repository's assigned model requires amending this ADR (or a +superseding one), not merely creating or deleting a branch. ### Canonical branch model @@ -59,11 +58,12 @@ ADR (or a superseding one), not merely creating or deleting a branch. | `zsh-fancy-completions` | 3 | trunk on `main` | `main` | `main` is consumable ref | | `.github` | 4 | trunk on `main` | `main` | n/a | -The publication-boundary column states the proposed policy, not a complete -inventory of live workflow triggers. At the 2026-07-18 audit, `src` and `zd` -also had semantic-tag publication triggers that the table does not capture. -Whether those triggers remain accepted class-1 exceptions is a maintainer -decision. +The publication-boundary column states the policy, not a complete inventory of +live workflow triggers. At the 2026-07-18 audit, `src` and `zd` also had +semantic-tag publication triggers that the table does not capture. Those +triggers are accepted class-1 compatibility publication paths that run +alongside the table's `main`-based boundary, not a deviation from it; they are +not scheduled for removal by this decision. ### How the class informs the default @@ -81,37 +81,26 @@ decision. branch (the "Development branch" column). For trunk repos, feature branches also start from `main`. -If this ADR is accepted, the private catalog/schema and root agent guidance need -a separate meta-workspace reconciliation. They are deliberately not changed by -this public factual-reconciliation draft. - -## Decision review required - -Before acceptance, a maintainer must: - -1. Confirm that GitHub defaults remain `main` while the table's development - branch identifies the normal integration base. -2. Decide whether the live `src` and `zd` semantic-tag publication triggers are - accepted exceptions or whether the proposed publication wording must change. -3. Accept, amend, supersede, or reject this proposal and record the decider and - decision date. +The private catalog/schema and root agent guidance need a separate +meta-workspace reconciliation. They are deliberately not changed by this +public factual-reconciliation change. ## Consequences -- If accepted, the table gives branch-policy audits an explicit public - comparison point; the ADR alone does not prevent catalog or repository drift. -- New repositories would be added to the table (with their ADR-0007 class) as - part of repository creation, before the first branch is cut. -- **Action on acceptance:** the private meta-workspace root guidance currently +- The table gives branch-policy audits an explicit public comparison point; + the ADR alone does not prevent catalog or repository drift. +- New repositories are added to the table (with their ADR-0007 class) as part + of repository creation, before the first branch is cut. +- **Pending action:** the private meta-workspace root guidance currently states "default development branch: `next` … all other work branches from - `next`" as a universal rule. On acceptance, update that guidance to reference + `next`" as a universal rule. That guidance should be updated to reference this ADR's per-repository table so agents do not get conflicting instructions - for trunk-only repositories. This separate meta-workspace change is not made - while the ADR remains proposed. + for trunk-only repositories. This separate meta-workspace change has not yet + been made. - Promotion from `next` to `main` is a publication trigger for class-1 deploy - repositories; the live tag-trigger exceptions above remain under review. For - other classes the merge validates but does not mint a release (consistent - with ADR-0007). + repositories; the live tag-trigger exceptions above are accepted alongside + it. For other classes the merge validates but does not mint a release + (consistent with ADR-0007). ## Alternatives considered diff --git a/decisions/0009-testing-ci-strategy.md b/decisions/0009-testing-ci-strategy.md index 3c18385c2..a7fa8c7a5 100644 --- a/decisions/0009-testing-ci-strategy.md +++ b/decisions/0009-testing-ci-strategy.md @@ -1,8 +1,8 @@ # 9. Testing and CI Strategy -- **Status:** PROPOSED -- **Date:** 2026-05-29 -- **Deciders:** TBD +- **Status:** ACCEPTED +- **Date:** 2026-07-25 +- **Deciders:** ss-o - **Supersedes:** None - **Superseded by:** None @@ -16,39 +16,42 @@ statement of _what level of testing each repository class owes_, which makes it hard to know whether a repo is under- or over-tested, and what a reviewer should require before merge. -ADR-0007 classified repositories by delivery model and ADR-0008 proposes a -branch model informed by those classes. This ADR similarly proposes a target CI -scope by class. It does not claim that every listed control is already live or -configured as a required check. +ADR-0007 classified repositories by delivery model and ADR-0008 establishes a +branch model informed by those classes. This ADR similarly establishes a +target CI scope by class, accepted with owned rollout gaps: it does not claim +that every listed control is already live or configured as a required check. ## Decision -If accepted, required CI scope follows the ADR-0007 repository class. Every -class shares a common target baseline; higher-risk classes add to it. Live -rollout gaps and the dated evidence behind them are tracked in issue #454 rather -than copied into this ADR as a transient workflow inventory. +Required CI scope follows the ADR-0007 repository class. Every class shares a +common target baseline; higher-risk classes add to it. Live rollout gaps and +the dated evidence behind them are tracked in issue #454 rather than copied +into this ADR as a transient workflow inventory. ### Baseline (all repos) +Every item below is target policy — the baseline every repository is expected +to meet, not an assertion that each control is already live everywhere. Live +rollout status per repository is tracked in issue #454, not restated here. + - Workflows comply with the org workflow conventions (SHA-pinned actions, least-privilege `permissions:`, `concurrency:`, no-emoji `name:` per ADR-0005, - kebab-case filenames). These conventions are defined in + kebab-case filenames), defined in `.github/instructions/github-actions-ci-cd-best-practices.instructions.md` and `decisions/0005-workflow-naming-conventions.md`; `AGENTS.md` only - summarizes them. This ADR references the concrete sources rather than - duplicating their details. + summarizes them. - Zsh sources pass `zsh -n` (syntax) and `zcompile` (compile) checks. - Dependency-update and vulnerability-remediation ownership follows accepted ADR-0012. ADR-0012 does **not** establish organization-wide secret-scanning coverage; that requires separately configured and verified controls. -- Under the target policy, Conventional Commits (ADR-0003), PR-title validation, - and the disallowed-trailer rule would be enforced in CI. Neither is a live - org-wide gate today: a sweep of the default branches of all 86 active, - non-fork, non-archived repositories found no workflow that runs the +- Conventional Commits (ADR-0003), PR-title validation, and the + disallowed-trailer rule are enforced in CI. None of these is a live org-wide + gate today: a sweep of the default branches of all 86 active, non-fork, + non-archived repositories found no workflow that runs the `DISALLOWED_TRAILER_PATTERN` check or validates commit messages. Non-default branches were not swept. The only implementation is a `commit-lint` workflow on the `next` branch of `z-shell/zi`, which has never reached a default - branch. This is not a claim of uniform live enforcement. + branch. ### By class @@ -58,11 +61,16 @@ than copied into this ADR as a transient workflow inventory. installer/loader validation, plus CodeQL where a supported language is present. 2. **Versioned tools and packages** (`zunit`, `zsh-lint`, packaged `zsh`) — a full - functional suite is **required** before a release tag is cut. ZUnit is the - target for Zsh tools and `go test` for the `zsh-lint` Go CLI. Compiled tools - additionally run an appropriate SAST control, such as CodeQL or `gosec`; a - release artifact is part of the security surface governed by - `decisions/0010-security-incident-response.md`. + functional suite is **required** before a release tag is cut, defined per + tool: `zunit`'s release workflow must run its own native suite on the exact + tag commit before publication, since prior branch checks alone do not prove + the released commit; packaged `zsh`'s gate is metadata/manifest validation + plus a clean disposable install and a startup/version smoke test, all on + the exact tag commit, since metadata-only validation alone is not a + functional suite; `zsh-lint`'s gate is `go test` on the exact tag commit. + Compiled tools additionally run an appropriate SAST control, such as + CodeQL or `gosec`; a release artifact is part of the security surface + governed by `decisions/0010-security-incident-response.md`. 3. **Git-consumed source** (`zi`, most plugins/annexes) — **validation-only**: the baseline checks above, plus ZUnit where the plugin ships tests. No release automation and no coverage gate; these repos are consumed from source and the @@ -80,27 +88,16 @@ ratcheting is a per-repo maintainer decision. Under the target policy, each repository marks its class-appropriate checks as required for merge to its publication branch (`main`, or `next` → `main` per ADR-0008). Validation-only repositories require the baseline; class-2 -repositories additionally require the functional suite. Actual rulesets and -required-check configuration must be verified repository by repository; this -ADR does not assert that they are live. - -## Decision review required - -Before acceptance, a maintainer must: - -1. Decide whether to accept this ADR now as target policy with owned rollout - gaps, or defer acceptance until the selected controls are implemented. -2. Define the full functional suite for packaged `zsh` and the release-gate - requirement for `zunit`. -3. Select and verify each repository's actual required checks, development-branch - validation, SAST coverage, and release-suite gate. -4. Accept, amend, supersede, or reject this proposal and record the decider and - decision date. +repositories additionally require the functional suite. Required checks, +development-branch validation, SAST coverage, and the release-suite gate are +each verified repository by repository through owning issues; the presence of +a workflow file is not by itself treated as proof that a check is required or +that a ruleset enforces it. ## Consequences -- If accepted, a reviewer can determine the target CI bar from the repository's - class instead of inferring policy from each workflow. +- A reviewer can determine the target CI bar from the repository's class + instead of inferring policy from each workflow. - New repositories have an explicit target CI scope for their class. - "Validation-only for git-consumed repositories" becomes an explicit rule, discouraging release machinery in class-3 repositories (consistent with @@ -109,7 +106,7 @@ Before acceptance, a maintainer must: currently reads as present-tense enforcement (for example, it states Conventional Commits and the disallowed-trailer check "are enforced"). That is target-state language, not evidence of current conformance, and the file - would be reconciled after acceptance. It is not changed by this draft. + should be reconciled to say so. It is not changed by this decision. ## Alternatives considered diff --git a/decisions/0010-security-incident-response.md b/decisions/0010-security-incident-response.md index 9568a5d05..64191ac70 100644 --- a/decisions/0010-security-incident-response.md +++ b/decisions/0010-security-incident-response.md @@ -43,16 +43,16 @@ affected repository and advisory is required before escalation is operational. ### Acknowledgement SLA -The proposed targets, subject to maintainer confirmation, are: +Confirmed 2026-07-25 (ss-o): - Acknowledge a security report within **3 business days** of receipt. - Triage to a severity within **5 business days**. ### Severity and remediation targets -Severity uses CVSS-style judgment (impact × exploitability). The proposed -time-to-fix or documented-mitigation targets from triage, also subject to -maintainer confirmation, are: +Severity uses CVSS-style judgment (impact × exploitability). Confirmed +2026-07-25 (ss-o), the time-to-fix or documented-mitigation targets from +triage are: | Severity | Examples | Target | | -------- | --------------------------------------------- | ----------- | @@ -103,16 +103,22 @@ verified. This ADR does not claim that those controls are enabled. ## Decision review required -Before acceptance, a maintainer must: - -1. Confirm the proposed 3/5-business-day acknowledgement and triage targets and - the 7/30/90-day remediation targets. -2. Name a backup incident contact and verify that contact's repository and - advisory permissions. -3. Confirm where private vulnerability reporting, notifications, and release - immutability are enabled or required. -4. Accept, amend, supersede, or reject this proposal and record the decider and - decision date. +This ADR remains **PROPOSED**. Before acceptance, a maintainer must: + +1. [x] Confirm the proposed 3/5-business-day acknowledgement and triage + targets and the 7/30/90-day remediation targets. Confirmed 2026-07-25 + (ss-o); see the SLA and severity sections above. +2. [ ] Name a backup incident contact and verify that contact's repository and + advisory permissions. +3. [ ] Confirm where private vulnerability reporting, notifications, and + release immutability are enabled or required. +4. [ ] Accept, amend, supersede, or reject this proposal and record the + decider and decision date. + +Items 2 and 3 are unresolved, so this ADR is deliberately kept proposed rather +than accepted with those as rollout gaps: an incident-response process without +a verified escalation route or verified reporting/notification settings would +overstate what the org can actually deliver. ## Consequences From e3a597dd7bcdcc1c863777f95ae92599afa203ac Mon Sep 17 00:00:00 2001 From: Sall Date: Sat, 25 Jul 2026 01:49:22 +0100 Subject: [PATCH 5/5] docs(adr): fix SECURITY.md path in ADR-0010 Copilot review: the repo's security policy file is .github/SECURITY.md; three references in this ADR were missing the .github/ prefix. The Context section and References already had it right. --- decisions/0010-security-incident-response.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/decisions/0010-security-incident-response.md b/decisions/0010-security-incident-response.md index 64191ac70..302e71af1 100644 --- a/decisions/0010-security-incident-response.md +++ b/decisions/0010-security-incident-response.md @@ -80,7 +80,7 @@ published version tag. - Fixes land through the normal branch model (ADR-0008); critical fixes may use a `hotfix-` branch from the publication branch. -- Coordinate disclosure with the reporter per `SECURITY.md`: no public disclosure +- Coordinate disclosure with the reporter per `.github/SECURITY.md`: no public disclosure until a fix is published or the report is declined, and credit the reporter. - Where a release artifact exists (ADR-0007 class 2), cut a patched tag and note the security fix in the release notes. @@ -126,15 +126,15 @@ overstate what the org can actually deliver. acknowledgement and remediation path instead of ad-hoc handling. - `runbooks/security-incident-response.md` would be reconciled after acceptance; it is not changed by this draft. -- `SECURITY.md` remains the reporter-facing entry point and would be reconciled - after acceptance; this ADR defines the proposed internal response. +- `.github/SECURITY.md` remains the reporter-facing entry point and would be + reconciled after acceptance; this ADR defines the proposed internal response. - Sanitized post-incident reviews build durable security memory without exposing restricted report data. ## Alternatives considered -- **Keep only `SECURITY.md`.** Rejected: it covers intake but leaves response - undefined, which is where time is actually lost. +- **Keep only `.github/SECURITY.md`.** Rejected: it covers intake but leaves + response undefined, which is where time is actually lost. - **Adopt a formal external framework (e.g. full ISO/NIST IR process).** Rejected as disproportionate for a small-maintainer OSS org; this ADR takes the load-bearing pieces (SLA, severity targets, escalation, review) without the