mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-09 14:02:56 +09:00
The shell translator rewrites test bodies and loses Bats reporting. The unit lane needs complete TAP results and JUnit reports without changing how live-cluster suites run. Sourced production helpers still need a dash pass, and unit test bodies need nounset without exporting shell options into subprocesses. Assisted-by: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
147 lines
7.2 KiB
Bash
147 lines
7.2 KiB
Bash
#!/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
|
|
}
|