From 89b7f99a8d3e17c883677b75e399a5d12b60ff2f Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Sun, 28 Jun 2026 15:12:50 +0200 Subject: [PATCH] =?UTF-8?q?build(ci):=20make=20dugite-check=20=E2=80=94=20?= =?UTF-8?q?track=20dugite-native=20upstream=20for=20security=20(T-88)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit D-59 requires tracking dugite-native (bundled git) releases for security updates, but it lived only in the D-record prose with no mechanism (clean-house flagged RULE-SUNSET-WITHOUT-TICKET). Add ci/check_dugite_version.sh + a `make dugite-check` target: compares the Makefile DUGITE_VERSION pin against the latest desktop/dugite-native release and loudly flags CVE / security mentions in the notes. Informational (not a push gate) — the bump itself is manual per D-63 and automated by T-25. The script header is the maintenance home (dugite is fetched, not built, and native/dugite/ is gitignored, so there's no BUILD.md to record it): cadence (quarterly / on a git CVE), advisory subscriptions, and the bump procedure. D-59's cost line + a Makefile comment now point at the mechanism. T-88 stays open as the recurring calendar; first check (2026-06-28) shows v2.53.0-3 current. Co-Authored-By: Claude Opus 4.8 (1M context) --- .pql/changelog/ticket_history/2026-06.sql | 24 +++++++++++ .pql/changelog/tickets/2026-06.sql | 44 +++++++++++++++++++ Makefile | 6 +++ ci/check_dugite_version.sh | 52 +++++++++++++++++++++++ governance/decisions/tooling.md | 2 +- 5 files changed, 127 insertions(+), 1 deletion(-) create mode 100755 ci/check_dugite_version.sh diff --git a/.pql/changelog/ticket_history/2026-06.sql b/.pql/changelog/ticket_history/2026-06.sql index f1f71ad1..db53768c 100644 --- a/.pql/changelog/ticket_history/2026-06.sql +++ b/.pql/changelog/ticket_history/2026-06.sql @@ -7665,3 +7665,27 @@ INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, chang INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGVDBD0F14FV5CDJQB063YSR', 'status', 'in_progress', 'done', NULL, '2026-06-28 10:17:18', '2026-06-28 10:17:18.750', '2026-06-28 10:17:18.750', NULL, '56fc691a9c2eb8dd703db036acee907a', 2) ON CONFLICT(hash) DO NOTHING; INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGVNCZS0JZP5Y7596GBV4RFC', 'status', 'backlog', 'in_progress', NULL, '2026-06-28 12:52:04', '2026-06-28 12:52:04.335', '2026-06-28 12:52:04.335', NULL, 'd0ba6a1fd4e721c47dcd766896eaf4f7', 2) ON CONFLICT(hash) DO NOTHING; INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGVNCZS0JZP5Y7596GBV4RFC', 'status', 'in_progress', 'done', NULL, '2026-06-28 12:58:12', '2026-06-28 12:58:12.193', '2026-06-28 12:58:12.193', NULL, '3086f007c53ceb3c9683b752649c19ad', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'status', 'backlog', 'in_progress', NULL, '2026-06-28 13:04:13', '2026-06-28 13:04:13.429', '2026-06-28 13:04:13.429', NULL, '95eee0461d6b7d2336c4f67be0c347ed', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'status', 'in_progress', 'in_progress', NULL, '2026-06-28 13:04:42', '2026-06-28 13:04:42.607', '2026-06-28 13:04:42.607', NULL, '2e336b2ef115de85788ce81540f38663', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'description', 'D-59 (bundled git via dugite-native) costs out: "Must track dugite-native releases for security updates." Up to today this lived only in the D-record prose with no tracking — clean-house v1 flagged it as RULE-SUNSET-WITHOUT-TICKET. + +**Acceptance:** +- A periodic check (manual or scheduled) compares the bundled `native/dugite/` SHA against the latest release at https://github.com/desktop/dugite-native/releases. +- When a new release lands with a CVE label or fixes a CVE-tagged git release, schedule a bump; otherwise track the version drift. +- Bumps follow D-63: rebuild with the new SHA, update `BUILD.md`, update `assets/licenses.yaml` if the dugite or git version changed, refresh the binary in `native/dugite/`. + +**Periodicity:** quarterly check is enough during normal operation; faster on git CVE announcements (subscribe to https://github.com/git/git/security/advisories, https://github.com/desktop/dugite-native/security/advisories). + +**Out of scope:** the rebuild itself is T-25 (CI reproducible build for libtree-sitter.so) — same shape applies to dugite. This ticket is the calendar; T-25 is the machine.', 'D-59 (bundled git via dugite-native) costs out: "Must track dugite-native releases for security updates." Up to today this lived only in the D-record prose with no tracking — clean-house v1 flagged it as RULE-SUNSET-WITHOUT-TICKET. + +**Acceptance:** +- A periodic check (manual or scheduled) compares the bundled `native/dugite/` SHA against the latest release at https://github.com/desktop/dugite-native/releases. +- When a new release lands with a CVE label or fixes a CVE-tagged git release, schedule a bump; otherwise track the version drift. +- Bumps follow D-63: rebuild with the new SHA, update `BUILD.md`, update `assets/licenses.yaml` if the dugite or git version changed, refresh the binary in `native/dugite/`. + +**Periodicity:** quarterly check is enough during normal operation; faster on git CVE announcements (subscribe to https://github.com/git/git/security/advisories, https://github.com/desktop/dugite-native/security/advisories). + +**Out of scope:** the rebuild itself is T-25 (CI reproducible build for libtree-sitter.so) — same shape applies to dugite. This ticket is the calendar; T-25 is the machine. + +Mechanism shipped 2026-06-28: ''make dugite-check'' (ci/check_dugite_version.sh) compares the Makefile DUGITE_VERSION pin against the latest desktop/dugite-native release and flags CVE/security mentions in the notes. D-59''s cost line + a Makefile comment now point at it (closes the clean-house RULE-SUNSET-WITHOUT-TICKET flag). FIRST CHECK (2026-06-28): bundled v2.53.0-3 == latest v2.53.0-3 — up to date, no CVE flagged, no bump needed. RECURRING — do not close. Next check due ~2026-09-28 (quarterly), or immediately on a git/dugite security advisory (subscribe: github.com/git/git/security/advisories, github.com/desktop/dugite-native/security/advisories). Bump = D-63 record + T-25 (CI machine); ''scheduled'' CI cron deferred until CI exists (T-25/T-491).', NULL, '2026-06-28 13:12:29', '2026-06-28 13:12:29.257', '2026-06-28 13:12:29.257', NULL, '46ef38531a96b893f70de886f19187cd', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'status', 'in_progress', 'backlog', NULL, '2026-06-28 13:12:29', '2026-06-28 13:12:29.289', '2026-06-28 13:12:29.289', NULL, 'aa8e667ed39d133c1bd3ca547d5a9acf', 2) ON CONFLICT(hash) DO NOTHING; diff --git a/.pql/changelog/tickets/2026-06.sql b/.pql/changelog/tickets/2026-06.sql index 84a58446..c4214254 100644 --- a/.pql/changelog/tickets/2026-06.sql +++ b/.pql/changelog/tickets/2026-06.sql @@ -9679,3 +9679,47 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGVNCZS0JZP5Y7596GBV4RFC', 'bug', '06FB0TNQM5TWC00GW0P3X02HZW', 'i18n warns on missing tool.name.* keys for proper-name tools (Bash, ScheduleWakeup, MCP)', NULL, 'backlog', 'medium', NULL, NULL, NULL, '2026-06-28 10:45:31.720', '2026-06-28 10:45:31.720', NULL, '771379bafaa0fc6b2bb7c887428c1c45', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGVNCZS0JZP5Y7596GBV4RFC', 'bug', '06FB0TNQM5TWC00GW0P3X02HZW', 'i18n warns on missing tool.name.* keys for proper-name tools (Bash, ScheduleWakeup, MCP)', NULL, 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-28 10:45:31.720', '2026-06-28 12:52:04.335', NULL, '2682b803f14e42f09665aed575dd55a9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGVNCZS0JZP5Y7596GBV4RFC', 'bug', '06FB0TNQM5TWC00GW0P3X02HZW', 'i18n warns on missing tool.name.* keys for proper-name tools (Bash, ScheduleWakeup, MCP)', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-06-28 10:45:31.720', '2026-06-28 12:58:12.193', NULL, 'a57d3c5c309321a204cb81441198d7a6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'task', NULL, 'track dugite-native upstream releases for security updates', 'D-59 (bundled git via dugite-native) costs out: "Must track dugite-native releases for security updates." Up to today this lived only in the D-record prose with no tracking — clean-house v1 flagged it as RULE-SUNSET-WITHOUT-TICKET. + +**Acceptance:** +- A periodic check (manual or scheduled) compares the bundled `native/dugite/` SHA against the latest release at https://github.com/desktop/dugite-native/releases. +- When a new release lands with a CVE label or fixes a CVE-tagged git release, schedule a bump; otherwise track the version drift. +- Bumps follow D-63: rebuild with the new SHA, update `BUILD.md`, update `assets/licenses.yaml` if the dugite or git version changed, refresh the binary in `native/dugite/`. + +**Periodicity:** quarterly check is enough during normal operation; faster on git CVE announcements (subscribe to https://github.com/git/git/security/advisories, https://github.com/desktop/dugite-native/security/advisories). + +**Out of scope:** the rebuild itself is T-25 (CI reproducible build for libtree-sitter.so) — same shape applies to dugite. This ticket is the calendar; T-25 is the machine.', 'in_progress', 'low', NULL, NULL, 'D-59', '2026-05-06 14:34:35', '2026-06-28 13:04:13.429', NULL, 'c3f38afed2af0fa1adee9b5fb32ab1b4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'task', NULL, 'track dugite-native upstream releases for security updates', 'D-59 (bundled git via dugite-native) costs out: "Must track dugite-native releases for security updates." Up to today this lived only in the D-record prose with no tracking — clean-house v1 flagged it as RULE-SUNSET-WITHOUT-TICKET. + +**Acceptance:** +- A periodic check (manual or scheduled) compares the bundled `native/dugite/` SHA against the latest release at https://github.com/desktop/dugite-native/releases. +- When a new release lands with a CVE label or fixes a CVE-tagged git release, schedule a bump; otherwise track the version drift. +- Bumps follow D-63: rebuild with the new SHA, update `BUILD.md`, update `assets/licenses.yaml` if the dugite or git version changed, refresh the binary in `native/dugite/`. + +**Periodicity:** quarterly check is enough during normal operation; faster on git CVE announcements (subscribe to https://github.com/git/git/security/advisories, https://github.com/desktop/dugite-native/security/advisories). + +**Out of scope:** the rebuild itself is T-25 (CI reproducible build for libtree-sitter.so) — same shape applies to dugite. This ticket is the calendar; T-25 is the machine.', 'in_progress', 'low', NULL, NULL, 'D-59', '2026-05-06 14:34:35', '2026-06-28 13:04:42.607', NULL, 'f862a90cce89bd454fe751e8baa79bbb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'task', NULL, 'track dugite-native upstream releases for security updates', 'D-59 (bundled git via dugite-native) costs out: "Must track dugite-native releases for security updates." Up to today this lived only in the D-record prose with no tracking — clean-house v1 flagged it as RULE-SUNSET-WITHOUT-TICKET. + +**Acceptance:** +- A periodic check (manual or scheduled) compares the bundled `native/dugite/` SHA against the latest release at https://github.com/desktop/dugite-native/releases. +- When a new release lands with a CVE label or fixes a CVE-tagged git release, schedule a bump; otherwise track the version drift. +- Bumps follow D-63: rebuild with the new SHA, update `BUILD.md`, update `assets/licenses.yaml` if the dugite or git version changed, refresh the binary in `native/dugite/`. + +**Periodicity:** quarterly check is enough during normal operation; faster on git CVE announcements (subscribe to https://github.com/git/git/security/advisories, https://github.com/desktop/dugite-native/security/advisories). + +**Out of scope:** the rebuild itself is T-25 (CI reproducible build for libtree-sitter.so) — same shape applies to dugite. This ticket is the calendar; T-25 is the machine. + +Mechanism shipped 2026-06-28: ''make dugite-check'' (ci/check_dugite_version.sh) compares the Makefile DUGITE_VERSION pin against the latest desktop/dugite-native release and flags CVE/security mentions in the notes. D-59''s cost line + a Makefile comment now point at it (closes the clean-house RULE-SUNSET-WITHOUT-TICKET flag). FIRST CHECK (2026-06-28): bundled v2.53.0-3 == latest v2.53.0-3 — up to date, no CVE flagged, no bump needed. RECURRING — do not close. Next check due ~2026-09-28 (quarterly), or immediately on a git/dugite security advisory (subscribe: github.com/git/git/security/advisories, github.com/desktop/dugite-native/security/advisories). Bump = D-63 record + T-25 (CI machine); ''scheduled'' CI cron deferred until CI exists (T-25/T-491).', 'in_progress', 'low', NULL, NULL, 'D-59', '2026-05-06 14:34:35', '2026-06-28 13:12:29.257', NULL, '9892c12985c069f85e0f5e78892b6d88', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'task', NULL, 'track dugite-native upstream releases for security updates', 'D-59 (bundled git via dugite-native) costs out: "Must track dugite-native releases for security updates." Up to today this lived only in the D-record prose with no tracking — clean-house v1 flagged it as RULE-SUNSET-WITHOUT-TICKET. + +**Acceptance:** +- A periodic check (manual or scheduled) compares the bundled `native/dugite/` SHA against the latest release at https://github.com/desktop/dugite-native/releases. +- When a new release lands with a CVE label or fixes a CVE-tagged git release, schedule a bump; otherwise track the version drift. +- Bumps follow D-63: rebuild with the new SHA, update `BUILD.md`, update `assets/licenses.yaml` if the dugite or git version changed, refresh the binary in `native/dugite/`. + +**Periodicity:** quarterly check is enough during normal operation; faster on git CVE announcements (subscribe to https://github.com/git/git/security/advisories, https://github.com/desktop/dugite-native/security/advisories). + +**Out of scope:** the rebuild itself is T-25 (CI reproducible build for libtree-sitter.so) — same shape applies to dugite. This ticket is the calendar; T-25 is the machine. + +Mechanism shipped 2026-06-28: ''make dugite-check'' (ci/check_dugite_version.sh) compares the Makefile DUGITE_VERSION pin against the latest desktop/dugite-native release and flags CVE/security mentions in the notes. D-59''s cost line + a Makefile comment now point at it (closes the clean-house RULE-SUNSET-WITHOUT-TICKET flag). FIRST CHECK (2026-06-28): bundled v2.53.0-3 == latest v2.53.0-3 — up to date, no CVE flagged, no bump needed. RECURRING — do not close. Next check due ~2026-09-28 (quarterly), or immediately on a git/dugite security advisory (subscribe: github.com/git/git/security/advisories, github.com/desktop/dugite-native/security/advisories). Bump = D-63 record + T-25 (CI machine); ''scheduled'' CI cron deferred until CI exists (T-25/T-491).', 'backlog', 'low', NULL, NULL, 'D-59', '2026-05-06 14:34:35', '2026-06-28 13:12:29.289', NULL, '0ef1067dc16303cce58e4b0fb485fa1f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); diff --git a/Makefile b/Makefile index 0c16c3bc..9a1ce1a8 100644 --- a/Makefile +++ b/Makefile @@ -264,6 +264,8 @@ else ifeq ($(FLUTTER_OS),macos) endif # -- dugite-native (bundled git) ------------------------------------------ +# Security tracking (D-59): run `make dugite-check` quarterly, or on a git CVE, +# to compare this pin against the latest upstream release. T-88 is the calendar. DUGITE_VERSION := v2.53.0-3 DUGITE_COMMIT := f49d009 @@ -330,6 +332,10 @@ clide-cli-clean: ## Remove the compiled C `clide` client. security: ## Supply-chain gate — osv-scanner over pubspec.lock (CI PR-merge pipeline; run locally on demand). Fails on a known advisory. ci/osv_scan.sh +.PHONY: dugite-check +dugite-check: ## Track dugite-native (bundled git) upstream releases for security drift (T-88 / D-59). Run quarterly, or on a git CVE. Informational, not a gate. + ci/check_dugite_version.sh + # -- pre-push gate -------------------------------------------------------- .PHONY: decisions-validate diff --git a/ci/check_dugite_version.sh b/ci/check_dugite_version.sh new file mode 100755 index 00000000..bd763422 --- /dev/null +++ b/ci/check_dugite_version.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# T-88 — track dugite-native (bundled git) upstream releases for security +# updates (D-59). Compares the pinned DUGITE_VERSION against the latest +# desktop/dugite-native release and flags CVE / security mentions. +# +# WHY THIS SCRIPT IS THE MAINTENANCE HOME: dugite's binary is FETCHED at build +# time (`make dugite-fetch`), not built, and native/dugite/ is gitignored — so +# there is no `native/dugite/BUILD.md` (D-63) to record it. The pin lives in the +# Makefile (DUGITE_VERSION / DUGITE_COMMIT); this script + its `make dugite-check` +# target are the version-tracking calendar D-59 requires. +# +# CADENCE: run quarterly during normal operation. Run IMMEDIATELY on a git or +# dugite-native security advisory — subscribe to: +# https://github.com/git/git/security/advisories +# https://github.com/desktop/dugite-native/security/advisories +# +# This check is INFORMATIONAL (not a push gate): it reports drift and flags CVE +# mentions. The bump itself is manual per D-63 (reproducibility record) and is +# automated by T-25 (CI). A bump updates: Makefile DUGITE_VERSION/COMMIT, the +# fetched binary in native/dugite/, and assets/licenses.yaml if the bundled git +# or dugite version changed. +set -euo pipefail +cd "$(dirname "$0")/.." + +REPO="desktop/dugite-native" +CURRENT="$(grep -E '^DUGITE_VERSION[[:space:]]*:=' Makefile | head -1 | sed -E 's/.*:=[[:space:]]*//')" + +# Public read — no auth needed for a quarterly check. gh would raise the rate +# limit but isn't required; curl keeps this dependency-free. +json="$(curl -fsSL -H 'Accept: application/vnd.github+json' "https://api.github.com/repos/$REPO/releases/latest" 2>/dev/null || true)" +LATEST="$(printf '%s' "$json" | sed -nE 's/.*"tag_name":[[:space:]]*"([^"]+)".*/\1/p' | head -1)" + +if [[ -z "$LATEST" ]]; then + echo "==> dugite-check: couldn't reach the dugite-native releases API." >&2 + echo " Check manually: https://github.com/$REPO/releases" >&2 + exit 2 +fi + +echo "==> dugite-check (T-88): bundled '$CURRENT' vs latest release '$LATEST'" +if [[ "$CURRENT" == "$LATEST" ]]; then + echo " OK — up to date." +else + echo " DRIFT — a newer dugite-native release exists: $CURRENT -> $LATEST" + echo " Bump (D-63 record; machine: T-25): update Makefile DUGITE_VERSION/COMMIT," + echo " refresh native/dugite/, and assets/licenses.yaml if the git/dugite version changed." +fi + +# Loud flag when the latest release notes mention a CVE / security fix — those +# jump the queue regardless of the quarterly cadence. +if printf '%s' "$json" | grep -qiE 'cve-[0-9]{4}|security (fix|advisory|release|update)|vulnerab'; then + echo " !! SECURITY: the latest release notes mention a CVE / security fix — schedule a bump NOW." >&2 +fi diff --git a/governance/decisions/tooling.md b/governance/decisions/tooling.md index e63b8ada..4da5626c 100644 --- a/governance/decisions/tooling.md +++ b/governance/decisions/tooling.md @@ -48,7 +48,7 @@ Toolchain, supply chain, CI, ignore strategy. - **Decision:** Ship a self-contained Git binary from [dugite-native](https://github.com/desktop/dugite-native) (the same distribution GitHub Desktop bundles). Downloaded at build time via `make dugite-fetch`, stored under `native/dugite/`, gitignored. The `Toolchain` class resolves to the bundled binary first, falling back to system git on PATH. - **Rationale:** The macOS app sandbox blocks execution of Homebrew-installed git (symlinks resolve to Cellar paths that SBPL cannot match without freezing rendering). `/usr/bin/git` is an xcrun shim that refuses to run inside a sandbox. Bundling dugite-native makes clide self-contained — no dependency on Homebrew, Xcode CLT, or system git. The approach is proven: GitHub Desktop, Tower, and other git GUI apps all bundle their own git for the same reason. - **Alternatives rejected:** (R) libgit2 via FFI — missing porcelain commands (pull/push/rebase), no hooks, would require rewriting GitClient. (R) Build git from source — dugite-native already does this with better infra. (R) SBPL exceptions for Homebrew — `(subpath "/opt/homebrew")` for process-exec freezes Flutter rendering on macOS 26. -- **Cost:** ~57 MB download (~199 MB unpacked, stripped at build time). Must track dugite-native releases for security updates (tracked in T-88). GPL-2.0 (git binary) applies to the bundled artefact, not to clide's MIT code. +- **Cost:** ~57 MB download (~199 MB unpacked, stripped at build time). Must track dugite-native releases for security updates — `make dugite-check` compares the Makefile pin against the latest upstream release and flags CVE mentions; run quarterly or on a git CVE (the calendar is T-88; the bump machine is D-63 / T-25). GPL-2.0 (git binary) applies to the bundled artefact, not to clide's MIT code. - **Cross-reference:** [D-31](#d-31-prefer-zero-deps-exact-pin), [D-42](#d-42-dependencies-documented-in-licensesyaml). - **Raised by:** 2026-04-25 macOS sandbox investigation.