mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-04-11 00:56:36 +00:00
Compare commits
2 Commits
chore/depo
...
snyk-fix-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
971c746b50 | ||
|
|
626adbf14c |
5
.github/workflows/backend-linter.yml
vendored
5
.github/workflows/backend-linter.yml
vendored
@@ -17,15 +17,14 @@ permissions:
|
|||||||
pull-requests: read
|
pull-requests: read
|
||||||
# Optional: allow write access to checks to allow the action to annotate code in the PR.
|
# Optional: allow write access to checks to allow the action to annotate code in the PR.
|
||||||
checks: write
|
checks: write
|
||||||
id-token: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
golangci-lint:
|
golangci-lint:
|
||||||
name: Run Golangci-lint
|
name: Run Golangci-lint
|
||||||
runs-on: depot-ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v6
|
||||||
|
|||||||
95
.github/workflows/build-next.yml
vendored
95
.github/workflows/build-next.yml
vendored
@@ -9,39 +9,43 @@ concurrency:
|
|||||||
group: build-next-image
|
group: build-next-image
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
id-token: write
|
|
||||||
attestations: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-next:
|
build-next:
|
||||||
runs-on: depot-ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
env:
|
contents: read
|
||||||
CONTAINER_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/pocket-id
|
packages: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: "pnpm"
|
|
||||||
|
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: "backend/go.mod"
|
go-version-file: "backend/go.mod"
|
||||||
|
|
||||||
- name: Set up Depot CLI
|
- name: Set up QEMU
|
||||||
uses: depot/setup-action@v1
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Set DOCKER_IMAGE_NAME
|
||||||
|
run: |
|
||||||
|
# Lowercase REPO_OWNER which is required for containers
|
||||||
|
REPO_OWNER=${{ github.repository_owner }}
|
||||||
|
DOCKER_IMAGE_NAME="ghcr.io/${REPO_OWNER,,}/pocket-id"
|
||||||
|
echo "DOCKER_IMAGE_NAME=${DOCKER_IMAGE_NAME}" >>${GITHUB_ENV}
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
@@ -50,40 +54,6 @@ jobs:
|
|||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Container Image Metadata
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ${{ env.CONTAINER_IMAGE_NAME }}
|
|
||||||
tags: |
|
|
||||||
type=raw,value=next
|
|
||||||
labels: |
|
|
||||||
org.opencontainers.image.authors=Pocket ID
|
|
||||||
org.opencontainers.image.url=https://github.com/pocket-id/pocket-id
|
|
||||||
org.opencontainers.image.documentation=https://github.com/pocket-id/pocket-id/blob/main/README.md
|
|
||||||
org.opencontainers.image.source=https://github.com/pocket-id/pocket-id
|
|
||||||
org.opencontainers.image.version=next
|
|
||||||
org.opencontainers.image.licenses=BSD-2-Clause
|
|
||||||
org.opencontainers.image.ref.name=pocket-id
|
|
||||||
org.opencontainers.image.title=Pocket ID
|
|
||||||
|
|
||||||
- name: Container Image Metadata
|
|
||||||
id: distroless-meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ${{ env.CONTAINER_IMAGE_NAME }}
|
|
||||||
tags: |
|
|
||||||
type=raw,value=next-distroless
|
|
||||||
labels: |
|
|
||||||
org.opencontainers.image.authors=Pocket ID
|
|
||||||
org.opencontainers.image.url=https://github.com/pocket-id/pocket-id
|
|
||||||
org.opencontainers.image.documentation=https://github.com/pocket-id/pocket-id/blob/main/README.md
|
|
||||||
org.opencontainers.image.source=https://github.com/pocket-id/pocket-id
|
|
||||||
org.opencontainers.image.version=next-distroless
|
|
||||||
org.opencontainers.image.licenses=BSD-2-Clause
|
|
||||||
org.opencontainers.image.ref.name=pocket-id
|
|
||||||
org.opencontainers.image.title=Pocket ID
|
|
||||||
|
|
||||||
- name: Install frontend dependencies
|
- name: Install frontend dependencies
|
||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
@@ -96,40 +66,31 @@ jobs:
|
|||||||
|
|
||||||
- name: Build and push container image
|
- name: Build and push container image
|
||||||
id: build-push-image
|
id: build-push-image
|
||||||
uses: depot/build-push-action@v1
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/Dockerfile-prebuilt
|
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ env.DOCKER_IMAGE_NAME }}:next
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
file: docker/Dockerfile-prebuilt
|
||||||
sbom: true
|
|
||||||
provenance: true
|
|
||||||
|
|
||||||
- name: Build and push container image (distroless)
|
- name: Build and push container image (distroless)
|
||||||
uses: depot/build-push-action@v1
|
uses: docker/build-push-action@v6
|
||||||
id: container-build-push-distroless
|
id: container-build-push-distroless
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/Dockerfile-distroless
|
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.distroless-meta.outputs.tags }}
|
tags: ${{ env.DOCKER_IMAGE_NAME }}:next-distroless
|
||||||
labels: ${{ steps.distroless-meta.outputs.labels }}
|
file: docker/Dockerfile-distroless
|
||||||
sbom: true
|
|
||||||
provenance: true
|
|
||||||
|
|
||||||
- name: Container image attestation
|
- name: Container image attestation
|
||||||
uses: actions/attest-build-provenance@v2
|
uses: actions/attest-build-provenance@v2
|
||||||
with:
|
with:
|
||||||
subject-name: "${{ env.CONTAINER_IMAGE_NAME }}"
|
subject-name: "${{ env.DOCKER_IMAGE_NAME }}"
|
||||||
subject-digest: ${{ steps.build-push-image.outputs.digest }}
|
subject-digest: ${{ steps.build-push-image.outputs.digest }}
|
||||||
push-to-registry: true
|
push-to-registry: true
|
||||||
|
|
||||||
- name: Container image attestation (distroless)
|
- name: Container image attestation (distroless)
|
||||||
uses: actions/attest-build-provenance@v2
|
uses: actions/attest-build-provenance@v2
|
||||||
with:
|
with:
|
||||||
subject-name: "${{ env.CONTAINER_IMAGE_NAME }}"
|
subject-name: "${{ env.DOCKER_IMAGE_NAME }}"
|
||||||
subject-digest: ${{ steps.container-build-push-distroless.outputs.digest }}
|
subject-digest: ${{ steps.container-build-push-distroless.outputs.digest }}
|
||||||
push-to-registry: true
|
push-to-registry: true
|
||||||
|
|||||||
97
.github/workflows/e2e-tests.yml
vendored
97
.github/workflows/e2e-tests.yml
vendored
@@ -13,15 +13,47 @@ on:
|
|||||||
- "**.md"
|
- "**.md"
|
||||||
- ".github/**"
|
- ".github/**"
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
actions: write
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
build:
|
||||||
|
if: github.event.pull_request.head.ref != 'i18n_crowdin'
|
||||||
|
timeout-minutes: 20
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
actions: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Build and export
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: docker/Dockerfile
|
||||||
|
push: false
|
||||||
|
load: false
|
||||||
|
tags: pocket-id:test
|
||||||
|
outputs: type=docker,dest=/tmp/docker-image.tar
|
||||||
|
build-args: BUILD_TAGS=e2etest
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
- name: Upload Docker image artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: docker-image
|
||||||
|
path: /tmp/docker-image.tar
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
test:
|
test:
|
||||||
if: github.event.pull_request.head.ref != 'i18n_crowdin'
|
if: github.event.pull_request.head.ref != 'i18n_crowdin'
|
||||||
runs-on: depot-ubuntu-24.04-32
|
permissions:
|
||||||
|
contents: read
|
||||||
|
actions: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -38,22 +70,15 @@ jobs:
|
|||||||
storage: database
|
storage: database
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: "pnpm"
|
|
||||||
|
|
||||||
- name: Set up Depot CLI
|
|
||||||
uses: depot/setup-action@v1
|
|
||||||
|
|
||||||
- name: Set up Depot Docker builder
|
|
||||||
run: depot configure-docker
|
|
||||||
|
|
||||||
- name: Cache Playwright Browsers
|
- name: Cache Playwright Browsers
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@@ -77,6 +102,21 @@ jobs:
|
|||||||
if: matrix.db == 'postgres' && steps.postgres-cache.outputs.cache-hit == 'true'
|
if: matrix.db == 'postgres' && steps.postgres-cache.outputs.cache-hit == 'true'
|
||||||
run: docker load < /tmp/postgres-image.tar
|
run: docker load < /tmp/postgres-image.tar
|
||||||
|
|
||||||
|
- name: Cache LLDAP Docker image
|
||||||
|
uses: actions/cache@v4
|
||||||
|
id: lldap-cache
|
||||||
|
with:
|
||||||
|
path: /tmp/lldap-image.tar
|
||||||
|
key: lldap-stable-${{ runner.os }}
|
||||||
|
- name: Pull and save LLDAP image
|
||||||
|
if: steps.lldap-cache.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
docker pull lldap/lldap:2025-05-19
|
||||||
|
docker save lldap/lldap:2025-05-19 > /tmp/lldap-image.tar
|
||||||
|
- name: Load LLDAP image
|
||||||
|
if: steps.lldap-cache.outputs.cache-hit == 'true'
|
||||||
|
run: docker load < /tmp/lldap-image.tar
|
||||||
|
|
||||||
- name: Cache SCIM Test Server Docker image
|
- name: Cache SCIM Test Server Docker image
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
id: scim-cache
|
id: scim-cache
|
||||||
@@ -108,6 +148,31 @@ jobs:
|
|||||||
if: matrix.storage == 's3' && steps.s3-cache.outputs.cache-hit == 'true'
|
if: matrix.storage == 's3' && steps.s3-cache.outputs.cache-hit == 'true'
|
||||||
run: docker load < /tmp/localstack-s3-image.tar
|
run: docker load < /tmp/localstack-s3-image.tar
|
||||||
|
|
||||||
|
- name: Cache AWS CLI Docker image
|
||||||
|
if: matrix.storage == 's3'
|
||||||
|
uses: actions/cache@v4
|
||||||
|
id: aws-cli-cache
|
||||||
|
with:
|
||||||
|
path: /tmp/aws-cli-image.tar
|
||||||
|
key: aws-cli-latest-${{ runner.os }}
|
||||||
|
- name: Pull and save AWS CLI image
|
||||||
|
if: matrix.storage == 's3' && steps.aws-cli-cache.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
docker pull amazon/aws-cli:latest
|
||||||
|
docker save amazon/aws-cli:latest > /tmp/aws-cli-image.tar
|
||||||
|
- name: Load AWS CLI image
|
||||||
|
if: matrix.storage == 's3' && steps.aws-cli-cache.outputs.cache-hit == 'true'
|
||||||
|
run: docker load < /tmp/aws-cli-image.tar
|
||||||
|
|
||||||
|
- name: Download Docker image artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: docker-image
|
||||||
|
path: /tmp
|
||||||
|
|
||||||
|
- name: Load Docker image
|
||||||
|
run: docker load -i /tmp/docker-image.tar
|
||||||
|
|
||||||
- name: Install test dependencies
|
- name: Install test dependencies
|
||||||
run: pnpm --filter pocket-id-tests install --frozen-lockfile
|
run: pnpm --filter pocket-id-tests install --frozen-lockfile
|
||||||
|
|
||||||
@@ -133,7 +198,7 @@ jobs:
|
|||||||
DOCKER_COMPOSE_FILE=docker-compose-s3.yml
|
DOCKER_COMPOSE_FILE=docker-compose-s3.yml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
docker compose -f "$DOCKER_COMPOSE_FILE" up -d --build
|
docker compose -f "$DOCKER_COMPOSE_FILE" up -d
|
||||||
|
|
||||||
{
|
{
|
||||||
LOG_FILE="/tmp/backend.log"
|
LOG_FILE="/tmp/backend.log"
|
||||||
|
|||||||
90
.github/workflows/release.yml
vendored
90
.github/workflows/release.yml
vendored
@@ -5,46 +5,42 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- "v*.*.*"
|
- "v*.*.*"
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
packages: write
|
|
||||||
attestations: write
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: depot-ubuntu-24.04-16
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
env:
|
contents: write
|
||||||
CONTAINER_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/pocket-id
|
packages: write
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
- name: Set up Depot CLI
|
|
||||||
uses: depot/setup-action@v1
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: "pnpm"
|
|
||||||
|
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: "backend/go.mod"
|
go-version-file: "backend/go.mod"
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Set DOCKER_IMAGE_NAME
|
||||||
|
run: |
|
||||||
|
# Lowercase REPO_OWNER which is required for containers
|
||||||
|
REPO_OWNER=${{ github.repository_owner }}
|
||||||
|
DOCKER_IMAGE_NAME="ghcr.io/${REPO_OWNER,,}/pocket-id"
|
||||||
|
echo "DOCKER_IMAGE_NAME=${DOCKER_IMAGE_NAME}" >>${GITHUB_ENV}
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{github.repository_owner}}
|
username: ${{github.repository_owner}}
|
||||||
password: ${{secrets.GITHUB_TOKEN}}
|
password: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
|
||||||
- name: Docker metadata
|
- name: Docker metadata
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
@@ -55,89 +51,59 @@ jobs:
|
|||||||
type=semver,pattern={{version}},prefix=v
|
type=semver,pattern={{version}},prefix=v
|
||||||
type=semver,pattern={{major}}.{{minor}},prefix=v
|
type=semver,pattern={{major}}.{{minor}},prefix=v
|
||||||
type=semver,pattern={{major}},prefix=v
|
type=semver,pattern={{major}},prefix=v
|
||||||
labels: |
|
|
||||||
org.opencontainers.image.authors=Pocket ID
|
|
||||||
org.opencontainers.image.url=https://github.com/pocket-id/pocket-id
|
|
||||||
org.opencontainers.image.documentation=https://github.com/pocket-id/pocket-id/blob/main/README.md
|
|
||||||
org.opencontainers.image.source=https://github.com/pocket-id/pocket-id
|
|
||||||
org.opencontainers.image.version=next
|
|
||||||
org.opencontainers.image.licenses=BSD-2-Clause
|
|
||||||
org.opencontainers.image.ref.name=pocket-id
|
|
||||||
org.opencontainers.image.title=Pocket ID
|
|
||||||
|
|
||||||
- name: Docker metadata (distroless)
|
- name: Docker metadata (distroless)
|
||||||
id: meta-distroless
|
id: meta-distroless
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
${{ env.CONTAINER_IMAGE_NAME }}
|
${{ env.DOCKER_IMAGE_NAME }}
|
||||||
flavor: |
|
flavor: |
|
||||||
suffix=-distroless,onlatest=true
|
suffix=-distroless,onlatest=true
|
||||||
tags: |
|
tags: |
|
||||||
type=semver,pattern={{version}},prefix=v
|
type=semver,pattern={{version}},prefix=v
|
||||||
type=semver,pattern={{major}}.{{minor}},prefix=v
|
type=semver,pattern={{major}}.{{minor}},prefix=v
|
||||||
type=semver,pattern={{major}},prefix=v
|
type=semver,pattern={{major}},prefix=v
|
||||||
labels: |
|
|
||||||
org.opencontainers.image.authors=Pocket ID
|
|
||||||
org.opencontainers.image.url=https://github.com/pocket-id/pocket-id
|
|
||||||
org.opencontainers.image.documentation=https://github.com/pocket-id/pocket-id/blob/main/README.md
|
|
||||||
org.opencontainers.image.source=https://github.com/pocket-id/pocket-id
|
|
||||||
org.opencontainers.image.version=next-distroless
|
|
||||||
org.opencontainers.image.licenses=BSD-2-Clause
|
|
||||||
org.opencontainers.image.ref.name=pocket-id
|
|
||||||
org.opencontainers.image.title=Pocket ID
|
|
||||||
|
|
||||||
- name: Install frontend dependencies
|
- name: Install frontend dependencies
|
||||||
run: pnpm --filter pocket-id-frontend install --frozen-lockfile
|
run: pnpm --filter pocket-id-frontend install --frozen-lockfile
|
||||||
|
|
||||||
- name: Build frontend
|
- name: Build frontend
|
||||||
run: pnpm --filter pocket-id-frontend build
|
run: pnpm --filter pocket-id-frontend build
|
||||||
|
|
||||||
- name: Build binaries
|
- name: Build binaries
|
||||||
run: sh scripts/development/build-binaries.sh
|
run: sh scripts/development/build-binaries.sh
|
||||||
|
|
||||||
- name: Build and push container image
|
- name: Build and push container image
|
||||||
uses: depot/build-push-action@v1
|
uses: docker/build-push-action@v6
|
||||||
id: container-build-push
|
id: container-build-push
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/Dockerfile-prebuilt
|
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
sbom: true
|
file: docker/Dockerfile-prebuilt
|
||||||
provenance: true
|
|
||||||
|
|
||||||
- name: Build and push container image (distroless)
|
- name: Build and push container image (distroless)
|
||||||
uses: depot/build-push-action@v1
|
uses: docker/build-push-action@v6
|
||||||
id: container-build-push-distroless
|
id: container-build-push-distroless
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/Dockerfile-distroless
|
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta-distroless.outputs.tags }}
|
tags: ${{ steps.meta-distroless.outputs.tags }}
|
||||||
labels: ${{ steps.meta-distroless.outputs.labels }}
|
labels: ${{ steps.meta-distroless.outputs.labels }}
|
||||||
sbom: true
|
file: docker/Dockerfile-distroless
|
||||||
provenance: true
|
|
||||||
|
|
||||||
- name: Binary attestation
|
- name: Binary attestation
|
||||||
uses: actions/attest-build-provenance@v2
|
uses: actions/attest-build-provenance@v2
|
||||||
with:
|
with:
|
||||||
subject-path: "backend/.bin/pocket-id-**"
|
subject-path: "backend/.bin/pocket-id-**"
|
||||||
|
|
||||||
- name: Container image attestation
|
- name: Container image attestation
|
||||||
uses: actions/attest-build-provenance@v2
|
uses: actions/attest-build-provenance@v2
|
||||||
with:
|
with:
|
||||||
subject-name: "${{ env.CONTAINER_IMAGE_NAME }}"
|
subject-name: "${{ env.DOCKER_IMAGE_NAME }}"
|
||||||
subject-digest: ${{ steps.container-build-push.outputs.digest }}
|
subject-digest: ${{ steps.container-build-push.outputs.digest }}
|
||||||
push-to-registry: true
|
push-to-registry: true
|
||||||
|
|
||||||
- name: Container image attestation (distroless)
|
- name: Container image attestation (distroless)
|
||||||
uses: actions/attest-build-provenance@v2
|
uses: actions/attest-build-provenance@v2
|
||||||
with:
|
with:
|
||||||
subject-name: "${{ env.CONTAINER_IMAGE_NAME }}"
|
subject-name: "${{ env.DOCKER_IMAGE_NAME }}"
|
||||||
subject-digest: ${{ steps.container-build-push-distroless.outputs.digest }}
|
subject-digest: ${{ steps.container-build-push-distroless.outputs.digest }}
|
||||||
push-to-registry: true
|
push-to-registry: true
|
||||||
- name: Upload binaries to release
|
- name: Upload binaries to release
|
||||||
@@ -146,12 +112,14 @@ jobs:
|
|||||||
run: gh release upload ${{ github.ref_name }} backend/.bin/*
|
run: gh release upload ${{ github.ref_name }} backend/.bin/*
|
||||||
|
|
||||||
publish-release:
|
publish-release:
|
||||||
runs-on: depot-ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [build]
|
needs: [build]
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v5
|
||||||
- name: Mark release as published
|
- name: Mark release as published
|
||||||
run: gh release edit ${{ github.ref_name }} --draft=false
|
run: gh release edit ${{ github.ref_name }} --draft=false
|
||||||
|
|||||||
17
.github/workflows/svelte-check.yml
vendored
17
.github/workflows/svelte-check.yml
vendored
@@ -21,31 +21,28 @@ on:
|
|||||||
- "frontend/svelte.config.js"
|
- "frontend/svelte.config.js"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
checks: write
|
|
||||||
pull-requests: write
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
type-check:
|
type-check:
|
||||||
name: Run Svelte Check
|
name: Run Svelte Check
|
||||||
# Don't run on dependabot branches
|
# Don't run on dependabot branches
|
||||||
if: github.actor != 'dependabot[bot]'
|
if: github.actor != 'dependabot[bot]'
|
||||||
runs-on: depot-ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
checks: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: "pnpm"
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm --filter pocket-id-frontend install --frozen-lockfile
|
run: pnpm --filter pocket-id-frontend install --frozen-lockfile
|
||||||
|
|||||||
12
.github/workflows/unit-tests.yml
vendored
12
.github/workflows/unit-tests.yml
vendored
@@ -9,16 +9,14 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "backend/**"
|
- "backend/**"
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
id-token: write
|
|
||||||
actions: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test-backend:
|
test-backend:
|
||||||
runs-on: depot-ubuntu-latest
|
permissions:
|
||||||
|
contents: read
|
||||||
|
actions: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: "backend/go.mod"
|
go-version-file: "backend/go.mod"
|
||||||
|
|||||||
5
.github/workflows/update-aaguids.yml
vendored
5
.github/workflows/update-aaguids.yml
vendored
@@ -8,15 +8,14 @@ on:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
id-token: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-aaguids:
|
update-aaguids:
|
||||||
runs-on: depot-ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Fetch JSON data
|
- name: Fetch JSON data
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ func (s *s3Storage) List(ctx context.Context, path string) ([]ObjectInfo, error)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
objects = append(objects, ObjectInfo{
|
objects = append(objects, ObjectInfo{
|
||||||
Path: aws.ToString(obj.Key),
|
Path: s.pathFromKey(aws.ToString(obj.Key)),
|
||||||
Size: aws.ToInt64(obj.Size),
|
Size: aws.ToInt64(obj.Size),
|
||||||
ModTime: aws.ToTime(obj.LastModified),
|
ModTime: aws.ToTime(obj.LastModified),
|
||||||
})
|
})
|
||||||
@@ -147,6 +147,13 @@ func (s *s3Storage) List(ctx context.Context, path string) ([]ObjectInfo, error)
|
|||||||
return objects, nil
|
return objects, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *s3Storage) pathFromKey(key string) string {
|
||||||
|
if s.prefix == "" {
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
return strings.TrimPrefix(key, s.prefix+"/")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *s3Storage) Walk(ctx context.Context, root string, fn func(ObjectInfo) error) error {
|
func (s *s3Storage) Walk(ctx context.Context, root string, fn func(ObjectInfo) error) error {
|
||||||
objects, err := s.List(ctx, root)
|
objects, err := s.List(ctx, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -35,6 +35,50 @@ func TestS3Helpers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("pathFromKey strips prefix to honor relative-path contract", func(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
prefix string
|
||||||
|
key string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{name: "no prefix returns key unchanged", prefix: "", key: "images/logo.png", expected: "images/logo.png"},
|
||||||
|
{name: "no prefix empty key", prefix: "", key: "", expected: ""},
|
||||||
|
{name: "prefix matches and is stripped", prefix: "data/uploads", key: "data/uploads/application-images/logo.svg", expected: "application-images/logo.svg"},
|
||||||
|
{name: "single-segment prefix stripped", prefix: "root", key: "root/foo/bar.txt", expected: "foo/bar.txt"},
|
||||||
|
{name: "prefix equal to key without trailing slash is unchanged", prefix: "root", key: "root", expected: "root"},
|
||||||
|
{name: "key without expected prefix returned unchanged", prefix: "data/uploads", key: "other/path.txt", expected: "other/path.txt"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
s := &s3Storage{
|
||||||
|
bucket: "bucket",
|
||||||
|
prefix: tc.prefix,
|
||||||
|
}
|
||||||
|
assert.Equal(t, tc.expected, s.pathFromKey(tc.key))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("pathFromKey is the inverse of buildObjectKey for clean paths", func(t *testing.T) {
|
||||||
|
paths := []string{
|
||||||
|
"images/logo.png",
|
||||||
|
"application-images/logo.svg",
|
||||||
|
"oidc-client-images/abc.png",
|
||||||
|
"deeply/nested/file.bin",
|
||||||
|
}
|
||||||
|
prefixes := []string{"", "root", "data/uploads"}
|
||||||
|
|
||||||
|
for _, prefix := range prefixes {
|
||||||
|
for _, p := range paths {
|
||||||
|
s := &s3Storage{bucket: "bucket", prefix: prefix}
|
||||||
|
assert.Equal(t, p, s.pathFromKey(s.buildObjectKey(p)),
|
||||||
|
"round-trip failed for prefix=%q path=%q", prefix, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("isS3NotFound detects expected errors", func(t *testing.T) {
|
t.Run("isS3NotFound detects expected errors", func(t *testing.T) {
|
||||||
assert.True(t, isS3NotFound(&smithy.GenericAPIError{Code: "NoSuchKey"}))
|
assert.True(t, isS3NotFound(&smithy.GenericAPIError{Code: "NoSuchKey"}))
|
||||||
assert.True(t, isS3NotFound(&smithy.GenericAPIError{Code: "NotFound"}))
|
assert.True(t, isS3NotFound(&smithy.GenericAPIError{Code: "NotFound"}))
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{ "id": "c36t29j6bz" }
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
# syntax=docker/dockerfile:1.7
|
|
||||||
|
|
||||||
# This file uses multi-stage builds to build the application from source, including the front-end
|
# This file uses multi-stage builds to build the application from source, including the front-end
|
||||||
|
|
||||||
# Tags passed to "go build"
|
# Tags passed to "go build"
|
||||||
@@ -11,33 +9,27 @@ RUN corepack enable
|
|||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
|
COPY pnpm-workspace.yaml pnpm-lock.yaml ./
|
||||||
COPY frontend/package.json ./frontend/
|
COPY frontend/package.json ./frontend/
|
||||||
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
|
RUN pnpm --filter pocket-id-frontend install --frozen-lockfile
|
||||||
pnpm --filter pocket-id-frontend install --frozen-lockfile
|
|
||||||
|
|
||||||
COPY ./frontend ./frontend/
|
COPY ./frontend ./frontend/
|
||||||
|
|
||||||
RUN --mount=type=cache,target=/build/frontend/node_modules/.vite \
|
RUN BUILD_OUTPUT_PATH=dist pnpm --filter pocket-id-frontend run build
|
||||||
--mount=type=cache,target=/build/frontend/.svelte-kit \
|
|
||||||
BUILD_OUTPUT_PATH=dist pnpm --filter pocket-id-frontend run build
|
|
||||||
|
|
||||||
# Stage 2: Build Backend
|
# Stage 2: Build Backend
|
||||||
FROM golang:1.26-alpine AS backend-builder
|
FROM golang:1.26-alpine AS backend-builder
|
||||||
ARG BUILD_TAGS
|
ARG BUILD_TAGS
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
COPY ./backend/go.mod ./backend/go.sum ./
|
COPY ./backend/go.mod ./backend/go.sum ./
|
||||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
RUN go mod download
|
||||||
go mod download
|
|
||||||
|
|
||||||
COPY ./backend ./
|
COPY ./backend ./
|
||||||
COPY --from=frontend-builder /build/frontend/dist ./frontend/dist
|
COPY --from=frontend-builder /build/frontend/dist ./frontend/dist
|
||||||
COPY .version .version
|
COPY .version .version
|
||||||
|
|
||||||
WORKDIR /build/cmd
|
WORKDIR /build/cmd
|
||||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
RUN VERSION=$(cat /build/.version) \
|
||||||
--mount=type=cache,target=/root/.cache/go-build \
|
|
||||||
VERSION=$(cat /build/.version) && \
|
|
||||||
CGO_ENABLED=0 \
|
CGO_ENABLED=0 \
|
||||||
GOOS=linux \
|
GOOS=linux \
|
||||||
go build \
|
go build \
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@simplewebauthn/browser": "^13.2.2",
|
"@simplewebauthn/browser": "^13.2.2",
|
||||||
"@tailwindcss/vite": "^4.2.0",
|
"@tailwindcss/vite": "^4.2.0",
|
||||||
"axios": "^1.13.5",
|
"axios": "^1.15.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"jose": "^6.1.3",
|
"jose": "^6.1.3",
|
||||||
|
|||||||
@@ -9,21 +9,21 @@ services:
|
|||||||
service: scim-test-server
|
service: scim-test-server
|
||||||
localstack-s3:
|
localstack-s3:
|
||||||
image: localstack/localstack:s3-latest
|
image: localstack/localstack:s3-latest
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localstack-s3:4566"]
|
||||||
|
interval: 1s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 10
|
||||||
|
create-bucket:
|
||||||
|
image: amazon/aws-cli:latest
|
||||||
environment:
|
environment:
|
||||||
AWS_ACCESS_KEY_ID: test
|
AWS_ACCESS_KEY_ID: test
|
||||||
AWS_SECRET_ACCESS_KEY: test
|
AWS_SECRET_ACCESS_KEY: test
|
||||||
AWS_DEFAULT_REGION: us-east-1
|
AWS_DEFAULT_REGION: us-east-1
|
||||||
volumes:
|
depends_on:
|
||||||
- ./localstack-init-s3.py:/etc/localstack/init/ready.d/10-init-s3.py
|
localstack-s3:
|
||||||
healthcheck:
|
condition: service_healthy
|
||||||
test:
|
entrypoint: "aws --endpoint-url=http://localstack-s3:4566 s3 mb s3://pocket-id-test"
|
||||||
[
|
|
||||||
"CMD-SHELL",
|
|
||||||
'curl -fs http://localstack-s3:4566/_localstack/init/ready | grep -q ''"completed": true''',
|
|
||||||
]
|
|
||||||
interval: 1s
|
|
||||||
timeout: 3s
|
|
||||||
retries: 10
|
|
||||||
pocket-id:
|
pocket-id:
|
||||||
extends:
|
extends:
|
||||||
file: docker-compose.yml
|
file: docker-compose.yml
|
||||||
@@ -37,8 +37,8 @@ services:
|
|||||||
S3_SECRET_ACCESS_KEY: test
|
S3_SECRET_ACCESS_KEY: test
|
||||||
S3_FORCE_PATH_STYLE: true
|
S3_FORCE_PATH_STYLE: true
|
||||||
depends_on:
|
depends_on:
|
||||||
localstack-s3:
|
create-bucket:
|
||||||
condition: service_healthy
|
condition: service_completed_successfully
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pocket-id-test-data:
|
pocket-id-test-data:
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
import boto3
|
|
||||||
from botocore.exceptions import ClientError
|
|
||||||
|
|
||||||
BUCKET_NAME = "pocket-id-test"
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
s3 = boto3.client(
|
|
||||||
"s3",
|
|
||||||
endpoint_url="http://localhost:4566",
|
|
||||||
aws_access_key_id="test",
|
|
||||||
aws_secret_access_key="test",
|
|
||||||
region_name="us-east-1",
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
s3.head_bucket(Bucket=BUCKET_NAME)
|
|
||||||
except ClientError:
|
|
||||||
s3.create_bucket(Bucket=BUCKET_NAME)
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
||||||
Reference in New Issue
Block a user