github

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package github 은 GitHub REST API 로 리포지토리를 프로비저닝한다.

GitLab 어댑터와 두 가지가 근본적으로 다르다.

하나, 네임스페이스를 만들 수 없다. GitHub Organization 은 API 로 생성되지 않으므로 EnsureGroup 은 "확인"만 한다 — 없으면 사람이 먼저 만들어야 한다.

둘, 토큰을 발급할 수 없다. GitLab 은 프로젝트 범위 토큰 API 가 있지만 GitHub 에는 리포 단위 토큰이 없다. 대신 워크플로가 내장 GITHUB_TOKEN 을 쓰고, 클러스터 쪽(Argo CD·kubelet)은 스택에 등록된 PAT 를 재사용한다.

Index

Constants

View Source
const (
	// DefaultAPIBaseURL 는 github.com 의 API 주소다.
	// GitHub Enterprise Server 는 https://{host}/api/v3 형태를 쓴다.
	DefaultAPIBaseURL = "https://api.github.com"

	// GHCRHost 는 GitHub Container Registry 의 호스트다.
	GHCRHost = "ghcr.io"
)
View Source
const SecretProvider = "openbao"

SecretProvider 는 토큰을 보관하는 시크릿 백엔드다.

Variables

View Source
var ErrAccessTokenUnsupported = errors.New(
	"github 은 리포 범위 액세스 토큰 발급을 지원하지 않습니다")

ErrAccessTokenUnsupported 는 GitHub 에 리포 범위 토큰 발급 API 가 없음을 알린다.

GitLab 의 Project Access Token 에 대응하는 것이 GitHub 에는 없다. 워크플로는 내장 GITHUB_TOKEN 을 쓰고, 클러스터 쪽 인증은 스택에 등록된 PAT 를 재사용한다. 호출자가 이 오류를 보고 그 경로로 갈라져야 한다.

Functions

func TokenSecretPath

func TokenSecretPath(env, orgID string) string

TokenSecretPath 는 PAT 의 시크릿 경로다.

값을 기록하는 쪽은 stack 모듈(설치 마지막의 토큰 소스 등록)이다. 경로를 양쪽에 따로 적으면 한쪽만 바뀌어도 컴파일은 통과하고 런타임에 "등록된 토큰이 없다" 로만 드러나므로 공유 규약을 그대로 쓴다.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client 는 port.SCMProvisioner 와 port.PipelineConfigurator 의 GitHub 구현체다.

func NewClient

func NewClient(baseURL, token string) *Client

NewClient 는 GitHub REST 클라이언트를 만든다.

baseURL 이 비면 github.com 을 쓴다. token 은 repo·workflow 스코프를 가진 PAT 다.

func (*Client) BaseURL

func (c *Client) BaseURL() string

BaseURL 은 이 클라이언트가 바라보는 API 주소다.

func (*Client) CommitFiles

func (c *Client) CommitFiles(ctx context.Context, projectID string, spec port.CommitSpec) error

CommitFiles 는 여러 파일을 한 커밋으로 올린다(upsert).

Contents API 를 파일마다 부르면 커밋이 파일 수만큼 생기고, Argo CD 가 그 중간 상태를 하나씩 동기화해 배포가 여러 번 일어난다. Git Data API 로 트리 하나를 만들어 커밋 하나로 밀어야 한다.

func (*Client) CreateProjectAccessToken

func (c *Client) CreateProjectAccessToken(
	_ context.Context,
	_ string,
	_ port.AccessTokenSpec,
) (string, error)

CreateProjectAccessToken 은 GitHub 에서 지원되지 않는다.

조용히 빈 문자열을 돌려주면 호출자가 자격증명 없이 Argo CD 를 구성해 동기화가 "authentication required" 로 실패한다. 명시적으로 알린다.

func (*Client) DeleteImageRepository

func (c *Client) DeleteImageRepository(ctx context.Context, target *port.ImageTarget) error

DeleteImageRepository 는 GHCR 패키지를 지운다.

리포지토리와 패키지는 GitHub 에서 별개 리소스다 — 리포를 지워도 패키지는 남는다. 경로도 다르다: 개인 계정은 /user/packages, 조직은 /orgs/{org}/packages.

