#Nested exec
1 messages · Page 1 of 1 (latest)
.
Things that would need to be namespaced:
- Host fs access import + export (should be the container's fs)
- Interacting with services (should only see services you start, not the parents)
- Cache volumes (addressed by human friendly names)
- Secrets?
- OCI registry credentials if they are handled as a special case (?)
Just to get the temperature on this one: It's not a hypothetical feature in a remote future, I need it right now to test the Python SDK 😄
So if we think it's not a good idea / needs design discussions I can find another path forward
I think maybe the safest would be @plush chasm's suggestion -- do it but hide it and disable by default
until we work through this
Yeah if we make it only available in a development build, I'm good with it
Well if you need to implement something now, seems like a good idea to start the design discussion now; even if we make tradeoffs for implementation speed, I prefer to know about the tradeoffs 🙂
Of course
All the namespacing stuff needs to happen both for extensions and for multitenant anyways, so once we solve it there then we could consider also enabling DAGGER_HOST access for exec ops in non-dev builds
Just wanted to know if I should start looking for an alternative
So: allow nesting, but hide it, and worry about namespacing later?
How about we add: configurable by an exec option, disabled by default
That way no risk of someone somewhere accidentally exec-ing a tool that instrospects for dagger api access and does evil things (long shot right now, but things could change quickly)
I was thinking either:
- ^^ this. But it makes it into our public API
- Or, janky environment variable, nowhere to be found in our docs
emphasis on accidentally. @tight trout can enable it for tests; he knows the risks and is careful what he execs
I think it's ok to make it public if it's disabled by default, and there's a scary warning in the docs
we can enable it by default later when it's safe
(Just thinking that after designing it -- we might remove the exec option because it's always on, since it's so secure there are no downsides)
It's almost the equivalent of --privileged (not quite, but comparable) so it needs a scary name
Can we just put this behind a buildtag for now?
no opinion on that
AFAIK not very convenient -- it's in bits and pieces of the codebase
but let me check
Could there be a const like enableDaggerSock that's false by default and true if you're doing a dev build. Then our code can check that bool
I'm going to try with the most hidden way I find, then we can make it more/less public? Changing how to enable it should be the easy part
doh -- right. I imagined putting the entire code behind build tag, I forgot this nifty if trick 😄
"10 tricks functional programmers don't want you to know"
I think it's probably extra paranoid to do it that way... but it just makes me nervous to give users that sort of option right now
even if it's tucked away
dagger.ExecYouWillGetHackedIfYouUseThisOpt
That would be alright too if we are willing to put it in our API 🙂
dagger.ExecYouWillGetHackedIfYouUseThisOpt{
SignedBy: "..."
}
and we can check the signature against the user's github ssh public key
i'm sure they'll never forget
I think the following is OK:
- Disabled by default
- Option name conveys the risk AND experimental nature, and is long for extra dissuassive power:
dagger.ExecExperimentalPrivilegedOpt - Clear and scary warning in the docs. "Do not use this option unless you trust the command being executed. The command being executed WILL BE GRANTED FULL ACCESS TO YOUR HOST FILESYSTEM"
Clear and scary warning in the go doc (same text)(this is a nice to have)- We all agree that in the future it's possible and desirable to remove privileged mode in favor of always-on, fully sandboxed nesting
- If anything goes wrong, we never had this conversation
I was midway reading and was about to suggest "if anything goes wrong, it's Solomon's fault"
options are codegen'd so won't be arbitrarily scary though
ok i'm going to try
But the field description from gql schema makes it into the go doc comment no?
Yep yep
oh, but it's not a field, it's a single argument
ok - well I think the name + regular docs is enough 🙂
ugh no hold on
if it's an exec flag (rather than an engine option), code must be aware of it
so it means all our tests: go, python, node -- have to use this Exec opt
it gets trickier when testing public facing bits (examples, docs) -- we don't want to put that flag in there
Yeah but we only need the flag when exec-ing dagger itselfcode that imports the dagger SDK no?
Oh right! Yes
mmmm...
it will work ONCE, not recursively
but we don't do it recursively anyway
so all good
well -- there's just the meta case of writing tests for this 😄 in which case it'll be 2 layers deep. But I can just not do tests
(mage test --> go test container --> the actual test)
If the flag stops working, we'll either 1) see our tests fail, or 2) get a complaint from malware developers asking for their money back
If a feature doesn't have a test, but is used by all the other tests, is that considered a test?
tests are running 🙂
#21 36.69 PASS
#21 36.69 ok dagger.io/dagger/internal/querybuilder 0.006s
dagger in dagger!
tests are failing!
ugh 😄
At least they are failing in Dagger 😎
Yeah, WorkDir based tests are failing. I don't see a way around. FS stuff
And .Connect() tests are silently passing ... but they're not testing the same thing
Makes sense, we need to wire the host fs to container
I just went on a big thought tangent wondering if we could model extensions not as schemas loaded into our server but on the client codegen level: codegen would still model them as an api but internally would just be submitted as exec ops with this flag enabled. I don't why but that's intriguing. Stashing away for later
I guess we could just sync the whole host into the container 😅
but that should work out of the box? since the buildkit client runs inside the container
If we load host workdir -> test container then when tests run they should have the same workdir... so yeah I can't think either where that would break
does the inner engine connect successfully to the buildkit container?
yes but not the workdir the test is expecting
I just understood this
fakextensions. i like it, don't know why either 😄
and logs.
WithLogOutput doesn't work anymore
- It moves complexity from the server-side to the codegen-side, but we could still present users the same facade of schemas, chainability, etc. as we wanted to before
- Avoids the annoying stuff around having to load extensions and dynamically change schema (and multitenant-ing that)
- Allows us to use gqlgen in our server instead of the abandoned graphql-go
- Answers questions around how to make the automatic mounting of extension input directories not a huge hack (it's just the mount api of exec op)
Only downside I can think of is that you wouldn't be able to easily do alpine{build(...)} from raw graphql. Which is meaningful, but not necessarily devastating. Essentially, our core graphql api becomes our assembly language, extensions are just compiled to that assembly language rather than becoming new instructions in the assembly language...
I don't have time for this right now 😅 but seems like an idea worth considering more!
How does this sound?
Exec(dagger.ContainerExecOpts{
Args: []string{"go", "test", "-v", "./..."},
// go test requires running dagger in dagger
ExperimentalPrivilegedNesting: true,
}).
doc description is this:
Provide dagger access to the executed command
Do not use this option unless you trust the command being executed
The command being executed WILL BE GRANTED FULL ACCESS TO YOUR HOST FILESYSTEM
IMO the “nesting” in the opt name is redundant
“privileged” evokes docker —privileged which is exactly the right analogy (nesting + danger)
I thought privilege was too much of a blanket flag. Do I get cgroup privileged access? Is it about AppArmor? I wanted to convey what the flag was doing and avoiding having a "catch all" privileged like docker
Also -- it's confusing with docker's privileged flag which does something completely different
So I thought the feature is "nesting", then "privileged" is a prefix (just like "experimental") -- took your advice of making it long and scary
WDYT?
Cool! It's ready
-
https://github.com/dagger/dagger/pull/3672 --> restructured our CI pipelines to accomodate Python (and Go, and Node)
-
https://github.com/dagger/dagger/pull/3674 --> dagger in dagger support. Dagger Go SDK tests are now running in dagger 🙂
@rigid vector re your question earlier today: how do I re-generate the API? now it's mage sdk:go:generate. And if you want to re-generate all SDKs, it's mage sdk:all:generate 🙂
same with everything sdk:all:test, sdk:python:lint, ...
new SDKs have to implement an interface and they get consistently supported by our CI pipelines. The joys of CI as code
that’s amazing
I love mage but every time I see a dagger pipeline run by mage I can’t help but feel weird. It makes sense intellectually to focus on the backend and embrace the wrapping, but it still feels weird
I don’t know what to do with that gut feeling yet
well, we can always build our own CLI or go run -- mage works as a library too
oh I didn’t know that!
their CLI is just a convenience to avoid having to go build or go run
that would actually solve one aspect of the problem: lack of a standard loading model in the go sdk
we could standardize on go run without sacrificing use of mage
which means in turn we can standardize CI integration guides, at least for each sdk
it would still feel weird to not have a unique standard CI integration shared by all SDKs… but baby steps 🙂
As a user tonight, I was kinda happy to not have a standard thing shared by everyone ... being pure Go allowed me to do some neat stuff which wouldn't translate to other languages
it's empowering
Yeah I love that too
type SDK interface {
Lint(context.Context) error
Test(context.Context) error
Generate(context.Context) error
}
var availableSDKs = []SDK{
&Go{},
}
this is how we do our pipelines 🙂
No intention of taking that away (we probably couldn’t even if we tried, it’s too popular already 😀)
helder just needs to write a Python type that implements the SDK interface
and everything is taken care of
I think a standard way is CLI-based and additive (and optional)
mmm the interface is cross-language??
our CI is entirely in Go
this threw me off
python type -> go type for doing python things?
I get it now - just had to re-read a few times 😅
SDK interface, lint+test+generate -- every SDK in our repo has to implement it, doing whatever they want
but then it's hooked up into everything automatically
sdk:all:generate all include python generation out of the box
@rich iron @smoky olive 👆
personally (as the one using the CI) -- if it were a go run, I'd just put that behind a Makefile
I just want to type mage <whatever> or make <whatever> 😄
don't want to cd around and autocomplete paths to a file somewhere
which actually is probably better than having to use mage