Istio 1.7: Fails to create a wasm filter

Sure, but it’s more or less what @ed.snible was showing, so perhaps the error you have is due to the wasm code, not the EnvoyFilter resource.
Here’s my EnvoyFilter:

  apiVersion: networking.istio.io/v1alpha3
  kind: EnvoyFilter
  metadata:
    name: ui-examplefilter
    namespace: default
  spec:
    configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          filterChain:
            filter:
              name: envoy.http_connection_manager
              subFilter:
                name: envoy.router
      patch:
        operation: INSERT_BEFORE
        value:
          name: example-filter
          typed_config:
            '@type': type.googleapis.com/udpa.type.v1.TypedStruct
            type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
            value:
              config:
                # 'configuration' available at root_context.getConfiguration()
                configuration:
                  '@type': type.googleapis.com/google.protobuf.StringValue
                  value: my-config
                # root_id MUST match registerRootContext() 2nd param
                root_id: add_header
                vm_config:
                  code:
                    local:
                      filename: /var/local/lib/wasm-filters/optimized.wasm
                  runtime: envoy.wasm.runtime.v8
                  vm_id: my-example
    workloadSelector:
      labels:
        app: ui
        version: base

Beside that, I used wasme for filter scaffolding:

wasme init ./new-filter

Here’s the generated code, in assembly script:

export * from "@solo-io/proxy-runtime/proxy";
import { RootContext, Context, RootContextHelper, ContextHelper, registerRootContext, FilterHeadersStatusValues, stream_context } from "@solo-io/proxy-runtime";

class AddHeaderRoot extends RootContext {
  configuration : string;

  onConfigure(): bool {
    let conf_buffer = super.getConfiguration();
    let result = String.UTF8.decode(conf_buffer);
    this.configuration = result;
    return true;
  }

  createContext(): Context {
    return ContextHelper.wrap(new AddHeader(this));
  }
}

class AddHeader extends Context {
  root_context : AddHeaderRoot;
  constructor(root_context:AddHeaderRoot){
    super();
    this.root_context = root_context;
  }
  onResponseHeaders(a: u32): FilterHeadersStatusValues {
    const root_context = this.root_context;
    if (root_context.configuration == "") {
      stream_context.headers.response.add("hello", "world!");
    } else {
      stream_context.headers.response.add("hello", root_context.configuration);
    }
    return FilterHeadersStatusValues.Continue;
  }
}

registerRootContext(() => { return RootContextHelper.wrap(new AddHeaderRoot()); }, "add_header");

(What it does is just adding a header)

Building:
npm install && npm run asbuild

Send as a config map:

kubectl create cm -n default example-filter --from-file=build/optimized.wasm

Add these pod annotations to mount this configmap

sidecar.istio.io/userVolume: '[{"name":"wasmfilters-dir","configMap": {"name": "example-filter"}}]'
sidecar.istio.io/userVolumeMount: '[{"mountPath":"/var/local/lib/wasm-filters","name":"wasmfilters-dir"}]'

Then, apply the envoyfilter:
kubectl apply -f ./envoyfilter.yml -n default

And finally, curling the service to check that the header is added (it is).

# curl -L -v http://ui.default:8080
[...]
< content-type: text/html;charset=UTF-8
< x-envoy-upstream-service-time: 58
< hello: my-config
* Server envoy is not blacklisted
< server: envoy
[...]