diff --git a/cmd/mesh-controller/desk_secret.go b/cmd/mesh-controller/desk_secret.go index 6cc60cf5..66fb9be9 100644 --- a/cmd/mesh-controller/desk_secret.go +++ b/cmd/mesh-controller/desk_secret.go @@ -228,9 +228,16 @@ const kindSecretGiven = "secret-given" func secretGivenObservation(node, module, name, how string, at time.Time) conditions.Observation { key := node + "." + module + "." + name where := module + " on " + node + // Within the bounds whatever the names' length: the module and machine, else the module, else the machine. headline := "New secret given for " + where - if len(headline) > conditions.HeadlineMax { - headline = "New secret given for " + module + for _, h := range []string{"New secret given for " + module, "New secret given on " + node} { + if len(headline) > conditions.HeadlineMax { + headline = h + } + } + resolved := "You saw that " + module + " was given a new secret" + if len(resolved) > conditions.HeadlineMax+20 { + resolved = "You saw that a new secret was given on " + node } return conditions.Observation{Scope: conditions.ScopeMachine, ID: key, Token: kindSecretGiven, Kind: kindSecretGiven, Machine: node, Severity: conditions.Urgent, Source: kindSecretGiven, @@ -240,7 +247,7 @@ func secretGivenObservation(node, module, name, how string, at time.Time) condit Explanation: fmt.Sprintf("The secret %s of %s was given %s. If you gave it, nothing else is needed. If you "+ "did not, somebody else now holds what %s acts with.", secretNameWords(name), where, how, module), Needs: "silence this if you just gave it; if you did not, give it again yourself so that only you hold it.", - Resolved: "You saw that " + module + " was given a new secret", + Resolved: resolved, Actions: []conditions.Action{conditions.SilenceAction(conditions.Key(conditions.ScopeMachine, key, kindSecretGiven))}} } diff --git a/cmd/mesh-controller/desk_secret_test.go b/cmd/mesh-controller/desk_secret_test.go index c37ee818..50015daf 100644 --- a/cmd/mesh-controller/desk_secret_test.go +++ b/cmd/mesh-controller/desk_secret_test.go @@ -215,11 +215,14 @@ func TestTheSecretGivenConditionSaysItselfInPlainWords(t *testing.T) { t.Error("the words carry the value") } } - // A long module name keeps the headline within its bound. - o := secretGivenObservation("anchor", "a-module-with-a-rather-long-name-indeed", "api-key", "at the controller's terminal", at) - if why, ok := conditions.PlainWords(conditions.Words{Headline: o.Headline, Explanation: o.Explanation, - Resolved: o.Resolved, Needs: o.Needs, Actions: o.Actions}, o.Machine); !ok { - t.Errorf("a long module name: %s", why) + // A long module name keeps the headline and the resolved line within their bounds. + for _, module := range []string{"a-module-with-a-rather-long-name-indeed", + "a-module-with-a-name-so-long-that-no-headline-could-ever-hold-it"} { + o := secretGivenObservation("anchor", module, "api-key", "at the controller's terminal", at) + if why, ok := conditions.PlainWords(conditions.Words{Headline: o.Headline, Explanation: o.Explanation, + Resolved: o.Resolved, Needs: o.Needs, Actions: o.Actions}, o.Machine); !ok { + t.Errorf("the module %s: %s", module, why) + } } } diff --git a/internal/conditions/plain.go b/internal/conditions/plain.go index ed287d33..315284ba 100644 --- a/internal/conditions/plain.go +++ b/internal/conditions/plain.go @@ -151,11 +151,17 @@ func unworded(o Observation, why string) { Unworded(o, why) return } - if _, seen := loggedUnworded.LoadOrStore(o.Kind+"\x00"+why, true); !seen { - log.Printf("the condition kind %q is said in the scope's words, not its own: %s", o.Kind, why) + // The reason without what it quotes of the words: a quoted fragment may be a hash-shaped secret, and a + // fragment that changes (a clock time) would log a new line every time. + reason := quotedFragment.ReplaceAllString(why, "") + if _, seen := loggedUnworded.LoadOrStore(o.Kind+"\x00"+reason, true); !seen { + log.Printf("the condition kind %q is said in the scope's words, not its own: %s", o.Kind, reason) } } +// quotedFragment is what a reason of the plain rule quotes of the words it refused, at its end. +var quotedFragment = regexp.MustCompile(` \([^()]*\)$`) + // The plain rule's shapes. var ( hexID = regexp.MustCompile(`\b[0-9a-f]{7,40}\b`) diff --git a/internal/conditions/plain_test.go b/internal/conditions/plain_test.go index 53b34bbc..c8d3e072 100644 --- a/internal/conditions/plain_test.go +++ b/internal/conditions/plain_test.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "log" - "os" "strings" "testing" ) @@ -256,18 +255,28 @@ func TestBorrowedWordsAreLogged(t *testing.T) { before := Unworded Unworded = nil t.Cleanup(func() { Unworded = before }) + loggedUnworded.Clear() + t.Cleanup(loggedUnworded.Clear) var out bytes.Buffer + writer := log.Writer() log.SetOutput(&out) - t.Cleanup(func() { log.SetOutput(os.Stderr) }) - for i := 0; i < 3; i++ { + t.Cleanup(func() { log.SetOutput(writer) }) + // A time that changes each observation, and a hash-shaped word: one line, quoting neither. + for _, at := range []string{"23:32", "23:33", "23:34"} { if _, err := k.Observe(t.Context(), Observation{Scope: ScopeMachine, ID: "ace", Kind: "test-clock", Machine: "ace", Severity: Warning, Source: "test", Summary: "s", Headline: "ace was given a secret", - Explanation: "It was given at 23:32.", Resolved: "Seen"}); err != nil { + Explanation: "It was given at " + at + ".", Resolved: "Seen"}); err != nil { t.Fatal(err) } } - if got := out.String(); strings.Count(got, "\n") != 1 || !strings.Contains(got, `"test-clock"`) || - !strings.Contains(got, "a clock time or date") { + if _, err := k.Observe(t.Context(), Observation{Scope: ScopeMachine, ID: "ace", Kind: "test-hash", Machine: "ace", + Severity: Warning, Source: "test", Summary: "s", Headline: "ace was given 0123abcd4567ef89", + Explanation: "It was given.", Resolved: "Seen"}); err != nil { + t.Fatal(err) + } + if got := out.String(); strings.Count(got, "\n") != 2 || !strings.Contains(got, `"test-clock"`) || + !strings.Contains(got, "a clock time or date") || strings.Contains(got, "23:3") || + !strings.Contains(got, `"test-hash"`) || strings.Contains(got, "0123abcd4567ef89") { t.Errorf("the log said %q", got) } }