1- .PHONY : build run-review run-review-verbose test clean develop develop-reflex river-deps river-install river-migrate river-setup river-ui-install river-ui db-flip version version-bump version-patch version-minor version-major version-bump-dirty version-patch-dirty version-minor-dirty version-major-dirty version-bump-dry version-patch-dry version-minor-dry version-major-dry build-versioned docker-build docker-build-push docker-build-dry docker-interactive docker-interactive-push docker-interactive-dry docker-build docker-build-push docker-build-versioned docker-build-push-versioned docker-build-dry docker-build-push-dry docker-multiarch docker-multiarch-push docker-multiarch-dry docker-interactive-multiarch docker-interactive-multiarch-push cplrops vendor-prompts-encrypt vendor-prompts-build vendor-prompts-rebuild vendor-docker-build vendor-docker-build-dry vendor-docker-build-push vendor-docker-multiarch-dry vendor-docker-multiarch-push run logrun build-with-ui
1+ .PHONY: build run-review run-review-verbose test clean develop develop-reflex river-deps river-install river-migrate river-setup river-ui-install river-ui db-flip version version-bump version-patch version-minor version-major version-bump-dirty version-patch-dirty version-minor-dirty version-major-dirty version-bump-dry version-patch-dry version-minor-dry version-major-dry build-versioned docker-build docker-build-push docker-build-dry docker-interactive docker-interactive-push docker-interactive-dry docker-build docker-build-push docker-build-versioned docker-build-push-versioned docker-build-dry docker-build-push-dry docker-multiarch docker-multiarch-push docker-multiarch-dry docker-interactive-multiarch docker-interactive-multiarch-push cplrops vendor-prompts-encrypt vendor-prompts-build vendor-prompts-rebuild vendor-docker-build vendor-docker-build-dry vendor-docker-build-push vendor-docker-multiarch-dry vendor-docker-multiarch-push run logrun build-with-ui security-sbom security-sbom-cyclonedx security-sbom-spdx security-sbom-validate release-notes-init release-notes-check release-preflight release-gh
22.PHONY : upload-secrets download-secrets list-secrets-files legacy-secrets-clear
33
44# Go parameters
@@ -8,12 +8,23 @@ GOCLEAN=$(GOCMD) clean
88GOTEST =$(GOCMD ) test
99BINARY_NAME =livereview
1010REQUIRED_GO_VERSION =$(shell awk '/^go /{print $$2; exit}' go.mod)
11+ REQUIRED_GO_SERIES =$(shell echo $(REQUIRED_GO_VERSION ) | awk -F. '{print $$1"."$$2}')
1112GOVULNCHECK_VERSION =v1.1.4
1213GOVULNCHECK_CMD=GOTOOLCHAIN =go$(REQUIRED_GO_VERSION ) $(GOCMD ) run -a golang.org/x/vuln/cmd/govulncheck@$(GOVULNCHECK_VERSION )
1314GH_REPO =HexmosTech/LiveReview
1415GH =/usr/bin/gh
1516GHSM_SCRIPT =scripts/ghsm.py
1617LEGACY_ENV_VARS =DATABASE_URL JWT_SECRET LIVEREVIEW_BACKEND_PORT LIVEREVIEW_FRONTEND_PORT LIVEREVIEW_REVERSE_PROXY LIVEREVIEW_IS_CLOUD CLOUD_JWT_SECRET FW_PARSE_ADMIN_SECRET RAZORPAY_MODE RAZORPAY_WEBHOOK_SECRET RAZORPAY_TEST_KEY RAZORPAY_TEST_SECRET RAZORPAY_TEST_MONTHLY_PLAN_ID RAZORPAY_TEST_YEARLY_PLAN_ID RAZORPAY_LIVE_KEY RAZORPAY_LIVE_SECRET RAZORPAY_LIVE_MONTHLY_PLAN_ID RAZORPAY_LIVE_YEARLY_PLAN_ID DISCORD_SIGNUP_WEBHOOK_URL OVSX_PAT
18+ SYFT_CMD =syft
19+ SBOM_DIR =security_issues/sbom
20+ SBOM_VERSION? =$(shell git describe --tags --exact-match 2>/dev/null || git describe --tags --abbrev=0 2>/dev/null || echo dev)
21+ SBOM_CDX =$(SBOM_DIR ) /livereview-$(SBOM_VERSION ) -cyclonedx.json
22+ SBOM_SPDX =$(SBOM_DIR ) /livereview-$(SBOM_VERSION ) -spdx.json
23+ SBOM_UI_CDX =$(SBOM_DIR ) /livereview-ui-$(SBOM_VERSION ) -cyclonedx.json
24+ SBOM_UI_SPDX =$(SBOM_DIR ) /livereview-ui-$(SBOM_VERSION ) -spdx.json
25+ RELEASE_NOTES_DIR =docs/releases
26+ RELEASE_NOTES_TEMPLATE =$(RELEASE_NOTES_DIR ) /_template.md
27+ RELEASE_GH_SCRIPT =scripts/release_gh.py
1728
1829# Load environment variables from .env file
1930include .env
@@ -129,16 +140,36 @@ docker-interactive-dry:
129140build-push : docker-build-push
130141
131142run :
143+ @DLV_BIN_DIR=$$(go env GOBIN ) ; \
144+ if [ -z " $$ DLV_BIN_DIR" ]; then DLV_BIN_DIR=" $$ (go env GOPATH)/bin" ; fi ; \
145+ command -v dlv > /dev/null 2>&1 || { \
146+ echo " Installing Delve with Go $( REQUIRED_GO_VERSION) ..." ; \
147+ GOTOOLCHAIN=go$(REQUIRED_GO_VERSION ) $(GOCMD ) install github.com/go-delve/delve/cmd/dlv@latest; \
148+ }; \
149+ if ! go version -m " $$ DLV_BIN_DIR/dlv" 2> /dev/null | grep -q " go$( REQUIRED_GO_SERIES) " ; then \
150+ echo " Rebuilding Delve with Go $( REQUIRED_GO_VERSION) for DWARFv5+ compatibility..." ; \
151+ GOTOOLCHAIN=go$(REQUIRED_GO_VERSION ) $(GOCMD ) install github.com/go-delve/delve/cmd/dlv@latest; \
152+ fi
132153 which air || go install github.com/air-verse/air@latest
133- air
154+ DLV_BIN_DIR= $$( go env GOBIN ) ; if [ -z " $$ DLV_BIN_DIR " ] ; then DLV_BIN_DIR= " $$ (go env GOPATH)/bin " ; fi ; PATH= " $$ DLV_BIN_DIR: $$ PATH " air
134155
135156logrun :
136157 which air || go install github.com/air-verse/air@latest
137158 bash -c ' set -o pipefail; air 2>&1 | tee "logrun-$$(date +%Y%m%d-%H%M%S).log"'
138159
139160develop :
161+ @DLV_BIN_DIR=$$(go env GOBIN ) ; \
162+ if [ -z " $$ DLV_BIN_DIR" ]; then DLV_BIN_DIR=" $$ (go env GOPATH)/bin" ; fi ; \
163+ command -v dlv > /dev/null 2>&1 || { \
164+ echo " Installing Delve with Go $( REQUIRED_GO_VERSION) ..." ; \
165+ GOTOOLCHAIN=go$(REQUIRED_GO_VERSION ) $(GOCMD ) install github.com/go-delve/delve/cmd/dlv@latest; \
166+ }; \
167+ if ! go version -m " $$ DLV_BIN_DIR/dlv" 2> /dev/null | grep -q " go$( REQUIRED_GO_SERIES) " ; then \
168+ echo " Rebuilding Delve with Go $( REQUIRED_GO_VERSION) for DWARFv5+ compatibility..." ; \
169+ GOTOOLCHAIN=go$(REQUIRED_GO_VERSION ) $(GOCMD ) install github.com/go-delve/delve/cmd/dlv@latest; \
170+ fi
140171 which air || go install github.com/air-verse/air@latest
141- air
172+ DLV_BIN_DIR= $$( go env GOBIN ) ; if [ -z " $$ DLV_BIN_DIR " ] ; then DLV_BIN_DIR= " $$ (go env GOPATH)/bin " ; fi ; PATH= " $$ DLV_BIN_DIR: $$ PATH " air
142173
143174develop-reflex :
144175 which reflex || go install github.com/cespare/reflex@latest
@@ -353,6 +384,13 @@ docker-multiarch:
353384
354385docker-multiarch-push :
355386 @python scripts/lrops.py build --docker --multiarch --push $(ARGS )
387+ @echo " ℹ️ Optional GitHub release publish: make release-gh"
388+ @echo " Optional explicit override: make release-gh VERSION=$$ (git describe --tags --abbrev=0 2>/dev/null || true)"
389+
390+ # Optionally publish a GitHub release using markdown notes (no binary assets).
391+ # VERSION is optional and auto-inferred by scripts/release_gh.py.
392+ release-gh :
393+ @python3 $(RELEASE_GH_SCRIPT ) --repo $(GH_REPO ) $(if $(VERSION ) ,--version $(VERSION ) ,)
356394
357395docker-multiarch-dry :
358396 @python scripts/lrops.py build --docker --multiarch --dry-run $(ARGS )
@@ -500,6 +538,88 @@ legacy-secrets-clear:
500538 done
501539 @echo " ✅ Legacy variable cleanup complete."
502540
541+ # Generate SBOMs in both CycloneDX and SPDX formats for Go and UI dependencies.
542+ security-sbom : security-sbom-cyclonedx security-sbom-spdx security-sbom-validate
543+
544+ security-sbom-cyclonedx :
545+ @command -v $(SYFT_CMD ) > /dev/null 2>&1 || { \
546+ echo " ❌ syft not found. Install from https://github.com/anchore/syft" ; \
547+ exit 1; \
548+ }
549+ @mkdir -p $(SBOM_DIR )
550+ @$(SYFT_CMD ) file:go.mod --source-name livereview --source-version $(SBOM_VERSION ) -o cyclonedx-json=$(SBOM_CDX )
551+ @$(SYFT_CMD ) file:ui/package-lock.json --source-name livereview-ui --source-version $(SBOM_VERSION ) -o cyclonedx-json=$(SBOM_UI_CDX )
552+ @echo " ℹ️ SBOM version: $( SBOM_VERSION) "
553+ @echo " ✅ Wrote $( SBOM_CDX) "
554+ @echo " ✅ Wrote $( SBOM_UI_CDX) "
555+
556+ security-sbom-spdx :
557+ @command -v $(SYFT_CMD ) > /dev/null 2>&1 || { \
558+ echo " ❌ syft not found. Install from https://github.com/anchore/syft" ; \
559+ exit 1; \
560+ }
561+ @mkdir -p $(SBOM_DIR )
562+ @$(SYFT_CMD ) file:go.mod --source-name livereview --source-version $(SBOM_VERSION ) -o spdx-json=$(SBOM_SPDX )
563+ @$(SYFT_CMD ) file:ui/package-lock.json --source-name livereview-ui --source-version $(SBOM_VERSION ) -o spdx-json=$(SBOM_UI_SPDX )
564+ @echo " ℹ️ SBOM version: $( SBOM_VERSION) "
565+ @echo " ✅ Wrote $( SBOM_SPDX) "
566+ @echo " ✅ Wrote $( SBOM_UI_SPDX) "
567+
568+ security-sbom-validate :
569+ @test -s $(SBOM_CDX )
570+ @test -s $(SBOM_SPDX )
571+ @test -s $(SBOM_UI_CDX )
572+ @test -s $(SBOM_UI_SPDX )
573+ @echo " ✅ SBOM validation passed"
574+
575+ # Generate release notes file from template.
576+ # Usage: make release-notes-init VERSION=v1.2.3
577+ release-notes-init :
578+ @if [ -z " $( VERSION) " ]; then \
579+ echo " ❌ VERSION is required. Example: make release-notes-init VERSION=v1.2.3" ; \
580+ exit 1; \
581+ fi
582+ @echo " $( VERSION) " | grep -Eq ' ^v[0-9]+\.[0-9]+\.[0-9]+$$' || { \
583+ echo " ❌ VERSION must match vX.Y.Z" ; \
584+ exit 1; \
585+ }
586+ @test -f $(RELEASE_NOTES_TEMPLATE ) || { \
587+ echo " ❌ Missing template: $( RELEASE_NOTES_TEMPLATE) " ; \
588+ exit 1; \
589+ }
590+ @mkdir -p $(RELEASE_NOTES_DIR )
591+ @target=" $( RELEASE_NOTES_DIR) /$( VERSION) .md" ; \
592+ if [ -f " $$ target" ]; then \
593+ echo " ❌ Release notes already exist: $$ target" ; \
594+ exit 1; \
595+ fi ; \
596+ sed -e " s/__VERSION__/$( VERSION) /g" -e " s/__DATE__/$( shell date -u +%Y-%m-%d) /g" " $( RELEASE_NOTES_TEMPLATE) " > " $$ target" ; \
597+ echo " ✅ Created $$ target"
598+
599+ # Validate release notes file exists and required headings are present.
600+ # Usage: make release-notes-check VERSION=v1.2.3
601+ release-notes-check :
602+ @if [ -z " $( VERSION) " ]; then \
603+ echo " ❌ VERSION is required. Example: make release-notes-check VERSION=v1.2.3" ; \
604+ exit 1; \
605+ fi
606+ @echo " $( VERSION) " | grep -Eq ' ^v[0-9]+\.[0-9]+\.[0-9]+$$' || { \
607+ echo " ❌ VERSION must match vX.Y.Z" ; \
608+ exit 1; \
609+ }
610+ @target=" $( RELEASE_NOTES_DIR) /$( VERSION) .md" ; \
611+ test -f " $$ target" || { echo " ❌ Missing release notes: $$ target" ; exit 1; }; \
612+ test -s " $$ target" || { echo " ❌ Release notes file is empty: $$ target" ; exit 1; }; \
613+ grep -q ' ^## Summary' " $$ target" || { echo " ❌ Missing required section: ## Summary" ; exit 1; }; \
614+ grep -q ' ^## Install and Update' " $$ target" || { echo " ❌ Missing required section: ## Install and Update" ; exit 1; }; \
615+ grep -q ' ^## Changes' " $$ target" || { echo " ❌ Missing required section: ## Changes" ; exit 1; }; \
616+ echo " ✅ Release notes validated: $$ target"
617+
618+ # Run all release checks before creating/publishing a GitHub release.
619+ # Usage: make release-preflight VERSION=v1.2.3
620+ release-preflight : release-notes-check
621+ @echo " ✅ Release preflight passed for $( VERSION) "
622+
503623check-status-doc :
504624 chmod +x scripts/check-status-doc-links.sh
505625 ./scripts/check-status-doc-links.sh
0 commit comments