Is there an existing issue for this?
Kubernetes Version
n/a (API conversion logic, reproducible as a unit test)
Shipwright Version
v0.20.13 / main @ 0d8ae09
Current Behavior
BuildRun conversion handles the deprecated .status.failedAt field in only one direction.
v1beta1 → v1alpha1 (ConvertTo) writes it. buildrun_conversion.go#L182-L189 deliberately mirrors FailureDetails.Location into the deprecated field, with an explicit opt-out of the staticcheck deprecation warning:
//nolint:staticcheck // SA1019 we want to give users some time to adopt to failureDetails
alphaBuildRun.Status.FailedAt = alphaBuildRun.Status.FailureDetails.Location
v1alpha1 → v1beta1 (ConvertFrom) never reads it. buildrun_conversion.go#L256-L262 only looks at FailureDetails:
if alphaBuildRun.Status.FailureDetails != nil {
src.Status.FailureDetails = &FailureDetails{
Reason: alphaBuildRun.Status.FailureDetails.Reason,
Message: alphaBuildRun.Status.FailureDetails.Message,
Location: (*Location)(alphaBuildRun.Status.FailureDetails.Location),
}
}
So a v1alpha1 BuildRun that populated only .status.failedAt — which is exactly what a client written against the older API would do, and what this codebase itself emitted before failureDetails existed — converts to a v1beta1 object with no failure location at all. .status.failureDetails comes out nil.
Expected Behavior
ConvertFrom should fall back to .status.failedAt when .status.failureDetails is absent, populating .status.failureDetails.location from it. That would make the deprecated field round-trip, consistent with ConvertTo already going out of its way to keep emitting it.
Steps To Reproduce
Converting a v1alpha1 BuildRun that sets only status.failedAt drops the location:
func TestFailedAtDropped(t *testing.T) {
alpha := &buildapialpha.BuildRun{
Status: buildapialpha.BuildRunStatus{
FailedAt: &buildapialpha.FailedAt{Pod: "buildrun-pod", Container: "step-build"},
},
}
alpha.APIVersion = "shipwright.io/v1alpha1"
alpha.Kind = "BuildRun"
raw, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(alpha)
u := &unstructured.Unstructured{Object: raw}
beta := &BuildRun{}
if err := beta.ConvertFrom(context.TODO(), u); err != nil {
t.Fatal(err)
}
if beta.Status.FailureDetails == nil {
t.Error("status.failureDetails is nil; the failure location was dropped")
}
}
Output:
INPUT v1alpha1: status.failedAt = &{Pod:buildrun-pod Container:step-build}
--- FAIL: TestFailedAtDropped
status.failureDetails is nil; the failure location was dropped
As a control, the opposite direction confirms the asymmetry is real — ConvertTo on a v1beta1 object with FailureDetails.Location set produces:
ConvertTo -> v1alpha1 status.failedAt found=true value=map[container:step-build pod:buildrun-pod]
Anything else?
I recognise failedAt is deprecated, so it is possible that ignoring it on the way in is intentional. Two things suggest otherwise, which is why I am raising it:
ConvertTo does not merely tolerate the field, it actively populates it and suppresses the deprecation lint to do so, with a comment stating the intent is to give users time to migrate. Accepting the field from v1alpha1 producers seems like the matching half of that grace period.
- The failure is silent. There is no warning and no error — the failure location simply disappears, which makes a failed BuildRun harder to debug precisely when the user needs that information.
If the current behaviour is intended, it may still be worth documenting that .status.failedAt is write-only across conversion.
I am happy to open a PR adding the fallback plus round-trip test coverage, if that would be welcome.
Found while auditing buildrun_conversion.go for the same class of issue as #2303.
Is there an existing issue for this?
Kubernetes Version
n/a (API conversion logic, reproducible as a unit test)
Shipwright Version
v0.20.13 / main @ 0d8ae09
Current Behavior
BuildRunconversion handles the deprecated.status.failedAtfield in only one direction.v1beta1 → v1alpha1 (
ConvertTo) writes it.buildrun_conversion.go#L182-L189deliberately mirrorsFailureDetails.Locationinto the deprecated field, with an explicit opt-out of the staticcheck deprecation warning:v1alpha1 → v1beta1 (
ConvertFrom) never reads it.buildrun_conversion.go#L256-L262only looks atFailureDetails:So a v1alpha1
BuildRunthat populated only.status.failedAt— which is exactly what a client written against the older API would do, and what this codebase itself emitted beforefailureDetailsexisted — converts to a v1beta1 object with no failure location at all..status.failureDetailscomes outnil.Expected Behavior
ConvertFromshould fall back to.status.failedAtwhen.status.failureDetailsis absent, populating.status.failureDetails.locationfrom it. That would make the deprecated field round-trip, consistent withConvertToalready going out of its way to keep emitting it.Steps To Reproduce
Converting a v1alpha1
BuildRunthat sets onlystatus.failedAtdrops the location:Output:
As a control, the opposite direction confirms the asymmetry is real —
ConvertToon a v1beta1 object withFailureDetails.Locationset produces:Anything else?
I recognise
failedAtis deprecated, so it is possible that ignoring it on the way in is intentional. Two things suggest otherwise, which is why I am raising it:ConvertTodoes not merely tolerate the field, it actively populates it and suppresses the deprecation lint to do so, with a comment stating the intent is to give users time to migrate. Accepting the field from v1alpha1 producers seems like the matching half of that grace period.If the current behaviour is intended, it may still be worth documenting that
.status.failedAtis write-only across conversion.I am happy to open a PR adding the fallback plus round-trip test coverage, if that would be welcome.
Found while auditing
buildrun_conversion.gofor the same class of issue as #2303.