Skip to content

Publish signed provider releases - #98

Merged
IlyaasK merged 1 commit into
mainfrom
hypeship/v1-release-publish
Jul 31, 2026
Merged

Publish signed provider releases#98
IlyaasK merged 1 commit into
mainfrom
hypeship/v1-release-publish

Conversation

@IlyaasK

@IlyaasK IlyaasK commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR completes the first provider release path with two modes:

  • manual workflow_dispatch preflight for an entered stable version
  • tag-triggered signing and GitHub Release publication

The manual preflight creates only a runner-local tag, builds and validates the
release artifacts, and proves the configured GPG key can sign the checksum. It
runs with contents: read, so it cannot create a remote tag or GitHub Release.

The tag-triggered path receives the prepared artifacts through
actions/download-artifact, verifies their checksums, requires the imported
private key to match the Terraform Registry fingerprint, signs the checksum,
creates a draft release, and publishes it only after every asset upload
succeeds.

Any Kernel engineer authorized by the protected v* tag ruleset can release a
commit already merged into main. This deliberately avoids a separate GitHub
release environment, second-person approval, and long-lived administration
PAT.

Why

The first public provider release will be v0.0.1. The artifact and signing
path must be testable before the first immutable remote tag exists. The manual
preflight exercises the build and signing path without permission to publish.

This PR does not change provider configuration, resources, data sources,
imports, API behavior, SDK behavior, or Terraform state. Runtime/session,
deployment, app, and API-key provider surfaces remain intentionally absent.

Security model

  • The release commit must be reachable from main.
  • The repository must be public.
  • Versions must use stable vMAJOR.MINOR.PATCH syntax.
  • Only the tag-triggered publication job receives contents: write.
  • Signing material is stored in repository Actions secrets.
  • The imported private key must match the configured Registry fingerprint.
  • Checksums are verified after same-run artifact download.
  • Exact remote tag refs are checked immediately before draft creation and
    publication; lightweight and annotated tags are supported.
  • The v* tag ruleset is administrator-owned configuration and must limit
    bypass to the Kernel engineering team.

Verification

  • gofmt -l cmd internal
  • go test -short -timeout=2m ./...
  • go vet ./...
  • terraform fmt -check -recursive examples
  • bash scripts/check-docs.sh
  • bash scripts/check-markdown-links.sh
  • bash scripts/check-examples.sh
  • bash scripts/test-release-scripts.sh
  • bash scripts/check-registry-manifest.sh
  • goreleaser check
  • Bash syntax validation for all release scripts
  • YAML parsing for .github/workflows/release.yml

The release-script suite creates a real temporary Git remote and covers
lightweight, annotated, missing, and moved tags. It also generates a disposable
passphrase-protected GPG key and verifies fingerprint mismatch rejection,
import, signing, and detached-signature verification.

Live provider acceptance tests were not rerun because provider behavior is
unchanged. The complete selected-surface acceptance matrix remains a required
pre-tag gate.

Remaining release setup

Before the first public tag:

  • make the repository public
  • configure and inspect the active v* tag ruleset, with bypass limited to the
    Kernel engineering team
  • run the manual v0.0.1 preflight from main
  • run the complete acceptance matrix against the release commit

No release environment, deployment approval, release PAT, or runtime ruleset
API check is required.

Issues #24 and #25 remain outside this PR.

@IlyaasK
IlyaasK marked this pull request as ready for review July 11, 2026 21:40
@IlyaasK
IlyaasK requested review from Sayan- and tnsardesai July 11, 2026 21:40
Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml Outdated
@IlyaasK
IlyaasK removed request for Sayan- and tnsardesai July 13, 2026 13:25
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-prepare branch from 01ac93e to a62a99d Compare July 13, 2026 13:36
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from a53f1fb to 0ba61eb Compare July 13, 2026 13:36
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-prepare branch from a62a99d to b85cf78 Compare July 13, 2026 14:32
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from 0ba61eb to 3755aea Compare July 13, 2026 14:32
Comment thread .github/workflows/release.yml Outdated
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from 3755aea to f96c137 Compare July 13, 2026 15:39
Comment thread .github/workflows/release.yml Outdated
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-prepare branch from 18cfeea to a89c140 Compare July 20, 2026 19:38
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from f96c137 to 2107314 Compare July 20, 2026 19:38
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-prepare branch from a89c140 to ef813b3 Compare July 21, 2026 14:46
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch 3 times, most recently from fa24611 to fc3f751 Compare July 21, 2026 19:51
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-prepare branch from 094fc64 to efa2797 Compare July 21, 2026 20:15
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from fc3f751 to af23b48 Compare July 21, 2026 20:15
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-prepare branch from efa2797 to 17d0c8a Compare July 28, 2026 21:16
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch 2 times, most recently from 49e9ba3 to 9e33a53 Compare July 29, 2026 19:21
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-prepare branch from 17d0c8a to 6a40866 Compare July 29, 2026 20:40
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from 9e33a53 to cec3e82 Compare July 29, 2026 20:46
@IlyaasK
IlyaasK requested a review from Sayan- July 29, 2026 20:58
Comment thread .github/workflows/release.yml

