Skip to content
This repository was archived by the owner on Jul 15, 2026. It is now read-only.
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
39 changes: 39 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Dependabot: weekly dependency PRs for both Go modules, the Actions pins in
# .github/workflows, and the Docusaurus site. Minor + patch bumps are grouped
# into one PR per ecosystem so the weekly noise is a handful of PRs, not
# dozens; majors stay individual because they usually need real review.
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: weekly
groups:
go-minor-and-patch:
update-types: ["minor", "patch"]

# The desktop shell is a separate Go module with its own go.mod (see
# Makefile: it is the repo's only cgo code, quarantined from the core).
- package-ecosystem: gomod
directory: "/cmd/msgbrowse-desktop"
schedule:
interval: weekly
groups:
desktop-minor-and-patch:
update-types: ["minor", "patch"]

- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
groups:
actions:
patterns: ["*"]

- package-ecosystem: npm
directory: "/docs-site"
schedule:
interval: weekly
groups:
docs-site-minor-and-patch:
update-types: ["minor", "patch"]
56 changes: 56 additions & 0 deletions .github/rulesets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Branch protection rulesets

Ruleset definitions for this repository, kept in-repo so the protection policy
is reviewable and versioned like everything else. GitHub does not read this
directory automatically — a repo admin applies it once (and re-applies it after
any change here).

## What `main.json` enforces on `main`

- **No direct pushes** — all changes land through a pull request.
- **Squash merges only** — matches the SDD merge strategy in CLAUDE.md and
keeps history linear (the `required_linear_history` rule backstops this).
- **Required status checks** — the two CI jobs that run on *every* PR must
pass before merging:
- `gofmt + vet + tests` (ci.yml)
- `docker image builds` (ci.yml)

The CSS, Desktop, and Security workflows are deliberately **not** required:
they are path-filtered and only run when their files change, so requiring
them would deadlock every PR that doesn't touch those paths (a required
check that never reports never turns green).
- **Review-thread resolution required** — every PR conversation must be
resolved before merge. The approving-review count is 0 because this repo is
developed by a single owner + agent pair; bump
`required_approving_review_count` to 1 if a second reviewer account should
gate merges.
- **No force pushes, no branch deletion** on `main`.
- **Branches need not be up to date with `main` to merge**
(`strict_required_status_checks_policy: false`) — squash merges keep history
clean without forcing a rebase-and-rerun on every landed PR. Flip it to
`true` for stricter pre-merge testing at the cost of serializing merges.

## How to apply

### Option A — GitHub UI (import)

Settings → Rules → Rulesets → New ruleset → **Import a ruleset** → upload
`main.json`.

### Option B — `gh` CLI

```sh
gh api repos/joestump-agent/msgbrowse/rulesets --input .github/rulesets/main.json
```

To update an existing ruleset instead of creating a duplicate, find its id and
`PUT` it:

```sh
gh api repos/joestump-agent/msgbrowse/rulesets --jq '.[] | {id, name}'
gh api -X PUT repos/joestump-agent/msgbrowse/rulesets/<id> --input .github/rulesets/main.json
```

> **Plan note:** rulesets (like classic branch protection) are free on public
> repositories; private repositories need GitHub Pro/Team for them to be
> enforced.
39 changes: 39 additions & 0 deletions .github/rulesets/main.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "protect-main",
"target": "branch",
"enforcement": "active",
"conditions": {
"ref_name": {
"include": ["~DEFAULT_BRANCH"],
"exclude": []
}
},
"rules": [
{ "type": "deletion" },
{ "type": "non_fast_forward" },
{ "type": "required_linear_history" },
{
"type": "pull_request",
"parameters": {
"required_approving_review_count": 0,
"dismiss_stale_reviews_on_push": true,
"require_code_owner_review": false,
"require_last_push_approval": false,
"required_review_thread_resolution": true,
"allowed_merge_methods": ["squash"]
}
},
{
"type": "required_status_checks",
"parameters": {
"strict_required_status_checks_policy": false,
"do_not_enforce_on_create": false,
"required_status_checks": [
{ "context": "gofmt + vet + tests" },
{ "context": "docker image builds" }
]
}
}
],
"bypass_actors": []
}
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ jobs:
steps:
- uses: actions/checkout@v4

