gitserver

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 6, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

View Source
const NearExpiryThreshold = 1 * time.Hour

NearExpiryThreshold is how close to expiry credentials must be to trigger refresh

Variables

View Source
var (
	// ErrPathExists is returned when the checkout path already exists and is not empty
	ErrPathExists = errors.New("path already exists and is not empty")

	// ErrNoCredentials is returned when credentials are not available
	ErrNoCredentials = errors.New("git credentials not available")

	// ErrCloneFailed is returned when git clone fails
	ErrCloneFailed = errors.New("git clone failed")

	// ErrEmptyURL is returned when an empty repo URL is provided
	ErrEmptyURL = errors.New("repo URL cannot be empty")
)

Functions

func BuildAuthURL added in v0.3.0

func BuildAuthURL(repoURL string, creds *GitCredentials) (string, error)

BuildAuthURL embeds credentials into the git URL for authentication. Uses the PAT token with oauth2 username for GitLab-style auth. SSH URLs are returned unchanged since they use SSH key auth. Supports https:// URLs and http://localhost URLs (for local development).

func CacheFilesTracked added in v0.3.0

func CacheFilesTracked(repoPath string) bool

CacheFilesTracked returns true if any .sageox/cache/ files are tracked by git. Used by doctor checks to detect cache files that were committed before .gitignore was in place.

func CheckoutGitignoreNeedsFix added in v0.3.0

func CheckoutGitignoreNeedsFix(repoPath string) bool

CheckoutGitignoreNeedsFix returns true if .sageox/.gitignore is missing or doesn't contain all required entries. Used by doctor checks to detect whether EnsureCheckoutGitignore needs to run.

func CloneFromURLWithEndpoint

func CloneFromURLWithEndpoint(ctx context.Context, repoURL, path, endpointURL string, opts *CheckoutOptions) error

CloneFromURLWithEndpoint clones using endpoint-specific credentials. Falls back to default credentials if no endpoint-specific ones exist.

func CreateAgentsMD

func CreateAgentsMD(ctx context.Context, repoPath string, opts *AgentsMDOptions) error

CreateAgentsMD creates an AGENTS.md file in the cloned ledger repository. This file explains the repository's purpose to AI agents and humans. Commits and pushes the file if the repo has a remote.

func DefaultCheckoutPath

func DefaultCheckoutPath(repoName, workDir string) string

DefaultCheckoutPath returns the default checkout path for a repo. For ledger repos, defaults to sibling directory of the working directory. For team repos, defaults to a team-specific subdirectory.

func EnsureCheckoutGitignore added in v0.3.0

func EnsureCheckoutGitignore(repoPath string) error

EnsureCheckoutGitignore ensures .sageox/.gitignore exists in the given repo with required entries to prevent daemon-written files from appearing as untracked. Without this, isCheckoutClean() in the GC path sees these files as dirty and permanently blocks blue-green reclone.

Writes the file and commits it so the gitignore itself doesn't appear as untracked. The commit propagates upstream on the next daemon push cycle.

Idempotent: reads existing content, only writes/commits if entries are missing. Preserves any existing custom entries in the file.

func EnsureCheckoutGitignoreCtx added in v0.3.0

func EnsureCheckoutGitignoreCtx(ctx context.Context, repoPath string) error

EnsureCheckoutGitignoreCtx is like EnsureCheckoutGitignore but accepts a context.

func EnsureGitignoreBeforeCommit added in v0.3.0

func EnsureGitignoreBeforeCommit(repoPath string)

EnsureGitignoreBeforeCommit is a guard that MUST be called before any git commit to a ledger or team context. It ensures .sageox/.gitignore is in place so that local-only cache files (e.g., sync-state.json) are never committed.

Without this guard, broad operations like `git add -A` will stage cache files. Even with explicit file lists, this guard prevents future regressions.

Also untracks any cache files that were committed before .gitignore existed (git rm --cached does not delete the local file).

func EnsureGitignoreBeforeCommitCtx added in v0.3.0

func EnsureGitignoreBeforeCommitCtx(ctx context.Context, repoPath string)

EnsureGitignoreBeforeCommitCtx is like EnsureGitignoreBeforeCommit but accepts a context.

func GetGitVersion

func GetGitVersion() (string, error)

GetGitVersion returns the installed git version

func GetStorageBackend

func GetStorageBackend() string

GetStorageBackend returns the currently active storage backend. Returns "keychain" or "file" depending on what's available.

func IsGitInstalled

func IsGitInstalled() bool

IsGitInstalled checks if git is available in PATH

func RefreshRemoteCredentials added in v0.1.1

func RefreshRemoteCredentials(repoPath, endpointURL string) error

RefreshRemoteCredentials updates a repo's git remote URL with the current PAT from the credential store. Handles three cases:

  • Stale PAT: replaces with current credentials
  • Bare HTTPS URL (no PAT): inserts credentials if host matches credential store
  • Current PAT: no-op

No-op for SSH URLs or non-oauth2 usernames (deploy tokens). Returns nil on success or no-op. Returns an error if credentials are unavailable or the git command fails — callers should log and continue, not abort.

func RemoveCredentials

func RemoveCredentials() error

RemoveCredentials deletes git server credentials from all storage locations. Removes from both keychain and file storage to ensure complete cleanup.

func RemoveCredentialsForEndpoint

func RemoveCredentialsForEndpoint(endpointURL string) error

RemoveCredentialsForEndpoint deletes git credentials for a specific endpoint. Removes from both keychain and file storage to ensure complete cleanup.

func SanitizeRemoteURL added in v0.1.1

func SanitizeRemoteURL(rawURL string) string

SanitizeRemoteURL removes credentials from a URL for safe display. Returns the original string for SSH URLs or unparseable URLs.

func SaveCredentialsForEndpoint

func SaveCredentialsForEndpoint(endpointURL string, creds GitCredentials) error

SaveCredentialsForEndpoint saves git credentials for a specific endpoint. Uses OS keychain as primary storage (with endpoint-specific key). Falls back to file storage for CI/headless environments.

func StripRemoteCredentials added in v0.1.1

func StripRemoteCredentials(repoPath string) error

StripRemoteCredentials removes embedded credentials from a repo's git remote URL. Transforms https://oauth2:TOKEN@host/repo.githttps://host/repo.git No-op for SSH URLs, bare URLs, or URLs without oauth2 userinfo.

func TestSetConfigDirOverride

func TestSetConfigDirOverride(dir string) string

TestSetConfigDirOverride sets the config directory override for testing. Returns the previous value so it can be restored. This function should only be called from tests.

func TestSetForceFileStorage

func TestSetForceFileStorage(force bool) bool

TestSetForceFileStorage forces file-based storage for testing. Returns the previous value so it can be restored. This function should only be called from tests.

func ValidateTeamContextClone added in v0.3.0

func ValidateTeamContextClone(repoPath string, cfg *manifest.ManifestConfig)

ValidateTeamContextClone checks that a freshly cloned team context has expected content. All checks are warning-only — a missing file does not fail the clone.

Types

type AgentsMDOptions

type AgentsMDOptions struct {
	// RepoURL is the linked repository URL (optional)
	RepoURL string

	// TeamID is the team identifier (optional)
	TeamID string

	// Endpoint is the SageOx API endpoint (optional, defaults to production)
	Endpoint string

	// RepoType is the type of repository ("ledger" or "team-context")
	RepoType string
}

AgentsMDOptions configures AGENTS.md generation.

type CheckoutOptions

type CheckoutOptions struct {
	// Depth sets shallow clone depth (0 = full clone)
	Depth int

	// Branch specifies the branch to checkout (empty = default branch)
	Branch string

	// SingleBranch clones only the specified branch (or default branch if Branch is empty)
	SingleBranch bool

	// PartialClone enables --filter=blob:none (treeless clone, blobs fetched on demand)
	PartialClone bool

	// Sparse enables --sparse (sparse checkout mode)
	Sparse bool

	// NoCheckout enables --no-checkout (skip working tree creation after clone)
	NoCheckout bool
}

CheckoutOptions configures the checkout behavior

type CredentialFetcher

type CredentialFetcher func() (*GitCredentials, error)

CredentialFetcher is a function that fetches new credentials from the API. Returns the new credentials or an error. The caller is responsible for providing authentication context.

type CredentialStatus

type CredentialStatus struct {
	// Valid is true if credentials exist and are not expired
	Valid bool
	// Reason describes why credentials are invalid (empty if valid)
	Reason string
	// RepoCount is the number of repos in credentials (0 if invalid)
	RepoCount int
	// ExpiresAt is when credentials expire (zero if unknown)
	ExpiresAt time.Time
	// TimeUntilExpiry is the duration until expiry (negative if expired)
	TimeUntilExpiry time.Duration
}

CredentialStatus represents the current state of git credentials

func CheckCredentialStatusForEndpoint

