Rules: placed in the same change they are created in
hc rule add --before/--after/--first created the rule at the end of its chain and then moved it: two history entries, two probations, the rule briefly in force in the wrong place, and in a changeset the place was lost. POST /rules (and the other ordered kinds) now takes ?before=ID, ?after=ID or ?first=1, kept with the operation when staged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
40748d3042
commit
05c811bddc
7 files changed
+95
-22
No files matched your search
@@ -1184,3 +1184,49 @@ func (e *env) text(path string) string {
|
||||
b, _ := io.ReadAll(resp.Body)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// TestCreatePlaced: a rule created ?before= another is placed in the same
|
||||
// change (one history entry), also when staged in a changeset.
|
||||
func TestCreatePlaced(t *testing.T) {
|
||||
e := newEnv(t)
|
||||
var a, b, c api.MutationResponse
|
||||
e.call(e.token, "POST", "/rules", model.Rule{Chain: "input", Match: model.Match{Services: []string{"ssh"}}}, &a)
|
||||
e.call(e.token, "POST", "/rules", model.Rule{Chain: "input", Match: model.Match{Services: []string{"dns"}}}, &b)
|
||||
var first model.Rule
|
||||
json.Unmarshal(a.Object, &first)
|
||||
if code := e.call(e.token, "POST", "/rules?before="+itoa(first.ID), model.Rule{Chain: "input", Match: model.Match{Services: []string{"http"}}, Comment: "placed"}, &c); code != 201 {
|
||||
t.Fatalf("create placed: %d %+v", code, c)
|
||||
}
|
||||
order := func() string {
|
||||
var out []string
|
||||
for _, r := range e.eng.State().Rules {
|
||||
out = append(out, strings.Join(r.Services, ""))
|
||||
}
|
||||
return strings.Join(out, ",")
|
||||
}
|
||||
if o := order(); o != "http,ssh,dns" {
|
||||
t.Errorf("order: %s", o)
|
||||
}
|
||||
var hs []model.HistoryEntry
|
||||
e.call(e.token, "GET", "/history", nil, &hs)
|
||||
if len(hs) != 3 || len(hs[0].Changes) != 1 || hs[0].Changes[0].Action() != "create" {
|
||||
t.Errorf("history: %d entries, newest %+v", len(hs), hs[0])
|
||||
}
|
||||
// Staged, the place goes with it.
|
||||
var cs model.Changeset
|
||||
e.call(e.token, "POST", "/changesets", nil, &cs)
|
||||
e.call(e.token, "POST", "/rules?first=1&changeset="+itoa(cs.ID), model.Rule{Chain: "input", Match: model.Match{Services: []string{"ntp"}}}, nil)
|
||||
if code := e.call(e.token, "POST", "/changesets/"+itoa(cs.ID)+"/apply", nil, nil); code != 200 {
|
||||
t.Fatalf("apply: %d", code)
|
||||
}
|
||||
if o := order(); o != "ntp,http,ssh,dns" {
|
||||
t.Errorf("order after the changeset: %s", o)
|
||||
}
|
||||
// A bad place: refused, nothing created.
|
||||
if code := e.call(e.token, "POST", "/rules?before=99999", model.Rule{Chain: "input"}, nil); code != 400 {
|
||||
t.Errorf("before a rule that isn't there: %d", code)
|
||||
}
|
||||
if n := len(e.eng.State().Rules); n != 4 {
|
||||
t.Errorf("%d rules", n)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user