Ctrl K
ComunidadGuías…

hack/check-mongodb-rd-secrets.bats

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env bats
# Unit test: mongodb-rd cozyrds must deliver the TLS trust anchor without
# private key material.
#
# The PSMDB operator creates <release>-ca-cert holding the CA PRIVATE KEY and
# <release>-ssl / <release>-ssl-internal holding server private keys. The tenant
# must receive only the key-free <release>.tenant-ca projection, reached by
# label. These names are the contract between this file and the operator, and
# nothing else in the repo checks them at this level.
#
# The declaration that names the extraction source is a TenantProjection the
# chart renders, covered by packages/apps/mongodb/tests/tenant_projection_test.yaml.

load test_helper

REPO_ROOT="$(cd "$(dirname "${BATS_TEST_FILENAME:-$0}")/.." && pwd)"
COZYRDS="$REPO_ROOT/packages/system/mongodb-rd/cozyrds/mongodb.yaml"
# Bound explicitly rather than read from BATS_TEST_FILENAME inside a test body.
# These files run under hack/cozytest.sh, not bats: it executes each body with
# set -u and never exports that variable, so a bare reference aborts the test —
# and the runner stops at the first failure, taking every later test with it.
# $0 is not a usable fallback either, since it expands to the runner's own path
# and would silently scan the wrong file.
SELF="$REPO_ROOT/hack/check-mongodb-rd-secrets.bats"

@test "mongodb-rd checks use the set -e-safe negation form" {
  # Guards the pattern itself, so the next negated assertion added here cannot
  # be silently dead. `!`-prefixed commands are exempt from set -e.
  # SELF is a hardcoded path and grep exits 2 on a missing file, which an `if`
  # reads as simply false — so renaming this file would turn the guard green
  # while it inspected nothing. Every other check here reads $COZYRDS through
  # `grep -q` or a `$(yq ...)` assignment, both of which abort under set -e;
  # this is the one input that can vanish quietly.
  if [ ! -f "$SELF" ]; then
    echo "SELF does not resolve ($SELF); this guard would be vacuous" >&2
    exit 1
  fi
  # [[:space:]] rather than \s: the latter is a GNU/PCRE extension, not POSIX
  # ERE, and degrades to a literal 's' on a BSD grep — which would make this
  # guard vacuous, the one property a vacuity guard must not have.
  if grep -nE '^[[:space:]]*![[:space:]]' "$SELF"; then
    echo "Negated assertion above is exempt from set -e; use if/exit 1 instead" >&2
    exit 1
  fi
}

@test "mongodb-rd cozyrds selects the key-free projection by label" {
  grep -q 'internal.cozystack.io/tenant-ca: "true"' "$COZYRDS"
}

@test "mongodb-rd cozyrds secrets.include path resolves" {
  # Positive control for the two structural checks below. Both walk
  # .spec.secrets.include, and yq returns 0 for a path that does not exist — so
  # a rename of that field would leave them green while asserting nothing. The
  # grep-based tests would not notice either, since the strings stay in the
  # file. Deleting `include` outright is already caught by the label grep; this
  # covers the rename.
  n="$(yq '.spec.secrets.include // [] | length' "$COZYRDS")"
  if [ "$n" -lt 2 ]; then
    echo "spec.secrets.include has $n entries; the structural checks would be vacuous" >&2
    exit 1
  fi
}

