Commit id of annotated tags not supported

27 views
Skip to first unread message

Larisch, Tamino

unread,
Feb 10, 2026, 5:04:49 AMFeb 10
to kas-...@googlegroups.com
Hi,

While working on adding a Kas manager to Renovate, I discovered that
Kas doesn't support using the commit ID of annotated tags to pin a
repository when combined with a specific tag. This is problematic
because Renovate's git-tag datasource consistently retrieves the commit
Id of annotated tags for a given tag, which then causes errors in Kas
as shown below.

My question is: should we consider allowing that as well?

Example kas dump output:
ERROR - Provided tag "yocto-5.2.4"
("ac097300921590ed6a814f2c3fa08a59f4ded92d") does not match provided
commit "5b889f5d92e7bcebbe664538402f1c3a433e8189" in repository
"bitbake", aborting!

Manual checkout works:
git checkout 5b889f5d92e7bcebbe664538402f1c3a433e8189
HEAD is now at ac0973009 tests/fetch: Update tests...

git show-ref yocto-5.2.4
5b889f5d92e7bcebbe664538402f1c3a433e8189 refs/tags/yocto-5.2.4

git ls-remote origin | grep yocto-5.2.4
5b889f5d92e7bcebbe664538402f1c3a433e8189 refs/tags/yocto-5.2.4
ac097300921590ed6a814f2c3fa08a59f4ded92d refs/tags/yocto-5.2.4^{}

Best regards,
Tamino Larisch
--
Tamino Larisch
Siemens AG
www.siemens.com

Jan Kiszka

unread,
Feb 10, 2026, 6:37:15 AMFeb 10
to Larisch, Tamino, kas-...@googlegroups.com
Well, sounds reasonable to support this. But how can we reliably
retrieve the commit ID from the signed tag?

Jan

--
Siemens AG, Foundational Technologies
Linux Expert Center

Larisch, Tamino

unread,
Feb 11, 2026, 11:53:10 AMFeb 11
to Kiszka, Jan, kas-...@googlegroups.com
Maybe with the same command, we use to resolve a tag?
As shown in the following patch.

Tamino
0001-repos-allow-commit-id-of-annotated-tags.patch
0002-test-pinning-repo-with-commit-id-of-annotated-tag.patch

Jan Kiszka

unread,
Feb 11, 2026, 3:16:01 PMFeb 11
to Larisch, Tamino (FT RPD CED OES-DE), kas-...@googlegroups.com
Please send patches inline so that we do not need to copy them around
for comments:

