-
Notifications
You must be signed in to change notification settings - Fork 251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(loader): validate wasm config #659
feat(loader): validate wasm config #659
Conversation
@@ -93,6 +98,37 @@ fn error_on_duplicate_ids(components: Vec<RawComponentManifest>) -> Result<()> { | |||
Ok(()) | |||
} | |||
|
|||
fn validate_raw_app_manifest(raw: &RawAppManifestAnyVersion) -> Result<()> { | |||
match raw { | |||
RawAppManifestAnyVersion::V1(raw) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than validating each raw storage format, would it make sense to validate the Application object? This is the common object which the rest of Spin works with and to which all raw formats get rendered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also wondering if we should set up more general validation infrastructure..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that this would not be the best place to put validator, as each new version would require some copy and paste of previous version's validations. Building a general validation infras would be hard, but I like the idea. It needs to be versioned too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @itowlson and @Mossaka, thanks for the suggestion. Currently, if we want to set validation on the Application
object, only up
and trigger
commands will be validated. Other commands like build
or deploy
use RawAppManifest
directly. For validating spin.toml
before runtime, I think adding validation in the Application
object is enough. If you all agree with this, I can update this PR later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
build
shouldn't care about configuration validity, unless used with --up
, and I'd expect it that part to go through Application
. Good point about deploy
(and publish
) though, we'd want to catch it there and they don't build Application
abstractions.
Given that, the best course is, I think, to go ahead with the validation where you have it, and raise an issue to revisit the consolidation issue as part of a general validation infrastructure, which might require more invasive changes. @Mossaka does that make sense to you?
crates/loader/src/local/mod.rs
Outdated
let _ = domains | ||
.iter() | ||
.map(|d| { | ||
Url::parse(d).with_context(|| format!("can't parse {} in allowed_http_hosts", d)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Url::parse(d).with_context(|| format!("can't parse {} in allowed_http_hosts", d)) | |
Url::parse(d).with_context(|| format!("Can't parse {} in allowed_http_hosts", d)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated it. Thank you.
@@ -93,6 +98,37 @@ fn error_on_duplicate_ids(components: Vec<RawComponentManifest>) -> Result<()> { | |||
Ok(()) | |||
} | |||
|
|||
fn validate_raw_app_manifest(raw: &RawAppManifestAnyVersion) -> Result<()> { | |||
match raw { | |||
RawAppManifestAnyVersion::V1(raw) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that this would not be the best place to put validator, as each new version would require some copy and paste of previous version's validations. Building a general validation infras would be hard, but I like the idea. It needs to be versioned too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good apart from a couple of minor changes, but it does hit a snag in our local loader flow. If you put the validation in the raw manifest deserialiser, it gets run during build
, which feels iffy. But if you don't put it in the deserialiser, it doesn't get run during deploy
or bindle prepare/publish
, which is even worse.
We can bodge around this by manually calling it from expand_manifest
, and I think that would work. But then we have multiple places where validation happens, and as the number of entry points grows it gets hard to make sure we're catching it everywhere. So we're probably going to need to do some rework on the loading pipeline.
My suggestion for now would be to remove the validation call from raw_manifest_from_file
(which really is meant to do nothing more than deserialise the TOML) and call it instead from from_file
and expand_manifest
. I think that would pick up all the cases.
As always I'm very open to discussion - I am really not entirely sure what the right thing to do is!
crates/loader/src/bindle/mod.rs
Outdated
let _ = domains | ||
.iter() | ||
.map(|d| { | ||
Url::parse(d).with_context(|| format!("can't parse {} in allowed_http_hosts", d)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Url::parse(d).with_context(|| format!("can't parse {} in allowed_http_hosts", d)) | |
Url::parse(d).with_context(|| format!("Can't parse {} in allowed_http_hosts", d)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated it. Thank you.
crates/loader/src/local/mod.rs
Outdated
Ok(()) | ||
} | ||
|
||
fn validate_raw_wasm_config(raw: &RawWasmConfig) -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the same function as in the bindle loader. I know the RawWasmConfig
types are different between the two, but the allowed_http_hosts
types are the same. Could we have a helper function that takes &Option<Vec<String>>
(or similar) and has all the logic in it, and call that function from both places?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your suggestion. I add a validate_allowed_http_hosts
function and remove validate_raw_wasm_config
in both local
and bindle
loader.
crates/loader/src/local/mod.rs
Outdated
@@ -60,6 +64,7 @@ pub async fn raw_manifest_from_file(app: &impl AsRef<Path>) -> Result<RawAppMani | |||
.with_context(|| anyhow!("Cannot read manifest file from {:?}", app.as_ref()))?; | |||
|
|||
let manifest: RawAppManifestAnyVersion = toml::from_slice(&buf)?; | |||
validate_raw_app_manifest(&manifest)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Placing this here will cause it to run on build
, which normally only cares about compilation... I'm not sure of a good solution to this. We could place this call in the from_file
and from_bindle
wrappers used by up
, and call it manually from deploy
. But then it starts to feel a bit like whack-a-mole...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I agree with it. We should have a place to transfer RawAppManifest
to Application.
Also, other functions/commands should rely on the Application
object, so we don't need to put the validating function everywhere.
93d9b8c
to
272973d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One final request but it's an easy one I hope - conceptually HTTP host validation is not part of the assets subsystem - I can't see an existing home so maybe create a new file/module for it? Thanks! Otherwise looks good to go.
crates/loader/src/assets.rs
Outdated
@@ -103,6 +104,24 @@ pub(crate) async fn change_file_permission( | |||
Ok(()) | |||
} | |||
|
|||
pub fn validate_allowed_http_hosts(http_hosts: &Option<Vec<String>>) -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I don't think this belongs in the assets
module; if there's no existing home for it then maybe create a new validation
module?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, add a validation
module for it. Thank you.
9644738
to
cf202dc
Compare
Signed-off-by: Frank Yang <yangpoan@gmail.com>
cf202dc
to
5931531
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, thanks! LGTM
resolves #658