The command API, which refuses everything until it knows who is asking
novox/hq ADR 0035: one implementation, several surfaces, and a surface holds no decisions. The act of assigning — including that an assignment which does not resolve is kept and still refused — moved into acts.go, and the command line now calls it too. Two surfaces, one refusal, in the same words. It will not run without --issuer, and refuses at start rather than per request so it is found by whoever ran it rather than by whoever finds it. There is no flag that removes the check. The authenticator is honest about what it is: no token can be verified until an identity provider exists, because that is a module and none is running, so every request is refused and told that the command line still works. A surface that functioned without authentication would be one somebody left running — and the board this stands behind is published on a public name. Four refusals, four tests. The last one first asserted "not 200", which passed because a request with no database fails at the store anyway — it proved nothing about whether the input was checked. It now asserts the specific refusal, and bites when the check is removed.
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type letIn struct{}
|
||||
|
||||
func (letIn) Who(*http.Request) (string, error) { return "somebody", nil }
|
||||
|
||||
func asking(t *testing.T, who Authenticator, method, path, body string) *httptest.ResponseRecorder {
|
||||
t.Helper()
|
||||
recorded := httptest.NewRecorder()
|
||||
commands(who).ServeHTTP(recorded, httptest.NewRequest(method, path, strings.NewReader(body)))
|
||||
return recorded
|
||||
}
|
||||
|
||||
// **Nothing is served to somebody the mesh cannot identify**, and that is the default rather than
|
||||
// a setting. The board this stands behind is published on a public name (novox/hq 11-a-board), so
|
||||
// an unauthenticated command surface is authority over the mesh handed to whoever finds it.
|
||||
func TestAnUnauthenticatedRequestIsRefused(t *testing.T) {
|
||||
got := asking(t, mustAuthenticate("https://identity.example/realms/mesh"),
|
||||
"POST", "/assign", `{"node":"anchor","module":"umami"}`)
|
||||
if got.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("an unidentified caller got %d", got.Code)
|
||||
}
|
||||
// And it says what to do instead, because the answer is not "give up".
|
||||
if !strings.Contains(got.Body.String(), "command line") {
|
||||
t.Errorf("the refusal does not say what still works: %s", got.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// The API refuses to start at all without being told whose tokens to believe.
|
||||
//
|
||||
// At start rather than per request, so it is found by whoever ran it rather than by whoever
|
||||
// finds it.
|
||||
func TestTheApiWillNotRunWithoutAnIssuer(t *testing.T) {
|
||||
err := apiCommand(context.Background(), []string{})
|
||||
if err == nil {
|
||||
t.Fatal("it served commands without being told who may give them")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "issuer") {
|
||||
t.Errorf("the refusal does not name what is missing: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// A request missing what it acts on is refused before anything is opened.
|
||||
func TestARequestThatNamesNothingIsRefused(t *testing.T) {
|
||||
// **The exact refusal, not merely "not accepted".** Asserting non-200 passes even when the
|
||||
// request got as far as opening a store and failing there, which proves nothing about whether
|
||||
// anything was checked — that is what the first version of this test did.
|
||||
for _, body := range []string{`{}`, `{"node":"anchor"}`, `{"module":"umami"}`, `not json`} {
|
||||
got := asking(t, letIn{}, "POST", "/assign", body)
|
||||
if got.Code != http.StatusBadRequest {
|
||||
t.Errorf("%s got %d, and a request naming nothing is a bad request", body, got.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A verb nobody implemented is said plainly. A command surface answering 404 to something
|
||||
// somebody expected is indistinguishable from one that is down.
|
||||
func TestAnUnknownRouteSaysWhatIsAccepted(t *testing.T) {
|
||||
got := asking(t, letIn{}, "POST", "/rotate", `{}`)
|
||||
if got.Code != http.StatusNotFound {
|
||||
t.Fatalf("got %d", got.Code)
|
||||
}
|
||||
var said map[string]any
|
||||
_ = json.Unmarshal(got.Body.Bytes(), &said)
|
||||
if !strings.Contains(said["refused"].(string), "/assign") {
|
||||
t.Errorf("it does not say what it does accept: %v", said)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user