| 1 | #!/usr/bin/env bash |
| 2 | # SPDX-License-Identifier: AGPL-3.0-or-later |
| 3 | # |
| 4 | # Fail when paid-organization feature decisions branch directly on |
| 5 | # orgs.plan outside the billing/entitlement boundary. Plan storage is |
| 6 | # allowed in schema/sqlc plumbing, but handlers and domain packages |
| 7 | # should ask the entitlement layer whether a feature is available. |
| 8 | # |
| 9 | # Allowed locations: |
| 10 | # internal/billing/... — owns subscription state |
| 11 | # internal/entitlements/... — owns feature availability |
| 12 | # internal/*/sqlc/... — generated data models |
| 13 | # internal/migrationsfs/... — schema definitions |
| 14 | # *_test.go everywhere — tests may seed or assert plan values |
| 15 | # |
| 16 | # Run from `make ci`. |
| 17 | |
| 18 | set -euo pipefail |
| 19 | |
| 20 | cd "$(git rev-parse --show-toplevel)" |
| 21 | |
| 22 | PATTERN='OrgPlan(Free|Team|Enterprise)|\.Plan[[:space:]]*(==|!=)|orgs\.plan|plan[[:space:]]+org_plan' |
| 23 | |
| 24 | matches=$(git grep -nE "$PATTERN" -- \ |
| 25 | 'cmd' 'internal' \ |
| 26 | ':!internal/billing/*' \ |
| 27 | ':!internal/entitlements/*' \ |
| 28 | ':!internal/*/sqlc/*' \ |
| 29 | ':!internal/migrationsfs/*' \ |
| 30 | ':!**/*_test.go' \ |
| 31 | 2>/dev/null || true) |
| 32 | |
| 33 | if [[ -n "$matches" ]]; then |
| 34 | echo "lint-org-plan-boundary: direct org plan feature gate outside billing/entitlements:" >&2 |
| 35 | echo "$matches" | sed 's/^/ /' >&2 |
| 36 | echo "" >&2 |
| 37 | echo "Fix: add or use an entitlement feature check instead of branching on orgs.plan directly." >&2 |
| 38 | exit 1 |
| 39 | fi |
| 40 | |
| 41 | echo "lint-org-plan-boundary: ok" |