Skip to content

fix(repo-info): preserve full CI-detected repo path in repo_info.name#1017

Merged
FayeSGW merged 4 commits into
mainfrom
gitlab-repo-name-full-path
Jul 14, 2026
Merged

fix(repo-info): preserve full CI-detected repo path in repo_info.name#1017
FayeSGW merged 4 commits into
mainfrom
gitlab-repo-name-full-path

Conversation

@FayeSGW

@FayeSGW FayeSGW commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Problem

For GitLab (and Bitbucket) CI, repo_info.name was reported as the short project name (e.g. creator) instead of the full path (e.g. cyber-dojo/creator), losing the namespace/sub-group context.

Root cause: getGitRepoInfoFromGitLab() correctly detects the full path (CI_PROJECT_PATH), but the --repository flag defaults to a shorter value (CI_PROJECT_NAME), and mergeGitRepoInfo unconditionally applied the flag value over the CI-detected base — so the short default always clobbered the full path. Bitbucket had the same latent issue (BITBUCKET_REPO_SLUG vs BITBUCKET_REPO_FULL_NAME).

Fix

--repository now overrides the CI-detected name only when set explicitly (or when the CI base has no name). Otherwise the fuller CI-detected value is preserved:

if repoName != "" && (repoNameExplicit || base.Name == "") {
    base.Name = repoName
}

repoNameExplicit is threaded from each command via cmd.Flags().Changed("repository"), mirroring the existing repoURLExplicit pattern.

Why this approach

The alternative — changing the GitLab --repository default to CI_PROJECT_PATH — would have broken GitLab's API ProjectID() (Org/Repositorynamespace/full-path, a duplicated namespace) and changed the meaning of --gitlab-org. This approach leaves the GitLab PR/API path completely untouched and fixes Bitbucket for free.

Testing

  • TestMergeGitRepoInfo — added cases for full-path preservation, explicit override, and a fully-populated base with no flags.
  • RepoInfoWiringTestSuite (new) — dry-run payload assertions across the three run() paths that build repo_info (attest generic, begin trail, attest artifact): CI-detected name used by default, explicit --repository overrides. A mutation (removing a repoNameExplicit assignment) fails the explicit cases, confirming the suite guards the wiring.
    • Not covered: attest pr * (call the live VCS API before the dry-run guard; token-gated, as the existing PR tests are).

Backward compatibility

  • Repo identity / history: safe. The server upserts repos by (org_id, repo_id) (external CI_PROJECT_ID), treating name as a mutable field. The next attestation updates the name in place — same inner_id, no fork. All downstream records (artifacts, trails, environment events, deployments, tags) key off inner_id, not name. The CLI only emits repo_info when id+name+url are all present, so the server's name-fallback (fork risk) is never triggered.
  • Behavior change (intended): GitLab/Bitbucket repos auto-detected without --repository now report the full path.
  • Breaking for old-name lookups: exact-match queries using the old short name stop resolving once the stored name flips — kosli get repo <short>, list artifacts --repo <short>, log environment --repo <short>, and the list-repos name= filter. Callers should use the full path, --repo-id, or search=. Not data loss.
  • Explicit --repository users, and GitHub/Azure/CircleCI users, are unaffected.
  • Mixed CLI-version rollout will make the stored name flap between short/full for the same repo_id; identity stays a single document throughout.

Follow-ups (not in this PR)

  • list artifacts --repo help/example still says yourRepoName; could be updated to reflect full-path naming.

