Skip to content
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

Merged

Conversation

FrankYang0529
Copy link
Contributor

resolves #658

@@ -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) => {
Copy link
Contributor

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.

Copy link
Contributor

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..

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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?

let _ = domains
.iter()
.map(|d| {
Url::parse(d).with_context(|| format!("can't parse {} in allowed_http_hosts", d))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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))

Copy link
Contributor Author

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) => {
Copy link
Contributor

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.

Copy link
Contributor

@itowlson itowlson left a 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!

let _ = domains
.iter()
.map(|d| {
Url::parse(d).with_context(|| format!("can't parse {} in allowed_http_hosts", d))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated it. Thank you.

Ok(())
}

fn validate_raw_wasm_config(raw: &RawWasmConfig) -> Result<()> {
Copy link
Contributor

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?

Copy link
Contributor Author

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.

@@ -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)?;
Copy link
Contributor

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...

Copy link
Contributor Author

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.

Copy link
Contributor

@itowlson itowlson left a 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.

@@ -103,6 +104,24 @@ pub(crate) async fn change_file_permission(
Ok(())
}

pub fn validate_allowed_http_hosts(http_hosts: &Option<Vec<String>>) -> Result<()> {
Copy link
Contributor

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?

Copy link
Contributor Author

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.

@FrankYang0529 FrankYang0529 force-pushed the add-validation-for-wasm-config branch 2 times, most recently from 9644738 to cf202dc Compare August 5, 2022 13:53
Signed-off-by: Frank Yang <yangpoan@gmail.com>
Copy link
Contributor

@itowlson itowlson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks! LGTM

@itowlson itowlson merged commit 4023d83 into fermyon:main Aug 8, 2022
@FrankYang0529 FrankYang0529 deleted the add-validation-for-wasm-config branch August 8, 2022 01:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Missing protocol in allowed_http_hosts gives misleading error at runtime
3 participants