Merge pull request #367 from naturallaw777/arena/019faeb9-sovran-systemsos

docs: real v1.0.4 changelog + auto-generated release notes in release script
This commit is contained in:
Sovran Systems
2026-07-29 11:38:42 -05:00
committed by GitHub
2 changed files with 142 additions and 25 deletions
+36 -4
View File
@@ -10,15 +10,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [1.0.4] - 2026-07-29
### Added
- (Add new features here)
- **Lightning Wallet Connections (NWC)** — Hub-managed Nostr Wallet Connect powered by Alby Hub + LND:
- Create, view, and delete wallet connections directly from the Sovran Hub with a tabbed modal UI
- Downloadable/printable LNURL QR codes for connecting external wallets
- Channel liquidity guide and onboarding guidance for new LND nodes
- Unique-hostname enforcement with conflict validation and UI guidance
- Official NWC branding and logo
- **Version visibility across the Hub**:
- Sovran_SystemsOS version badge displayed under the Hub title
- Version numbers shown on all Hub service tiles and next to service modal titles
- Deployed PHP app versions surfaced in service titles
- Build-time version reference file (`VERSION`) so version lookups are instantaneous and consistent
- **Automated stable release workflow** (`scripts/release-stable.sh`) with versioned ISO naming from the `VERSION` file
- `CONTRIBUTING.md` and expanded project documentation
### Changed
- (Add changes here)
- **Manual Backup overhauled**: replaced tar+DB+LND archive approach with a reliable ext4 + rsync workflow, including
mount checks, path safety, atomic completion markers, stale-marker cleanup, and behavioral test coverage
- **Port-forwarding UX simplified**: removed onboarding Step 4 and the misleading local "ready" status;
Njal.la DDNS now runs automatically when the feature is enabled
- README restructured for clarity, links, and accuracy; added router/ISP port-forwarding requirements
for Server + Desktop mode; acknowledged LiveKit and Alby Hub
- Updated nixpkgs and Bitcoin clients
- Repository cleanup: removed unused `.github`, `.tests`, `nix/`, and `docs/ai` directories
### Fixed
- (Add bug fixes here)
- NWC wallet certificate path wiring (now uses the nix-bitcoin LND cert path)
- Deterministic LND/Alby Hub port collision
- Alby Hub executable resolution and v1.23.0 patches regenerated against exact upstream source
- Manual Backup exit-code failures (bash/gawk in service PATH, tar tolerance, flock, browser-cache exclusions)
- rsync destination-directory failures in backups (auto `mkdir -p`, mount check, 19 behavioral tests)
- `sovran-hosts-update` converted to `writeShellApplication` with explicit runtime inputs
- Incorrect `lib.mkIf` usage in the NWC wallets module
- Duplicate systemd LND strings
- `git fetch` tag-clobber errors against Gitea (now uses `--force`)
[1.0.4]: https://git.sovransystems.com/api/Sovran_Systems/Sovran_SystemsOS/releases/tag/v1.0.4
### Security
- Hardened Lightning Wallet Connections (NWC): restricted `ReadOnlyPaths` for the unlock password,
fixed an Authorization-header bug, eliminated stack-trace exposure flagged by CodeQL,
and tightened credential access and amount validation
[1.0.4]: https://git.sovransystems.com/Sovran_Systems/Sovran_SystemsOS/releases/tag/v1.0.4
## [1.0.3] - 2026-07-29
+106 -21
View File
@@ -130,7 +130,7 @@ done
if [[ -z "$RELEASE_MESSAGE" ]]; then
echo
read -rp "Enter release message (or press Enter for default): " input_msg
read -rp "Enter release headline (or press Enter for default): " input_msg
if [[ -n "$input_msg" ]]; then
RELEASE_MESSAGE="$input_msg"
else
@@ -138,6 +138,91 @@ if [[ -z "$RELEASE_MESSAGE" ]]; then
fi
fi
# ─────────────────────────────────────────────────────────────────────────────
# Helper: Generate categorized release notes from commit history
# Groups commits since the last tag into Keep-a-Changelog sections based on
# conventional-commit prefixes (feat/fix/docs/security/etc.) and keywords.
# ─────────────────────────────────────────────────────────────────────────────
generate_release_notes() {
local range="$1"
local added="" changed="" fixed="" security="" docs=""
while IFS= read -r subject; do
# Skip noise commits
case "$subject" in
"Initial plan"|"initial plan") continue ;;
"Merge pull request"*|"Merge branch"*) continue ;;
"chore: bump VERSION"*|"docs: update CHANGELOG"*) continue ;;
"Address code review"*|"Address review"*|"Address validation"*) continue ;;
esac
# Strip conventional-commit prefix for display
local clean
clean="$(echo "$subject" | sed -E 's/^(feat|fix|docs|chore|refactor|test|security|perf|style|ci|build)(\([^)]*\))?!?:[[:space:]]*//')"
# Capitalize first letter
clean="$(echo "${clean:0:1}" | tr '[:lower:]' '[:upper:]')${clean:1}"
case "$subject" in
security:*|security\(*) security+="- ${clean}"$'\n' ;;
feat:*|feat\(*) added+="- ${clean}"$'\n' ;;
fix:*|fix\(*|Fix\ *|fixed\ *) fixed+="- ${clean}"$'\n' ;;
docs:*|docs\(*) docs+="- ${clean}"$'\n' ;;
refactor:*|refactor\(*|chore:*|chore\(*|removed\ *|Updated\ *|updated\ *) changed+="- ${clean}"$'\n' ;;
test:*|test\(*) continue ;;
*) added+="- ${clean}"$'\n' ;;
esac
done < <(git log --no-merges --format='%s' "$range" 2>/dev/null | awk '!seen[$0]++')
local notes=""
if [[ -n "$added" ]]; then notes+=$'### Added\n'"$added"$'\n'; fi
if [[ -n "$changed" ]]; then notes+=$'### Changed\n'"$changed"$'\n'; fi
if [[ -n "$fixed" ]]; then notes+=$'### Fixed\n'"$fixed"$'\n'; fi
if [[ -n "$security" ]]; then notes+=$'### Security\n'"$security"$'\n'; fi
if [[ -n "$docs" ]]; then notes+=$'### Documentation\n'"$docs"$'\n'; fi
if [[ -z "$notes" ]]; then
notes=$'### Changed\n- Incremental stable updates\n'
fi
printf '%s' "$notes"
}
# Build the notes from commits since the previous tag
if [[ -n "$LATEST_TAG" ]] && git rev-parse -q --verify "$LATEST_TAG" >/dev/null; then
COMMIT_RANGE="${LATEST_TAG}..HEAD"
else
COMMIT_RANGE="HEAD"
fi
echo
echo -e "${BLUE}Generating draft release notes from ${COMMIT_RANGE}...${NC}"
RELEASE_NOTES="$(generate_release_notes "$COMMIT_RANGE")"
# Let the user review/edit the generated notes before publishing
NOTES_FILE="$(mktemp "/tmp/release-notes-${TAG}.XXXXXX.md")"
{
echo "## Sovran_SystemsOS ${TAG}"
echo
echo "${RELEASE_MESSAGE}"
echo
echo "$RELEASE_NOTES"
echo "**Full changelog:** [CHANGELOG.md](https://github.com/naturallaw777/Sovran_SystemsOS/blob/main/CHANGELOG.md)"
} > "$NOTES_FILE"
echo -e " ${GREEN}${NC} Draft notes written to: ${CYAN}${NOTES_FILE}${NC}"
echo
echo "──────────────── Draft Release Notes ────────────────"
cat "$NOTES_FILE"
echo "──────────────────────────────────────────────────────"
echo
read -rp "Edit the notes before publishing? (y/N): " edit_confirm
if [[ "$edit_confirm" =~ ^[Yy]$ ]]; then
"${EDITOR:-nano}" "$NOTES_FILE"
RELEASE_NOTES="$(sed -n '/^###/,$p' "$NOTES_FILE" | sed '/^\*\*Full changelog/d')"
fi
RELEASE_BODY="$(cat "$NOTES_FILE")"
echo
echo -e "${YELLOW}════════════════════════════════════════════════════════════${NC}"
echo -e "${YELLOW} Preparing Release${NC}"
@@ -200,19 +285,11 @@ echo -e "${BLUE}Step 3: Updating ${CHANGELOG_FILE}...${NC}"
TODAY=$(date +%Y-%m-%d)
# Create new changelog entry
# Create new changelog entry from the generated notes (no placeholders)
NEW_ENTRY="## [${VERSION}] - ${TODAY}
### Added
- (Add new features here)
### Changed
- (Add changes here)
### Fixed
- (Add bug fixes here)
[${VERSION}]: ${GITEA_API_URL%/*}/Sovran_Systems/Sovran_SystemsOS/releases/tag/${TAG}
${RELEASE_NOTES}
[${VERSION}]: https://git.sovransystems.com/Sovran_Systems/Sovran_SystemsOS/releases/tag/${TAG}
"
# Prepend to changelog (after the header)
@@ -281,8 +358,8 @@ echo -e "${BLUE}Step 4: Creating GitHub Release...${NC}"
if command -v gh &>/dev/null; then
if gh release create "${TAG}" \
--repo naturallaw777/Sovran_SystemsOS \
--title "${TAG}" \
--notes "${RELEASE_MESSAGE}" \
--title "${TAG}${RELEASE_MESSAGE#Sovran_SystemsOS v* — }" \
--notes-file "${NOTES_FILE}" \
--target main 2>/dev/null; then
echo -e " ${GREEN}${NC} GitHub release created successfully"
else
@@ -313,16 +390,21 @@ fi
if [[ -n "${GITEA_TOKEN:-}" ]]; then
GITEA_REPO="Sovran_Systems/Sovran_SystemsOS"
# Build JSON payload safely (release body may contain quotes/newlines)
if command -v jq &>/dev/null; then
PAYLOAD=$(jq -n \
--arg tag "${TAG}" \
--arg name "${TAG} — Stable Release" \
--arg body "${RELEASE_BODY}" \
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')
else
PAYLOAD=$(python3 -c "import json,sys; print(json.dumps({'tag_name': sys.argv[1], 'name': sys.argv[1] + ' — Stable Release', 'body': open(sys.argv[2]).read(), 'draft': False, 'prerelease': False}))" "${TAG}" "${NOTES_FILE}")
fi
RESPONSE=$(curl -s -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"tag_name\": \"${TAG}\",
\"name\": \"${TAG}\",
\"body\": \"${RELEASE_MESSAGE}\",
\"draft\": false,
\"prerelease\": false
}" \
-d "${PAYLOAD}" \
"${GITEA_API_URL}/repos/${GITEA_REPO}/releases" 2>/dev/null || echo "")
if echo "$RESPONSE" | grep -q '"id"'; then
@@ -348,3 +430,6 @@ echo " • Verify releases on both GitHub and Gitea"
echo
echo -e "${CYAN}Tag created: ${TAG}${NC}"
git show "${TAG}" --quiet
# Clean up temp notes file
rm -f "${NOTES_FILE}"