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

unknown(false) is not work when configuration "allowUnknown" is true #2824

Open
LuEason opened this issue Aug 23, 2022 · 10 comments · May be fixed by #2882
Open

unknown(false) is not work when configuration "allowUnknown" is true #2824

LuEason opened this issue Aug 23, 2022 · 10 comments · May be fixed by #2882
Labels
bug Bug or defect support Questions, discussions, and general support

Comments

@LuEason
Copy link

LuEason commented Aug 23, 2022

Support plan

  • is this issue currently blocking your project? (yes/no): yes
  • is this issue affecting a production system? (yes/no): yes

Context

  • node version: 14.20.0
  • module version: 17.6.0
  • environment (e.g. node, browser, native): node
  • used with (e.g. hapi application, another framework, standalone, ...): node
  • any other relevant information:

How can we help?

Our project use version 14 before, we want to allow all fields of all object except for some fields we don't expect
For example, we want to allow field "e" of data.d only, and allow other unknown fields for data.b and even data, we use below code:

const joi = require('joi');

const schema = joi.object().keys({
  a: joi.string(),
  b: joi.object().keys({
    c: joi.string()
  }),
  d: joi.object().keys({
    e: joi.string()
  }).unknown(false)
});

const value = {
  a: '123',
  b: {
    c: '123',
    f: 123
  },
  d: {
    e: '12',
    g: 123
  },
  h: 123
};

const result = schema.validate(value, {
  abortEarly: false,
  allowUnknown: true
});

console.log(result?.error?.message);
// child "d" fails because ["g" is not allowed]

After we use version 17, the data pass the validation, which we do not expect.

Do you have any suggestions?

@LuEason LuEason added the support Questions, discussions, and general support label Aug 23, 2022
@Marsup Marsup added the bug Bug or defect label Aug 23, 2022
@Marsup
Copy link
Collaborator

Marsup commented Aug 23, 2022

It looks like a bug. In the meantime, you can replace .unknown(false) by .options({ allowUnknown: false }), just beware that it's inherited by children schemas.

@LuEason
Copy link
Author

LuEason commented Aug 24, 2022

Thanks Marsup.
By the way, I look up the source code and found where is this error caused. It is in /lib/base.js.

$_setFlag(name, value, options = {}) {

        Assert(name[0] === '_' || !this._inRuleset(), 'Cannot set flag inside a ruleset');

        const flag = this._definition.flags[name] || {};
        if (DeepEqual(value, flag.default)) {
            value = undefined;
        }

        if (DeepEqual(value, this._flags[name])) {
            return this;
        }
}

It is so weird to set the value to undefined when value same as the default value of flag. But once I delete this if statement, many tests failed. Please help have a check.

@geeksilva97
Copy link

Hi folks. Could I work on that issue?

@Marsup
Copy link
Collaborator

Marsup commented Sep 30, 2022

It's not the easiest one but sure.

@geeksilva97
Copy link

Thanks @Marsup .

@geeksilva97
Copy link

Hi, @LuEason I tested this code you sent using Joi 17.6.1 and it looks like it works as you expect.

It doesn't have any errors. When I print the result I get the following:

{
  value: { a: '123', b: { c: '123', f: 123 }, d: { e: '12', g: 123 }, h: 123 }
}

Maybe it was already fixed @Marsup .

@Marsup
Copy link
Collaborator

Marsup commented Oct 11, 2022

@geeksilva97 that's precisely the problem, it should fail on object d because g is not allowed.

@kamweti
Copy link

kamweti commented Nov 15, 2022

@Marsup

It looks like a bug

This is expected:

from the docs

allowUnknown - when true, allows object to contain unknown keys which are ignored. Defaults to false.

allowUknown will override any .unknown(false) settings you have

const schema = joi.object().keys({
    foo: joi.object().keys({
        bar: joi.string()
    }).unknown(false)
})

console.log(
    schema.validate({
        foo: {
            bar: "bar",
            baaz: "baaz"
        }
    })
) // "foo.baaz" is not allowed

console.log(
    schema.validate({
        foo: {
            bar: "bar",
            baaz: "baaz"
        }
    }, {allowUnknown: true})
) // valid

@LuEason

you can turn on this feature by not passing allowUnknown: true and instead add granular uknown(false) entries to the your desired keys

@Marsup
Copy link
Collaborator

Marsup commented Nov 15, 2022

Local should always override global, it is imo a bug.

@kamweti
Copy link

kamweti commented Nov 15, 2022

fair enough, i now see this is what happens in the yup lib as well

const schema = yup.object().shape({
    foo: yup.object({
        bar: yup.string()
    }).noUnknown(true)
})

console.log(
    schema.validate({
        foo: {
            bar: "bar",
            baaz: "baaz"
        }
    }, {stripUnknown: false})
) // foo field has unspecified keys: baaz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Bug or defect support Questions, discussions, and general support
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants