Files
supermq/scripts/combine-schema.sh
Steve Munene 362a4fc76d MG-370 - Add fine grained access control to rules engine (#402)
* update go mod file

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* fix rules endpoint tests

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* fix yaml file

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* fix build

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* address comments

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* remove roles from alarms

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* change approach for schema combaine

Signed-off-by: Arvindh <arvindh91@gmail.com>

* change approach for schema combaine

Signed-off-by: Arvindh <arvindh91@gmail.com>

* fix permissions for rules

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* fix authorization file

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* fix linter

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* fix linter

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

---------

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Signed-off-by: Arvindh <arvindh91@gmail.com>
Co-authored-by: Arvindh <arvindh91@gmail.com>
2026-03-05 11:42:51 +01:00

351 lines
10 KiB
Bash
Executable File

#!/bin/sh
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
REPO_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
SUPERMQ_SCHEMA="$REPO_ROOT/docker/supermq-docker/spicedb/schema.zed"
OVERRIDE_SCHEMA="$REPO_ROOT/docker/spicedb/override-schema.zed"
OUTPUT_SCHEMA="$REPO_ROOT/docker/spicedb/combined-schema.zed"
if [ ! -f "$SUPERMQ_SCHEMA" ]; then
echo "ERROR: $SUPERMQ_SCHEMA not found" >&2
exit 1
fi
if [ ! -f "$OVERRIDE_SCHEMA" ]; then
echo "ERROR: $OVERRIDE_SCHEMA not found" >&2
exit 1
fi
mkdir -p "$(dirname "$OUTPUT_SCHEMA")"
tmp_supermq_schema=$(mktemp)
tmp_supermq_merged=$(mktemp)
tmp_override_remaining=$(mktemp)
tmp_overlay_domain=$(mktemp)
tmp_overlay_team=$(mktemp)
tmp_overlay_domain_relations=$(mktemp)
tmp_overlay_team_relations=$(mktemp)
tmp_overlay_domain_permissions=$(mktemp)
tmp_overlay_membership_extension=$(mktemp)
cleanup() {
rm -f "$tmp_supermq_schema"
rm -f "$tmp_supermq_merged"
rm -f "$tmp_override_remaining"
rm -f "$tmp_overlay_domain"
rm -f "$tmp_overlay_team"
rm -f "$tmp_overlay_domain_relations"
rm -f "$tmp_overlay_team_relations"
rm -f "$tmp_overlay_domain_permissions"
rm -f "$tmp_overlay_membership_extension"
}
trap cleanup EXIT INT TERM
cp "$SUPERMQ_SCHEMA" "$tmp_supermq_schema"
# Extract the first domain overlay block from override schema.
if ! awk '
BEGIN {
in_domain = 0
found = 0
}
!found && /^definition domain[[:space:]]*{/ {
in_domain = 1
found = 1
next
}
in_domain {
if ($0 ~ /^}/) {
in_domain = 0
next
}
print
}
END {
if (!found) {
exit 1
}
}
' "$OVERRIDE_SCHEMA" > "$tmp_overlay_domain"; then
echo "ERROR: definition domain block not found in $OVERRIDE_SCHEMA" >&2
exit 1
fi
# Extract the first team overlay block from override schema.
if ! awk '
BEGIN {
in_team = 0
found = 0
}
!found && /^definition team[[:space:]]*{/ {
in_team = 1
found = 1
next
}
in_team {
if ($0 ~ /^}/) {
in_team = 0
next
}
print
}
END {
if (!found) {
exit 1
}
}
' "$OVERRIDE_SCHEMA" > "$tmp_overlay_team"; then
echo "ERROR: definition team block not found in $OVERRIDE_SCHEMA" >&2
exit 1
fi
# Read explicit domain overlay relations from override domain block.
awk '
/^[[:space:]]*relation[[:space:]]+[A-Za-z0-9_]+:[[:space:]]*role#member[[:space:]]*\|[[:space:]]*team#member[[:space:]]*$/ {
line = $0
sub(/^[[:space:]]*/, "\t", line)
print line
}
' "$tmp_overlay_domain" > "$tmp_overlay_domain_relations"
# Read explicit team overlay relations from override team block.
awk '
/^[[:space:]]*relation[[:space:]]+[A-Za-z0-9_]+:[[:space:]]*role#member[[:space:]]*\|[[:space:]]*team#member[[:space:]]*$/ {
line = $0
sub(/^[[:space:]]*/, "\t", line)
print line
}
' "$tmp_overlay_team" > "$tmp_overlay_team_relations"
# Read explicit domain overlay permissions from override domain block.
awk '
/^[[:space:]]*permission[[:space:]]+[A-Za-z0-9_]+_permission[[:space:]]*=/ {
line = $0
sub(/^[[:space:]]*/, "\t", line)
print line
}
' "$tmp_overlay_domain" > "$tmp_overlay_domain_permissions"
# Read explicit domain membership extension expression from override domain block.
awk '
/^[[:space:]]*permission[[:space:]]+membership_extension[[:space:]]*=/ {
line = $0
sub(/^[[:space:]]*permission[[:space:]]+membership_extension[[:space:]]*=[[:space:]]*/, "", line)
print line
exit
}
' "$tmp_overlay_domain" > "$tmp_overlay_membership_extension"
if [ ! -s "$tmp_overlay_domain_relations" ]; then
echo "ERROR: no domain relation overlay lines found in definition domain block of $OVERRIDE_SCHEMA" >&2
exit 1
fi
if [ ! -s "$tmp_overlay_team_relations" ]; then
echo "ERROR: no team relation overlay lines found in definition team block of $OVERRIDE_SCHEMA" >&2
exit 1
fi
if [ ! -s "$tmp_overlay_domain_permissions" ]; then
echo "ERROR: no domain permission overlay lines found in definition domain block of $OVERRIDE_SCHEMA" >&2
exit 1
fi
if [ ! -s "$tmp_overlay_membership_extension" ]; then
echo "ERROR: permission membership_extension not found in definition domain block of $OVERRIDE_SCHEMA" >&2
exit 1
fi
# Remove the first domain and first team overlay blocks from override schema before appending.
if ! awk '
BEGIN {
skip_domain = 0
skip_team = 0
removed_domain = 0
removed_team = 0
}
!removed_domain && /^definition domain[[:space:]]*{/ {
skip_domain = 1
removed_domain = 1
next
}
skip_domain {
if ($0 ~ /^}/) {
skip_domain = 0
}
next
}
!removed_team && /^definition team[[:space:]]*{/ {
skip_team = 1
removed_team = 1
next
}
skip_team {
if ($0 ~ /^}/) {
skip_team = 0
}
next
}
{ print }
END {
if (!removed_domain || !removed_team) {
exit 1
}
}
' "$OVERRIDE_SCHEMA" > "$tmp_override_remaining"; then
echo "ERROR: failed to strip definition domain/team blocks from $OVERRIDE_SCHEMA" >&2
exit 1
fi
# Inject explicit override lines into SuperMQ domain and team definitions.
awk \
-v domain_relations_file="$tmp_overlay_domain_relations" \
-v team_relations_file="$tmp_overlay_team_relations" \
-v domain_permissions_file="$tmp_overlay_domain_permissions" \
-v membership_extension_file="$tmp_overlay_membership_extension" '
BEGIN {
while ((getline line < domain_relations_file) > 0) {
domain_relations = domain_relations line ORS
}
close(domain_relations_file)
while ((getline line < team_relations_file) > 0) {
team_relations = team_relations line ORS
}
close(team_relations_file)
while ((getline line < domain_permissions_file) > 0) {
domain_permissions = domain_permissions line ORS
}
close(domain_permissions_file)
membership_extension = ""
if ((getline line < membership_extension_file) > 0) {
membership_extension = line
}
close(membership_extension_file)
in_domain = 0
in_team = 0
in_domain_membership = 0
inserted_domain_relations = 0
inserted_team_relations = 0
inserted_domain_permissions = 0
inserted_domain_membership = 0
}
{
if ($0 ~ /^definition domain[[:space:]]*{/) {
in_domain = 1
} else if ($0 ~ /^definition team[[:space:]]*{/) {
in_team = 1
}
if (in_domain && $0 ~ /^[[:space:]]*permission membership[[:space:]]*=/) {
in_domain_membership = 1
}
if (in_domain && in_domain_membership && $0 ~ /organization->admin[[:space:]]*$/) {
membership_tail = $0
sub(/[[:space:]]*\+[[:space:]]*organization->admin[[:space:]]*$/, " +", membership_tail)
print membership_tail
print "\t" membership_extension " +"
print "\torganization->admin"
in_domain_membership = 0
inserted_domain_membership = 1
next
}
print $0
if (in_domain && $0 ~ /^[[:space:]]*relation group_view_role_users: role#member \| team#member[[:space:]]*$/) {
print ""
print "\t// Magistrala-specific relations"
printf "%s", domain_relations
inserted_domain_relations = 1
}
if (in_team && $0 ~ /^[[:space:]]*relation group_view_role_users: role#member \| team#member[[:space:]]*$/) {
print ""
print "\t// Magistrala-specific relations"
printf "%s", team_relations
inserted_team_relations = 1
}
if (in_domain && $0 ~ /^[[:space:]]*permission group_view_role_users_permission = group_view_role_users \+ team->group_view_role_users \+ organization->admin[[:space:]]*$/) {
print ""
print "\t// Magistrala-specific permissions"
printf "%s", domain_permissions
inserted_domain_permissions = 1
}
if (in_domain && $0 ~ /^}/) {
in_domain = 0
in_domain_membership = 0
} else if (in_team && $0 ~ /^}/) {
in_team = 0
}
}
END {
if (!inserted_domain_relations || !inserted_team_relations || !inserted_domain_permissions || !inserted_domain_membership) {
exit 1
}
}
' "$tmp_supermq_schema" > "$tmp_supermq_merged" || {
echo "ERROR: failed to merge override schema into SuperMQ schema" >&2
exit 1
}
first_domain_relation=$(awk 'NR == 1 {print $2}' "$tmp_overlay_domain_relations")
first_team_relation=$(awk 'NR == 1 {print $2}' "$tmp_overlay_team_relations")
first_domain_permission=$(awk 'NR == 1 {print $2}' "$tmp_overlay_domain_permissions")
if [ -z "$first_domain_relation" ] || [ -z "$first_team_relation" ] || [ -z "$first_domain_permission" ]; then
echo "ERROR: failed to verify merged overlay lines" >&2
exit 1
fi
sub_first_domain_relation=${first_domain_relation%%:*}
sub_first_team_relation=${first_team_relation%%:*}
if ! grep -Fq "relation $sub_first_domain_relation: role#member | team#member" "$tmp_supermq_merged"; then
echo "ERROR: merged schema is missing domain relation $sub_first_domain_relation" >&2
exit 1
fi
if ! grep -Fq "relation $sub_first_team_relation: role#member | team#member" "$tmp_supermq_merged"; then
echo "ERROR: merged schema is missing team relation $sub_first_team_relation" >&2
exit 1
fi
if ! grep -Fq "permission $first_domain_permission" "$tmp_supermq_merged"; then
echo "ERROR: merged schema is missing domain permission $first_domain_permission" >&2
exit 1
fi
membership_extension_value=$(cat "$tmp_overlay_membership_extension")
if ! grep -Fq "$membership_extension_value +" "$tmp_supermq_merged"; then
echo "ERROR: merged schema is missing domain membership_extension values" >&2
exit 1
fi
{
cat <<'EOF'
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
// Code generated by scripts/combine-schema.sh. DO NOT EDIT.
//
// Combined from:
// - docker/supermq-docker/spicedb/schema.zed
// - docker/spicedb/override-schema.zed
EOF
cat "$tmp_supermq_merged" "$tmp_override_remaining"
} > "$OUTPUT_SCHEMA"
echo "Combined schema generated at: $OUTPUT_SCHEMA"