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
8 changes: 8 additions & 0 deletions .github/scripts/tests/test_release_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ def test_cosign_is_verified_before_release_publication(self):
)
self.assertLess(restore_position, publish_position)

def test_cosign_signing_retries_transient_service_failures(self):
self.assertEqual(self.workflow.count("for attempt in 1 2 3; do"), 3)
self.assertEqual(
self.workflow.count('echo "Cosign signing failed after $attempt attempts"'),
3,
)
self.assertEqual(self.workflow.count("sleep $((attempt * 15))"), 3)

def test_github_release_uses_the_git_tag_not_the_product_version(self):
self.assertIn('gh release create "$GIT_TAG"', self.workflow)
self.assertIn("--verify-tag", self.workflow)
Expand Down
37 changes: 34 additions & 3 deletions .github/workflows/build-branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,18 @@ jobs:
env:
DIGEST: ${{ steps.build.outputs.digest }}
IMAGE: ${{ env.IMAGE_PREFIX }}${{ matrix.image }}
run: cosign sign --yes "${IMAGE}@${DIGEST}"
run: |
set -euo pipefail
for attempt in 1 2 3; do
if cosign sign --yes "${IMAGE}@${DIGEST}"; then
exit 0
fi
if [[ "$attempt" -eq 3 ]]; then
echo "Cosign signing failed after $attempt attempts" >&2
exit 1
fi
sleep $((attempt * 15))
done

- name: Verify release image signature
if: needs.setup.outputs.is_release == 'true'
Expand Down Expand Up @@ -468,7 +479,18 @@ jobs:
env:
DIGEST: ${{ steps.build.outputs.digest }}
IMAGE: ${{ env.IMAGE_PREFIX }}aio
run: cosign sign --yes "${IMAGE}@${DIGEST}"
run: |
set -euo pipefail
for attempt in 1 2 3; do
if cosign sign --yes "${IMAGE}@${DIGEST}"; then
exit 0
fi
if [[ "$attempt" -eq 3 ]]; then
echo "Cosign signing failed after $attempt attempts" >&2
exit 1
fi
sleep $((attempt * 15))
done

- name: Verify release image signature
if: needs.setup.outputs.is_release == 'true'
Expand Down Expand Up @@ -614,7 +636,16 @@ jobs:
fi

chart_ref="ghcr.io/szymczag/charts/hangar@${chart_digest}"
cosign sign --yes "$chart_ref"
for attempt in 1 2 3; do
if cosign sign --yes "$chart_ref"; then
break
fi
if [[ "$attempt" -eq 3 ]]; then
echo "Cosign signing failed after $attempt attempts" >&2
exit 1
fi
sleep $((attempt * 15))
done
cosign verify \
--certificate-identity "$CERTIFICATE_IDENTITY" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ the table marks them as available.
## Deployment

- [Docker deployment](deployments/cli/community/README.md)
- [Kubernetes and Helm](docs/kubernetes/README.md) — `0.1.0-rc.28`
- [Kubernetes and Helm](docs/kubernetes/README.md) — `0.1.0-rc.29`
evaluation release; production support gates remain open.
- [Amazon SES, deliverability, and OpenPGP email](docs/aws-ses-email-operations.md)
— secure transactional-email configuration and operations.
Expand Down Expand Up @@ -170,7 +170,7 @@ Install Cosign, obtain the digest for the version you intend to deploy, and veri
both the exact workflow identity and GitHub's OIDC issuer:

```sh
VERSION=v0.1.0-rc.28
VERSION=v0.1.0-rc.29
GIT_TAG=hangar-$VERSION
DIGEST=sha256:replace-with-the-published-digest
IMAGE=ghcr.io/szymczag/hangar-api
Expand Down
21 changes: 11 additions & 10 deletions charts/hangar/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ published as an OCI artifact at:
oci://ghcr.io/szymczag/charts/hangar
```

The latest published chart is `0.1.0-rc.28` (`appVersion: v0.1.0-rc.28`). Its
The latest published chart is `0.1.0-rc.29` (`appVersion: v0.1.0-rc.29`). Its
evaluation profile is live-qualified on AMD64. It is a prerelease and is not yet
supported for production. Release packaging stages these versions and immutable
image digests from the release tag; source defaults remain fail-closed.
Expand All @@ -27,17 +27,18 @@ Inspect the published chart without registry credentials:

```bash
helm show chart oci://ghcr.io/szymczag/charts/hangar \
--version 0.1.0-rc.28
--version 0.1.0-rc.29
```

