From 3406bc8e3aa2d176e7a79aea17fd347da2e0a553 Mon Sep 17 00:00:00 2001 From: Gordon Farquharson Date: Mon, 20 Jul 2026 10:35:37 +0100 Subject: [PATCH 1/2] Add edge-sso template and workflows, rebuilt off main Rebuilt the SSO delivery branch cleanly on top of main instead of the stale feature/saml-app branch: - edge-sso/ template (canonical version from feature/totp-app, which is a strict superset of feature/saml-app's edge-sso) - Split publish-sso-*.yml workflows (gate-only/cookie/header x auth/filter) - test-edge-sso.yml - Rename shared reusable _publish.yml -> _publish_rs.yml, add _publish_js.yml for TS auth-apps; harden-cookies/html2md updated to match - Updated read-template-registry action Excludes all edge-totp content so this can merge to main independently of feature/totp-app. --- .github/read-template-registry/action.yaml | 14 +- .github/workflows/_publish_js.yml | 93 + .../{_publish.yml => _publish_rs.yml} | 41 +- .github/workflows/publish-harden-cookies.yml | 5 +- .github/workflows/publish-html2md.yml | 5 +- .github/workflows/publish-sso-cookie-auth.yml | 24 + .../workflows/publish-sso-cookie-filter.yml | 24 + .../workflows/publish-sso-gate-only-auth.yml | 25 + .../publish-sso-gate-only-filter.yml | 24 + .github/workflows/publish-sso-header-auth.yml | 24 + .../workflows/publish-sso-header-filter.yml | 24 + .github/workflows/test-edge-sso.yml | 90 + edge-sso/.cargo/config.toml | 2 + edge-sso/.gitignore | 45 + edge-sso/AGENTS.md | 38 + edge-sso/CLAUDE.md | 69 + edge-sso/Cargo.lock | 889 +++ edge-sso/Cargo.toml | 18 + edge-sso/LICENSE | 201 + edge-sso/README.md | 74 + edge-sso/context/INDEX.md | 46 + edge-sso/context/architecture/auth-modes.md | 44 + edge-sso/context/architecture/overview.md | 125 + .../architecture/runtime-constraints.md | 144 + edge-sso/context/architecture/saml-flow.md | 143 + edge-sso/context/architecture/security.md | 128 + edge-sso/context/design/integration.md | 121 + edge-sso/context/development/testing.md | 79 + edge-sso/core/federation/app.tsx | 148 + edge-sso/core/federation/chooser.tsx | 237 + edge-sso/core/federation/config.ts | 108 + edge-sso/core/federation/error.tsx | 24 + edge-sso/core/federation/index.ts | 13 + edge-sso/core/federation/providers/common.ts | 117 + .../core/federation/providers/facebook.ts | 243 + edge-sso/core/federation/providers/github.ts | 268 + .../core/federation/providers/google-oidc.ts | 26 + edge-sso/core/federation/providers/google.ts | 235 + .../federation/providers/microsoft-oidc.ts | 69 + .../core/federation/providers/microsoft.ts | 251 + .../core/federation/providers/registry.ts | 92 + edge-sso/core/federation/saml/claims.ts | 102 + edge-sso/core/federation/saml/config.ts | 21 + edge-sso/core/federation/saml/handlers.ts | 138 + edge-sso/core/federation/saml/request.ts | 96 + edge-sso/core/federation/saml/response.ts | 330 ++ edge-sso/core/federation/util/redirect.ts | 48 + edge-sso/core/filter/Cargo.toml | 30 + edge-sso/core/filter/src/lib.rs | 401 ++ edge-sso/core/package.json | 34 + edge-sso/core/session/key.ts | 20 + edge-sso/core/session/token.ts | 172 + edge-sso/core/tsconfig.json | 9 + edge-sso/core/util/bytes.ts | 39 + edge-sso/core/util/env.ts | 16 + edge-sso/package.json | 11 + edge-sso/pnpm-lock.yaml | 4942 +++++++++++++++++ edge-sso/pnpm-workspace.yaml | 21 + edge-sso/scripts/gen-ec-keypair.mjs | 51 + .../templates/cookie/auth-app/.env.example | 171 + edge-sso/templates/cookie/auth-app/.env.test | 37 + .../templates/cookie/auth-app/package.json | 35 + .../templates/cookie/auth-app/registry.json | 330 ++ edge-sso/templates/cookie/auth-app/server.tsx | 7 + .../cookie/auth-app/tests/_cookies.ts | 11 + .../cookie/auth-app/tests/app.test.ts | 788 +++ .../auth-app/tests/e2e/facebook.test.ts | 289 + .../cookie/auth-app/tests/e2e/github.test.ts | 297 + .../cookie/auth-app/tests/e2e/google.test.ts | 336 ++ .../auth-app/tests/e2e/microsoft.test.ts | 314 ++ .../cookie/auth-app/tests/non-cookie-smoke.ts | 101 + .../cookie/auth-app/tests/tsconfig.json | 15 + .../tests/unit/default-claims.test.ts | 38 + .../auth-app/tests/unit/google-oidc.test.ts | 138 + .../tests/unit/microsoft-oidc.test.ts | 228 + .../auth-app/tests/unit/oauth-common.test.ts | 117 + .../tests/unit/providers-registry.test.ts | 94 + .../auth-app/tests/unit/redirect.test.ts | 83 + .../auth-app/tests/unit/saml-claims.test.ts | 120 + .../auth-app/tests/unit/saml-response.test.ts | 382 ++ .../auth-app/tests/unit/session-token.test.ts | 207 + .../templates/cookie/auth-app/tsconfig.json | 9 + .../templates/cookie/cdn-filter/.env.example | 61 + .../templates/cookie/cdn-filter/Cargo.toml | 12 + .../templates/cookie/cdn-filter/package.json | 15 + .../templates/cookie/cdn-filter/registry.json | 50 + .../templates/cookie/cdn-filter/src/lib.rs | 10 + .../cookie/cdn-filter/tests/filter-suite.ts | 866 +++ .../cookie/cdn-filter/tests/filter.test.ts | 118 + .../templates/gate-only/auth-app/.env.example | 168 + .../templates/gate-only/auth-app/package.json | 26 + .../gate-only/auth-app/registry.json | 316 ++ .../templates/gate-only/auth-app/server.tsx | 9 + .../gate-only/auth-app/tests/app.test.ts | 6 + .../gate-only/auth-app/tsconfig.json | 9 + .../gate-only/cdn-filter/.env.example | 61 + .../templates/gate-only/cdn-filter/Cargo.toml | 13 + .../gate-only/cdn-filter/package.json | 9 + .../gate-only/cdn-filter/registry.json | 50 + .../templates/gate-only/cdn-filter/src/lib.rs | 10 + .../templates/header/auth-app/.env.example | 169 + .../templates/header/auth-app/package.json | 26 + .../templates/header/auth-app/registry.json | 316 ++ edge-sso/templates/header/auth-app/server.tsx | 16 + .../header/auth-app/tests/app.test.ts | 8 + .../templates/header/auth-app/tsconfig.json | 9 + .../templates/header/cdn-filter/.env.example | 66 + .../templates/header/cdn-filter/Cargo.toml | 12 + .../templates/header/cdn-filter/package.json | 15 + .../templates/header/cdn-filter/registry.json | 50 + .../templates/header/cdn-filter/src/lib.rs | 10 + .../header/cdn-filter/tests/filter.test.ts | 301 + edge-sso/tsconfig.base.json | 13 + 113 files changed, 17822 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/_publish_js.yml rename .github/workflows/{_publish.yml => _publish_rs.yml} (62%) create mode 100644 .github/workflows/publish-sso-cookie-auth.yml create mode 100644 .github/workflows/publish-sso-cookie-filter.yml create mode 100644 .github/workflows/publish-sso-gate-only-auth.yml create mode 100644 .github/workflows/publish-sso-gate-only-filter.yml create mode 100644 .github/workflows/publish-sso-header-auth.yml create mode 100644 .github/workflows/publish-sso-header-filter.yml create mode 100644 .github/workflows/test-edge-sso.yml create mode 100755 edge-sso/.cargo/config.toml create mode 100644 edge-sso/.gitignore create mode 100644 edge-sso/AGENTS.md create mode 100644 edge-sso/CLAUDE.md create mode 100644 edge-sso/Cargo.lock create mode 100644 edge-sso/Cargo.toml create mode 100644 edge-sso/LICENSE create mode 100644 edge-sso/README.md create mode 100644 edge-sso/context/INDEX.md create mode 100644 edge-sso/context/architecture/auth-modes.md create mode 100644 edge-sso/context/architecture/overview.md create mode 100644 edge-sso/context/architecture/runtime-constraints.md create mode 100644 edge-sso/context/architecture/saml-flow.md create mode 100644 edge-sso/context/architecture/security.md create mode 100644 edge-sso/context/design/integration.md create mode 100644 edge-sso/context/development/testing.md create mode 100644 edge-sso/core/federation/app.tsx create mode 100644 edge-sso/core/federation/chooser.tsx create mode 100644 edge-sso/core/federation/config.ts create mode 100644 edge-sso/core/federation/error.tsx create mode 100644 edge-sso/core/federation/index.ts create mode 100644 edge-sso/core/federation/providers/common.ts create mode 100644 edge-sso/core/federation/providers/facebook.ts create mode 100644 edge-sso/core/federation/providers/github.ts create mode 100644 edge-sso/core/federation/providers/google-oidc.ts create mode 100644 edge-sso/core/federation/providers/google.ts create mode 100644 edge-sso/core/federation/providers/microsoft-oidc.ts create mode 100644 edge-sso/core/federation/providers/microsoft.ts create mode 100644 edge-sso/core/federation/providers/registry.ts create mode 100644 edge-sso/core/federation/saml/claims.ts create mode 100644 edge-sso/core/federation/saml/config.ts create mode 100644 edge-sso/core/federation/saml/handlers.ts create mode 100644 edge-sso/core/federation/saml/request.ts create mode 100644 edge-sso/core/federation/saml/response.ts create mode 100644 edge-sso/core/federation/util/redirect.ts create mode 100644 edge-sso/core/filter/Cargo.toml create mode 100644 edge-sso/core/filter/src/lib.rs create mode 100644 edge-sso/core/package.json create mode 100644 edge-sso/core/session/key.ts create mode 100644 edge-sso/core/session/token.ts create mode 100644 edge-sso/core/tsconfig.json create mode 100644 edge-sso/core/util/bytes.ts create mode 100644 edge-sso/core/util/env.ts create mode 100644 edge-sso/package.json create mode 100644 edge-sso/pnpm-lock.yaml create mode 100644 edge-sso/pnpm-workspace.yaml create mode 100644 edge-sso/scripts/gen-ec-keypair.mjs create mode 100644 edge-sso/templates/cookie/auth-app/.env.example create mode 100644 edge-sso/templates/cookie/auth-app/.env.test create mode 100644 edge-sso/templates/cookie/auth-app/package.json create mode 100644 edge-sso/templates/cookie/auth-app/registry.json create mode 100644 edge-sso/templates/cookie/auth-app/server.tsx create mode 100644 edge-sso/templates/cookie/auth-app/tests/_cookies.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/app.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/e2e/facebook.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/e2e/github.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/e2e/google.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/e2e/microsoft.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/non-cookie-smoke.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/tsconfig.json create mode 100644 edge-sso/templates/cookie/auth-app/tests/unit/default-claims.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/unit/google-oidc.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/unit/microsoft-oidc.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/unit/oauth-common.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/unit/providers-registry.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/unit/redirect.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/unit/saml-claims.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/unit/saml-response.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tests/unit/session-token.test.ts create mode 100644 edge-sso/templates/cookie/auth-app/tsconfig.json create mode 100644 edge-sso/templates/cookie/cdn-filter/.env.example create mode 100644 edge-sso/templates/cookie/cdn-filter/Cargo.toml create mode 100644 edge-sso/templates/cookie/cdn-filter/package.json create mode 100644 edge-sso/templates/cookie/cdn-filter/registry.json create mode 100644 edge-sso/templates/cookie/cdn-filter/src/lib.rs create mode 100644 edge-sso/templates/cookie/cdn-filter/tests/filter-suite.ts create mode 100644 edge-sso/templates/cookie/cdn-filter/tests/filter.test.ts create mode 100644 edge-sso/templates/gate-only/auth-app/.env.example create mode 100644 edge-sso/templates/gate-only/auth-app/package.json create mode 100644 edge-sso/templates/gate-only/auth-app/registry.json create mode 100644 edge-sso/templates/gate-only/auth-app/server.tsx create mode 100644 edge-sso/templates/gate-only/auth-app/tests/app.test.ts create mode 100644 edge-sso/templates/gate-only/auth-app/tsconfig.json create mode 100644 edge-sso/templates/gate-only/cdn-filter/.env.example create mode 100644 edge-sso/templates/gate-only/cdn-filter/Cargo.toml create mode 100644 edge-sso/templates/gate-only/cdn-filter/package.json create mode 100644 edge-sso/templates/gate-only/cdn-filter/registry.json create mode 100644 edge-sso/templates/gate-only/cdn-filter/src/lib.rs create mode 100644 edge-sso/templates/header/auth-app/.env.example create mode 100644 edge-sso/templates/header/auth-app/package.json create mode 100644 edge-sso/templates/header/auth-app/registry.json create mode 100644 edge-sso/templates/header/auth-app/server.tsx create mode 100644 edge-sso/templates/header/auth-app/tests/app.test.ts create mode 100644 edge-sso/templates/header/auth-app/tsconfig.json create mode 100644 edge-sso/templates/header/cdn-filter/.env.example create mode 100644 edge-sso/templates/header/cdn-filter/Cargo.toml create mode 100644 edge-sso/templates/header/cdn-filter/package.json create mode 100644 edge-sso/templates/header/cdn-filter/registry.json create mode 100644 edge-sso/templates/header/cdn-filter/src/lib.rs create mode 100644 edge-sso/templates/header/cdn-filter/tests/filter.test.ts create mode 100644 edge-sso/tsconfig.base.json diff --git a/.github/read-template-registry/action.yaml b/.github/read-template-registry/action.yaml index 6bdc089..8d98e30 100644 --- a/.github/read-template-registry/action.yaml +++ b/.github/read-template-registry/action.yaml @@ -32,11 +32,13 @@ runs: TEMPLATE_DIR: ${{ inputs.template_dir }} run: | echo "name=$(jq -r '.name' "$TEMPLATE_DIR/registry.json")" >> "$GITHUB_OUTPUT" - echo "template_id=$(jq -r '.template_id' "$TEMPLATE_DIR/registry.json")" >> "$GITHUB_OUTPUT" + echo "template_id=$(jq -r '.template_id // empty' "$TEMPLATE_DIR/registry.json")" >> "$GITHUB_OUTPUT" echo "descr=$(jq -r '.description' "$TEMPLATE_DIR/registry.json")" >> "$GITHUB_OUTPUT" echo "params=$(jq -c '.params' "$TEMPLATE_DIR/registry.json")" >> "$GITHUB_OUTPUT" - { - echo 'instructions<> "$GITHUB_OUTPUT" + if [ -f "$TEMPLATE_DIR/instructions.md" ]; then + { + echo 'instructions<> "$GITHUB_OUTPUT" + fi diff --git a/.github/workflows/_publish_js.yml b/.github/workflows/_publish_js.yml new file mode 100644 index 0000000..9453cfd --- /dev/null +++ b/.github/workflows/_publish_js.yml @@ -0,0 +1,93 @@ +name: Publish JS template + +# Reusable workflow: build one TypeScript app to wasm via fastedge-build and +# publish it as a portal template. No Harbor/compiler image needed — the build +# toolchain comes from npm. Callers pass the workspace root, the per-app build +# command, and the resulting wasm path. + +on: + workflow_call: + inputs: + template: + description: Template name (job label) + required: true + type: string + working_directory: + description: Workspace root to run pnpm install in + required: true + type: string + build_command: + description: "Command that builds the wasm (e.g. pnpm -C otp-app build)" + required: true + type: string + output_path: + description: Built wasm destination (relative to repo root) + required: true + type: string + registry_dir: + description: Dir holding registry.json / instructions.md + required: true + type: string + +permissions: + contents: read + +jobs: + build_and_publish: + name: Build and publish ${{ inputs.template }} + runs-on: [self-hosted, ubuntu-22-04, regular] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Import credentials from Vault + uses: hashicorp/vault-action@v3 + id: creds + with: + url: https://puppet-vault.gc.onl + token: ${{ secrets.VAULT_TOKEN }} + secrets: | + secret/project_fastedge/gcore_api/preprod apitoken | PREPROD_API_KEY ; + secret/project_fastedge/gcore_api/preprod hostname | PREPROD_API_URL ; + secret/project_fastedge/gcore_api/prod apitoken | PROD_API_KEY ; + secret/project_fastedge/gcore_api/prod hostname | PROD_API_URL ; + + - name: Setup Node.js and install dependencies + uses: ./.github/setup-node + with: + working_directory: ${{ inputs.working_directory }} + + - name: Build ${{ inputs.template }} + working-directory: ${{ inputs.working_directory }} + run: ${{ inputs.build_command }} + + - name: Read ${{ inputs.template }} registry + id: registry + uses: ./.github/read-template-registry + with: + template_dir: ${{ inputs.registry_dir }} + + - name: Deploy ${{ inputs.template }} to preprod + uses: gcore-github-actions/fastedge/deploy-template@v1 + with: + api_key: ${{ steps.creds.outputs.PREPROD_API_KEY }} + api_url: ${{ steps.creds.outputs.PREPROD_API_URL }} + wasm_file: ${{ inputs.output_path }} + template_name: ${{ steps.registry.outputs.name }} + short_descr: ${{ steps.registry.outputs.descr }} + long_descr: ${{ steps.registry.outputs.instructions }} + params: ${{ steps.registry.outputs.params }} + + - name: Deploy ${{ inputs.template }} to prod + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: gcore-github-actions/fastedge/deploy-template@v1 + with: + api_key: ${{ steps.creds.outputs.PROD_API_KEY }} + api_url: ${{ steps.creds.outputs.PROD_API_URL }} + wasm_file: ${{ inputs.output_path }} + template_name: ${{ steps.registry.outputs.name }} + template_id: ${{ steps.registry.outputs.template_id }} + short_descr: ${{ steps.registry.outputs.descr }} + long_descr: ${{ steps.registry.outputs.instructions }} + params: ${{ steps.registry.outputs.params }} diff --git a/.github/workflows/_publish.yml b/.github/workflows/_publish_rs.yml similarity index 62% rename from .github/workflows/_publish.yml rename to .github/workflows/_publish_rs.yml index 0b7286c..6d267b3 100644 --- a/.github/workflows/_publish.yml +++ b/.github/workflows/_publish_rs.yml @@ -1,12 +1,37 @@ -name: Publish template +name: Publish Rust template + +# Reusable workflow: build one Rust cdylib to wasm and publish it as a portal +# template. Simple templates (one dir = one package = one wasm) call this with +# just `template:`. Templates whose layout doesn't follow that convention +# (e.g. edge-sso filters living in a shared Cargo workspace) pass explicit +# paths to override the defaults. on: workflow_call: inputs: template: - description: Template directory / package name to build and publish + description: Template name (job label + default for the paths below) required: true type: string + rust_package: + description: "Cargo package name (default: template)" + required: false + type: string + working_directory: + description: "Dir containing the Cargo project (default: template)" + required: false + type: string + output_path: + description: "Built wasm destination (default: