diff --git a/dagger.json b/dagger.json index e65bf48f4..d1bc9354e 100644 --- a/dagger.json +++ b/dagger.json @@ -2,5 +2,5 @@ "name": "chainloop", "sdk": "go", "source": "extras/dagger", - "engineVersion": "v0.12.3" + "engineVersion": "v0.13.0" } diff --git a/extras/dagger/README.md b/extras/dagger/README.md index c2f5453a2..a5c136f6d 100644 --- a/extras/dagger/README.md +++ b/extras/dagger/README.md @@ -165,7 +165,18 @@ dagger call -m github.com/chainloop-dev/chainloop \ mark-canceled --reason "nothing to see here" ``` -### Pointing to a different Chainloop Instance +## CLI operations + +This module also provides access to the underlying Chainloop CLI by exposing some of its commands + +### Workflow Creation + +```sh + dagger call -m github.com/chainloop-dev/chainloop \ + workflow-create --token env:CHAINLOOP_TOKEN --name [your-workflow-name] --project [its-project] +``` + +## Pointing to a different Chainloop Instance By default, this dagger module points to Chainloop's upstream instance, but if you want to point to your own instance, you can do it by running the with-instance command just right after `dagger call` diff --git a/extras/dagger/go.mod b/extras/dagger/go.mod index d8e8ad57f..783c34574 100644 --- a/extras/dagger/go.mod +++ b/extras/dagger/go.mod @@ -44,3 +44,11 @@ require ( golang.org/x/sync v0.7.0 google.golang.org/grpc v1.64.1 ) + +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/extras/dagger/main.go b/extras/dagger/main.go index 78fcf26cf..38020baa2 100644 --- a/extras/dagger/main.go +++ b/extras/dagger/main.go @@ -270,58 +270,35 @@ func (att *Attestation) Debug() *dagger.Container { return att.Container(0).Terminal() } -// Build an ephemeral container with everything needed to process the attestation -func (att *Attestation) Container( - // Cache TTL for chainloop commands, in seconds - // Defaults to 0: no caching - // +optional - // +default=0 - ttl int, -) *dagger.Container { - ctr := dag. - Container(). +func cliContainer(ttl int, token *dagger.Secret, instance InstanceInfo) *dagger.Container { + ctr := dag.Container(). From(fmt.Sprintf("ghcr.io/chainloop-dev/chainloop/cli:%s", chainloopVersion)). WithEntrypoint([]string{"/chainloop"}). // Be explicit to prepare for possible API change WithEnvVariable("CHAINLOOP_DAGGER_CLIENT", chainloopVersion). - WithUser("") // Our images come with pre-defined user set, so we need to reset it - - if att.Token != nil { - ctr = ctr.WithSecretVariable("CHAINLOOP_TOKEN", att.Token) - } - - if att.repository != nil { - ctr = ctr.WithDirectory(".", att.repository) - } - - if addr := att.RegistryAuth.Address; addr != "" { - ctr = ctr.WithEnvVariable("CHAINLOOP_REGISTRY_SERVER", addr) - } + WithUser(""). // Our images come with pre-defined user set, so we need to reset it + WithEnvVariable("DAGGER_CACHE_KEY", time.Now().Truncate(time.Duration(ttl)*time.Second).String()) // Cache TTL - if user := att.RegistryAuth.Username; user != "" { - ctr = ctr.WithEnvVariable("CHAINLOOP_REGISTRY_USERNAME", user) + if token != nil { + ctr = ctr.WithSecretVariable("CHAINLOOP_TOKEN", token) } - if pw := att.RegistryAuth.Password; pw != nil { - ctr = ctr.WithSecretVariable("CHAINLOOP_REGISTRY_PASSWORD", pw) - } - - if api := att.Client.Instance.ControlplaneAPI; api != "" { + if api := instance.ControlplaneAPI; api != "" { ctr = ctr.WithEnvVariable("CHAINLOOP_CONTROL_PLANE_API", api) } - if ca := att.Client.Instance.ControlplaneCAPath; ca != nil { + if ca := instance.ControlplaneCAPath; ca != nil { ctr = ctr.WithFile("/controlplane-ca.pem", ca).WithEnvVariable("CHAINLOOP_CONTROL_PLANE_API_CA", "/controlplane-ca.pem") } - if ca := att.Client.Instance.CASCAPath; ca != nil { + if ca := instance.CASCAPath; ca != nil { ctr = ctr.WithFile("/cas-ca.pem", ca).WithEnvVariable("CHAINLOOP_ARTIFACT_CAS_API_CA", "/cas-ca.pem") } - if cas := att.Client.Instance.CASAPI; cas != "" { + if cas := instance.CASAPI; cas != "" { ctr = ctr.WithEnvVariable("CHAINLOOP_ARTIFACT_CAS_API", cas) } - if att.Client.Instance.Insecure { + if instance.Insecure { ctr = ctr.WithEnvVariable("CHAINLOOP_API_INSECURE", "true") } @@ -331,6 +308,34 @@ func (att *Attestation) Container( return ctr } +// Build an ephemeral container with everything needed to process the attestation +func (att *Attestation) Container( + // Cache TTL for chainloop commands, in seconds + // Defaults to 0: no caching + // +optional + // +default=0 + ttl int, +) *dagger.Container { + ctr := cliContainer(ttl, att.Token, att.Client.Instance) + if att.repository != nil { + ctr = ctr.WithDirectory(".", att.repository) + } + + if addr := att.RegistryAuth.Address; addr != "" { + ctr = ctr.WithEnvVariable("CHAINLOOP_REGISTRY_SERVER", addr) + } + + if user := att.RegistryAuth.Username; user != "" { + ctr = ctr.WithEnvVariable("CHAINLOOP_REGISTRY_USERNAME", user) + } + + if pw := att.RegistryAuth.Password; pw != nil { + ctr = ctr.WithSecretVariable("CHAINLOOP_REGISTRY_PASSWORD", pw) + } + + return ctr +} + // Generate, sign and push the attestation to the chainloop control plane func (att *Attestation) Push( ctx context.Context, @@ -407,3 +412,42 @@ func (att *Attestation) reset(ctx context.Context, Sync(ctx) return err } + +/// standalone API calls + +// Create a new workflow +func (m *Chainloop) WorkflowCreate( + ctx context.Context, + // Chainloop API token + token *dagger.Secret, + // Workflow name + name string, + // Workflow project + project string, + // +optional + team string, + // +optional + description string, + // name of an existing contract + // +optional + contractName string, + // Set workflow as public so other organizations can see it + // +optional + public bool, + // If the workflow already exists, skip the creation and return success + // +optional + skipIfExists bool, +) (string, error) { + return cliContainer(0, token, m.Instance). + WithExec([]string{ + "workflow", "create", + "--name", name, + "--project", project, + "--team", team, + "--description", description, + "--contract", contractName, + "--public", fmt.Sprintf("%t", public), + "--skip-if-exists", fmt.Sprintf("%t", skipIfExists), + }, execOpts). + Stdout(ctx) +}