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
1 change: 1 addition & 0 deletions .github/release-allowed-signers
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
steipete@gmail.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII9XsaCcr8TInPnHcuTVfvXXcsoUFrOE7menfbEIHFW9 steipete@gmail.com
97 changes: 0 additions & 97 deletions .github/workflows/release-assets.yml

This file was deleted.

40 changes: 40 additions & 0 deletions .github/workflows/release-unified.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Release (unified)

on:
workflow_dispatch:
inputs:
version:
description: SemVer to release
required: true
type: string

permissions: {}

jobs:
release:
permissions:
actions: read
checks: read
contents: write
pull-requests: write
statuses: read
uses: openclaw/release-workflows/.github/workflows/release-go-cli.yml@v1
with:
version: ${{ inputs.version }}
repository-type: openclaw
homebrew-tap: openclaw/homebrew-tap
homebrew-formula: gitcrawl
archive-files: '["CHANGELOG.md","LICENSE","README.md"]'
checksum-filename: checksums.txt
nfpm: auto
stable-identifier: org.openclaw.gitcrawl
require-signed-tag: true
darwin-universal: disabled
ci-check-events: '["push","pull_request"]'
secrets:
MACOS_SIGNING_P12: ${{ secrets.MACOS_SIGNING_P12 }}
MACOS_SIGNING_P12_PASSWORD: ${{ secrets.MACOS_SIGNING_P12_PASSWORD }}
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_PRIVATE_KEY_P8: ${{ secrets.ASC_PRIVATE_KEY_P8 }}
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
59 changes: 0 additions & 59 deletions .github/workflows/release.yml

This file was deleted.

4 changes: 0 additions & 4 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ builds:
targets:
- darwin_amd64
- darwin_arm64
hooks:
post:
- ./scripts/codesign-macos.sh "{{ .Path }}"

archives:
- ids:
- gitcrawl
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 0.8.8 - Unreleased

### Maintenance

- Move official releases to the shared signed, notarized, independently verified GitHub Actions pipeline while preserving archive names, contents, checksums, and Homebrew delivery.

## 0.8.7 - 2026-07-26

### Portable stores
Expand Down
14 changes: 7 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ VERSION ?= dev

.DEFAULT_GOAL := help

.PHONY: help build generate-sqlc tidy-check fmt lint test test-coverage run clean smoke test-release check snapshot release verify-release release-artifacts
.PHONY: help build generate-sqlc tidy-check fmt lint test test-coverage run clean smoke test-release check snapshot release verify-release release-artifacts release-snapshot

help:
@printf '%s\n' \
Expand All @@ -15,7 +15,7 @@ help:
' lint Run vet, vulnerability, and dead-code checks.' \
' check Run every local gate enforced by CI.' \
' snapshot Build credential-free release artifacts.' \
' release Build and verify official release artifacts (VERSION=vX.Y.Z).' \
' release Refuse local publishing and print the official CI command.' \
' verify-release Verify existing release artifacts (VERSION=vX.Y.Z).' \
' generate-sqlc Regenerate sqlc output.' \
' tidy-check Verify go.mod and go.sum are tidy.' \
Expand All @@ -24,7 +24,8 @@ help:
' test-release Test the release scripts.' \
' run Run the CLI (ARGS=...).' \
' clean Remove local build output.' \
' release-artifacts Alias for release.'
' release-artifacts Alias for release.' \
' release-snapshot Alias for snapshot.'

build:
mkdir -p bin
Expand Down Expand Up @@ -70,7 +71,6 @@ clean:
smoke: build
@set -e; version="$$(./bin/$(BINARY) --version)"; test -n "$$version"
@set -e; output="$$(./bin/$(BINARY) metadata --json)"; printf '%s' "$$output" | grep -q '"schema_version"'
@set -e; output="$$(./bin/$(BINARY) status --json)"; printf '%s' "$$output" | grep -q '"databases"'
@set -e; output="$$(./bin/$(BINARY) help tui)"; \
printf '%s\n' "$$output"; \
printf '%s' "$$output" | grep -q "gitcrawl tui"
Expand All @@ -84,12 +84,12 @@ snapshot:
GOWORK=off goreleaser release --snapshot --clean --skip=publish

release:
@test -n "$(VERSION)" && [ "$(VERSION)" != dev ] || (echo "usage: make release VERSION=vX.Y.Z" >&2; exit 2)
@helper="$${MAC_RELEASE_HELPER:-$$HOME/Projects/agent-scripts/skills/release-mac-app/scripts/mac-release}"; \
"$$helper" codesign-run -- ./scripts/package-release.sh "$(VERSION)"
@./scripts/package-release.sh

verify-release:
@test -n "$(VERSION)" && [ "$(VERSION)" != dev ] || (echo "usage: make verify-release VERSION=vX.Y.Z" >&2; exit 2)
./scripts/verify-release.sh "$(VERSION)"

release-artifacts: release

release-snapshot: snapshot
34 changes: 22 additions & 12 deletions docs/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,31 @@ permalink: /releasing/

# Releasing Gitcrawl

Official releases are assembled locally on an authorized maintainer Mac. GitHub Actions only validates credential-free snapshots and never publishes release artifacts.
`.github/workflows/release-unified.yml` is the only official release path. It calls `openclaw/release-workflows@v1` from protected `main`, requires an existing SSH-signed version tag, preserves Gitcrawl's six thin platform archives and `checksums.txt`, signs and notarizes both macOS binaries as `org.openclaw.gitcrawl`, verifies the complete asset inventory independently on arm64 and Intel macOS, and waits for `openclaw/homebrew-tap` to update successfully.

1. Prepare and sign the release commit and tag on `main`, then ensure the checkout is clean and `HEAD` exactly matches that tag.
2. Configure the shared `release-mac-app` helper at runtime for the passwordless managed keychain. The identity must be `Developer ID Application: OpenClaw Foundation (FWJYW4S8P8)`. Supply `NOTARYTOOL_KEYCHAIN_PROFILE` through the approved private runtime environment; never commit its value or add it to GitHub Actions. Keep keychain and 1Password routing in the ignored `.mac-release.env` or another approved private environment, never in Git.
3. Use the official local release target to build all release archives. Each thin Darwin binary is signed as `org.openclaw.gitcrawl` with the hardened runtime and a trusted timestamp, submitted to Apple in an ephemeral ZIP, and required to pass the notarized code requirement before packaging. Linux and Windows builds remain ordinary cross-compiles:
The public compatibility contract remains:

```bash
make release VERSION=vX.Y.Z
```
- `gitcrawl_VERSION_{darwin,linux}_{amd64,arm64}.tar.gz`
- `gitcrawl_VERSION_windows_{amd64,arm64}.zip`
- `checksums.txt`
- `CHANGELOG.md`, `LICENSE`, `README.md`, and the Gitcrawl executable inside every platform archive
- OpenClaw Foundation Team ID `FWJYW4S8P8` and code identifier `org.openclaw.gitcrawl`

`make release` fails unless `scripts/package-release.sh` completes `scripts/verify-release.sh` against every final Darwin archive. To recheck artifacts that were already built, run `make verify-release VERSION=vX.Y.Z`. The former `make release-artifacts` name remains an alias for compatibility.
The shared pipeline also publishes verifier control assets (`ASSET-INVENTORY.json`, `SIGNING-MANIFEST.json`, and `RELEASE-NOTES.md`).

4. Create a draft GitHub release from the signed tag. Attach the archives and `checksums.txt` from `dist/`, then manually run the `Release Assets` workflow for that tag. Its ephemeral token has `contents: write` only because GitHub otherwise hides drafts; the token is scoped to read-only asset downloads and is removed before verification. Publish only after both macOS verification jobs pass.
5. After publication, verify the release notes and assets, then dispatch the `openclaw/homebrew-tap` formula update for `gitcrawl` and verify the installed binary.
## Release

Local `go build`, `make build`, tests, and `make snapshot` never require release credentials. Official releases set `GITCRAWL_REQUIRE_CODESIGN=1`; the signing hook then requires `NOTARYTOOL_KEYCHAIN_PROFILE`, waits for an accepted notarization response, and replaces the GoReleaser output only after online notarization verification succeeds. `scripts/verify-release.sh` independently checks every extracted Darwin binary for the Foundation designated requirement and the notarized requirement. Raw executables cannot carry a stapled ticket, so verification requires network access to Apple.
Prepare a dated changelog section and land it on protected `main`. The `user.signingkey` SSH key must be listed for your principal in `.github/release-allowed-signers`. Create the annotated signed tag, verify it explicitly against the repository allowlist, push it, and dispatch the workflow:

`scripts/package-release.sh` fails closed unless it runs from the exact trusted signed tag with the Foundation identity supplied by `release-mac-app codesign-run` and a runtime notary profile.
```sh
git -c gpg.format=ssh tag -s vX.Y.Z -m "Release X.Y.Z"
git -c gpg.format=ssh -c gpg.ssh.allowedSignersFile=.github/release-allowed-signers tag -v vX.Y.Z
git push origin vX.Y.Z
gh workflow run release-unified.yml --repo openclaw/gitcrawl -f version=X.Y.Z
```

The release is complete only when the GitHub Release contains the full asset set, both native macOS verification jobs pass, and the Homebrew handoff is green.

## Local diagnostics

Local publishing is disabled. `make release`, `make release-artifacts`, and `scripts/package-release.sh` refuse and print the official workflow command. `make snapshot` remains credential-free, and `make verify-release VERSION=vX.Y.Z` rechecks already downloaded Darwin artifacts in `dist/` against `checksums.txt`, the stable Foundation designated requirement, architecture, embedded version, and Apple's online notarization ticket.
71 changes: 3 additions & 68 deletions scripts/package-release.sh
Original file line number Diff line number Diff line change
@@ -1,71 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
VERSION=${1:-}
EXPECTED_AUTHORITY='Developer ID Application: OpenClaw Foundation (FWJYW4S8P8)'

if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]]; then
echo "usage: $0 vX.Y.Z" >&2
exit 2
fi
[[ "$(uname -s)" == Darwin ]] || {
echo "official release packaging must run on macOS" >&2
exit 1
}
[[ "$(uname -m)" == arm64 ]] || {
echo "official release packaging requires Apple Silicon with Rosetta for both architecture smoke tests" >&2
exit 1
}
[[ "${CODESIGN_IDENTITY:-}" == "$EXPECTED_AUTHORITY" ]] || {
echo "official releases require $EXPECTED_AUTHORITY" >&2
exit 1
}
[[ -n "${NOTARYTOOL_KEYCHAIN_PROFILE:-}" ]] || {
echo "official releases require NOTARYTOOL_KEYCHAIN_PROFILE at runtime" >&2
exit 1
}

for tool in codesign ditto git go goreleaser lipo plutil shasum tar xcrun; do
command -v "$tool" >/dev/null || {
echo "missing required tool: $tool" >&2
exit 1
}
done

head_commit=$(git -C "$ROOT" rev-parse HEAD)
tag_commit=$(git -C "$ROOT" rev-parse "refs/tags/$VERSION^{commit}" 2>/dev/null) || {
echo "release tag does not exist locally: $VERSION" >&2
exit 1
}
[[ "$head_commit" == "$tag_commit" ]] || {
echo "HEAD does not match release tag $VERSION" >&2
exit 1
}
[[ -z "$(git -C "$ROOT" status --porcelain --untracked-files=normal)" ]] || {
echo "release checkout is not clean" >&2
exit 1
}
git -C "$ROOT" tag -v "$VERSION" >/dev/null 2>&1 || {
echo "release tag is not signed by a trusted git signing key: $VERSION" >&2
exit 1
}

release_version=${VERSION#v}
for arch in amd64 arm64; do
archive="$ROOT/dist/gitcrawl_${release_version}_darwin_${arch}.tar.gz"
[[ ! -e "$archive" ]] || {
echo "refusing to overwrite existing artifact: $archive" >&2
exit 1
}
done

(
cd "$ROOT"
CODESIGN_IDENTITY="$EXPECTED_AUTHORITY" \
GITCRAWL_REQUIRE_CODESIGN=1 \
GOWORK=off \
goreleaser release --clean --skip=publish
)

"$ROOT/scripts/verify-release.sh" "$VERSION"
echo "local releases are disabled because this path cannot enforce the shared verifier and publication chain" >&2
echo "official releases must use: gh workflow run release-unified.yml --repo openclaw/gitcrawl -f version=X.Y.Z" >&2
exit 1
Loading