FayeSGW and others added 2 commits July 13, 2026 12:24
The --repository flag defaults to a short repo name in some CIs
(GitLab's CI_PROJECT_NAME, Bitbucket's slug) while getGitRepoInfoFrom*
detects the full path (GitLab's CI_PROJECT_PATH). Because
mergeGitRepoInfo always applied the flag value, the short default
clobbered the full CI-detected name, so repo_info.name lost its
namespace (e.g. "creator" instead of "cyber-dojo/creator").

Only override the CI-detected name when --repository is set explicitly
(or when no CI name was detected), threading repoNameExplicit through
the attest/begin-trail commands. The GitLab API ProjectID path is
untouched. Also fixes the same latent issue for Bitbucket.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ment

Add RepoInfoWiringTestSuite covering the three run() paths that build
repo_info (attest generic, begin trail, attest artifact): the CI-detected
full-path name is used by default and an explicit --repository overrides
it. A mutation (removing a repoNameExplicit assignment) fails the
explicit cases, so the suite guards the command wiring.

Also add a mergeGitRepoInfo unit case for a fully-populated base with no
flags, and a comment on attestPRGitlab clarifying that GitlabConfig.
Repository (short, for the API ProjectID) is separate from repo_info.name
(full CI_PROJECT_PATH).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Claude finished @FayeSGW's task in 3m 11s —— View job


PR Review: preserve full CI-detected repo path in repo_info.name

  • Static analysis (go build, go vet, go mod tidy)
  • Review core merge logic (attestation.go)
  • Verify flag wiring across all commands
  • Review tests
  • Post review feedback

Verdict: LGTM ✅

Clean, correctly-scoped fix. I traced it end-to-end and it holds up across every provider.

Static analysis

Check Result
go build ./... ✅ pass
go vet ./... ✅ pass
go mod tidy + git diff ✅ clean

Correctness — verified against the source of the "fuller" name

The fix hinges on the CI-detected base name being richer than the --repository default. I confirmed this is true for exactly the two providers the PR targets, and a no-op for the rest:

Provider base Name (getGitRepoInfoFrom…) --repository default (ciTemplates) Effect of fix
GitLab CI_PROJECT_PATH (full) CI_PROJECT_NAME (short) full path preserved
Bitbucket BITBUCKET_REPO_FULL_NAME (full) BITBUCKET_REPO_SLUG (short) full path preserved
GitHub GITHUB_REPOSITORY (full) GITHUB_REPOSITORY (same) no change ✅
Azure BUILD_REPOSITORY_NAME same no change ✅
CircleCI CIRCLE_PROJECT_REPONAME same no change ✅

So the repoName != "" && (repoNameExplicit || base.Name == "") guard does exactly what's claimed, and only GitLab/Bitbucket behavior changes — matching the PR description.

Explicit-override via env var also works (worth noting for reviewers)

I checked whether cmd.Flags().Changed("repository") misses users who set KOSLI_REPOSITORY rather than the CLI flag. It does not: bindFlags in root.go:603 applies viper values through cmd.Flags().Set(...) during PersistentPreRunE, which marks the flag Changed=true before RunE reads it. CI env vars like CI_PROJECT_NAME aren't KOSLI_-prefixed, so they don't trip this — only a genuine explicit KOSLI_REPOSITORY does. The design is coherent.

Tests

  • TestMergeGitRepoInfo cases are well-chosen (full-path preservation, explicit override, fully-populated base, and the "apply flag when base has no name" fallback).
  • RepoInfoWiringTestSuite is a nice touch — it exercises all three real run() paths as dry-run payload assertions, and the header comment honestly documents the mutation test and the attest pr * coverage gap.
  • Wiring confirmed present in all 14 commands + the two standalone run()s (attestArtifact, beginTrail); go build passing means no struct is missing the embedded field.

Minor observations (non-blocking)

  1. Duplication of o.repoNameExplicit = cmd.Flags().Changed("repository") across 14 RunE bodies — already raised and you've agreed to defer. Agreed it's fine for now; it mirrors the existing repoURLExplicit convention.
  2. Asymmetry with repoID: repoID still overrides base.ID unconditionally while repoName is now conditional. This is correct (the repo-id default is CI_PROJECT_ID, which equals the base ID, so there's nothing to clobber), but a one-line comment noting why the two fields differ would save a future reader the same investigation I just did. Optional.

Good work worth calling out

  • Root cause nailed precisely, and the chosen fix leaves the GitLab API ProjectID() path untouched — the alternative (changing the default to CI_PROJECT_PATH) would have duplicated the namespace, as the PR notes.
  • The inline comment in attestPRGitlab.go distinguishing GitlabConfig.Repository (API) from repo_info.name is exactly the kind of note that prevents a future "helpful" refactor from reintroducing the bug.
  • The backward-compatibility analysis (upsert by repo_id, name as mutable field, old-short-name lookups breaking) is thorough and honest about the behavior change.
    gitlab-repo-name-full-path

Comment thread cmd/kosli/attestation.go
@FayeSGW FayeSGW enabled auto-merge (squash) July 14, 2026 08:04
@FayeSGW FayeSGW merged commit 6de291f into main Jul 14, 2026
20 checks passed
@FayeSGW FayeSGW deleted the gitlab-repo-name-full-path branch July 14, 2026 08:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants