mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 15:51:26 +00:00
Git-sourced deploys never materialized a checkout: sourcePath was build_path resolved against the server cwd, so builds consumed the backend's own directory. Remote placement could only run registry-pulled images. - internal/source: per-deployment checkout (init/fetch/checkout) at branch or commit; GIT_ASKPASS keeps tokens out of argv, .git/config, and the build context; dumb-transport and SHA-refusal fallbacks; build_path validated inside the checkout. - BuildManager.PackageContext: produces the same tar context Build ships to the daemon — generated Dockerfile at tar root, .git excluded. Fixes nixpacks passing the Dockerfile path as content. - Agent artifact endpoint: GET /api/agents/artifacts/:id streams build contexts and docker-save tarballs behind agent-token auth; hex-validated ids, per-deployment cleanup, boot-time purge. - Agent commands: build_image (docker build -, --build-arg values via process env, not argv) and load_image (docker load for containr-* rollback tags no registry serves). - Deployment flow: remote git builds package context → artifact → node docker-builds the deployment tag; remote rollbacks of local tags export via SaveImage → artifact → node docker-loads. Verified end-to-end: agent-pinned git service built on the node (build_image → create_container → deployed) and rollback shipped a docker-save tarball (load_image → deployed). Artifact auth returns 401/404 correctly; workspaces and blobs are removed after deploy. Authored By: TDvorak <[email protected]>
85 lines
2.5 KiB
Go
85 lines
2.5 KiB
Go
package api
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"containr/internal/database"
|
|
"containr/internal/source"
|
|
)
|
|
|
|
// resolveGitCloneSpec turns a service's git_repo (clone URL, ssh remote, or
|
|
// owner/repo) into a source.Spec with the project owner's provider token.
|
|
// Public repos get no token — the clone proceeds anonymously. github_app
|
|
// providers store the installation id, not a usable token; a fresh
|
|
// installation token is minted per deploy.
|
|
func resolveGitCloneSpec(db *database.DB, ownerID, gitRepo, branch, commit, buildPath string) (source.Spec, error) {
|
|
raw := strings.TrimSpace(gitRepo)
|
|
cloneURL, err := source.NormalizeCloneURL(raw)
|
|
if err != nil {
|
|
return source.Spec{}, err
|
|
}
|
|
|
|
spec := source.Spec{Branch: branch, Commit: commit, BuildPath: buildPath}
|
|
|
|
var providerID string
|
|
if !strings.Contains(cloneURL, "://") {
|
|
// Bare owner/repo — the connected repository row knows the host.
|
|
err = db.QueryRow(
|
|
`SELECT clone_url, provider_id FROM git_repositories
|
|
WHERE full_name = $1 AND user_id = $2 LIMIT 1`,
|
|
cloneURL, ownerID,
|
|
).Scan(&cloneURL, &providerID)
|
|
if err != nil {
|
|
return source.Spec{}, fmt.Errorf("repository %s is not connected — connect it under Git settings or store a clone URL", raw)
|
|
}
|
|
} else {
|
|
// URL form — match a connected repo for its provider when possible;
|
|
// an unmatched public URL still clones, just without credentials.
|
|
_ = db.QueryRow(
|
|
`SELECT provider_id FROM git_repositories
|
|
WHERE clone_url = $1 AND user_id = $2 LIMIT 1`,
|
|
cloneURL, ownerID,
|
|
).Scan(&providerID)
|
|
}
|
|
|
|
if err := source.ValidateRemoteURL(cloneURL); err != nil {
|
|
return source.Spec{}, err
|
|
}
|
|
spec.CloneURL = cloneURL
|
|
|
|
if providerID == "" {
|
|
return spec, nil
|
|
}
|
|
var name, apiURL, token string
|
|
if err := db.QueryRow(
|
|
`SELECT name, api_url, access_token FROM git_providers
|
|
WHERE id = $1 AND user_id = $2`,
|
|
providerID, ownerID,
|
|
).Scan(&name, &apiURL, &token); err != nil {
|
|
return spec, nil // provider row gone — anonymous clone still works for public repos
|
|
}
|
|
|
|
switch strings.ToLower(name) {
|
|
case "github_app":
|
|
installationID, err := strconv.ParseInt(strings.TrimSpace(token), 10, 64)
|
|
if err == nil && installationID > 0 {
|
|
if minted, err := getGitHubAppInstallationToken(apiURL, installationID); err == nil {
|
|
spec.Token = minted
|
|
spec.User = "x-access-token"
|
|
}
|
|
}
|
|
case "gitlab":
|
|
spec.Token = token
|
|
spec.User = "oauth2"
|
|
case "bitbucket":
|
|
spec.Token = token
|
|
spec.User = "x-token-auth"
|
|
default:
|
|
spec.Token = token
|
|
spec.User = "x-access-token"
|
|
}
|
|
return spec, nil
|
|
}
|