202 lines
4.8 KiB
Bash
202 lines
4.8 KiB
Bash
#!/usr/bin/env bash
|
|
# License validation script for StellaOps CI
|
|
# Usage: validate-licenses.sh <type> <input-file>
|
|
# type: nuget | npm
|
|
# input-file: Path to package list or license-checker output
|
|
|
|
set -euo pipefail
|
|
|
|
# SPDX identifiers for licenses compatible with AGPL-3.0-or-later
|
|
ALLOWED_LICENSES=(
|
|
"MIT"
|
|
"Apache-2.0"
|
|
"Apache 2.0"
|
|
"BSD-2-Clause"
|
|
"BSD-3-Clause"
|
|
"BSD"
|
|
"ISC"
|
|
"0BSD"
|
|
"CC0-1.0"
|
|
"CC0"
|
|
"Unlicense"
|
|
"PostgreSQL"
|
|
"MPL-2.0"
|
|
"MPL 2.0"
|
|
"LGPL-2.1-or-later"
|
|
"LGPL-3.0-or-later"
|
|
"GPL-3.0-or-later"
|
|
"AGPL-3.0-or-later"
|
|
"Zlib"
|
|
"WTFPL"
|
|
"BlueOak-1.0.0"
|
|
"Python-2.0"
|
|
"(MIT OR Apache-2.0)"
|
|
"(Apache-2.0 OR MIT)"
|
|
"MIT OR Apache-2.0"
|
|
"Apache-2.0 OR MIT"
|
|
)
|
|
|
|
# Licenses that are OK but should be noted
|
|
CONDITIONAL_LICENSES=(
|
|
"MPL-2.0"
|
|
"LGPL-2.1-or-later"
|
|
"LGPL-3.0-or-later"
|
|
"CC-BY-4.0"
|
|
)
|
|
|
|
# Licenses that are NOT compatible with AGPL-3.0-or-later
|
|
BLOCKED_LICENSES=(
|
|
"GPL-2.0-only"
|
|
"SSPL-1.0"
|
|
"SSPL"
|
|
"BUSL-1.1"
|
|
"BSL-1.0"
|
|
"Commons Clause"
|
|
"Proprietary"
|
|
"Commercial"
|
|
"UNLICENSED"
|
|
)
|
|
|
|
TYPE="${1:-}"
|
|
INPUT="${2:-}"
|
|
|
|
if [[ -z "$TYPE" || -z "$INPUT" ]]; then
|
|
echo "Usage: $0 <nuget|npm> <input-file>"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "$INPUT" ]]; then
|
|
echo "ERROR: Input file not found: $INPUT"
|
|
exit 1
|
|
fi
|
|
|
|
echo "=== StellaOps License Validation ==="
|
|
echo "Type: $TYPE"
|
|
echo "Input: $INPUT"
|
|
echo ""
|
|
|
|
found_blocked=0
|
|
found_conditional=0
|
|
found_unknown=0
|
|
|
|
validate_npm() {
|
|
local input="$1"
|
|
|
|
echo "Validating npm licenses..."
|
|
|
|
# Extract licenses from license-checker JSON output
|
|
if command -v jq &> /dev/null; then
|
|
jq -r 'to_entries[] | "\(.key): \(.value.licenses)"' "$input" 2>/dev/null | while read -r line; do
|
|
pkg=$(echo "$line" | cut -d: -f1)
|
|
license=$(echo "$line" | cut -d: -f2- | xargs)
|
|
|
|
# Check if license is blocked
|
|
for blocked in "${BLOCKED_LICENSES[@]}"; do
|
|
if [[ "$license" == *"$blocked"* ]]; then
|
|
echo "BLOCKED: $pkg uses '$license'"
|
|
found_blocked=$((found_blocked + 1))
|
|
fi
|
|
done
|
|
|
|
# Check if license is allowed
|
|
allowed=0
|
|
for ok_license in "${ALLOWED_LICENSES[@]}"; do
|
|
if [[ "$license" == *"$ok_license"* ]]; then
|
|
allowed=1
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ $allowed -eq 0 ]]; then
|
|
echo "UNKNOWN: $pkg uses '$license'"
|
|
found_unknown=$((found_unknown + 1))
|
|
fi
|
|
done
|
|
else
|
|
echo "WARNING: jq not available, performing basic grep check"
|
|
for blocked in "${BLOCKED_LICENSES[@]}"; do
|
|
if grep -qi "$blocked" "$input"; then
|
|
echo "BLOCKED: Found potentially blocked license: $blocked"
|
|
found_blocked=$((found_blocked + 1))
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
validate_nuget() {
|
|
local input="$1"
|
|
|
|
echo "Validating NuGet licenses..."
|
|
|
|
# NuGet package list doesn't include licenses directly
|
|
# We check for known problematic packages
|
|
|
|
# Known packages with compatible licenses (allowlist approach for critical packages)
|
|
known_good_patterns=(
|
|
"Microsoft."
|
|
"System."
|
|
"Newtonsoft.Json"
|
|
"Serilog"
|
|
"BouncyCastle"
|
|
"Npgsql"
|
|
"Dapper"
|
|
"Polly"
|
|
"xunit"
|
|
"Moq"
|
|
"FluentAssertions"
|
|
"CycloneDX"
|
|
"YamlDotNet"
|
|
"StackExchange.Redis"
|
|
"Google."
|
|
"AWSSDK."
|
|
"Grpc."
|
|
)
|
|
|
|
# Check if any packages don't match known patterns
|
|
echo "Checking for unknown packages..."
|
|
|
|
# This is informational - we trust the allowlist in THIRD-PARTY-DEPENDENCIES.md
|
|
echo "OK: NuGet validation relies on documented license allowlist"
|
|
echo "See: docs/legal/THIRD-PARTY-DEPENDENCIES.md"
|
|
}
|
|
|
|
case "$TYPE" in
|
|
npm)
|
|
validate_npm "$INPUT"
|
|
;;
|
|
nuget)
|
|
validate_nuget "$INPUT"
|
|
;;
|
|
*)
|
|
echo "ERROR: Unknown type: $TYPE"
|
|
echo "Supported types: nuget, npm"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
echo ""
|
|
echo "=== Validation Summary ==="
|
|
echo "Blocked licenses found: $found_blocked"
|
|
echo "Conditional licenses found: $found_conditional"
|
|
echo "Unknown licenses found: $found_unknown"
|
|
|
|
if [[ $found_blocked -gt 0 ]]; then
|
|
echo ""
|
|
echo "ERROR: Blocked licenses detected!"
|
|
echo "These licenses are NOT compatible with AGPL-3.0-or-later"
|
|
echo "Please remove or replace the affected packages"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ $found_unknown -gt 0 ]]; then
|
|
echo ""
|
|
echo "WARNING: Unknown licenses detected"
|
|
echo "Please review and add to allowlist if compatible"
|
|
echo "See: docs/legal/LICENSE-COMPATIBILITY.md"
|
|
# Don't fail on unknown - just warn
|
|
fi
|
|
|
|
echo ""
|
|
echo "License validation: PASSED"
|
|
exit 0
|