Do not use `0.1.0-rc.1`, `0.1.0-rc.2`, `0.1.0-rc.20`, `0.1.0-rc.24`, or
`0.1.0-rc.25`; those immutable versions were consumed by incomplete release
attempts. `0.1.0-rc.24` and `0.1.0-rc.25` each published only a subset of their
container sets and no chart. `0.1.0-rc.27` is the immediately previous complete
Do not use `0.1.0-rc.1`, `0.1.0-rc.2`, `0.1.0-rc.20`, `0.1.0-rc.24`,
`0.1.0-rc.25`, or `0.1.0-rc.28`; those immutable versions were consumed by
incomplete release attempts. `0.1.0-rc.24`, `0.1.0-rc.25`, and `0.1.0-rc.28`
each published only a subset of their container sets and no chart or GitHub
Release. `0.1.0-rc.27` is the immediately previous complete
publication, but it predates the signed preview grant and transactional duplicate
admission controls in `rc.28`.
admission controls in `rc.29`.
Earlier `rc.12` through `rc.17` additionally contain frontend migration failures.
Use `0.1.0-rc.28`; there is no security-equivalent
Use `0.1.0-rc.29`; there is no security-equivalent
rollback target among the earlier release candidates.

## Deployment profiles
Expand Down Expand Up @@ -114,8 +115,8 @@ digests for the five Hangar application images. The source chart intentionally
contains all-zero application digests so an unstaged source checkout fails
closed.

