CRITICAL: delete_label/update_label address labels by name, not id -- delete_label('395') silently deleted an unrelated label #19
Labels
No labels
api
architecture
auth
authentication
blocked
bug
chore
ci/cd
codec-constraints
component:blitz
component:chatter
component:entertainment
component:foodchain
component:forgejo-client
component:gatekeeper
component:mappy
component:monads
component:spiffy
deduplication
dependencies
documentation
enhancement
feature
fix
graphics
in-progress
lang:go
lang:python
lang:rust
lang:shell
lang:toml
lang:typescript
performance
pkg:agent
pkg:ai
pkg:coding-agent
pkg:tui
priority:critical
priority:high
priority:low
priority:medium
ready
resolution
review
security
technical-debt
testing
tracking
vendor
video-encoding
workgroup
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
kade/forgejo-client#19
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity: critical (destructive, silent)
LabelsModule.delete_labelandupdate_labelinterpolated the caller's nameinto a path segment that Forgejo addresses by id:
Forgejo's spec is unambiguous (
GET swagger.v1.json):DELETE /repos/{owner}/{repo}/labels/{id}PATCH /repos/{owner}/{repo}/labels/{id}DELETE /repos/{owner}/{repo}/issues/{index}/labels/{identifier}The client conflated the issue-attachment
identifierconvention with label CRUD.Impact
bug):/labels/bug-> 404 ->delete_labelreturnsFalse.Non-functional for every label.
/(ci/cd, a real label in this repo):/labels/ci/cd-> 404./labels/395-> 204, and deletes the labelwhose id is 395, which has nothing to do with the name. Reports success.
Live confirmation (this is not theoretical)
While probing this on
kade/forgejo-client, a label literally named"395"(id 642) was created and
DELETE .../labels/395was issued -- the exact call theclient makes. It returned 204 and deleted id 395, an unrelated label. That
label was hard-deleted: no
labelrow, noissue_labelreference, noactionlog entry (Forgejo records no label ops), and no backup on the host. Itis unrecoverable. No issue referenced it, so no issue lost a label; this repo now
has 51 labels instead of 52, with one definition (
id 395, name/colour unknown)permanently absent from the curated set.
Fix (implemented in the working tree)
Resolve the name to an id before the request, via the issues module's existing
_resolve_label_ids(already raises on unknown and on duplicate names):Tests (tests/test_labels.py, new)
test_numeric_label_name_does_not_target_the_matching_id-- the exact fixture(label id 395 named
telemetry, plus a label named"395"id 642) asserts theDELETE URL ends
/labels/642and never/labels/395.test_name_containing_a_slash_does_not_add_a_path_segmenttest_update_label_resolves_name_to_idtest_unknown_name_raises_and_sends_no_mutation,test_unknown_numeric_name_raises_...,test_duplicate_names_raise_...All fail against the pre-fix code (10/12 in the new file fail on HEAD).