# check-latest so builds pick up Go patch releases (stdlib security
# fixes land there — see security.yml) instead of the runner's cache.
- uses: actions/setup-go@v5
with:
go-version: "1.25"
check-latest: true
cache: true

# make check runs gofmt -l, go vet, and go test — no build tag needed.
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,12 @@ jobs:
steps:
- uses: actions/checkout@v4

# check-latest so release artifacts pick up Go patch releases (stdlib
# security fixes land there — see security.yml).
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
check-latest: true
cache: true
cache-dependency-path: |
go.sum
Expand Down Expand Up @@ -480,9 +483,12 @@ jobs:
sudo apt-get update
sudo apt-get install -y --no-install-recommends libgtk-3-dev libwebkit2gtk-4.1-dev pkg-config

# check-latest so release artifacts pick up Go patch releases (stdlib
# security fixes land there — see security.yml).
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
check-latest: true
cache: true
cache-dependency-path: |
go.sum
Expand Down
74 changes: 74 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Security

# govulncheck over both Go modules (the core and the desktop shell). Unlike a
# plain dependency-version audit, govulncheck reports only vulnerabilities in
# code paths the modules actually reach, so findings are actionable.
#
# Scheduling rationale: new vulnerabilities are published against dependencies
# we already have, not just when we bump them — so this runs weekly against
# main (and on demand) in addition to gating PRs that touch the module graphs.
# It is deliberately NOT a required branch-protection check: it is
# path-filtered on PRs, and a newly published vuln in an unrelated dependency
# must not turn every open PR red.
on:
pull_request:
paths:
- "go.mod"
- "go.sum"
- "cmd/msgbrowse-desktop/go.mod"
- "cmd/msgbrowse-desktop/go.sum"
- ".github/workflows/security.yml"
push:
branches: [main]
paths:
- "go.mod"
- "go.sum"
- "cmd/msgbrowse-desktop/go.mod"
- "cmd/msgbrowse-desktop/go.sum"
- ".github/workflows/security.yml"
schedule:
# Weekly, Monday 06:23 UTC (off the :00 spike so scheduled runs aren't
# queued behind everyone else's).
- cron: "23 6 * * 1"
workflow_dispatch:

permissions:
contents: read

jobs:
govulncheck:
name: govulncheck
runs-on: ubuntu-latest
# The core is CGO_ENABLED=0 everywhere else in CI; keep the scan honest to
# the shipped build.
env:
CGO_ENABLED: "0"
steps:
- uses: actions/checkout@v4

# check-latest matters here: stdlib vulnerabilities are fixed in patch
# releases (e.g. GO-2026-5856 fixed in 1.25.12), so scanning with the
# runner's cached older patch would keep reporting fixed vulns — or worse,
# miss that the build toolchain needs bumping.
- uses: actions/setup-go@v5
with:
go-version: "1.25"
check-latest: true
cache: true
cache-dependency-path: |
go.sum
cmd/msgbrowse-desktop/go.sum

- name: Install govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@latest

- name: Scan core module
run: govulncheck ./...

# The desktop shell is its own Go module (cmd/msgbrowse-desktop/go.mod).
# Without the `desktop` build tag this scans the same pure-Go surface the
# headless tests cover — the cgo/webview code needs GTK headers and is
# exercised by desktop.yml instead.
- name: Scan desktop module
working-directory: cmd/msgbrowse-desktop
run: govulncheck ./...
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
# --- build stage ---
# msgbrowse uses the pure-Go modernc.org/sqlite driver (FTS5 built in), so the
# build needs no C toolchain — just the Go image.
FROM golang:1.25-bookworm AS build
# The official golang images set GOTOOLCHAIN=local, which would silently ignore
# the go.mod toolchain directive — pin the exact patch so the shipped image gets
# stdlib security fixes (see GO-2026-5856).
FROM golang:1.25.12-bookworm AS build

WORKDIR /src

Expand Down
2 changes: 2 additions & 0 deletions cmd/msgbrowse-desktop/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module github.com/joestump/msgbrowse/cmd/msgbrowse-desktop

go 1.25.0

toolchain go1.25.12

replace github.com/joestump/msgbrowse => ../..

require (
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module github.com/joestump/msgbrowse

go 1.25.0

toolchain go1.25.12

require (
github.com/charmbracelet/log v1.0.0
github.com/modelcontextprotocol/go-sdk v1.6.1
Expand Down
Loading