Skip to content

Commit 883d26d

Browse files
committed
Merge branch 'sec-refactor' into master
2 parents b176301 + f94979d commit 883d26d

File tree

90 files changed

+6566
-1694
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+6566
-1694
lines changed

.github/workflows/sbom.yml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: sbom
2+
3+
on:
4+
workflow_dispatch: {}
5+
release:
6+
types:
7+
- published
8+
push:
9+
branches:
10+
- main
11+
- master
12+
paths:
13+
- go.mod
14+
- go.sum
15+
- ui/package.json
16+
- ui/package-lock.json
17+
- Makefile
18+
- .github/workflows/sbom.yml
19+
20+
jobs:
21+
generate-sbom:
22+
runs-on: ubuntu-latest
23+
permissions:
24+
contents: read
25+
env:
26+
SYFT_VERSION: v1.25.0
27+
SYFT_CACHE_DIR: ${{ github.workspace }}/.cache/syft-bin
28+
steps:
29+
- uses: actions/checkout@v4
30+
with:
31+
ref: ${{ github.event_name == 'release' && github.event.release.tag_name || github.ref }}
32+
33+
- name: Compute syft cache epoch
34+
id: syft-cache-epoch
35+
run: echo "epoch=$(date -u +%Y-%m)" >> "$GITHUB_OUTPUT"
36+
37+
- name: Cache syft binary
38+
id: syft-cache
39+
uses: actions/cache@v4
40+
with:
41+
path: ${{ env.SYFT_CACHE_DIR }}/syft
42+
key: ${{ runner.os }}-syft-${{ env.SYFT_VERSION }}-${{ steps.syft-cache-epoch.outputs.epoch }}
43+
restore-keys: |
44+
${{ runner.os }}-syft-${{ env.SYFT_VERSION }}-
45+
46+
- name: Install syft
47+
if: steps.syft-cache.outputs.cache-hit != 'true'
48+
run: |
49+
mkdir -p "${SYFT_CACHE_DIR}"
50+
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b "${SYFT_CACHE_DIR}" "${SYFT_VERSION}"
51+
52+
- name: Add syft to PATH
53+
run: echo "${SYFT_CACHE_DIR}" >> "$GITHUB_PATH"
54+
55+
- name: Verify syft
56+
run: |
57+
syft version
58+
59+
- name: Ensure optional Make env file exists
60+
run: touch .env
61+
62+
- name: Generate SBOM files
63+
run: |
64+
if [ "${{ github.event_name }}" = "release" ]; then
65+
make security-sbom SBOM_VERSION="${{ github.event.release.tag_name }}"
66+
else
67+
make security-sbom
68+
fi
69+
70+
- name: Upload SBOM artifacts
71+
uses: actions/upload-artifact@v4
72+
with:
73+
name: sbom-livereview-${{ github.run_id }}
74+
path: security_issues/sbom/*.json
75+
if-no-files-found: error
76+
retention-days: 30
77+
78+
publish-release-assets:
79+
if: github.event_name == 'release'
80+
needs:
81+
- generate-sbom
82+
runs-on: ubuntu-latest
83+
permissions:
84+
contents: write
85+
steps:
86+
- name: Download SBOM artifacts
87+
uses: actions/download-artifact@v4
88+
with:
89+
name: sbom-livereview-${{ github.run_id }}
90+
path: security_issues/sbom
91+
92+
- name: Upload SBOMs to release
93+
uses: softprops/action-gh-release@v2
94+
with:
95+
tag_name: ${{ github.event.release.tag_name }}
96+
fail_on_unmatched_files: true
97+
clobber: true
98+
files: |
99+
security_issues/sbom/*.json

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ debug_prompt.txt
1515
gh_pr_*.json
1616

1717
livereview_pgdata/
18+
.livereview_pgdata/
1819
lrdata/postgres/
1920

2021
# Vendor prompts local artifacts (never commit)

.gitleaks.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
title = "LiveReview gitleaks config"
2+
3+
[extend]
4+
useDefault = true
5+
6+
[[allowlists]]
7+
description = "Allow synthetic API-key fragment fixture in prompts redaction test"
8+
regexes = [
9+
'''rawKey := "abcdef123456"''',
10+
]
11+
paths = [
12+
'''internal/prompts/prompts_test.go''',
13+
]

Makefile

Lines changed: 123 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
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
88
GOTEST=$(GOCMD) test
99
BINARY_NAME=livereview
1010
REQUIRED_GO_VERSION=$(shell awk '/^go /{print $$2; exit}' go.mod)
11+
REQUIRED_GO_SERIES=$(shell echo $(REQUIRED_GO_VERSION) | awk -F. '{print $$1"."$$2}')
1112
GOVULNCHECK_VERSION=v1.1.4
1213
GOVULNCHECK_CMD=GOTOOLCHAIN=go$(REQUIRED_GO_VERSION) $(GOCMD) run -a golang.org/x/vuln/cmd/govulncheck@$(GOVULNCHECK_VERSION)
1314
GH_REPO=HexmosTech/LiveReview
1415
GH=/usr/bin/gh
1516
GHSM_SCRIPT=scripts/ghsm.py
1617
LEGACY_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
1930
include .env
@@ -129,16 +140,36 @@ docker-interactive-dry:
129140
build-push: docker-build-push
130141

131142
run:
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

135156
logrun:
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

139160
develop:
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

143174
develop-reflex:
144175
which reflex || go install github.com/cespare/reflex@latest
@@ -353,6 +384,13 @@ docker-multiarch:
353384

354385
docker-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

357395
docker-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+
503623
check-status-doc:
504624
chmod +x scripts/check-status-doc-links.sh
505625
./scripts/check-status-doc-links.sh

0 commit comments

Comments
 (0)