Skip to content

Commit eb5a130

Browse files
committed
fix(bootstrap): an empty preview when no operator CA is registered, not a refusal
Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
1 parent fd39eb1 commit eb5a130

3 files changed

Lines changed: 28 additions & 3 deletions

File tree

‎docs/first-run.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ during first run retires the earlier one at once.
8989

9090
A new session keeps the registration but must confirm it again before it can
9191
submit a certificate: call with `ca_cert_der` empty for the preview, then with
92-
its `confirm_sha256`.
92+
its `confirm_sha256`. With nothing registered, that preview is empty (no
93+
`operator_ca`) and doesn't count as a failure.
9394

9495
## 👤 The first admin certificate
9596

‎internal/bootstrap/register.go‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,16 @@ func (s *Service) previewOf(reg *registration) *fleetv1.OperatorCA {
263263
}
264264

265265
// reconfirm previews the current registration for a new session, or records
266-
// the new session's confirmation of it without changing anything.
266+
// the new session's confirmation of it without changing anything. With
267+
// nothing registered the preview is empty.
267268
func (s *Service) reconfirm(ctx context.Context, sessionHash, confirm string) (*connect.Response[fleetv1.BootstrapServiceRegisterOperatorCAResponse], error) {
268269
row := s.activeCA(ctx)
269270
if row == nil {
271+
// A new session asks for the current registration first. Nothing
272+
// registered is an empty answer, not the caller's mistake.
273+
if confirm == "" {
274+
return connect.NewResponse(&fleetv1.BootstrapServiceRegisterOperatorCAResponse{}), nil
275+
}
270276
return nil, s.fail(ctx, caRejected(connect.CodeFailedPrecondition, fleetv1.ErrorReason_ERROR_REASON_NOT_CONFIRMED,
271277
"no operator CA is registered yet; upload one"))
272278
}

‎internal/bootstrap/register_test.go‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ limitations under the License.
1818

1919
import (
2020
"context"
21+
"crypto/rand"
2122
"crypto/x509"
2223
"net/http"
2324
"net/http/httptest"
@@ -304,10 +305,27 @@ func TestRegister_LaterSessionRetiresTheEarlierAndMustReconfirm(t *testing.T) {
304305
}
305306
}
306307

308+
// A new session probes for the current registration. With nothing
309+
// registered that is an empty preview, not a refusal, and it spends no
310+
// rate-limit budget, so restarting first run costs the token holder nothing.
311+
// Confirming a CA that isn't registered is still refused.
307312
func TestRegister_NothingRegisteredToPreview(t *testing.T) {
308313
h := newHarness(t)
309314
secret := h.startSession()
310-
_, err := h.register(secret, &fleetv1.BootstrapServiceRegisterOperatorCARequest{})
315+
for i := 0; i < 10; i++ {
316+
resp, err := h.register(secret, &fleetv1.BootstrapServiceRegisterOperatorCARequest{})
317+
if err != nil {
318+
t.Fatalf("preview %d with nothing registered: %v", i+1, err)
319+
}
320+
if resp.GetOperatorCa() != nil || resp.GetConfirmed() {
321+
t.Fatalf("preview with nothing registered = %+v, want empty", resp)
322+
}
323+
}
324+
bad, _ := NewToken(rand.Reader)
325+
_, err := h.client().StartBootstrapSession(h.ctx, connect.NewRequest(&fleetv1.StartBootstrapSessionRequest{Token: bad}))
326+
wantCode(t, err, apperr.CodeTokenInvalid, "") // not 1602: the previews spent nothing
327+
328+
_, err = h.register(secret, &fleetv1.BootstrapServiceRegisterOperatorCARequest{ConfirmSha256: strings.Repeat("ab", 32)})
311329
wantCode(t, err, apperr.CodeOperatorCARejected, "NOT_CONFIRMED")
312330
if connect.CodeOf(err) != connect.CodeFailedPrecondition {
313331
t.Errorf("Connect code %v, want FailedPrecondition", connect.CodeOf(err))

0 commit comments

Comments
 (0)