diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml deleted file mode 100644 index 5e85642..0000000 --- a/.github/workflows/docker-publish.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: Docker - -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -on: - push: - branches: [ "main" ] - # Publish semver tags as releases. - tags: [ 'v*.*.*' ] - -env: - # Use docker.io for Docker Hub if empty - REGISTRY: ghcr.io - # github.repository as / - IMAGE_NAME: pelotech/goose - GOOSE_VERSION: v3.26.0 - -jobs: - build: - - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - # This is used to complete the identity challenge - # with sigstore/fulcio when running outside of PRs. - id-token: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # https://github.com/sigstore/cosign-installer - - name: Install cosign - if: github.event_name != 'pull_request' - uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 #v3.5.0 - with: - cosign-release: 'v2.2.4' - - - uses: docker/setup-qemu-action@v3 - - # https://github.com/docker/setup-buildx-action - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - if: github.event_name != 'pull_request' - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - # https://github.com/docker/build-push-action - - name: Build and Push Goose Image - id: build-and-push - uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 - with: - context: ./images - file: ./images/goose.dockerfile - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - platforms: linux/amd64,linux/arm64 - - # https://github.com/sigstore/cosign - - name: Sign the published Docker image - if: ${{ github.event_name != 'pull_request' }} - env: - # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable - TAGS: ${{ steps.meta.outputs.tags }} - DIGEST: ${{ steps.build-and-push.outputs.digest }} - # This step uses the identity token to provision an ephemeral certificate - # against the sigstore community Fulcio instance. - run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} diff --git a/.github/workflows/helm-publish.yml b/.github/workflows/helm-publish.yml deleted file mode 100644 index e7ed3ca..0000000 --- a/.github/workflows/helm-publish.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: helm-publish -on: - push: - branches: - - main - -jobs: - helm-publish: - runs-on: ubuntu-latest - permissions: - packages: write - contents: read - steps: - - uses: actions/checkout@v6 - - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - uses: appany/helm-oci-chart-releaser@v0.5.0 - with: - name: postgrest - repository: pelotech/database - tag: 0.2.1 - registry: ghcr.io - registry_username: ${{ github.actor }} - registry_password: ${{ secrets.GITHUB_TOKEN }} - update_dependencies: 'true' diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..cafb439 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,35 @@ +name: lint + +on: + pull_request: null + push: + branches: + - main + tags: + - "v*.*.*" + +permissions: {} + +jobs: + helm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: '0' + - uses: azure/setup-helm@v4.3.1 + with: + version: 'latest' + - uses: actions/setup-python@v6 + with: + python-version: '3.x' + check-latest: true + - uses: helm/chart-testing-action@v2.8.0 + - id: list-changed + run: | + changed=$(ct list-changed) + if [[ -n "$changed" ]]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + - if: steps.list-changed.outputs.changed == 'true' + run: ct lint --chart-repos cluster=https://cloudnative-pg.io/charts diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml new file mode 100644 index 0000000..ed1e43e --- /dev/null +++ b/.github/workflows/push.yaml @@ -0,0 +1,78 @@ +name: Build and Publish Artifacts + +on: + pull_request: null + push: + branches: + - main + tags: [ "v*.*.*" ] + +env: + REGISTRY: ghcr.io + GOOSE_IMAGE_NAME: pelotech/goose + GOOSE_PACKAGE_VERSION: v3.26.0 + +jobs: + charts: + if: github.event_name != 'pull_request' + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v6 + - uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: appany/helm-oci-chart-releaser@v0.5.0 + if: ${{ github.event_name != 'pull_request' }} + with: + name: postgrest + tag: ${{ github.ref }} + repository: ${{ github.repository }} + registry: ${{ env.REGISTRY }} + registry_username: ${{ github.actor }} + registry_password: ${{ secrets.GITHUB_TOKEN }} + + images: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + id-token: write + steps: + - uses: actions/checkout@v6 + - uses: sigstore/cosign-installer@v3.5.0 + if: ${{ github.event_name != 'pull_request' }} + with: + cosign-release: 'v2.2.4' + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + - uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: docker/metadata-action@v5 + id: metadata + with: + images: ${{ env.REGISTRY }}/${{ env.GOOSE_IMAGE_NAME }} + - uses: docker/build-push-action@v6 + id: goose-image + with: + context: ./images + file: ./images/goose.dockerfile + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.metadata.outputs.tags }} + labels: ${{ steps.metadata.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64,linux/arm64 + - name: sign the published image + if: ${{ github.event_name != 'pull_request' }} + env: + TAGS: ${{ steps.metadata.outputs.tags }} + DIGEST: ${{ steps.goose-image.outputs.digest }} + run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} diff --git a/charts/postgrest/Chart.lock b/charts/postgrest/Chart.lock index 50ae7e0..008b4b0 100644 --- a/charts/postgrest/Chart.lock +++ b/charts/postgrest/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: cluster - repository: https://cloudnative-pg.io/charts/ + repository: https://cloudnative-pg.io/charts version: 0.5.0 -digest: sha256:b1926f62c6d6db85689a161c910e31e550970843d33aed3f01159f50d9bddc15 -generated: "2026-01-05T17:38:04.423244-05:00" +digest: sha256:bd4115e6b9154294c12879f19116e015f1e98563d7f1324f103ed170e3dab69e +generated: "2026-01-08T14:31:47.621461-05:00" diff --git a/charts/postgrest/Chart.yaml b/charts/postgrest/Chart.yaml index 889470e..3effb04 100644 --- a/charts/postgrest/Chart.yaml +++ b/charts/postgrest/Chart.yaml @@ -1,10 +1,14 @@ apiVersion: v2 name: postgrest -version: 0.2.1 +icon: https://docs.postgrest.org/en/v14/_images/postgrest.png +version: 0.2.2 +maintainers: + - name: jared-prime + email: jared.davis@pelo.tech description: Helm chart for a PostgREST data api dependencies: - name: cluster version: 0.5.0 - repository: https://cloudnative-pg.io/charts/ + repository: https://cloudnative-pg.io/charts condition: cluster.enabled diff --git a/charts/postgrest/Quickstart.md b/charts/postgrest/Quickstart.md index fe90e97..abac2d8 100644 --- a/charts/postgrest/Quickstart.md +++ b/charts/postgrest/Quickstart.md @@ -1,32 +1,9 @@ # quickstart -Login to the GitHub Container Registry -```shell -username="my user name" -personal="my personal access token with package read / write permissions" -docker login ghcr.io -u $username $personal -``` ```shell -kind create cluster --name pelotech - -docker build -t ghcr.io/pelotech/goose:example example/migrations - -kind load docker-image ghcr.io/pelotech/goose:example --name pelotech - -helm upgrade --install cnpg \ - --namespace cnpg-system \ - --create-namespace \ - --wait \ - --timeout 1m \ - cnpg/cloudnative-pg - -helm dependency build ./charts/postgrest - -helm upgrade --install postgrest \ - --namespace default \ - ./charts/postgrest +./example/build.sh ``` ## usage diff --git a/charts/postgrest/templates/_helpers.tpl b/charts/postgrest/templates/_helpers.tpl index d193180..8266f96 100644 --- a/charts/postgrest/templates/_helpers.tpl +++ b/charts/postgrest/templates/_helpers.tpl @@ -1,15 +1,15 @@ -{{ define "database.connection" }} -{{ $username := .Values.database.connection.username }} -{{ $password := .Values.database.connection.password }} -{{ $database := .Values.database.connection.database }} -{{ $hostname := .Values.database.connection.hostname }} -{{ printf "user=%s password=%s host=%s dbname=%s sslmode=disable" $username $password $hostname $database }} -{{ end }} +{{- define "database.connection" -}} +{{- $username := .Values.database.connection.username }} +{{- $password := .Values.database.connection.password }} +{{- $database := .Values.database.connection.database }} +{{- $hostname := .Values.database.connection.hostname }} +{{- printf "user=%s password=%s host=%s dbname=%s sslmode=disable" $username $password $hostname $database }} +{{- end -}} -{{ define "database.migrations" }} -{{ $username := .Values.database.migrations.username }} -{{ $password := .Values.database.migrations.password }} -{{ $database := .Values.database.migrations.database }} -{{ $hostname := .Values.database.migrations.hostname }} -{{ printf "user=%s password=%s host=%s dbname=%s sslmode=disable" $username $password $hostname $database }} -{{ end }} +{{- define "database.migrations" -}} +{{- $username := .Values.database.migrations.username }} +{{- $password := .Values.database.migrations.password }} +{{- $database := .Values.database.migrations.database }} +{{- $hostname := .Values.database.migrations.hostname }} +{{- printf "user=%s password=%s host=%s dbname=%s sslmode=disable" $username $password $hostname $database }} +{{- end -}} diff --git a/charts/postgrest/templates/database.yaml b/charts/postgrest/templates/database.yaml new file mode 100644 index 0000000..037cbcc --- /dev/null +++ b/charts/postgrest/templates/database.yaml @@ -0,0 +1,12 @@ +{{- if (not .Values.cluster.enabled) }} +{{- range $database := .Values.cluster.databases }} +apiVersion: postgresql.cnpg.io/v1 +kind: Database +metadata: + name: postgrest + namespace: "{{ .Release.Namespace }}" +spec: + {{ $database | toYaml | nindent 2 }} +--- +{{- end }} +{{- end }} diff --git a/charts/postgrest/templates/deployment.yaml b/charts/postgrest/templates/deployment.yaml index 21e6ad7..b9b38e0 100644 --- a/charts/postgrest/templates/deployment.yaml +++ b/charts/postgrest/templates/deployment.yaml @@ -2,26 +2,43 @@ apiVersion: apps/v1 kind: Deployment metadata: name: postgrest - + namespace: "{{ .Release.Namespace }}" spec: replicas: 1 selector: matchLabels: - name: postgrest + app.kubernetes.io/component: postgrest + app.kubernetes.io/instance: "{{ .Release.Namespace }}" + app.kubernetes.io/name: postgrest template: metadata: labels: - name: postgrest + app.kubernetes.io/component: postgrest + app.kubernetes.io/instance: "{{ .Release.Namespace }}" + app.kubernetes.io/name: postgrest spec: initContainers: + - name: wait-for-databases + image: alpine:3.23 + imagePullPolicy: IfNotPresent + command: + - /bin/sh + - -c + - | + apk add postgresql-client && + while ! psql {{ include "database.connection" . | quote }} -c "SELECT 1;" 2>/dev/null; do + echo "awaiting connection - retrying in 5 seconds" + sleep 5 + done + echo "connection succeeded" {{ if not (empty .Values.application.jwk.public) }} - - name: jwks - image: alpine/curl + - name: curl-the-jwks + image: alpine:3.23 imagePullPolicy: IfNotPresent command: - /bin/sh - -c - - "curl --location {{ .Values.application.jwk.public }} > /etc/opt/postgrest/certificates/jwk.json" + - curl --location {{ .Values.application.jwk.public | quote }} > /etc/opt/postgrest/certificates/jwk.json - volumeMounts: - mountPath: /etc/opt/postgrest/certificates name: certificates @@ -44,6 +61,10 @@ spec: - name: postgrest image: postgrest/postgrest imagePullPolicy: IfNotPresent + ports: + - name: postgrest + containerPort: 3000 + protocol: TCP env: - name: PGRST_DB_URI valueFrom: diff --git a/charts/postgrest/templates/service.yaml b/charts/postgrest/templates/service.yaml index 0f18901..864bfd3 100644 --- a/charts/postgrest/templates/service.yaml +++ b/charts/postgrest/templates/service.yaml @@ -2,12 +2,15 @@ apiVersion: v1 kind: Service metadata: name: postgrest - + namespace: "{{ .Release.Namespace }}" spec: - type: NodePort + type: ClusterIP selector: - name: postgrest + app.kubernetes.io/component: postgrest + app.kubernetes.io/instance: "{{ .Release.Namespace }}" + app.kubernetes.io/name: postgrest ports: - - port: 3000 - targetPort: 3000 - nodePort: 30001 + - name: postgrest + port: 3000 + protocol: TCP + targetPort: postgrest diff --git a/charts/postgrest/values.yaml b/charts/postgrest/values.yaml index cae9174..23e6021 100644 --- a/charts/postgrest/values.yaml +++ b/charts/postgrest/values.yaml @@ -1,9 +1,9 @@ application: - schemas: public # PSQL schemas (comma separated) for api usage - anon: anon # PSQL role to grant anonymous api usage - auth: auth # PSQL role to grant authenticated api usage + schemas: public # PSQL schemas (comma separated) for api usage + anon: anon # PSQL role to grant anonymous api usage + auth: auth # PSQL role to grant authenticated api usage jwk: - public: "" # accessible URL for a public JWK + public: "" # accessible URL for a public JWK jwt: secret: a-string-secret-at-least-256-bits-long claim: @@ -11,15 +11,15 @@ application: database: connection: - username: postgrest # application username for PSQL connection - password: postgrest # application password for PSQL connection - database: postgrest # application database for PSQL connection + username: postgrest # application username for PSQL connection + password: postgrest # application password for PSQL connection + database: postgrest # application database for PSQL connection hostname: postgrest-cluster-rw # application hostname for PSQL connection migrations: - username: goose # superuser username for PSQL connection - password: goose # superuser password for PSQL connection - database: postgrest # superuser database for PSQL connection + username: goose # superuser username for PSQL connection + password: goose # superuser password for PSQL connection + database: postgrest # superuser database for PSQL connection hostname: postgrest-cluster-rw # superuser hostname for PSQL connection image: ghcr.io/pelotech/goose tag: example diff --git a/example/build.sh b/example/build.sh new file mode 100755 index 0000000..dbf927b --- /dev/null +++ b/example/build.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +directory=$(git rev-parse --show-toplevel) + +kind delete cluster --name example +kind create cluster --name example + +helm dependency build "$directory/charts/postgrest" + +helm upgrade \ + --install cnpg \ + --namespace cnpg-system \ + --create-namespace \ + --wait \ + --timeout 1m \ + cnpg/cloudnative-pg + +helm template --namespace default postgrest "$directory/charts/postgrest" | \ + tee "$(pwd)/example.manifest.yaml" | \ + kubectl apply -f - diff --git a/images/goose.dockerfile b/images/goose.dockerfile index f4f650b..84f10c8 100644 --- a/images/goose.dockerfile +++ b/images/goose.dockerfile @@ -1,7 +1,10 @@ -FROM golang:alpine AS builder +FROM golang:1.25-alpine AS builder LABEL authors="Jared Davis " +RUN addgroup --system goose --gid 1001 && \ + adduser --system -G goose goose + WORKDIR /github.com/pressly RUN apk add git @@ -12,9 +15,14 @@ WORKDIR /github.com/pressly/goose RUN go mod tidy && go build -ldflags="-s -w" -tags='no_sqlite no_clickhouse no_mssql no_mysql' -o /bin/goose ./cmd/goose + FROM scratch -COPY --from=builder /bin/goose /bin/goose +COPY --from=builder /etc/passwd /etc/passwd + +USER goose + +COPY --chown=goose:goose --from=builder /bin/goose /bin/goose # https://pressly.github.io/goose/documentation/environment-variables/ ENV GOOSE_DBSTRING="user=postgres dbname=postgres sslmode=disable"