diff --git a/.dagger/.gitattributes b/.dagger/.gitattributes new file mode 100644 index 00000000000..3a454933cbe --- /dev/null +++ b/.dagger/.gitattributes @@ -0,0 +1,4 @@ +/dagger.gen.go linguist-generated +/internal/dagger/** linguist-generated +/internal/querybuilder/** linguist-generated +/internal/telemetry/** linguist-generated diff --git a/.dagger/.gitignore b/.dagger/.gitignore new file mode 100644 index 00000000000..7ebabcc1426 --- /dev/null +++ b/.dagger/.gitignore @@ -0,0 +1,4 @@ +/dagger.gen.go +/internal/dagger +/internal/querybuilder +/internal/telemetry diff --git a/.dagger/go.mod b/.dagger/go.mod new file mode 100644 index 00000000000..5500608f28d --- /dev/null +++ b/.dagger/go.mod @@ -0,0 +1,50 @@ +module dagger/harbor + +go 1.23.2 + +require ( + github.com/99designs/gqlgen v0.17.55 + github.com/Khan/genqlient v0.7.0 + github.com/vektah/gqlparser/v2 v2.5.17 + go.opentelemetry.io/otel v1.27.0 + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88 + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 + go.opentelemetry.io/otel/log v0.3.0 + go.opentelemetry.io/otel/metric v1.27.0 + go.opentelemetry.io/otel/sdk v1.27.0 + go.opentelemetry.io/otel/sdk/log v0.3.0 + go.opentelemetry.io/otel/sdk/metric v1.27.0 + go.opentelemetry.io/otel/trace v1.27.0 + go.opentelemetry.io/proto/otlp v1.3.1 + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa + golang.org/x/sync v0.8.0 + google.golang.org/grpc v1.65.0 +) + +require ( + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect + github.com/sosodev/duration v1.3.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.18.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/protobuf v1.34.2 // indirect +) + +replace go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc => go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88 + +replace go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp => go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0 + +replace go.opentelemetry.io/otel/log => go.opentelemetry.io/otel/log v0.3.0 + +replace go.opentelemetry.io/otel/sdk/log => go.opentelemetry.io/otel/sdk/log v0.3.0 diff --git a/.dagger/go.sum b/.dagger/go.sum new file mode 100644 index 00000000000..c52dd24bd0b --- /dev/null +++ b/.dagger/go.sum @@ -0,0 +1,83 @@ +github.com/99designs/gqlgen v0.17.55 h1:3vzrNWYyzSZjGDFo68e5j9sSauLxfKvLp+6ioRokVtM= +github.com/99designs/gqlgen v0.17.55/go.mod h1:3Bq768f8hgVPGZxL8aY9MaYmbxa6llPM/qu1IGH1EJo= +github.com/Khan/genqlient v0.7.0 h1:GZ1meyRnzcDTK48EjqB8t3bcfYvHArCUUvgOwpz1D4w= +github.com/Khan/genqlient v0.7.0/go.mod h1:HNyy3wZvuYwmW3Y7mkoQLZsa/R5n5yIRajS1kPBvSFM= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4= +github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/vektah/gqlparser/v2 v2.5.17 h1:9At7WblLV7/36nulgekUgIaqHZWn5hxqluxrxGUhOmI= +github.com/vektah/gqlparser/v2 v2.5.17/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww= +go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= +go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88 h1:oM0GTNKGlc5qHctWeIGTVyda4iFFalOzMZ3Ehj5rwB4= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88/go.mod h1:JGG8ebaMO5nXOPnvKEl+DiA4MGwFjCbjsxT1WHIEBPY= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0 h1:ccBrA8nCY5mM0y5uO7FT0ze4S0TuFcWdDB2FxGMTjkI= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0/go.mod h1:/9pb6634zi2Lk8LYg9Q0X8Ar6jka4dkFOylBLbVQPCE= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0 h1:bFgvUr3/O4PHj3VQcFEuYKvRZJX1SJDQ+11JXuSB3/w= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0/go.mod h1:xJntEd2KL6Qdg5lwp97HMLQDVeAhrYxmzFseAMDPQ8I= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0 h1:CIHWikMsN3wO+wq1Tp5VGdVRTcON+DmOJSfDjXypKOc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0/go.mod h1:TNupZ6cxqyFEpLXAZW7On+mLFL0/g0TE3unIYL91xWc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 h1:QY7/0NeRPKlzusf40ZE4t1VlMKbqSNT7cJRYzWuja0s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0/go.mod h1:HVkSiDhTM9BoUJU8qE6j2eSWLLXvi1USXjyd2BXT8PY= +go.opentelemetry.io/otel/log v0.3.0 h1:kJRFkpUFYtny37NQzL386WbznUByZx186DpEMKhEGZs= +go.opentelemetry.io/otel/log v0.3.0/go.mod h1:ziCwqZr9soYDwGNbIL+6kAvQC+ANvjgG367HVcyR/ys= +go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= +go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= +go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= +go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= +go.opentelemetry.io/otel/sdk/log v0.3.0 h1:GEjJ8iftz2l+XO1GF2856r7yYVh74URiF9JMcAacr5U= +go.opentelemetry.io/otel/sdk/log v0.3.0/go.mod h1:BwCxtmux6ACLuys1wlbc0+vGBd+xytjmjajwqqIul2g= +go.opentelemetry.io/otel/sdk/metric v1.27.0 h1:5uGNOlpXi+Hbo/DRoI31BSb1v+OGcpv2NemcCrOL8gI= +go.opentelemetry.io/otel/sdk/metric v1.27.0/go.mod h1:we7jJVrYN2kh3mVBlswtPU22K0SA+769l93J6bsyvqw= +go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= +go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/.dagger/main.go b/.dagger/main.go new file mode 100644 index 00000000000..ff60af01372 --- /dev/null +++ b/.dagger/main.go @@ -0,0 +1,361 @@ +package main + +import ( + "context" + "dagger/harbor/internal/dagger" + "fmt" + "log" + "strings" +) + +const ( + GOLANGCILINT_VERSION = "v1.61.0" + GO_VERSION = "latest" + SYFT_VERSION = "v1.9.0" + GORELEASER_VERSION = "v2.3.2" +) + +type Package string +type Platform string + +var ( + targetPlatforms = []Platform{"linux/arm64", "linux/amd64"} + packages = []Package{"core", "jobservice", "registryctl", "cmd/exporter", "cmd/standalone-db-migrator"} + //packages = []string{"core", "jobservice"} +) + +type BuildMetadata struct { + Package Package + BinaryPath string + Container *dagger.Container + Platform Platform +} + +func New( + // +optional + // +defaultPath="./" + source *dagger.Directory, +) *Harbor { + return &Harbor{Source: source} +} + +type Harbor struct { + Source *dagger.Directory +} + +// LintReport Executes the Linter and writes the linting results to a file golangci-linter-report.sarif +func (m *Harbor) LintReport(ctx context.Context) (string, error) { + report := "golangci-lint-report.sarif" + output, _ := m.Source.File(report).Name(ctx) + return m.linter(ctx).WithExec([]string{"golangci-lint", "run", + "--out-format", "sarif:" + report, + "--issues-exit-code", "0"}).File(report).Export(ctx, report) +} + +// Lint Run the linter golangci-linter +func (m *Harbor) Lint(ctx context.Context) (string, error) { + return m.linter(ctx).WithExec([]string{"golangci-lint", "run"}).Stderr(ctx) +} + +func (m *Harbor) linter(ctx context.Context) *dagger.Container { + fmt.Printf("👀 Running linter") + linter := dag.Container(). + From("golangci/golangci-lint:"+GOLANGCILINT_VERSION+"-alpine"). + WithMountedCache("/lint-cache", dag.CacheVolume("/lint-cache")). + WithEnvVariable("GOLANGCI_LINT_CACHE", "/lint-cache"). + WithMountedDirectory("/harbor", m.Source). + WithWorkdir("/harbor/src/") + return linter +} + +func (m *Harbor) PublishAndSignAllImages( + ctx context.Context, + registry string, + registryUsername string, + registryPassword *dagger.Secret, + imageTags []string, + // +optional + githubToken *dagger.Secret, + // +optional + actionsIdTokenRequestToken *dagger.Secret, + // +optional + actionsIdTokenRequestUrl string, +) (string, error) { + + imageAddrs := m.PublishAllImages(ctx, registry, registryUsername, imageTags, registryPassword) + _, err := m.Sign( + ctx, + githubToken, + actionsIdTokenRequestUrl, + actionsIdTokenRequestToken, + registryUsername, + registryPassword, + imageAddrs[0], + ) + if err != nil { + return "", fmt.Errorf("failed to sign image: %w", err) + } + + fmt.Printf("Signed image: %s\n", imageAddrs) + return imageAddrs[0], nil +} + +// Sign signs a container image using Cosign, works also with GitHub Actions +func (m *Harbor) Sign(ctx context.Context, + // +optional + githubToken *dagger.Secret, + // +optional + actionsIdTokenRequestUrl string, + // +optional + actionsIdTokenRequestToken *dagger.Secret, + registryUsername string, + registryPassword *dagger.Secret, + imageAddr string, +) (string, error) { + + registryPasswordPlain, _ := registryPassword.Plaintext(ctx) + + cosing_ctr := dag.Container().From("cgr.dev/chainguard/cosign") + + // If githubToken is provided, use it to sign the image. (GitHub Actions) use case + if githubToken != nil { + if actionsIdTokenRequestUrl == "" || actionsIdTokenRequestToken == nil { + return "", fmt.Errorf("actionsIdTokenRequestUrl (exist=%s) and actionsIdTokenRequestToken (exist=%t) must be provided when githubToken is provided", actionsIdTokenRequestUrl, actionsIdTokenRequestToken != nil) + } + fmt.Printf("Setting the ENV Vars GITHUB_TOKEN, ACTIONS_ID_TOKEN_REQUEST_URL, ACTIONS_ID_TOKEN_REQUEST_TOKEN to sign with GitHub Token") + cosing_ctr = cosing_ctr.WithSecretVariable("GITHUB_TOKEN", githubToken). + WithEnvVariable("ACTIONS_ID_TOKEN_REQUEST_URL", actionsIdTokenRequestUrl). + WithSecretVariable("ACTIONS_ID_TOKEN_REQUEST_TOKEN", actionsIdTokenRequestToken) + } + + return cosing_ctr.WithSecretVariable("REGISTRY_PASSWORD", registryPassword). + WithExec([]string{"cosign", "env"}). + WithExec([]string{"cosign", "sign", "--yes", "--recursive", + "--registry-username", registryUsername, + "--registry-password", registryPasswordPlain, + imageAddr, + "--timeout", "1m", + }).Stdout(ctx) +} + +func (m *Harbor) PublishAllImages( + ctx context.Context, + registry, registryUsername string, + imageTags []string, + registryPassword *dagger.Secret) []string { + + allImages := m.buildAllImages(ctx) + + for i, tag := range imageTags { + imageTags[i] = strings.TrimSpace(tag) + if strings.HasPrefix(imageTags[i], "v") { + imageTags[i] = strings.TrimPrefix(imageTags[i], "v") + } + } + fmt.Printf("provided tags: %s\n", imageTags) + + platformVariantsContainer := make(map[Package][]*dagger.Container) + for _, meta := range allImages { + platformVariantsContainer[meta.Package] = append(platformVariantsContainer[meta.Package], meta.Container) + } + + var imageAddresses []string + for pkg, imgs := range platformVariantsContainer { + for _, imageTag := range imageTags { + container := dag.Container().WithRegistryAuth(registry, registryUsername, registryPassword) + imgAddress, err := container.Publish(ctx, + fmt.Sprintf("%s/%s/%s:%s", registry, "harbor", pkg, imageTag), + dagger.ContainerPublishOpts{PlatformVariants: imgs}, + ) + if err != nil { + fmt.Printf("Failed to publish image: %s/%s/%s:%s\n", registry, "harbor", pkg, imageTag) + fmt.Printf("Error: %s\n", err) + continue + } + imageAddresses = append(imageAddresses, imgAddress) + fmt.Printf("Published image: %s\n", imgAddress) + } + } + return imageAddresses +} + +func (m *Harbor) PublishImage( + ctx context.Context, + registry, registryUsername string, + imageTags []string, + registryPassword *dagger.Secret) []string { + + releaseImages := []*dagger.Container{} + + for i, tag := range imageTags { + imageTags[i] = strings.TrimSpace(tag) + if strings.HasPrefix(imageTags[i], "v") { + imageTags[i] = strings.TrimPrefix(imageTags[i], "v") + } + } + fmt.Printf("provided tags: %s\n", imageTags) + + for _, platform := range targetPlatforms { + for _, pkg := range packages { + build := m.buildImage(ctx, platform, pkg) + if strings.HasPrefix(string(platform), "linux") { + releaseImages = append(releaseImages, build.Container) + } + } + } + + imageAddrs := []string{} + for _, imageTag := range imageTags { + addr, err := dag.Container().WithRegistryAuth(registry, registryUsername, registryPassword). + Publish(ctx, + fmt.Sprintf("%s/%s/harbor-cli:%s", registry, "harbor-cli", imageTag), + dagger.ContainerPublishOpts{PlatformVariants: releaseImages}, + ) + + if err != nil { + panic(err) + } + fmt.Printf("Published image address: %s\n", addr) + imageAddrs = append(imageAddrs, addr) + } + return imageAddrs +} + +func (m *Harbor) ExportAllImages(ctx context.Context) *dagger.Directory { + metdata := m.buildAllImages(ctx) + artifacts := dag.Directory() + for _, meta := range metdata { + artifacts = artifacts.WithFile(fmt.Sprintf("containers/%s/%s.tgz", meta.Platform, meta.Package), meta.Container.AsTarball()) + } + return artifacts +} + +func (m *Harbor) BuildAllImages(ctx context.Context) []*dagger.Container { + metdata := m.buildAllImages(ctx) + images := make([]*dagger.Container, len(metdata)) + for i, meta := range metdata { + images[i] = meta.Container + } + return images +} + +func (m *Harbor) buildAllImages(ctx context.Context) []*BuildMetadata { + var buildMetadata []*BuildMetadata + for _, platform := range targetPlatforms { + for _, pkg := range packages { + img := m.BuildImage(ctx, platform, pkg) + buildMetadata = append(buildMetadata, &BuildMetadata{ + Package: pkg, + BinaryPath: fmt.Sprintf("bin/%s/%s", platform, pkg), + Container: img, + Platform: platform, + }) + } + } + return buildMetadata +} + +func (m *Harbor) BuildImage(ctx context.Context, platform Platform, pkg Package) *dagger.Container { + buildMtd := m.buildImage(ctx, platform, pkg) + if pkg == "core" { + buildMtd.Container = buildMtd.Container.WithDirectory("/migrations", m.Source.Directory("make/migrations")) + } + return buildMtd.Container + +} + +func (m *Harbor) buildImage(ctx context.Context, platform Platform, pkg Package) *BuildMetadata { + buildMtd := m.buildBinary(ctx, platform, pkg) + img := dag.Container(dagger.ContainerOpts{Platform: dagger.Platform(string(platform))}). + WithFile("/"+string(pkg), buildMtd.Container.File(buildMtd.BinaryPath)). + WithEntrypoint([]string{"/" + string(pkg)}) + buildMtd.Container = img + return buildMtd +} + +func (m *Harbor) BuildAllBinaries(ctx context.Context) *dagger.Directory { + output := dag.Directory() + builds := m.buildAllBinaries(ctx) + for _, build := range builds { + output = output.WithFile(build.BinaryPath, build.Container.File(build.BinaryPath)) + } + return output +} + +func (m *Harbor) buildAllBinaries(ctx context.Context) []*BuildMetadata { + var buildContainers []*BuildMetadata + for _, platform := range targetPlatforms { + for _, pkg := range packages { + buildContainer := m.buildBinary(ctx, platform, pkg) + buildContainers = append(buildContainers, buildContainer) + } + } + return buildContainers +} + +func (m *Harbor) BuildBinary(ctx context.Context, platform Platform, pkg Package) *dagger.File { + build := m.buildBinary(ctx, platform, pkg) + return build.Container.File(build.BinaryPath) +} + +func (m *Harbor) buildBinary(ctx context.Context, platform Platform, pkg Package) *BuildMetadata { + + os, arch, err := parsePlatform(string(platform)) + if err != nil { + log.Fatalf("Error parsing platform: %v", err) + } + + outputPath := fmt.Sprintf("bin/%s/%s", platform, pkg) + src := fmt.Sprintf("%s/main.go", pkg) + builder := dag.Container(). + From("golang:latest"). + WithMountedCache("/go/pkg/mod", dag.CacheVolume("go-mod-"+GO_VERSION)). + WithEnvVariable("GOMODCACHE", "/go/pkg/mod"). + WithMountedCache("/go/build-cache", dag.CacheVolume("go-build-"+GO_VERSION)). + WithEnvVariable("GOCACHE", "/go/build-cache"). + WithMountedDirectory("/harbor", m.Source). + WithWorkdir("/harbor/src/"). + WithEnvVariable("GOOS", os). + WithEnvVariable("GOARCH", arch). + WithEnvVariable("CGO_ENABLED", "0"). + WithExec([]string{"go", "build", "-o", outputPath, "-ldflags", "-extldflags=-static -s -w", src}) + + return &BuildMetadata{ + Package: pkg, + BinaryPath: outputPath, + Container: builder, + Platform: platform, + } +} + +func (m *Harbor) buildPortal(ctx context.Context, platform Platform, pkg Package) *dagger.Directory { + fmt.Println("🛠️ Building Harbor Core...") + os, arch, err := parsePlatform(string(platform)) + + if err != nil { + log.Fatalf("Error parsing platform: %v", err) + } + + outputPath := fmt.Sprintf("bin/%s/%s", platform, pkg) + src := fmt.Sprintf("src/%s/main.go", pkg) + builder := dag.Container(). + From("golang:latest"). + WithMountedCache("/go/pkg/mod", dag.CacheVolume("go-mod-"+GO_VERSION)). + WithEnvVariable("GOMODCACHE", "/go/pkg/mod"). + WithMountedCache("/go/build-cache", dag.CacheVolume("go-build-"+GO_VERSION)). + WithEnvVariable("GOCACHE", "/go/build-cache"). + WithMountedDirectory("/harbor", m.Source). + WithWorkdir("/harbor"). + WithEnvVariable("GOOS", os). + WithEnvVariable("GOARCH", arch). + WithExec([]string{"go", "build", "-o", outputPath, src}) + return builder.Directory(outputPath) +} + +func parsePlatform(platform string) (string, string, error) { + parts := strings.Split(platform, "/") + if len(parts) != 2 { + return "", "", fmt.Errorf("invalid platform format: %s. Should be os/arch. E.g. darwin/amd64", platform) + } + return parts[0], parts[1], nil +} diff --git a/.gitignore b/.gitignore index f2b08ad4aa9..3624ca1c6b8 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,5 @@ src/server/v2.0/restapi/ harborclient/ openapi-generator-cli.jar + +bin/ diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 00000000000..c35d551a9e3 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,17 @@ +run: + timeout: 3m +linters: + enable: + # Default linters are already enabled, these are the additional ones + - typecheck + - gofmt + - gosec + - nilnil + # - wrapcheck + # - gocritic + # - revive #, enable once current issues are resolved +issues: + exclude-dirs: + - .dagger/internal + exclude-files: + - ^.*\\.gen\\.go$ diff --git a/dagger.json b/dagger.json new file mode 100644 index 00000000000..6c1a89943e5 --- /dev/null +++ b/dagger.json @@ -0,0 +1,6 @@ +{ + "name": "harbor", + "engineVersion": "v0.14.0", + "sdk": "go", + "source": ".dagger" +} diff --git a/src/core/main.go b/src/core/main.go index f0bc9656452..3a5bbeb1d62 100644 --- a/src/core/main.go +++ b/src/core/main.go @@ -28,6 +28,8 @@ import ( "github.com/beego/beego/v2/server/web" + _ "golang.org/x/crypto/x509roots/fallback" + "github.com/goharbor/harbor/src/common/dao" common_http "github.com/goharbor/harbor/src/common/http" configCtl "github.com/goharbor/harbor/src/controller/config" diff --git a/src/go.mod b/src/go.mod index 0d720e2872a..b36cff139a8 100644 --- a/src/go.mod +++ b/src/go.mod @@ -21,12 +21,12 @@ require ( github.com/go-asn1-ber/asn1-ber v1.5.7 github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-openapi/errors v0.22.0 - github.com/go-openapi/loads v0.22.0 // indirect + github.com/go-openapi/loads v0.22.0 github.com/go-openapi/runtime v0.28.0 - github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/spec v0.21.0 github.com/go-openapi/strfmt v0.23.0 github.com/go-openapi/swag v0.23.0 - github.com/go-openapi/validate v0.24.0 // indirect + github.com/go-openapi/validate v0.24.0 github.com/go-redis/redis/v8 v8.11.4 github.com/gocarina/gocsv v0.0.0-20210516172204-ca9e8a8ddea8 github.com/gocraft/work v0.5.1 @@ -78,7 +78,10 @@ require ( sigs.k8s.io/yaml v1.4.0 ) -require github.com/prometheus/client_model v0.6.1 +require ( + github.com/prometheus/client_model v0.6.1 + golang.org/x/crypto/x509roots/fallback v0.0.0-20241127184453-8c4e668694cc +) require ( cloud.google.com/go/compute/metadata v0.3.0 // indirect diff --git a/src/go.sum b/src/go.sum index 7c8df2472a6..bcd19178103 100644 --- a/src/go.sum +++ b/src/go.sum @@ -53,17 +53,13 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190726115642-cd293c93fd97 h1:bNE5ID4C3YOkROfvBjXJUG53gyb+8az3TQN02LqnGBk= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190726115642-cd293c93fd97/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1193 h1:C5LuIDWuQlugv30EBsSLKFF6jdtrqoVH84nYCdVYTC4= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1193/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= -github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= github.com/beego/beego/v2 v2.2.1 h1:5RatpEOKnw6sm76hj6lQvEFi4Tco+E21VQomnVB7NsA= github.com/beego/beego/v2 v2.2.1/go.mod h1:X4hHhM2AXn0hN2tbyz5X/PD7v5JUdE4IihZApiljpNA= github.com/beego/i18n v0.0.0-20140604031826-e87155e8f0c0 h1:fQaDnUQvBXHHQdGBu9hz8nPznB4BeiPQokvmQVjmNEw= @@ -605,6 +601,8 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto/x509roots/fallback v0.0.0-20241127184453-8c4e668694cc h1:N2DXFnxni8U4KZ7CcK6kicRat3uowReUjOJxwYTxQv8= +golang.org/x/crypto/x509roots/fallback v0.0.0-20241127184453-8c4e668694cc/go.mod h1:kNa9WdvYnzFwC79zRpLRMJbdEFlhyM5RPFBBZp/wWH8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= @@ -711,7 +709,6 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=