6 Commits

Author SHA1 Message Date
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
43 changed files with 129 additions and 118 deletions
+7 -3
View File
@@ -13,7 +13,7 @@ Just drop the binary on a server and start triaging.
### Option A: Download the Binary ### 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. 2. Place the binary in a dedicated directory and execute it.
3. Visit `http://localhost:8080` in your browser. 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*). Ensure you have **Go 1.26+** installed (*CGO is required for the native `mattn/go-sqlite3` driver*).
```bash ```bash
git clone https://epigas.gitea.cloud/RiskRancher/core git clone https://code.riskrancher.com/RiskRancher/core
cd core cd core
go build -o rr ./cmd/rr/main.go go build -o rr ./cmd/rr/main.go
./rr ./rr
``` ```
## License
Apache License 2.0
+3 -3
View File
@@ -4,9 +4,9 @@ import (
"log" "log"
"net/http" "net/http"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore" "code.riskrancher.com/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/server" "code.riskrancher.com/RiskRancher/core/pkg/server"
"epigas.gitea.cloud/RiskRancher/core/ui" "code.riskrancher.com/RiskRancher/core/ui"
) )
var ( var (
+2 -2
View File
@@ -10,8 +10,8 @@ import (
"net/http" "net/http"
"time" "time"
"epigas.gitea.cloud/RiskRancher/core/pkg/auth" "code.riskrancher.com/RiskRancher/core/pkg/auth"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore" "code.riskrancher.com/RiskRancher/core/pkg/datastore"
) )
func main() { func main() {
+1 -1
View File
@@ -1,4 +1,4 @@
module epigas.gitea.cloud/RiskRancher/core module code.riskrancher.com/RiskRancher/core
go 1.26.0 go 1.26.0
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"strconv" "strconv"
"strings" "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) { func (h *Handler) HandleGetAdapters(w http.ResponseWriter, r *http.Request) {
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"testing" "testing"
"time" "time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore" "code.riskrancher.com/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
func setupTestAdapters(t *testing.T) (*Handler, *sql.DB) { func setupTestAdapters(t *testing.T) (*Handler, *sql.DB) {
+1 -1
View File
@@ -1,7 +1,7 @@
package adapters package adapters
import ( import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
type Handler struct { type Handler struct {
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"epigas.gitea.cloud/RiskRancher/core/pkg/auth" "code.riskrancher.com/RiskRancher/core/pkg/auth"
) )
// PasswordResetRequest is the expected JSON payload // PasswordResetRequest is the expected JSON payload
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
func TestGetGlobalConfig(t *testing.T) { func TestGetGlobalConfig(t *testing.T) {
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
func TestExportSystemState(t *testing.T) { func TestExportSystemState(t *testing.T) {
+1 -1
View File
@@ -1,7 +1,7 @@
package admin package admin
import ( import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
// Handler encapsulates all Admin and Sheriff HTTP logic // Handler encapsulates all Admin and Sheriff HTTP logic
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"testing" "testing"
"time" "time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore" "code.riskrancher.com/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
// setupTestAdmin returns the clean Admin Handler and the raw DB // setupTestAdmin returns the clean Admin Handler and the raw DB
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"testing" "testing"
"time" "time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore" "code.riskrancher.com/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
func setupTestAnalytics(t *testing.T) (*Handler, *sql.DB) { func setupTestAnalytics(t *testing.T) (*Handler, *sql.DB) {
+1 -1
View File
@@ -1,7 +1,7 @@
package analytics package analytics
import ( import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
type Handler struct { type Handler struct {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"encoding/base64" "encoding/base64"
"math/rand" "math/rand"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore" "code.riskrancher.com/RiskRancher/core/pkg/datastore"
) )
func setupTestAuth(t *testing.T) (*Handler, *sql.DB) { func setupTestAuth(t *testing.T) (*Handler, *sql.DB) {
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"errors" "errors"
"time" "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 // ErrNotFound is a standard error we can use across our handlers
+10 -3
View File
@@ -6,9 +6,11 @@ import (
_ "embed" _ "embed"
"encoding/json" "encoding/json"
"log" "log"
"os"
"path/filepath"
"time" "time"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
_ "modernc.org/sqlite" _ "modernc.org/sqlite"
) )
@@ -18,9 +20,14 @@ var schemaSQL string
//go:embed defaults/*.json //go:embed defaults/*.json
var defaultAdaptersFS embed.FS var defaultAdaptersFS embed.FS
func InitDB(filepath string) *sql.DB { func InitDB(dbPath string) *sql.DB {
dsn := "file:" + filepath + "?_pragma=journal_mode(WAL)&_pragma=busy_timeout(5000)&_pragma=synchronous(NORMAL)&_pragma=foreign_keys(1)" 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) db, err := sql.Open("sqlite", dsn)
if err != nil { if err != nil {
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"database/sql" "database/sql"
"testing" "testing"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
_ "modernc.org/sqlite" // We need the SQLite driver for the test _ "modernc.org/sqlite" // We need the SQLite driver for the test
) )
+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 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), ('Vulnerability', 'Critical', 3, 14, 1),
('Privacy', 'Critical', 3, 3, 0), ('Privacy', 'High', 3, 7, 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); ('Incident', 'Critical', 3, 1, 0);
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (
+1 -1
View File
@@ -3,7 +3,7 @@ package datastore
import ( import (
"database/sql" "database/sql"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
type SQLiteStore struct { type SQLiteStore struct {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"context" "context"
"time" "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 { func (s *SQLiteStore) UpdateAppConfig(ctx context.Context, config domain2.AppConfig) error {
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"time" "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) { func (s *SQLiteStore) GetSheriffAnalytics(ctx context.Context) (domain2.SheriffAnalytics, error) {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"context" "context"
"fmt" "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 { func (s *SQLiteStore) SaveDraft(ctx context.Context, d domain2.DraftTicket) error {
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"database/sql" "database/sql"
"time" "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 { func (s *SQLiteStore) IngestTickets(ctx context.Context, tickets []domain2.Ticket) error {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"fmt" "fmt"
"time" "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) { func (s *SQLiteStore) GetTickets(ctx context.Context) ([]domain.Ticket, error) {
+1 -1
View File
@@ -1,7 +1,7 @@
package ingest package ingest
import ( import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
type Handler struct { type Handler struct {
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"net/http" "net/http"
"strconv" "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) { func (h *Handler) HandleIngest(w http.ResponseWriter, r *http.Request) {
+2 -2
View File
@@ -13,8 +13,8 @@ import (
"testing" "testing"
"time" "time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore" "code.riskrancher.com/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
func setupTestIngest(t *testing.T) (*Handler, *sql.DB) { func setupTestIngest(t *testing.T) (*Handler, *sql.DB) {
+2 -2
View File
@@ -5,8 +5,8 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"epigas.gitea.cloud/RiskRancher/core/pkg/auth" "code.riskrancher.com/RiskRancher/core/pkg/auth"
domain2 "epigas.gitea.cloud/RiskRancher/core/pkg/domain" domain2 "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
func (h *Handler) HandleSaveDraft(w http.ResponseWriter, r *http.Request) { func (h *Handler) HandleSaveDraft(w http.ResponseWriter, r *http.Request) {
+1 -1
View File
@@ -1,7 +1,7 @@
package report package report
import ( import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
type Handler struct { type Handler struct {
+2 -2
View File
@@ -13,8 +13,8 @@ import (
"testing" "testing"
"time" "time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore" "code.riskrancher.com/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
func setupTestReport(t *testing.T) (*Handler, *sql.DB) { func setupTestReport(t *testing.T) (*Handler, *sql.DB) {
+2 -2
View File
@@ -3,8 +3,8 @@ package server
import ( import (
"net/http" "net/http"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
"epigas.gitea.cloud/RiskRancher/core/pkg/sla" "code.riskrancher.com/RiskRancher/core/pkg/sla"
) )
type App struct { type App struct {
+9 -9
View File
@@ -3,14 +3,14 @@ package server
import ( import (
"net/http" "net/http"
"epigas.gitea.cloud/RiskRancher/core/pkg/adapters" "code.riskrancher.com/RiskRancher/core/pkg/adapters"
"epigas.gitea.cloud/RiskRancher/core/pkg/admin" "code.riskrancher.com/RiskRancher/core/pkg/admin"
"epigas.gitea.cloud/RiskRancher/core/pkg/analytics" "code.riskrancher.com/RiskRancher/core/pkg/analytics"
"epigas.gitea.cloud/RiskRancher/core/pkg/auth" "code.riskrancher.com/RiskRancher/core/pkg/auth"
"epigas.gitea.cloud/RiskRancher/core/pkg/ingest" "code.riskrancher.com/RiskRancher/core/pkg/ingest"
"epigas.gitea.cloud/RiskRancher/core/pkg/report" "code.riskrancher.com/RiskRancher/core/pkg/report"
"epigas.gitea.cloud/RiskRancher/core/pkg/tickets" "code.riskrancher.com/RiskRancher/core/pkg/tickets"
"epigas.gitea.cloud/RiskRancher/core/ui" "code.riskrancher.com/RiskRancher/core/ui"
) )
func RegisterRoutes(app *App) { func RegisterRoutes(app *App) {
@@ -85,7 +85,7 @@ func RegisterRoutes(app *App) {
app.Router.Handle("POST /api/adapters", adminOnly(adapterH.HandleCreateAdapter)) app.Router.Handle("POST /api/adapters", adminOnly(adapterH.HandleCreateAdapter))
app.Router.Handle("DELETE /api/adapters/{id}", adminOnly(adapterH.HandleDeleteAdapter)) 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/export", sheriffOnly(adminH.HandleExportState))
app.Router.Handle("GET /api/admin/check-updates", sheriffOnly(adminH.HandleCheckUpdates)) app.Router.Handle("GET /api/admin/check-updates", sheriffOnly(adminH.HandleCheckUpdates))
app.Router.Handle("POST /api/admin/shutdown", sheriffOnly(adminH.HandleShutdown)) app.Router.Handle("POST /api/admin/shutdown", sheriffOnly(adminH.HandleShutdown))
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"log" "log"
"time" "time"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
// DefaultSLACalculator implements the SLACalculator interface // DefaultSLACalculator implements the SLACalculator interface
+1 -1
View File
@@ -1,7 +1,7 @@
package tickets package tickets
import ( import (
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
// Handler encapsulates all Ticket-related HTTP logic // Handler encapsulates all Ticket-related HTTP logic
+2 -2
View File
@@ -10,8 +10,8 @@ import (
"testing" "testing"
"time" "time"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore" "code.riskrancher.com/RiskRancher/core/pkg/datastore"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
func setupTestTickets(t *testing.T) (*Handler, *sql.DB) { func setupTestTickets(t *testing.T) (*Handler, *sql.DB) {
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
) )
type InlineUpdateRequest struct { type InlineUpdateRequest struct {
+3
View File
@@ -10,15 +10,18 @@
<div class="tab-nav"> <div class="tab-nav">
<button class="tab-btn active" onclick="switchTab('tab-metrics', this)">📊 Metrics</button> <button class="tab-btn active" onclick="switchTab('tab-metrics', this)">📊 Metrics</button>
<button class="tab-btn" onclick="switchTab('tab-performance', this)">📡 Performance</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"> <button class="tab-btn" style="color: #94a3b8; cursor: not-allowed;" title="Available in RiskRancher Pro">
🔒 Risk Reviews (Pro) 🔒 Risk Reviews (Pro)
</button> </button>
{{ end }}
<button class="tab-btn" onclick="switchTab('tab-config', this)">⚙️ Configuration</button> <button class="tab-btn" onclick="switchTab('tab-config', this)">⚙️ Configuration</button>
<button class="tab-btn" onclick="switchTab('tab-feed', this)">📻 System Logs</button> <button class="tab-btn" onclick="switchTab('tab-feed', this)">📻 System Logs</button>
</div> </div>
{{template "admin_metrics" .}} {{template "admin_metrics" .}}
{{template "admin_performance" .}} {{template "admin_performance" .}}
{{block "pro_risk_tab_content" .}}{{end}}
{{template "admin_config" .}} {{template "admin_config" .}}
{{template "admin_feed" .}} {{template "admin_feed" .}}
{{template "admin_modals" .}} {{template "admin_modals" .}}
+38 -48
View File
@@ -24,7 +24,7 @@
</table> </table>
</div> </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="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;"> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
<h3 style="margin: 0; color: #64748b;">🛤️ Source Routing</h3> <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> <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> </div>
</div> {{end}}
</div> </div>
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;"> <div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div style="border: 1px solid #e2e8f0; border-radius: 8px; padding: 15px; position: relative;"> {{block "pro_sla_policy" .}}
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;"> <div style="border: 1px solid #e2e8f0; border-radius: 8px; padding: 15px; position: relative;">
<div> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
<h3 style="margin: 0;">⏱️ SLA Policies & System Time</h3> <div>
<p style="margin: 2px 0 0 0; font-size: 0.8rem; color: #64748b;">Locked to Standard FedRAMP/NIST Default Timeframes</p> <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> </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 style="display: flex; gap: 30px; opacity: 0.7; pointer-events: none;">
</div> <div style="flex: 1; padding: 15px; background: #f8fafc; border-radius: 6px; border: 1px solid #e2e8f0;">
<div style="display: flex; gap: 30px; opacity: 0.7; pointer-events: none;"> <h4 style="margin-top: 0;">Base Configuration</h4>
<div style="flex: 1; padding: 15px; background: #f8fafc; border-radius: 6px; border: 1px solid #e2e8f0;"> <label>System Timezone:</label>
<h4 style="margin-top: 0;">Base Configuration</h4> <select disabled style="width: 100%; padding: 6px; margin-bottom: 10px; background: #e2e8f0;">
<label>System Timezone:</label> <option selected>UTC (Universal)</option>
<select disabled style="width: 100%; padding: 6px; margin-bottom: 10px; background: #e2e8f0;"> </select>
<option selected>UTC (Universal)</option> <div style="display: flex; gap: 10px; margin-bottom: 10px;">
</select> <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="display: flex; gap: 10px; margin-bottom: 10px;"> <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="flex: 1;"><label>Biz Start:</label><input type="text" disabled value="09:00" style="width: 100%; padding: 6px; background: #e2e8f0;"></div> </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 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> </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>
</div> {{end}}
<div style="border: 1px solid #e2e8f0; border-radius: 8px; padding: 15px; display: flex; flex-direction: column;"> <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> <h3 style="margin: 0 0 15px 0;">⚙️ Operations</h3>
<div style="margin-bottom: 20px;"> {{block "pro_backups" .}}
<label style="font-weight: bold; display: flex; justify-content: space-between;"> {{end}}
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>
<div style="margin-bottom: 20px;"> <div style="margin-bottom: 20px;">
<label style="font-weight: bold;">Data Portability</label> <label style="font-weight: bold;">Data Portability</label>
+5 -3
View File
@@ -8,9 +8,11 @@
</a> </a>
<a href="/dashboard?tab=chute" class="tab-btn {{if eq .CurrentTab "chute"}}active{{end}}">🤠 The Chute (Assigned)</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;"> {{block "pro_verification_tab" .}}
🔒 Pending Verification (Pro) <a href="javascript:void(0)" onclick="showUpsell('E2E Exception & Verification Pipeline')" class="tab-btn" style="color: #94a3b8;">
</a> 🔒 Pending Verification (Pro)
</a>
{{end}}
<a href="/dashboard?tab=archives" class="tab-btn {{if eq .CurrentTab "archives"}}active{{end}}"> <a href="/dashboard?tab=archives" class="tab-btn {{if eq .CurrentTab "archives"}}active{{end}}">
🗄️ The Archives 🗄️ The Archives
+2 -2
View File
@@ -1,11 +1,12 @@
{{define "content"}} {{define "content"}}
<script> <script>
window.CurrentTab = "{{.CurrentTab}}"; window.CurrentTab = "{{.CurrentTab}}";
</script> </script>
{{template "dash_tabs" .}} {{template "dash_tabs" .}}
{{block "pro_risk_tab_content" .}}{{end}}
<div class="tab-pane active"> <div class="tab-pane active">
{{template "dash_table" .}} {{template "dash_table" .}}
</div> </div>
@@ -13,5 +14,4 @@
{{template "dash_modals" .}} {{template "dash_modals" .}}
<script src="/static/dashboard.js"></script> <script src="/static/dashboard.js"></script>
{{end}} {{end}}
+3 -3
View File
@@ -13,9 +13,9 @@ import (
"strconv" "strconv"
"strings" "strings"
"epigas.gitea.cloud/RiskRancher/core/pkg/auth" "code.riskrancher.com/RiskRancher/core/pkg/auth"
"epigas.gitea.cloud/RiskRancher/core/pkg/domain" "code.riskrancher.com/RiskRancher/core/pkg/domain"
"epigas.gitea.cloud/RiskRancher/core/pkg/report" "code.riskrancher.com/RiskRancher/core/pkg/report"
) )
//go:embed templates/* templates/components/* static/* //go:embed templates/* templates/components/* static/*