Implemented admin pane + user permission

This commit is contained in:
Martino Ferrari
2026-06-22 17:49:14 +02:00
parent 73fcbe7b28
commit ac24011487
67 changed files with 5925 additions and 411 deletions
+12 -4
View File
@@ -24,12 +24,20 @@ type ConfigRule struct {
Name string `json:"name"`
SetID string `json:"setId"`
Description string `json:"description,omitempty"`
Version int `json:"version"`
Tag string `json:"tag,omitempty"`
Owner string `json:"owner,omitempty"`
Source string `json:"source"`
// Enabled gates whether the rule runs when instances of the bound set are
// saved/applied. A nil pointer (legacy rules created before the flag) is
// treated as enabled, so existing rules keep their behaviour.
Enabled *bool `json:"enabled,omitempty"`
Version int `json:"version"`
Tag string `json:"tag,omitempty"`
Owner string `json:"owner,omitempty"`
Source string `json:"source"`
}
// IsEnabled reports whether the rule participates in instance evaluation. A nil
// Enabled flag (legacy rules) is treated as enabled.
func (r ConfigRule) IsEnabled() bool { return r.Enabled == nil || *r.Enabled }
// RuleViolation is a single constraint failure from evaluating a rule.
type RuleViolation struct {
Rule string `json:"rule,omitempty"` // rule ID that produced it (aggregate runs)
+9 -1
View File
@@ -45,6 +45,10 @@ type Meta struct {
// empty for sets. Lets clients group/filter instances by set without a GET
// per instance.
SetID string `json:"setId,omitempty"`
// Enabled is only populated for rules: nil for sets/instances and for legacy
// rules without the flag. Lets the rule list show enabled/disabled status
// without a GET per rule.
Enabled *bool `json:"enabled,omitempty"`
}
// VersionMeta describes a single persisted revision.
@@ -85,6 +89,7 @@ type header struct {
Version int `json:"version"`
Tag string `json:"tag"`
SetID string `json:"setId"`
Enabled *bool `json:"enabled"`
}
func validateID(id string) error {
@@ -149,7 +154,7 @@ func (s *Store) List(k Kind) ([]Meta, error) {
if err != nil {
continue
}
out = append(out, Meta{ID: id, Name: h.Name, Version: h.Version, SetID: h.SetID})
out = append(out, Meta{ID: id, Name: h.Name, Version: h.Version, SetID: h.SetID, Enabled: h.Enabled})
}
return out, nil
}
@@ -587,6 +592,9 @@ func (s *Store) rulesForSet(setID string) ([]ConfigRule, error) {
if err != nil {
continue
}
if !rule.IsEnabled() {
continue
}
out = append(out, rule)
}
return out, nil
+20
View File
@@ -95,6 +95,26 @@ func TestRuleTransformPersists(t *testing.T) {
}
}
func TestDisabledRuleSkipped(t *testing.T) {
s, _ := New(t.TempDir())
set, _ := s.CreateSet(sampleSet(), "")
disabled := false
if _, err := s.CreateRule(ConfigRule{
Name: "voltage cap",
SetID: set.ID,
Enabled: &disabled,
Source: "voltage: <=24",
}, ""); err != nil {
t.Fatal(err)
}
// A value that would violate the rule still saves because the rule is off.
if _, err := s.CreateInstance(ConfigInstance{
Name: "bad", SetID: set.ID, Values: map[string]any{"voltage": 40.0},
}, ""); err != nil {
t.Fatalf("expected disabled rule to be skipped, got %v", err)
}
}
func asRuleError(err error, target **RuleError) bool {
for err != nil {
if re, ok := err.(*RuleError); ok {