Merge pull request #1168 from aluzzardi/dagger-secret-service

Migrate dagger.#Secret and dagger.#Stream to new format
This commit is contained in:
Andrea Luzzardi 2021-12-07 12:29:00 -08:00 committed by GitHub
commit 2a946385fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 367 additions and 299 deletions

View File

@ -217,7 +217,7 @@ func (c *Client) logSolveStatus(ctx context.Context, pctx *plancontext.Context,
secureSprintf := func(format string, a ...interface{}) string { secureSprintf := func(format string, a ...interface{}) string {
s := fmt.Sprintf(format, a...) s := fmt.Sprintf(format, a...)
for _, secret := range secrets { for _, secret := range secrets {
s = strings.ReplaceAll(s, secret.PlainText, "***") s = strings.ReplaceAll(s, secret.PlainText(), "***")
} }
return s return s
} }

View File

@ -11,6 +11,7 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
"go.dagger.io/dagger/client" "go.dagger.io/dagger/client"
"go.dagger.io/dagger/compiler" "go.dagger.io/dagger/compiler"
"go.dagger.io/dagger/plancontext"
"go.dagger.io/dagger/state" "go.dagger.io/dagger/state"
) )
@ -85,12 +86,17 @@ func CurrentEnvironmentState(ctx context.Context, project *state.Project) *state
// FormatValue returns the String representation of the cue value // FormatValue returns the String representation of the cue value
func FormatValue(val *compiler.Value) string { func FormatValue(val *compiler.Value) string {
if val.HasAttr("artifact") { switch {
case val.HasAttr("artifact"):
return "dagger.#Artifact" return "dagger.#Artifact"
} case plancontext.IsSecretValue(val):
if val.HasAttr("secret") {
return "dagger.#Secret" return "dagger.#Secret"
case plancontext.IsFSValue(val):
return "dagger.#FS"
case plancontext.IsServiceValue(val):
return "dagger.#Service"
} }
if val.IsConcreteR() != nil { if val.IsConcreteR() != nil {
return val.IncompleteKind().String() return val.IncompleteKind().String()
} }

View File

@ -346,7 +346,7 @@ func walkStdlib(ctx context.Context, output, format string) {
return nil return nil
} }
pkgName := fmt.Sprintf("alpha.dagger.io/%s", p) pkgName := fmt.Sprintf("%s/%s", stdlib.ModuleName, p)
lg.Info().Str("package", pkgName).Str("format", format).Msg("generating doc") lg.Info().Str("package", pkgName).Str("format", format).Msg("generating doc")
val, err := loadCode(pkgName) val, err := loadCode(pkgName)
if err != nil { if err != nil {

View File

@ -10,6 +10,7 @@ import (
"go.dagger.io/dagger/cmd/dagger/logger" "go.dagger.io/dagger/cmd/dagger/logger"
"go.dagger.io/dagger/compiler" "go.dagger.io/dagger/compiler"
"go.dagger.io/dagger/environment" "go.dagger.io/dagger/environment"
"go.dagger.io/dagger/plancontext"
"go.dagger.io/dagger/solver" "go.dagger.io/dagger/solver"
"go.dagger.io/dagger/state" "go.dagger.io/dagger/state"
@ -60,6 +61,21 @@ var listCmd = &cobra.Command{
isConcrete := (inp.IsConcreteR() == nil) isConcrete := (inp.IsConcreteR() == nil)
_, hasDefault := inp.Default() _, hasDefault := inp.Default()
switch {
case plancontext.IsSecretValue(inp):
if _, err := env.Context().Secrets.FromValue(inp); err != nil {
isConcrete = false
}
case plancontext.IsFSValue(inp):
if _, err := env.Context().FS.FromValue(inp); err != nil {
isConcrete = false
}
case plancontext.IsServiceValue(inp):
if _, err := env.Context().Services.FromValue(inp); err != nil {
isConcrete = false
}
}
if !viper.GetBool("all") { if !viper.GetBool("all") {
// skip input that is not overridable // skip input that is not overridable
if !hasDefault && isConcrete { if !hasDefault && isConcrete {

View File

@ -13,6 +13,7 @@ import (
"go.dagger.io/dagger/compiler" "go.dagger.io/dagger/compiler"
"go.dagger.io/dagger/environment" "go.dagger.io/dagger/environment"
"go.dagger.io/dagger/plan" "go.dagger.io/dagger/plan"
"go.dagger.io/dagger/plancontext"
"go.dagger.io/dagger/solver" "go.dagger.io/dagger/solver"
"golang.org/x/term" "golang.org/x/term"
@ -140,7 +141,23 @@ func checkInputs(ctx context.Context, env *environment.Environment) error {
} }
for _, i := range inputs { for _, i := range inputs {
if i.IsConcreteR(cue.Optional(true)) != nil { isConcrete := (i.IsConcreteR(cue.Optional(true)) == nil)
switch {
case plancontext.IsSecretValue(i):
if _, err := env.Context().Secrets.FromValue(i); err != nil {
isConcrete = false
}
case plancontext.IsFSValue(i):
if _, err := env.Context().FS.FromValue(i); err != nil {
isConcrete = false
}
case plancontext.IsServiceValue(i):
if _, err := env.Context().Services.FromValue(i); err != nil {
isConcrete = false
}
}
if !isConcrete {
notConcreteInputs = append(notConcreteInputs, i) notConcreteInputs = append(notConcreteInputs, i)
} }
} }

View File

@ -24,10 +24,6 @@ func NewValue() *Value {
return DefaultCompiler.NewValue() return DefaultCompiler.NewValue()
} }
func NewValueWithContent(x interface{}, selectors ...cue.Selector) (*Value, error) {
return DefaultCompiler.NewValueWithContent(x, selectors...)
}
// FIXME can be refactored away now? // FIXME can be refactored away now?
func Wrap(v cue.Value) *Value { func Wrap(v cue.Value) *Value {
return DefaultCompiler.Wrap(v) return DefaultCompiler.Wrap(v)
@ -84,14 +80,6 @@ func (c *Compiler) NewValue() *Value {
return empty return empty
} }
func (c *Compiler) NewValueWithContent(x interface{}, selectors ...cue.Selector) (*Value, error) {
v := c.NewValue()
if err := v.FillPath(cue.MakePath(selectors...), x); err != nil {
return nil, err
}
return v, nil
}
func (c *Compiler) Compile(name string, src string) (*Value, error) { func (c *Compiler) Compile(name string, src string) (*Value, error) {
c.lock() c.lock()
defer c.unlock() defer c.unlock()

View File

@ -156,7 +156,11 @@ func (v *Value) IsConcrete() bool {
// Recursive concreteness check. // Recursive concreteness check.
func (v *Value) IsConcreteR(opts ...cue.Option) error { func (v *Value) IsConcreteR(opts ...cue.Option) error {
o := []cue.Option{cue.Concrete(true)} o := []cue.Option{
cue.All(),
cue.Concrete(true),
cue.Hidden(true),
}
o = append(o, opts...) o = append(o, opts...)
return v.val.Validate(o...) return v.val.Validate(o...)
} }

View File

@ -21,7 +21,7 @@ Create an ArgoCD application
|*config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version | |*config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version |
|*config.server* | `string` |ArgoCD server | |*config.server* | `string` |ArgoCD server |
|*config.project* | `*"default" \| string` |ArgoCD project | |*config.project* | `*"default" \| string` |ArgoCD project |
|*config.token* | `dagger.#Secret` |ArgoCD authentication token | |*config.token* | `*null \| {}` |ArgoCD authentication token |
|*name* | `string` |App name | |*name* | `string` |App name |
|*repo* | `string` |Repository url (git or helm) | |*repo* | `string` |Repository url (git or helm) |
|*path* | `string` |Folder to deploy | |*path* | `string` |Folder to deploy |
@ -29,7 +29,7 @@ Create an ArgoCD application
|*image.config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version | |*image.config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version |
|*image.config.server* | `string` |ArgoCD server | |*image.config.server* | `string` |ArgoCD server |
|*image.config.project* | `*"default" \| string` |ArgoCD project | |*image.config.project* | `*"default" \| string` |ArgoCD project |
|*image.config.token* | `dagger.#Secret` |ArgoCD authentication token | |*image.config.token* | `*null \| {}` |ArgoCD authentication token |
|*namespace* | `*"default" \| string` |Destination namespace | |*namespace* | `*"default" \| string` |Destination namespace |
|*env.APP_NAME* | `string` |- | |*env.APP_NAME* | `string` |- |
|*env.APP_REPO* | `string` |- | |*env.APP_REPO* | `string` |- |
@ -52,7 +52,7 @@ Re-usable CLI component
|*config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version | |*config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version |
|*config.server* | `string` |ArgoCD server | |*config.server* | `string` |ArgoCD server |
|*config.project* | `*"default" \| string` |ArgoCD project | |*config.project* | `*"default" \| string` |ArgoCD project |
|*config.token* | `dagger.#Secret` |ArgoCD authentication token | |*config.token* | `*null \| {}` |ArgoCD authentication token |
### argocd.#CLI Outputs ### argocd.#CLI Outputs
@ -69,7 +69,7 @@ ArgoCD configuration
|*version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version | |*version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version |
|*server* | `string` |ArgoCD server | |*server* | `string` |ArgoCD server |
|*project* | `*"default" \| string` |ArgoCD project | |*project* | `*"default" \| string` |ArgoCD project |
|*token* | `dagger.#Secret` |ArgoCD authentication token | |*token* | `*null \| {}` |ArgoCD authentication token |
### argocd.#Config Outputs ### argocd.#Config Outputs
@ -86,7 +86,7 @@ Get application's status
|*config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version | |*config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version |
|*config.server* | `string` |ArgoCD server | |*config.server* | `string` |ArgoCD server |
|*config.project* | `*"default" \| string` |ArgoCD project | |*config.project* | `*"default" \| string` |ArgoCD project |
|*config.token* | `dagger.#Secret` |ArgoCD authentication token | |*config.token* | `*null \| {}` |ArgoCD authentication token |
|*name* | `string` |ArgoCD application | |*name* | `string` |ArgoCD application |
### argocd.#Status Outputs ### argocd.#Status Outputs
@ -111,18 +111,18 @@ Sync an application to its targer state
|*config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version | |*config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version |
|*config.server* | `string` |ArgoCD server | |*config.server* | `string` |ArgoCD server |
|*config.project* | `*"default" \| string` |ArgoCD project | |*config.project* | `*"default" \| string` |ArgoCD project |
|*config.token* | `dagger.#Secret` |ArgoCD authentication token | |*config.token* | `*null \| {}` |ArgoCD authentication token |
|*application* | `string` |ArgoCD application | |*application* | `string` |ArgoCD application |
|*wait* | `*false \| bool` |Wait the application to sync correctly | |*wait* | `*false \| bool` |Wait the application to sync correctly |
|*ctr.image.config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version | |*ctr.image.config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version |
|*ctr.image.config.server* | `string` |ArgoCD server | |*ctr.image.config.server* | `string` |ArgoCD server |
|*ctr.image.config.project* | `*"default" \| string` |ArgoCD project | |*ctr.image.config.project* | `*"default" \| string` |ArgoCD project |
|*ctr.image.config.token* | `dagger.#Secret` |ArgoCD authentication token | |*ctr.image.config.token* | `*null \| {}` |ArgoCD authentication token |
|*ctr.env.APPLICATION* | `string` |- | |*ctr.env.APPLICATION* | `string` |- |
|*status.config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version | |*status.config.version* | `*"v2.0.5" \| string` |ArgoCD CLI binary version |
|*status.config.server* | `string` |ArgoCD server | |*status.config.server* | `string` |ArgoCD server |
|*status.config.project* | `*"default" \| string` |ArgoCD project | |*status.config.project* | `*"default" \| string` |ArgoCD project |
|*status.config.token* | `dagger.#Secret` |ArgoCD authentication token | |*status.config.token* | `*null \| {}` |ArgoCD authentication token |
|*status.name* | `string` |ArgoCD application | |*status.name* | `string` |ArgoCD application |
### argocd.#Sync Outputs ### argocd.#Sync Outputs

View File

@ -56,6 +56,18 @@ _No input._
_No output._ _No output._
## dagger.#Service
A reference to a network service endpoint, for example: - A TCP or UDP port - A unix or npipe socket - An HTTPS endpoint
### dagger.#Service Inputs
_No input._
### dagger.#Service Outputs
_No output._
## dagger.#Stream ## dagger.#Stream
Dagger stream. Can be mounted as a UNIX socket. Dagger stream. Can be mounted as a UNIX socket.

View File

@ -19,7 +19,7 @@ Commit & push to git repository
| Name | Type | Description | | Name | Type | Description |
| ------------- |:-------------: |:-------------: | | ------------- |:-------------: |:-------------: |
|*repository.remote* | `string` |Repository remote URL | |*repository.remote* | `string` |Repository remote URL |
|*repository.authToken* | `dagger.#Secret` |Authentication token (PAT or password) | |*repository.authToken* | `*null \| {}` |Authentication token (PAT or password) |
|*repository.branch* | `string` |Git branch | |*repository.branch* | `string` |Git branch |
|*name* | `string` |Username | |*name* | `string` |Username |
|*email* | `string` |Email | |*email* | `string` |Email |
@ -69,8 +69,8 @@ A git repository
|*remote* | `string` |Git remote link | |*remote* | `string` |Git remote link |
|*ref* | `string` |Git ref: can be a commit, tag or branch. Example: "main" | |*ref* | `string` |Git ref: can be a commit, tag or branch. Example: "main" |
|*subdir* | `*null \| string` |(optional) Subdirectory | |*subdir* | `*null \| string` |(optional) Subdirectory |
|*authToken* | `dagger.#Secret` |(optional) Add Personal Access Token | |*authToken* | `*null \| {}` |(optional) Add Personal Access Token |
|*authHeader* | `dagger.#Secret` |(optional) Add OAuth Token | |*authHeader* | `*null \| {}` |(optional) Add OAuth Token |
### git.#Repository Outputs ### git.#Repository Outputs

View File

@ -37,7 +37,7 @@ Apply Kubernetes resources
|*url* | `*null \| string` |Kubernetes manifest url to deploy remote configuration | |*url* | `*null \| string` |Kubernetes manifest url to deploy remote configuration |
|*namespace* | `*"default" \| string` |Kubernetes Namespace to deploy to | |*namespace* | `*"default" \| string` |Kubernetes Namespace to deploy to |
|*version* | `*"v1.19.9" \| string` |Version of kubectl client | |*version* | `*"v1.19.9" \| string` |Version of kubectl client |
|*kubeconfig* | `dagger.#Secret` |Kube config file | |*kubeconfig* | `(string\|struct)` |Kube config file |
### kubernetes.#Resources Outputs ### kubernetes.#Resources Outputs

View File

@ -27,7 +27,7 @@ Install a Helm chart
|*timeout* | `*"5m" \| string` |time to wait for any individual Kubernetes operation (like Jobs for hooks) | |*timeout* | `*"5m" \| string` |time to wait for any individual Kubernetes operation (like Jobs for hooks) |
|*wait* | `*true \| bool` |if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as timeout | |*wait* | `*true \| bool` |if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as timeout |
|*atomic* | `*true \| bool` |if set, installation process purges chart on fail. The wait option will be set automatically if atomic is used | |*atomic* | `*true \| bool` |if set, installation process purges chart on fail. The wait option will be set automatically if atomic is used |
|*kubeconfig* | `dagger.#Secret` |Kube config file | |*kubeconfig* | `(string\|struct)` |Kube config file |
|*version* | `*"3.5.2" \| string` |Helm version | |*version* | `*"3.5.2" \| string` |Helm version |
|*kubectlVersion* | `*"v1.19.9" \| string` |Kubectl version | |*kubectlVersion* | `*"v1.19.9" \| string` |Kubectl version |

View File

@ -40,13 +40,6 @@ const (
StateCompleted = State("completed") StateCompleted = State("completed")
) )
var (
fsIDPath = cue.MakePath(
cue.Hid("_fs", "alpha.dagger.io/dagger"),
cue.Str("id"),
)
)
// An execution pipeline // An execution pipeline
type Pipeline struct { type Pipeline struct {
code *compiler.Value code *compiler.Value
@ -102,90 +95,40 @@ func IsComponent(v *compiler.Value) bool {
return v.Lookup("#up").Exists() return v.Lookup("#up").Exists()
} }
func isFS(v *compiler.Value) bool { func (p *Pipeline) ops() ([]*compiler.Value, error) {
return v.LookupPath(fsIDPath).Exists()
}
func ops(code *compiler.Value) ([]*compiler.Value, error) {
ops := []*compiler.Value{} ops := []*compiler.Value{}
// dagger.#FS forward compat // dagger.#FS forward compat
// FIXME: remove this // FIXME: remove this
if isFS(code) { if plancontext.IsFSValue(p.code) {
ops = append(ops, code) ops = append(ops, p.code)
} }
// 1. attachment array // 1. attachment array
if IsComponent(code) { if IsComponent(p.code) {
xops, err := code.Lookup("#up").List() xops, err := p.code.Lookup("#up").List()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// 'from' has an executable attached // 'from' has an executable attached
ops = append(ops, xops...) ops = append(ops, xops...)
// 2. individual op // 2. individual op
} else if _, err := code.Lookup("do").String(); err == nil { } else if _, err := p.code.Lookup("do").String(); err == nil {
ops = append(ops, code) ops = append(ops, p.code)
// 3. op array // 3. op array
} else if xops, err := code.List(); err == nil { } else if xops, err := p.code.List(); err == nil {
ops = append(ops, xops...) ops = append(ops, xops...)
} else { } else {
// 4. error // 4. error
source, err := code.Source() source, err := p.code.Source()
if err != nil { if err != nil {
panic(err) panic(err)
} }
return nil, fmt.Errorf("not executable: %s (%s)", source, code.Path().String()) return nil, fmt.Errorf("not executable: %s (%s)", source, p.code.Path().String())
} }
return ops, nil return ops, nil
} }
func Analyze(fn func(*compiler.Value) error, code *compiler.Value) error {
ops, err := ops(code)
if err != nil {
// Ignore CUE errors when analyzing. This might be because the value is
// not concrete since static analysis runs before pipelines are executed.
return nil
}
for _, op := range ops {
if err := analyzeOp(fn, op); err != nil {
return err
}
}
return nil
}
func analyzeOp(fn func(*compiler.Value) error, op *compiler.Value) error {
// dagger.#FS forward compat
// FIXME: remove this
if isFS(op) {
return nil
}
if err := fn(op); err != nil {
return err
}
do, err := op.Lookup("do").String()
if err != nil {
return err
}
switch do {
case "load", "copy":
return Analyze(fn, op.Lookup("from"))
case "exec":
fields, err := op.Lookup("mount").Fields()
if err != nil {
return err
}
for _, mnt := range fields {
if from := mnt.Value.Lookup("from"); from.Exists() {
return Analyze(fn, from)
}
}
}
return nil
}
func (p *Pipeline) Run(ctx context.Context) error { func (p *Pipeline) Run(ctx context.Context) error {
lg := log. lg := log.
Ctx(ctx). Ctx(ctx).
@ -230,7 +173,7 @@ func (p *Pipeline) Run(ctx context.Context) error {
} }
func (p *Pipeline) run(ctx context.Context) error { func (p *Pipeline) run(ctx context.Context) error {
ops, err := ops(p.code) ops, err := p.ops()
if err != nil { if err != nil {
return err return err
} }
@ -269,17 +212,12 @@ func (p *Pipeline) run(ctx context.Context) error {
func (p *Pipeline) doOp(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { func (p *Pipeline) doOp(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) {
// dagger.#FS forward compat // dagger.#FS forward compat
// FIXME: remove this // FIXME: remove this
if isFS(op) { if plancontext.IsFSValue(op) {
id, err := op.LookupPath(fsIDPath).String() fs, err := p.pctx.FS.FromValue(op)
if err != nil { if err != nil {
return st, err return st, nil
} }
return fs.Result().ToState()
fs := p.pctx.FS.Get(plancontext.ContextKey(id))
if fs == nil {
return st, fmt.Errorf("fs %q not found", id)
}
return fs.Result.ToState()
} }
do, err := op.Lookup("do").String() do, err := op.Lookup("do").String()
@ -595,30 +533,26 @@ func (p *Pipeline) mount(ctx context.Context, dest string, mnt *compiler.Value)
// eg. mount: "/foo": secret: mysecret // eg. mount: "/foo": secret: mysecret
if secret := mnt.Lookup("secret"); secret.Exists() { if secret := mnt.Lookup("secret"); secret.Exists() {
id, err := getSecretID(secret) s, err := p.pctx.Secrets.FromValue(secret)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return llb.AddSecret(dest, return llb.AddSecret(dest,
llb.SecretID(id), llb.SecretID(s.ID()),
llb.SecretFileOpt(0, 0, 0400), // uid, gid, mask) llb.SecretFileOpt(0, 0, 0400), // uid, gid, mask)
), nil ), nil
} }
// eg. mount: "/var/run/docker.sock": stream: mystream // eg. mount: "/var/run/docker.sock": stream: mystream
if stream := mnt.Lookup("stream"); stream.Exists() { if stream := mnt.Lookup("stream"); stream.Exists() {
if !stream.HasAttr("stream") { s, err := p.pctx.Services.FromValue(stream)
return nil, fmt.Errorf("invalid stream %q: not a stream", stream.Path().String())
}
id, err := stream.Lookup("id").String()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid stream %q: %w", stream.Path().String(), err) return nil, err
} }
return llb.AddSSHSocket( return llb.AddSSHSocket(
llb.SSHID(id), llb.SSHID(s.ID()),
llb.SSHSocketTarget(dest), llb.SSHSocketTarget(dest),
), nil ), nil
} }
@ -761,15 +695,11 @@ func parseStringOrSecret(pctx *plancontext.Context, v *compiler.Value) (string,
} }
// If we get here, it's a secret // If we get here, it's a secret
id, err := getSecretID(v) secret, err := pctx.Secrets.FromValue(v)
if err != nil { if err != nil {
return "", err return "", err
} }
secret := pctx.Secrets.Get(plancontext.ContextKey(id)) return secret.PlainText(), nil
if secret == nil {
return "", fmt.Errorf("secret %s not found", id)
}
return secret.PlainText, nil
} }
func (p *Pipeline) Load(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { func (p *Pipeline) Load(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) {
@ -973,21 +903,6 @@ func (p *Pipeline) SaveImage(ctx context.Context, op *compiler.Value, st llb.Sta
), nil ), nil
} }
func getSecretID(secretField *compiler.Value) (string, error) {
if !secretField.HasAttr("secret") {
return "", fmt.Errorf("invalid secret %q: not a secret", secretField.Path().String())
}
idValue := secretField.Lookup("id")
if !idValue.Exists() {
return "", fmt.Errorf("invalid secret %q: no id field", secretField.Path().String())
}
id, err := idValue.String()
if err != nil {
return "", fmt.Errorf("invalid secret id: %w", err)
}
return id, nil
}
func (p *Pipeline) FetchGit(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { func (p *Pipeline) FetchGit(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) {
remote, err := op.Lookup("remote").String() remote, err := op.Lookup("remote").String()
if err != nil { if err != nil {
@ -1017,18 +932,18 @@ func (p *Pipeline) FetchGit(ctx context.Context, op *compiler.Value, st llb.Stat
} }
// Secret // Secret
if authToken := op.Lookup("authToken"); authToken.Exists() { if authToken := op.Lookup("authToken"); authToken.Exists() {
id, err := getSecretID(authToken) authTokenSecret, err := p.pctx.Secrets.FromValue(authToken)
if err != nil { if err != nil {
return st, err return st, err
} }
gitOpts = append(gitOpts, llb.AuthTokenSecret(id)) gitOpts = append(gitOpts, llb.AuthTokenSecret(authTokenSecret.ID()))
} }
if authHeader := op.Lookup("authHeader"); authHeader.Exists() { if authHeader := op.Lookup("authHeader"); authHeader.Exists() {
id, err := getSecretID(authHeader) authHeaderSecret, err := p.pctx.Secrets.FromValue(authHeader)
if err != nil { if err != nil {
return st, err return st, err
} }
gitOpts = append(gitOpts, llb.AuthHeaderSecret(id)) gitOpts = append(gitOpts, llb.AuthHeaderSecret(authHeaderSecret.ID()))
} }
gitOpts = append(gitOpts, llb.WithCustomName(p.vertexNamef("FetchGit %s@%s", remoteRedacted, ref))) gitOpts = append(gitOpts, llb.WithCustomName(p.vertexNamef("FetchGit %s@%s", remoteRedacted, ref)))

View File

@ -8,6 +8,7 @@ import (
"github.com/gofrs/flock" "github.com/gofrs/flock"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"go.dagger.io/dagger/stdlib"
) )
const ( const (
@ -15,7 +16,7 @@ const (
) )
func isUniverse(repoName string) bool { func isUniverse(repoName string) bool {
return strings.HasPrefix(strings.ToLower(repoName), "alpha.dagger.io") return strings.HasPrefix(strings.ToLower(repoName), stdlib.ModuleName)
} }
func Install(ctx context.Context, workspace, repoName, versionConstraint string) (*Require, error) { func Install(ctx context.Context, workspace, repoName, versionConstraint string) (*Require, error) {

View File

@ -7,6 +7,8 @@ import (
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"go.dagger.io/dagger/stdlib"
) )
type Require struct { type Require struct {
@ -25,7 +27,7 @@ func newRequire(repoName, versionConstraint string) (*Require, error) {
switch { switch {
case strings.HasPrefix(repoName, "github.com"): case strings.HasPrefix(repoName, "github.com"):
return parseGithubRepoName(repoName, versionConstraint) return parseGithubRepoName(repoName, versionConstraint)
case strings.HasPrefix(repoName, "alpha.dagger.io"): case strings.HasPrefix(repoName, stdlib.ModuleName):
return parseDaggerRepoName(repoName, versionConstraint) return parseDaggerRepoName(repoName, versionConstraint)
default: default:
return nil, fmt.Errorf("repo name does not match suported providers") return nil, fmt.Errorf("repo name does not match suported providers")
@ -52,7 +54,7 @@ func parseGithubRepoName(repoName, versionConstraint string) (*Require, error) {
}, nil }, nil
} }
var daggerRepoNameRegex = regexp.MustCompile(`alpha.dagger.io([a-zA-Z0-9/_.-]*)@?([0-9a-zA-Z.-]*)`) var daggerRepoNameRegex = regexp.MustCompile(stdlib.ModuleName + `([a-zA-Z0-9/_.-]*)@?([0-9a-zA-Z.-]*)`)
func parseDaggerRepoName(repoName, versionConstraint string) (*Require, error) { func parseDaggerRepoName(repoName, versionConstraint string) (*Require, error) {
repoMatches := daggerRepoNameRegex.FindStringSubmatch(repoName) repoMatches := daggerRepoNameRegex.FindStringSubmatch(repoName)
@ -62,7 +64,7 @@ func parseDaggerRepoName(repoName, versionConstraint string) (*Require, error) {
} }
return &Require{ return &Require{
repo: "alpha.dagger.io", repo: stdlib.ModuleName,
path: repoMatches[1], path: repoMatches[1],
version: repoMatches[2], version: repoMatches[2],
versionConstraint: versionConstraint, versionConstraint: versionConstraint,

View File

@ -67,10 +67,7 @@ func (p *Plan) registerLocalDirs() error {
if err != nil { if err != nil {
return err return err
} }
p.context.LocalDirs.Add(dir)
p.context.LocalDirs.Register(&plancontext.LocalDir{
Path: dir,
})
} }
return nil return nil

View File

@ -68,13 +68,10 @@ func (c importTask) Run(ctx context.Context, pctx *plancontext.Context, s solver
return nil, err return nil, err
} }
id := pctx.FS.Register(&plancontext.FS{ fs := pctx.FS.New(result)
Result: result, out := compiler.NewValue()
}) if err := out.FillPath(cue.ParsePath("fs"), fs.MarshalCUE()); err != nil {
return nil, err
return compiler.NewValueWithContent(id, }
cue.Str("fs"), return out, nil
cue.Hid("_fs", "alpha.dagger.io/dagger"),
cue.Str("id"),
)
} }

View File

@ -36,12 +36,10 @@ func (c secretEnvTask) Run(ctx context.Context, pctx *plancontext.Context, _ sol
if env == "" { if env == "" {
return nil, fmt.Errorf("environment variable %q not set", secretEnv.Envvar) return nil, fmt.Errorf("environment variable %q not set", secretEnv.Envvar)
} }
id := pctx.Secrets.Register(&plancontext.Secret{ secret := pctx.Secrets.New(env)
PlainText: env, out := compiler.NewValue()
}) if err := out.FillPath(cue.ParsePath("contents"), secret.MarshalCUE()); err != nil {
return nil, err
return compiler.NewValueWithContent(id, }
cue.Str("contents"), return out, nil
cue.Str("id"),
)
} }

View File

@ -31,16 +31,15 @@ func (c secretFileTask) Run(ctx context.Context, pctx *plancontext.Context, _ so
lg.Debug().Str("path", secretFile.Path).Msg("loading secret") lg.Debug().Str("path", secretFile.Path).Msg("loading secret")
data, err := os.ReadFile(secretFile.Path) plaintext, err := os.ReadFile(secretFile.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
id := pctx.Secrets.Register(&plancontext.Secret{
PlainText: string(data),
})
return compiler.NewValueWithContent(id, secret := pctx.Secrets.New(string(plaintext))
cue.Str("contents"), out := compiler.NewValue()
cue.Str("id"), if err := out.FillPath(cue.ParsePath("contents"), secret.MarshalCUE()); err != nil {
) return nil, err
}
return out, nil
} }

View File

@ -2,18 +2,10 @@ package plancontext
import ( import (
"crypto/sha256" "crypto/sha256"
"encoding/json"
"fmt" "fmt"
) )
type ContextKey string
// Context holds the execution context for a plan. // Context holds the execution context for a plan.
//
// Usage:
// ctx := plancontext.New()
// id := ctx.Secrets.Register("mysecret")
// secret := ctx.Secrets.Get(id)
type Context struct { type Context struct {
Platform *platformContext Platform *platformContext
FS *fsContext FS *fsContext
@ -28,25 +20,26 @@ func New() *Context {
platform: defaultPlatform, platform: defaultPlatform,
}, },
FS: &fsContext{ FS: &fsContext{
store: make(map[ContextKey]*FS), store: make(map[string]*FS),
}, },
LocalDirs: &localDirContext{ LocalDirs: &localDirContext{
store: make(map[ContextKey]*LocalDir), store: []string{},
}, },
Secrets: &secretContext{ Secrets: &secretContext{
store: make(map[ContextKey]*Secret), store: make(map[string]*Secret),
}, },
Services: &serviceContext{ Services: &serviceContext{
store: make(map[ContextKey]*Service), store: make(map[string]*Service),
}, },
} }
} }
func hashID(v interface{}) ContextKey { func hashID(values ...string) string {
data, err := json.Marshal(v) hash := sha256.New()
if err != nil { for _, v := range values {
panic(err) if _, err := hash.Write([]byte(v)); err != nil {
panic(err)
}
} }
hash := sha256.Sum256(data) return fmt.Sprintf("%x", hash)
return ContextKey(fmt.Sprintf("%x", hash))
} }

View File

@ -9,10 +9,8 @@ import (
func TestContext(t *testing.T) { func TestContext(t *testing.T) {
ctx := New() ctx := New()
id := ctx.Secrets.Register(&Secret{ secret := ctx.Secrets.New("test")
PlainText: "test", get, err := ctx.Secrets.FromValue(secret.MarshalCUE())
}) require.NoError(t, err)
secret := ctx.Secrets.Get(id) require.Equal(t, "test", get.PlainText())
require.NotNil(t, secret)
require.Equal(t, "test", secret.PlainText)
} }

View File

@ -1,32 +1,76 @@
package plancontext package plancontext
import ( import (
"fmt"
"sync" "sync"
"cuelang.org/go/cue"
"github.com/google/uuid"
bkgw "github.com/moby/buildkit/frontend/gateway/client" bkgw "github.com/moby/buildkit/frontend/gateway/client"
"go.dagger.io/dagger/compiler"
"go.dagger.io/dagger/stdlib"
) )
var (
fsIDPath = cue.MakePath(
cue.Hid("_fs", stdlib.PackageName),
cue.Str("id"),
)
)
func IsFSValue(v *compiler.Value) bool {
return v.LookupPath(fsIDPath).Exists()
}
type FS struct { type FS struct {
Result bkgw.Reference id string
result bkgw.Reference
}
func (fs *FS) Result() bkgw.Reference {
return fs.result
}
func (fs *FS) MarshalCUE() *compiler.Value {
v := compiler.NewValue()
if err := v.FillPath(fsIDPath, fs.id); err != nil {
panic(err)
}
return v
} }
type fsContext struct { type fsContext struct {
l sync.RWMutex l sync.RWMutex
store map[ContextKey]*FS store map[string]*FS
} }
func (c *fsContext) Register(fs *FS) ContextKey { func (c *fsContext) New(result bkgw.Reference) *FS {
c.l.Lock() c.l.Lock()
defer c.l.Unlock() defer c.l.Unlock()
id := hashID(fs) fs := &FS{
c.store[id] = fs // FIXME: get a hash from result instead
return id id: uuid.New().String(),
result: result,
}
c.store[fs.id] = fs
return fs
} }
func (c *fsContext) Get(id ContextKey) *FS { func (c *fsContext) FromValue(v *compiler.Value) (*FS, error) {
c.l.RLock() c.l.RLock()
defer c.l.RUnlock() defer c.l.RUnlock()
return c.store[id] id, err := v.LookupPath(fsIDPath).String()
if err != nil {
return nil, fmt.Errorf("invalid FS %q: %w", v.Path(), err)
}
fs, ok := c.store[id]
if !ok {
return nil, fmt.Errorf("fs %q not found", id)
}
return fs, nil
} }

View File

@ -5,41 +5,16 @@ import (
"sync" "sync"
) )
type LocalDir struct {
Path string
}
type localDirContext struct { type localDirContext struct {
l sync.RWMutex l sync.RWMutex
store map[ContextKey]*LocalDir store []string
} }
func (c *localDirContext) Register(directory *LocalDir) ContextKey { func (c *localDirContext) Add(dir string) {
c.l.Lock() c.l.Lock()
defer c.l.Unlock() defer c.l.Unlock()
id := hashID(directory) c.store = append(c.store, dir)
c.store[id] = directory
return id
}
func (c *localDirContext) Get(id ContextKey) *LocalDir {
c.l.RLock()
defer c.l.RUnlock()
return c.store[id]
}
func (c *localDirContext) List() []*LocalDir {
c.l.RLock()
defer c.l.RUnlock()
directories := make([]*LocalDir, 0, len(c.store))
for _, d := range c.store {
directories = append(directories, d)
}
return directories
} }
func (c *localDirContext) Paths() (map[string]string, error) { func (c *localDirContext) Paths() (map[string]string, error) {
@ -48,12 +23,12 @@ func (c *localDirContext) Paths() (map[string]string, error) {
directories := make(map[string]string) directories := make(map[string]string)
for _, d := range c.store { for _, d := range c.store {
abs, err := filepath.Abs(d.Path) abs, err := filepath.Abs(d)
if err != nil { if err != nil {
return nil, err return nil, err
} }
directories[d.Path] = abs directories[d] = abs
} }
return directories, nil return directories, nil

View File

@ -1,26 +1,82 @@
package plancontext package plancontext
import "sync" import (
"fmt"
"sync"
type secretContext struct { "cuelang.org/go/cue"
l sync.RWMutex "go.dagger.io/dagger/compiler"
store map[ContextKey]*Secret "go.dagger.io/dagger/stdlib"
)
var (
secretIDPath = cue.MakePath(
cue.Hid("_secret", stdlib.PackageName),
cue.Str("id"),
)
)
func IsSecretValue(v *compiler.Value) bool {
return v.LookupPath(secretIDPath).Exists()
} }
type Secret struct { type Secret struct {
PlainText string id string
plainText string
} }
func (c *secretContext) Register(secret *Secret) ContextKey { func (s *Secret) ID() string {
return s.id
}
func (s *Secret) PlainText() string {
return s.plainText
}
func (s *Secret) MarshalCUE() *compiler.Value {
v := compiler.NewValue()
if err := v.FillPath(secretIDPath, s.id); err != nil {
panic(err)
}
return v
}
type secretContext struct {
l sync.RWMutex
store map[string]*Secret
}
func (c *secretContext) New(plaintext string) *Secret {
secret := &Secret{
id: hashID(plaintext),
plainText: plaintext,
}
c.l.Lock() c.l.Lock()
defer c.l.Unlock() defer c.l.Unlock()
id := hashID(secret.PlainText) c.store[secret.id] = secret
c.store[id] = secret return secret
return id
} }
func (c *secretContext) Get(id ContextKey) *Secret { func (c *secretContext) FromValue(v *compiler.Value) (*Secret, error) {
c.l.RLock()
defer c.l.RUnlock()
id, err := v.LookupPath(secretIDPath).String()
if err != nil {
return nil, fmt.Errorf("invalid secret %q: %w", v.Path(), err)
}
secret, ok := c.store[id]
if !ok {
return nil, fmt.Errorf("secret %q not found", id)
}
return secret, nil
}
func (c *secretContext) Get(id string) *Secret {
c.l.RLock() c.l.RLock()
defer c.l.RUnlock() defer c.l.RUnlock()

View File

@ -1,27 +1,89 @@
package plancontext package plancontext
import "sync" import (
"fmt"
"sync"
type serviceContext struct { "cuelang.org/go/cue"
l sync.RWMutex "go.dagger.io/dagger/compiler"
store map[ContextKey]*Service "go.dagger.io/dagger/stdlib"
)
var (
serviceIDPath = cue.MakePath(
cue.Hid("_service", stdlib.PackageName),
cue.Str("id"),
)
)
func IsServiceValue(v *compiler.Value) bool {
return v.LookupPath(serviceIDPath).Exists()
} }
type Service struct { type Service struct {
Unix string id string
Npipe string
unix string
npipe string
} }
func (c *serviceContext) Register(service *Service) ContextKey { func (s *Service) ID() string {
return s.id
}
func (s *Service) Unix() string {
return s.unix
}
func (s *Service) NPipe() string {
return s.npipe
}
func (s *Service) MarshalCUE() *compiler.Value {
v := compiler.NewValue()
if err := v.FillPath(serviceIDPath, s.id); err != nil {
panic(err)
}
return v
}
type serviceContext struct {
l sync.RWMutex
store map[string]*Service
}
func (c *serviceContext) New(unix, npipe string) *Service {
c.l.Lock() c.l.Lock()
defer c.l.Unlock() defer c.l.Unlock()
id := hashID(service) s := &Service{
c.store[id] = service id: hashID(unix, npipe),
return id unix: unix,
npipe: npipe,
}
c.store[s.id] = s
return s
} }
func (c *serviceContext) Get(id ContextKey) *Service { func (c *serviceContext) FromValue(v *compiler.Value) (*Service, error) {
c.l.RLock()
defer c.l.RUnlock()
id, err := v.LookupPath(serviceIDPath).String()
if err != nil {
return nil, fmt.Errorf("invalid service %q: %w", v.Path(), err)
}
s, ok := c.store[id]
if !ok {
return nil, fmt.Errorf("service %q not found", id)
}
return s, nil
}
func (c *serviceContext) Get(id string) *Service {
c.l.RLock() c.l.RLock()
defer c.l.RUnlock() defer c.l.RUnlock()

View File

@ -21,7 +21,7 @@ type inputStore struct {
func (s *inputStore) GetSecret(ctx context.Context, id string) ([]byte, error) { func (s *inputStore) GetSecret(ctx context.Context, id string) ([]byte, error) {
lg := log.Ctx(ctx) lg := log.Ctx(ctx)
secret := s.pctx.Secrets.Get(plancontext.ContextKey(id)) secret := s.pctx.Secrets.Get(id)
if secret == nil { if secret == nil {
return nil, secrets.ErrNotFound return nil, secrets.ErrNotFound
} }
@ -31,5 +31,5 @@ func (s *inputStore) GetSecret(ctx context.Context, id string) ([]byte, error) {
Str("id", id). Str("id", id).
Msg("injecting secret") Msg("injecting secret")
return []byte(secret.PlainText), nil return []byte(secret.PlainText()), nil
} }

View File

@ -36,7 +36,7 @@ func (sp *SocketProvider) ForwardAgent(stream sshforward.SSH_ForwardAgentServer)
id = v[0] id = v[0]
} }
service := sp.pctx.Services.Get(plancontext.ContextKey(id)) service := sp.pctx.Services.Get(id)
if service == nil { if service == nil {
return fmt.Errorf("invalid socket id %q", id) return fmt.Errorf("invalid socket id %q", id)
} }

View File

@ -12,9 +12,9 @@ import (
) )
func dialService(service *plancontext.Service) (net.Conn, error) { func dialService(service *plancontext.Service) (net.Conn, error) {
if service.Unix == "" { if service.Unix() == "" {
return nil, errors.New("unsupported socket type") return nil, errors.New("unsupported socket type")
} }
return net.DialTimeout("unix", service.Unix, time.Second) return net.DialTimeout("unix", service.Unix(), time.Second)
} }

View File

@ -13,10 +13,10 @@ import (
) )
func dialService(service *plancontext.Service) (net.Conn, error) { func dialService(service *plancontext.Service) (net.Conn, error) {
if service.Npipe == "" { if service.NPipe() == "" {
return nil, errors.New("unsupported socket type") return nil, errors.New("unsupported socket type")
} }
dur := time.Second dur := time.Second
return winio.DialPipe(service.Npipe, &dur) return winio.DialPipe(service.NPipe(), &dur)
} }

View File

@ -12,7 +12,6 @@ import (
"cuelang.org/go/cue" "cuelang.org/go/cue"
"go.dagger.io/dagger/compiler" "go.dagger.io/dagger/compiler"
"go.dagger.io/dagger/plancontext"
) )
// An input is a value or artifact supplied by the user. // An input is a value or artifact supplied by the user.
@ -121,9 +120,7 @@ func (dir dirInput) Compile(state *State) (*compiler.Value, error) {
return nil, err return nil, err
} }
state.Context.LocalDirs.Register(&plancontext.LocalDir{ state.Context.LocalDirs.Add(p)
Path: p,
})
llb := fmt.Sprintf( llb := fmt.Sprintf(
`#up: [{do: "local", dir: %s, include: %s, exclude: %s}]`, `#up: [{do: "local", dir: %s, include: %s, exclude: %s}]`,
@ -195,11 +192,8 @@ func SecretInput(data string) Input {
type secretInput string type secretInput string
func (i secretInput) Compile(st *State) (*compiler.Value, error) { func (i secretInput) Compile(st *State) (*compiler.Value, error) {
id := st.Context.Secrets.Register(&plancontext.Secret{ secret := st.Context.Secrets.New(i.PlainText())
PlainText: i.PlainText(), return secret.MarshalCUE(), nil
})
secretValue := fmt.Sprintf(`{id: %q}`, id)
return compiler.Compile("", secretValue)
} }
func (i secretInput) PlainText() string { func (i secretInput) PlainText() string {
@ -301,10 +295,6 @@ type socketInput struct {
} }
func (i socketInput) Compile(st *State) (*compiler.Value, error) { func (i socketInput) Compile(st *State) (*compiler.Value, error) {
id := st.Context.Services.Register(&plancontext.Service{ service := st.Context.Services.New(i.Unix, i.Npipe)
Unix: i.Unix, return service.MarshalCUE(), nil
Npipe: i.Npipe,
})
socketValue := fmt.Sprintf(`{id: %q}`, id)
return compiler.Compile("", socketValue)
} }

View File

@ -399,7 +399,7 @@ func VendorUniverse(ctx context.Context, p string) error {
// add universe and lock file to `.gitignore` // add universe and lock file to `.gitignore`
if err := os.WriteFile( if err := os.WriteFile(
path.Join(p, "cue.mod", "pkg", ".gitignore"), path.Join(p, "cue.mod", "pkg", ".gitignore"),
[]byte(fmt.Sprintf("# generated by dagger\n%s\ndagger.lock\n", stdlib.PackageName)), []byte(fmt.Sprintf("# generated by dagger\n%s\ndagger.lock\n", stdlib.ModuleName)),
0600, 0600,
); err != nil { ); err != nil {
return err return err
@ -408,7 +408,7 @@ func VendorUniverse(ctx context.Context, p string) error {
log.Ctx(ctx).Debug().Str("mod", p).Msg("vendoring universe") log.Ctx(ctx).Debug().Str("mod", p).Msg("vendoring universe")
if err := stdlib.Vendor(ctx, p); err != nil { if err := stdlib.Vendor(ctx, p); err != nil {
// FIXME(samalba): disabled install remote stdlib temporarily // FIXME(samalba): disabled install remote stdlib temporarily
// if _, err := mod.Install(ctx, p, "alpha.dagger.io", ""); err != nil { // if _, err := mod.Install(ctx, p, stdlib.ModuleName, ""); err != nil {
return err return err
} }

View File

@ -24,13 +24,18 @@ import (
... ...
} }
// Dagger stream. Can be mounted as a UNIX socket. // A reference to a network service endpoint, for example:
#Stream: { // - A TCP or UDP port
@dagger(stream) // - A unix or npipe socket
// - An HTTPS endpoint
id: string #Service: {
_service: id: string
} }
// Dagger stream. Can be mounted as a UNIX socket.
// FIXME: Deprecated. For backward compatibility only, use #Service instead.
#Stream: #Service
// A reference to an external secret, for example: // A reference to an external secret, for example:
// - A password // - A password
// - A SSH private key // - A SSH private key
@ -38,9 +43,7 @@ import (
// Secrets are never merged in the Cue tree. They can only be used // Secrets are never merged in the Cue tree. They can only be used
// by a special filesystem mount designed to minimize leak risk. // by a special filesystem mount designed to minimize leak risk.
#Secret: { #Secret: {
@dagger(secret) _secret: id: string
id: string
} }
#Input: { #Input: {

View File

@ -17,8 +17,9 @@ var (
//go:embed **/*.cue **/*/*.cue //go:embed **/*.cue **/*/*.cue
FS embed.FS FS embed.FS
PackageName = "alpha.dagger.io" ModuleName = "alpha.dagger.io"
Path = path.Join("cue.mod", "pkg", PackageName) PackageName = fmt.Sprintf("%s/dagger", ModuleName)
Path = path.Join("cue.mod", "pkg", ModuleName)
lockFilePath = path.Join("cue.mod", "dagger.lock") lockFilePath = path.Join("cue.mod", "dagger.lock")
) )

View File

@ -17,7 +17,6 @@ TestSecrets: #up: [
op.#Exec & { op.#Exec & {
mount: "/secret": secret: mySecret mount: "/secret": secret: mySecret
env: PLAIN: mySecret.id
args: [ args: [
"/bin/bash", "/bin/bash",
"--noprofile", "--noprofile",
@ -27,7 +26,6 @@ TestSecrets: #up: [
"-c", "-c",
#""" #"""
test "$(cat /secret)" = "SecretValue" test "$(cat /secret)" = "SecretValue"
test "$PLAIN" != "SecretValue"
"""#, """#,
] ]
}, },

View File

@ -141,10 +141,6 @@ setup() {
"$DAGGER" input secret mySecret SecretValue "$DAGGER" input secret mySecret SecretValue
run "$DAGGER" up run "$DAGGER" up
assert_success assert_success
# Make sure the secret doesn't show in dagger query
run "$DAGGER" query mySecret.id -f text
assert_success
} }
@test "core: stream" { @test "core: stream" {