@test "mongodb-rd cozyrds has no catch-all secrets selector" {
  # The mine this guards: an include entry with an empty matchLabels and no
  # resourceNames. LabelSelectorAsSelector({}) resolves to labels.Everything()
  # and a nil resourceNames matches any name, so such an entry promotes EVERY
  # Secret in the namespace — including the key-bearing TLS Secrets — to the
  # tenant. Checked structurally rather than by grep, because the correct
  # selector being present says nothing about a second, wider one alongside it.
  empty="$(yq '[.spec.secrets.include[]
    | select((.matchLabels // {} | length) == 0 and (.resourceNames // [] | length) == 0)]
    | length' "$COZYRDS")"
  if [ "$empty" != "0" ]; then
    echo "Found $empty secrets.include entry/entries matching every Secret in the namespace" >&2
    exit 1
  fi
}

@test "mongodb-rd cozyrds does not hand the tenant any key-bearing secret by name" {
  # resourceNames entries are name grants. The CA and leaf secrets each carry a
  # private key, so neither may appear as one.
  #
  # Matched on the suffix over the parsed resourceNames lists, not on a literal
  # spelling: the same object can be written "mongodb-{{ .name }}-ca-cert" or
  # "{{ .release }}-ca-cert", and a grep pinned to either form misses the other.
  # Walking the yq path also confines the check to grants, so a legitimate
  # mention of one of these names elsewhere in the file cannot trip it.
  leaks="$(yq '[.spec.secrets.include[].resourceNames[]?
    | select(test("-(ca-cert|ssl|ssl-internal|ssl-old|ssl-internal-old)$"))]
    | length' "$COZYRDS")"
  if [ "$leaks" != "0" ]; then
    echo "Found $leaks key-bearing secret(s) granted to the tenant by name" >&2
    exit 1
  fi
}

@test "mongodb-rd cozyrds excludes every key-bearing secret" {
  # The exclude list is the structural backstop behind the label-only include
  # selector, and nothing else pins it: deleting it leaves every other check in
  # this file green. Asserted positively — a count alone would go vacuous on a
  # renamed path, the same way the include checks would without their own
  # positive control.
  for name in ca-cert ssl ssl-internal ssl-old ssl-internal-old \
             percona-server-mongodb-users mongodb-encryption-key mongodb-keyfile s3-creds; do
    hits="$(yq "[.spec.secrets.exclude[].resourceNames[]? | select(. == \"mongodb-{{ .name }}-$name\")] | length" "$COZYRDS")"
    if [ "$hits" != "1" ]; then
      echo "mongodb-{{ .name }}-$name is not excluded (found $hits entries)" >&2
      exit 1
    fi
  done
}

@test "mongodb-rd cozyrds excludes the operator-internal secrets" {
  # These carry the internal- prefix rather than a release suffix, so they do
  # not fit the loop above. Quoted: the template braces contain spaces, and an
  # unquoted list item would word-split into "internal-mongodb-{{", ".name",
  # "}}" and assert on three names that do not exist.
  for name in "internal-mongodb-{{ .name }}" "internal-mongodb-{{ .name }}-users"; do
    hits="$(yq "[.spec.secrets.exclude[].resourceNames[]? | select(. == \"$name\")] | length" "$COZYRDS")"
    if [ "$hits" != "1" ]; then
      echo "$name is not excluded (found $hits entries)" >&2
      exit 1
    fi
  done
}

@test "mongodb-rd cozyrds still delivers the credentials secret" {
  # The exclude list added alongside the trust anchor is evaluated BEFORE
  # include and wins outright, so it now sits upstream of this pre-existing
  # grant. Every other line in that block is about withholding a Secret, which
  # makes adding this one to it a plausible edit — and one that would silently
  # revoke the tenant's access to their own connection string. Assert both
  # directions.
  inc="$(yq '[.spec.secrets.include[].resourceNames[]? | select(. == "mongodb-{{ .name }}-credentials")] | length' "$COZYRDS")"
  if [ "$inc" != "1" ]; then
    echo "credentials is not granted via include (found $inc entries)" >&2
    exit 1
  fi
  exc="$(yq '[.spec.secrets.exclude[].resourceNames[]? | select(. == "mongodb-{{ .name }}-credentials")] | length' "$COZYRDS")"
  if [ "$exc" != "0" ]; then
    echo "credentials appears in exclude, which wins over include" >&2
    exit 1
  fi
}