> From cb660ec69689b5717a704a512a4485361ca193e9 Mon Sep 17 00:00:00 2001
> From: Tamino Larisch <tamino....@siemens.com>
> Date: Wed, 11 Feb 2026 17:04:08 +0100
> Subject: [PATCH 1/2] repos: allow commit id of annotated tags
>
> Support using the commit ID of annotated tags to pin a repository when
> combined with this specific tag name. This is a second alternative to
> pin a repository.
>
> Signed-off-by: Tamino Larisch <tamino....@siemens.com>
> ---
> kas/repos.py | 17 ++++++++++++-----
> 1 file changed, 12 insertions(+), 5 deletions(-)
>
> diff --git a/kas/repos.py b/kas/repos.py
> index ed1122d..68c2ace 100644
> --- a/kas/repos.py
> +++ b/kas/repos.py
> @@ -501,11 +501,15 @@ class RepoImpl(Repo):
>
> desired_ref = output.strip()
> if self.commit and desired_ref != self.commit:
> - # Ensure provided commit and tag match
> - raise RepoRefError(f'Provided tag "{self.tag}" '
> - f'("{desired_ref}") does not match '
> - f'provided commit "{self.commit}" in '
> - f'repository "{self.name}", aborting!')
> + (retc, output) = run_cmd(self.resolve_commit_cmd(),
> + cwd=self.path,
> + fail=False)
> + if desired_ref != output.strip():
> + # Ensure provided commit and tag match
> + raise RepoRefError(f'Provided tag "{self.tag}" '
> + f'("{desired_ref}") does not match '
> + f'provided commit "{self.commit}" in '
> + f'repository "{self.name}", aborting!')
> is_branch = False
> elif self.branch:
> (retc, output) = run_cmd(self.resolve_branch_cmd(),
> @@ -738,6 +742,9 @@ class GitRepo(RepoImpl):
> def resolve_tag_cmd(self):
> return ['git', 'rev-list', '-n', '1', self.remove_ref_prefix(self.tag)]
>
> + def resolve_commit_cmd(self):
> + return ['git', 'rev-list', '-n', '1', self.commit]
> +

There is "git show-ref refs/tags/<tag>" to tell you the commit ID of an
annotated tag. I think is it nicer to match the specified commit ID
against that - and call this helper differently (revolve_annotated_tag_cmd).

And don't forget to provide a method for MercurialRepo as well.

Tamino Larisch

unread,
Feb 15, 2026, 12:17:17 PMFeb 15
to jan.k...@siemens.com, kas-...@googlegroups.com, Tamino Larisch
Support using the commit ID of annotated tags to pin a repository when
combined with this specific tag name. This is a second alternative to
pin a repository.

Signed-off-by: Tamino Larisch <tamino....@siemens.com>
---
kas/repos.py | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/kas/repos.py b/kas/repos.py
index ed1122d..0aa67a4 100644
--- a/kas/repos.py
+++ b/kas/repos.py
@@ -501,11 +501,12 @@ class RepoImpl(Repo):

desired_ref = output.strip()
if self.commit and desired_ref != self.commit:
- # Ensure provided commit and tag match
- raise RepoRefError(f'Provided tag "{self.tag}" '
- f'("{desired_ref}") does not match '
- f'provided commit "{self.commit}" in '
- f'repository "{self.name}", aborting!')
+ if not self.annotated_tag_matches_commit():
+ # Ensure provided commit and tag match
+ raise RepoRefError(f'Provided tag "{self.tag}" '
+ f'("{desired_ref}") does not match '
+ f'provided commit "{self.commit}" in '
+ f'repository "{self.name}", aborting!')
is_branch = False
elif self.branch:
(retc, output) = run_cmd(self.resolve_branch_cmd(),
@@ -738,6 +739,14 @@ class GitRepo(RepoImpl):
def resolve_tag_cmd(self):
return ['git', 'rev-list', '-n', '1', self.remove_ref_prefix(self.tag)]

+ def resolve_annotated_tag_cmd(self):
+ return ['git', 'show-ref', '--tags', self.remove_ref_prefix(self.tag)]
+
+ def annotated_tag_matches_commit(self):
+ (_, output) = run_cmd(self.resolve_annotated_tag_cmd(),
+ cwd=self.path, fail=False)
+ return output.split()[0] == self.commit
+
def branch_contains_ref(self):
return ['git', 'branch', f'origin/{self.branch}',
'-r', '--contains', self.commit]
@@ -849,6 +858,12 @@ class MercurialRepo(RepoImpl):
refspec = self.tag or self.refspec
return ['hg', 'identify', '--id', '-r', f'tag({refspec})']

+ def resolve_annotated_tag_cmd(self):
+ raise NotImplementedError("Mercurial does not support annotated tags")
+
+ def annotated_tag_matches_commit(self):
+ return False
+
def branch_contains_ref(self):
return ['hg', 'log', '-r', self.commit, '-b', self.branch]

--
2.39.5

Tamino Larisch

unread,
Feb 15, 2026, 12:17:29 PMFeb 15
to jan.k...@siemens.com, kas-...@googlegroups.com, Tamino Larisch
Signed-off-by: Tamino Larisch <tamino....@siemens.com>
---
tests/test_commands.py | 17 ++++++++++++-----
tests/test_commands/test-invalid-tag.yml | 9 +++++++++
tests/test_commands/test-shallow.yml | 5 +++++
3 files changed, 26 insertions(+), 5 deletions(-)
create mode 100644 tests/test_commands/test-invalid-tag.yml

diff --git a/tests/test_commands.py b/tests/test_commands.py
index 13386c7..777227a 100644
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -31,7 +31,7 @@ import pytest
from kas import kas
from kas.libkas import TaskExecError, KasUserError, run_cmd
from kas.attestation import file_digest_slow
-from kas.repos import RepoFetchError
+from kas.repos import RepoFetchError, RepoRefError


@pytest.mark.dirsfromenv
@@ -99,12 +99,19 @@ def test_checkout(monkeykas, tmpdir):
kas.kas(['checkout', '--update', 'test-no-commit.yml'])


-def test_invalid_checkout(monkeykas, tmpdir, capsys):
+...@pytest.mark.parametrize(
+ "file, error",
+ [
+ ('test-invalid.yml', TaskExecError),
+ ('test-invalid-tag.yml', RepoRefError),
+ ],
+)
+def test_invalid_checkout(monkeykas, tmpdir, capsys, file, error):
tdir = str(tmpdir / 'test_commands')
shutil.copytree('tests/test_commands', tdir)
monkeykas.chdir(tdir)
- with pytest.raises(TaskExecError):
- kas.kas(['checkout', 'test-invalid.yml'])
+ with pytest.raises(error):
+ kas.kas(['checkout', file])


@pytest.mark.dirsfromenv
@@ -151,7 +158,7 @@ def test_checkout_shallow(monkeykas, tmpdir):
with monkeykas.context() as mp:
mp.setenv('KAS_CLONE_DEPTH', '1')
kas.kas(['checkout', 'test-shallow.yml'])
- for repo in ['kas_1', 'kas_2', 'kas_3', 'kas_4']:
+ for repo in ['kas_1', 'kas_2', 'kas_3', 'kas_4', 'kas_5']:
repo_path = monkeykas.get_kwd() / repo
output = subprocess.check_output(
['git', 'rev-list', '--count', 'HEAD'], cwd=repo_path)
diff --git a/tests/test_commands/test-invalid-tag.yml b/tests/test_commands/test-invalid-tag.yml
new file mode 100644
index 0000000..ab575d6
--- /dev/null
+++ b/tests/test_commands/test-invalid-tag.yml
@@ -0,0 +1,9 @@
+header:
+ version: 15
+
+repos:
+ kas_invalid:
+ url: https://github.com/siemens/kas.git
+ tag: '4.3'
+ # non matching commit (tag: 4.2)
+ commit: 23211cbd3518936d83169722d1eb40656344ba27
diff --git a/tests/test_commands/test-shallow.yml b/tests/test_commands/test-shallow.yml
index dfd711c..c5a7a15 100644
--- a/tests/test_commands/test-shallow.yml
+++ b/tests/test_commands/test-shallow.yml
@@ -21,3 +21,8 @@ repos:
url: https://github.com/siemens/kas.git
# keep legacy refspec here for testing purposes
refspec: master
+
+ kas_5:
+ url: https://github.com/siemens/kas.git
+ tag: '4.3'
+ commit: beb5b60c6823ec53300efb3b854a5a921b22bd3d
--
2.39.5

Jan Kiszka

unread,
Feb 16, 2026, 12:51:05 AMFeb 16
to Tamino Larisch, kas-...@googlegroups.com
You can fold this method into its only caller.

BTW, it looks like you do not need to strip the refs/tags/ prefix for
this operation.

> +
> + def annotated_tag_matches_commit(self):
> + (_, output) = run_cmd(self.resolve_annotated_tag_cmd(),
> + cwd=self.path, fail=False)
> + return output.split()[0] == self.commit

You are processing an error message with "output" here in case run_cmd
failed. I would avoid that and directly return False then.

> +
> def branch_contains_ref(self):
> return ['git', 'branch', f'origin/{self.branch}',
> '-r', '--contains', self.commit]
> @@ -849,6 +858,12 @@ class MercurialRepo(RepoImpl):
> refspec = self.tag or self.refspec
> return ['hg', 'identify', '--id', '-r', f'tag({refspec})']
>
> + def resolve_annotated_tag_cmd(self):
> + raise NotImplementedError("Mercurial does not support annotated tags")

Real dead code.

> +
> + def annotated_tag_matches_commit(self):
> + return False
> +
> def branch_contains_ref(self):
> return ['hg', 'log', '-r', self.commit, '-b', self.branch]
>

Jan Kiszka

unread,
Feb 16, 2026, 12:51:40 AMFeb 16
to Tamino Larisch, kas-...@googlegroups.com
On 15.02.26 18:16, Tamino Larisch wrote:
This is the tag object for 4.3, right? Leave a comment to make this more
readable.

Tamino Larisch

unread,
Feb 16, 2026, 6:11:01 AM (14 days ago) Feb 16
to jan.k...@siemens.com, kas-...@googlegroups.com, Tamino Larisch
Support using the commit ID of annotated tags to pin a repository when
combined with this specific tag name. This is a second alternative to
pin a repository.

Signed-off-by: Tamino Larisch <tamino....@siemens.com>
---
kas/repos.py | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/kas/repos.py b/kas/repos.py
index ed1122d..dbdf94b 100644
--- a/kas/repos.py
+++ b/kas/repos.py
@@ -501,11 +501,12 @@ class RepoImpl(Repo):

desired_ref = output.strip()
if self.commit and desired_ref != self.commit:
- # Ensure provided commit and tag match
- raise RepoRefError(f'Provided tag "{self.tag}" '
- f'("{desired_ref}") does not match '
- f'provided commit "{self.commit}" in '
- f'repository "{self.name}", aborting!')
+ if not self.annotated_tag_matches_commit():
+ # Ensure provided commit and tag match
+ raise RepoRefError(f'Provided tag "{self.tag}" '
+ f'("{desired_ref}") does not match '
+ f'provided commit "{self.commit}" in '
+ f'repository "{self.name}", aborting!')
is_branch = False
elif self.branch:
(retc, output) = run_cmd(self.resolve_branch_cmd(),
@@ -738,6 +739,13 @@ class GitRepo(RepoImpl):
def resolve_tag_cmd(self):
return ['git', 'rev-list', '-n', '1', self.remove_ref_prefix(self.tag)]

+ def annotated_tag_matches_commit(self):
+ cmd = ['git', 'show-ref', '--tags', self.tag]
+ (retc, output) = run_cmd(cmd, cwd=self.path, fail=False)
+ if retc:
+ return False
+ return output.split()[0] == self.commit
+
def branch_contains_ref(self):
return ['git', 'branch', f'origin/{self.branch}',
'-r', '--contains', self.commit]
@@ -849,6 +857,9 @@ class MercurialRepo(RepoImpl):
refspec = self.tag or self.refspec
return ['hg', 'identify', '--id', '-r', f'tag({refspec})']

+ def annotated_tag_matches_commit(self):
+ return False
+
def branch_contains_ref(self):
return ['hg', 'log', '-r', self.commit, '-b', self.branch]

--
2.39.5

Tamino Larisch

unread,
Feb 16, 2026, 6:11:03 AM (14 days ago) Feb 16
to jan.k...@siemens.com, kas-...@googlegroups.com, Tamino Larisch
Signed-off-by: Tamino Larisch <tamino....@siemens.com>
---
tests/test_commands.py | 17 ++++++++++++-----
tests/test_commands/test-invalid-tag.yml | 9 +++++++++
tests/test_commands/test-shallow.yml | 6 ++++++
3 files changed, 27 insertions(+), 5 deletions(-)
index dfd711c..dd90d52 100644
--- a/tests/test_commands/test-shallow.yml
+++ b/tests/test_commands/test-shallow.yml
@@ -21,3 +21,9 @@ repos:
url: https://github.com/siemens/kas.git
# keep legacy refspec here for testing purposes
refspec: master
+
+ kas_5:
+ url: https://github.com/siemens/kas.git
+ tag: '4.3'
+ # commid id of tag object 4.3:

Jan Kiszka

unread,
Feb 16, 2026, 8:54:58 AM (14 days ago) Feb 16
to Tamino Larisch, kas-...@googlegroups.com
Thanks, applied this instance of the series - next time versioned,
please ;).

Jan Kiszka

unread,
Feb 16, 2026, 1:12:18 PM (14 days ago) Feb 16
to Tamino Larisch, kas-...@googlegroups.com
On 16.02.26 12:10, Tamino Larisch wrote:
Needs a "@pytest.mark.online", or our CI becomes unhappy. Fixed in next,
no need for a new version.

Jan
Reply all
Reply to author
Forward
0 new messages