Skip to content

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

Open
FayeSGW wants to merge 3 commits into
mainfrom
gitlab-repo-name-full-path
Open

fix(repo-info): preserve full CI-detected repo path in repo_info.name#1017
FayeSGW wants to merge 3 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 35s —— View job


Review complete ✅

  • Static analysis (go build ./..., go vet ./... — both clean; go.mod/go.sum untouched)
  • Review the merge logic in attestation.go
  • Review flag threading across command files
  • Review tests (attestation_test.go, repoInfoWiring_test.go)
  • Investigate the .approval_tests_temp added file
  • Post review summary

Summary

This is a well-scoped, well-reasoned fix. The root-cause analysis in the PR description checks out against the code:

  • getGitRepoInfoFromGitLab() sets Name: CI_PROJECT_PATH (full path) and Bitbucket sets BITBUCKET_REPO_FULL_NAME, while the --repository default is the short CI_PROJECT_NAME / BITBUCKET_REPO_SLUG (cli_utils.go:103,116).
  • The old unconditional if repoName != "" clobbered the fuller CI base. The new guard repoName != "" && (repoNameExplicit || base.Name == "") is correct and minimal.

Verified:

  • ✅ All 14 call sites that reach mergeGitRepoInfo (12 attest * subcommands via CommonAttestationOptions.run, plus attest artifact and begin trail) set repoNameExplicit. No missing wiring.
  • ✅ The GitLab PR/API path (GitlabConfig.Repository = o.repoNameProjectID) is left untouched, and the new comment at attestPRGitlab.go:146-148 documents why the short name is still needed there. Good call preferring this over changing the default.
  • ✅ Empty-string edge case is safe: --repository "" can't clear an existing name (the repoName != "" guard).

Tests — strong. TestMergeGitRepoInfo gains focused cases (full-path preservation, explicit override, fully-populated base, base-has-no-name). The new RepoInfoWiringTestSuite guards the command wiring across all three run() paths and is honest about its limits (attest pr * is token-gated; the underlying default-clobber can't reproduce under KOSLI_TESTS). The mutation-testing note (removing a repoNameExplicit assignment fails the explicit cases) is exactly the right way to justify a wiring test. Env vars are saved/restored in SetupSuite/TearDownSuite — good hygiene (and safe since cmd/kosli tests run sequentially).

Note: I couldn't execute the test suites here — go test needs approval in this environment — but the two suites are pure/dry-run (no server), go build/go vet pass, and the logic is verified by inspection.

Issues

1. Stray file committed — .approval_tests_temp/.approved_files.log (should be removed)
This empty file was added in commit ef99408e. It's not gitignored and isn't referenced by any approval-testing setup in the repo — it looks like an accidental artifact from a local tool run. Recommend git rm it and, if the tool is used locally, add .approval_tests_temp/ to .gitignore.
Fix this →

2. Per-command duplication of the Changed("repository") assignment (minor / maintainability)
See the inline comment on attestation.go:102. Threading repoNameExplicit through 14 RunE bodies mirrors the existing repoURLExplicit pattern, so it's consistent — but a future attest command that omits the line would silently ignore an explicit --repository. Worth a follow-up to centralize; not blocking.

Nits (optional)

  • The PR body itself flags that list artifacts --repo help still says yourRepoName. Since the stored name now flips to the full path for GitLab/Bitbucket, updating that example (and a one-line note in the changelog/release notes about the old-short-name lookup break) would help users who hit the behavior change.

Overall: clean fix, thoughtful backward-compat analysis, good tests. The only thing I'd block on is removing the stray .approval_tests_temp/ file.
• branch gitlab-repo-name-full-path

Comment thread cmd/kosli/attestation.go
return err
}
payload.GitRepoInfo = mergeGitRepoInfo(payload.GitRepoInfo, o.repoID, o.repoName, o.repoURL, o.repoProvider)
payload.GitRepoInfo = mergeGitRepoInfo(payload.GitRepoInfo, o.repoID, o.repoName, o.repoURL, o.repoProvider, o.repoNameExplicit)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor / maintainability: o.repoNameExplicit is populated per-command via cmd.Flags().Changed("repository") duplicated across 14 RunE bodies. Any future attest command that forgets that line will silently fall back to repoNameExplicit=false, causing an explicit --repository to be ignored whenever a CI-detected base name is present — a quiet correctness regression rather than a compile error.

This mirrors the existing repoURLExplicit convention, so it's consistent and fine to keep. But since run() already has the flag values, consider a follow-up that derives both *Explicit bools centrally (e.g. threading cmd in, or a shared PersistentPreRunE on the attest command group) so it can't be forgotten. Not blocking.

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.

1 participant