kd-cli 2.9.0__tar.gz → 2.9.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {kd_cli-2.9.0/kd_cli.egg-info → kd_cli-2.9.1}/PKG-INFO +1 -1
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/resources/CHANGELOG.md +16 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/resources/error-messages.yaml +61 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1/kd_cli.egg-info}/PKG-INFO +1 -1
- {kd_cli-2.9.0 → kd_cli-2.9.1}/pyproject.toml +1 -1
- {kd_cli-2.9.0 → kd_cli-2.9.1}/LICENSE +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/MANIFEST.in +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/README.md +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/api/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/api/articles.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/api/http.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/api/hub.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/api/saved_queries.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/api/tags.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/api/youtrack.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/article_marker.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/auth.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cache.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/core/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/core/command_base.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/core/command_parser.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/core/confirm.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/core/namespaces.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/core/option_registry.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/input.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/main.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/alias/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/article/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/cache/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/init.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/issue/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/primer/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/project/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/query/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/release_notes.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/search/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/system/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/tag/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/time/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/namespaces/user/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/output.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/cli/tree.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/client.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/config.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/config_read.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/config_schema.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/connection.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/debug.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/exceptions.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/history.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/locking.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/article.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/assist.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/attachment.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/comment.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/common.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/issue.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/project.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/saved_query.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/search.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/tag.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/tag_entities.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/user.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/models/work_item.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/operating_guide.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/primer.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/query_parser.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/release_notes.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/resources/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/resources/command-synonyms.yaml +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/resources/config-template.yaml +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/resources/operating-guide.md +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/resources/primers/__init__.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/resources/primers/hitl.yaml +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/resources/sdlc-doctrine.md +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd/sdlc.py +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd_cli.egg-info/SOURCES.txt +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd_cli.egg-info/dependency_links.txt +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd_cli.egg-info/entry_points.txt +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd_cli.egg-info/requires.txt +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/kd_cli.egg-info/top_level.txt +0 -0
- {kd_cli-2.9.0 → kd_cli-2.9.1}/setup.cfg +0 -0
|
@@ -4,6 +4,22 @@ All notable changes to kd-cli are recorded here. The project follows [Semantic V
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.9.1] — 2026-05-12
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- `/tag add` and `/tag remove` no longer report "Article <id> not found"
|
|
11
|
+
when the upstream denies tag mutation. A 403 on
|
|
12
|
+
`DELETE /<articles|issues>/{id}/tags/{tag_id}` now surfaces as
|
|
13
|
+
"Tag remove denied for <article|issue> {id} (tag {tag_id})" with a
|
|
14
|
+
hint about tag ownership / `updateableBy` sharing; the 403 on
|
|
15
|
+
`POST /<articles|issues>/{id}/tags` surfaces as "Tag attach denied
|
|
16
|
+
for <article|issue> {id}". A 404 on the DELETE path now names the
|
|
17
|
+
tag attachment ("Tag {tag_id} was not found on <article|issue>
|
|
18
|
+
{id}") instead of falling through to the catch-all article/issue
|
|
19
|
+
404 rule. The resolver pre-flight (KDCLI-198) already covers
|
|
20
|
+
parent-missing and not-attached cases at the SDK boundary; this
|
|
21
|
+
closes the residual HTTP-status surface (KDCLI-197).
|
|
22
|
+
|
|
7
23
|
## [2.9.0] — 2026-05-12
|
|
8
24
|
|
|
9
25
|
### Changed
|
|
@@ -29,6 +29,57 @@
|
|
|
29
29
|
Time tracking may not be enabled for this project.
|
|
30
30
|
Enable it in YouTrack: project Settings → Time Tracking.
|
|
31
31
|
|
|
32
|
+
# --- Tag mutation 403 (articles, issues) ---
|
|
33
|
+
# DELETE carries a tag_id segment; POST does not (tag id is in the body).
|
|
34
|
+
# YouTrack's stock body for the tag-mutation permission check is
|
|
35
|
+
# "Can't tag issue" on both article and issue endpoints. The body
|
|
36
|
+
# pattern is load-bearing: a 403 on these paths can also come from
|
|
37
|
+
# parent-entity permission denial (token can't read the article/issue
|
|
38
|
+
# at all), and that has nothing to do with tag ownership. Without the
|
|
39
|
+
# pattern guard, those unrelated 403s would be misdescribed as an
|
|
40
|
+
# updateableBy gap. The rules below only fire when the body actually
|
|
41
|
+
# carries the tag-mutation denial.
|
|
42
|
+
|
|
43
|
+
- status: 403
|
|
44
|
+
path: '/articles/(?P<id>[^/]+)/tags/(?P<tag_id>[^/]+)$'
|
|
45
|
+
pattern: "(?i)can.t tag issue"
|
|
46
|
+
message: 'Tag remove denied for article {id} (tag {tag_id})'
|
|
47
|
+
suggestion: >-
|
|
48
|
+
YouTrack denied removing this tag. The tag's owner has not shared
|
|
49
|
+
mutation rights with you (its `updateableBy` group does not include
|
|
50
|
+
the caller). Either ask the tag owner to widen `updateableBy`, or
|
|
51
|
+
reassign the tag's `owner` to a shared account.
|
|
52
|
+
|
|
53
|
+
- status: 403
|
|
54
|
+
path: '/issues/(?P<id>[^/]+)/tags/(?P<tag_id>[^/]+)$'
|
|
55
|
+
pattern: "(?i)can.t tag issue"
|
|
56
|
+
message: 'Tag remove denied for issue {id} (tag {tag_id})'
|
|
57
|
+
suggestion: >-
|
|
58
|
+
YouTrack denied removing this tag. The tag's owner has not shared
|
|
59
|
+
mutation rights with you (its `updateableBy` group does not include
|
|
60
|
+
the caller). Either ask the tag owner to widen `updateableBy`, or
|
|
61
|
+
reassign the tag's `owner` to a shared account.
|
|
62
|
+
|
|
63
|
+
- status: 403
|
|
64
|
+
path: '/articles/(?P<id>[^/]+)/tags$'
|
|
65
|
+
pattern: "(?i)can.t tag issue"
|
|
66
|
+
message: 'Tag attach denied for article {id}'
|
|
67
|
+
suggestion: >-
|
|
68
|
+
YouTrack denied attaching this tag. The tag's owner has not shared
|
|
69
|
+
mutation rights with you (its `updateableBy` group does not include
|
|
70
|
+
the caller). Either ask the tag owner to widen `updateableBy`, or
|
|
71
|
+
reassign the tag's `owner` to a shared account.
|
|
72
|
+
|
|
73
|
+
- status: 403
|
|
74
|
+
path: '/issues/(?P<id>[^/]+)/tags$'
|
|
75
|
+
pattern: "(?i)can.t tag issue"
|
|
76
|
+
message: 'Tag attach denied for issue {id}'
|
|
77
|
+
suggestion: >-
|
|
78
|
+
YouTrack denied attaching this tag. The tag's owner has not shared
|
|
79
|
+
mutation rights with you (its `updateableBy` group does not include
|
|
80
|
+
the caller). Either ask the tag owner to widen `updateableBy`, or
|
|
81
|
+
reassign the tag's `owner` to a shared account.
|
|
82
|
+
|
|
32
83
|
# --- Sub-resource 404s (issues) ---
|
|
33
84
|
|
|
34
85
|
- status: 404
|
|
@@ -46,6 +97,11 @@
|
|
|
46
97
|
message: 'Comment {id} not found'
|
|
47
98
|
suggestion: 'Show the parent issue to list its comments.'
|
|
48
99
|
|
|
100
|
+
- status: 404
|
|
101
|
+
path: '/issues/(?P<id>[^/]+)/tags/(?P<tag_id>[^/]+)$'
|
|
102
|
+
message: 'Tag {tag_id} was not found on issue {id}'
|
|
103
|
+
suggestion: 'List currently attached tags with: kd /issue show <ISSUE> -o yaml.'
|
|
104
|
+
|
|
49
105
|
# --- Sub-resource 404s (articles) ---
|
|
50
106
|
|
|
51
107
|
- status: 404
|
|
@@ -58,6 +114,11 @@
|
|
|
58
114
|
message: 'Comment {id} not found'
|
|
59
115
|
suggestion: 'List comments with: kd /article comment list <ARTICLE>.'
|
|
60
116
|
|
|
117
|
+
- status: 404
|
|
118
|
+
path: '/articles/(?P<id>[^/]+)/tags/(?P<tag_id>[^/]+)$'
|
|
119
|
+
message: 'Tag {tag_id} was not found on article {id}'
|
|
120
|
+
suggestion: 'List currently attached tags with: kd /article show <ARTICLE> -o yaml.'
|
|
121
|
+
|
|
61
122
|
# --- Top-level 404s ---
|
|
62
123
|
|
|
63
124
|
- status: 404
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|