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
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ jobs:
- name: Check generated docs
run: bash scripts/check-docs.sh

- name: Test release scripts
run: bash scripts/test-release-scripts.sh

- name: Set up GoReleaser
uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2
with:
Expand Down
133 changes: 127 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
name: Release preparation
name: Release

on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: Stable version to prepare without publishing
required: true
type: string

permissions:
contents: read

env:
RELEASE_TAG: ${{ inputs.version || github.ref_name }}

defaults:
run:
shell: bash

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
Expand All @@ -31,8 +44,13 @@ jobs:
run: |
test -s LICENSE

if [[ ! "$GITHUB_REF_NAME" =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
echo "Release tags must use stable semantic version format vMAJOR.MINOR.PATCH." >&2
if [[ ! "$RELEASE_TAG" =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
echo "Release versions must use stable semantic version format vMAJOR.MINOR.PATCH." >&2
exit 1
fi

if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ] && [ "$GITHUB_REF" != "refs/heads/main" ]; then
echo "Manual release preflight must run from main." >&2
exit 1
fi

Expand All @@ -47,6 +65,15 @@ jobs:
exit 1
fi

- name: Create local preflight tag
if: github.event_name == 'workflow_dispatch'
run: |
if git show-ref --verify --quiet "refs/tags/${RELEASE_TAG}"; then
echo "Release version ${RELEASE_TAG} already exists." >&2
exit 1
fi
git tag "$RELEASE_TAG" "$GITHUB_SHA"

- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
Expand All @@ -60,18 +87,26 @@ jobs:
version: v2.17.0
args: release --clean --skip=publish,sign
env:
GORELEASER_CURRENT_TAG: ${{ github.ref_name }}
GORELEASER_CURRENT_TAG: ${{ env.RELEASE_TAG }}

- name: Verify release artifacts
run: |
version="${GITHUB_REF_NAME#v}"
version="${RELEASE_TAG#v}"
cp terraform-registry-manifest.json "dist/terraform-provider-kernel_${version}_manifest.json"
bash scripts/check-release-artifacts.sh "$version"

- name: Verify signing configuration
if: github.event_name == 'workflow_dispatch'
env:
EXPECTED_GPG_FINGERPRINT: ${{ vars.GPG_FINGERPRINT }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
PASSPHRASE: ${{ secrets.PASSPHRASE }}
run: bash scripts/sign-release-checksum.sh "${RELEASE_TAG#v}"

- name: Upload release artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-${{ github.ref_name }}-${{ github.run_id }}
name: release-${{ env.RELEASE_TAG }}-${{ github.run_id }}
path: |
dist/*.zip
dist/*_manifest.json
Expand All @@ -80,3 +115,89 @@ jobs:
retention-days: 7
compression-level: 0
overwrite: true

publish:
name: Sign and publish release
if: github.event_name == 'push'
needs: prepare
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write

steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Download release artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-${{ github.ref_name }}-${{ github.run_id }}
path: dist

- name: Check publication preconditions
env:
GH_TOKEN: ${{ github.token }}
run: |
release="$(
gh api --paginate --slurp "repos/${GITHUB_REPOSITORY}/releases?per_page=100" |
jq -c --arg tag "$GITHUB_REF_NAME" '[.[][] | select(.tag_name == $tag)][0] // empty'
)"
if [ -n "$release" ]; then
if [ "$(jq -r .draft <<<"$release")" = "true" ]; then
echo "An existing draft release must be inspected and removed before retrying ${GITHUB_REF_NAME}." >&2
else
echo "A published release already exists for ${GITHUB_REF_NAME}." >&2
fi
exit 1
fi

version="${GITHUB_REF_NAME#v}"
checksum="dist/terraform-provider-kernel_${version}_SHA256SUMS"
test -s "$checksum"
(cd dist && sha256sum --check "$(basename "$checksum")")

- name: Sign and verify checksums
env:
EXPECTED_GPG_FINGERPRINT: ${{ vars.GPG_FINGERPRINT }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
PASSPHRASE: ${{ secrets.PASSPHRASE }}
run: bash scripts/sign-release-checksum.sh "${GITHUB_REF_NAME#v}"

- name: Create draft release
env:
GH_TOKEN: ${{ github.token }}
run: |
version="${GITHUB_REF_NAME#v}"
first_release_url="https://github.com/${GITHUB_REPOSITORY}/blob/${GITHUB_SHA}/docs/first-release.md"
manifest="dist/terraform-provider-kernel_${version}_manifest.json"
checksum="dist/terraform-provider-kernel_${version}_SHA256SUMS"
signature="${checksum}.sig"
notes=()
if [ "$GITHUB_REF_NAME" = "v0.0.1" ]; then
notes=(--notes "First-release guidance: [supported surface and imports](${first_release_url}).")
fi

bash scripts/check-release-tag.sh "$GITHUB_REF_NAME" "$GITHUB_SHA"

gh release create "$GITHUB_REF_NAME" \
dist/terraform-provider-kernel_"${version}"_*.zip \
"$manifest" \
"$checksum" \
"$signature" \
--repo "$GITHUB_REPOSITORY" \
--verify-tag \
--draft \
--generate-notes \
"${notes[@]}" \
--title "$GITHUB_REF_NAME"

- name: Publish release
env:
GH_TOKEN: ${{ github.token }}
run: |
bash scripts/check-release-tag.sh "$GITHUB_REF_NAME" "$GITHUB_SHA"

gh release edit "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --draft=false
Comment thread
IlyaasK marked this conversation as resolved.
17 changes: 0 additions & 17 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,5 @@ checksum:
- glob: terraform-registry-manifest.json
name_template: "{{ .ProjectName }}_{{ .Version }}_manifest.json"

signs:
- artifacts: checksum
signature: "${artifact}.sig"
args:
- --batch
- --local-user
- "{{ .Env.GPG_FINGERPRINT }}"
- --output
- ${signature}
- --detach-sign
- ${artifact}

release:
extra_files:
- glob: terraform-registry-manifest.json
name_template: "{{ .ProjectName }}_{{ .Version }}_manifest.json"

changelog:
disable: true
9 changes: 4 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

All notable changes to the Kernel Terraform provider are recorded here.

## Unreleased
## v0.0.1

First public release candidate:
First public release:

- Provider configuration for `api_key`, `base_url`, and `project_id`.
- `kernel_project` and `kernel_browser_pool` resources for durable desired state.
Expand All @@ -20,6 +20,5 @@ Intentionally not included:
- API key, profile, proxy, extension, deployment, or app resources.
- `force_destroy` browser-pool deletion.

There is no upgrade or migration path from an earlier published version because
this repository has no published provider tags. See the
[first public release guide](docs/first-release.md).
v0.0.1 has no upgrade or migration path from an earlier published version. See
the [first public release guide](docs/first-release.md).
3 changes: 2 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## Supported Versions

The provider has no public release yet; the first public release ships as a complete v1, and v0 tags stay internal. Before the first public release, confirm which released versions receive security fixes and update this section if support differs from latest-only.
Security fixes are provided for the latest released version. Before the first
release, this policy applies to the `main` branch.

## Reporting Security Issues

Expand Down
10 changes: 6 additions & 4 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Kernel Terraform Provider Architecture

This document records the durable-only architecture, the implemented v0 baseline, and the target scope for the first public v1 of the Kernel Terraform provider.
This document records the durable-only architecture, the initial public v0.0.1 surface, and the target scope for a future v1 of the Kernel Terraform provider.

## First Principles

Expand All @@ -25,8 +25,9 @@ Provider configuration:
- optional `base_url`
- optional `project_id`

Resource:
Resources:

- `kernel_project`
- `kernel_browser_pool`

Data sources:
Expand All @@ -38,11 +39,12 @@ Data sources:

Import:

- `kernel_project` imports by canonical project ID.
- `kernel_browser_pool` imports by canonical browser pool ID, optionally qualified as `<project-id>/<pool-id>`.

## v1 Target Scope

The first public v1 should make durable Kernel configuration production-ready without turning Terraform into a runtime control plane. Core items are release-blocking unless the release notes explicitly defer them with an upstream API or SDK blocker.
A future v1 should broaden production-ready durable Kernel configuration without turning Terraform into a runtime control plane.

Resources require stable identity, refresh, delete, import, and, where applicable, project-scoping and sensitive-state semantics. Data sources require stable identity, deterministic exact lookup, and, where applicable, masked sensitive metadata, pagination, and project scoping. Tooling experiments require deterministic regeneration and must preserve the handwritten lifecycle boundary.

Expand Down Expand Up @@ -268,4 +270,4 @@ Release checklist:
- Runtime operations are absent from Terraform resources.
- Import behavior is documented.
- API and SDK blockers are either resolved or explicitly deferred.
- Release process, signing, licensing, and versioning are complete before the first public v1 publication.
- Release process, signing, licensing, and versioning are complete before the first public v0.0.1 publication.
2 changes: 1 addition & 1 deletion docs/first-release.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# First Public Release

The first published Kernel Terraform provider version will be v1. This
The first published Kernel Terraform provider version is v0.0.1. This
repository has no earlier published tags, so this release has no provider
upgrade or state migration path.

Expand Down
60 changes: 46 additions & 14 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Use this checklist before publishing a Kernel Terraform provider version.

## Release Preconditions

- The repository has no published provider tags. Present v1 as the first public release, not as an upgrade or migration from v0.
- Review the [first public release guide](first-release.md) and include its supported-surface and import guidance in the release notes.
- For v0.0.1, present it as the first public release, not as an upgrade or migration from an earlier provider version.
- For v0.0.1, review the [first public release guide](first-release.md) and include its supported-surface and import guidance in the release notes.
- Work from a clean `main` checkout after the PR stack is merged.
- Run `bash scripts/check-docs.sh`.
- Run `bash scripts/check-markdown-links.sh`.
Expand All @@ -28,12 +28,26 @@ Use this checklist before publishing a Kernel Terraform provider version.
- Verify unscoped API calls send no `X-Kernel-Project-Id` header; it is sent only when a resource-level `project_id` or the provider default resolves a project.
- Confirm `terraform-registry-manifest.json` contains protocol `["6.0"]` for Terraform Plugin Framework.
- Confirm `LICENSE` contains the approved Apache License 2.0 text.
- Confirm immutable GitHub Releases are enabled for the repository. The
publication job intentionally has no repository-administration permission to
inspect or change this setting.
- Confirm GitHub private vulnerability reporting or a public security contact is configured and reflected in `SECURITY.md`.
- Confirm there is no branch named like the release tag, for example `v1.0.0`.

- Store `GPG_PRIVATE_KEY` and `PASSPHRASE` as repository Actions secrets. Set
the repository Actions variable `GPG_FINGERPRINT` to the fingerprint
registered with the Terraform Registry.
- Add a repository ruleset that restricts creation, update, and deletion of
`v*` tags to the Kernel engineering team. Inspect the ruleset's bypass list
before releasing; do not allow repository roles, outside collaborators, or
organization administrators to bypass it. Ruleset configuration is an
administrator-owned setup requirement, not a workflow runtime check.
- GitHub repository writers can create Releases through the API; GitHub does not
provide a separate release-publisher role. Treat every account with repository
write access as release-authorized and keep that group limited to Kernel
engineers. The tag ruleset remains the control that authorizes a release
workflow run.
## Registry Release Assets

Terraform Registry provider releases are GitHub Releases with semver tags prefixed by `v`, such as `v1.0.0`.
Terraform Registry provider releases are GitHub Releases with semver tags prefixed by `v`, such as `v0.0.1`.

Each release must include:

Expand All @@ -58,16 +72,34 @@ Do not replace or mutate assets for a published version. If an asset, checksum,
## GoReleaser Notes

- `.goreleaser.yml` is the source of truth for registry artifact names, target
platforms, checksums, manifest inclusion, and checksum signing.
platforms, checksums, and manifest inclusion. The release workflow owns
checksum signing and publication.
- Normal CI validates the GoReleaser configuration and registry manifest without
building the complete platform matrix.
- `.github/workflows/release.yml` prepares unsigned, unpublished assets for
stable `vMAJOR.MINOR.PATCH` tags after confirming the repository is public
and the tag commit is reachable from `main`. It pins GoReleaser to the pushed
tag, verifies the release contract, and retains the assets for seven days.
- Real releases sign the checksum file once with the GPG key selected by
`GPG_FINGERPRINT`. The detached signature is named by appending `.sig` to the
checksum filename. Publication remains a separate release step.
- `.github/workflows/release.yml` runs for `v*` tags. Its preparation job has
read-only repository access and accepts only stable `vMAJOR.MINOR.PATCH`
versions. It requires the Apache 2.0 license, public repository visibility,
and a commit reachable from `main`, then builds and verifies the unsigned
assets. The workflow artifact is retained for seven days. Only the
tag-triggered publication job receives `contents: write`.
- Before creating a tag, run the workflow manually with the intended version.
Manual runs create an unpushed tag only inside the ephemeral runner, build
the same unsigned assets, and exercise checksum and GPG signing with
`contents: read`. They never create a remote tag or GitHub Release.
- For a tag-triggered release, confirm the acceptance matrix passed and the tag
ruleset's bypass list still contains only the Kernel engineering team before
creating the tag. The job revalidates the tag and checksums, requires the
imported key to match `GPG_FINGERPRINT`, signs the checksum file, and publishes
the GitHub Release.
- Failed-job reruns reuse the prepared artifact from the same workflow run. A
full rerun replaces that run's artifact. If publication fails or is
interrupted, it may leave a draft. Any existing draft stops retries until a
Kernel engineer inspects and removes it manually. An existing published
release always stops the workflow.
- For `v0.0.1`, GitHub includes the tagged
[first public release guide](first-release.md) with the generated release
notes. Later versions use generated release notes without first-release
guidance.

## Registry Setup

Expand Down Expand Up @@ -96,4 +128,4 @@ References:

- HashiCorp Terraform provider publishing: https://developer.hashicorp.com/terraform/registry/providers/publishing
- HashiCorp provider registry protocol: https://developer.hashicorp.com/terraform/internals/provider-registry-protocol
- GoReleaser checksum signing: https://goreleaser.com/customization/sign/
- GitHub rulesets: https://docs.github.com/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/about-rulesets
Loading