9 Commits

Author SHA1 Message Date
quiet-professional ead3c9043d updated branding
Build and Release Core / Test and Build (push) Successful in 4m44s
2026-05-01 09:59:58 -04:00
quiet-professional 317dd9aedf patched bug
Build and Release Core / Test and Build (push) Successful in 4m55s
2026-04-30 13:24:41 -04:00
quiet-professional 7f22302859 patched sla bug
Build and Release Core / Test and Build (push) Successful in 6m4s
2026-04-30 12:49:51 -04:00
quiet-professional dc0ae8eb96 updated module name
Build and Release Core / Test and Build (push) Successful in 5m26s
2026-04-29 11:04:14 -04:00
quiet-professional b07a114227 updated paths
Build and Release Core / Test and Build (push) Successful in 4m2s
2026-04-29 10:36:05 -04:00
quiet-professional 88f77edadd added license call out
Build and Release Core / Test and Build (push) Successful in 4m23s
2026-04-28 13:52:01 -04:00
quiet-professional decad4cc82 patched folder bug for users
Build and Release Core / Test and Build (push) Successful in 4m28s
2026-04-02 15:27:33 -04:00
quiet-professional fd0ff13991 updated the sqlite driver connection string
Build and Release Core / Test and Build (push) Successful in 4m2s
2026-04-02 15:05:40 -04:00
quiet-professional 5f53ffec4f updated sqlite engine to address compilation errors
Build and Release Core / Test and Build (push) Successful in 2m54s
2026-04-02 15:00:31 -04:00
48 changed files with 220 additions and 137 deletions
+7 -3
View File
@@ -13,7 +13,7 @@ Just drop the binary on a server and start triaging.
### Option A: Download the Binary
1. Go to the [Releases](https://epigas.gitea.cloud/RiskRancher/core/releases) tab and download the compiled executable for your OS (Windows/macOS/Linux).
1. Go to the [Releases](https://code.riskrancher.com/RiskRancher/core/releases) tab and download the compiled executable for your OS (Windows/macOS/Linux).
2. Place the binary in a dedicated directory and execute it.
3. Visit `http://localhost:8080` in your browser.
@@ -22,8 +22,12 @@ Just drop the binary on a server and start triaging.
Ensure you have **Go 1.26+** installed (*CGO is required for the native `mattn/go-sqlite3` driver*).
```bash
git clone https://epigas.gitea.cloud/RiskRancher/core
git clone https://code.riskrancher.com/RiskRancher/core
cd core
go build -o rr ./cmd/rr/main.go
./rr
```
```
## License
Apache License 2.0
+3 -3
View File
@@ -4,9 +4,9 @@ import (
"log"
"net/http"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/server"
"epigas.gitea.cloud/RiskRancher/core/ui"
"code.riskrancher.com/RiskRancher/core/pkg/datastore"
"code.riskrancher.com/RiskRancher/core/pkg/server"
"code.riskrancher.com/RiskRancher/core/ui"
)
var (
+2 -2
View File
@@ -10,8 +10,8 @@ import (
"net/http"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/auth"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore"
"code.riskrancher.com/RiskRancher/core/pkg/auth"
"code.riskrancher.com/RiskRancher/core/pkg/datastore"
)
func main() {
+14 -2
View File
@@ -1,8 +1,20 @@
module epigas.gitea.cloud/RiskRancher/core
module code.riskrancher.com/RiskRancher/core
go 1.26.0
require (
github.com/mattn/go-sqlite3 v1.14.34
golang.org/x/crypto v0.48.0
modernc.org/sqlite v1.48.0
)
require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
golang.org/x/sys v0.42.0 // indirect
modernc.org/libc v1.70.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)
+51 -2
View File
@@ -1,4 +1,53 @@
github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk=
github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw=
modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0=
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw=
modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.48.0 h1:ElZyLop3Q2mHYk5IFPPXADejZrlHu7APbpB0sF78bq4=
modernc.org/sqlite v1.48.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"strconv"
"strings"
domain2 "epigas.gitea.cloud/RiskRancher/core/pkg/domain"
domain2 "code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func (h *Handler) HandleGetAdapters(w http.ResponseWriter, r *http.Request) {
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"testing"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/datastore"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func setupTestAdapters(t *testing.T) (*Handler, *sql.DB) {
+1 -1
View File
@@ -1,7 +1,7 @@
package adapters
import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
type Handler struct {
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strconv"
"strings"
"epigas.gitea.cloud/RiskRancher/core/pkg/auth"
"code.riskrancher.com/RiskRancher/core/pkg/auth"
)
// PasswordResetRequest is the expected JSON payload
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"net/http/httptest"
"testing"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func TestGetGlobalConfig(t *testing.T) {
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"net/http/httptest"
"testing"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func TestExportSystemState(t *testing.T) {
+1 -1
View File
@@ -1,7 +1,7 @@
package admin
import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
// Handler encapsulates all Admin and Sheriff HTTP logic
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"testing"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/datastore"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
// setupTestAdmin returns the clean Admin Handler and the raw DB
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"testing"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/datastore"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func setupTestAnalytics(t *testing.T) (*Handler, *sql.DB) {
+1 -1
View File
@@ -1,7 +1,7 @@
package analytics
import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
type Handler struct {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"encoding/base64"
"math/rand"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
"golang.org/x/crypto/bcrypt"
)
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"net/http/httptest"
"testing"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore"
"code.riskrancher.com/RiskRancher/core/pkg/datastore"
)
func setupTestAuth(t *testing.T) (*Handler, *sql.DB) {
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"errors"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
// ErrNotFound is a standard error we can use across our handlers
+3 -3
View File
@@ -7,7 +7,7 @@ import (
"sync"
"testing"
_ "github.com/mattn/go-sqlite3"
_ "modernc.org/sqlite"
)
// runChaosEngine fires 100 concurrent workers at the provided database connection
@@ -73,8 +73,8 @@ func TestSQLiteConcurrency_Tuned_Succeeds(t *testing.T) {
tempDir := t.TempDir()
dbPath := filepath.Join(tempDir, "tuned.db")
dsn := fmt.Sprintf("%s?_journal_mode=WAL&_synchronous=NORMAL&_busy_timeout=5000", dbPath)
db, err := sql.Open("sqlite3", dsn)
dsn := fmt.Sprintf("%s?_pragma=journal_mode(WAL)&_pragma=synchronous(NORMAL)&_pragma=busy_timeout(5000)", dbPath)
db, err := sql.Open("sqlite", dsn)
if err != nil {
t.Fatalf("Failed to open tuned DB: %v", err)
}
+13 -5
View File
@@ -6,10 +6,12 @@ import (
_ "embed"
"encoding/json"
"log"
"os"
"path/filepath"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
_ "github.com/mattn/go-sqlite3"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
_ "modernc.org/sqlite"
)
//go:embed schema.sql
@@ -18,10 +20,16 @@ var schemaSQL string
//go:embed defaults/*.json
var defaultAdaptersFS embed.FS
func InitDB(filepath string) *sql.DB {
dsn := "file:" + filepath + "?_journal=WAL&_timeout=5000&_sync=1&_fk=1"
func InitDB(dbPath string) *sql.DB {
db, err := sql.Open("sqlite3", dsn)
dir := filepath.Dir(dbPath)
if err := os.MkdirAll(dir, 0755); err != nil {
log.Fatalf("Failed to create database directory: %v", err)
}
dsn := "file:" + dbPath + "?_pragma=journal_mode(WAL)&_pragma=busy_timeout(5000)&_pragma=synchronous(NORMAL)&_pragma=foreign_keys(1)"
db, err := sql.Open("sqlite", dsn)
if err != nil {
log.Fatalf("Failed to open database: %v", err)
}
+3 -3
View File
@@ -5,12 +5,12 @@ import (
"database/sql"
"testing"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
_ "github.com/mattn/go-sqlite3" // We need the SQLite driver for the test
"code.riskrancher.com/RiskRancher/core/pkg/domain"
_ "modernc.org/sqlite" // We need the SQLite driver for the test
)
func setupTestDB(t *testing.T) *SQLiteStore {
db, err := sql.Open("sqlite3", ":memory:")
db, err := sql.Open("sqlite", ":memory:")
if err != nil {
t.Fatalf("Failed to open in-memory SQLite database: %v", err)
}
+2 -2
View File
@@ -4,11 +4,11 @@ import (
"database/sql"
"testing"
_ "github.com/mattn/go-sqlite3"
_ "modernc.org/sqlite"
)
func TestSchemaMigrations(t *testing.T) {
db, err := sql.Open("sqlite3", ":memory:")
db, err := sql.Open("sqlite", ":memory:")
if err != nil {
t.Fatalf("Failed to open test db: %v", err)
}
+7 -2
View File
@@ -28,8 +28,13 @@ CREATE TABLE IF NOT EXISTS sla_policies (
);
INSERT OR IGNORE INTO sla_policies (domain, severity, days_to_triage, days_to_remediate, max_extensions) VALUES
('Vulnerability', 'Critical', 3, 14, 1), ('Vulnerability', 'High', 3, 30, 2),
('Privacy', 'Critical', 3, 3, 0), ('Privacy', 'High', 3, 7, 1),
('Vulnerability', 'Critical', 3, 14, 1),
('Vulnerability', 'High', 3, 30, 2),
('Vulnerability', 'Medium', 7, 60, 2),
('Vulnerability', 'Low', 14, 90, 3),
('Vulnerability', 'Info', 30, 180, 5),
('Privacy', 'Critical', 3, 3, 0),
('Privacy', 'High', 3, 7, 1),
('Incident', 'Critical', 3, 1, 0);
CREATE TABLE IF NOT EXISTS users (
+1 -1
View File
@@ -3,7 +3,7 @@ package datastore
import (
"database/sql"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
type SQLiteStore struct {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"context"
"time"
domain2 "epigas.gitea.cloud/RiskRancher/core/pkg/domain"
domain2 "code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func (s *SQLiteStore) UpdateAppConfig(ctx context.Context, config domain2.AppConfig) error {
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"fmt"
"time"
domain2 "epigas.gitea.cloud/RiskRancher/core/pkg/domain"
domain2 "code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func (s *SQLiteStore) GetSheriffAnalytics(ctx context.Context) (domain2.SheriffAnalytics, error) {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"context"
"fmt"
domain2 "epigas.gitea.cloud/RiskRancher/core/pkg/domain"
domain2 "code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func (s *SQLiteStore) SaveDraft(ctx context.Context, d domain2.DraftTicket) error {
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"database/sql"
"time"
domain2 "epigas.gitea.cloud/RiskRancher/core/pkg/domain"
domain2 "code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func (s *SQLiteStore) IngestTickets(ctx context.Context, tickets []domain2.Ticket) error {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"fmt"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func (s *SQLiteStore) GetTickets(ctx context.Context) ([]domain.Ticket, error) {
+1 -1
View File
@@ -1,7 +1,7 @@
package ingest
import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
type Handler struct {
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"net/http"
"strconv"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func (h *Handler) HandleIngest(w http.ResponseWriter, r *http.Request) {
+2 -2
View File
@@ -13,8 +13,8 @@ import (
"testing"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/datastore"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func setupTestIngest(t *testing.T) (*Handler, *sql.DB) {
+2 -2
View File
@@ -5,8 +5,8 @@ import (
"net/http"
"strconv"
"epigas.gitea.cloud/RiskRancher/core/pkg/auth"
domain2 "epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/auth"
domain2 "code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func (h *Handler) HandleSaveDraft(w http.ResponseWriter, r *http.Request) {
+1 -1
View File
@@ -1,7 +1,7 @@
package report
import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
type Handler struct {
+2 -2
View File
@@ -13,8 +13,8 @@ import (
"testing"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/datastore"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func setupTestReport(t *testing.T) (*Handler, *sql.DB) {
+2 -2
View File
@@ -3,8 +3,8 @@ package server
import (
"net/http"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"epigas.gitea.cloud/RiskRancher/core/pkg/sla"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/sla"
)
type App struct {
+9 -9
View File
@@ -3,14 +3,14 @@ package server
import (
"net/http"
"epigas.gitea.cloud/RiskRancher/core/pkg/adapters"
"epigas.gitea.cloud/RiskRancher/core/pkg/admin"
"epigas.gitea.cloud/RiskRancher/core/pkg/analytics"
"epigas.gitea.cloud/RiskRancher/core/pkg/auth"
"epigas.gitea.cloud/RiskRancher/core/pkg/ingest"
"epigas.gitea.cloud/RiskRancher/core/pkg/report"
"epigas.gitea.cloud/RiskRancher/core/pkg/tickets"
"epigas.gitea.cloud/RiskRancher/core/ui"
"code.riskrancher.com/RiskRancher/core/pkg/adapters"
"code.riskrancher.com/RiskRancher/core/pkg/admin"
"code.riskrancher.com/RiskRancher/core/pkg/analytics"
"code.riskrancher.com/RiskRancher/core/pkg/auth"
"code.riskrancher.com/RiskRancher/core/pkg/ingest"
"code.riskrancher.com/RiskRancher/core/pkg/report"
"code.riskrancher.com/RiskRancher/core/pkg/tickets"
"code.riskrancher.com/RiskRancher/core/ui"
)
func RegisterRoutes(app *App) {
@@ -85,7 +85,7 @@ func RegisterRoutes(app *App) {
app.Router.Handle("POST /api/adapters", adminOnly(adapterH.HandleCreateAdapter))
app.Router.Handle("DELETE /api/adapters/{id}", adminOnly(adapterH.HandleDeleteAdapter))
app.Router.Handle("GET /api/admin/export", sheriffOnly(adminH.HandleExportState))
app.Router.Handle("GET /api/admin/check-updates", sheriffOnly(adminH.HandleCheckUpdates))
app.Router.Handle("POST /api/admin/shutdown", sheriffOnly(adminH.HandleShutdown))
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"log"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
// DefaultSLACalculator implements the SLACalculator interface
+2 -2
View File
@@ -4,7 +4,7 @@ import (
"database/sql"
"testing"
_ "github.com/mattn/go-sqlite3"
_ "modernc.org/sqlite"
)
// GetSLAPolicy simulates the core engine function that fetches SLA rules
@@ -16,7 +16,7 @@ func GetSLAPolicy(db *sql.DB, domain string, severity string) (daysToRemediate i
// setupTestDB spins up an isolated, in-memory database for testing
func setupTestDB(t *testing.T) *sql.DB {
db, err := sql.Open("sqlite3", ":memory:")
db, err := sql.Open("sqlite", ":memory:")
if err != nil {
t.Fatalf("Failed to open test database: %v", err)
}
+1 -1
View File
@@ -1,7 +1,7 @@
package tickets
import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
// Handler encapsulates all Ticket-related HTTP logic
+2 -2
View File
@@ -10,8 +10,8 @@ import (
"testing"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/datastore"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
func setupTestTickets(t *testing.T) (*Handler, *sql.DB) {
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"net/http"
"strconv"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
)
type InlineUpdateRequest struct {
+3
View File
@@ -10,15 +10,18 @@
<div class="tab-nav">
<button class="tab-btn active" onclick="switchTab('tab-metrics', this)">📊 Metrics</button>
<button class="tab-btn" onclick="switchTab('tab-performance', this)">📡 Performance</button>
{{ block "pro_risk_tab_btn" .}}
<button class="tab-btn" style="color: #94a3b8; cursor: not-allowed;" title="Available in RiskRancher Pro">
🔒 Risk Reviews (Pro)
</button>
{{ end }}
<button class="tab-btn" onclick="switchTab('tab-config', this)">⚙️ Configuration</button>
<button class="tab-btn" onclick="switchTab('tab-feed', this)">📻 System Logs</button>
</div>
{{template "admin_metrics" .}}
{{template "admin_performance" .}}
{{block "pro_risk_tab_content" .}}{{end}}
{{template "admin_config" .}}
{{template "admin_feed" .}}
{{template "admin_modals" .}}
+10 -4
View File
@@ -3,16 +3,22 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RiskRancher OSS</title>
<title>RiskRancher {{if isProActive}}PRO{{else}}OSS{{end}}</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<header style="display: flex; justify-content: space-between; align-items: center; padding: 10px 20px; background: white; border-bottom: 1px solid #e2e8f0;">
<div class="logo">
<h2 style="margin: 0;"><a href="/dashboard" style="color: #0f172a; text-decoration: none;">🐴 RiskRancher</a></h2>
<h2 style="margin: 0;">
<a href="/dashboard" style="color: #0f172a; text-decoration: none;">
🐴 RiskRancher{{if isProActive}}{{with getCompanyName}} | {{.}}{{end}}{{end}}
</a>
</h2>
</div>
<nav style="display: flex; align-items: center; gap: 15px;">
<span style="color: #475569; font-size: 0.9rem; font-family: monospace; padding-left: 15px; margin-left: 5px;">Community Edition</span>
<span style="color: {{if isProActive}}#059669{{else}}#475569{{end}}; font-size: 0.9rem; font-family: monospace; padding-left: 15px; margin-left: 5px; font-weight: {{if isProActive}}bold{{else}}normal{{end}};">
{{if isProActive}}PRO Edition{{else}}Community Edition{{end}}
</span>
<button onclick="logout()" style="background: #f1f5f9; color: #dc2626; border: 1px solid #e2e8f0; padding: 6px 12px; border-radius: 4px; font-weight: bold; cursor: pointer; font-size: 0.85rem;">Log Out</button>
</nav>
</header>
@@ -29,7 +35,7 @@
{{template "content" .}}
</main>
<footer style="text-align: center; padding: 20px; margin-top: 40px; border-top: 1px solid #e2e8f0; color: #94a3b8; font-size: 0.85rem;">
🐴 RiskRancher Core Edition | Version: <strong>{{.Version}}</strong> | Build: <strong>{{.Commit}}</strong>
🐴 RiskRancher {{if isProActive}}PRO Edition{{else}}Core Edition{{end}} | Version: <strong>{{.Version}}</strong> | Build: <strong>{{.Commit}}</strong>
</footer>
</body>
</html>
+38 -48
View File
@@ -24,7 +24,7 @@
</table>
</div>
<div style="border: 1px solid #e2e8f0; border-radius: 8px; padding: 15px;">
{{block "pro_source_routing" .}}
<div style="border: 1px solid #e2e8f0; border-radius: 8px; padding: 15px; background: #f8fafc;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
<h3 style="margin: 0; color: #64748b;">🛤️ Source Routing</h3>
@@ -35,65 +35,55 @@
<a href="https://RiskRancher.com/pro" target="_blank" style="color: #8b5cf6; text-decoration: none; font-weight: bold; font-size: 0.85rem;">Learn about RiskRancher Pro &rarr;</a>
</div>
</div>
</div>
{{end}}
</div>
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div style="border: 1px solid #e2e8f0; border-radius: 8px; padding: 15px; position: relative;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
<div>
<h3 style="margin: 0;">⏱️ SLA Policies & System Time</h3>
<p style="margin: 2px 0 0 0; font-size: 0.8rem; color: #64748b;">Locked to Standard FedRAMP/NIST Default Timeframes</p>
{{block "pro_sla_policy" .}}
<div style="border: 1px solid #e2e8f0; border-radius: 8px; padding: 15px; position: relative;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
<div>
<h3 style="margin: 0;">⏱️ SLA Policies & System Time</h3>
<p style="margin: 2px 0 0 0; font-size: 0.8rem; color: #64748b;">Locked to Standard FedRAMP/NIST Default Timeframes</p>
</div>
<button class="btn" style="padding: 6px 12px; font-size: 0.85rem; background: #f8fafc; color: #64748b; border: 1px solid #cbd5e1;" onclick="showUpsell('Custom SLA Timers & Business Hours')">🔒 Customize (Pro)</button>
</div>
<button class="btn" style="padding: 6px 12px; font-size: 0.85rem; background: #f8fafc; color: #64748b; border: 1px solid #cbd5e1;" onclick="showUpsell('Custom SLA Timers & Business Hours')">🔒 Customize (Pro)</button>
</div>
<div style="display: flex; gap: 30px; opacity: 0.7; pointer-events: none;">
<div style="flex: 1; padding: 15px; background: #f8fafc; border-radius: 6px; border: 1px solid #e2e8f0;">
<h4 style="margin-top: 0;">Base Configuration</h4>
<label>System Timezone:</label>
<select disabled style="width: 100%; padding: 6px; margin-bottom: 10px; background: #e2e8f0;">
<option selected>UTC (Universal)</option>
</select>
<div style="display: flex; gap: 10px; margin-bottom: 10px;">
<div style="flex: 1;"><label>Biz Start:</label><input type="text" disabled value="09:00" style="width: 100%; padding: 6px; background: #e2e8f0;"></div>
<div style="flex: 1;"><label>Biz End:</label><input type="text" disabled value="17:00" style="width: 100%; padding: 6px; background: #e2e8f0;"></div>
<div style="display: flex; gap: 30px; opacity: 0.7; pointer-events: none;">
<div style="flex: 1; padding: 15px; background: #f8fafc; border-radius: 6px; border: 1px solid #e2e8f0;">
<h4 style="margin-top: 0;">Base Configuration</h4>
<label>System Timezone:</label>
<select disabled style="width: 100%; padding: 6px; margin-bottom: 10px; background: #e2e8f0;">
<option selected>UTC (Universal)</option>
</select>
<div style="display: flex; gap: 10px; margin-bottom: 10px;">
<div style="flex: 1;"><label>Biz Start:</label><input type="text" disabled value="09:00" style="width: 100%; padding: 6px; background: #e2e8f0;"></div>
<div style="flex: 1;"><label>Biz End:</label><input type="text" disabled value="17:00" style="width: 100%; padding: 6px; background: #e2e8f0;"></div>
</div>
</div>
<div style="flex: 2;">
<div style="margin-bottom: 10px; display: flex; justify-content: space-between;">
<h4 style="margin: 0;">SLA Matrix (Days to Patch)</h4>
</div>
<table style="font-size: 0.85rem; width: 100%; text-align: left;">
<thead><tr><th style="padding-bottom: 5px;">Severity</th><th>Triage</th><th>Patch</th></tr></thead>
<tbody>
<tr class="sla-row"><td style="padding: 4px 0;"><span class="badge critical">Critical</span></td><td>1</td><td>3</td></tr>
<tr class="sla-row"><td style="padding: 4px 0;"><span class="badge high">High</span></td><td>3</td><td>14</td></tr>
<tr class="sla-row"><td style="padding: 4px 0;"><span class="badge medium">Medium</span></td><td>7</td><td>30</td></tr>
<tr class="sla-row"><td style="padding: 4px 0;"><span class="badge low">Low</span></td><td>14</td><td>90</td></tr>
</tbody>
</table>
</div>
</div>
<div style="flex: 2;">
<div style="margin-bottom: 10px; display: flex; justify-content: space-between;">
<h4 style="margin: 0;">SLA Matrix (Days to Patch)</h4>
</div>
<table style="font-size: 0.85rem; width: 100%; text-align: left;">
<thead><tr><th style="padding-bottom: 5px;">Severity</th><th>Triage</th><th>Patch</th></tr></thead>
<tbody>
<tr class="sla-row"><td style="padding: 4px 0;"><span class="badge critical">Critical</span></td><td>1</td><td>3</td></tr>
<tr class="sla-row"><td style="padding: 4px 0;"><span class="badge high">High</span></td><td>3</td><td>14</td></tr>
<tr class="sla-row"><td style="padding: 4px 0;"><span class="badge medium">Medium</span></td><td>7</td><td>30</td></tr>
<tr class="sla-row"><td style="padding: 4px 0;"><span class="badge low">Low</span></td><td>14</td><td>90</td></tr>
</tbody>
</table>
</div>
</div>
</div>
{{end}}
<div style="border: 1px solid #e2e8f0; border-radius: 8px; padding: 15px; display: flex; flex-direction: column;">
<h3 style="margin: 0 0 15px 0;">⚙️ Operations</h3>
<div style="margin-bottom: 20px;">
<label style="font-weight: bold; display: flex; justify-content: space-between;">
Automated Backups
<span style="font-size: 0.75rem; color: #8b5cf6; font-weight: normal;">Pro Feature</span>
</label>
<div style="display: flex; gap: 10px; margin-top: 5px;">
<select disabled style="flex: 1; padding: 6px; background: #f1f5f9; color: #94a3b8; cursor: not-allowed; border: 1px solid #cbd5e1;">
<option>Manual Only (Free Core)</option>
<option>Daily Automated</option>
<option>Weekly Automated</option>
</select>
<button class="btn btn-secondary" style="color: #94a3b8; border-color: #cbd5e1;" onclick="showUpsell('Automated DB Backups')">🔒 Apply</button>
</div>
</div>
{{block "pro_backups" .}}
{{end}}
<div style="margin-bottom: 20px;">
<label style="font-weight: bold;">Data Portability</label>
+5 -3
View File
@@ -8,9 +8,11 @@
</a>
<a href="/dashboard?tab=chute" class="tab-btn {{if eq .CurrentTab "chute"}}active{{end}}">🤠 The Chute (Assigned)</a>
<a href="javascript:void(0)" onclick="showUpsell('E2E Exception & Verification Pipeline')" class="tab-btn" style="color: #94a3b8;">
🔒 Pending Verification (Pro)
</a>
{{block "pro_verification_tab" .}}
<a href="javascript:void(0)" onclick="showUpsell('E2E Exception & Verification Pipeline')" class="tab-btn" style="color: #94a3b8;">
🔒 Pending Verification (Pro)
</a>
{{end}}
<a href="/dashboard?tab=archives" class="tab-btn {{if eq .CurrentTab "archives"}}active{{end}}">
🗄️ The Archives
+2 -2
View File
@@ -1,11 +1,12 @@
{{define "content"}}
<script>
window.CurrentTab = "{{.CurrentTab}}";
</script>
{{template "dash_tabs" .}}
{{block "pro_risk_tab_content" .}}{{end}}
<div class="tab-pane active">
{{template "dash_table" .}}
</div>
@@ -13,5 +14,4 @@
{{template "dash_modals" .}}
<script src="/static/dashboard.js"></script>
{{end}}
+8 -4
View File
@@ -13,9 +13,9 @@ import (
"strconv"
"strings"
"epigas.gitea.cloud/RiskRancher/core/pkg/auth"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain"
"epigas.gitea.cloud/RiskRancher/core/pkg/report"
"code.riskrancher.com/RiskRancher/core/pkg/auth"
"code.riskrancher.com/RiskRancher/core/pkg/domain"
"code.riskrancher.com/RiskRancher/core/pkg/report"
)
//go:embed templates/* templates/components/* static/*
@@ -36,7 +36,11 @@ func SetVersionInfo(version, commit string) {
}
func init() {
funcMap := template.FuncMap{"lower": strings.ToLower}
funcMap := template.FuncMap{
"lower": strings.ToLower,
"isProActive": func() bool { return false },
"getCompanyName": func() string { return "" },
}
Pages = make(map[string]*template.Template)
var err error