@Sayan- Sayan- left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The protection model is thorough. Validating the environment's required-reviewer and self-review settings plus the tag ruleset at runtime, re-checking that the tag still resolves to the workflow commit at three separate points, re-verifying checksums after download, and inspecting the key with --import-options show-only before trusting it are all the right calls. Secrets reach gpg through env: and stdin rather than argv, so nothing lands in the process list. No notes on the security design.

Two operational things, both downstream of the fact that none of this has executed yet.

First, this supersedes the dry-run suggestion I left on #97. The semver gate here requires major ≥ 1 and rejects prereleases, so there's no throwaway tag available — the first tag pushed is the first time prepare ever runs, and the ruleset this job requires blocks tag deletion. If prepare fails on that attempt, the version number is burned and the retry has to be v1.0.1. Either go in accepting that the first tag may be sacrificial, or add a prepare-only workflow_dispatch path so the gates can be exercised before any tag exists. Given how much of this path is un-run, I'd lean toward the latter.

Second, worth confirming before release day: GET /repos/{owner}/{repo}/rulesets/{id} documents a requirement of Administration (read), and administration isn't a grantable scope in a workflow permissions: block, so GITHUB_TOKEN cannot hold it. If that call 403s, the publish job dies on its first step — after a human has already approved the deployment. It fails closed, so nothing unsafe happens, but that's an expensive place to discover a permissions problem. Cheapest check is to run those three gh api calls once from a scratch workflow here and confirm the token reads all of them; if the ruleset call is the odd one out, a read-only PAT scoped to the release environment covers it.

@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from cec3e82 to f7597f9 Compare July 30, 2026 14:35
@IlyaasK
IlyaasK requested a review from Sayan- July 30, 2026 14:36
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from f7597f9 to 90c3170 Compare July 30, 2026 15:12
@IlyaasK
IlyaasK requested review from Sayan- and removed request for Sayan- July 30, 2026 15:13

@Sayan- Sayan- left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The preflight job is a better answer than what I suggested. Running the real protection checks and a real signing operation under contents: read exercises the whole path with no structural ability to publish, and it settles the ruleset-permission question empirically instead of on release day. Extracting the shell into check-release-protections.sh and sign-release-checksum.sh so CI can exercise them against a faked gh and a disposable key is the right instinct — that logic was previously unreachable by any test.

The docs being explicit about what cannot be verified at runtime is also the right call: administrator bypass, ruleset bypass actors, and the immutable-releases setting are all genuinely outside a least-privilege token's reach, and saying so beats implying the workflow checks more than it does. Same for the note that repository write access is effectively release authorization — that's the actual threat model, stated plainly.

One gap worth closing in test-release-scripts.sh. It covers the happy path plus a single negative case (reviewer mismatch), but the assertions doing the real security work have no negative fixture: enforcement == "active", the creation/update/deletion rule set, prevent_self_review == true, and the exact deployment-policy match. Those jq filters are the control. If one silently went vacuous — a typo in a field name, a ? in the wrong place — the script would pass against a repository with no meaningful protection, and nothing in CI would notice. The harness already exists, so this is a handful of fixtures: an inactive ruleset, one missing the deletion rule, prevent_self_review: false, and a policy list with an extra entry. Each should exit non-zero with its own message, same shape as the reviewer-mismatch assertion you already have.

@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from 90c3170 to 9054963 Compare July 30, 2026 17:49
@IlyaasK
IlyaasK requested a review from Sayan- July 30, 2026 17:50

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 9054963. Configure here.

Comment thread .github/workflows/release.yml Outdated
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from 9054963 to b1bf2ee Compare July 30, 2026 18:54
@IlyaasK
IlyaasK changed the base branch from hypeship/v1-release-prepare to hypeship/v1-release-artifacts July 30, 2026 18:55
@IlyaasK
IlyaasK removed the request for review from Sayan- July 30, 2026 18:55
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from b1bf2ee to c334d17 Compare July 30, 2026 19:27
@IlyaasK
IlyaasK changed the base branch from hypeship/v1-release-artifacts to hypeship/land-release-prepare-main July 30, 2026 19:28
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from c334d17 to 29407cd Compare July 30, 2026 19:29
@IlyaasK
IlyaasK changed the base branch from hypeship/land-release-prepare-main to main July 30, 2026 19:29
Require protected release approval before importing the Registry key, signing the prepared checksum, and publishing retry-safe GitHub Release assets.
@IlyaasK
IlyaasK force-pushed the hypeship/v1-release-publish branch from 29407cd to 371cda6 Compare July 30, 2026 19:31
@IlyaasK
IlyaasK requested a review from Sayan- July 30, 2026 20:22
@IlyaasK
IlyaasK merged commit 203eeab into main Jul 31, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants