Skip to content

Slice 2A: release.json schema + generator + processgit update check#126

Merged
rg4444 merged 1 commit into
mainfrom
slice-2/release-manifest-and-update-check
May 23, 2026
Merged

Slice 2A: release.json schema + generator + processgit update check#126
rg4444 merged 1 commit into
mainfrom
slice-2/release-manifest-and-update-check

Conversation

@rg4444
Copy link
Copy Markdown
Contributor

@rg4444 rg4444 commented May 22, 2026

Slice 2A — Release manifest schema, generator, and processgit update check

Foundation for the in-product update system. Read-only and additive — does not touch any running paths and adds no dependencies.

What ships in this PR

File What
build/release.schema.json JSON Schema (Draft 2020-12) describing the per-release manifest
build/release-helper/main.go Stdlib-only Go program that emits release.json from env vars (driven by the release workflow in a follow-up)
cmd/update.go New processgit update subcommand with check verb
cmd/main.go Registers CmdUpdate in subCmdStandalone (1-line add)

processgit update check — usage

$ processgit update check
Repository:      Algomation-AI/ProcessGit
Channel:         stable
Current version: 0.1.0
Latest version:  0.1.2
Released at:     2026-06-01T10:00:00Z
Release notes:   https://github.com/Algomation-AI/ProcessGit/releases/tag/v0.1.2

Status:          update available (0.1.0 → 0.1.2)

Flags:

  • --repo OWNER/NAME (default Algomation-AI/ProcessGit, env PROCESSGIT_UPDATE_REPO)
  • --channel stable|prerelease (default stable)
  • --github-api URL (for GitHub Enterprise)
  • --github-token TOKEN (optional; raises rate limit; env PROCESSGIT_UPDATE_GITHUB_TOKEN or GITHUB_TOKEN)
  • --timeout 15s
  • --json for machine-readable output

JSON output (for the updater sidecar and external tooling):

{
  "current": "0.1.0",
  "latest": "0.1.2",
  "latest_tag": "v0.1.2",
  "update_available": true,
  "prerelease": false,
  "release_url": "https://github.com/Algomation-AI/ProcessGit/releases/tag/v0.1.2",
  "released_at": "2026-06-01T10:00:00Z",
  "release_name": "v0.1.2",
  "channel": "stable",
  "repo": "Algomation-AI/ProcessGit"
}

release.json — design

Every published release will carry a machine-readable manifest as a release asset. The schema covers:

  • Identity: version, tag, released_at, prerelease
  • Image: registry, repository, tag, digest, platforms, additional_tags
  • Binaries: list of OS/arch/url/sha256 (empty for v0.1.0 — container only)
  • Source: archive url + sha256
  • Signing: method (currently cosign-keyless), issuer, identity_regex — enough for any consumer to construct a cosign verify command
  • Migration: whether required, command to run, estimated downtime
  • Breaking changes + deprecations as plain-text lists
  • Build provenance: commit, workflow run URL

additionalProperties: false throughout so we can evolve safely with schema_version bumps.

release-helper — design

  • Stdlib only (no go.mod changes anywhere in the project — the helper compiles standalone in its own sub-module, driven by go run ./build/release-helper or by building a binary in the workflow)
  • All inputs via env vars, so workflow integration is just env: ... block
  • Required env enforced — exits non-zero with a clear message if anything is missing
  • Output target via OUTPUT= env (defaults to stdout)

Validation done

  • gofmt clean on both Go files
  • release-helper compiles standalone and emits valid JSON
  • Sample emitted JSON validates against the schema using jsonschema.Draft202012Validator
  • cmd/main.go change is a single-line addition to subCmdStandalone
  • Inline semver parser handles: bare semver, v prefix, pre-release ordering (numeric < alphanumeric, longer prefix list wins ties), build metadata stripped

Intentionally NOT in this PR

