Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
5012d9d
ci: enforce the coverage floor that the Makefile already defines
shaneutt Aug 14, 2026
395a56d
perf(api): paginate cluster-wide list calls
shaneutt Aug 14, 2026
698acfd
fix(routes): reject method and queryParams matches Praxis cannot honour
shaneutt Aug 14, 2026
da4919c
fix(config): scope filter conditions to their rule's own match
shaneutt Aug 14, 2026
5c87a80
feat(observability): add health, readiness and metrics endpoints
shaneutt Aug 14, 2026
ea4603d
feat(operator): add leader election for multi-replica safety
shaneutt Aug 14, 2026
db75dee
test(config): guard config generation against non-determinism
shaneutt Aug 14, 2026
5c0cef3
ci(conformance): raise the suite timeout above its observed runtime
shaneutt Aug 14, 2026
bdf8bb6
feat(operator): emit Kubernetes events for rejected Gateways
shaneutt Aug 14, 2026
14b59ba
feat(dataplane): make replicas configurable and survive disruption
shaneutt Aug 14, 2026
70a687b
chore(deps): move off the abandoned serde_yaml onto yaml_serde
shaneutt Aug 14, 2026
43aafed
fix(config): emit only redirect statuses Praxis accepts
shaneutt Aug 14, 2026
0fc4ec5
refactor(config): parse listener protocols once instead of comparing …
shaneutt Aug 14, 2026
5db65ac
chore(release): add a release workflow, changelog and benchmark
shaneutt Aug 14, 2026
e9145b1
fix(operator): report readiness for standby replicas
shaneutt Aug 14, 2026
9e61778
refactor(config): name the attached-route pair
shaneutt Aug 14, 2026
0407619
fix(build): stub the bench target
shaneutt Aug 14, 2026
f79346a
refactor(config): extract endpoint weight distribution into its own m…
shaneutt Aug 14, 2026
3115396
chore: benchmark the converter
shaneutt Aug 14, 2026
9ed9f21
chore: replace the copy-pasted test lint preamble with real cfg
shaneutt Aug 14, 2026
8dcd643
chore(refactor): serve cluster-wide reads from watch caches instead o…
shaneutt Aug 14, 2026
ce30c52
chore: evaluate matchExpressions when rejecting routes by namespace
shaneutt Aug 14, 2026
16b50ec
chore: keep the data-plane default at one replica
shaneutt Aug 14, 2026
9c1e304
test(conformance): restate the failing conformance tests at the end o…
shaneutt Aug 14, 2026
d3a17dc
chore: do not let an unserved listener protocol conflict with a serve…
shaneutt Aug 14, 2026
42d6237
chore: report ListenersNotValid when only some listeners are valid
shaneutt Aug 14, 2026
276019d
chore(cleanup): stop claiming a response-header feature the data plan…
shaneutt Aug 14, 2026
ed5035d
chore: pin that an observedGeneration bump alone is still written
shaneutt Aug 14, 2026
3045b99
chore(refactor): sort cache reads so the generated config stops churning
shaneutt Aug 14, 2026
00a98e2
chore(refactor): build status documents from types instead of json! l…
shaneutt Aug 14, 2026
65f9563
chore(deps): update the data plane to praxis 0.5.2
shaneutt Aug 14, 2026
1ecfe41
tests(conformance): run the conformance suites praxis 0.5.2 can now pass
shaneutt Aug 14, 2026
dc3a7b2
chore: place route filters on the side of the router they belong on
shaneutt Aug 14, 2026
9a50cda
feat: implement URLRewrite
shaneutt Aug 14, 2026
7f9ece6
fix: match wildcard hostnames at any depth
shaneutt Aug 14, 2026
ff08d19
fix: answer 500 when every backend of a rule was refused
shaneutt Aug 14, 2026
4fd5370
fix: propagate Gateway infrastructure metadata to generated resources
shaneutt Aug 14, 2026
402acd0
fix: honor the timeouts an HTTPRoute rule declares
shaneutt Aug 14, 2026
7344a52
chore: claim the redirect features
shaneutt Aug 14, 2026
eb40c37
fix: resolve parentRefs by port as well as by section name
shaneutt Aug 14, 2026
5fe9931
chore(deps): add a Kubernetes client backed by canned responses
shaneutt Aug 14, 2026
b53359a
tests(coverage): cover the ownership checks
shaneutt Aug 14, 2026
bfa7e2c
chore(coverage): cover listener validation and namespace filtering
shaneutt Aug 14, 2026
db3fa7b
tests(coverage): cover Gateway status assembly against a fake API server
shaneutt Aug 14, 2026
38647af
fix: keep generated resource names inside the 63-character limit
shaneutt Aug 14, 2026
15e0fb3
test(coverage): cover the Gateway reconciler's apply and cleanup paths
shaneutt Aug 14, 2026
6ee16fc
tests(coverage): cover the HTTPRoute reconciler's rejection paths
shaneutt Aug 14, 2026
43332b6
fix: raise the coverage floor to 95%
shaneutt Aug 14, 2026
fd13345
fix: retry the network fetches CI depends on
shaneutt Aug 14, 2026
1a7793d
fix: claim the two features that need no data-plane change
shaneutt Aug 14, 2026
8285148
ci(deps): Bump the actions group with 4 updates
dependabot[bot] Aug 14, 2026
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
15 changes: 10 additions & 5 deletions .github/workflows/conformance.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ env:
CARGO_TERM_COLOR: always
CONTAINER_ENGINE: docker
KIND_CLUSTER_NAME: praxis-conformance
PRAXIS_IMAGE: ghcr.io/praxis-proxy/praxis:0.3.1
PRAXIS_IMAGE: ghcr.io/praxis-proxy/praxis:0.5.2
OPERATOR_IMAGE: praxis-operator:dev

