mirror of
https://github.com/sredevopsorg/deepseek-kubernetes-sandbox.git
synced 2026-11-03 01:13:24 +00:00
- Replace user:token cookies with opaque server-side sessions, revocable on logout, delete, recreate and expiry; bind every credential to the path user and add cross-user regression tests. - Rate-limit /users and /login, add optional signup invite codes and form same-origin checks, and unify login failures to 401. - Require explicit ALLOW_INSECURE_COOKIES for plain HTTP, use __Host-dsh_gw_session when secure, and fix secure cookie deletion. - Strip client-supplied forwarding/SSO headers, add an optional upstream allowlist, per-user in-flight and WebSocket message caps, credential-free handshake errors, and sweep-time state pruning. - Digest-pin base images, hash-pin gateway dependencies, verify DSH_COMMIT in the build, and run the gateway image as non-root with a pinned Python base. - Update manifests, production checklist, architecture/security docs and add an SSO preflight script. BREAKING CHANGE: existing dsh_gw_session=<user>:<token> cookies are invalid; users must sign in again. Unknown users on POST /login now return 401 instead of 404, and the gateway refuses COOKIE_SECURE=false unless ALLOW_INSECURE_COOKIES=1.
129 lines
4.8 KiB
YAML
129 lines
4.8 KiB
YAML
# Build-only check for the main DSH Web image: linux/amd64, no registry login,
|
|
# no push. It proves the Dockerfile still builds from the pinned versions.env and
|
|
# that the resulting image can actually run DSH Web. The published multi-arch
|
|
# build stays in build-main.yaml (merge to main) and release.yaml (tags).
|
|
#
|
|
# Like ci-python.yaml and ci-manifests.yaml this is path-filtered, so it is an
|
|
# on-demand check rather than a required status check.
|
|
name: CI image
|
|
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- Dockerfile
|
|
- .dockerignore
|
|
- versions.env
|
|
- .github/workflows/ci-image.yaml
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: ci-image-${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
build-amd64:
|
|
name: build-amd64
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 120
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Read versions.env
|
|
id: meta
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
set -a
|
|
# shellcheck disable=SC1091
|
|
source versions.env
|
|
set +a
|
|
identity="$DSH_VERSION"
|
|
[ -z "${RELEASE_REVISION:-}" ] || identity="$DSH_VERSION-$RELEASE_REVISION"
|
|
{
|
|
echo "identity=$identity"
|
|
echo "dsh_version=$DSH_VERSION"
|
|
echo "dsh_commit=$DSH_COMMIT"
|
|
echo "pnpm_version=$PNPM_VERSION"
|
|
echo "release_revision=${RELEASE_REVISION:-}"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
|
|
|
- name: Build linux/amd64 (load locally, never push)
|
|
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
|
|
with:
|
|
context: .
|
|
file: Dockerfile
|
|
platforms: linux/amd64
|
|
push: false
|
|
load: true
|
|
tags: dsh-web:ci
|
|
build-args: |
|
|
DSH_VERSION=${{ steps.meta.outputs.dsh_version }}
|
|
DSH_COMMIT=${{ steps.meta.outputs.dsh_commit }}
|
|
RELEASE_REVISION=${{ steps.meta.outputs.release_revision }}
|
|
PNPM_VERSION=${{ steps.meta.outputs.pnpm_version }}
|
|
VCS_REF=${{ github.sha }}
|
|
labels: |
|
|
org.opencontainers.image.source=https://github.com/${{ github.repository }}
|
|
org.opencontainers.image.version=${{ steps.meta.outputs.identity }}
|
|
org.opencontainers.image.revision=${{ github.sha }}
|
|
cache-from: type=gha,scope=ci-image-linux-amd64
|
|
cache-to: type=gha,mode=max,scope=ci-image-linux-amd64
|
|
|
|
- name: Smoke test the image
|
|
env:
|
|
IDENTITY: ${{ steps.meta.outputs.identity }}
|
|
DSH_VERSION: ${{ steps.meta.outputs.dsh_version }}
|
|
run: |
|
|
set -euo pipefail
|
|
image=dsh-web:ci
|
|
|
|
# The packaged CLI runs and reports the version pinned in versions.env.
|
|
version="$(docker run --rm --entrypoint node "$image" /app/lib/bin.js --version)"
|
|
printf 'DSH CLI: %s\n' "$version"
|
|
grep -q "${DSH_VERSION#dsh-v}" <<<"$version"
|
|
|
|
# The container runs as the non-root node user and its writable
|
|
# directories exist and are owned by that user.
|
|
[ "$(docker run --rm --entrypoint id "$image" -u)" = "1000" ]
|
|
docker run --rm --entrypoint sh "$image" -c \
|
|
'test -d /workspace && test -d "$DSH_HOME" && [ "$(stat -c %u /workspace)" = 1000 ]'
|
|
|
|
# The command-sandbox runner this image is expected to ship.
|
|
docker run --rm --entrypoint bwrap "$image" --version
|
|
|
|
# Labels come from the build args rather than a hard-coded value.
|
|
label="$(docker inspect -f '{{ index .Config.Labels "org.opencontainers.image.version" }}' "$image")"
|
|
printf 'image version label: %s\n' "$label"
|
|
[ "$label" = "$IDENTITY" ]
|
|
|
|
- name: Serve DSH Web
|
|
run: |
|
|
set -euo pipefail
|
|
docker run -d --name dsh-ci -p 18080:3080 \
|
|
-e DSH_TRUSTED_HOSTS=127.0.0.1:18080 dsh-web:ci >/dev/null
|
|
trap 'docker rm -f dsh-ci >/dev/null 2>&1 || true' EXIT
|
|
|
|
# /favicon.svg is unauthenticated and served by the web layer, which is
|
|
# why the shipped probes use it too.
|
|
for second in $(seq 1 60); do
|
|
if curl -fsS -o /dev/null http://127.0.0.1:18080/favicon.svg; then
|
|
printf 'DSH Web served /favicon.svg after ~%ss\n' "$((second * 2))"
|
|
exit 0
|
|
fi
|
|
sleep 2
|
|
done
|
|
|
|
echo "::error::DSH Web did not serve /favicon.svg within 120s"
|
|
# Pod logs can hold the DSH launch token: never dump them verbatim.
|
|
docker logs dsh-ci 2>&1 | grep -v 'token=' | tail -50 || true
|
|
exit 1
|