Repository navigation
fix(project): drop three fields the GitLab API does not accept - #418
Conversation
|
Hi Markus, thank you so much for this, and for the depth of research behind it. Tracing While reviewing I ran into one thing in client-go that I think flips the conclusion for the third field, plus a couple of smaller points. I'd love to sort these out before we merge. Before merging1. client-go rewrites the regex before sending, so
2. Upgrade note: removed fields are rejected, not just pruned I checked this on envtest and kind:
Crossplane applies composed resources via SSA and only tolerates I don't think we need a deprecation period for a v1alpha1 API, as long as the fields we drop are ones that never took effect. A clear note in the description and commit body should cover it, for example:
Smaller things3. Older GitLab. 4. Doc line. The 5. PR template. The PR body is missing the template's "How has this code been tested" section. What I checked and found correct
Thanks again for taking this on. Happy to help with any of it. |
Three `Project` spec fields were sent to GitLab although the API neither accepts nor returns them. GitLab discards undeclared parameters without an error, so setting them never had any effect. `buildCoverageRegex` was removed from the Projects API in GitLab 15.0 and the identifier does not occur anywhere in `gitlab-org/gitlab` at master. `operationsAccessLevel` was deprecated in 15.8 and removed in 16.0; GitLab lists it under `unexposed_attributes` in its own request spec. Both were also part of `isProjectUpToDate`, compared against an observation that can never be populated, so a spec that set either one stayed permanently out of date — an update on every reconcile, a `PUT` returning 200 because GitLab dropped the parameter, and the same difference again next time, while the resource reported `Synced=True` and `Ready=True`. Same failure shape as #416. The third is `containerExpirationPolicyAttributes.name_regex`. GitLab declares the deletion pattern as `name_regex` and nothing else; `name_regex_delete` was proposed in 2020, closed without merging, and is still an open backlog item. The spec carried both spellings, and the one that worked was the one GitLab does not have: client-go overwrites `ContainerExpirationPolicyAttributes.NameRegex` with `NameRegexDelete` in `CreateProject`, `CreateProjectForUser` and `EditProject` before encoding the request. `nameRegexDelete` therefore reached GitLab as `name_regex`, while the snake_case `name_regex` field was cleared and never sent. The surviving field is named after the API parameter, `nameRegex`, and is written to client-go's `NameRegexDelete` so the library forwards it. A new test drives the real `CreateProject` and `EditProject` against an httptest server and asserts `name_regex` in the request body; the existing tests compare `Generate*Options` output, which is the state before client-go rewrites it and cannot catch this. The observation field becomes `nameRegex` for the same reason: GitLab returns `name_regex`, and the previous `nameRegexDelete` status field was always empty. All three fields are removed rather than marked deprecated — a field that cannot take effect should not be part of the API. BREAKING CHANGE: The `Project` spec no longer accepts `buildCoverageRegex`, `operationsAccessLevel` or `containerExpirationPolicyAttributes.name_regex`, and `containerExpirationPolicyAttributes.nameRegexDelete` is renamed to `nameRegex`. Remove the dropped fields from manifests and Composition output before upgrading: strict `kubectl apply` and server-side apply reject unknown fields, and for Crossplane that stops reconciliation of the whole claim. Note that `name_regex` never took effect — moving its value to `nameRegex` will start deleting matching tags. Assisted-by: Kiro:claude-opus-5 Signed-off-by: Markus Siebert <markus.siebert@deutschebahn.com>
ff54e70 to
44913f4
Compare
|
Thank you — point 1 is correct and I had it backwards. I reproduced every step before changing anything. The rewrite is unconditional in client-go v2.64.0 (
So I fixed it slightly differently from your suggestion, on two sub-points. The surviving field is named The converter writes only Happy to switch to Points 2 to 5 are in: the upgrade note is in the description and the commit body, including that strict apply and SSA reject rather than prune and what that means for Compositions; the sentence about older GitLab is there; the One side effect worth noting: the SA1019 suppression on that converter line is gone, because I also need to correct my upstream report. client-go#2303 claims that setting I have not verified your envtest and kind results on SSA myself; I have no cluster set up for it at the moment. Everything else in your checklist matches what I measured. |
|
Update on the upstream side: client-go!3080 landed and closed #2303, released in v3.16.2. It swaps the annotations — That does not change anything in this PR. The fix is v3-only, the v2 line is frozen at v2.64.0 (tagged a month earlier), and this branch builds against v2.64.0, where the overwrite still applies. Verified against v3.17.0 that the mapping chosen here keeps working on both lines:
So writing One thing worth recording: the SA1019 on the converter line was a true positive, and the first version of this PR carried the suppression forward while changing the field underneath it. That is how the regression got in. Thanks again for catching it. |
henrysachs
left a comment
There was a problem hiding this comment.
Thanks, Markus, great follow-up, and nice work getting the fix landed upstream. I checked v3.17.0 and the wire test, both behave as you describe. Looks good to me!
Description of your changes
Three
Projectspec fields were sent to GitLab although the API neither accepts norreturns them. GitLab discards undeclared parameters without an error, so setting them
never had any effect.
Two of them were also part of
isProjectUpToDate, compared against an observation thatcan never be populated. A spec that set either one therefore stayed permanently out of
date: an update on every reconcile, a
PUTreturning 200 because GitLab dropped theparameter, and the same difference again next time — while the resource reported
Synced=TrueandReady=True. Same failure shape as #416.buildCoverageRegexwas removed from the Projects API in GitLab 15.0 and the identifierdoes not occur anywhere in
gitlab-org/gitlabat master.operationsAccessLevelwasdeprecated in 15.8 and removed in 16.0; GitLab lists it under
unexposed_attributesinits own request spec. The third is
containerExpirationPolicyAttributes.name_regex, thesnake_case field this spec carried alongside
nameRegexDelete: GitLab declares thedeletion pattern as
name_regexand nothing else, but client-go overwritesContainerExpirationPolicyAttributes.NameRegexwithNameRegexDeletebefore encoding therequest, so a value placed in the snake_case field was cleared and never left the process.
All three are removed rather than marked deprecated — a field that cannot take effect
should not be part of the API.
The deletion pattern is now a single field named after the API parameter. The first
version of this PR had this backwards and removed
nameRegexDelete, the spelling thatdoes work, which would have stopped sending the pattern altogether. Thanks to
@henrysachs for catching it. Request bodies captured through the real client:
NameRegexDeleteset →{"name_regex":"delete-me-.*","name_regex_delete":"delete-me-.*"}NameRegexset →container_expiration_policy_attributesempty, no pattern sentnameRegexDeleteis therefore renamed tonameRegex, matching both the GitLab parameterand the observation field, and the converter writes it to client-go's
NameRegexDeletesothe library forwards it. That removes the last snake_case key from this CRD, and it also
removes an SA1019 suppression on the write path that was telling the truth.
Breaking change
The
Projectspec no longer acceptsbuildCoverageRegex,operationsAccessLevelorcontainerExpirationPolicyAttributes.name_regex, andcontainerExpirationPolicyAttributes.nameRegexDeleteis renamed tonameRegex.Remove the dropped fields from manifests and Composition output before upgrading. Strict
kubectl applyand server-side apply reject unknown fields rather than pruning them, andbecause Crossplane applies composed resources via SSA, a Composition that still emits one
of them stops reconciling the whole claim.
The rename of
nameRegexDeleteis mechanical, the behaviour is unchanged. Moving a valuefrom
name_regextonameRegexis not: that pattern never took effect, and under the newname it will start deleting matching tags.
The two removed parameters were still accepted on older GitLab —
operations_access_levelup to 15.x,
build_coverage_regexin 14.x. The provider does not document a minimumGitLab version; on those releases these fields stop being sent.
Follow-up, not in this PR
GitLab split
operations_access_levelintoreleases,environments,feature_flags,infrastructureandmonitoraccess levels. This API exposes none of them, so thosefeatures currently cannot be controlled at all.
How has this code been tested
make generateis reproducible, andgo build ./...,go test ./...and golangci-lintare clean.
The new
containerexpirationpolicy_wire_test.godrives the realCreateProjectandEditProjectagainst anhttptestserver and assertsname_regexin the encoded requestbody. The existing tests compare
Generate*Optionsoutput, which is the state beforeclient-go rewrites the field, and cannot catch this class of bug. Reverting the converter
to
NameRegexmakes both new tests fail with an empty attributes object.The removals were checked against GitLab source at a current tag — REST params, entity,
model and GraphQL type — and against a live self-managed EE instance, where
name_regex_deleteis discarded whilename_regexis applied.I have:
make generateandgolangci-lintto ensure this PR is ready for review.