jobs:
Expand All @@ -38,7 +38,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Login to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand All @@ -48,19 +48,24 @@ jobs:
run: docker build -t ${{ env.OPERATOR_IMAGE }} -f Containerfile .

- name: Pull praxis image
run: docker pull ${{ env.PRAXIS_IMAGE }}
run: bash hack/retry.sh docker pull ${{ env.PRAXIS_IMAGE }}

- name: Install KIND
run: |
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.27.0/kind-linux-amd64
# --fail matters as much as the retries: without it an HTTP error
# page is written to ./kind, chmod +x succeeds, and the failure
# surfaces later as an unreadable exec format error.
bash hack/retry.sh curl --fail --location --show-error --silent \
--retry 3 --retry-all-errors --retry-delay 2 \
--output ./kind https://kind.sigs.k8s.io/dl/v0.27.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

- name: Setup KIND cluster
run: bash hack/setup-kind.sh

- name: Install Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.24"
cache: false
Expand Down
13 changes: 9 additions & 4 deletions .github/workflows/integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ env:
KIND_CLUSTER_NAME: ci
V: ${{ inputs.debug && '1' || '' }}
OPERATOR_IMAGE: praxis-operator:dev
PRAXIS_IMAGE: ghcr.io/praxis-proxy/praxis:0.3.1
PRAXIS_IMAGE: ghcr.io/praxis-proxy/praxis:0.5.2

jobs:
# ---------------------------------------------------------------------------
Expand All @@ -45,7 +45,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Login to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand All @@ -57,11 +57,16 @@ jobs:
run: docker build -t ${{ env.OPERATOR_IMAGE }} -f Containerfile .

- name: Pull praxis image
run: docker pull ${{ env.PRAXIS_IMAGE }}
run: bash hack/retry.sh docker pull ${{ env.PRAXIS_IMAGE }}

- name: Install KIND
run: |
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.27.0/kind-linux-amd64
# --fail matters as much as the retries: without it an HTTP error
# page is written to ./kind, chmod +x succeeds, and the failure
# surfaces later as an unreadable exec format error.
bash hack/retry.sh curl --fail --location --show-error --silent \
--retry 3 --retry-all-errors --retry-delay 2 \
--output ./kind https://kind.sigs.k8s.io/dl/v0.27.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

