helm / helm/chart-releaser

Add --sign-commits flag to `cr index` so the GitHub Pages commit is Verified

Open
#625 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
783
Forks
126
Avg merge
1d 18h
Merged PRs (30d)
11

Description

## Proposal

Add an opt-in flag (e.g. `--sign-commits`) to `cr index` so that, when set, the commit pushed to the GitHub Pages branch is created via GitHub's [`createCommitOnBranch`](https://docs.github.com/en/graphql/reference/mutations#createcommitonbranch) GraphQL mutation instead of `git commit` + `git push`. Commits created via that API are server-side signed with GitHub's web-flow key and appear as **Verified** in the GitHub UI without any signing key on the runner.

Default behaviour stays exactly as today; the flag is purely additive.

## Why

`cr index --push` is the standard way Helm chart repositories on GitHub Pages are kept up to date from CI. The resulting commit is currently unsigned because `pkg/git/git.go`'s `Commit` runs `git commit --message ... --signoff` (DCO sign-off only — no cryptographic signature) and `Push` runs plain `git push`.

This creates friction for organisations that:

- **Apply "Require signed commits" branch protection** on the Pages branch. The `cr` push is rejected and the workflow has to be either excluded from the rule or the rule has to be relaxed for the bot identity.
- **Require Verified commits for audit / supply-chain hardening.** Mixing Verified and Unverified commits on the chart-publishing branch weakens the provenance story for the published artifacts.
- **Run from GitHub Apps** (the recommended modern pattern). Apps cannot have GPG/SSH keys registered against them, so there is no way to make the existing `git commit` path produce a signed commit. The only path to a signed commit from an App is the GitHub API (`createCommitOnBranch` or the REST contents API).

There doesn't appear to be an open issue or prior PR on this in `helm/chart-releaser`. #81 added `cr package --sign` which signs Helm package `.tgz` provenance — orthogonal to git commit signing.

## Proposed change

The change is additive and self-contained. Sketch:

1. **New flag** on `cr index`:
```
--sign-commits Create the index.yaml commit via GitHub's createCommitOnBranch
GraphQL mutation so it is signed by GitHub's web-flow key.
Mutually inclusive with --push. Mutually exclusive with --pr
(since --pr already uses local git for the temporary branch
commit; --sign-commits could be supported there too in a
follow-up, but this PR scopes to --push only).
```

2. **Implementation outline** (in `pkg/releaser/releaser.go`'s `UpdateIndexFile`):
- When `--sign-commits` is set, skip the `git.Add` / `git.Commit` / `git.Push` sequence at the end of `UpdateIndexFile`.
- Instead, read the regenerated `index.yaml` bytes from `r.config.IndexPath`.
- Use the existing `pkg/github` client (which already wraps `go-github` for the releases work) to:
- Fetch the current OID of `refs/heads/` (for `expectedHeadOid`).
- Build a `CreateCommitOnBranchInput` with `additions: [{ path: , contents: base64(index.yaml) }]` and `message: { headline: "Update " }`.
- Call the GraphQL mutation via the existing client.
- On success, the new commit is on the Pages branch, signed by GitHub's web-flow key. No worktree, no `git push`, no local git invocation at all for this code path.

3. **Token requirements** — unchanged. The existing `--token` must have `contents: write` on the repository, which is already required for `git push`. `createCommitOnBranch` accepts the same token.

4. **Backwards compatibility** — `--sign-commits` defaults to `false`. Users who don't set it get exactly the current behaviour. No config-file changes; the flag is opt-in.

5. **Edge cases handled**:
- `expectedHeadOid` concurrency: if another push lands on the Pages branch between fetch and mutation, the mutation fails with a clear error — re-run the workflow. This is stricter than `git push` (which can race more silently), but arguably safer.
- Payload size: GraphQL has a request-size cap. `index.yaml` for a typical chart repo is well under it. Worth noting in the flag's help text.
- File mode: `createCommitOnBranch` accepts file additions as regular files only (no executable bit / symlinks). `index.yaml` is a regular file, so this is fine for the `cr index` use case.

6. **Tests**: extend `pkg/releaser/releaser_test.go` to cover the new code path, with the `pkg/github` client mocked (already the pattern for the existing tests).

7. **Docs**: README flag list under `cr index [flags]`.

## Asking before I send a PR

I'm happy to put this together as a PR if the maintainers are on board with the overall shape (opt-in `--sign-commits` flag, additive, no behaviour change by default). Two specific questions before I spend the time:

1. Are you open to taking a dependency on the GraphQL API surface of `go-github` for this code path? (The releases code already uses `go-github`'s REST surface.)
2. Is `--sign-commits` the preferred flag name, or would you rather call it something different (e.g. `--api-commit`, `--use-api`, `--signed`)?

Happy to discuss alternatives if there's a different design you'd prefer.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.