Skip to content

fix: make Sprig first/last/rest/initial nil-safe - #651

Open
ogormans-deptstack wants to merge 2 commits into
crossplane-contrib:mainfrom
ogormans-deptstack:fix/nil-safe-sprig-list-funcs
Open

ogormans-deptstack wants to merge 2 commits into
crossplane-contrib:mainfrom
ogormans-deptstack:fix/nil-safe-sprig-list-funcs

Conversation

@ogormans-deptstack

@ogormans-deptstack ogormans-deptstack commented Oct 16, 2026 •

Copy link
Copy Markdown

Description of your changes

Sprig's first, last, rest, and initial call reflect.TypeOf(list).Kind()
without guarding against an untyped nil. When a template reaches for a field that
isn't populated yet — e.g. a status that a composed resource hasn't reported — list
is an untyped nil, reflect.TypeOf(nil) is nil, and .Kind() panics with an
invalid memory address. text/template surfaces that as error calling first: ...
and the whole reconcile fails.

This replaces those four accessors in GetNewTemplateWithFunctionMaps with thin
wrappers (nilSafeList) that treat a nil input as an empty result and otherwise
defer to Sprig's must* variants, which report unsupported types as errors instead
of panics . It follows the existing env/expandenv removal pattern already in
that function. Valid inputs behave exactly as before.

Credit to @shashankvarma499, who traced this root cause in the issue thread — the
approach here follows their write-up. Happy to hand this off to him if he'd rather carry it
himself, or if this issue is stale or considered not necessary to fix yet.

I ran into something similar writing compositions against Crossplane CRDs (I maintain
kubectl-schemagen, a lesser used krew plugin that scaffolds manifests for CRDs including
Crossplane's Composition / CompositeResourceDefinition / EnvironmentConfig), where
referencing a not-yet-populated status field is easy to do by accident.

-->

Fixes #78

I have:

  • [ x] Read and followed Crossplane's [contribution process].
  • [ x] Added or updated unit tests for my change.

These four Sprig list accessors call reflect.TypeOf(list).Kind() without
a nil check, so referencing a missing observed field (such as a status
that is not yet populated) panics and fails the whole reconcile. Wrap
them so a nil input returns an empty result, deferring to Sprig's must*
variants for valid inputs and unsupported-type errors.

Fixes crossplane-contrib#78

Signed-off-by: ogormans-deptstack <sean.ogorman@deptagency.com>
Extract the mustFirst/mustLast/mustRest/mustInitial assertions into
comma-ok checks so the type assertion is the sole right-hand side of an
assignment, satisfying golangci-lint's forcetypeassert. If sprig ever
stops providing a must* variant the original accessor is left untouched.

Signed-off-by: ogormans-deptstack <sean.ogorman@deptagency.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error during access to the item of the list

1 participant