func CheckCredentialStatusForEndpoint(endpointURL string) CredentialStatus

CheckCredentialStatusForEndpoint checks the status of credentials for a specific endpoint.

func EnsureValidCredentialsForEndpoint

func EnsureValidCredentialsForEndpoint(endpointURL string, fetcher CredentialFetcher) (CredentialStatus, error)

EnsureValidCredentialsForEndpoint checks credentials for a specific endpoint and refreshes if needed. This is the endpoint-aware version that should be used in multi-endpoint setups.

func (CredentialStatus) FormatExpiry

func (s CredentialStatus) FormatExpiry() string

FormatExpiry returns a human-readable expiry string

func (CredentialStatus) NeedsRefresh

func (s CredentialStatus) NeedsRefresh() bool

NeedsRefresh returns true if credentials need to be refreshed

type GitCredentials

type GitCredentials struct {
	Token     string               `json:"token"`
	ServerURL string               `json:"server_url"`
	Username  string               `json:"username"`
	ExpiresAt time.Time            `json:"expires_at"`
	Repos     map[string]RepoEntry `json:"repos,omitempty"` // indexed by team ID
}

GitCredentials holds git server authentication credentials and repo URLs. Repos contains team-context repos indexed by team ID. Ledger URLs are NOT stored here.

func LoadCredentialsForEndpoint

func LoadCredentialsForEndpoint(endpointURL string) (*GitCredentials, error)

LoadCredentialsForEndpoint loads git credentials for a specific endpoint. Tries OS keychain first (with endpoint-specific key), falls back to file storage. Falls back to default credentials if endpoint-specific ones don't exist.

func (*GitCredentials) AddRepo

func (c *GitCredentials) AddRepo(entry RepoEntry)

AddRepo adds or updates a repo entry

func (*GitCredentials) GetRepo

func (c *GitCredentials) GetRepo(name string) *RepoEntry

GetRepo returns a repo entry by name, or nil if not found

func (*GitCredentials) IsExpired

func (c *GitCredentials) IsExpired() bool

IsExpired checks if the credentials are expired

type RefreshResult

type RefreshResult struct {
	// Refreshed is true if new credentials were fetched and saved
	Refreshed bool
	// Skipped is true if refresh was skipped (credentials still valid)
	Skipped bool
	// Error is set if refresh failed (old credentials preserved)
	Error error
	// Status is the credential status after refresh attempt
	Status CredentialStatus
}

RefreshResult describes the outcome of a credential refresh attempt

func RefreshCredentialsForEndpoint

func RefreshCredentialsForEndpoint(endpointURL string, fetcher CredentialFetcher, force bool) RefreshResult

RefreshCredentialsForEndpoint checks and refreshes credentials for a specific endpoint. This is the endpoint-aware version that saves credentials to the correct per-endpoint file.

type RepoEntry

type RepoEntry struct {
	Name   string `json:"name"`              // display name (e.g., "Ox CLI Test")
	Type   string `json:"type"`              // "team-context"
	URL    string `json:"url"`               // git clone URL
	TeamID string `json:"team_id,omitempty"` // stable team identifier (e.g., "team_jij1bg2btu")
	Slug   string `json:"slug,omitempty"`    // kebab-case team slug (server-provided)
}

RepoEntry represents a single git repository from the credentials API. NOTE: GET /api/v1/cli/repos only returns team-context repos, not ledgers. Ledger URLs come from GET /api/v1/repos/{repo_id}/ledger-status separately.

func (RepoEntry) StableID

func (r RepoEntry) StableID() string

StableID returns the stable team identifier (team_xxx) for path construction and lookups.

type TwoPhaseCloneResult added in v0.3.0

type TwoPhaseCloneResult struct {
	ManifestConfig *manifest.ManifestConfig
	SparsePaths    []string
}

TwoPhaseCloneResult holds the result of a two-phase team context clone.

func TwoPhaseClone added in v0.3.0

func TwoPhaseClone(ctx context.Context, cloneURL, repoPath string) (*TwoPhaseCloneResult, error)

TwoPhaseClone performs a two-phase partial clone for team context repos.

Phase 1: Clone with --filter=blob:none --depth=1 --sparse --no-checkout, materialize only .sageox/ to read the manifest.

Phase 2: Read manifest, compute sparse set, apply sparse checkout to materialize only allowed paths. Unshallow for pull --rebase compatibility.

This function is used by both the daemon (normal path) and the CLI (doctor fallback when daemon unavailable).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL