Skip to content

Commit 340421d

Browse files
authored
re-implement git-initializer component using git2go (#1939)
Signed-off-by: Kent Rancourt <kent.rancourt@microsoft.com>
1 parent 6ff548c commit 340421d

File tree

13 files changed

+455
-446
lines changed

13 files changed

+455
-446
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ test-unit-go:
103103
cd sdk/v3 && \
104104
go test \
105105
-v \
106+
-tags testUnit \
106107
-timeout=60s \
107108
-race \
108109
-coverprofile=coverage.txt \
@@ -111,6 +112,7 @@ test-unit-go:
111112
cd ../../v2 && \
112113
go test \
113114
-v \
115+
-tags testUnit \
114116
-timeout=60s \
115117
-race \
116118
-coverprofile=coverage.txt \

golangci.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
run:
22
concurrency: 1
33
deadline: 10m
4-
skip-files:
4+
build-tags:
5+
- lint
56

67
linters:
78
disable-all: true
Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,59 @@
1-
FROM golang:1.17.2-windowsservercore-1809 as builder
1+
# escape=`
22

3-
ARG VERSION
4-
ARG COMMIT
5-
ENV CGO_ENABLED=0
3+
FROM brigadecore/win-go-tools:v0.2.0 as builder
64

7-
WORKDIR /src
8-
COPY sdk/ sdk/
9-
WORKDIR /src/v2
10-
COPY v2/git-initializer/ git-initializer/
11-
COPY v2/internal/ internal/
12-
COPY v2/go.mod go.mod
13-
COPY v2/go.sum go.sum
5+
# As of this writing, pacman installs a newer libgit2 than we are able to use.
6+
# Here, we download and install an older version.
7+
RUN curl `
8+
-L `
9+
https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-libgit2-1.2.0-3-any.pkg.tar.zst `
10+
-o C:\windows\temp/libgit2.pkg.tar.zst `
11+
&& bash -l -c "pacman --noconfirm -U /c/windows/temp/libgit2.pkg.tar.zst"
1412

15-
RUN go build \
16-
-o ../bin/git-initializer.exe \
17-
-ldflags \"-w -X github.com/brigadecore/brigade-foundations/version.version=$env:VERSION -X github.com/brigadecore/brigade-foundations/version.commit=$env:COMMIT\" \
18-
./git-initializer
13+
WORKDIR C:\\msys64\\brigade
14+
COPY sdk\\ sdk\\
15+
WORKDIR C:\\msys64\\brigade\\v2
16+
COPY v2\\go.mod go.mod
17+
COPY v2\\go.sum go.sum
18+
RUN bash -l -c " `
19+
cd /brigade/v2 `
20+
&& PATH=$PATH:/mingw64/bin `
21+
GOROOT=/mingw64/lib/go `
22+
go mod download `
23+
"
24+
COPY v2\\git-initializer\\ git-initializer\\
25+
COPY v2\\internal\\ internal\\
1926

20-
FROM mcr.microsoft.com/windows/nanoserver:1809
27+
# The `-tags static,system_libgit2` specified below instruct git2go on how to
28+
# locate libgit2. It does NOT imply our binary is statically linked -- in fact,
29+
# it is not. In theory, that can be accomplished by including
30+
# `-extldflags 'static'` in the `-ldflags`, but we've had no luck getting that
31+
# to work.
32+
RUN bash -l -c " `
33+
cd /brigade/v2 `
34+
&& PATH=$PATH:/mingw64/bin `
35+
GOROOT=/mingw64/lib/go `
36+
go build `
37+
-tags static,system_libgit2 `
38+
-ldflags \"-w -X github.com/brigadecore/brigade-foundations/version.version=$VERSION -X github.com/brigadecore/brigade-foundations/version.commit=$COMMIT\" `
39+
-o ../bin/git-initializer.exe `
40+
./git-initializer `
41+
"
2142

22-
COPY --from=builder /src/bin/ /brigade/bin/
43+
ENTRYPOINT [ "C:\\msys64\\brigade\\bin\\git-initializer.exe" ]
2344

24-
ENTRYPOINT ["/brigade/bin/git-initializer.exe"]
45+
FROM mcr.microsoft.com/windows/nanoserver:1809 AS final
46+
47+
USER ContainerAdministrator
48+
49+
# Note that because we were unable to produce a statically-linked binary, we
50+
# depend on a number of .dlls from the builder image, so we just copy them
51+
# all over and add them to the path.
52+
COPY --from=builder C:\\msys64\\mingw64\\bin\\ C:\\mingw64\\bin\\
53+
RUN setx /M PATH "%PATH%;C:\mingw64\bin"
54+
55+
COPY --from=builder C:\\msys64\\brigade\\bin\\ C:\\brigade\\bin\\
56+
57+
USER ContainerUser
58+
59+
ENTRYPOINT ["C:\\brigade\\bin\\git-initializer.exe"]

v2/git-initializer/Dockerfile

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
FROM --platform=$BUILDPLATFORM brigadecore/go-tools:v0.9.0 as builder
1+
FROM brigadecore/go-libgit2:v0.1.0 as builder
22

33
ARG VERSION
44
ARG COMMIT
5-
ARG TARGETOS
6-
ARG TARGETARCH
7-
ENV CGO_ENABLED=0
85

96
WORKDIR /src
107
COPY sdk/ sdk/
@@ -15,12 +12,15 @@ RUN go mod download
1512
COPY v2/git-initializer/ git-initializer/
1613
COPY v2/internal/ internal/
1714

18-
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build \
15+
# Despite CGO being involved, this builds a statically linked binary
16+
RUN go build \
17+
-tags static,system_libgit2 \
1918
-o ../bin/git-initializer \
20-
-ldflags "-w -X github.com/brigadecore/brigade-foundations/version.version=$VERSION -X github.com/brigadecore/brigade-foundations/version.commit=$COMMIT" \
19+
-ldflags "-extldflags '-static -lgcrypt -lgpg-error' -w -X github.com/brigadecore/brigade-foundations/version.version=$VERSION -X github.com/brigadecore/brigade-foundations/version.commit=$COMMIT" \
2120
./git-initializer
2221

23-
FROM gcr.io/distroless/static:nonroot as final
22+
# Note: Cannot use gcr.io/distroless/static:nonroot because we still need glibc
23+
FROM gcr.io/distroless/base:nonroot as final
2424

2525
COPY --from=builder /src/bin/ /brigade/bin/
2626

v2/git-initializer/credentials.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//go:build !testUnit && !lint
2+
// +build !testUnit,!lint
3+
4+
// We exclude this file from unit tests and linting because it cannot be
5+
// compiled without CGO and a specific version of libgit2 pre-installed. To keep
6+
// our linting and unit tests lightweight, those are complications we'd like to
7+
// avoid. We'll live without the linting and test this well with integration
8+
// tests.
9+
10+
package main
11+
12+
import (
13+
git "github.com/libgit2/git2go/v32"
14+
"github.com/pkg/errors"
15+
"golang.org/x/crypto/ssh"
16+
)
17+
18+
// getCredentialsCallback extracts credentials, if any, from project secrets in
19+
// the provided map and returns a callback function. If no credentials are found
20+
// in the secrets, a nil function pointer is returned.
21+
func getCredentialsCallback(
22+
secrets map[string]string,
23+
) (git.CredentialsCallback, error) {
24+
// We'll check the project's secrets first for a well-known key that we could
25+
// expect contains a private SSH key. If we find that, we'll use it.
26+
if privateKey, ok := secrets["gitSSHKey"]; ok {
27+
var signer ssh.Signer
28+
var err error
29+
// The private key may or may not be protected by a passphrase...
30+
if keyPassStr, ok := secrets["gitSSHKeyPassword"]; ok {
31+
// Auth using key and passphrase
32+
signer, err = ssh.ParsePrivateKeyWithPassphrase(
33+
[]byte(privateKey),
34+
[]byte(keyPassStr),
35+
)
36+
} else {
37+
// Auth using a key without a passphrase
38+
signer, err = ssh.ParsePrivateKey([]byte(privateKey))
39+
}
40+
if err != nil {
41+
return nil, errors.Wrap(
42+
err,
43+
`error parsing private SSH key specified by secret "gitSSHKey"`,
44+
)
45+
}
46+
return func(
47+
string,
48+
string,
49+
git.CredentialType,
50+
) (*git.Credential, error) {
51+
return git.NewCredentialSSHKeyFromSigner("git", signer)
52+
}, nil
53+
}
54+
55+
// Check the project's secrets for a well-known key that we could expect
56+
// contains a password or token.
57+
if password, ok := secrets["gitPassword"]; ok {
58+
// There may or may not be a username associated with the password. It
59+
// really depends on who hosts the repository we're cloning from. GitHub,
60+
// for instance, expects the username to be any non-empty string (and the
61+
// password to be a personal access token), while Bitbucket expects a valid
62+
// username (and the password to be an app password).
63+
username := secrets["gitUsername"]
64+
// Ultimately, the username and password are used with basic auth and an
65+
// empty username isn't allowed, so if no username was specified (e.g. for a
66+
// repo hosted on GitHub), just use the string "git" as the username.
67+
if username == "" {
68+
username = "git"
69+
}
70+
return func(
71+
string,
72+
string,
73+
git.CredentialType,
74+
) (*git.Credential, error) {
75+
// Basic auth
76+
return git.NewCredentialUserpassPlaintext(username, password)
77+
}, nil
78+
}
79+
80+
// No credentials found
81+
return nil, nil
82+
}

v2/git-initializer/events.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"io/ioutil"
6+
7+
"github.com/brigadecore/brigade/sdk/v3"
8+
"github.com/pkg/errors"
9+
)
10+
11+
// event is a custom representation of a Brigade event that matches what the
12+
// API server provides to the git-initializer.
13+
type event struct {
14+
Project struct {
15+
Secrets map[string]string `json:"secrets"`
16+
} `json:"project"`
17+
Worker struct {
18+
Git *sdk.GitConfig `json:"git"`
19+
} `json:"worker"`
20+
}
21+
22+
// getEvent loads an event from the indicated path on the file system.
23+
func getEvent(path string) (event, error) {
24+
evt := event{}
25+
eventPath := "/var/event/event.json"
26+
data, err := ioutil.ReadFile(eventPath)
27+
if err != nil {
28+
return evt,
29+
errors.Wrapf(err, "error reading event from file %q", eventPath)
30+
}
31+
return evt, errors.Wrapf(
32+
json.Unmarshal(data, &evt),
33+
"error reading event from file %q",
34+
eventPath,
35+
)
36+
}

0 commit comments

Comments
 (0)