Skip to content

✨ Fail loudly when the source repository is not git - #162

Open
dymurray wants to merge 1 commit into
konveyor:mainfrom
dymurray:git-url-validation-143
Open

✨ Fail loudly when the source repository is not git#162
dymurray wants to merge 1 commit into
konveyor:mainfrom
dymurray:git-url-validation-143

Conversation

@dymurray

Copy link
Copy Markdown

Summary

The harness only supports git, but Hub's shared/scm also supports subversion. Previously a non-git source was passed straight into go-git and failed with a confusing deep clone error, with the reason landing only in pod logs.

This adds fail-fast validation and surfaces the reason on the AgentRun status:

  • harnessValidateSourceRepository (+ ErrUnsupportedSourceSCM sentinel) rejects non-git sources before cloning, using Hub's authoritative Repository.Kind (accept ""/git, reject anything else; also reject an empty URL). Kind is used rather than URL-scheme heuristics because SVN can also be served over https.
  • harness — on failure, a plain human-readable message is written to the pod termination log (best-effort).
  • controller — the pod termination message is surfaced on the AgentRun's Ready=False condition Message (falling back to the generic Sandbox reason), so the reason is visible via kubectl describe agentrun — not solely in logs. Adds pods RBAC and sets TerminationMessagePolicy=FallbackToLogsOnError on the agent container.

Validation lives in the harness (not the controller) because the clone URL is fetched from Hub at runtime and never passes through a CRD — keeping the controller domain-agnostic.

Test plan

  • make test — controller unit + envtest suites pass (new envtest asserts a failed pod's termination message lands on the Ready condition and phase is Failed).
  • cd harness && go test ./... — new tests for ValidateSourceRepository, termination.Write, all pass.
  • make lint — 0 issues; harness gofmt/go vet clean.

Fixes #143

🤖 Generated with Claude Code

The harness only supports git, but Hub's shared/scm also supports
subversion. Previously a non-git source URL was passed straight into
go-git and failed with a confusing deep clone error, with the reason
landing only in pod logs (issue konveyor#143).

Now the harness validates the source SCM before cloning, using Hub's
authoritative Repository.Kind (accept "" / "git", reject anything else;
also reject an empty URL). On failure it writes a plain human-readable
message to the pod termination log, which the controller surfaces on the
AgentRun's Ready=False condition so the reason is visible via
kubectl describe, not solely in logs.

- harness: ValidateSourceRepository + ErrUnsupportedSourceSCM sentinel.
- harness: termination.Write records the failure message best-effort.
- controller: copy the pod termination message onto the Ready condition
  (falls back to the generic Sandbox reason); add pods RBAC and set
  TerminationMessagePolicy=FallbackToLogsOnError on the agent container.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Dylan Murray <dymurray@redhat.com>
@dymurray
dymurray force-pushed the git-url-validation-143 branch from 0ad7e13 to ce8d441 Compare August 19, 2026 22:14
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@dymurray, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 58 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 67a2cfd2-f711-4fa8-a71b-ebc4e0e3b235

📥 Commits

Reviewing files that changed from the base of the PR and between ef5a7e1 and ce8d441.

📒 Files selected for processing (10)
  • changes/unreleased/143-git-source-validation.yaml
  • config/rbac/role.yaml
  • harness/cmd/migration-harness/main.go
  • harness/internal/hub/client.go
  • harness/internal/hub/client_test.go
  • harness/internal/termination/termination.go
  • harness/internal/termination/termination_test.go
  • internal/controller/agentrun_controller.go
  • internal/controller/agentrun_controller_test.go
  • internal/controller/agentrun_termination_test.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@savitharaghunathan

savitharaghunathan commented Aug 20, 2026

Copy link
Copy Markdown
Member

Thanks @dymurray — took a first pass at review, a few findings:

Blocking:

  1. Nil-pointer panic on apps with no repositoryharness/cmd/migration-harness/main.go:473
    resolveFromHub logs app.Repository.URL before the new ValidateSourceRepository(app.Repository) nil-check runs on line 477. Hub's Application.Repository is *api.Repository with omitempty, so an app with no source repo configured has Repository == nil — the log line panics before the graceful-rejection path this PR adds ever gets a chance to run. Suggest moving the ValidateSourceRepository call (or at least a nil guard) above the log statement.

Non-blocking / worth a look:

  1. Termination message can permanently stick on the generic fallbackinternal/controller/agentrun_controller.go:655
    lookupTerminationMessage does a single best-effort r.List() on Pods with no Watches/Owns on Pods and no requeue anywhere in the reconciler. If this controller's Pod informer cache lags behind the Sandbox "Finished" condition at the moment Reconcile fires, we get the generic "Sandbox finished with reason: ..." message permanently (Failed is terminal, nothing re-triggers Reconcile). Might be worth a short RequeueAfter retry if the message comes back empty, to close the race window.

  2. Error surfacing is broader than the issue scopeharness/cmd/migration-harness/main.go:48
    termination.Write(err.Error()) now fires for any rootCmd.Execute() failure (config parsing, DB/goose errors, push failures, etc.), not just the new SCM-validation error. That puts more internal error text onto AgentRun.Status.Conditions[Ready].Message, which is readable by a broader audience than pod logs typically require RBAC for. Not a credential leak (auth is passed separately from the URL in git.go), but worth confirming this broader exposure is intentional.

  3. Truncation can split a UTF-8 runeharness/internal/termination/termination.go:30
    message[:maxMessageLen] truncates by byte index, not rune boundary — a message with multi-byte chars near the 3072-byte cutoff could produce invalid UTF-8 in kubectl describe agentrun. Minor, but an easy fix (e.g. trim to the last valid rune boundary).

ctx context.Context,
run *konveyoriov1alpha1.AgentRun,
) string {
var pods corev1.PodList

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.

this is the controller's first pod read and r.List goes through the manager cache, which has no namespace or ByObject restriction, so it'll start a cluster-wide pod informer. Probably more resident memory than a best-effort message is worth. Could we use mgr.GetAPIReader() here instead?

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.

Error loudly when the source URL is not a git URL (skip non-git for dev-preview)

3 participants