#!/usr/bin/env bash
set -euo pipefail
export GOWORK=off

root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
cd "$root/backend"

all_deps=$(go list -deps -test ./cmd/runtime-api/... ./cmd/runtime-worker/...)
api_deps=$(go list -deps ./cmd/runtime-api/...)
# Do not pipe these dependency snapshots into `grep -q` while `pipefail` is
# enabled. A successful early grep exit can give the producer SIGPIPE once the
# snapshot exceeds the pipe buffer, turning a present dependency into a false
# negative. Here-strings let grep consume the already-materialized snapshot
# without a second process in the pipeline.
for forbidden in \
  github.com/nexuscrm/backend/distributions \
  github.com/nexuscrm/backend/pkg/serverruntime \
  github.com/nexuscrm/backend/internal/application/services \
  github.com/nexuscrm/app-packs-conformance \
  github.com/pingcap-inc/nexuscrm-app-packs \
  dialect-sf-crm \
  issue-tracker; do
  if grep -Fq "$forbidden" <<<"$all_deps"; then
    echo "runtime process dependency closure contains forbidden owner: $forbidden" >&2
    exit 1
  fi
done

# Runtime API may consume only the Catalog-owned serving read facades, their
# pure immutable authority value model, and the release-artifact value model.
# Runtime API must not acquire setup or reconciliation write ownership.
while IFS= read -r dependency; do
  case "$dependency" in
    github.com/pingcap-inc/nexuscrm-controlplane/catalogread|github.com/pingcap-inc/nexuscrm-controlplane/catalogconsumer|github.com/pingcap-inc/nexuscrm-controlplane/internal/catalogconsumerauthority|github.com/pingcap-inc/nexuscrm-controlplane/releaseartifact)
      ;;
    github.com/pingcap-inc/nexuscrm-controlplane/*)
      echo "runtime process dependency closure contains non-Catalog control-plane owner: $dependency" >&2
      exit 1
      ;;
  esac
done <<<"$api_deps"

for forbidden in \
  google.golang.org/grpc/encoding/gzip \
  github.com/pingcap-inc/nexuscrm-connectors; do
  if grep -Fxq "$forbidden" <<<"$api_deps"; then
    echo "runtime-api production closure contains forbidden auth/compression initializer: $forbidden" >&2
    exit 1
  fi
done

for required in \
  github.com/nexuscrm/auth \
  github.com/nexuscrm/backend/internal/runtimeproduction \
  github.com/nexuscrm/metadata/catalogsnapshot \
  github.com/pingcap-inc/nexuscrm-controlplane/catalogconsumer \
  github.com/pingcap-inc/nexuscrm-controlplane/catalogread; do
  if ! grep -Fxq "$required" <<<"$api_deps"; then
    echo "runtime-api serving closure lost required D1 owner: $required" >&2
    exit 1
  fi
done

# gRPC decompresses before a unary interceptor runs. The only enforceable
# identity-only request invariant is therefore structural: no production
# dependency may register a compressor. Scan every current and future package
# in the runtime-api command closure, while excluding gRPC's registry function
# definition itself.
while IFS='|' read -r import_path directory files; do
  if [[ "$import_path" == "google.golang.org/grpc/encoding" ]] || [[ -z "$directory" ]]; then
    continue
  fi
  for file in $files; do
    if grep -Eq 'RegisterCompressor[[:space:]]*\(' "$directory/$file"; then
      echo "runtime-api production closure registers a gRPC compressor: $import_path/$file" >&2
      exit 1
    fi
  done
done < <(go list -deps -f '{{.ImportPath}}|{{.Dir}}|{{join .GoFiles " "}}' ./cmd/runtime-api/...)

# The D1 Runtime is the Identity issuer, so the command closure must sign with
# operator-provided private material. It must never generate a key or embed a
# private key literal/default.
while IFS='|' read -r import_path directory files; do
  [[ -z "$directory" ]] && continue
  [[ "$directory" != "$root/"* ]] && continue
  for file in $files; do
    if grep -Eq 'ed25519\.(GenerateKey|NewKeyFromSeed)[[:space:]]*\(' "$directory/$file"; then
      echo "runtime-api production closure generates signing-key material: $import_path/$file" >&2
      exit 1
    fi
  done
done < <(go list -deps -f '{{.ImportPath}}|{{.Dir}}|{{join .GoFiles " "}}' ./cmd/runtime-api/...)

# Production issuer source may accept operator-provided private material and
# call Sign, but it may never generate a startup key or embed an Org,
# AppInstallation, or Runtime capability grant.
if grep -R --include='*.go' --exclude='*_test.go' -Eq 'ed25519\.(GenerateKey|NewKeyFromSeed)[[:space:]]*\(' internal/runtimeidentity; then
  echo "Runtime Identity production source generates a signing key" >&2
  exit 1
fi
if grep -R --include='*.go' --exclude='*_test.go' -Eq '"(org-|installation-|runtime\.[a-z0-9_.-]+\.v[0-9]+)"' internal/runtimeidentity; then
  echo "Runtime Identity production source contains a static authority grant" >&2
  exit 1
fi

command_source=$(cat cmd/runtime-api/main.go internal/runtimeproduction/*.go)
for required in 'runtimeproduction.Assemble(' 'LoadSigningKeySnapshot(' 'catalogread.New(' 'catalogconsumer.New(' 'CatalogServingSource(' 'tls.VersionTLS13' 'TransportCredentials:'; do
  if ! grep -Fq "$required" <<<"$command_source"; then
    echo "runtime-api command lost explicit D1 composition step: $required" >&2
    exit 1
  fi
done
runtime_api_command=$(cat cmd/runtime-api/main.go)
for required in \
  'len(args) == 1 && args[0] == "bootstrap"' \
  'runtimeconfig.LoadAPIBootstrap(' \
  'runtimeapi.AssembleNonServingBootstrap(' \
  'if len(args) != 0' \
  'runtimeproduction.Assemble('; do
  if ! grep -Fq "$required" <<<"$runtime_api_command"; then
    echo "runtime-api command lost the explicit fail-closed deployment/activation split: $required" >&2
    exit 1
  fi
done

if grep -R --include='*.go' --exclude='*_test.go' -Eq 'SessionResolver|RejectingSessionResolver' internal/runtimeapi; then
  echo "runtime-api retains the legacy production SessionResolver identity path" >&2
  exit 1
fi

security_admission="internal/runtimeapi/security_admission.go"
for required in 'VerifyCallerBound(' 'a.state.authorize(' 'session.AuthEpoch != claims.AuthEpoch'; do
  if ! grep -Fq "$required" "$security_admission"; then
    echo "runtime-api trusted admission lost required durable security step: $required" >&2
    exit 1
  fi
done
if grep -Fq 'a.verifier.Verify(' "$security_admission"; then
  echo "runtime-api regressed to a single preselected Org/AppInstallation verifier binding" >&2
  exit 1
fi

# D2B turns runtime-worker into a real L0 engine process. It may depend on the
# neutral engine SCC needed by its work families. The retained dependency ceiling
# permits the released catalogreconcile closure; it is not evidence that a work
# family publishes Catalog state. The worker must not become an API or L1 host.
worker_deps=$(go list -deps -test ./cmd/runtime-worker/...)
catalog_publisher_deps=$(go list -deps \
  github.com/pingcap-inc/nexuscrm-controlplane/catalogreconcile \
  github.com/pingcap-inc/nexuscrm-controlplane/bootstrapimpl)
# Runtime Worker may interpret durable metadata work through the one dedicated
# mutation graph. It must not acquire the serving read assembly or a future
# sibling assembly merely because all of them share a parent import path.
runtime_assembly=github.com/nexuscrm/backend/internal/runtimeassembly
mutation_graph=$runtime_assembly/recordmutation
while IFS= read -r dependency; do
  case "$dependency" in
    "$mutation_graph"|"$mutation_graph"/*)
      ;;
    "$runtime_assembly"|"$runtime_assembly"/*)
      echo "runtime-worker dependency closure contains forbidden assembly owner: $dependency" >&2
      exit 1
      ;;
  esac
done <<<"$worker_deps"
while IFS= read -r dependency; do
  case "$dependency" in
    google.golang.org/grpc|google.golang.org/grpc/*|\
    github.com/nexuscrm/backend/internal/runtimeapi|github.com/nexuscrm/backend/internal/runtimeapi/*|\
    github.com/nexuscrm/backend/internal/runtimeproduction|github.com/nexuscrm/backend/internal/runtimeproduction/*|\
    github.com/pingcap-inc/nexuscrm-app-packs|github.com/pingcap-inc/nexuscrm-app-packs/*|\
    *dialect-sf-crm*)
      echo "runtime-worker dependency closure contains forbidden owner: $dependency" >&2
      exit 1
      ;;
  esac
done <<<"$worker_deps"
while IFS= read -r dependency; do
  case "$dependency" in
    github.com/pingcap-inc/nexuscrm-controlplane|github.com/pingcap-inc/nexuscrm-controlplane/*|\
    github.com/pingcap-inc/nexuscrm-connectors|github.com/pingcap-inc/nexuscrm-connectors/*)
      if [[ "$dependency" == "github.com/pingcap-inc/nexuscrm-controlplane/catalogread" ]]; then
        continue
      fi
      if ! grep -Fxq "$dependency" <<<"$catalog_publisher_deps"; then
        echo "runtime-worker dependency closure exceeds the released Catalog publisher: $dependency" >&2
        exit 1
      fi
      ;;
  esac
done <<<"$worker_deps"
for required in \
  github.com/nexuscrm/audit \
  github.com/nexuscrm/db \
  github.com/nexuscrm/persistence \
  github.com/nexuscrm/records; do
  if ! grep -Fxq "$required" <<<"$worker_deps"; then
    echo "runtime-worker dependency closure lost required D2B engine owner: $required" >&2
    exit 1
  fi
done

cd "$root"
if [[ "$(head -n 1 infra/runtime.Dockerfile.dockerignore)" != "**" ]] || \
   grep -Eq '^!(nexuscrm-app-packs|backend/distributions|dialect-toy)(/|$)' infra/runtime.Dockerfile.dockerignore; then
  echo "Runtime Docker context is not deny-by-default or explicitly admits an L1/distribution tree" >&2
  exit 1
fi

# The Runtime image context is deny-by-default. Derive every backend source
# package needed by every packaged L0 command and require an allowlisted parent
# subtree. This closes the gap where a local build succeeds but Docker silently
# omits a newly imported internal package until the trusted publisher runs.
runtime_dockerignore=infra/runtime.Dockerfile.dockerignore
while IFS= read -r directory; do
  [[ "$directory" == "$root/backend/"* ]] || continue
  relative=${directory#"$root/"}
  candidate=$relative
  admitted=false
  while [[ "$candidate" == backend/* ]]; do
    if grep -Fxq "!$candidate/" "$runtime_dockerignore" && \
       grep -Fxq "!$candidate/**" "$runtime_dockerignore"; then
      admitted=true
      break
    fi
    candidate=${candidate%/*}
  done
  if [[ "$admitted" != true ]]; then
    echo "Runtime Docker context excludes production command dependency: $relative" >&2
    exit 1
  fi
done < <(cd backend && go list -deps -f '{{.Dir}}' ./cmd/runtime-api/... ./cmd/runtime-worker/... ./cmd/setup/... | sort -u)

for forbidden in \
  nexuscrm-app-packs \
  backend/distributions \
  dialect-toy \
  dialect-sf-crm \
  issue-tracker \
  cmd/crm-server; do
  if grep -Fq "$forbidden" infra/runtime.Dockerfile; then
    echo "Runtime image build imports a forbidden L1/distribution owner: $forbidden" >&2
    exit 1
  fi
done

for required in \
  'ARG SOURCE_REVISION=dev' \
  "printf '%s\\n' \"\$VERSION\" | grep -Eq '^dev-[0-9]{8}-[0-9]+\\.[0-9]+\\.[0-9]+-[0-9a-f]{8}\$'" \
  "printf '%s\\n' \"\$SOURCE_REVISION\" | grep -Eq '^[0-9a-f]{40}\$'" \
  '-X main.version=${SOURCE_REVISION}' \
  'org.opencontainers.image.version="${VERSION}"' \
  'org.opencontainers.image.revision="${SOURCE_REVISION}"'; do
  if ! grep -Fq -- "$required" infra/runtime.Dockerfile; then
    echo "Runtime image again conflates candidate version with source revision: $required" >&2
    exit 1
  fi
done

for schema in backend/internal/runtimeconfig/schema/*.schema.json; do
  jq -e '.additionalProperties == false and (.required | index("NEXUSCRM_RUNTIME_WORKLOAD_IDENTITY_TOKEN_FILE")) != null' "$schema" >/dev/null
done
jq -e '(.required | index("NEXUSCRM_RUNTIME_API_TLS_CERTIFICATE_FILE")) != null and (.required | index("NEXUSCRM_RUNTIME_API_TLS_PRIVATE_KEY_FILE")) != null' \
  backend/internal/runtimeconfig/schema/runtime-api.schema.json >/dev/null

for forbidden in '__c' nexuscrm-app-packs issue-tracker salesforce sfcrm; do
  if grep -RFiq --include='*.yaml' --include='*.yml' "$forbidden" infra/runtime; then
    echo "generic Runtime deployment artifacts contain an L1/tenant token: $forbidden" >&2
    exit 1
  fi
done

python3 infra/runtime/test_deploy.py

# Runtime, Worker, and Integration are roles of one L0 Engine release. The
# central checker owns publication, signing, and stale-path invariants.
scripts/ci/check-l0-engine-release-boundary.sh

# The image smoke is the executable owner of the packaged runtime-api startup
# contract. Keep this PR-time structural guard beside the command/image
# boundary so a future config change cannot leave the post-merge Docker smoke
# on an older bootstrap contract.
runtime_smoke=scripts/ci/runtime-image-smoke.sh
for required in \
  'chmod 0400 "$token_file"' \
  'prepare_startup_contracts' \
  'sudo chown -R 10001:10001 "$secret_source"' \
  'type=bind,src=$secret_source,dst=/var/run/secrets/nexuscrm,readonly' \
  'NEXUSCRM_RUNTIME_API_SIGNING_KEY_FILE=/var/run/secrets/nexuscrm/signing.json' \
  'NEXUSCRM_RUNTIME_API_SERVING_CONFIG_FILE=/var/run/secrets/nexuscrm/serving.json' \
  'NEXUSCRM_RUNTIME_API_TLS_CERTIFICATE_FILE=/var/run/secrets/nexuscrm/tls.crt' \
  'NEXUSCRM_RUNTIME_API_TLS_PRIVATE_KEY_FILE=/var/run/secrets/nexuscrm/tls.key' \
  'nexuscrm.runtime-api-serving/v2' \
  'runtime.records.evaluate-access.v1' \
  'runtime.records.query.v1' \
  'capabilities: [' \
  'admission_lease: "2s"' \
  'assert_api_bootstrap_is_live_unready_and_metadata_independent' \
  'assert_api_fails_closed_without_serving_authority' \
  'nexuscrm.runtime-worker-role/v1' \
  'worker_source_revision: $source_revision' \
  'NEXUSCRM_RUNTIME_WORKER_CONFIG_FILE=/var/run/secrets/nexuscrm/worker.json' \
  'assert_worker_fails_closed_without_database_or_ownership' \
  'binary source revision' \
  "failed to ping database"; do
  if ! grep -Fq -- "$required" "$runtime_smoke"; then
    echo "Runtime image smoke lost serving startup contract evidence: $required" >&2
    exit 1
  fi
done
for required in \
  'go test -tags runtime_worker_integration' \
  "TestRuntimeWorkerRealTiDBFenceRecoveryAndLifecycle" \
  "TestRuntimeFlowCommandWorkerRealTiDBRecoversIdentityAfterRollbackAndReplays" \
  "TestTimedFlowDueProducerTiDBCommitsAndRollsBackWithRecordEventAttempt" \
  "TestRuntimeAPIProductionCompositionBuildsPlatformAdapters" \
  "TestRuntimeAPIProductionSearchScopeOrderUsesTiDBAuthority" \
  "TestM1CMutationToTimedFlowCrossProcessWalkingSlice"; do
  if ! grep -Fq -- "$required" .github/workflows/go-ci.yml; then
    echo "go-ci lost the exact-main Runtime Worker TiDB recovery gate: $required" >&2
    exit 1
  fi
done
for forbidden in \
  'chmod 0444 "$token_file"' \
  'nexuscrm.runtime-api-serving/v1' \
  'record_access_admission_lease' \
  'runtime.records.read-selected-root.v1' \
  '--entrypoint /bin/sh' \
  'type=volume,src=$secret_volume'; do
  if grep -Fq -- "$forbidden" "$runtime_smoke"; then
    echo "Runtime image smoke retains the old non-serving contract: $forbidden" >&2
    exit 1
  fi
done

engine_publisher=.github/workflows/trusted-publish-l0-engine-release.yml
for invocation in \
  'runtime-api) scripts/ci/runtime-image-smoke.sh --api-only "$IMAGE_NAME@$digest" "$RELEASE_VERSION" "$SOURCE_SHA"' \
  'runtime-worker) scripts/ci/runtime-image-smoke.sh --worker-only "$IMAGE_NAME@$digest" "$RELEASE_VERSION" "$SOURCE_SHA"'; do
  if ! grep -Fq -- "$invocation" "$engine_publisher"; then
    echo "L0 Engine publisher lost exact-digest functional smoke: $invocation" >&2
    exit 1
  fi
done

echo "runtime process boundary: OK"