Where What
Workflow patch .github/workflows/release.yml update to call release-helper + sign+attach release.json. Lives on top of #125 — will ship as a small follow-up PR once #125 merges.
Slice 2B processgit update download (fetch image/binary, verify signatures, stage) and processgit update apply (atomic binary swap, migrate, re-exec). These touch the running binary and deserve their own PR.
Slice 3 processgit-updater sidecar container.
Slice 4 Admin UI page at /-/admin/updates.

Sequencing for landing

  1. Merge ci: add release workflow (semver tag → GHCR + cosign + GH Release) #125 (release workflow)
  2. Merge this PR (Slice 2A: release.json schema + generator + processgit update check #126 — slice 2A)
  3. Tiny follow-up PR: update release.yml to invoke release-helper and attach release.json to the GH Release
  4. Tag v0.1.0 — workflow produces the first signed image and the first release.json
  5. From any deployment: processgit update check should now print up to date

…date check`

Adds the data plumbing for releases to be machine-discoverable and for
deployments to be able to check for newer versions. Foundation for
Slice 2B (download + apply), Slice 3 (updater sidecar), and any
external tooling that wants to know what a release contains.

Three additions:

1. build/release.schema.json
   JSON Schema (Draft 2020-12) describing the per-release manifest.
   Required fields: version/tag/released_at/prerelease, image
   (registry/repository/tag/digest/platforms), signing (method/issuer/
   identity_regex), release_notes_url. Optional: binaries, source,
   migration, breaking_changes, deprecations, build provenance.
   Conservative schema_version=1 with `additionalProperties: false`
   throughout so we can add fields safely later.

2. build/release-helper/main.go
   Tiny stdlib-only Go program that emits release.json from environment
   variables. Designed to be driven from the GitHub Actions release
   workflow (in a follow-up workflow update, not part of this PR --
   that change layers on top of #125 once it merges).

3. cmd/update.go
   New `processgit update` subcommand with `check` as the first verb.
   Queries the GitHub Releases API, walks the result list to handle
   channel filtering (stable / prerelease) more robustly than the
   /releases/latest endpoint, and compares to setting.AppVer using a
   small inline semver parser (no new dependencies).
   Flags: --repo, --channel, --github-api (for GHE), --github-token
   (optional, raises rate limit), --timeout, --json.
   Registered in cmd/main.go as a standalone (config-free) subcommand.

Slice 2B will add `update download` (with sig verification) and
`update apply` (atomic binary swap + migrate + re-exec). Those touch
the running binary and deserve their own focused PR.

Validation performed before this PR:
- gofmt clean on both Go files
- release-helper compiles standalone and emits valid JSON
- Sample emitted JSON validates against the schema using
  jsonschema (Draft202012Validator)
- cmd/main.go patch is a 1-line add to subCmdStandalone

Co-authored-by: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 77c5197685

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/update.go
// brand-new repos that have only pre-releases).
// For `prerelease`, it returns the newest non-draft entry of any kind.
func fetchLatestRelease(ctx context.Context, apiBase, repo, channel, token string, timeout time.Duration) (*ghRelease, error) {
url := fmt.Sprintf("%s/repos/%s/releases?per_page=30", apiBase, repo)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Paginate release listing before declaring no stable release

This request hard-codes per_page=30 and never follows pagination, so update check --channel stable can incorrectly report "no published release found" when the first 30 releases are drafts/prereleases but an older stable release exists on later pages. This is a real failure mode for repos that publish many prereleases between stables, and it will suppress valid update information.

Useful? React with 👍 / 👎.

Version: mustEnv("RELEASE_VERSION"),
Tag: mustEnv("RELEASE_TAG"),
ReleasedAt: time.Now().UTC().Format(time.RFC3339),
Prerelease: envBool("RELEASE_PRERELEASE", false),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require prerelease flag instead of silently defaulting false

The manifest generator treats RELEASE_PRERELEASE as optional and defaults to false, so a missing env var will label a prerelease artifact as stable in release.json. Because this field is security/rollout metadata for update consumers, silently coercing a missing required input can produce incorrect channel behavior; this should fail fast like the other required release fields.

Useful? React with 👍 / 👎.

@rg4444 rg4444 merged commit b26be65 into main May 23, 2026
13 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant