mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-03-28 18:26:36 +00:00
Compare commits
3 Commits
chore/depo
...
callback-u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76da41f126 | ||
|
|
a06d9d21e4 | ||
|
|
cbecbd088f |
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: |
|
||||||
|
|||||||
31
CHANGELOG.md
31
CHANGELOG.md
@@ -1,3 +1,34 @@
|
|||||||
|
## v2.5.0
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- better error messages when there's another instance of Pocket ID running ([#1370](https://github.com/pocket-id/pocket-id/pull/1370) by @ItalyPaleAle)
|
||||||
|
- move tooltip inside of form input to prevent shifting ([#1369](https://github.com/pocket-id/pocket-id/pull/1369) by @GameTec-live)
|
||||||
|
- derive LDAP admin access from group membership ([#1374](https://github.com/pocket-id/pocket-id/pull/1374) by @kmendell)
|
||||||
|
- avoid fmt.Sprintf on custom GeoLiteDBUrl without %s placeholder ([#1384](https://github.com/pocket-id/pocket-id/pull/1384) by @choyri)
|
||||||
|
- show a warning when SQLite DB is stored on NFS/SMB/FUSE ([#1381](https://github.com/pocket-id/pocket-id/pull/1381) by @ItalyPaleAle)
|
||||||
|
- empty background restore after reboot ([#1379](https://github.com/pocket-id/pocket-id/pull/1379) by @taoso)
|
||||||
|
- allow one-char username on signup ([#1378](https://github.com/pocket-id/pocket-id/pull/1378) by @taoso)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- allow use of svg, png, and ico images types for favicon ([#1289](https://github.com/pocket-id/pocket-id/pull/1289) by @taoso)
|
||||||
|
- allow clearing background image ([#1290](https://github.com/pocket-id/pocket-id/pull/1290) by @taoso)
|
||||||
|
- add `token_endpoint_auth_methods_supported` to `.well-known` ([#1388](https://github.com/pocket-id/pocket-id/pull/1388) by @owenvoke)
|
||||||
|
- add TRUSTED_PLATFORM environment variable for gin ([#1372](https://github.com/pocket-id/pocket-id/pull/1372) by @choyri)
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
- add pr quality action ([e3905cf](https://github.com/pocket-id/pocket-id/commit/e3905cf3159fe0370778b0d7d3be64b4246d19be) by @stonith404)
|
||||||
|
- separate querying LDAP and updating DB during sync ([#1371](https://github.com/pocket-id/pocket-id/pull/1371) by @ItalyPaleAle)
|
||||||
|
- bump google.golang.org/grpc from 1.79.1 to 1.79.3 in /backend in the go_modules group across 1 directory ([#1391](https://github.com/pocket-id/pocket-id/pull/1391) by @dependabot[bot])
|
||||||
|
- Improve Latvian translations in lv.json ([#1382](https://github.com/pocket-id/pocket-id/pull/1382) by @Raito00)
|
||||||
|
- ignore linter on app image bootstrap ([5251cd9](https://github.com/pocket-id/pocket-id/commit/5251cd97994177c96cb6f9ab3f88ca31367b5b55) by @kmendell)
|
||||||
|
- upgrade dependencies ([e7e0176](https://github.com/pocket-id/pocket-id/commit/e7e0176316857186b9683e2f0cb0686189f86cfb) by @kmendell)
|
||||||
|
- upgrade dependencies ([3c42a71](https://github.com/pocket-id/pocket-id/commit/3c42a713ce91b4061ffcf86d92cbb19294359ff8) by @kmendell)
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/pocket-id/pocket-id/compare/v2.4.0...v2.5.0
|
||||||
|
|
||||||
## v2.4.0
|
## v2.4.0
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -89,12 +89,19 @@ type OidcController struct {
|
|||||||
// @Router /api/oidc/authorize [post]
|
// @Router /api/oidc/authorize [post]
|
||||||
func (oc *OidcController) authorizeHandler(c *gin.Context) {
|
func (oc *OidcController) authorizeHandler(c *gin.Context) {
|
||||||
var input dto.AuthorizeOidcClientRequestDto
|
var input dto.AuthorizeOidcClientRequestDto
|
||||||
if err := c.ShouldBindJSON(&input); err != nil {
|
err := c.ShouldBindJSON(&input)
|
||||||
|
if err != nil {
|
||||||
_ = c.Error(err)
|
_ = c.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
code, callbackURL, err := oc.oidcService.Authorize(c.Request.Context(), input, c.GetString("userID"), c.ClientIP(), c.Request.UserAgent())
|
code, callbackURL, err := oc.oidcService.Authorize(
|
||||||
|
c.Request.Context(),
|
||||||
|
input,
|
||||||
|
c.GetString("userID"),
|
||||||
|
c.ClientIP(),
|
||||||
|
c.Request.UserAgent(),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.Error(err)
|
_ = c.Error(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ type OidcClientWithAllowedGroupsCountDto struct {
|
|||||||
|
|
||||||
type OidcClientUpdateDto struct {
|
type OidcClientUpdateDto struct {
|
||||||
Name string `json:"name" binding:"required,max=50" unorm:"nfc"`
|
Name string `json:"name" binding:"required,max=50" unorm:"nfc"`
|
||||||
CallbackURLs []string `json:"callbackURLs" binding:"omitempty,dive,callback_url"`
|
CallbackURLs []string `json:"callbackURLs" binding:"omitempty,dive,callback_url_pattern"`
|
||||||
LogoutCallbackURLs []string `json:"logoutCallbackURLs" binding:"omitempty,dive,callback_url"`
|
LogoutCallbackURLs []string `json:"logoutCallbackURLs" binding:"omitempty,dive,callback_url_pattern"`
|
||||||
IsPublic bool `json:"isPublic"`
|
IsPublic bool `json:"isPublic"`
|
||||||
PkceEnabled bool `json:"pkceEnabled"`
|
PkceEnabled bool `json:"pkceEnabled"`
|
||||||
RequiresReauthentication bool `json:"requiresReauthentication"`
|
RequiresReauthentication bool `json:"requiresReauthentication"`
|
||||||
@@ -66,7 +66,7 @@ type OidcClientFederatedIdentityDto struct {
|
|||||||
type AuthorizeOidcClientRequestDto struct {
|
type AuthorizeOidcClientRequestDto struct {
|
||||||
ClientID string `json:"clientID" binding:"required"`
|
ClientID string `json:"clientID" binding:"required"`
|
||||||
Scope string `json:"scope" binding:"required"`
|
Scope string `json:"scope" binding:"required"`
|
||||||
CallbackURL string `json:"callbackURL"`
|
CallbackURL string `json:"callbackURL" binding:"omitempty,callback_url"`
|
||||||
Nonce string `json:"nonce"`
|
Nonce string `json:"nonce"`
|
||||||
CodeChallenge string `json:"codeChallenge"`
|
CodeChallenge string `json:"codeChallenge"`
|
||||||
CodeChallengeMethod string `json:"codeChallengeMethod"`
|
CodeChallengeMethod string `json:"codeChallengeMethod"`
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
||||||
@@ -19,38 +21,38 @@ var validateUsernameRegex = regexp.MustCompile("^[a-zA-Z0-9]([a-zA-Z0-9_.@-]*[a-
|
|||||||
var validateClientIDRegex = regexp.MustCompile("^[a-zA-Z0-9._-]+$")
|
var validateClientIDRegex = regexp.MustCompile("^[a-zA-Z0-9._-]+$")
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
v := binding.Validator.Engine().(*validator.Validate)
|
engine := binding.Validator.Engine().(*validator.Validate)
|
||||||
|
|
||||||
// Maximum allowed value for TTLs
|
// Maximum allowed value for TTLs
|
||||||
const maxTTL = 31 * 24 * time.Hour
|
const maxTTL = 31 * 24 * time.Hour
|
||||||
|
|
||||||
if err := v.RegisterValidation("username", func(fl validator.FieldLevel) bool {
|
validators := map[string]validator.Func{
|
||||||
return ValidateUsername(fl.Field().String())
|
"username": func(fl validator.FieldLevel) bool {
|
||||||
}); err != nil {
|
return ValidateUsername(fl.Field().String())
|
||||||
panic("Failed to register custom validation for username: " + err.Error())
|
},
|
||||||
|
"client_id": func(fl validator.FieldLevel) bool {
|
||||||
|
return ValidateClientID(fl.Field().String())
|
||||||
|
},
|
||||||
|
"ttl": func(fl validator.FieldLevel) bool {
|
||||||
|
ttl, ok := fl.Field().Interface().(utils.JSONDuration)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Allow zero, which means the field wasn't set
|
||||||
|
return ttl.Duration == 0 || (ttl.Duration > time.Second && ttl.Duration <= maxTTL)
|
||||||
|
},
|
||||||
|
"callback_url": func(fl validator.FieldLevel) bool {
|
||||||
|
return ValidateCallbackURL(fl.Field().String())
|
||||||
|
},
|
||||||
|
"callback_url_pattern": func(fl validator.FieldLevel) bool {
|
||||||
|
return ValidateCallbackURLPattern(fl.Field().String())
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
for k, v := range validators {
|
||||||
if err := v.RegisterValidation("client_id", func(fl validator.FieldLevel) bool {
|
err := engine.RegisterValidation(k, v)
|
||||||
return ValidateClientID(fl.Field().String())
|
if err != nil {
|
||||||
}); err != nil {
|
panic("Failed to register custom validation for " + k + ": " + err.Error())
|
||||||
panic("Failed to register custom validation for client_id: " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := v.RegisterValidation("ttl", func(fl validator.FieldLevel) bool {
|
|
||||||
ttl, ok := fl.Field().Interface().(utils.JSONDuration)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
// Allow zero, which means the field wasn't set
|
|
||||||
return ttl.Duration == 0 || (ttl.Duration > time.Second && ttl.Duration <= maxTTL)
|
|
||||||
}); err != nil {
|
|
||||||
panic("Failed to register custom validation for ttl: " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := v.RegisterValidation("callback_url", func(fl validator.FieldLevel) bool {
|
|
||||||
return ValidateCallbackURL(fl.Field().String())
|
|
||||||
}); err != nil {
|
|
||||||
panic("Failed to register custom validation for callback_url: " + err.Error())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,8 +66,24 @@ func ValidateClientID(clientID string) bool {
|
|||||||
return validateClientIDRegex.MatchString(clientID)
|
return validateClientIDRegex.MatchString(clientID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateCallbackURL validates callback URLs with support for wildcards
|
// ValidateCallbackURL validates the input callback URL
|
||||||
func ValidateCallbackURL(raw string) bool {
|
func ValidateCallbackURL(str string) bool {
|
||||||
|
// Ensure the URL is a valid one and that the protocol is not "javascript:" or "data:"
|
||||||
|
u, err := url.Parse(str)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch strings.ToLower(u.Scheme) {
|
||||||
|
case "javascript", "data":
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateCallbackURLPattern validates callback URL patterns, with support for wildcards
|
||||||
|
func ValidateCallbackURLPattern(raw string) bool {
|
||||||
err := utils.ValidateCallbackURLPattern(raw)
|
err := utils.ValidateCallbackURLPattern(raw)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,3 +57,28 @@ func TestValidateClientID(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateCallbackURL(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{"valid https URL", "https://example.com/callback", true},
|
||||||
|
{"valid loopback URL", "http://127.0.0.1:49813/callback", true},
|
||||||
|
{"empty scheme", "//127.0.0.1:49813/callback", true},
|
||||||
|
{"valid custom scheme", "pocketid://callback", true},
|
||||||
|
{"invalid malformed URL", "http://[::1", false},
|
||||||
|
{"invalid missing scheme separator", "://example.com/callback", false},
|
||||||
|
{"rejects javascript scheme", "javascript:alert(1)", false},
|
||||||
|
{"rejects mixed case javascript scheme", "JavaScript:alert(1)", false},
|
||||||
|
{"rejects data scheme", "data:text/html;base64,PGgxPkhlbGxvPC9oMT4=", false},
|
||||||
|
{"rejects mixed case data scheme", "DaTa:text/html;base64,PGgxPkhlbGxvPC9oMT4=", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tt.expected, ValidateCallbackURL(tt.input))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -125,9 +125,7 @@ func (s *OidcService) getJWKCache(ctx context.Context) (*jwk.Cache, error) {
|
|||||||
|
|
||||||
func (s *OidcService) Authorize(ctx context.Context, input dto.AuthorizeOidcClientRequestDto, userID, ipAddress, userAgent string) (string, string, error) {
|
func (s *OidcService) Authorize(ctx context.Context, input dto.AuthorizeOidcClientRequestDto, userID, ipAddress, userAgent string) (string, string, error) {
|
||||||
tx := s.db.Begin()
|
tx := s.db.Begin()
|
||||||
defer func() {
|
defer tx.Rollback()
|
||||||
tx.Rollback()
|
|
||||||
}()
|
|
||||||
|
|
||||||
var client model.OidcClient
|
var client model.OidcClient
|
||||||
err := tx.
|
err := tx.
|
||||||
|
|||||||
@@ -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 \
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pocket-id-frontend",
|
"name": "pocket-id-frontend",
|
||||||
"version": "2.4.0",
|
"version": "2.5.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -71,19 +71,16 @@
|
|||||||
reauthToken = await webauthnService.reauthenticate(authResponse);
|
reauthToken = await webauthnService.reauthenticate(authResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
await oidService
|
const authResult = await oidService.authorize(
|
||||||
.authorize(
|
client!.id,
|
||||||
client!.id,
|
scope,
|
||||||
scope,
|
callbackURL,
|
||||||
callbackURL,
|
nonce,
|
||||||
nonce,
|
codeChallenge,
|
||||||
codeChallenge,
|
codeChallengeMethod,
|
||||||
codeChallengeMethod,
|
reauthToken
|
||||||
reauthToken
|
);
|
||||||
)
|
onSuccess(authResult.code, authResult.callbackURL, authResult.issuer);
|
||||||
.then(async ({ code, callbackURL, issuer }) => {
|
|
||||||
onSuccess(code, callbackURL, issuer);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
errorMessage = getWebauthnErrorMessage(e);
|
errorMessage = getWebauthnErrorMessage(e);
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
@@ -91,13 +88,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onSuccess(code: string, callbackURL: string, issuer: string) {
|
function onSuccess(code: string, callbackURL: string, issuer: string) {
|
||||||
|
const redirectURL = new URL(callbackURL);
|
||||||
|
if (redirectURL.protocol == 'javascript:' || redirectURL.protocol == 'data:') {
|
||||||
|
throw new Error('Invalid redirect URL protocol');
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectURL.searchParams.append('code', code);
|
||||||
|
redirectURL.searchParams.append('state', authorizeState);
|
||||||
|
redirectURL.searchParams.append('iss', issuer);
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const redirectURL = new URL(callbackURL);
|
|
||||||
redirectURL.searchParams.append('code', code);
|
|
||||||
redirectURL.searchParams.append('state', authorizeState);
|
|
||||||
redirectURL.searchParams.append('iss', issuer);
|
|
||||||
|
|
||||||
window.location.href = redirectURL.toString();
|
window.location.href = redirectURL.toString();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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