Release `0.1.0-rc.28` is available from the
[GitHub Release](https://github.com/szymczag/hangar/releases/tag/hangar-v0.1.0-rc.28)
Release `0.1.0-rc.29` is available from the
[GitHub Release](https://github.com/szymczag/hangar/releases/tag/hangar-v0.1.0-rc.29)
and GHCR. Follow the [verification guide](../../docs/kubernetes/security.md)
before admitting the package to a controlled environment.

Expand Down
28 changes: 14 additions & 14 deletions docs/kubernetes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Hangar publishes a Helm chart for Kubernetes at:
oci://ghcr.io/szymczag/charts/hangar
```

The current release is `0.1.0-rc.28`. It is qualified for evaluation on
The current release is `0.1.0-rc.29`. It is qualified for evaluation on
AMD64 Kubernetes clusters. It is not yet a supported production release.

> [!IMPORTANT]
Expand Down Expand Up @@ -44,7 +44,7 @@ only to review and help qualify the production profile.

## Compatibility

The `0.1.0-rc.28` qualification boundary is:
The `0.1.0-rc.29` qualification boundary is:

| Item | Qualified boundary |
| ---------------------- | ---------------------------------------------------------------- |
Expand Down Expand Up @@ -110,23 +110,23 @@ The product, chart, and Git identifiers are deliberately different:

| Identifier | Current value |
| ------------------ | -------------------------------------------- |
| Product version | `v0.1.0-rc.28` |
| Helm chart version | `0.1.0-rc.28` |
| Git tag | `hangar-v0.1.0-rc.28` |
| OCI chart | `ghcr.io/szymczag/charts/hangar:0.1.0-rc.28` |

`rc.1`, `rc.2`, `rc.20`, `rc.24`, and `rc.25` were consumed by incomplete publication
attempts. Do not use them. `rc.27` is the immediately previous complete publication, but it
predates the signed preview grant and transactional duplicate admission controls in `rc.28`.
| Product version | `v0.1.0-rc.29` |
| Helm chart version | `0.1.0-rc.29` |
| Git tag | `hangar-v0.1.0-rc.29` |
| OCI chart | `ghcr.io/szymczag/charts/hangar:0.1.0-rc.29` |

`rc.1`, `rc.2`, `rc.20`, `rc.24`, `rc.25`, and `rc.28` were consumed by incomplete
publication attempts. Do not use them. `rc.27` is the immediately previous complete publication, but it
predates the signed preview grant and transactional duplicate admission controls in `rc.29`.
Earlier `rc.12` through `rc.17` additionally contain frontend migration failures.
There is no security-equivalent rollback target among the earlier release
candidates. Published versions are immutable and are never repaired in place. In
particular, `rc.24` and `rc.25` each published only a subset of their container
sets and published no chart or GitHub Release.
particular, `rc.24`, `rc.25`, and `rc.28` each published only a subset of their
container sets and published no chart or GitHub Release.

## Documentation

- [Release `v0.1.0-rc.28` notes](../releases/hangar-v0.1.0-rc.28.md) — review
- [Release `v0.1.0-rc.29` notes](../releases/hangar-v0.1.0-rc.29.md) — review
security changes, migrations, compatibility, limitations, and rollback.
- [Install the evaluation profile](evaluation-install.md) — complete a first
installation in a dedicated namespace.
Expand All @@ -151,7 +151,7 @@ Pod Security, migrations, HTTPS ingress, WebSockets, positive and negative
network-policy checks, dependency connectivity, object-storage persistence, an
atomic upgrade, rollback-on-failure behavior, uninstall, and retained PVCs.

The public `rc.28` chart archive, OCI chart, and digest-pinned Hangar images are
The public `rc.29` chart archive, OCI chart, and digest-pinned Hangar images are
anonymously downloadable. The release workflow also created provenance
attestations and keyless Cosign signatures.

Expand Down
4 changes: 2 additions & 2 deletions docs/kubernetes/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ global:
Use a component's `image.pullSecrets` for a narrower credential. Worker, beat,
and migrator Pods use `api.image.pullSecrets` because they run the API image.
Public release images currently pull anonymously, so a GHCR credential is not
required for `0.1.0-rc.28`.
required for `0.1.0-rc.29`.

## Replicas and disruption budgets

Expand All @@ -400,7 +400,7 @@ spread, and a termination grace period. Component templates combine these values
with their security constraints.

Evaluation dependencies are fixed to `kubernetes.io/arch: amd64`. All application
images in `0.1.0-rc.28` are also AMD64-only.
images in `0.1.0-rc.29` are also AMD64-only.

## Evaluation storage

Expand Down
12 changes: 6 additions & 6 deletions docs/kubernetes/evaluation-install.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Install Hangar for evaluation

This tutorial installs Hangar `0.1.0-rc.28` in a dedicated namespace with bundled,
This tutorial installs Hangar `0.1.0-rc.29` in a dedicated namespace with bundled,
persistent PostgreSQL, Valkey, RabbitMQ, and object storage. When complete, you
will have a TLS-enabled Hangar instance suitable for evaluation and compatibility
testing.
Expand All @@ -26,7 +26,7 @@ You need:
Set the release parameters used throughout this tutorial:

```bash
export CHART_VERSION=0.1.0-rc.28
export CHART_VERSION=0.1.0-rc.29
export RELEASE_NAME=hangar
export NAMESPACE=hangar-evaluation
export HANGAR_HOST=hangar-evaluation.example.com
Expand All @@ -43,10 +43,10 @@ helm show chart oci://ghcr.io/szymczag/charts/hangar \
--version "$CHART_VERSION"
```

Confirm the output reports chart version `0.1.0-rc.28`, application version
`v0.1.0-rc.28`, and the expected Kubernetes version constraint.
Confirm the output reports chart version `0.1.0-rc.29`, application version
`v0.1.0-rc.29`, and the expected Kubernetes version constraint.

For higher-assurance environments, complete [artifact verification](security.md#verify-release-010-rc28)
For higher-assurance environments, complete [artifact verification](security.md#verify-release-010-rc29)
before installation.

## 2. Create a Restricted namespace
Expand Down Expand Up @@ -82,7 +82,7 @@ Download the release-matched Secret structure into a private local file:
umask 077
curl --fail --location --silent --show-error \
--output evaluation-secrets.yaml \
https://raw.githubusercontent.com/szymczag/hangar/hangar-v0.1.0-rc.28/charts/hangar/examples/evaluation-secrets.example.yaml
https://raw.githubusercontent.com/szymczag/hangar/hangar-v0.1.0-rc.29/charts/hangar/examples/evaluation-secrets.example.yaml
```

Replace every `CHANGE_ME` value with a unique, randomly generated credential.
Expand Down
15 changes: 9 additions & 6 deletions docs/kubernetes/operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ that one over-limit request returns `429` without creating a job or source.

## Upgrade a release

### Upgrade from `rc.27` to `rc.28`
### Upgrade from `rc.27` to `rc.29`

`rc.28` was consumed by an incomplete publication and is not an upgrade target.
Upgrade directly from the immediately previous complete release, `rc.27`.

This release closes two Todoist import admission gaps. Starting an import now
requires a server-signed, 15-minute, single-use preview grant bound to the
Expand All @@ -79,13 +82,13 @@ Before upgrading:

1. take a PostgreSQL backup, prove that it can be restored in isolation, and
record the current Helm revision and application image digests;
2. confirm the target chart is `0.1.0-rc.28`, its application version is
`v0.1.0-rc.28`, and its signatures and digests pass the
[release verification procedure](security.md#verify-release-010-rc28);
2. confirm the target chart is `0.1.0-rc.29`, its application version is
`v0.1.0-rc.29`, and its signatures and digests pass the
[release verification procedure](security.md#verify-release-010-rc29);
3. render the existing values against the target chart and verify that only the
expected release versions and immutable image digests change; and
4. deploy every application image as one coordinated Helm revision. Do not mix
`rc.27` and `rc.28` web or API images because their preview-execution request
`rc.27` and `rc.29` web or API images because their preview-execution request
contract intentionally changed together.

Wait for the revision-scoped migration Job to complete before admitting traffic.
Expand All @@ -98,7 +101,7 @@ also fail without creating a job or retaining a source object.
target; the nullable column may remain in the database. It restores the preview
bypass and duplicate-confirmation race, however, so it is not a
security-equivalent rollback. Prefer a forward correction and return every
application component to `rc.28` promptly.
application component to `rc.29` promptly.

### Upgrade from `rc.26` to `rc.27`

Expand Down
6 changes: 3 additions & 3 deletions docs/kubernetes/production-install.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ stateful services. It is intended for platform engineers participating in
production qualification and design review.

> [!CAUTION]
> Hangar `0.1.0-rc.28` is not supported for production. The production profile
> Hangar `0.1.0-rc.29` is not supported for production. The production profile
> renders with secure defaults, but it has not completed the installation,
> upgrade, backup/restore, failure-recovery, security-review, or compatibility
> gates required for production support. Do not place critical data or users on
Expand Down Expand Up @@ -81,7 +81,7 @@ Confirm that:
## 4. Create the namespace and TLS Secret

```bash
export CHART_VERSION=0.1.0-rc.28
export CHART_VERSION=0.1.0-rc.29
export RELEASE_NAME=hangar
export NAMESPACE=hangar
export HANGAR_HOST=hangar.example.com
Expand Down Expand Up @@ -133,7 +133,7 @@ Download the release-matched example:
```bash
curl --fail --location --silent --show-error \
--output production-values.yaml \
https://raw.githubusercontent.com/szymczag/hangar/hangar-v0.1.0-rc.28/charts/hangar/examples/production-values.yaml
https://raw.githubusercontent.com/szymczag/hangar/hangar-v0.1.0-rc.29/charts/hangar/examples/production-values.yaml
```

At minimum, set:
Expand Down
14 changes: 7 additions & 7 deletions docs/kubernetes/security.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Kubernetes security and artifact verification

This document explains the chart's security boundaries and provides commands for
verifying the public `0.1.0-rc.28` release.
verifying the public `0.1.0-rc.29` release.

## Security model

Expand Down Expand Up @@ -88,9 +88,9 @@ that does not enforce policies can fail open.

## Release trust chain

For `0.1.0-rc.28`, the trust chain is:
For `0.1.0-rc.29`, the trust chain is:

1. signed Git tag `hangar-v0.1.0-rc.28` identifies the source commit;
1. signed Git tag `hangar-v0.1.0-rc.29` identifies the source commit;
2. the release workflow builds AMD64 images with BuildKit SBOM and provenance;
3. GitHub creates build-provenance attestations;
4. the workflow signs image and chart digests keylessly with GitHub OIDC;
Expand All @@ -101,16 +101,16 @@ For `0.1.0-rc.28`, the trust chain is:
Verification must use immutable digests and the exact workflow identity. A valid
signature for a different workflow, repository, tag, or issuer is not sufficient.

## Verify release `0.1.0-rc.28`
## Verify release `0.1.0-rc.29`

These commands require `curl`, `sha256sum`, GitHub CLI for the GitHub attestation,
and Cosign for OCI signatures.

### 1. Download public release assets

```bash
export VERSION=0.1.0-rc.28
export GIT_TAG=hangar-v0.1.0-rc.28
export VERSION=0.1.0-rc.29
export GIT_TAG=hangar-v0.1.0-rc.29
export RELEASE_URL="https://github.com/szymczag/hangar/releases/download/$GIT_TAG"

mkdir "hangar-$VERSION-release"
Expand Down Expand Up @@ -232,7 +232,7 @@ licenses, vulnerabilities, and maintenance status independently.

## Current limitations

`0.1.0-rc.28` is a prerelease. Only the evaluation profile has completed live
`0.1.0-rc.29` is a prerelease. Only the evaluation profile has completed live
cluster qualification. Vulnerability and license approval, production security
qualification, backup/restore, migration-failure recovery, and the complete
support matrix remain open gates.
Expand Down
4 changes: 2 additions & 2 deletions docs/kubernetes/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Confirm the chart is public:

```bash
helm show chart oci://ghcr.io/szymczag/charts/hangar \
--version 0.1.0-rc.28
--version 0.1.0-rc.29
```

Confirm the node architecture:
Expand All @@ -69,7 +69,7 @@ Confirm the node architecture:
kubectl get nodes --label-columns kubernetes.io/arch
```

`0.1.0-rc.28` is AMD64-only. An ARM64-only cluster cannot schedule or run the
`0.1.0-rc.29` is AMD64-only. An ARM64-only cluster cannot schedule or run the
qualified images.

Published charts use digest references. Inspect the failed Pod's image without
Expand Down
Loading
Loading