feat(kubernetes): add Namespace to the core group [FIX-555] - #88
Merged
Conversation
Namespaces are where teams record ownership (team, cost-centre, environment), so an unlabelled namespace is exactly the kind of gap a tagging policy exists to catch — but it cannot be reported if the namespace never reaches the tree. Adds core.Namespace and wires it into the core group. Unlike the other kinds in the group it provisions nothing and has no cost-relevant fields of its own: its labels, stored as the base resource's Tags, are the point. Annotations are carried too, matching the other kinds.
liamg
approved these changes
Aug 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds
core.Namespaceto the Kubernetes core group so the parser can put namespaces in the tree, which is what lets tagging policies be enforced on them (FIX-555).Namespaces are where teams commonly record ownership — team, cost-centre, environment — so an unlabelled namespace is exactly the kind of gap a tagging policy exists to catch. It can't be reported while namespaces never reach the tree.
Open question — address shape (opinions wanted)
A Namespace is cluster-scoped, so it has no
metadata.namespaceof its own, and it doesn't fit the[namespace, kind, name]address every other Kubernetes kind uses. Two options; I went with the first, but I'm not attached to it and would like a second opinion before this lands.Chosen — self-scoped, 3 segments:
Keeps every Kubernetes kind on one address shape, and groups a namespace with the resources inside it — which reads well when policies are reported per namespace. Downside: the name appears twice, which looks odd on first sight.
Rejected — cluster-scoped, 2 segments:
Honest about the API model (a Namespace really has no namespace). Downside: it'd be the only Kubernetes kind with a 2-segment address, and it needs a carve-out that returns a differently-shaped address rather than one that just fills in a different value.
The tie-breaker for me was that nothing actually depends on the choice, so consistency won over literal accuracy. I checked
providers,runnerandcli: the address is treated as an opaque string everywhere (.String()for map keys, display, and comparison againstPreviousResourceAddresses). The only length-sensitive code isproviders/internal/infracost/usage.go:77, which indexes from the end (At(Len()-2)) behind aLen() >= 2guard, so it resolves the type correctly under either shape. Happy to switch if people prefer the literal model — it's a one-line change in the companion parser PR.Notes for reviewers
coreis cost-relevant.resource.Resource'sTags— the same promotion every other Kubernetes kind does, which is what makes the existing tag machinery apply.Annotationsis carried too, matchingWorkload/PersistentVolumeClaim/Service.Corewith atree:"namespace"tag is the whole change — no generated code to update.Testing
Extended
TestKubernetesRoundTripto cover a Namespace throughToProto→FromProto, asserting the labels-as-tags andSupportsTagssurvive — those being what tag policies act on. Full suite andgolangci-lintpass.Checklist