Compare commits

...

3 Commits

Author SHA1 Message Date
516ce9c42c Add issue templates, CI workflows, and decentralization plan
Some checks failed
Go / build-and-release (push) Has been cancelled
- Add Gitea issue templates for bug reports and feature requests with
  structured YAML forms for version, database backend, and log level
- Add GitHub Actions CI workflow for automated testing on push/PR
- Add GitHub Actions release workflow for building multi-platform
  binaries on tag push with SHA256 checksums
- Add CONTRIBUTING.md with development setup, PR guidelines, and
  commit message format documentation
- Add DECENTRALIZE_NOSTR.md expansion plan outlining WireGuard tunnel,
  GUI installer, system tray, and proxy server architecture
- Update allowed commands in Claude settings
- Bump version to v0.35.5

Files modified:
- .gitea/issue_template/: Bug report, feature request, and config YAML
- .github/workflows/: CI and release automation workflows
- CONTRIBUTING.md: New contributor guide
- docs/plans/DECENTRALIZE_NOSTR.md: Expansion architecture plan
- .claude/settings.local.json: Updated allowed commands
- pkg/version/version: Version bump to v0.35.5

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 20:50:49 +01:00
ed95947971 Add release command and bump version to v0.35.4
Some checks failed
Go / build-and-release (push) Has been cancelled
- Add .claude/commands/release.md slash command for automated release
  workflow with version bumping, commit creation, tagging, and push
- Supports patch and minor version increments with proper validation
- Includes build verification step before committing
- Update settings.local.json with allowed commands from previous session
- Bump version from v0.35.3 to v0.35.4

Files modified:
- .claude/commands/release.md: New release automation command
- .claude/settings.local.json: Updated allowed commands
- pkg/version/version: Version bump to v0.35.4

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 19:50:13 +01:00
b58b91cd14 Add ORLY_POLICY_PATH for custom policy file location
Some checks failed
Go / build-and-release (push) Has been cancelled
- Add ORLY_POLICY_PATH environment variable to configure custom policy
  file path, overriding the default ~/.config/ORLY/policy.json location
- Enforce ABSOLUTE paths only - relay panics on startup if relative path
  is provided, preventing common misconfiguration errors
- Update PolicyManager to store and expose configPath for hot-reload saves
- Add ConfigPath() method to P struct delegating to internal PolicyManager
- Update NewWithManager() signature to accept optional custom path parameter
- Add BUG_REPORTS_AND_FEATURE_REQUEST_PROTOCOL.md with issue submission
  guidelines requiring environment details, reproduction steps, and logs
- Update README.md with system requirements (500MB minimum memory) and
  link to bug report protocol
- Update CLAUDE.md and README.md documentation for new ORLY_POLICY_PATH

Files modified:
- app/config/config.go: Add PolicyPath config field
- pkg/policy/policy.go: Add configPath storage and validation
- app/handle-policy-config.go: Use policyManager.ConfigPath()
- app/main.go: Pass cfg.PolicyPath to NewWithManager
- pkg/policy/*_test.go: Update test calls with new parameter
- BUG_REPORTS_AND_FEATURE_REQUEST_PROTOCOL.md: New file
- README.md, CLAUDE.md: Documentation updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 18:36:04 +01:00
25 changed files with 1265 additions and 20 deletions

View File

@@ -0,0 +1,50 @@
# Release Command
Review all changes in the repository and create a release with proper commit message, version tag, and push to remotes.
## Argument: $ARGUMENTS
The argument should be one of:
- `patch` - Bump the patch version (e.g., v0.35.3 -> v0.35.4)
- `minor` - Bump the minor version and reset patch to 0 (e.g., v0.35.3 -> v0.36.0)
If no argument provided, default to `patch`.
## Steps to perform:
1. **Read the current version** from `pkg/version/version`
2. **Calculate the new version** based on the argument:
- Parse the current version (format: vMAJOR.MINOR.PATCH)
- If `patch`: increment PATCH by 1
- If `minor`: increment MINOR by 1, set PATCH to 0
3. **Update the version file** (`pkg/version/version`) with the new version
4. **Review changes** using `git status` and `git diff --stat HEAD`
5. **Compose a commit message** following this format:
- First line: 72 chars max, imperative mood summary
- Blank line
- Bullet points describing each significant change
- "Files modified:" section listing affected files
- Footer with Claude Code attribution
6. **Stage all changes** with `git add -A`
7. **Create the commit** with the composed message
8. **Create a git tag** with the new version (e.g., `v0.36.0`)
9. **Push to remotes** (origin and gitea) with tags:
```
git push origin main --tags
git push gitea main --tags
```
10. **Report completion** with the new version and commit hash
## Important:
- Do NOT push to github remote (only origin and gitea)
- Always verify the build compiles before committing: `CGO_ENABLED=0 go build -o /dev/null ./...`
- If build fails, fix issues before proceeding

View File

@@ -116,7 +116,11 @@
"WebFetch(domain:eylenburg.github.io)",
"Bash(go run -exec '' -c 'package main; import \"\"git.mleku.dev/mleku/nostr/utils/normalize\"\"; import \"\"fmt\"\"; func main() { fmt.Println(string(normalize.URL([]byte(\"\"relay.example.com:3334\"\")))); fmt.Println(string(normalize.URL([]byte(\"\"relay.example.com:443\"\")))); fmt.Println(string(normalize.URL([]byte(\"\"ws://relay.example.com:3334\"\")))); fmt.Println(string(normalize.URL([]byte(\"\"wss://relay.example.com:3334\"\")))) }')",
"Bash(go run:*)",
"Bash(git commit -m \"$(cat <<''EOF''\nFix NIP-11 fetch URL scheme conversion for non-proxied relays\n\n- Convert wss:// to https:// and ws:// to http:// before fetching NIP-11\n documents, fixing failures for users not using HTTPS upgrade proxies\n- The fetchNIP11 function was using WebSocket URLs directly for HTTP\n requests, causing scheme mismatch errors\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n)\")"
"Bash(git commit -m \"$(cat <<''EOF''\nFix NIP-11 fetch URL scheme conversion for non-proxied relays\n\n- Convert wss:// to https:// and ws:// to http:// before fetching NIP-11\n documents, fixing failures for users not using HTTPS upgrade proxies\n- The fetchNIP11 function was using WebSocket URLs directly for HTTP\n requests, causing scheme mismatch errors\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n)\")",
"Bash(/tmp/orly help:*)",
"Bash(git commit -m \"$(cat <<''EOF''\nAdd ORLY_POLICY_PATH for custom policy file location\n\n- Add ORLY_POLICY_PATH environment variable to configure custom policy\n file path, overriding the default ~/.config/ORLY/policy.json location\n- Enforce ABSOLUTE paths only - relay panics on startup if relative path\n is provided, preventing common misconfiguration errors\n- Update PolicyManager to store and expose configPath for hot-reload saves\n- Add ConfigPath() method to P struct delegating to internal PolicyManager\n- Update NewWithManager() signature to accept optional custom path parameter\n- Add BUG_REPORTS_AND_FEATURE_REQUEST_PROTOCOL.md with issue submission\n guidelines requiring environment details, reproduction steps, and logs\n- Update README.md with system requirements (500MB minimum memory) and\n link to bug report protocol\n- Update CLAUDE.md and README.md documentation for new ORLY_POLICY_PATH\n\nFiles modified:\n- app/config/config.go: Add PolicyPath config field\n- pkg/policy/policy.go: Add configPath storage and validation\n- app/handle-policy-config.go: Use policyManager.ConfigPath()\n- app/main.go: Pass cfg.PolicyPath to NewWithManager\n- pkg/policy/*_test.go: Update test calls with new parameter\n- BUG_REPORTS_AND_FEATURE_REQUEST_PROTOCOL.md: New file\n- README.md, CLAUDE.md: Documentation updates\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n)\")",
"Bash(mkdir:*)",
"Bash(ssh:*)"
],
"deny": [],
"ask": []

View File

@@ -0,0 +1,118 @@
name: Bug Report
about: Report a bug or unexpected behavior in ORLY relay
title: "[BUG] "
labels:
- bug
body:
- type: markdown
attributes:
value: |
## Bug Report Guidelines
Thank you for taking the time to report a bug. Please fill out the form below to help us understand and reproduce the issue.
**Before submitting:**
- Search [existing issues](https://git.mleku.dev/mleku/next.orly.dev/issues) to avoid duplicates
- Check the [documentation](https://git.mleku.dev/mleku/next.orly.dev) for configuration guidance
- Ensure you're running a recent version of ORLY
- type: input
id: version
attributes:
label: ORLY Version
description: Run `./orly version` to get the version
placeholder: "v0.35.4"
validations:
required: true
- type: dropdown
id: database
attributes:
label: Database Backend
description: Which database backend are you using?
options:
- Badger (default)
- Neo4j
- WasmDB
validations:
required: true
- type: textarea
id: description
attributes:
label: Bug Description
description: A clear and concise description of the bug
placeholder: Describe what happened and what you expected to happen
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Steps to Reproduce
description: Detailed steps to reproduce the behavior
placeholder: |
1. Start relay with `./orly`
2. Connect with client X
3. Perform action Y
4. Observe error Z
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: What did you expect to happen?
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant Logs
description: |
Include relevant log output. Set `ORLY_LOG_LEVEL=debug` or `trace` for more detail.
This will be automatically formatted as code.
render: shell
- type: textarea
id: config
attributes:
label: Configuration
description: |
Relevant environment variables or configuration (redact sensitive values).
This will be automatically formatted as code.
render: shell
placeholder: |
ORLY_ACL_MODE=follows
ORLY_POLICY_ENABLED=true
ORLY_DB_TYPE=badger
- type: textarea
id: environment
attributes:
label: Environment
description: Operating system, Go version, etc.
placeholder: |
OS: Linux 6.8.0
Go: 1.25.3
Architecture: amd64
- type: textarea
id: additional
attributes:
label: Additional Context
description: Any other context, screenshots, or information that might help
- type: checkboxes
id: checklist
attributes:
label: Checklist
options:
- label: I have searched existing issues and this is not a duplicate
required: true
- label: I have included version information
required: true
- label: I have included steps to reproduce the issue
required: true

View File

@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Documentation
url: https://git.mleku.dev/mleku/next.orly.dev
about: Check the repository documentation before opening an issue
- name: Nostr Protocol (NIPs)
url: https://github.com/nostr-protocol/nips
about: For questions about Nostr protocol specifications

View File

@@ -0,0 +1,118 @@
name: Feature Request
about: Suggest a new feature or enhancement for ORLY relay
title: "[FEATURE] "
labels:
- enhancement
body:
- type: markdown
attributes:
value: |
## Feature Request Guidelines
Thank you for suggesting a feature. Please provide as much detail as possible to help us understand your proposal.
**Before submitting:**
- Search [existing issues](https://git.mleku.dev/mleku/next.orly.dev/issues) to avoid duplicates
- Check if this is covered by an existing [NIP](https://github.com/nostr-protocol/nips)
- Review the [documentation](https://git.mleku.dev/mleku/next.orly.dev) for current capabilities
- type: dropdown
id: category
attributes:
label: Feature Category
description: What area of ORLY does this feature relate to?
options:
- Protocol (NIP implementation)
- Database / Storage
- Performance / Optimization
- Policy / Access Control
- Web UI / Admin Interface
- Deployment / Operations
- API / Integration
- Documentation
- Other
validations:
required: true
- type: textarea
id: problem
attributes:
label: Problem Statement
description: |
What problem does this feature solve? Is this related to a frustration you have?
A clear problem statement helps us understand the motivation.
placeholder: "I'm always frustrated when..."
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: |
Describe the solution you'd like. Be specific about expected behavior.
placeholder: "I would like ORLY to..."
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: |
Describe any alternative solutions or workarounds you've considered.
placeholder: "I've tried X but it doesn't work because..."
- type: input
id: nip
attributes:
label: Related NIP
description: If this relates to a Nostr Implementation Possibility, provide the NIP number
placeholder: "NIP-XX"
- type: dropdown
id: impact
attributes:
label: Scope of Impact
description: How significant is this feature?
options:
- Minor enhancement (small quality-of-life improvement)
- Moderate feature (adds useful capability)
- Major feature (significant new functionality)
- Breaking change (requires migration or config changes)
validations:
required: true
- type: dropdown
id: contribution
attributes:
label: Willingness to Contribute
description: Would you be willing to help implement this feature?
options:
- "Yes, I can submit a PR"
- "Yes, I can help with testing"
- "No, but I can provide more details"
- "No"
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional Context
description: |
Any other context, mockups, examples, or references that help explain the feature.
For protocol features, include example event structures or message flows if applicable.
- type: checkboxes
id: checklist
attributes:
label: Checklist
options:
- label: I have searched existing issues and this is not a duplicate
required: true
- label: I have described the problem this feature solves
required: true
- label: I have checked if this relates to an existing NIP
required: false

53
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,53 @@
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Download libsecp256k1
run: |
wget -q https://git.mleku.dev/mleku/nostr/raw/branch/main/crypto/p8k/libsecp256k1.so -O libsecp256k1.so
chmod +x libsecp256k1.so
- name: Run tests
run: |
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(pwd)"
CGO_ENABLED=0 go test ./...
- name: Build binary
run: |
CGO_ENABLED=0 go build -o orly .
./orly version
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Check go mod tidy
run: |
go mod tidy
git diff --exit-code go.mod go.sum
- name: Run go vet
run: CGO_ENABLED=0 go vet ./...

154
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,154 @@
name: Release
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- goos: linux
goarch: amd64
platform: linux-amd64
ext: ""
lib: libsecp256k1.so
- goos: linux
goarch: arm64
platform: linux-arm64
ext: ""
lib: libsecp256k1.so
- goos: darwin
goarch: amd64
platform: darwin-amd64
ext: ""
lib: libsecp256k1.dylib
- goos: darwin
goarch: arm64
platform: darwin-arm64
ext: ""
lib: libsecp256k1.dylib
- goos: windows
goarch: amd64
platform: windows-amd64
ext: ".exe"
lib: libsecp256k1.dll
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install bun
run: |
curl -fsSL https://bun.sh/install | bash
echo "$HOME/.bun/bin" >> $GITHUB_PATH
- name: Build Web UI
run: |
cd app/web
$HOME/.bun/bin/bun install
$HOME/.bun/bin/bun run build
- name: Get version
id: version
run: echo "version=$(cat pkg/version/version)" >> $GITHUB_OUTPUT
- name: Build binary
env:
CGO_ENABLED: 0
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
run: |
VERSION=${{ steps.version.outputs.version }}
OUTPUT="orly-${VERSION}-${{ matrix.platform }}${{ matrix.ext }}"
go build -ldflags "-s -w -X main.version=${VERSION}" -o ${OUTPUT} .
sha256sum ${OUTPUT} > ${OUTPUT}.sha256
- name: Download runtime library
run: |
VERSION=${{ steps.version.outputs.version }}
LIB="${{ matrix.lib }}"
wget -q "https://git.mleku.dev/mleku/nostr/raw/branch/main/crypto/p8k/${LIB}" -O "${LIB}" || true
if [ -f "${LIB}" ]; then
sha256sum "${LIB}" > "${LIB}.sha256"
fi
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: orly-${{ matrix.platform }}
path: |
orly-*
libsecp256k1*
release:
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Get version
id: version
run: echo "version=$(cat pkg/version/version)" >> $GITHUB_OUTPUT
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: Create combined checksums
run: |
cd artifacts
cat *.sha256 | sort -k2 > SHA256SUMS.txt
rm -f *.sha256
- name: List release files
run: ls -la artifacts/
- name: Create Release
uses: softprops/action-gh-release@v1
with:
name: ORLY ${{ steps.version.outputs.version }}
body: |
## ORLY ${{ steps.version.outputs.version }}
### Downloads
Download the appropriate binary for your platform. The `libsecp256k1` library is optional but recommended for better cryptographic performance.
### Installation
1. Download the binary for your platform
2. (Optional) Download the corresponding `libsecp256k1` library
3. Place both files in the same directory
4. Make the binary executable: `chmod +x orly-*`
5. Run: `./orly-*-linux-amd64` (or your platform's binary)
### Verify Downloads
```bash
sha256sum -c SHA256SUMS.txt
```
### Configuration
See the [repository documentation](https://git.mleku.dev/mleku/next.orly.dev) for configuration options.
files: |
artifacts/*
draft: false
prerelease: false

View File

@@ -0,0 +1,254 @@
# Feature Request and Bug Report Protocol
This document describes how to submit effective bug reports and feature requests for ORLY relay. Following these guidelines helps maintainers understand and resolve issues quickly.
## Before Submitting
1. **Search existing issues** - Your issue may already be reported or discussed
2. **Check documentation** - Review `CLAUDE.md`, `docs/`, and `pkg/*/README.md` files
3. **Verify with latest version** - Ensure the issue exists in the current release
4. **Test with default configuration** - Rule out configuration-specific problems
## Bug Reports
### Required Information
**Title**: Concise summary of the problem
- Good: "Kind 3 events with 8000+ follows truncated on save"
- Bad: "Events not saving" or "Bug in database"
**Environment**:
```
ORLY version: (output of ./orly version)
OS: (e.g., Ubuntu 24.04, macOS 14.2)
Go version: (output of go version)
Database backend: (badger/neo4j/wasmdb)
```
**Configuration** (relevant settings only):
```bash
ORLY_DB_TYPE=badger
ORLY_POLICY_ENABLED=true
# Include any non-default settings
```
**Steps to Reproduce**:
1. Start relay with configuration X
2. Connect client and send event Y
3. Query for event with filter Z
4. Observe error/unexpected behavior
**Expected Behavior**: What should happen
**Actual Behavior**: What actually happens
**Logs**: Include relevant log output with `ORLY_LOG_LEVEL=debug` or `trace`
### Minimal Reproduction
The most effective bug reports include a minimal reproduction case:
```bash
# Example: Script that demonstrates the issue
export ORLY_LOG_LEVEL=debug
./orly &
sleep 2
# Send problematic event
echo '["EVENT", {...}]' | websocat ws://localhost:3334
# Show the failure
echo '["REQ", "test", {"kinds": [1]}]' | websocat ws://localhost:3334
```
Or provide a failing test case:
```go
func TestReproduceBug(t *testing.T) {
// Setup
db := setupTestDB(t)
// This should work but fails
event := createTestEvent(kind, content)
err := db.SaveEvent(ctx, event)
require.NoError(t, err)
// Query returns unexpected result
results, err := db.QueryEvents(ctx, filter)
assert.Len(t, results, 1) // Fails: got 0
}
```
## Feature Requests
### Required Information
**Title**: Clear description of the feature
- Good: "Add WebSocket compression support (permessage-deflate)"
- Bad: "Make it faster" or "New feature idea"
**Problem Statement**: What problem does this solve?
```
Currently, clients with high-latency connections experience slow sync times
because event data is transmitted uncompressed. A typical session transfers
50MB of JSON that could be reduced to ~10MB with compression.
```
**Proposed Solution**: How should it work?
```
Add optional permessage-deflate WebSocket extension support:
- New config: ORLY_WS_COMPRESSION=true
- Negotiate compression during WebSocket handshake
- Apply to messages over configurable threshold (default 1KB)
```
**Use Case**: Who benefits and how?
```
- Mobile clients on cellular connections
- Users syncing large follow lists
- Relays with bandwidth constraints
```
**Alternatives Considered** (optional):
```
- Application-level compression: Rejected because it requires client changes
- HTTP/2: Not applicable for WebSocket connections
```
### Implementation Notes (optional)
If you have implementation ideas:
```
Suggested approach:
1. Add compression config to app/config/config.go
2. Modify gorilla/websocket upgrader in app/handle-websocket.go
3. Add compression threshold check before WriteMessage()
Reference: gorilla/websocket has built-in permessage-deflate support
```
## What Makes Reports Effective
**Do**:
- Be specific and factual
- Include version numbers and exact error messages
- Provide reproducible steps
- Attach relevant logs (redact sensitive data)
- Link to related issues or discussions
- Respond to follow-up questions promptly
**Avoid**:
- Vague descriptions ("it doesn't work")
- Multiple unrelated issues in one report
- Assuming the cause without evidence
- Demanding immediate fixes
- Duplicating existing issues
## Issue Labels
When applicable, suggest appropriate labels:
| Label | Use When |
|-------|----------|
| `bug` | Something isn't working as documented |
| `enhancement` | New feature or improvement |
| `performance` | Speed or resource usage issue |
| `documentation` | Docs are missing or incorrect |
| `question` | Clarification needed (not a bug) |
| `good first issue` | Suitable for new contributors |
## Response Expectations
- **Acknowledgment**: Within a few days
- **Triage**: Issue labeled and prioritized
- **Resolution**: Depends on complexity and priority
Complex features may require discussion before implementation. Bug fixes for critical issues are prioritized.
## Following Up
If your issue hasn't received attention:
1. **Check issue status** - It may be labeled or assigned
2. **Add new information** - If you've discovered more details
3. **Politely bump** - A single follow-up comment after 2 weeks is appropriate
4. **Consider contributing** - PRs that fix bugs or implement features are welcome
## Contributing Fixes
If you want to fix a bug or implement a feature yourself:
1. Comment on the issue to avoid duplicate work
2. Follow the coding patterns in `CLAUDE.md`
3. Include tests for your changes
4. Keep PRs focused on a single issue
5. Reference the issue number in your PR
## Security Issues
**Do not report security vulnerabilities in public issues.**
For security-sensitive bugs:
- Contact maintainers directly
- Provide detailed reproduction steps privately
- Allow reasonable time for a fix before disclosure
## Examples
### Good Bug Report
```markdown
## WebSocket disconnects after 60 seconds of inactivity
**Environment**:
- ORLY v0.34.5
- Ubuntu 22.04
- Go 1.25.3
- Badger backend
**Steps to Reproduce**:
1. Connect to relay: `websocat ws://localhost:3334`
2. Send subscription: `["REQ", "test", {"kinds": [1], "limit": 1}]`
3. Wait 60 seconds without sending messages
4. Observe connection closed
**Expected**: Connection remains open (Nostr relays should maintain persistent connections)
**Actual**: Connection closed with code 1000 after exactly 60 seconds
**Logs** (ORLY_LOG_LEVEL=debug):
```
1764783029014485🔎 client timeout, closing connection /app/handle-websocket.go:142
```
**Possible Cause**: May be related to read deadline not being extended on subscription activity
```
### Good Feature Request
```markdown
## Add rate limiting per pubkey
**Problem**:
A single pubkey can flood the relay with events, consuming storage and
bandwidth. Currently there's no way to limit per-author submission rate.
**Proposed Solution**:
Add configurable rate limiting:
```bash
ORLY_RATE_LIMIT_EVENTS_PER_MINUTE=60
ORLY_RATE_LIMIT_BURST=10
```
When exceeded, return OK false with "rate-limited" message per NIP-20.
**Use Case**:
- Public relays protecting against spam
- Community relays with fair-use policies
- Paid relays enforcing subscription tiers
**Alternatives Considered**:
- IP-based limiting: Ineffective because users share IPs and use VPNs
- Global limiting: Punishes all users for one bad actor
```

View File

@@ -147,6 +147,10 @@ export ORLY_SPROCKET_ENABLED=true
# Enable policy system
export ORLY_POLICY_ENABLED=true
# Custom policy file path (MUST be ABSOLUTE path starting with /)
# Default: ~/.config/ORLY/policy.json (or ~/.config/{ORLY_APP_NAME}/policy.json)
# export ORLY_POLICY_PATH=/etc/orly/policy.json
# Database backend selection (badger, neo4j, or wasmdb)
export ORLY_DB_TYPE=badger
@@ -270,7 +274,8 @@ export ORLY_AUTH_TO_WRITE=false # Require auth only for writes
- `none.go` - Open relay (no restrictions)
**`pkg/policy/`** - Event filtering and validation policies
- Policy configuration loaded from `~/.config/ORLY/policy.json`
- Policy configuration loaded from `~/.config/ORLY/policy.json` by default
- Custom path via `ORLY_POLICY_PATH` (MUST be absolute path starting with `/`)
- Per-kind size limits, age restrictions, custom scripts
- **Write-Only Validation**: Size, age, tag, and expiry validations apply ONLY to write operations
- **Read-Only Filtering**: `read_allow`, `read_deny`, `privileged` apply ONLY to read operations

101
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,101 @@
# Contributing to ORLY
Thank you for your interest in contributing to ORLY! This document outlines the process for reporting bugs, requesting features, and submitting contributions.
**Canonical Repository:** https://git.mleku.dev/mleku/next.orly.dev
## Issue Reporting Policy
### Before Opening an Issue
1. **Search existing issues** to avoid duplicates
2. **Check the documentation** in the repository
3. **Verify your version** - run `./orly version` and ensure you're on a recent release
4. **Review the CLAUDE.md** file for configuration guidance
### Bug Reports
Use the **Bug Report** template when reporting unexpected behavior. A good bug report includes:
- **Version information** - exact ORLY version from `./orly version`
- **Database backend** - Badger, Neo4j, or WasmDB
- **Clear description** - what happened vs. what you expected
- **Reproduction steps** - detailed steps to trigger the bug
- **Logs** - relevant log output (use `ORLY_LOG_LEVEL=debug` or `trace`)
- **Configuration** - relevant environment variables (redact secrets)
#### Log Levels for Debugging
```bash
export ORLY_LOG_LEVEL=trace # Most verbose
export ORLY_LOG_LEVEL=debug # Development debugging
export ORLY_LOG_LEVEL=info # Default
```
### Feature Requests
Use the **Feature Request** template when suggesting new functionality. A good feature request includes:
- **Problem statement** - what problem does this solve?
- **Proposed solution** - specific description of desired behavior
- **Alternatives considered** - workarounds you've tried
- **Related NIP** - if this implements a Nostr protocol specification
- **Impact assessment** - is this a minor tweak or major change?
#### Feature Categories
- **Protocol** - NIP implementations and Nostr protocol features
- **Database** - Storage backends, indexing, query optimization
- **Performance** - Caching, SIMD operations, memory optimization
- **Policy** - Access control, event filtering, validation
- **Web UI** - Admin interface improvements
- **Operations** - Deployment, monitoring, systemd integration
## Code Contributions
### Development Setup
```bash
# Clone the repository
git clone https://git.mleku.dev/mleku/next.orly.dev.git
cd next.orly.dev
# Build
CGO_ENABLED=0 go build -o orly
# Run tests
./scripts/test.sh
# Build with web UI
./scripts/update-embedded-web.sh
```
### Pull Request Guidelines
1. **One feature/fix per PR** - keep changes focused
2. **Write tests** - for new functionality and bug fixes
3. **Follow existing patterns** - match the code style of surrounding code
4. **Update documentation** - if your change affects configuration or behavior
5. **Test your changes** - run `./scripts/test.sh` before submitting
### Commit Message Format
```
Short summary (72 chars max, imperative mood)
- Bullet point describing change 1
- Bullet point describing change 2
Files modified:
- path/to/file1.go: Description of change
- path/to/file2.go: Description of change
```
## Communication
- **Issues:** https://git.mleku.dev/mleku/next.orly.dev/issues
- **Documentation:** https://git.mleku.dev/mleku/next.orly.dev
## License
By contributing to ORLY, you agree that your contributions will be licensed under the same license as the project.

View File

@@ -1,5 +1,7 @@
# next.orly.dev
---
![orly.dev](./docs/orly.png)
![Version v0.24.1](https://img.shields.io/badge/version-v0.24.1-blue.svg)
@@ -10,6 +12,19 @@ zap me: <20>mlekudev@getalby.com
follow me on [nostr](https://jumble.social/users/npub1fjqqy4a93z5zsjwsfxqhc2764kvykfdyttvldkkkdera8dr78vhsmmleku)
## ⚠️ Bug Reports & Feature Requests
**Bug reports and feature requests that do not follow the protocol will not be accepted.**
Before submitting any issue, you must read and follow [BUG_REPORTS_AND_FEATURE_REQUEST_PROTOCOL.md](./BUG_REPORTS_AND_FEATURE_REQUEST_PROTOCOL.md).
Requirements:
- **Bug reports**: Include environment details, reproduction steps, expected/actual behavior, and logs
- **Feature requests**: Include problem statement, proposed solution, and use cases
- **Both**: Search existing issues first, verify with latest version, provide minimal reproduction
Issues missing required information will be closed without review.
## ⚠️ System Requirements
> **IMPORTANT: ORLY requires a minimum of 500MB of free memory to operate.**
@@ -217,7 +232,12 @@ ORLY includes a comprehensive policy system for fine-grained control over event
```bash
export ORLY_POLICY_ENABLED=true
# Create policy file at ~/.config/ORLY/policy.json
# Default policy file: ~/.config/ORLY/policy.json
# OPTIONAL: Use a custom policy file location
# WARNING: ORLY_POLICY_PATH MUST be an ABSOLUTE path (starting with /)
# Relative paths will be REJECTED and the relay will fail to start
export ORLY_POLICY_PATH=/etc/orly/policy.json
```
For detailed configuration and examples, see the [Policy Usage Guide](docs/POLICY_USAGE_GUIDE.md).

View File

@@ -82,7 +82,8 @@ type C struct {
DirectorySpiderInterval time.Duration `env:"ORLY_DIRECTORY_SPIDER_INTERVAL" default:"24h" usage:"how often to run directory spider"`
DirectorySpiderMaxHops int `env:"ORLY_DIRECTORY_SPIDER_HOPS" default:"3" usage:"maximum hops for relay discovery from seed users"`
PolicyEnabled bool `env:"ORLY_POLICY_ENABLED" default:"false" usage:"enable policy-based event processing (configuration found in $HOME/.config/ORLY/policy.json)"`
PolicyEnabled bool `env:"ORLY_POLICY_ENABLED" default:"false" usage:"enable policy-based event processing (default config: $HOME/.config/ORLY/policy.json)"`
PolicyPath string `env:"ORLY_POLICY_PATH" usage:"ABSOLUTE path to policy configuration file (MUST start with /); overrides default location; relative paths are rejected"`
// NIP-43 Relay Access Metadata and Requests
NIP43Enabled bool `env:"ORLY_NIP43_ENABLED" default:"false" usage:"enable NIP-43 relay access metadata and invite system"`

View File

@@ -3,9 +3,7 @@ package app
import (
"bytes"
"fmt"
"path/filepath"
"github.com/adrg/xdg"
"lol.mleku.dev/log"
"git.mleku.dev/mleku/nostr/encoders/event"
"git.mleku.dev/mleku/nostr/encoders/filter"
@@ -76,8 +74,8 @@ func (l *Listener) HandlePolicyConfigUpdate(ev *event.E) error {
log.I.F("policy config validation passed")
// Get config path for saving
configPath := filepath.Join(xdg.ConfigHome, l.Config.AppName, "policy.json")
// Get config path for saving (uses custom path if set, otherwise default)
configPath := l.policyManager.ConfigPath()
// 3. Pause ALL message processing (lock mutex)
// Note: We need to release the RLock first (which caller holds), then acquire exclusive Lock

View File

@@ -74,7 +74,7 @@ func setupPolicyTestListener(t *testing.T, policyAdminHex string) (*Listener, *d
}
// Create policy manager - now config file exists at XDG path
policyManager := policy.NewWithManager(ctx, cfg.AppName, cfg.PolicyEnabled)
policyManager := policy.NewWithManager(ctx, cfg.AppName, cfg.PolicyEnabled, "")
server := &Server{
Ctx: ctx,

View File

@@ -87,7 +87,7 @@ func Run(
l.sprocketManager = NewSprocketManager(ctx, cfg.AppName, cfg.SprocketEnabled)
// Initialize policy manager
l.policyManager = policy.NewWithManager(ctx, cfg.AppName, cfg.PolicyEnabled)
l.policyManager = policy.NewWithManager(ctx, cfg.AppName, cfg.PolicyEnabled, cfg.PolicyPath)
// Merge policy-defined owners with environment-defined owners
// This allows cloud deployments to add owners via policy.json when env vars cannot be modified

View File

@@ -0,0 +1,325 @@
# ORLY Expansion Plan: Documentation, Installer, Tray, and WireGuard
## Overview
Expand ORLY from a relay binary into a complete ecosystem for personal Nostr relay deployment, with:
1. **Textbook-style README** - Progressive documentation from novice to expert
2. **GUI Installer** - Wails-based setup wizard (Linux + macOS)
3. **System Tray** - Service monitoring and control
4. **WireGuard Client** - Embedded tunnel for NAT traversal
5. **Proxy Server** - Self-hostable AND managed service option
---
## Architecture
```
USER SYSTEMS
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ orly-setup │ │ orly │ │ orly --tray │ │
│ │ (Installer) │ │ (Relay) │ │ (Systray) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ │ generates │ serves │ monitors │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ ~/.config/ │ │ :3334 WS/HTTP│ │ /api/admin/* │ │
│ │ systemd svc │ │ + WG tunnel │ │ status/ctrl │ │
│ └──────────────┘ └──────┬───────┘ └──────────────┘ │
│ │ │
│ ┌───────┴───────┐ │
│ │ pkg/tunnel/ │ │
│ │ WireGuard │ │
│ └───────┬───────┘ │
└─────────────────────────────┼───────────────────────────────────────┘
│ WG Tunnel (UDP :51820)
┌─────────────────────────────────────────────────────────────────────┐
│ PROXY SERVER │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ WG Server │───▶│ Nostr Auth │───▶│ Public Proxy │ │
│ │ :51820 │ │ (npub-based) │ │ Egress │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
---
## Package Structure
```
next.orly.dev/
├── cmd/
│ ├── orly-setup/ # NEW: Wails installer
│ │ ├── main.go
│ │ ├── app.go # Backend logic
│ │ ├── frontend/ # Svelte wizard UI
│ │ │ └── src/steps/ # Welcome, Config, Install, Complete
│ │ └── install/
│ │ ├── preflight.go # Dependency checks
│ │ ├── systemd.go # Service creation
│ │ └── verify.go # Post-install checks
│ │
│ └── proxy-server/ # NEW: WireGuard proxy
│ ├── main.go
│ ├── server.go # WG server
│ ├── auth.go # Nostr auth
│ └── registry.go # User management
├── pkg/
│ ├── tunnel/ # NEW: Embedded WG client
│ │ ├── tunnel.go # Main interface
│ │ ├── client.go # wireguard-go wrapper
│ │ ├── reconnect.go # Auto-reconnect
│ │ └── health.go # Connection health
│ │
│ ├── tray/ # NEW: System tray
│ │ ├── tray.go # Platform abstraction
│ │ ├── tray_linux.go # Linux implementation
│ │ ├── tray_darwin.go # macOS implementation
│ │ └── menu.go # Menu construction
│ │
│ ├── admin/ # NEW: Admin HTTP API
│ │ ├── api.go # Router
│ │ ├── status.go # GET /api/admin/status
│ │ ├── control.go # POST /api/admin/start|stop|restart
│ │ └── logs.go # GET /api/admin/logs (SSE)
│ │
│ └── interfaces/
│ ├── tunnel/tunnel.go # Tunnel interface
│ ├── tray/tray.go # Tray interface
│ └── admin/admin.go # Admin API interface
└── docs/
└── README.adoc # NEW: Textbook-style docs
```
---
## Implementation Phases
### Phase 1: Documentation Foundation
**Files to create/modify:**
- `README.adoc` - New textbook-style documentation
- `docs/` - Reorganize scattered docs
**README Structure (Textbook Style):**
```
Chapter 1: Quick Start (5-minute setup)
Chapter 2: Installation (platform-specific)
Chapter 3: Configuration (all env vars)
Chapter 4: Operations (systemd, monitoring)
Chapter 5: Security (TLS, ACLs, policy)
Chapter 6: Advanced (Neo4j, clustering, WoT)
Chapter 7: Architecture (internals)
Appendices: Reference tables, troubleshooting
```
### Phase 2: Admin API
**Files to create:**
- `pkg/admin/api.go` - Router and middleware
- `pkg/admin/status.go` - Status endpoint
- `pkg/admin/control.go` - Start/stop/restart
- `pkg/admin/logs.go` - Log streaming via SSE
- `pkg/interfaces/admin/admin.go` - Interface definition
**Files to modify:**
- `app/server.go` - Register `/api/admin/*` routes
- `app/config/config.go` - Add admin API config
**Endpoints:**
```
GET /api/admin/status - Relay status, uptime, connections
POST /api/admin/start - Start relay (when in tray mode)
POST /api/admin/stop - Graceful shutdown
POST /api/admin/restart - Graceful restart
GET /api/admin/logs - SSE log stream
```
### Phase 3: System Tray
**Files to create:**
- `pkg/tray/tray.go` - Platform abstraction
- `pkg/tray/tray_linux.go` - Linux (dbus/appindicator)
- `pkg/tray/tray_darwin.go` - macOS (NSStatusBar)
- `pkg/tray/menu.go` - Menu construction
- `pkg/interfaces/tray/tray.go` - Interface
**Files to modify:**
- `main.go` - Add `--tray` flag handling
- `app/config/config.go` - Add tray config
**Features:**
- Status icon (green/yellow/red)
- Start/Stop/Restart menu items
- Open Web UI (launches browser)
- View Logs submenu
- Auto-start on login toggle
### Phase 4: Installer GUI (Wails)
**Files to create:**
- `cmd/orly-setup/main.go` - Wails entry point
- `cmd/orly-setup/app.go` - Backend methods
- `cmd/orly-setup/frontend/` - Svelte wizard
- `cmd/orly-setup/install/preflight.go` - Dependency checks
- `cmd/orly-setup/install/systemd.go` - Service creation
- `cmd/orly-setup/install/config.go` - Config generation
- `cmd/orly-setup/install/verify.go` - Post-install checks
- `scripts/build-installer.sh` - Build script
**Wizard Steps:**
1. Welcome - Introduction, license
2. Preflight - Check Go, disk, ports
3. Configuration - Port, data dir, TLS domains
4. Admin Setup - Generate or import admin keys
5. Database - Choose Badger or Neo4j
6. WireGuard (optional) - Tunnel config
7. Installation - Create service, start relay
8. Complete - Verify and show status
### Phase 5: WireGuard Client
**Files to create:**
- `pkg/tunnel/tunnel.go` - Main interface
- `pkg/tunnel/client.go` - wireguard-go wrapper
- `pkg/tunnel/config.go` - WG configuration
- `pkg/tunnel/reconnect.go` - Auto-reconnect logic
- `pkg/tunnel/health.go` - Health monitoring
- `pkg/tunnel/handoff.go` - Graceful restart
- `pkg/interfaces/tunnel/tunnel.go` - Interface
**Files to modify:**
- `app/config/config.go` - Add WG config fields
- `app/main.go` - Initialize tunnel on startup
- `main.go` - Tunnel lifecycle management
**Config additions:**
```go
WGEnabled bool `env:"ORLY_WG_ENABLED" default:"false"`
WGServer string `env:"ORLY_WG_SERVER"`
WGPrivateKey string `env:"ORLY_WG_PRIVATE_KEY"`
WGServerPubKey string `env:"ORLY_WG_PUBLIC_KEY"`
WGKeepalive int `env:"ORLY_WG_KEEPALIVE" default:"25"`
WGMTU int `env:"ORLY_WG_MTU" default:"1280"`
WGReconnect bool `env:"ORLY_WG_RECONNECT" default:"true"`
```
### Phase 6: Proxy Server
**Files to create:**
- `cmd/proxy-server/main.go` - Entry point
- `cmd/proxy-server/server.go` - WG server management
- `cmd/proxy-server/auth.go` - Nostr-based auth
- `cmd/proxy-server/registry.go` - User/relay registry
- `cmd/proxy-server/bandwidth.go` - Traffic monitoring
- `cmd/proxy-server/config.go` - Server configuration
**Features:**
- WireGuard server (wireguard-go)
- Nostr event-based authentication (NIP-98 style)
- User registration via signed events
- Relay discovery and assignment
- Bandwidth monitoring and quotas
- Multi-tenant isolation
---
## Key Interfaces
### Tunnel Interface
```go
type Tunnel interface {
Connect(ctx context.Context) error
Disconnect() error
Status() TunnelStatus
Handoff() (*HandoffState, error)
Resume(state *HandoffState) error
}
```
### Admin API Interface
```go
type AdminAPI interface {
Status() (*RelayStatus, error)
Start() error
Stop() error
Restart() error
Logs(ctx context.Context, lines int) (<-chan LogEntry, error)
}
```
### Tray Interface
```go
type TrayApp interface {
Run() error
Quit()
UpdateStatus(status StatusLevel, tooltip string)
ShowNotification(title, message string)
}
```
---
## Dependencies to Add
```go
// go.mod additions
require (
github.com/wailsapp/wails/v2 v2.x.x // Installer GUI
golang.zx2c4.com/wireguard v0.x.x // WireGuard client
github.com/getlantern/systray v1.x.x // System tray (or fyne.io/systray)
)
```
---
## Build Commands
```bash
# Standard relay build (unchanged)
CGO_ENABLED=0 go build -o orly
# Relay with tray support
CGO_ENABLED=0 go build -tags tray -o orly
# Installer GUI
cd cmd/orly-setup && wails build -platform linux/amd64,darwin/amd64
# Proxy server
CGO_ENABLED=0 go build -o orly-proxy ./cmd/proxy-server
# All platforms
./scripts/build-all.sh
```
---
## Critical Files Reference
| File | Purpose |
|------|---------|
| `app/config/config.go` | Add WG, tray, admin API config |
| `app/server.go` | Register admin API routes |
| `main.go` | Add --tray flag, WG initialization |
| `scripts/deploy.sh` | Pattern for installer service creation |
| `app/web/src/App.svelte` | Pattern for installer UI |
---
## Backward Compatibility
- Main `orly` binary behavior unchanged without flags
- All new features opt-in via environment variables
- WireGuard gracefully degrades if connection fails
- Tray mode only activates with `--tray` flag
- Admin API can be disabled via `ORLY_ADMIN_API_ENABLED=false`
---
## Success Criteria
1. New user can install via GUI wizard in < 5 minutes
2. README guides user from zero to running relay
3. System tray provides one-click relay management
4. WireGuard tunnel auto-connects and reconnects
5. Proxy server enables home relay exposure without port forwarding
6. All existing functionality preserved

4
go.sum
View File

@@ -1,5 +1,5 @@
git.mleku.dev/mleku/nostr v1.0.8 h1:YYREdIxobEqYkzxQ7/5ALACPzLkiHW+CTira+VvSQZk=
git.mleku.dev/mleku/nostr v1.0.8/go.mod h1:iYTlg2WKJXJ0kcsM6QBGOJ0UDiJidMgL/i64cHyPjZc=
git.mleku.dev/mleku/nostr v1.0.9 h1:aiN0ihnXzEpboXjW4u8qr5XokLQqg4P0XSZ1Y273qM0=
git.mleku.dev/mleku/nostr v1.0.9/go.mod h1:iYTlg2WKJXJ0kcsM6QBGOJ0UDiJidMgL/i64cHyPjZc=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/ImVexed/fasturl v0.0.0-20230304231329-4e41488060f3 h1:ClzzXMDDuUbWfNNZqGeYq4PnYOlwlOVIvSyNaIy0ykg=

View File

@@ -96,7 +96,7 @@ func TestBugReproduction_WithPolicyManager(t *testing.T) {
// Create policy with manager (enabled)
ctx := context.Background()
policy := NewWithManager(ctx, "ORLY", true)
policy := NewWithManager(ctx, "ORLY", true, "")
// Load policy from file
if err := policy.LoadFromFile(policyPath); err != nil {

View File

@@ -31,7 +31,7 @@ func setupTestPolicy(t *testing.T, appName string) (*P, func()) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
policy := NewWithManager(ctx, appName, true)
policy := NewWithManager(ctx, appName, true, "")
if policy == nil {
cancel()
os.RemoveAll(configDir)

View File

@@ -29,7 +29,7 @@ func setupHotreloadTestPolicy(t *testing.T, appName string) (*P, func()) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
policy := NewWithManager(ctx, appName, true)
policy := NewWithManager(ctx, appName, true, "")
if policy == nil {
cancel()
os.RemoveAll(configDir)

View File

@@ -514,12 +514,19 @@ type PolicyManager struct {
ctx context.Context
cancel context.CancelFunc
configDir string
configPath string // Path to policy.json file
scriptPath string // Default script path for backward compatibility
enabled bool
mutex sync.RWMutex
runners map[string]*ScriptRunner // Map of script path -> runner
}
// ConfigPath returns the path to the policy configuration file.
// This is used by hot-reload handlers to know where to save updated policy.
func (pm *PolicyManager) ConfigPath() string {
return pm.configPath
}
// P represents a complete policy configuration for a Nostr relay.
// It defines access control rules, kind filtering, and default behavior.
// Policies are evaluated in order: global rules, kind filtering, specific rules, then default policy.
@@ -695,6 +702,15 @@ func (p *P) IsEnabled() bool {
return p != nil && p.manager != nil && p.manager.IsEnabled()
}
// ConfigPath returns the path to the policy configuration file.
// Delegates to the internal PolicyManager.
func (p *P) ConfigPath() string {
if p == nil || p.manager == nil {
return ""
}
return p.manager.ConfigPath()
}
// getDefaultPolicyAction returns true if the default policy is "allow", false if "deny"
func (p *P) getDefaultPolicyAction() (allowed bool) {
switch p.DefaultPolicy {
@@ -711,10 +727,29 @@ func (p *P) getDefaultPolicyAction() (allowed bool) {
// NewWithManager creates a new policy with a policy manager for script execution.
// It initializes the policy manager, loads configuration from files, and starts
// background processes for script management and periodic health checks.
func NewWithManager(ctx context.Context, appName string, enabled bool) *P {
//
// The customPolicyPath parameter allows overriding the default policy file location.
// If empty, uses the default path: $HOME/.config/{appName}/policy.json
// If provided, it MUST be an absolute path (starting with /) or the function will panic.
func NewWithManager(ctx context.Context, appName string, enabled bool, customPolicyPath string) *P {
configDir := filepath.Join(xdg.ConfigHome, appName)
scriptPath := filepath.Join(configDir, "policy.sh")
configPath := filepath.Join(configDir, "policy.json")
// Determine the policy config path
var configPath string
if customPolicyPath != "" {
// Validate that custom path is absolute
if !filepath.IsAbs(customPolicyPath) {
panic(fmt.Sprintf("FATAL: ORLY_POLICY_PATH must be an ABSOLUTE path (starting with /), got: %q", customPolicyPath))
}
configPath = customPolicyPath
// Update configDir to match the custom path's directory for script resolution
configDir = filepath.Dir(customPolicyPath)
scriptPath = filepath.Join(configDir, "policy.sh")
log.I.F("using custom policy path: %s", configPath)
} else {
configPath = filepath.Join(configDir, "policy.json")
}
ctx, cancel := context.WithCancel(ctx)
@@ -722,6 +757,7 @@ func NewWithManager(ctx context.Context, appName string, enabled bool) *P {
ctx: ctx,
cancel: cancel,
configDir: configDir,
configPath: configPath,
scriptPath: scriptPath,
enabled: enabled,
runners: make(map[string]*ScriptRunner),

View File

@@ -825,7 +825,7 @@ func TestNewWithManager(t *testing.T) {
// Test with disabled policy (doesn't require policy.json file)
t.Run("disabled policy", func(t *testing.T) {
enabled := false
policy := NewWithManager(ctx, appName, enabled)
policy := NewWithManager(ctx, appName, enabled, "")
if policy == nil {
t.Fatal("Expected policy but got nil")

View File

@@ -31,7 +31,7 @@ func setupTagValidationTestPolicy(t *testing.T, appName string) (*P, func()) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
policy := NewWithManager(ctx, appName, true)
policy := NewWithManager(ctx, appName, true, "")
if policy == nil {
cancel()
os.RemoveAll(configDir)

View File

@@ -1 +1 @@
v0.35.2
v0.35.5