Expand Down
81 changes: 81 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Release

# ------------------------------------------------------------------------------
# Workflow Settings
# ------------------------------------------------------------------------------

on:
push:
tags: ["v*"]
workflow_dispatch:
inputs:
tag:
description: "Tag to build and publish"
required: true
type: string

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

permissions: {}

env:
CARGO_TERM_COLOR: always
REGISTRY: ghcr.io

jobs:
# ---------------------------------------------------------------------------
# Verify before publishing
# ---------------------------------------------------------------------------

verify:
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: praxis-proxy/conventions/.github/actions/setup-rust@7e1e8d97c2dc820d24b31f9a65b119c4d0e5342c # v0.1.0

- name: Tests
run: make test

# ---------------------------------------------------------------------------
# Build and publish the operator image
# ---------------------------------------------------------------------------

image:
needs: verify
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Login to GHCR
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Derive image tags
id: tags
run: |
version="${{ inputs.tag || github.ref_name }}"
image="${REGISTRY}/${GITHUB_REPOSITORY,,}"
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "tags=${image}:${version},${image}:latest" >> "$GITHUB_OUTPUT"

- name: Build and push
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
file: Containerfile
push: true
tags: ${{ steps.tags.outputs.tags }}
labels: |
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.version=${{ steps.tags.outputs.version }}
21 changes: 21 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,27 @@ jobs:
- name: Tests
run: make test

# ---------------------------------------------------------------------------
# Coverage floor
# ---------------------------------------------------------------------------

coverage:
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: praxis-proxy/conventions/.github/actions/setup-rust@7e1e8d97c2dc820d24b31f9a65b119c4d0e5342c # v0.1.0

- name: Install cargo-llvm-cov
uses: taiki-e/install-action@7f4eb899022d8fe70b20c4f3de697aa85c309026 # v2.62.44
with:
tool: cargo-llvm-cov

- name: Coverage
run: make coverage-check

# ---------------------------------------------------------------------------
# Supply-chain audit
# ---------------------------------------------------------------------------
Expand Down
47 changes: 47 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Changelog

All notable changes to this project are documented here.

The format follows [Keep a Changelog], and this project adheres to
[Semantic Versioning].

[Keep a Changelog]: https://keepachangelog.com/en/1.1.0/
[Semantic Versioning]: https://semver.org/spec/v2.0.0.html

## [Unreleased]

### Added

- Health, readiness and metrics endpoints on port 8080, with matching
probes on the operator Deployment.
- Leader election over a coordination `Lease`, so the operator can run
more than one replica safely.
- Kubernetes events explaining why a Gateway was rejected.
- Configurable data-plane replicas via the `praxis.sh/replicas`
annotation, a `PodDisruptionBudget`, and pod spread across nodes.
- `method` and `queryParams` route matches are now detected and
reported rather than silently ignored.
- Listener protocol and hostname conflict detection.

### Fixed

- Status writes no longer restamp unchanged conditions, which had kept
the operator in a permanent reconcile loop.
- Endpoint weight distribution no longer overflows `i32` and aborts the
process.
- The Gateway and HTTPRoute controllers no longer overwrite each other's
entries in `status.parents`.
- Unsupported route matchers and filters are rejected instead of being
widened into something the author did not ask for.
- Hostname matching is case-insensitive, per RFC 1123.
- Named `targetPort`s resolve by port name instead of picking an
arbitrary port on multi-port Services.
- Terminating endpoints are excluded from the data-plane config.
- Route parent status is cleared when its Gateway is deleted.
- Redirect statuses outside the set Praxis accepts no longer produce a
config the data plane refuses to load.

### Security

- RBAC no longer grants write access to Secrets and Endpoints.
- The operator pod is hardened to match the data-plane pods it creates.
Loading
Loading