Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
cf17246
Retire legacy subscriptions in favor of operator provisioning
turgaybulut Sep 7, 2026
b712c7e
feat: capture and persist gateway diagnostic metadata
turgaybulut Sep 8, 2026
0ffd32e
Record gateway policy decisions through durable audit lifecycle
turgaybulut Sep 8, 2026
d6d3f4a
feat(enterprise): add scoped teams and durable key controls
turgaybulut Sep 8, 2026
a09c4cd
fix(accounting): preserve scope lock order during team settlement
turgaybulut Sep 8, 2026
976c787
Expose policy decisions and caller identity in audit log reads
turgaybulut Sep 8, 2026
4af4750
fix(audit): distinguish key access denial from quota exhaustion
turgaybulut Sep 8, 2026
735ddf2
feat(enterprise): add customer OIDC sessions and Vault secrets
turgaybulut Sep 8, 2026
6202ebd
feat(enterprise): expose worker successful-pass readiness
turgaybulut Sep 8, 2026
69d385c
fix(identity): synchronize team grants and finish local logout offline
turgaybulut Sep 8, 2026
d968cd7
feat(enterprise): route tenant models through approved deployments
turgaybulut Sep 8, 2026
cda5ce0
fix: expose unknown request pricing without fabricated zero costs
turgaybulut Sep 8, 2026
c4e15c9
fix: mark unpriced overview totals as incomplete
turgaybulut Sep 8, 2026
29f8fac
fix: label budget alerts with pricing completeness
turgaybulut Sep 8, 2026
affa82a
fix: preserve unknown billing costs and scope prompt hashes by deploy…
turgaybulut Sep 8, 2026
07af639
Sign enterprise releases and verify offline image bundles
turgaybulut Sep 8, 2026
d7680db
Reuse platform-specific BuildKit SBOM in release delivery
turgaybulut Sep 8, 2026
2309155
feat(deploy): package gateway dashboard and workers with Helm
turgaybulut Sep 8, 2026
db29675
test(on-prem): add isolated chart and real identity smoke harness
turgaybulut Sep 8, 2026
f7c9c45
feat(gateway): audit native Anthropic token counting without billing
turgaybulut Sep 8, 2026
7be329e
fix(enterprise): retain model configuration and deployment audit evid…
turgaybulut Sep 8, 2026
a593055
docs(gateway): describe registry routing and nonbillable token counts
turgaybulut Sep 8, 2026
987cb73
fix(enterprise): bound model health checks by a wall-clock deadline
turgaybulut Sep 8, 2026
e292dda
docs(enterprise): document separate-database restore rehearsal
turgaybulut Sep 8, 2026
8a0036b
Verify offline imports using archive configuration digests
turgaybulut Sep 8, 2026
e00d6b4
fix(deploy): make migration deadlines configurable and use native ini…
turgaybulut Sep 8, 2026
70fe575
docs(release): use the private dashboard package namespace
turgaybulut Sep 8, 2026
397b412
docs(deploy): clarify Redis requirements and canonical image digests
turgaybulut Sep 8, 2026
4d3d0d8
docs(enterprise): isolate restored worker side effects
turgaybulut Sep 8, 2026
546a493
fix(deploy): verify isolated chart with native images and real services
turgaybulut Sep 8, 2026
fd765a7
fix(deploy): reject unsafe cluster reuse before cleanup
turgaybulut Sep 8, 2026
8b3c1e1
test(deploy): include reuse safety in ownership and CI checks
turgaybulut Sep 8, 2026
936fabc
docs: retain maintained project guides and remove workspace records
turgaybulut Sep 8, 2026
afd06d9
Fix Cosign installation and require modern fixture TLS
turgaybulut Sep 8, 2026
f3d9ff1
Handle token-count system instructions in prompt hashing
turgaybulut Sep 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions .github/workflows/enterprise-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
name: enterprise release

on:
push:
tags: ["enterprise-v*"]

permissions:
contents: read

jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
version: ${{ steps.version.outputs.value }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Validate the component version and create the release
id: version
env:
GH_TOKEN: ${{ github.token }}
run: |
version="${GITHUB_REF_NAME#enterprise-v}"
[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]
test "$version" = "$(python3 -c 'import tomllib; print(tomllib.load(open("ee/pyproject.toml", "rb"))["project"]["version"])')"
echo "value=$version" >> "$GITHUB_OUTPUT"
gh release view "$GITHUB_REF_NAME" > /dev/null 2>&1 || \
gh release create "$GITHUB_REF_NAME" --verify-tag --draft --prerelease --generate-notes

image:
needs: release
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
arch: [amd64, arm64]
permissions:
contents: write
packages: write
env:
IMAGE: ghcr.io/getshim/shim-enterprise
VERSION: ${{ needs.release.outputs.version }}
ARCH: ${{ matrix.arch }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: docker/setup-qemu-action@1f40c72289eff860ee54a304f1438e3cff362e0a # v4
- uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4
- uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
with:
cosign-release: v3.1.3
- name: Log in with this repository's package token
env:
GH_TOKEN: ${{ github.token }}
run: echo "$GH_TOKEN" | docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin
- name: Build and publish the component
id: build
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
with:
context: .
file: ee/Dockerfile
platforms: linux/${{ matrix.arch }}
push: true
tags: ghcr.io/getshim/shim-enterprise:${{ env.VERSION }}-${{ matrix.arch }}
provenance: mode=max
sbom: true
- name: Sign the image and its offline delivery files
env:
COSIGN_PRIVATE_KEY: ${{ secrets.RELEASE_COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.RELEASE_COSIGN_PASSWORD }}
DIGEST: ${{ steps.build.outputs.digest }}
GH_TOKEN: ${{ github.token }}
run: |
test -n "$COSIGN_PRIVATE_KEY"
delivery="shim-enterprise-$VERSION-$ARCH"
mkdir "$delivery"
cosign public-key --key env://COSIGN_PRIVATE_KEY > "$delivery/release.pub"
cosign sign --yes --key env://COSIGN_PRIVATE_KEY --use-signing-config=false --tlog-upload=false "$IMAGE@$DIGEST"
docker pull --platform "linux/$ARCH" "$IMAGE@$DIGEST"
docker save --platform "linux/$ARCH" --output "$delivery/image.tar" "$IMAGE@$DIGEST"
docker buildx imagetools inspect "$IMAGE@$DIGEST" --format '{{json .SBOM}}' | \
jq -e '.SPDX' > "$delivery/sbom.spdx.json"
cp LICENSE "$delivery/community-LICENSE"
cp NOTICE "$delivery/community-NOTICE"
cp ee/LICENSE "$delivery/enterprise-LICENSE"
cp ee/NOTICE "$delivery/enterprise-NOTICE"
cp ee/docs/OFFLINE_RELEASES.md "$delivery/"
docker buildx imagetools inspect "$IMAGE@$DIGEST" --format '{{json .Provenance}}' > "$delivery/provenance.json"
jq -e '.SLSA != null' "$delivery/provenance.json" > /dev/null
jq -n --arg component enterprise --arg version "$VERSION" --arg platform "linux/$ARCH" \
--arg source "$IMAGE@$DIGEST" --arg commit "$GITHUB_SHA" \
'{component:$component,version:$version,platform:$platform,source:$source,commit:$commit}' \
> "$delivery/image.json"
(cd "$delivery" && sha256sum image.tar image.json sbom.spdx.json provenance.json release.pub community-LICENSE community-NOTICE enterprise-LICENSE enterprise-NOTICE OFFLINE_RELEASES.md > SHA256SUMS)
cosign sign-blob --yes --key env://COSIGN_PRIVATE_KEY --use-signing-config=false --tlog-upload=false \
--bundle "$delivery/SHA256SUMS.sigstore.json" "$delivery/SHA256SUMS"
cosign verify-blob --key "$delivery/release.pub" --insecure-ignore-tlog \
--bundle "$delivery/SHA256SUMS.sigstore.json" "$delivery/SHA256SUMS"
tar -cf "$delivery.tar" "$delivery"
gh release upload "$GITHUB_REF_NAME" "$delivery.tar"

publish:
needs: [release, image]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Publish only after every platform artifact succeeds
env:
GH_TOKEN: ${{ github.token }}
run: gh release edit "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --draft=false
85 changes: 85 additions & 0 deletions .github/workflows/on-prem-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Isolated on-prem chart smoke

on:
workflow_dispatch:
inputs:
dashboard_image:
description: Prebuilt OIDC dashboard image with immutable sha256 digest (runner must have pull access)
type: string
required: true
dashboard_version:
description: Dashboard source commit/version recorded for this acceptance run
type: string
required: true

permissions:
contents: read

jobs:
isolated-chart:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
version: "0.12.5"
enable-cache: false
- name: Install pinned local cluster tools
shell: bash
run: |
set -euo pipefail
cd "$RUNNER_TEMP"
curl --fail --silent --show-error --location -o kind-linux-amd64 https://github.com/kubernetes-sigs/kind/releases/download/v0.33.0/kind-linux-amd64
curl --fail --silent --show-error --location -o kind-linux-amd64.sha256sum https://github.com/kubernetes-sigs/kind/releases/download/v0.33.0/kind-linux-amd64.sha256sum
sha256sum --check kind-linux-amd64.sha256sum
sudo install -m 0755 kind-linux-amd64 /usr/local/bin/kind
curl --fail --silent --show-error --location -o helm.tar.gz https://get.helm.sh/helm-v4.2.4-linux-amd64.tar.gz
curl --fail --silent --show-error --location -o helm.sha256 https://get.helm.sh/helm-v4.2.4-linux-amd64.tar.gz.sha256sum
mv helm.tar.gz helm-v4.2.4-linux-amd64.tar.gz
sha256sum --check helm.sha256
tar -xzf helm-v4.2.4-linux-amd64.tar.gz
sudo install -m 0755 linux-amd64/helm /usr/local/bin/helm
kubectl version --client
- name: Authenticate private dashboard artifact pulls when configured
env:
GHCR_TOKEN: ${{ secrets.ON_PREM_DASHBOARD_GHCR_TOKEN }}
GHCR_USER: ${{ vars.ON_PREM_DASHBOARD_GHCR_USER || github.actor }}
run: |
if [ -n "$GHCR_TOKEN" ]; then
printf '%s' "$GHCR_TOKEN" | docker login ghcr.io --username "$GHCR_USER" --password-stdin
fi
- name: Validate dashboard artifact and build enterprise runtime
env:
DASHBOARD_IMAGE: ${{ inputs.dashboard_image }}
DASHBOARD_VERSION: ${{ inputs.dashboard_version }}
shell: bash
run: |
set -euo pipefail
[[ "$DASHBOARD_IMAGE" =~ @sha256:[0-9a-f]{64}$ ]]
docker pull "$DASHBOARD_IMAGE"
printf 'Dashboard source: %s\n' "$DASHBOARD_VERSION" >> "$GITHUB_STEP_SUMMARY"
docker build --network=default -f ee/Dockerfile --target runtime -t shim-enterprise:isolated-ci .
- name: Run real services on an internet-isolated cluster
env:
DASHBOARD_IMAGE: ${{ inputs.dashboard_image }}
run: |
uv run --locked --all-packages ruff check ee/deploy/test
uv run --locked --all-packages ruff format --check ee/deploy/test
uv run --locked --all-packages python -m pytest -q ee/deploy/test/test_reuse.py
uv run --locked --all-packages python ee/deploy/test/run.py --gateway-image shim-enterprise:isolated-ci --dashboard-image "$DASHBOARD_IMAGE"
- name: Save non-secret evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: isolated-chart-evidence
path: |
/tmp/shim-chart-smoke-*/result.json
/tmp/shim-chart-smoke-*/asset-audit.json
/tmp/shim-chart-smoke-*/resources.txt
if-no-files-found: warn
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ jobs:
with:
version: "0.12.5"
enable-cache: true
- uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
with:
cosign-release: v3.1.3
- run: uv lock --check
- run: uv sync --locked --all-packages
- run: uv run --locked --package shim-enterprise alembic -c ee/alembic.ini upgrade head
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# shim repository rules

Read `docs/CURRENT_ARCHITECTURE.md`, `docs/TARGET_ARCHITECTURE.md`, and
`DEVELOPER_GUIDE.md` before changing runtime boundaries.
Read `docs/CURRENT_ARCHITECTURE.md` and `DEVELOPER_GUIDE.md` before changing
runtime boundaries.

## Ownership

Expand Down
6 changes: 5 additions & 1 deletion DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ uv run --locked --package shim-enterprise alembic -c ee/alembic.ini upgrade head
Never downgrade a production database. Roll production back to the previous
schema-compatible application image.

Contact-only plan activation is an enterprise operation:
Operator-managed provisioning and plan activation are enterprise operations.
Follow [the provisioning and existing-customer transition runbook](ee/docs/PROVISIONING.md):

```bash
uv run --locked --package shim-enterprise python ee/scripts/activate_plan.py --help
Expand Down Expand Up @@ -125,6 +126,9 @@ assets and require the exact matching `shim-gateway` version.

## Changing an API or dependency

Diagnostic field semantics and null behavior are documented in
[`ee/docs/DIAGNOSTIC_METADATA.md`](ee/docs/DIAGNOSTIC_METADATA.md).

1. Trace the route through authentication, `GatewayService`, `GatewayKernel`,
provider execution, streaming, and usage finalization.
2. Change the owning product; keep the other product unchanged unless a public
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ Gemini `generateContent` routes, `/v1/models`, `/v1/scan`, `/health` and
`/metrics`. The checked-in contract is [`openapi/community.json`](openapi/community.json).

To run from source instead, see [the developer guide](DEVELOPER_GUIDE.md).
For customer-operated enterprise installations, see [deployment and recovery](ee/deploy/README.md).

## Limitations

Expand All @@ -142,7 +143,6 @@ To run from source instead, see [the developer guide](DEVELOPER_GUIDE.md).

- [Developer guide](DEVELOPER_GUIDE.md)
- [Current architecture](docs/CURRENT_ARCHITECTURE.md)
- [Target architecture](docs/TARGET_ARCHITECTURE.md)
- [Contributing](CONTRIBUTING.md)
- [Security policy](https://github.com/GetSHIM/shim/security/policy)

Expand Down
32 changes: 26 additions & 6 deletions architecture/module_ownership.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ forbidden_public_import_roots = [
# Exact community symbols consumed by enterprise runtime code. Any new entry is
# a deliberate expansion of the supported cross-license API.
[enterprise_public_api]
"shim.api.v1.chat" = ["router"]
"shim.api.v1.chat" = ["model_record", "router"]
"shim.api.v1.gemini" = ["router"]
"shim.api.v1.messages" = ["router"]
"shim.api.v1.responses" = ["router"]
Expand Down Expand Up @@ -54,15 +54,15 @@ forbidden_public_import_roots = [
"validate_actor_identity",
]
"shim.gateway.kernel.gateway_kernel" = ["GatewayKernel"]
"shim.gateway.kernel.result" = ["AdmissionState", "PreparedInference"]
"shim.gateway.kernel.result" = ["AdmissionState", "PreparedInference", "ProviderTarget", "UNSPECIFIED_PROVIDER_MODEL"]
"shim.gateway.pipeline.anthropic_execution" = ["AnthropicExecution"]
"shim.gateway.pipeline.authenticate" = ["GatewayRequestMetadata"]
"shim.gateway.pipeline.google_execution" = ["GoogleExecution"]
"shim.gateway.pipeline.openai_execution" = ["OpenAIExecution"]
"shim.gateway.pipeline.privacy" = ["ScanPrivacyOutcome", "ScanPrivacyStage"]
"shim.gateway.request_policy" = ["RequestPolicyContext", "ResolvedRequestPolicy"]
"shim.gateway.streaming.finalization" = ["StreamFinalization"]
"shim.gateway.usage" = ["UsageFailureReason", "UsageLimitExceeded"]
"shim.gateway.usage" = ["UsageAuditPersistenceError", "UsageFailureReason", "UsageLimitExceeded"]
"shim.observability.logging" = [
"configure_error_reporting",
"configure_logging",
Expand Down Expand Up @@ -184,6 +184,7 @@ public = [
"tests/gateway/test_openai_sdk_transport.py",
"tests/gateway/test_provider_error_fidelity.py",
"tests/gateway/test_request_policy.py",
"tests/gateway/test_token_count.py",
"tests/gateway/test_usage.py",
"tests/observability/test_sanitization.py",
"tests/secrets/test_credentials.py",
Expand All @@ -193,8 +194,15 @@ public = [
enterprise = [
"ee/alembic/env.py",
"ee/alembic/versions/aa8b038bc50c_architecture_baseline.py",
"ee/alembic/versions/c31b7a91d602_oidc_identity.py",
"ee/alembic/versions/c7a108be3201_teams_roles_and_scoped_key_controls.py",
"ee/alembic/versions/f10e4ac92d17_harden_function_search_paths.py",
"ee/alembic/versions/fcc02bbe6443_add_tenant_model_deployment_registry.py",
"ee/deploy/test/fixtures.py",
"ee/deploy/test/run.py",
"ee/deploy/test/test_reuse.py",
"ee/scripts/activate_plan.py",
"ee/scripts/offline_bundle.py",
"ee/scripts/sign_license.py",
"ee/src/shim_enterprise/__init__.py",
"ee/src/shim_enterprise/ai_act/__init__.py",
Expand All @@ -215,7 +223,6 @@ enterprise = [
"ee/src/shim_enterprise/api/v1/management.py",
"ee/src/shim_enterprise/api/v1/router.py",
"ee/src/shim_enterprise/api/v1/scan.py",
"ee/src/shim_enterprise/api/v1/subscriptions.py",
"ee/src/shim_enterprise/application.py",
"ee/src/shim_enterprise/billing/__init__.py",
"ee/src/shim_enterprise/billing/ledger.py",
Expand Down Expand Up @@ -287,21 +294,27 @@ enterprise = [
"ee/src/shim_enterprise/secrets/gcp_secret_manager.py",
"ee/src/shim_enterprise/secrets/migration.py",
"ee/src/shim_enterprise/secrets/store.py",
"ee/src/shim_enterprise/secrets/vault.py",
"ee/src/shim_enterprise/services/__init__.py",
"ee/src/shim_enterprise/services/gateway/__init__.py",
"ee/src/shim_enterprise/services/gateway/enterprise.py",
"ee/src/shim_enterprise/shared_results/__init__.py",
"ee/src/shim_enterprise/shared_results/api.py",
"ee/src/shim_enterprise/shared_results/models.py",
"ee/src/shim_enterprise/tenants/__init__.py",
"ee/src/shim_enterprise/tenants/audit.py",
"ee/src/shim_enterprise/tenants/deployments.py",
"ee/src/shim_enterprise/tenants/models.py",
"ee/src/shim_enterprise/tenants/oidc.py",
"ee/src/shim_enterprise/tenants/plans.py",
"ee/src/shim_enterprise/tenants/policy.py",
"ee/src/shim_enterprise/tenants/service.py",
"ee/src/shim_enterprise/tenants/subscriptions.py",
"ee/src/shim_enterprise/tenants/teams.py",
"ee/src/shim_enterprise/workers/__init__.py",
"ee/src/shim_enterprise/workers/ai_act.py",
"ee/src/shim_enterprise/workers/compliance.py",
"ee/src/shim_enterprise/workers/outbox.py",
"ee/src/shim_enterprise/workers/readiness.py",
"ee/src/shim_enterprise/workers/reconciliation.py",
"ee/tests/ai_act/test_audit_chain.py",
"ee/tests/ai_act/test_control_plane.py",
Expand All @@ -325,19 +338,26 @@ enterprise = [
"ee/tests/gateway/api/test_scan_endpoint.py",
"ee/tests/gateway/cache/test_loop_detection.py",
"ee/tests/gateway/kernel/test_accounting_coordinator.py",
"ee/tests/gateway/pipeline/test_decisions.py",
"ee/tests/gateway/pipeline/test_scan.py",
"ee/tests/gateway/pipeline/test_scan_recovery.py",
"ee/tests/gateway/privacy/test_chain_store.py",
"ee/tests/observability/test_enterprise_observability.py",
"ee/tests/outbox/test_dead_letter.py",
"ee/tests/outbox/test_publisher.py",
"ee/tests/outbox/test_worker.py",
"ee/tests/scripts/test_offline_bundle.py",
"ee/tests/secrets/test_ciphertext_compatibility.py",
"ee/tests/secrets/test_store.py",
"ee/tests/secrets/test_vault.py",
"ee/tests/shared_results/test_api.py",
"ee/tests/tenants/test_deployments.py",
"ee/tests/tenants/test_oidc.py",
"ee/tests/tenants/test_plans.py",
"ee/tests/tenants/test_policy.py",
"ee/tests/tenants/test_service.py",
"ee/tests/tenants/test_subscriptions.py",
"ee/tests/tenants/test_teams.py",
"ee/tests/workers/test_readiness.py",
]

# Transitional Python files that contain or exercise both ownership regions.
Expand Down
Loading