nais / nais/api

unleash: Create dereferences a nil response when bifrost returns any non-201

Open
#498 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
3
Forks
2
Avg merge
1d 9h
Merged PRs (30d)
17

Description

Summary

unleash.Create never checks bifrost's HTTP status. The generated client returns err only for transport failures, so any non-201 response leaves resp.JSON201 nil, and the nil flows into toUnleashInstance, which dereferences it.

Severity: low today, rising — see "Why this has not bitten yet"
Component: internal/unleash/queries.go (Create), internal/unleash/models.go:221 and the toUnleashInstance below it

Mechanism

resp, err := client.CreateInstance(ctx, req)
if err != nil {
    return nil, err          // transport errors only
}
unleashInstance := bifrostUnleashToK8s(resp.JSON201)   // nil for any non-201
…
return toUnleashInstance(unleashInstance), nil          // dereferences u.Spec

bifrostUnleashToK8s guards nil and returns nil (models.go:222-224), but toUnleashInstance starts with for _, env := range u.Spec.ExtraEnvVars with no guard.

Reachable bifrost responses today: 400 validation_failed, 400 no_version_source, 500 creation_failed.

Why this has not bitten yet

Loki, 14 days of bifrost traffic: 2985 GET /v1/releasechannels, 15 PUT /v1/unleash/{name}, and zero POST /v1/unleash. Instance creation is essentially never exercised, so the path has not been hit. No matching panic appears in nais-api's logs over the same window.

Why it is worth fixing now

nais/bifrost#549 adds two new create responses — 409 already_exists when the instance already exists, and 503 when the existence check is inconclusive. The 409 in particular is raised on a duplicate POST, which is the one non-exotic way to hit a non-201. It converts a rare data-loss path in bifrost into a nil dereference here.

Proposed fix

Check the status before converting, and map bifrost's error responses to sensible GraphQL errors — at minimum 409 should surface as "an Unleash instance already exists for this team" rather than an internal error. A nil guard in toUnleashInstance is worth having regardless, as defence in depth.

Acceptance criteria

  • A non-201 from bifrost returns an error, not a nil dereference.
  • 409 surfaces a distinguishable "already exists" message.
  • toUnleashInstance tolerates nil.
  • Test covering at least the 409 and 500 responses.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in internal/unleash/queries.go at Create, then inspect bifrostUnleashToK8s and toUnleashInstance in internal/unleash/models.go. Add coverage for 409 and 500 responses, confirming non-201 responses return errors, 409 is distinguishable, and nil conversion does not panic.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, graphql
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.