PAT 에 delete:packages 스코프가 필요하다.

func (*Client) DeleteProject

func (c *Client) DeleteProject(ctx context.Context, projectID string) error

DeleteProject 는 리포지토리를 지운다.

이미 없으면 성공으로 본다 — 삭제의 목표는 "없는 상태" 이고, 404 를 오류로 올리면 앞선 시도가 절반쯤 성공한 뒤 재시도할 때 영영 끝나지 않는다.

PAT 에 delete_repo 스코프가 없으면 403 이 온다. 이 경우 GitHub 은 권한 부족을 알려주므로 오류를 그대로 올려 사용자가 스코프를 고칠 수 있게 한다.

func (*Client) EnsureGroup

func (c *Client) EnsureGroup(ctx context.Context, spec port.GroupSpec) (*port.SCMGroup, error)

EnsureGroup 은 소유자(Organization 또는 사용자 계정)가 존재하는지 확인한다.

만들지 않는다 — GitHub Organization 은 API 로 생성할 수 없다. 없는 소유자를 조용히 넘기면 리포 생성이 엉뚱한 네임스페이스로 흘러가므로 여기서 끊는다.

func (*Client) EnsureProject

func (c *Client) EnsureProject(ctx context.Context, spec port.ProjectSpec) (*port.SCMProject, error)

EnsureProject 는 리포지토리를 조회하고 없으면 만든다.

func (*Client) Ping

func (c *Client) Ping(ctx context.Context) error

Ping 은 현재 토큰이 실제로 인증되는지 확인한다.

보관된 PAT 는 사용자가 폐기하거나 만료될 수 있다. 쓰기 전에 확인하지 않으면 이후 모든 호출이 401 로 죽고 원인이 프로비저닝 실패처럼 보인다.

func (*Client) SetProjectVariable

func (c *Client) SetProjectVariable(ctx context.Context, projectID string, v port.ProjectVariable) error

SetProjectVariable 은 Actions 시크릿을 등록하거나 이미 있으면 갱신한다.

GitHub 은 평문 시크릿을 받지 않는다. 리포의 공개키를 받아 libsodium sealed box 로 암호화한 값만 올릴 수 있다 — 평문으로 PUT 하면 400 이 난다. PUT 자체가 upsert 라 GitLab 처럼 POST→PUT 폴백이 필요 없다.

func (*Client) WithHTTPClient

func (c *Client) WithHTTPClient(h *http.Client) *Client

WithHTTPClient 는 타임아웃·전송 계층을 교체한다.

type SecretStore

type SecretStore interface {
	GetTokenForStack(ctx context.Context, provider, stackID, path string) (string, error)
}

SecretStore 는 토큰 조회에 필요한 최소 동작만 노출한다.

다른 모듈의 동일 타입을 재사용하지 않는다 — 모듈 간 직접 import 를 피하기 위해 CI/CD 컨텍스트가 자기 계약을 소유한다.

type TokenIssuer

type TokenIssuer struct {
	// contains filtered or unexported fields
}

TokenIssuer 는 보관된 GitHub PAT 를 돌려준다.

이름은 GitLab 쪽과 맞췄지만 실제로 발급하지는 않는다 — GitHub 은 SaaS 라 우리가 토큰을 만들 수 없다. 사용자가 등록한 PAT 를 읽는 것이 전부이며, 그래서 Force 재발급도 의미가 없다(만료·폐기되면 사람이 다시 등록해야 한다).

func NewTokenIssuer

func NewTokenIssuer(secrets SecretStore) *TokenIssuer

NewTokenIssuer 는 TokenIssuer 를 만든다.

func (*TokenIssuer) EnsureToken

func (t *TokenIssuer) EnsureToken(ctx context.Context, spec port.SCMTokenSpec) (string, error)

EnsureToken 은 보관된 PAT 를 돌려준다.

없으면 새로 만들지 않고 실패한다 — 조용히 빈 토큰으로 진행하면 리포 생성이 401 로 죽고, 오류가 프로비저닝 버그처럼 보여 원인을 찾기 어렵다.

Jump to

Keyboard shortcuts

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